backgroundFrequencies;
+
+ /**
+ * Constructor
+ */
+ public HiddenMarkovModel()
+ {
+ }
+
+ /**
+ * Copy constructor given a new aligned sequence with which to associate the
+ * HMM profile
+ *
+ * @param hmm
+ * @param sq
+ */
+ public HiddenMarkovModel(HiddenMarkovModel hmm, SequenceI sq)
+ {
+ super();
+ this.fileProperties = new HashMap<>(hmm.fileProperties);
+ this.alphabet = hmm.alphabet;
+ this.nodes = new ArrayList<>(hmm.nodes);
+ this.symbolIndexLookup = hmm.symbolIndexLookup;
+ this.fileHeader = new String(hmm.fileHeader);
+ this.hmmSeq = sq;
+ this.backgroundFrequencies = hmm.getBackgroundFrequencies();
+ if (sq.getDatasetSequence() == hmm.mapToHmmConsensus.getTo())
+ {
+ // same dataset sequence e.g. after realigning search results
+ this.mapToHmmConsensus = hmm.mapToHmmConsensus;
+ }
+ else
+ {
+ // different dataset sequence e.g. after loading HMM from project
+ this.mapToHmmConsensus = new Mapping(sq.getDatasetSequence(),
+ hmm.mapToHmmConsensus.getMap());
+ }
+ }
+
+ /**
+ * Returns the information content at a specified column, calculated as the
+ * sum (over possible symbols) of the log ratio
+ *
+ *
+ * log(emission probability / background probability) / log(2)
+ *
+ *
+ * @param column
+ * column position (base 0)
+ * @return
+ */
+ public float getInformationContent(int column)
+ {
+ float informationContent = 0f;
+
+ for (char symbol : getSymbols().toCharArray())
+ {
+ float freq = ResidueProperties.backgroundFrequencies
+ .get(getAlphabetType()).get(symbol);
+ float prob = (float) getMatchEmissionProbability(column, symbol);
+ informationContent += prob * Math.log(prob / freq);
+ }
+
+ informationContent = informationContent / (float) LOG2;
+
+ return informationContent;
+ }
+
+ /**
+ * Gets the file header of the .hmm file this model came from
+ *
+ * @return
+ */
+ public String getFileHeader()
+ {
+ return fileHeader;
+ }
+
+ /**
+ * Sets the file header of this model.
+ *
+ * @param header
+ */
+ public void setFileHeader(String header)
+ {
+ fileHeader = header;
+ }
+
+ /**
+ * Returns the symbols used in this hidden Markov model
+ *
+ * @return
+ */
+ public String getSymbols()
+ {
+ return alphabet;
+ }
+
+ /**
+ * Gets the node in the hidden Markov model at the specified position.
+ *
+ * @param nodeIndex
+ * The index of the node requested. Node 0 optionally contains the
+ * average match emission probabilities across the entire model, and
+ * always contains the insert emission probabilities and state
+ * transition probabilities for the begin node. Node 1 contains the
+ * first node in the HMM that can correspond to a column in the
+ * alignment.
+ * @return
+ */
+ public HMMNode getNode(int nodeIndex)
+ {
+ return nodes.get(nodeIndex);
+ }
+
+ /**
+ * Returns the name of the sequence alignment on which the HMM is based.
+ *
+ * @return
+ */
+ public String getName()
+ {
+ return fileProperties.get(HMMFile.NAME);
+ }
+
+ /**
+ * Answers the string value of the property (parsed from an HMM file) for the
+ * given key, or null if the property is not present
+ *
+ * @param key
+ * @return
+ */
+ public String getProperty(String key)
+ {
+ return fileProperties.get(key);
+ }
+
+ /**
+ * Answers true if the property with the given key is present with a value of
+ * "yes" (not case-sensitive), else false
+ *
+ * @param key
+ * @return
+ */
+ public boolean getBooleanProperty(String key)
+ {
+ return YES.equalsIgnoreCase(fileProperties.get(key));
+ }
+
+ /**
+ * Returns the length of the hidden Markov model. The value returned is the
+ * LENG property if specified, else the number of nodes, excluding the begin
+ * node (which should be the same thing).
+ *
+ * @return
+ */
+ public int getLength()
+ {
+ if (fileProperties.get(HMMFile.LENGTH) == null)
+ {
+ return nodes.size() - 1; // not counting BEGIN node
+ }
+ return Integer.parseInt(fileProperties.get(HMMFile.LENGTH));
+ }
+
+ /**
+ * Returns the value of mandatory property "ALPH" - "amino", "DNA", "RNA" are
+ * the options. Other alphabets may be added.
+ *
+ * @return
+ */
+ public String getAlphabetType()
+ {
+ return fileProperties.get(HMMFile.ALPHABET);
+ }
+
+ /**
+ * Sets the model alphabet to the symbols in the given string (ignoring any
+ * whitespace), and returns the number of symbols
+ *
+ * @param symbols
+ */
+ public int setAlphabet(String symbols)
+ {
+ String trimmed = symbols.toUpperCase().replaceAll("\\s", "");
+ int count = trimmed.length();
+ alphabet = trimmed;
+ symbolIndexLookup = new int['Z' - 'A' + 1];
+ Arrays.fill(symbolIndexLookup, -1);
+ int ignored = 0;
+
+ /*
+ * save the symbols in order, and a quick lookup of symbol position
+ */
+ for (short i = 0; i < count; i++)
+ {
+ char symbol = trimmed.charAt(i);
+ if (symbol >= 'A' && symbol <= 'Z'
+ && symbolIndexLookup[symbol - 'A'] == -1)
+ {
+ symbolIndexLookup[symbol - 'A'] = i;
+ }
+ else
+ {
+ System.err
+ .println(
+ "Unexpected or duplicated character in HMM ALPHabet: "
+ + symbol);
+ ignored++;
+ }
+ }
+ return count - ignored;
+ }
+
+ /**
+ * Answers the node of the model corresponding to an aligned column position
+ * (0...), or null if there is no such node
+ *
+ * @param column
+ * @return
+ */
+ HMMNode getNodeForColumn(int column)
+ {
+ /*
+ * if the hmm consensus is gapped at the column,
+ * there is no corresponding node
+ */
+ if (Comparison.isGap(hmmSeq.getCharAt(column)))
+ {
+ return null;
+ }
+
+ /*
+ * find the node (if any) that is mapped to the
+ * consensus sequence residue position at the column
+ */
+ int seqPos = hmmSeq.findPosition(column);
+ int[] nodeNo = mapToHmmConsensus.getMap().locateInFrom(seqPos, seqPos);
+ if (nodeNo != null)
+ {
+ return getNode(nodeNo[0]);
+ }
+ return null;
+ }
+
+ /**
+ * Gets the match emission probability for a given symbol at a column in the
+ * alignment.
+ *
+ * @param alignColumn
+ * The index of the alignment column, starting at index 0. Index 0
+ * usually corresponds to index 1 in the HMM.
+ * @param symbol
+ * The symbol for which the desired probability is being requested.
+ * @return
+ *
+ */
+ public double getMatchEmissionProbability(int alignColumn, char symbol)
+ {
+ HMMNode node = getNodeForColumn(alignColumn);
+ int symbolIndex = getSymbolIndex(symbol);
+ if (node != null && symbolIndex != -1)
+ {
+ return node.getMatchEmission(symbolIndex);
+ }
+ return 0D;
+ }
+
+ /**
+ * Gets the insert emission probability for a given symbol at a column in the
+ * alignment.
+ *
+ * @param alignColumn
+ * The index of the alignment column, starting at index 0. Index 0
+ * usually corresponds to index 1 in the HMM.
+ * @param symbol
+ * The symbol for which the desired probability is being requested.
+ * @return
+ *
+ */
+ public double getInsertEmissionProbability(int alignColumn, char symbol)
+ {
+ HMMNode node = getNodeForColumn(alignColumn);
+ int symbolIndex = getSymbolIndex(symbol);
+ if (node != null && symbolIndex != -1)
+ {
+ return node.getInsertEmission(symbolIndex);
+ }
+ return 0D;
+ }
+
+ /**
+ * Gets the state transition probability for a given symbol at a column in the
+ * alignment.
+ *
+ * @param alignColumn
+ * The index of the alignment column, starting at index 0. Index 0
+ * usually corresponds to index 1 in the HMM.
+ * @param symbol
+ * The symbol for which the desired probability is being requested.
+ * @return
+ *
+ */
+ public double getStateTransitionProbability(int alignColumn,
+ int transition)
+ {
+ HMMNode node = getNodeForColumn(alignColumn);
+ if (node != null)
+ {
+ return node.getStateTransition(transition);
+ }
+ return 0D;
+ }
+
+ /**
+ * Returns the sequence position linked to the node at the given index. This
+ * corresponds to an aligned column position (counting from 1).
+ *
+ * @param nodeIndex
+ * The index of the node, starting from index 1. Index 0 is the begin
+ * node, which does not correspond to a column in the alignment.
+ * @return
+ */
+ public int getNodeMapPosition(int nodeIndex)
+ {
+ return nodes.get(nodeIndex).getResidueNumber();
+ }
+
+ /**
+ * Returns the consensus residue at the specified node.
+ *
+ * @param nodeIndex
+ * The index of the specified node.
+ * @return
+ */
+ public char getConsensusResidue(int nodeIndex)
+ {
+ char value = nodes.get(nodeIndex).getConsensusResidue();
+ return value;
+ }
+
+ /**
+ * Returns the reference annotation at the specified node.
+ *
+ * @param nodeIndex
+ * The index of the specified node.
+ * @return
+ */
+ public char getReferenceAnnotation(int nodeIndex)
+ {
+ char value = nodes.get(nodeIndex).getReferenceAnnotation();
+ return value;
+ }
+
+ /**
+ * Returns the mask value at the specified node.
+ *
+ * @param nodeIndex
+ * The index of the specified node.
+ * @return
+ */
+ public char getMaskedValue(int nodeIndex)
+ {
+ char value = nodes.get(nodeIndex).getMaskValue();
+ return value;
+ }
+
+ /**
+ * Returns the consensus structure at the specified node.
+ *
+ * @param nodeIndex
+ * The index of the specified node.
+ * @return
+ */
+ public char getConsensusStructure(int nodeIndex)
+ {
+ char value = nodes.get(nodeIndex).getConsensusStructure();
+ return value;
+ }
+
+ /**
+ * Sets a property read from an HMM file
+ *
+ * @param key
+ * @param value
+ */
+ public void setProperty(String key, String value)
+ {
+ fileProperties.put(key, value);
+ }
+
+ /**
+ * Temporary implementation, should not be used.
+ *
+ * @return
+ */
+ public String getViterbi()
+ {
+ String value;
+ value = fileProperties.get(HMMFile.VITERBI);
+ return value;
+ }
+
+ /**
+ * Temporary implementation, should not be used.
+ *
+ * @return
+ */
+ public String getMSV()
+ {
+ String value;
+ value = fileProperties.get(HMMFile.MSV);
+ return value;
+ }
+
+ /**
+ * Temporary implementation, should not be used.
+ *
+ * @return
+ */
+ public String getForward()
+ {
+ String value;
+ value = fileProperties.get(HMMFile.FORWARD);
+ return value;
+ }
+
+ /**
+ * Constructs the consensus sequence based on the most probable symbol at each
+ * position. Gap characters are inserted for discontinuities in the node map
+ * numbering (if provided), else an ungapped sequence is generated.
+ *
+ * A mapping between the HMM nodes and residue positions of the sequence is
+ * also built and saved.
+ *
+ * @return
+ */
+ void buildConsensusSequence()
+ {
+ List toResidues = new ArrayList<>();
+
+ /*
+ * if the HMM provided a map to sequence, use those start/end values,
+ * else just treat it as for a contiguous sequence numbered from 1
+ */
+ boolean hasMap = getBooleanProperty(HMMFile.MAP);
+ int start = hasMap ? getNode(1).getResidueNumber() : 1;
+ int endResNo = hasMap ? getNode(nodes.size() - 1).getResidueNumber()
+ : (start + getLength() - 1);
+ char[] sequence = new char[endResNo];
+
+ int lastResNo = start - 1;
+ int seqOffset = -1;
+ int gapCount = 0;
+
+
+ for (int seqN = 0; seqN < start; seqN++)
+ {
+ sequence[seqN] = GAP_DASH;
+ seqOffset++;
+ }
+
+ for (int nodeNo = 1; nodeNo < nodes.size(); nodeNo++)
+ {
+ HMMNode node = nodes.get(nodeNo);
+ final int resNo = hasMap ? node.getResidueNumber() : lastResNo + 1;
+
+ /*
+ * insert gaps if map numbering is not continuous
+ */
+ while (resNo > lastResNo + 1)
+ {
+ sequence[seqOffset++] = GAP_DASH;
+ lastResNo++;
+ gapCount++;
+ }
+ char consensusResidue = node.getConsensusResidue();
+ if (GAP_DASH == consensusResidue)
+ {
+ /*
+ * no residue annotation in HMM - scan for the symbol
+ * with the highest match emission probability
+ */
+ int symbolIndex = node.getMaxMatchEmissionIndex();
+ consensusResidue = alphabet.charAt(symbolIndex);
+ if (node.getMatchEmission(symbolIndex) < 0.5D)
+ {
+ // follow convention of lower case if match emission prob < 0.5
+ consensusResidue = Character.toLowerCase(consensusResidue);
+ }
+ }
+ sequence[seqOffset++] = consensusResidue;
+ lastResNo = resNo;
+ }
+
+ Sequence seq = new Sequence(getName(), sequence, start,
+ lastResNo - gapCount);
+ seq.createDatasetSequence();
+ seq.setHMM(this);
+ this.hmmSeq = seq;
+
+ /*
+ * construct and store Mapping of nodes to residues
+ * note as constructed this is just an identity mapping,
+ * but it allows for greater flexibility in future
+ */
+ List fromNodes = new ArrayList<>();
+ fromNodes.add(new int[] { 1, getLength() });
+ toResidues.add(new int[] { seq.getStart(), seq.getEnd() });
+ MapList mapList = new MapList(fromNodes, toResidues, 1, 1);
+ mapToHmmConsensus = new Mapping(seq.getDatasetSequence(), mapList);
+ }
+
+
+ /**
+ * Answers the aligned consensus sequence for the profile. Note this will
+ * return null if called before setNodes
has been called.
+ *
+ * @return
+ */
+ public SequenceI getConsensusSequence()
+ {
+ return hmmSeq;
+ }
+
+ /**
+ * Answers the index position (0...) of the given symbol, or -1 if not a valid
+ * symbol for this HMM
+ *
+ * @param symbol
+ * @return
+ */
+ private int getSymbolIndex(char symbol)
+ {
+ /*
+ * symbolIndexLookup holds the index for 'A' to 'Z'
+ */
+ char c = Character.toUpperCase(symbol);
+ if ('A' <= c && c <= 'Z')
+ {
+ return symbolIndexLookup[c - 'A'];
+ }
+ return -1;
+ }
+
+ /**
+ * Sets the nodes of this HMM, and also extracts the HMM consensus sequence
+ * and a mapping between node numbers and sequence positions
+ *
+ * @param nodeList
+ */
+ public void setNodes(List nodeList)
+ {
+ nodes = nodeList;
+ if (nodes.size() > 1)
+ {
+ buildConsensusSequence();
+ }
+ }
+
+ /**
+ * Sets the aligned consensus sequence this HMM is the model for
+ *
+ * @param hmmSeq
+ */
+ public void setHmmSeq(SequenceI hmmSeq)
+ {
+ this.hmmSeq = hmmSeq;
+ }
+
+ public void setBackgroundFrequencies(Map bkgdFreqs)
+ {
+ backgroundFrequencies = bkgdFreqs;
+ }
+
+ public void setBackgroundFrequencies(ResidueCount bkgdFreqs)
+ {
+ backgroundFrequencies = new HashMap<>();
+
+ int total = bkgdFreqs.getTotalResidueCount();
+
+ for (char c : bkgdFreqs.getSymbolCounts().symbols)
+ {
+ backgroundFrequencies.put(c, bkgdFreqs.getCount(c) * 1f / total);
+ }
+
+ }
+
+ public Map getBackgroundFrequencies()
+ {
+ return backgroundFrequencies;
+ }
+
+}
+
diff --git a/src/jalview/datamodel/ResidueCount.java b/src/jalview/datamodel/ResidueCount.java
index 74eb887..047b7e7 100644
--- a/src/jalview/datamodel/ResidueCount.java
+++ b/src/jalview/datamodel/ResidueCount.java
@@ -25,6 +25,8 @@ import jalview.util.Format;
import jalview.util.QuickSort;
import jalview.util.SparseCount;
+import java.util.List;
+
/**
* A class to count occurrences of residues in a profile, optimised for speed
* and memory footprint.
@@ -148,6 +150,24 @@ public class ResidueCount
}
/**
+ * A constructor that counts frequency of all symbols (including gaps) in the
+ * sequences (not case-sensitive)
+ *
+ * @param sequences
+ */
+ public ResidueCount(List sequences)
+ {
+ this();
+ for (SequenceI seq : sequences)
+ {
+ for (int i = 0; i < seq.getLength(); i++)
+ {
+ add(seq.getCharAt(i));
+ }
+ }
+ }
+
+ /**
* Increments the count for the given character. The supplied character may be
* upper or lower case but counts are for the upper case only. Gap characters
* (space, ., -) are all counted together.
@@ -640,4 +660,19 @@ public class ResidueCount
sb.append("]");
return sb.toString();
}
+
+ /**
+ * Answers the total count for all symbols (excluding gaps)
+ *
+ * @return
+ */
+ public int getTotalResidueCount()
+ {
+ int total = 0;
+ for (char symbol : this.getSymbolCounts().symbols)
+ {
+ total += getCount(symbol);
+ }
+ return total;
+ }
}
diff --git a/src/jalview/datamodel/Sequence.java b/src/jalview/datamodel/Sequence.java
index 552349f..009a290 100755
--- a/src/jalview/datamodel/Sequence.java
+++ b/src/jalview/datamodel/Sequence.java
@@ -27,6 +27,7 @@ import jalview.util.Comparison;
import jalview.util.DBRefUtils;
import jalview.util.MapList;
import jalview.util.StringUtils;
+import jalview.workers.InformationThread;
import java.util.ArrayList;
import java.util.Arrays;
@@ -82,6 +83,10 @@ public class Sequence extends ASequence implements SequenceI
private String vamsasId;
+ HiddenMarkovModel hmm;
+
+ boolean isHMMConsensusSequence = false;
+
private DBModList dbrefs; // controlled access
/**
@@ -361,6 +366,11 @@ public class Sequence extends ASequence implements SequenceI
this.addPDBId(new PDBEntry(pdb));
}
}
+ if (seq.getHMM() != null)
+ {
+ this.hmm = new HiddenMarkovModel(seq.getHMM(), this);
+ }
+
}
@Override
@@ -1069,7 +1079,8 @@ public class Sequence extends ASequence implements SequenceI
@Override
public ContiguousI findPositions(int fromColumn, int toColumn)
{
- if (toColumn < fromColumn || fromColumn < 1)
+ fromColumn = Math.max(fromColumn, 1);
+ if (toColumn < fromColumn)
{
return null;
}
@@ -1804,7 +1815,8 @@ public class Sequence extends ASequence implements SequenceI
{
for (AlignmentAnnotation ann : annotation)
{
- if (ann.calcId != null && ann.calcId.equals(calcId)
+ String id = ann.getCalcId();
+ if (id != null && id.equals(calcId)
&& ann.label != null && ann.label.equals(label))
{
result.add(ann);
@@ -1924,6 +1936,34 @@ public class Sequence extends ASequence implements SequenceI
}
}
+ @Override
+ public HiddenMarkovModel getHMM()
+ {
+ return hmm;
+ }
+
+ @Override
+ public void setHMM(HiddenMarkovModel hmm)
+ {
+ this.hmm = hmm;
+ }
+
+ @Override
+ public boolean hasHMMAnnotation()
+ {
+ if (this.annotation == null) {
+ return false;
+ }
+ for (AlignmentAnnotation ann : annotation)
+ {
+ if (InformationThread.HMM_CALC_ID.equals(ann.getCalcId()))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* {@inheritDoc}
*/
@@ -2088,4 +2128,10 @@ public class Sequence extends ASequence implements SequenceI
// otherwise, sequence was completely hidden
return 0;
}
+
+ @Override
+ public boolean hasHMMProfile()
+ {
+ return hmm != null;
+ }
}
diff --git a/src/jalview/datamodel/SequenceCollectionI.java b/src/jalview/datamodel/SequenceCollectionI.java
index e2bb5a6..aa15d1f 100644
--- a/src/jalview/datamodel/SequenceCollectionI.java
+++ b/src/jalview/datamodel/SequenceCollectionI.java
@@ -83,4 +83,12 @@ public interface SequenceCollectionI
* @return
*/
boolean isNucleotide();
+
+ /**
+ * Returns the (possibly empty) list of HMM consensus sequences in the
+ * collection
+ *
+ * @return
+ */
+ List getHmmSequences();
}
diff --git a/src/jalview/datamodel/SequenceGroup.java b/src/jalview/datamodel/SequenceGroup.java
index 861595c..0431708 100755
--- a/src/jalview/datamodel/SequenceGroup.java
+++ b/src/jalview/datamodel/SequenceGroup.java
@@ -25,6 +25,8 @@ 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;
@@ -43,11 +45,10 @@ import java.util.Map;
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
- // quick fix for JAL-2665
+ // 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);
@@ -65,40 +66,46 @@ public class SequenceGroup implements AnnotatedCollectionI
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.
+ /*
+ * 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;
- /**
- * group members
+ /*
+ * sequences in the group
*/
private List sequences;
- /**
+ /*
* representative sequence for this group (if any)
*/
private SequenceI seqrep = null;
int width = -1;
- /**
- * Colourscheme applied to group if any
+ /*
+ * colour scheme applied to group if any
*/
public ResidueShaderI cs;
@@ -122,22 +129,29 @@ public class SequenceGroup implements AnnotatedCollectionI
public Color textColour2 = Color.white;
- /**
- * consensus calculation property
+ /*
+ * properties for consensus annotation
*/
private boolean ignoreGapsInConsensus = true;
- /**
- * consensus calculation property
- */
private boolean showSequenceLogo = false;
- /**
- * flag indicating if logo should be rendered normalised
- */
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;
@@ -145,18 +159,22 @@ public class SequenceGroup implements AnnotatedCollectionI
/*
* visibility of columns intersecting this group
*/
- private boolean hidecols = false;
+ private boolean hidecols;
AlignmentAnnotation consensus = null;
AlignmentAnnotation conservation = null;
+ private AlignmentAnnotation hmmInformation;
+
private boolean showConsensusHistogram;
-
+
private AnnotatedCollectionI context;
+
/**
- * Creates a new SequenceGroup object.
+ * Constructor, assigning a generated default name of "JGroup:" with object
+ * hashcode appended
*/
public SequenceGroup()
{
@@ -199,10 +217,13 @@ public class SequenceGroup implements AnnotatedCollectionI
* 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<>();
@@ -228,6 +249,9 @@ public class SequenceGroup implements AnnotatedCollectionI
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;
@@ -236,8 +260,12 @@ public class SequenceGroup implements AnnotatedCollectionI
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(); // ??
}
@@ -580,8 +608,9 @@ public class SequenceGroup implements AnnotatedCollectionI
}
/**
- * calculate residue conservation for group - but only if necessary. returns
- * true if the calculation resulted in a visible change to group
+ * 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
@@ -589,7 +618,8 @@ public class SequenceGroup implements AnnotatedCollectionI
*/
public boolean recalcConservation(boolean defer)
{
- if (cs == null && consensus == null && conservation == null)
+ if (cs == null && consensus == null && conservation == null
+ && hmmInformation == null)
{
return false;
}
@@ -600,6 +630,16 @@ public class SequenceGroup implements AnnotatedCollectionI
{
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());
@@ -700,6 +740,33 @@ public class SequenceGroup implements AnnotatedCollectionI
}
/**
+ * 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
@@ -1156,6 +1223,22 @@ public class SequenceGroup implements AnnotatedCollectionI
}
/**
+ * 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
*
@@ -1242,6 +1325,26 @@ public class SequenceGroup implements AnnotatedCollectionI
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
@@ -1485,4 +1588,70 @@ public class SequenceGroup implements AnnotatedCollectionI
{
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 getHmmSequences()
+ {
+ List result = new ArrayList<>();
+ for (int i = 0; i < sequences.size(); i++)
+ {
+ SequenceI seq = sequences.get(i);
+ if (seq.hasHMMProfile())
+ {
+ result.add(seq);
+ }
+ }
+ return result;
+ }
+
}
diff --git a/src/jalview/datamodel/SequenceI.java b/src/jalview/datamodel/SequenceI.java
index 933f332..72ce22c 100755
--- a/src/jalview/datamodel/SequenceI.java
+++ b/src/jalview/datamodel/SequenceI.java
@@ -48,6 +48,10 @@ public interface SequenceI extends ASequenceI
*/
public void setName(String name);
+ public HiddenMarkovModel getHMM();
+
+ public void setHMM(HiddenMarkovModel hmm);
+
/**
* Get the display name
*/
@@ -215,10 +219,10 @@ public interface SequenceI extends ASequenceI
* from 1), or null if no residues are included in the range
*
* @param fromColum
- * - first column base 1
+ * - first column base 1. (0 and negative positions are rounded up)
* @param toColumn
* - last column, base 1
- * @return
+ * @return null if fromColum>toColumn
*/
public ContiguousI findPositions(int fromColum, int toColumn);
@@ -506,6 +510,12 @@ public interface SequenceI extends ASequenceI
public List getPrimaryDBRefs();
/**
+ * Answers true if the sequence has annotation for Hidden Markov Model
+ * information content, else false
+ */
+ boolean hasHMMAnnotation();
+
+ /**
* Returns a (possibly empty) list of sequence features that overlap the given
* alignment column range, optionally restricted to one or more specified
* feature types. If the range is all gaps, then features which enclose it are
@@ -542,7 +552,7 @@ public interface SequenceI extends ASequenceI
* @param c1
* @param c2
*/
- public int replace(char c1, char c2);
+ int replace(char c1, char c2);
/**
* Answers the GeneLociI, or null if not known
@@ -572,7 +582,7 @@ public interface SequenceI extends ASequenceI
* the iterator to use
* @return a String corresponding to the sequence
*/
- public String getSequenceStringFromIterator(Iterator it);
+ String getSequenceStringFromIterator(Iterator it);
/**
* Locate the first position in this sequence which is not contained in an
@@ -582,8 +592,15 @@ public interface SequenceI extends ASequenceI
* iterator over regions
* @return first residue not contained in regions
*/
+
public int firstResidueOutsideIterator(Iterator it);
+ /**
+ * Answers true if this sequence has an associated Hidden Markov Model
+ *
+ * @return
+ */
+ boolean hasHMMProfile();
}
diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java
index 5f7d0d4..9d8407a 100644
--- a/src/jalview/gui/AlignFrame.java
+++ b/src/jalview/gui/AlignFrame.java
@@ -64,6 +64,13 @@ import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
import jalview.gui.ColourMenuHelper.ColourChangeListener;
import jalview.gui.ViewSelectionMenu.ViewSetProvider;
+import jalview.hmmer.HMMAlign;
+import jalview.hmmer.HMMBuild;
+import jalview.hmmer.HMMERParamStore;
+import jalview.hmmer.HMMERPreset;
+import jalview.hmmer.HMMSearch;
+import jalview.hmmer.HmmerCommand;
+import jalview.hmmer.JackHMMER;
import jalview.io.AlignmentProperties;
import jalview.io.AnnotationFile;
import jalview.io.BackupFiles;
@@ -98,10 +105,23 @@ import jalview.viewmodel.AlignmentViewport;
import jalview.viewmodel.ViewportRanges;
import jalview.ws.DBRefFetcher;
import jalview.ws.DBRefFetcher.FetchFinishedListenerI;
+import jalview.ws.ServiceChangeListener;
+import jalview.ws.WSDiscovererI;
+import jalview.ws.api.ServiceWithParameters;
import jalview.ws.jws1.Discoverer;
import jalview.ws.jws2.Jws2Discoverer;
-import jalview.ws.jws2.jabaws2.Jws2Instance;
+import jalview.ws.jws2.PreferredServiceRegistry;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.ParamDatastoreI;
+import jalview.ws.params.WsParamSetI;
import jalview.ws.seqfetcher.DbSourceProxy;
+import jalview.ws.slivkaws.SlivkaWSDiscoverer;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.swing.JFileChooser;
+import javax.swing.JOptionPane;
import java.awt.BorderLayout;
import java.awt.Color;
@@ -130,12 +150,14 @@ import java.awt.event.MouseEvent;
import java.awt.print.PageFormat;
import java.awt.print.PrinterJob;
import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Deque;
import java.util.Enumeration;
import java.util.Hashtable;
@@ -154,6 +176,8 @@ import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
+import javax.swing.event.InternalFrameAdapter;
+import javax.swing.event.InternalFrameEvent;
import ext.vamsas.ServiceHandle;
@@ -164,8 +188,9 @@ import ext.vamsas.ServiceHandle;
* @version $Revision$
*/
@SuppressWarnings("serial")
-public class AlignFrame extends GAlignFrame implements DropTargetListener,
- IProgressIndicator, AlignViewControllerGuiI, ColourChangeListener
+public class AlignFrame extends GAlignFrame
+ implements DropTargetListener, IProgressIndicator,
+ AlignViewControllerGuiI, ColourChangeListener, ServiceChangeListener
{
public static int frameCount;
@@ -195,6 +220,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
*/
String fileName = null;
+ /**
+ * TODO: remove reference to 'FileObject' in AlignFrame - not correct mapping
+ */
File fileObject;
private int id;
@@ -357,7 +385,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
void init()
{
-
boolean newPanel = (alignPanel == null);
viewport.setShowAutocalculatedAbove(isShowAutoCalculatedAbove());
if (newPanel)
@@ -434,9 +461,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
if (Desktop.getDesktopPane() != null)
{
this.setDropTarget(new java.awt.dnd.DropTarget(this, this));
+ addServiceListeners();
if (!Platform.isJS())
{
- addServiceListeners();
}
setGUINucleotide();
}
@@ -855,6 +882,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
ap.av.updateConservation(ap);
ap.av.updateConsensus(ap);
ap.av.updateStrucConsensus(ap);
+ ap.av.initInformationWorker(ap);
}
}
}
@@ -874,58 +902,43 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
return viewport;
}
+ @Override
+ public void servicesChanged(WSDiscovererI discoverer,
+ Collection extends ServiceWithParameters> services)
+ {
+ buildWebServicesMenu();
+ }
+
/* Set up intrinsic listeners for dynamically generated GUI bits. */
private void addServiceListeners()
{
- final java.beans.PropertyChangeListener thisListener;
- Desktop.getInstance().addJalviewPropertyChangeListener("services",
- thisListener = new java.beans.PropertyChangeListener()
- {
-
- @Override
- public void propertyChange(PropertyChangeEvent evt)
- {
- // // System.out.println("Discoverer property change.");
- // if (evt.getPropertyName().equals("services"))
- {
- SwingUtilities.invokeLater(new Runnable()
- {
-
- @Override
- public void run()
- {
- System.err.println(
- "Rebuild WS Menu for service change");
- BuildWebServiceMenu();
- }
-
- });
- }
- }
- });
- addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
+ if (Cache.getDefault("SHOW_SLIVKA_SERVICES", true))
{
-
+ WSDiscovererI discoverer = SlivkaWSDiscoverer.getInstance();
+ discoverer.addServiceChangeListener(this);
+ }
+ if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
+ {
+ WSDiscovererI discoverer = Jws2Discoverer.getInstance();
+ discoverer.addServiceChangeListener(this);
+ }
+ // legacy event listener for compatibility with jws1
+ PropertyChangeListener legacyListener = (changeEvent) -> {
+ buildWebServicesMenu();
+ };
+ Desktop.getInstance().addJalviewPropertyChangeListener("services",legacyListener);
+
+ addInternalFrameListener(new InternalFrameAdapter() {
@Override
- public void internalFrameClosed(
- javax.swing.event.InternalFrameEvent evt)
- {
- // System.out.println("deregistering discoverer listener");
- Desktop.getInstance().removeJalviewPropertyChangeListener(
- "services", thisListener);
+ public void internalFrameClosed(InternalFrameEvent e) {
+ System.out.println("deregistering discoverer listener");
+ SlivkaWSDiscoverer.getInstance().removeServiceChangeListener(AlignFrame.this);
+ Jws2Discoverer.getInstance().removeServiceChangeListener(AlignFrame.this);
+ Desktop.getInstance().removeJalviewPropertyChangeListener("services", legacyListener);
closeMenuItem_actionPerformed(true);
}
});
- // Finally, build the menu once to get current service state
- new Thread(new Runnable()
- {
-
- @Override
- public void run()
- {
- BuildWebServiceMenu();
- }
- }).start();
+ buildWebServicesMenu();
}
/**
@@ -999,6 +1012,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
showConsensusHistogram.setSelected(av.isShowConsensusHistogram());
showSequenceLogo.setSelected(av.isShowSequenceLogo());
normaliseSequenceLogo.setSelected(av.isNormaliseSequenceLogo());
+ showInformationHistogram.setSelected(av.isShowInformationHistogram());
+ showHMMSequenceLogo.setSelected(av.isShowHMMSequenceLogo());
+ normaliseHMMSequenceLogo.setSelected(av.isNormaliseHMMSequenceLogo());
ColourMenuHelper.setColourSelected(colourMenu,
av.getGlobalColourScheme());
@@ -1043,6 +1059,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
{
progressBar.setProgressBar(message, id);
}
+
+ @Override
+ public void removeProgressBar(long id)
+ {
+ progressBar.removeProgressBar(id);
+ }
@Override
public void registerHandler(final long id,
@@ -1101,6 +1123,257 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
}
@Override
+ public void hmmBuild_actionPerformed(boolean withDefaults)
+ {
+ if (!alignmentIsSufficient(1))
+ {
+ return;
+ }
+
+ /*
+ * get default parameters, and optionally show a dialog
+ * to allow them to be modified
+ */
+ ParamDatastoreI store = HMMERParamStore.forBuild(viewport);
+ List args = store.getServiceParameters();
+
+ if (!withDefaults)
+ {
+ WsParamSetI set = new HMMERPreset();
+ WsJobParameters params = new WsJobParameters(store, set, args);
+ if (params.showRunDialog())
+ {
+ args = params.getJobParams();
+ }
+ else
+ {
+ return; // user cancelled
+ }
+ }
+ new Thread(new HMMBuild(this, args)).start();
+ }
+
+ @Override
+ public void hmmAlign_actionPerformed(boolean withDefaults)
+ {
+ if (!(checkForHMM() && alignmentIsSufficient(2)))
+ {
+ return;
+ }
+
+ /*
+ * get default parameters, and optionally show a dialog
+ * to allow them to be modified
+ */
+ ParamDatastoreI store = HMMERParamStore.forAlign(viewport);
+ List args = store.getServiceParameters();
+
+ if (!withDefaults)
+ {
+ WsParamSetI set = new HMMERPreset();
+ WsJobParameters params = new WsJobParameters(store, set, args);
+ if (params.showRunDialog())
+ {
+ args = params.getJobParams();
+ }
+ else
+ {
+ return; // user cancelled
+ }
+ }
+ new Thread(new HMMAlign(this, args)).start();
+ }
+
+ @Override
+ public void hmmSearch_actionPerformed(boolean withDefaults)
+ {
+ if (!checkForHMM())
+ {
+ return;
+ }
+
+ /*
+ * get default parameters, and (if requested) show
+ * dialog to allow modification
+ */
+ ParamDatastoreI store = HMMERParamStore.forSearch(viewport);
+ List args = store.getServiceParameters();
+
+ if (!withDefaults)
+ {
+ WsParamSetI set = new HMMERPreset();
+ WsJobParameters params = new WsJobParameters(store, set, args);
+ if (params.showRunDialog())
+ {
+ args = params.getJobParams();
+ }
+ else
+ {
+ return; // user cancelled
+ }
+ }
+ new Thread(new HMMSearch(this, args)).start();
+ alignPanel.repaint();
+ }
+
+ @Override
+ public void jackhmmer_actionPerformed(boolean withDefaults)
+ {
+
+ /*
+ * get default parameters, and (if requested) show
+ * dialog to allow modification
+ */
+
+ ParamDatastoreI store = HMMERParamStore.forJackhmmer(viewport);
+ List args = store.getServiceParameters();
+
+ if (!withDefaults)
+ {
+ WsParamSetI set = new HMMERPreset();
+ WsJobParameters params = new WsJobParameters(store, set, args);
+ if (params.showRunDialog())
+ {
+ args = params.getJobParams();
+ }
+ else
+ {
+ return; // user cancelled
+ }
+ }
+ new Thread(new JackHMMER(this, args)).start();
+ alignPanel.repaint();
+
+ }
+
+ /**
+ * Checks if the alignment has at least one hidden Markov model, if not shows
+ * a dialog advising to run hmmbuild or load an HMM profile
+ *
+ * @return
+ */
+ private boolean checkForHMM()
+ {
+ if (viewport.getAlignment().getHmmSequences().isEmpty())
+ {
+ JOptionPane.showMessageDialog(this,
+ MessageManager.getString("warn.no_hmm"));
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ protected void filterByEValue_actionPerformed()
+ {
+ viewport.filterByEvalue(inputDouble("Enter E-Value Cutoff"));
+ }
+
+ @Override
+ protected void filterByScore_actionPerformed()
+ {
+ viewport.filterByScore(inputDouble("Enter Bit Score Threshold"));
+ }
+
+ private double inputDouble(String message)
+ {
+ String str = null;
+ Double d = null;
+ while (d == null || d <= 0)
+ {
+ str = JOptionPane.showInputDialog(this.alignPanel, message);
+ try
+ {
+ d = Double.valueOf(str);
+ } catch (NumberFormatException e)
+ {
+ }
+ }
+ return d;
+ }
+
+ /**
+ * Checks if the alignment contains the required number of sequences.
+ *
+ * @param required
+ * @return
+ */
+ public boolean alignmentIsSufficient(int required)
+ {
+ if (getViewport().getSequenceSelection().length < required)
+ {
+ JOptionPane.showMessageDialog(this,
+ MessageManager.getString("label.not_enough_sequences"));
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Opens a file browser and adds the selected file, if in Fasta, Stockholm or
+ * Pfam format, to the list held under preference key "HMMSEARCH_DBS" (as a
+ * comma-separated list)
+ */
+ @Override
+ public void addDatabase_actionPerformed() throws IOException
+ {
+ if (Cache.getProperty(Preferences.HMMSEARCH_DBS) == null)
+ {
+ Cache.setProperty(Preferences.HMMSEARCH_DBS, "");
+ }
+
+ String path = openFileChooser(false);
+ if (path != null && new File(path).exists())
+ {
+ IdentifyFile identifier = new IdentifyFile();
+ FileFormatI format = identifier.identify(path, DataSourceType.FILE);
+ if (format == FileFormat.Fasta || format == FileFormat.Stockholm
+ || format == FileFormat.Pfam)
+ {
+ String currentDbPaths = Cache
+ .getProperty(Preferences.HMMSEARCH_DBS);
+ currentDbPaths += Preferences.COMMA + path;
+ Cache.setProperty(Preferences.HMMSEARCH_DBS, currentDbPaths);
+ }
+ else
+ {
+ JOptionPane.showMessageDialog(this,
+ MessageManager.getString("warn.invalid_format"));
+ }
+ }
+ }
+
+ /**
+ * Opens a file chooser, optionally restricted to selecting folders
+ * (directories) only. Answers the path to the selected file or folder, or
+ * null if none is chosen.
+ *
+ * @param
+ * @return
+ */
+ protected String openFileChooser(boolean forFolder)
+ {
+ // TODO duplicates GPreferences method - relocate to JalviewFileChooser?
+ String choice = null;
+ JFileChooser chooser = new JFileChooser();
+ if (forFolder)
+ {
+ chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+ }
+ chooser.setDialogTitle(
+ MessageManager.getString("label.open_local_file"));
+ chooser.setToolTipText(MessageManager.getString("action.open"));
+
+ int value = chooser.showOpenDialog(this);
+
+ if (value == JFileChooser.APPROVE_OPTION)
+ {
+ choice = chooser.getSelectedFile().getPath();
+ }
+ return choice;
+ }
+
+ @Override
public void reload_actionPerformed(ActionEvent e)
{
if (fileName == null && fileObject == null)
@@ -1570,6 +1843,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
@Override
public void associatedData_actionPerformed(ActionEvent e)
+ throws IOException, InterruptedException
{
final JalviewFileChooser chooser = new JalviewFileChooser(
jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
@@ -2070,10 +2344,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
*
* @param e
* DOCUMENT ME!
+ * @throws InterruptedException
+ * @throws IOException
*/
@Override
protected void pasteNew_actionPerformed(ActionEvent e)
+ throws IOException, InterruptedException
{
paste(true);
}
@@ -2083,10 +2360,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
*
* @param e
* DOCUMENT ME!
+ * @throws InterruptedException
+ * @throws IOException
*/
@Override
protected void pasteThis_actionPerformed(ActionEvent e)
+ throws IOException, InterruptedException
{
paste(false);
}
@@ -2096,9 +2376,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
*
* @param newAlignment
* true to paste to a new alignment, otherwise add to this.
+ * @throws InterruptedException
+ * @throws IOException
*/
-
- void paste(boolean newAlignment)
+ void paste(boolean newAlignment) throws IOException, InterruptedException
{
boolean externalPaste = true;
try
@@ -2427,7 +2708,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
System.out.println("Exception whilst pasting: " + ex);
// could be anything being pasted in here
}
-
}
@Override
@@ -3794,6 +4074,28 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
alignPanel.paintAlignment(true, false);
}
+ @Override
+ public void sortEValueMenuItem_actionPerformed(ActionEvent e)
+ {
+ SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
+ AlignmentSorter.sortByEValue(viewport.getAlignment());
+ addHistoryItem(new OrderCommand("Group Sort", oldOrder,
+ viewport.getAlignment()));
+ alignPanel.paintAlignment(true, false);
+
+ }
+
+ @Override
+ public void sortBitScoreMenuItem_actionPerformed(ActionEvent e)
+ {
+ SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
+ AlignmentSorter.sortByBitScore(viewport.getAlignment());
+ addHistoryItem(new OrderCommand("Group Sort", oldOrder,
+ viewport.getAlignment()));
+ alignPanel.paintAlignment(true, false);
+
+ }
+
/**
* DOCUMENT ME!
*
@@ -4015,34 +4317,33 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
}
if (viewport.getAlignment().getAlignmentAnnotation()
- .hashCode() != _annotationScoreVectorHash)
+ .hashCode() == _annotationScoreVectorHash)
+ {
+ return;
+ }
+
+ sortByAnnotScore.removeAll();
+ Set scoreSorts = new HashSet<>();
+ for (SequenceI sqa : viewport.getAlignment().getSequences())
{
- sortByAnnotScore.removeAll();
- // almost certainly a quicker way to do this - but we keep it simple
- Hashtable scoreSorts = new Hashtable<>();
- AlignmentAnnotation aann[];
- for (SequenceI sqa : viewport.getAlignment().getSequences())
+ AlignmentAnnotation[] anns = sqa.getAnnotation();
+ for (int i = 0; anns != null && i < anns.length; i++)
{
- aann = sqa.getAnnotation();
- for (int i = 0; aann != null && i < aann.length; i++)
+ AlignmentAnnotation aa = anns[i];
+ if (aa != null && aa.hasScore() && aa.sequenceRef != null)
{
- if (aann[i].hasScore() && aann[i].sequenceRef != null)
- {
- scoreSorts.put(aann[i].label, aann[i].label);
- }
+ scoreSorts.add(aa.label);
}
}
- Enumeration labels = scoreSorts.keys();
- while (labels.hasMoreElements())
- {
- addSortByAnnotScoreMenuItem(sortByAnnotScore, labels.nextElement());
- }
- sortByAnnotScore.setVisible(scoreSorts.size() > 0);
- scoreSorts.clear();
-
- _annotationScoreVectorHash = viewport.getAlignment()
- .getAlignmentAnnotation().hashCode();
}
+ for (String label : scoreSorts)
+ {
+ addSortByAnnotScoreMenuItem(sortByAnnotScore, label);
+ }
+ sortByAnnotScore.setVisible(!scoreSorts.isEmpty());
+
+ _annotationScoreVectorHash = viewport.getAlignment()
+ .getAlignmentAnnotation().hashCode();
}
/**
@@ -4324,185 +4625,80 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
return tp;
}
- private boolean buildingMenu = false;
-
/**
- * Generates menu items and listener event actions for web service clients
- *
+ * Schedule the web services menu rebuild to the event dispatch thread.
*/
-
- public void BuildWebServiceMenu()
+ public void buildWebServicesMenu()
{
- while (buildingMenu)
- {
- try
+ SwingUtilities.invokeLater(() -> {
+ Cache.log.info("Rebuiling WS menu");
+ webService.removeAll();
+ if (Cache.getDefault("SHOW_SLIVKA_SERVICES", true))
{
- System.err.println("Waiting for building menu to finish.");
- Thread.sleep(10);
- } catch (Exception e)
+ Cache.log.info("Building web service menu for slivka");
+ SlivkaWSDiscoverer discoverer = SlivkaWSDiscoverer.getInstance();
+ JMenu submenu = new JMenu("Slivka");
+ buildWebServicesMenu(discoverer, submenu);
+ webService.add(submenu);
+ }
+ if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
{
+ WSDiscovererI jws2servs = Jws2Discoverer.getInstance();
+ JMenu submenu = new JMenu("JABAWS");
+ buildLegacyWebServicesMenu(submenu);
+ buildWebServicesMenu(jws2servs, submenu);
+ webService.add(submenu);
}
- }
- final AlignFrame me = this;
- buildingMenu = true;
- new Thread(new Runnable()
- {
+ });
+ }
- @Override
- public void run()
+ private void buildLegacyWebServicesMenu(JMenu menu)
+ {
+ JMenu secstrmenu = new JMenu("Secondary Structure Prediction");
+ if (Discoverer.getServices() != null && Discoverer.getServices().size() > 0)
+ {
+ var secstrpred = Discoverer.getServices().get("SecStrPred");
+ if (secstrpred != null)
{
- final List legacyItems = new ArrayList<>();
- try
- {
- // System.err.println("Building ws menu again "
- // + Thread.currentThread());
- // TODO: add support for context dependent disabling of services based
- // on
- // alignment and current selection
- // TODO: add additional serviceHandle parameter to specify abstract
- // handler
- // class independently of AbstractName
- // TODO: add in rediscovery GUI function to restart discoverer
- // TODO: group services by location as well as function and/or
- // introduce
- // object broker mechanism.
- final Vector wsmenu = new Vector<>();
- final IProgressIndicator af = me;
-
- /*
- * do not i18n these strings - they are hard-coded in class
- * compbio.data.msa.Category, Jws2Discoverer.isRecalculable() and
- * SequenceAnnotationWSClient.initSequenceAnnotationWSClient()
- */
- final JMenu msawsmenu = new JMenu("Alignment");
- final JMenu secstrmenu = new JMenu(
- "Secondary Structure Prediction");
- final JMenu seqsrchmenu = new JMenu("Sequence Database Search");
- final JMenu analymenu = new JMenu("Analysis");
- final JMenu dismenu = new JMenu("Protein Disorder");
- // JAL-940 - only show secondary structure prediction services from
- // the legacy server
- Hashtable> ds = Discoverer
- .getInstance().getServices();
- if (// Cache.getDefault("SHOW_JWS1_SERVICES", true)
- // &&
- ds != null && (ds.size() > 0))
- {
- // TODO: refactor to allow list of AbstractName/Handler bindings to
- // be
- // stored or retrieved from elsewhere
- // No MSAWS used any more:
- // Vector msaws = null; // (Vector)
- // Discoverer.services.get("MsaWS");
- Vector secstrpr = ds.get("SecStrPred");
- if (secstrpr != null)
- {
- // Add any secondary structure prediction services
- for (int i = 0, j = secstrpr.size(); i < j; i++)
- {
- final ext.vamsas.ServiceHandle sh = secstrpr.get(i);
- jalview.ws.WSMenuEntryProviderI impl = jalview.ws.jws1.Discoverer
- .getServiceClient(sh);
- int p = secstrmenu.getItemCount();
- impl.attachWSMenuEntry(secstrmenu, me);
- int q = secstrmenu.getItemCount();
- for (int litm = p; litm < q; litm++)
- {
- legacyItems.add(secstrmenu.getItem(litm));
- }
- }
- }
- }
-
- // Add all submenus in the order they should appear on the web
- // services menu
- wsmenu.add(msawsmenu);
- wsmenu.add(secstrmenu);
- wsmenu.add(dismenu);
- wsmenu.add(analymenu);
- // No search services yet
- // wsmenu.add(seqsrchmenu);
-
- javax.swing.SwingUtilities.invokeLater(new Runnable()
- {
-
- @Override
- public void run()
- {
- try
- {
- webService.removeAll();
- // first, add discovered services onto the webservices menu
- if (wsmenu.size() > 0)
- {
- for (int i = 0, j = wsmenu.size(); i < j; i++)
- {
- webService.add(wsmenu.get(i));
- }
- }
- else
- {
- webService.add(me.webServiceNoServices);
- }
- // TODO: move into separate menu builder class.
- // boolean new_sspred = false;
- if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
- {
- Jws2Discoverer jws2servs = Jws2Discoverer.getInstance();
- if (jws2servs != null)
- {
- if (jws2servs.hasServices())
- {
- jws2servs.attachWSMenuEntry(webService, me);
- for (Jws2Instance sv : jws2servs.getServices())
- {
- if (sv.description.toLowerCase().contains("jpred"))
- {
- for (JMenuItem jmi : legacyItems)
- {
- jmi.setVisible(false);
- }
- }
- }
-
- }
- if (jws2servs.isRunning())
- {
- JMenuItem tm = new JMenuItem(
- "Still discovering JABA Services");
- tm.setEnabled(false);
- webService.add(tm);
- }
- }
- }
- build_urlServiceMenu(me.webService);
- build_fetchdbmenu(webService);
- for (JMenu item : wsmenu)
- {
- if (item.getItemCount() == 0)
- {
- item.setEnabled(false);
- }
- else
- {
- item.setEnabled(true);
- }
- }
- } catch (Exception e)
- {
- Cache.log.debug(
- "Exception during web service menu building process.",
- e);
- }
- }
- });
- } catch (Exception e)
+ for (ext.vamsas.ServiceHandle sh : secstrpred)
{
+ var menuProvider = Discoverer.getServiceClient(sh);
+ menuProvider.attachWSMenuEntry(secstrmenu, this);
}
- buildingMenu = false;
}
- }).start();
+ }
+ menu.add(secstrmenu);
+ }
+ /**
+ * Constructs the web services menu for the given discoverer under the
+ * specified menu. This method must be called on the EDT
+ *
+ * @param discoverer
+ * the discoverer used to build the menu
+ * @param menu
+ * parent component which the elements will be attached to
+ */
+ private void buildWebServicesMenu(WSDiscovererI discoverer, JMenu menu)
+ {
+ if (discoverer.hasServices())
+ {
+ PreferredServiceRegistry.getRegistry().populateWSMenuEntry(
+ discoverer.getServices(), sv -> buildWebServicesMenu(), menu,
+ this, null);
+ }
+ if (discoverer.isRunning())
+ {
+ JMenuItem item = new JMenuItem("Service discovery in progress.");
+ item.setEnabled(false);
+ menu.add(item);
+ }
+ else if (!discoverer.hasServices())
+ {
+ JMenuItem item = new JMenuItem("No services available.");
+ item.setEnabled(false);
+ menu.add(item);
+ }
}
/**
@@ -4943,6 +5139,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
*
* @param file
* either a filename or a URL string.
+ * @throws InterruptedException
+ * @throws IOException
*/
public void loadJalviewDataFile(Object file, DataSourceType sourceType,
@@ -6079,6 +6277,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
}
}
+ /**
+ * Sets the status of the HMMER menu
+ */
+ public void updateHMMERStatus()
+ {
+ hmmerMenu.setEnabled(HmmerCommand.isHmmerAvailable());
+ }
+
@Override
protected void loadVcf_actionPerformed()
{
diff --git a/src/jalview/gui/AlignViewport.java b/src/jalview/gui/AlignViewport.java
index 7ab84ad..dca9047 100644
--- a/src/jalview/gui/AlignViewport.java
+++ b/src/jalview/gui/AlignViewport.java
@@ -39,6 +39,7 @@ import jalview.datamodel.SearchResults;
import jalview.datamodel.SearchResultsI;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.FeatureMatcherSetI;
import jalview.renderer.ResidueShader;
import jalview.schemes.ColourSchemeI;
import jalview.schemes.ColourSchemeProperty;
@@ -264,14 +265,13 @@ f */
setFont(new Font(fontName, style, Integer.parseInt(fontSize)), true);
- alignment
- .setGapCharacter(Cache.getDefault("GAP_SYMBOL", "-").charAt(0));
+ alignment.setGapCharacter(Cache.getDefault("GAP_SYMBOL", "-").charAt(0));
// We must set conservation and consensus before setting colour,
// as Blosum and Clustal require this to be done
- if (hconsensus == null && !isDataset)
+ if (hconsensus == null && !isDataset)
{
- if (!alignment.isNucleotide())
+ if (!alignment.isNucleotide())
{
showConservation = Cache.getDefault("SHOW_CONSERVATION", true);
showQuality = Cache.getDefault("SHOW_QUALITY", true);
@@ -283,13 +283,19 @@ f */
showSequenceLogo = Cache.getDefault("SHOW_CONSENSUS_LOGO", false);
normaliseSequenceLogo = Cache.getDefault("NORMALISE_CONSENSUS_LOGO",
false);
+ // for now, use consensus options for Information till it gets its own
+ setShowHMMSequenceLogo(showSequenceLogo);
+ setNormaliseHMMSequenceLogo(normaliseSequenceLogo);
+ setShowInformationHistogram(showConsensusHistogram);
showGroupConsensus = Cache.getDefault("SHOW_GROUP_CONSENSUS", false);
showConsensus = Cache.getDefault("SHOW_IDENTITY", true);
showOccupancy = Cache.getDefault(Preferences.SHOW_OCCUPANCY, true);
}
initAutoAnnotation();
- String colourProperty = alignment.isNucleotide()
+ // initInformation();
+
+ String colourProperty = alignment.isNucleotide()
? Preferences.DEFAULT_COLOUR_NUC
: Preferences.DEFAULT_COLOUR_PROT;
String schemeName = Cache.getProperty(colourProperty);
@@ -312,11 +318,11 @@ f */
if (residueShading != null)
{
- residueShading.setConsensus(hconsensus);
+ residueShading.setConsensus(hconsensus);
}
setColourAppliesToAllGroups(true);
}
-
+
boolean validCharWidth;
/**
@@ -401,7 +407,7 @@ f */
/*
* replace mappings on our alignment
*/
- if (alignment != null && align != null)
+ if (alignment != null && align != null)
{
alignment.setCodonFrames(align.getCodonFrames());
}
@@ -454,7 +460,7 @@ f */
}
/**
- * returns the visible column regions of the alignment
+ * Returns an iterator over the visible column regions of the alignment
*
* @param selectedRegionOnly
* true to just return the contigs intersecting with the selected
@@ -474,8 +480,9 @@ f */
{
end = alignment.getWidth();
}
- return (alignment.getHiddenColumns().getVisContigsIterator(start, end,
- false));
+
+ return (alignment.getHiddenColumns().getVisContigsIterator(start,
+ end, false));
}
/**
@@ -525,7 +532,7 @@ f */
}
public boolean followSelection = true;
-
+
/**
* @return true if view selection should always follow the selections
* broadcast by other selection sources
@@ -590,18 +597,20 @@ f */
return StructureSelectionManager
.getStructureSelectionManager(Desktop.getInstance());
}
-
+
@Override
public boolean isNormaliseSequenceLogo()
{
return normaliseSequenceLogo;
}
- public void setNormaliseSequenceLogo(boolean state)
+ @Override
+public void setNormaliseSequenceLogo(boolean state)
{
normaliseSequenceLogo = state;
}
+
/**
*
* @return true if alignment characters should be displayed
@@ -611,7 +620,7 @@ f */
{
return validCharWidth;
}
-
+
private Hashtable calcIdParams = new Hashtable<>();
public AutoCalcSetting getCalcIdSettingsFor(String calcId)
@@ -1091,6 +1100,9 @@ f */
{
FeatureColourI preferredColour = featureSettings
.getFeatureColour(type);
+ FeatureMatcherSetI preferredFilters = featureSettings
+ .getFeatureFilters(type);
+
FeatureColourI origColour = fr.getFeatureStyle(type);
if (!mergeOnly || (!origRenderOrder.contains(type)
|| origColour == null
@@ -1105,6 +1117,11 @@ f */
{
fr.setColour(type, preferredColour);
}
+ if (preferredFilters != null
+ && (!mergeOnly || fr.getFeatureFilter(type) != null))
+ {
+ fr.setFeatureFilter(type, preferredFilters);
+ }
if (featureSettings.isFeatureDisplayed(type))
{
displayed.setVisible(type);
diff --git a/src/jalview/gui/AnnotationLabels.java b/src/jalview/gui/AnnotationLabels.java
index c843f37..673f04d 100755
--- a/src/jalview/gui/AnnotationLabels.java
+++ b/src/jalview/gui/AnnotationLabels.java
@@ -61,6 +61,7 @@ import jalview.io.FormatAdapter;
import jalview.util.Comparison;
import jalview.util.MessageManager;
import jalview.util.Platform;
+import jalview.workers.InformationThread;
/**
* The panel that holds the labels for alignment annotations, providing
@@ -352,6 +353,10 @@ public class AnnotationLabels extends JPanel
pop.show(this, evt.getX(), evt.getY());
return;
}
+
+ final AlignmentAnnotation ann = aa[selectedRow];
+ final boolean isSequenceAnnotation = ann.sequenceRef != null;
+
item = new JMenuItem(EDITNAME);
item.addActionListener(this);
pop.add(item);
@@ -399,7 +404,8 @@ public class AnnotationLabels extends JPanel
if (selectedRow < aa.length)
{
final String label = aa[selectedRow].label;
- if (!aa[selectedRow].autoCalculated)
+ if (!(aa[selectedRow].autoCalculated)
+ && !(InformationThread.HMM_CALC_ID.equals(ann.getCalcId())))
{
if (aa[selectedRow].graph == AlignmentAnnotation.NO_GRAPH)
{
@@ -407,7 +413,7 @@ public class AnnotationLabels extends JPanel
pop.addSeparator();
// av and sequencegroup need to implement same interface for
item = new JCheckBoxMenuItem(TOGGLE_LABELSCALE,
- aa[selectedRow].scaleColLabel);
+ aa[selectedRow].scaleColLabel);
item.addActionListener(this);
pop.add(item);
}
@@ -420,11 +426,169 @@ public class AnnotationLabels extends JPanel
consclipbrd.addActionListener(this);
pop.add(consclipbrd);
}
+ else if (InformationThread.HMM_CALC_ID.equals(ann.getCalcId()))
+ {
+ addHmmerMenu(pop, ann);
+ }
}
pop.show(this, evt.getX(), evt.getY());
}
/**
+ * Adds context menu options for (alignment or group) Hmmer annotation
+ *
+ * @param pop
+ * @param ann
+ */
+ protected void addHmmerMenu(JPopupMenu pop, final AlignmentAnnotation ann)
+ {
+ final boolean isGroupAnnotation = ann.groupRef != null;
+ pop.addSeparator();
+ final JCheckBoxMenuItem cbmi = new JCheckBoxMenuItem(
+ MessageManager.getString(
+ "label.ignore_below_background_frequency"),
+ isGroupAnnotation
+ ? ann.groupRef
+ .isIgnoreBelowBackground()
+ : ap.av.isIgnoreBelowBackground());
+ cbmi.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ if (isGroupAnnotation)
+ {
+ if (!ann.groupRef.isUseInfoLetterHeight())
+ {
+ ann.groupRef.setIgnoreBelowBackground(cbmi.getState());
+ // todo and recompute group annotation
+ }
+ }
+ else if (!ap.av.isInfoLetterHeight())
+ {
+ ap.av.setIgnoreBelowBackground(cbmi.getState(), ap);
+ // todo and recompute annotation
+ }
+ ap.alignmentChanged(); // todo not like this
+ }
+ });
+ pop.add(cbmi);
+ final JCheckBoxMenuItem letterHeight = new JCheckBoxMenuItem(
+ MessageManager.getString("label.use_info_for_height"),
+ isGroupAnnotation ? ann.groupRef.isUseInfoLetterHeight()
+ : ap.av.isInfoLetterHeight());
+ letterHeight.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ if (isGroupAnnotation)
+ {
+ ann.groupRef.setInfoLetterHeight((letterHeight.getState()));
+ ann.groupRef.setIgnoreBelowBackground(true);
+ // todo and recompute group annotation
+ }
+ else
+ {
+ ap.av.setInfoLetterHeight(letterHeight.getState(), ap);
+ ap.av.setIgnoreBelowBackground(true, ap);
+ // todo and recompute annotation
+ }
+ ap.alignmentChanged();
+ }
+ });
+ pop.add(letterHeight);
+ if (isGroupAnnotation)
+ {
+ final JCheckBoxMenuItem chist = new JCheckBoxMenuItem(
+ MessageManager.getString("label.show_group_histogram"),
+ ann.groupRef.isShowInformationHistogram());
+ chist.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ ann.groupRef.setShowInformationHistogram(chist.getState());
+ ap.repaint();
+ }
+ });
+ pop.add(chist);
+ final JCheckBoxMenuItem cprofl = new JCheckBoxMenuItem(
+ MessageManager.getString("label.show_group_logo"),
+ ann.groupRef.isShowHMMSequenceLogo());
+ cprofl.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ ann.groupRef.setShowHMMSequenceLogo(cprofl.getState());
+ ap.repaint();
+ }
+ });
+ pop.add(cprofl);
+ final JCheckBoxMenuItem cproflnorm = new JCheckBoxMenuItem(
+ MessageManager.getString("label.normalise_group_logo"),
+ ann.groupRef.isNormaliseHMMSequenceLogo());
+ cproflnorm.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ ann.groupRef
+ .setNormaliseHMMSequenceLogo(cproflnorm.getState());
+ // automatically enable logo display if we're clicked
+ ann.groupRef.setShowHMMSequenceLogo(true);
+ ap.repaint();
+ }
+ });
+ pop.add(cproflnorm);
+ }
+ else
+ {
+ final JCheckBoxMenuItem chist = new JCheckBoxMenuItem(
+ MessageManager.getString("label.show_histogram"),
+ av.isShowInformationHistogram());
+ chist.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ av.setShowInformationHistogram(chist.getState());
+ ap.repaint();
+ }
+ });
+ pop.add(chist);
+ final JCheckBoxMenuItem cprof = new JCheckBoxMenuItem(
+ MessageManager.getString("label.show_logo"),
+ av.isShowHMMSequenceLogo());
+ cprof.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ av.setShowHMMSequenceLogo(cprof.getState());
+ ap.repaint();
+ }
+ });
+ pop.add(cprof);
+ final JCheckBoxMenuItem cprofnorm = new JCheckBoxMenuItem(
+ MessageManager.getString("label.normalise_logo"),
+ av.isNormaliseHMMSequenceLogo());
+ cprofnorm.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ av.setShowHMMSequenceLogo(true);
+ av.setNormaliseHMMSequenceLogo(cprofnorm.getState());
+ ap.repaint();
+ }
+ });
+ pop.add(cprofnorm);
+ }
+ }
+
+ /**
* A helper method that adds menu options for calculation and visualisation of
* group and/or alignment consensus annotation to a popup menu. This is
* designed to be reusable for either unwrapped mode (popup menu is shown on
@@ -926,7 +1090,6 @@ public class AnnotationLabels extends JPanel
PaintRefresher.Refresh(ap, ap.av.getSequenceSetId());
ap.av.sendSelection();
}
-
}
}
return;
@@ -990,7 +1153,6 @@ public class AnnotationLabels extends JPanel
@Override
public void paintComponent(Graphics g)
{
-
int width = getWidth();
if (width == 0)
{
@@ -1005,7 +1167,6 @@ public class AnnotationLabels extends JPanel
}
drawComponent(g2, true, width);
-
}
/**
diff --git a/src/jalview/gui/CalculationChooser.java b/src/jalview/gui/CalculationChooser.java
index c69d0a8..46d02f7 100644
--- a/src/jalview/gui/CalculationChooser.java
+++ b/src/jalview/gui/CalculationChooser.java
@@ -23,12 +23,12 @@ package jalview.gui;
import jalview.analysis.TreeBuilder;
import jalview.analysis.scoremodels.ScoreModels;
import jalview.analysis.scoremodels.SimilarityParams;
+import jalview.api.AlignViewportI;
import jalview.api.analysis.ScoreModelI;
import jalview.api.analysis.SimilarityParamsI;
import jalview.bin.Cache;
import jalview.datamodel.SequenceGroup;
import jalview.util.MessageManager;
-
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
@@ -643,7 +643,7 @@ public class CalculationChooser extends JPanel
* gui validation shouldn't allow insufficient sequences here, but leave
* this check in in case this method gets exposed programmatically in future
*/
- AlignViewport viewport = af.getViewport();
+ AlignViewportI viewport = af.getViewport();
SequenceGroup sg = viewport.getSelectionGroup();
if (sg != null && sg.getSize() < MIN_TREE_SELECTION)
{
@@ -671,8 +671,7 @@ public class CalculationChooser extends JPanel
public static Object openPcaPanel(AlignFrame af, String modelName,
SimilarityParamsI params)
{
-
- AlignViewport viewport = af.getViewport();
+ AlignViewportI viewport = af.getViewport();
/*
* gui validation shouldn't allow insufficient sequences here, but leave
diff --git a/src/jalview/gui/Desktop.java b/src/jalview/gui/Desktop.java
index bbd38ec..88c94f6 100644
--- a/src/jalview/gui/Desktop.java
+++ b/src/jalview/gui/Desktop.java
@@ -59,8 +59,11 @@ import java.util.Hashtable;
import java.util.List;
import java.util.ListIterator;
import java.util.Vector;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
import java.util.concurrent.Semaphore;
import javax.swing.AbstractAction;
@@ -123,6 +126,7 @@ import jalview.util.MessageManager;
import jalview.util.Platform;
import jalview.util.UrlConstants;
import jalview.viewmodel.AlignmentViewport;
+import jalview.ws.WSDiscovererI;
import jalview.ws.params.ParamManager;
import jalview.ws.utils.UrlDownloadClient;
@@ -162,6 +166,7 @@ public class Desktop extends GDesktop
public static HashMap savingFiles = new HashMap();
+ @SuppressWarnings("deprecation")
private JalviewChangeSupport changeSupport = new JalviewChangeSupport();
/**
@@ -175,6 +180,7 @@ public class Desktop extends GDesktop
* @param listener
* @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.beans.PropertyChangeListener)
*/
+ @Deprecated
public void addJalviewPropertyChangeListener(
PropertyChangeListener listener)
{
@@ -187,6 +193,7 @@ public class Desktop extends GDesktop
* @see jalview.gui.JalviewChangeSupport#addJalviewPropertyChangeListener(java.lang.String,
* java.beans.PropertyChangeListener)
*/
+ @Deprecated
public void addJalviewPropertyChangeListener(String propertyName,
PropertyChangeListener listener)
{
@@ -199,6 +206,7 @@ public class Desktop extends GDesktop
* @see jalview.gui.JalviewChangeSupport#removeJalviewPropertyChangeListener(java.lang.String,
* java.beans.PropertyChangeListener)
*/
+ @Deprecated
public void removeJalviewPropertyChangeListener(String propertyName,
PropertyChangeListener listener)
{
@@ -1607,7 +1615,8 @@ public class Desktop extends GDesktop
return;
}
- AlignmentViewport source = null, target = null;
+ AlignViewportI source = null;
+ AlignViewportI target = null;
if (frames[0] instanceof AlignFrame)
{
source = ((AlignFrame) frames[0]).getCurrentView();
@@ -2573,6 +2582,13 @@ public class Desktop extends GDesktop
progressBars.put(Long.valueOf(id), addProgressPanel(message));
}
}
+
+ @Override
+ public void removeProgressBar(long id)
+ {
+ //TODO
+ throw new UnsupportedOperationException("not implemented");
+ }
/*
* (non-Javadoc)
@@ -2692,10 +2708,13 @@ public class Desktop extends GDesktop
public void startServiceDiscovery(boolean blocking)
{
- boolean alive = true;
- Thread t0 = null, t1 = null, t2 = null;
+ System.out.println("Starting service discovery");
+ var tasks = new ArrayList>();
// JAL-940 - JALVIEW 1 services are now being EOLed as of JABA 2.1 release
- if (true)
+
+ System.out.println("loading services");
+
+ /** @j2sIgnore */
{
// todo: changesupport handlers need to be transferred
if (discoverer == null)
@@ -2706,31 +2725,30 @@ public class Desktop extends GDesktop
}
// JAL-940 - disabled JWS1 service configuration - always start discoverer
// until we phase out completely
- (t0 = new Thread(discoverer)).start();
+ var f = new FutureTask(discoverer, null);
+ new Thread(f).start();
+ tasks.add(f);
}
if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
{
- t2 = jalview.ws.jws2.Jws2Discoverer.getInstance()
- .startDiscoverer(changeSupport);
+ tasks.add(jalview.ws.jws2.Jws2Discoverer.getInstance().startDiscoverer());
}
- Thread t3 = null;
+ if (Cache.getDefault("SHOW_SLIVKA_SERVICES", true))
{
- // TODO: do rest service discovery
+ tasks.add(jalview.ws.slivkaws.SlivkaWSDiscoverer.getInstance().startDiscoverer());
}
if (blocking)
{
- while (alive)
- {
+ for (Future> task : tasks) {
try
{
- Thread.sleep(15);
+ // block until all discovery tasks are done
+ task.get();
} catch (Exception e)
{
+ e.printStackTrace();
}
- alive = (t1 != null && t1.isAlive()) || (t2 != null && t2.isAlive())
- || (t3 != null && t3.isAlive())
- || (t0 != null && t0.isAlive());
}
}
}
@@ -2744,8 +2762,10 @@ public class Desktop extends GDesktop
{
if (evt.getNewValue() == null || evt.getNewValue() instanceof Vector)
{
- final String ermsg = jalview.ws.jws2.Jws2Discoverer.getInstance()
- .getErrorMessages();
+ final WSDiscovererI discoverer = jalview.ws.jws2.Jws2Discoverer
+ .getInstance();
+ final String ermsg = discoverer.getErrorMessages();
+ // CONFLICT:ALT:? final String ermsg = jalview.ws.jws2.Jws2Discoverer.getInstance()
if (ermsg != null)
{
if (Cache.getDefault("SHOW_WSDISCOVERY_ERRORS", true))
diff --git a/src/jalview/gui/IProgressIndicator.java b/src/jalview/gui/IProgressIndicator.java
index 35bd871..c250aca 100644
--- a/src/jalview/gui/IProgressIndicator.java
+++ b/src/jalview/gui/IProgressIndicator.java
@@ -56,4 +56,11 @@ public interface IProgressIndicator
*/
boolean operationInProgress();
+ /**
+ * Remove progress bar with a given id from the panel.
+ *
+ * @param id
+ */
+ void removeProgressBar(long id);
+
}
diff --git a/src/jalview/gui/JalviewChangeSupport.java b/src/jalview/gui/JalviewChangeSupport.java
index 784e6c1..21c1af0 100644
--- a/src/jalview/gui/JalviewChangeSupport.java
+++ b/src/jalview/gui/JalviewChangeSupport.java
@@ -23,6 +23,7 @@ package jalview.gui;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
+@Deprecated
public class JalviewChangeSupport implements PropertyChangeListener
{
public void propertyChange(PropertyChangeEvent evt)
diff --git a/src/jalview/gui/JvSwingUtils.java b/src/jalview/gui/JvSwingUtils.java
index f23dcf8..8a735ed 100644
--- a/src/jalview/gui/JvSwingUtils.java
+++ b/src/jalview/gui/JvSwingUtils.java
@@ -20,12 +20,10 @@
*/
package jalview.gui;
-import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
+import java.awt.Container;
import java.awt.Font;
-import java.awt.GridLayout;
-import java.awt.Rectangle;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
@@ -37,10 +35,8 @@ import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
-import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
-import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.SwingConstants;
import javax.swing.border.Border;
@@ -156,54 +152,23 @@ public final class JvSwingUtils
}
/**
+ * A convenience method that that adds a component with label to a container,
+ * sets a tooltip on both component and label, and optionally specifies layout
+ * constraints for the added component (but not the label)
*
- * @param panel
+ * @param container
* @param tooltip
* @param label
- * @param valBox
- * @return the GUI element created that was added to the layout so it's
- * attributes can be changed.
+ * @param comp
+ * @param constraints
*/
- public static JPanel addtoLayout(JPanel panel, String tooltip,
- JComponent label, JComponent valBox)
- {
- JPanel laypanel = new JPanel(new GridLayout(1, 2));
- JPanel labPanel = new JPanel(new BorderLayout());
- JPanel valPanel = new JPanel();
- labPanel.setBounds(new Rectangle(7, 7, 158, 23));
- valPanel.setBounds(new Rectangle(172, 7, 270, 23));
- labPanel.add(label, BorderLayout.WEST);
- valPanel.add(valBox);
- laypanel.add(labPanel);
- laypanel.add(valPanel);
- valPanel.setToolTipText(tooltip);
- labPanel.setToolTipText(tooltip);
- valBox.setToolTipText(tooltip);
- panel.add(laypanel);
- panel.validate();
- return laypanel;
- }
-
- public static void mgAddtoLayout(JPanel cpanel, String tooltip,
- JLabel jLabel, JComponent name)
+ public static void addtoLayout(Container container, String tooltip,
+ JComponent label, JComponent comp, String constraints)
{
- mgAddtoLayout(cpanel, tooltip, jLabel, name, null);
- }
-
- public static void mgAddtoLayout(JPanel cpanel, String tooltip,
- JLabel jLabel, JComponent name, String params)
- {
- cpanel.add(jLabel);
- if (params == null)
- {
- cpanel.add(name);
- }
- else
- {
- cpanel.add(name, params);
- }
- name.setToolTipText(tooltip);
- jLabel.setToolTipText(tooltip);
+ container.add(label);
+ container.add(comp, constraints);
+ comp.setToolTipText(tooltip); // this doesn't seem to show?
+ label.setToolTipText(tooltip);
}
/**
@@ -368,7 +333,7 @@ public final class JvSwingUtils
/**
* Adds a titled border to the component in the default font and position (top
- * left), optionally witht italic text
+ * left), optionally with italic text
*
* @param comp
* @param title
diff --git a/src/jalview/gui/OptsAndParamsPage.java b/src/jalview/gui/OptsAndParamsPage.java
index 5342c90..046eb81 100644
--- a/src/jalview/gui/OptsAndParamsPage.java
+++ b/src/jalview/gui/OptsAndParamsPage.java
@@ -20,30 +20,46 @@
*/
package jalview.gui;
+import jalview.bin.Cache;
+import jalview.io.DataSourceType;
+import jalview.io.FileLoader;
+import jalview.io.JalviewFileChooser;
+import jalview.io.JalviewFileView;
import jalview.util.MessageManager;
+import jalview.ws.jws2.dm.JabaOption;
import jalview.ws.params.ArgumentI;
import jalview.ws.params.OptionI;
import jalview.ws.params.ParameterI;
import jalview.ws.params.ValueConstrainI;
import jalview.ws.params.ValueConstrainI.ValueType;
+import jalview.ws.params.simple.FileParameter;
+import jalview.ws.params.simple.LogarithmicParameter;
+import jalview.ws.params.simple.RadioChoiceParameter;
+import jalview.ws.params.simple.StringParameter;
import java.awt.BorderLayout;
+import java.awt.Color;
import java.awt.Component;
+import java.awt.Container;
import java.awt.Dimension;
+import java.awt.FlowLayout;
import java.awt.Font;
-import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
+import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
-import java.awt.event.KeyListener;
+import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
+import java.io.File;
import java.net.URL;
import java.util.ArrayList;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
@@ -52,6 +68,7 @@ import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
+import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JTextArea;
@@ -71,15 +88,33 @@ import net.miginfocom.swing.MigLayout;
*/
public class OptsAndParamsPage
{
- /**
+ public static final int PARAM_WIDTH = 340;
+
+ public static final int PARAM_HEIGHT = 150;
+
+ public static final int PARAM_CLOSEDHEIGHT = 80;
+
+ URL linkImageURL = getClass().getResource("/images/link.gif");
+
+ Map optSet = new LinkedHashMap<>();
+
+ Map paramSet = new LinkedHashMap<>();
+
+ /*
* compact or verbose style parameters
*/
boolean compact = false;
+ OptsParametersContainerI poparent;
+
+ /**
+ * A class that models a panel rendering a single option (checkbox or choice
+ * list)
+ */
public class OptionBox extends JPanel
implements MouseListener, ActionListener
{
- JCheckBox enabled = new JCheckBox();
+ JCheckBox enabled;
final URL finfo;
@@ -91,57 +126,89 @@ public class OptsAndParamsPage
OptionI option;
- JLabel optlabel = new JLabel();
-
- JComboBox val = new JComboBox();
+ JComboBox val;
+ /**
+ * Constructs and adds labels and controls to the panel for one Option
+ *
+ * @param opt
+ */
public OptionBox(OptionI opt)
{
option = opt;
- setLayout(new BorderLayout());
- enabled.setSelected(opt.isRequired()); // TODO: lock required options
+ setLayout(new FlowLayout(FlowLayout.LEFT));
+ enabled = new JCheckBox(opt.getLabel());
+ enabled.setSelected(opt.isRequired());
+
+ /*
+ * If option is required, show a label, if optional a checkbox
+ * (but not for Jabaws pending JWS-126 resolution)
+ */
+ if (opt.isRequired() && !(opt instanceof JabaOption))
+ {
+ finfo = null;
+ add(new JLabel(opt.getLabel()));
+ }
+ else
+ {
+ finfo = option.getFurtherDetails();
+ configureCheckbox(opt);
+ add(enabled);
+ }
+
+ /*
+ * construct the choice box with possible values,
+ * or their display names if provided
+ */
+ val = buildComboBox(opt);
+ val.setSelectedItem(opt.getValue());
+
+ /*
+ * only show the choicebox if there is more than one option,
+ * or the option is mandatory
+ */
+ if (opt.getPossibleValues().size() > 1 || opt.isRequired())
+ {
+ val.addActionListener(this);
+ add(val);
+ }
+
+ setInitialValue();
+ }
+
+ /**
+ * Configures the checkbox that controls whether or not the option is
+ * selected
+ *
+ * @param opt
+ */
+ protected void configureCheckbox(OptionI opt)
+ {
enabled.setFont(new Font("Verdana", Font.PLAIN, 11));
- enabled.setText("");
- enabled.setText(opt.getName());
enabled.addActionListener(this);
- finfo = option.getFurtherDetails();
- String desc = opt.getDescription();
+ final String desc = opt.getDescription();
if (finfo != null)
{
hasLink = true;
-
- enabled.setToolTipText(JvSwingUtils.wrapTooltip(true,
- ((desc == null || desc.trim().length() == 0)
- ? MessageManager.getString(
- "label.opt_and_params_further_details")
- : desc) + " "));
- enabled.addMouseListener(this);
+ String description = desc;
+ if (desc == null || desc.trim().isEmpty())
+ {
+ description = MessageManager
+ .getString("label.opt_and_params_further_details");
+ }
+ description = description + " ";
+ String text = JvSwingUtils.wrapTooltip(true, description);
+ enabled.setToolTipText(text);
+ enabled.addMouseListener(this); // for popup menu to show link
}
else
{
if (desc != null && desc.trim().length() > 0)
{
- enabled.setToolTipText(
- JvSwingUtils.wrapTooltip(true, opt.getDescription()));
+ enabled.setToolTipText(JvSwingUtils.wrapTooltip(true, desc));
}
}
- add(enabled, BorderLayout.NORTH);
- for (Object str : opt.getPossibleValues())
- {
- val.addItem(str);
- }
- val.setSelectedItem(opt.getValue());
- if (opt.getPossibleValues().size() > 1)
- {
- setLayout(new GridLayout(1, 2));
- val.addActionListener(this);
- add(val, BorderLayout.SOUTH);
- }
- // TODO: add actionListeners for popup (to open further info),
- // and to update list of parameters if an option is enabled
- // that takes a value. JBPNote: is this TODO still valid ?
- setInitialValue();
}
@Override
@@ -178,31 +245,21 @@ public class OptsAndParamsPage
poparent.argSetModified(this, !notmod);
}
- public OptionI getOptionIfEnabled()
+ /**
+ * Answers null if the option is not selected, else a new Option holding the
+ * selected value
+ *
+ * @return
+ */
+ public ArgumentI getSelectedOption()
{
if (!enabled.isSelected())
{
return null;
}
+ String value = getSelectedValue(option, val.getSelectedIndex());
OptionI opt = option.copy();
- if (opt.getPossibleValues() != null
- && opt.getPossibleValues().size() == 1)
- {
- // Hack to make sure the default value for an enabled option with only
- // one value is actually returned
- opt.setValue(opt.getPossibleValues().get(0));
- }
- if (val.getSelectedItem() != null)
- {
- opt.setValue((String) val.getSelectedItem());
- }
- else
- {
- if (option.getValue() != null)
- {
- opt.setValue(option.getValue());
- }
- }
+ opt.setValue(value);
return opt;
}
@@ -218,15 +275,11 @@ public class OptsAndParamsPage
@Override
public void mouseEntered(MouseEvent e)
{
- // TODO Auto-generated method stub
-
}
@Override
public void mouseExited(MouseEvent e)
{
- // TODO Auto-generated method stub
-
}
@Override
@@ -268,27 +321,57 @@ public class OptsAndParamsPage
}
}
+ /**
+ * toString representation for identification in the debugger only
+ */
+ @Override
+ public String toString()
+ {
+ return option == null ? super.toString() : option.toString();
+ }
+
}
+ /**
+ * A class that models a panel rendering a single parameter
+ */
public class ParamBox extends JPanel
implements ChangeListener, ActionListener, MouseListener
{
- boolean adjusting = false;
+ /*
+ * parameter values (or their logs) are multiplied by this
+ * scaling factor to ensure an integer range for the slider
+ */
+ private int sliderScaleFactor = 1;
+
+ boolean isLogarithmicParameter;
+
+ boolean isChoiceParameter;
+
+ boolean isIntegerParameter;
- boolean choice = false;
+ boolean isStringParameter;
- JComboBox choicebox;
+ boolean adjusting;
- JPanel controlPanel = new JPanel();
+ /*
+ * drop-down list of choice options (if applicable)
+ */
+ JComboBox choicebox;
- boolean descisvisible = false;
+ /*
+ * radio buttons as an alternative to combo box
+ */
+ ButtonGroup buttonGroup;
+
+ JPanel controlsPanel = new JPanel();
+
+ boolean descriptionIsVisible = false;
JScrollPane descPanel = new JScrollPane();
final URL finfo;
- boolean integ = false;
-
Object lastVal;
ParameterI parameter;
@@ -297,58 +380,82 @@ public class OptsAndParamsPage
JPanel settingPanel = new JPanel();
- JButton showDesc = new JButton();
+ JSlider slider;
- JSlider slider = null;
+ JTextArea descriptionText = new JTextArea();
- JTextArea string = new JTextArea();
+ ValueConstrainI validator;
- ValueConstrainI validator = null;
+ JTextField valueField;
- JTextField valueField = null;
+ private String descTooltip;
- public ParamBox(final OptsParametersContainerI pmlayout,
+ public ParamBox(final OptsParametersContainerI paramContainer,
ParameterI parm)
{
- pmdialogbox = pmlayout;
+ pmdialogbox = paramContainer;
finfo = parm.getFurtherDetails();
validator = parm.getValidValue();
parameter = parm;
+
+ isLogarithmicParameter = parm instanceof LogarithmicParameter;
+
if (validator != null)
{
- integ = validator.getType() == ValueType.Integer;
- }
- else
- {
- if (parameter.getPossibleValues() != null)
+ ValueType type = validator.getType();
+ isIntegerParameter = type == ValueType.Integer;
+ isStringParameter = type == ValueType.String
+ || type == ValueType.File;
+
+ /*
+ * ensure slider has an integer range corresponding to
+ * the min-max range of the parameter
+ */
+ if (validator.getMin() != null && validator.getMax() != null
+ // && !isIntegerParameter
+ && !isStringParameter)
{
- choice = true;
+ double min = validator.getMin().doubleValue();
+ double max = validator.getMax().doubleValue();
+ if (isLogarithmicParameter)
+ {
+ min = Math.log(min);
+ max = Math.log(max);
+ }
+ sliderScaleFactor = (int) (1000000 / (max - min));
+ // todo scaleMin, scaleMax could also be final fields
}
}
- if (!compact)
+ List possibleValues = parameter.getPossibleValues();
+ isChoiceParameter = possibleValues != null
+ && !possibleValues.isEmpty();
+
+ if (compact)
{
- makeExpanderParam(parm);
+ addCompactParameter(parm);
}
else
{
- makeCompactParam(parm);
-
+ addExpandableParam(parm);
}
}
- private void makeCompactParam(ParameterI parm)
+ /**
+ * Adds a 'compact' format parameter, with any help text shown as a tooltip
+ *
+ * @param parm
+ */
+ private void addCompactParameter(ParameterI parm)
{
setLayout(new MigLayout("", "[][grow]"));
-
String ttipText = null;
- controlPanel.setLayout(new BorderLayout());
+ controlsPanel.setLayout(new BorderLayout());
if (parm.getDescription() != null
&& parm.getDescription().trim().length() > 0)
{
- // Only create description boxes if there actually is a description.
ttipText = (JvSwingUtils.wrapTooltip(true,
parm.getDescription() + (finfo != null ? " "
@@ -357,91 +464,57 @@ public class OptsAndParamsPage
: "")));
}
- JvSwingUtils.mgAddtoLayout(this, ttipText, new JLabel(parm.getName()),
- controlPanel, "");
+ JvSwingUtils.addtoLayout(this, ttipText, new JLabel(parm.getName()),
+ controlsPanel, "");
updateControls(parm);
validate();
}
- private void makeExpanderParam(ParameterI parm)
+ /**
+ * Adds an 'expanded' format parameter, with any help shown in a panel that
+ * may be shown or hidden
+ *
+ * @param parm
+ */
+ private void addExpandableParam(ParameterI parm)
{
setPreferredSize(new Dimension(PARAM_WIDTH, PARAM_CLOSEDHEIGHT));
setBorder(new TitledBorder(parm.getName()));
setLayout(null);
- showDesc.setFont(new Font("Verdana", Font.PLAIN, 6));
- showDesc.setText("+");
- string.setFont(new Font("Verdana", Font.PLAIN, 11));
- string.setBackground(getBackground());
+ descriptionText.setFont(new Font("Verdana", Font.PLAIN, 11));
+ descriptionText.setBackground(getBackground());
- string.setEditable(false);
- descPanel.getViewport().setView(string);
+ descriptionText.setEditable(false);
+ descPanel.getViewport().setView(descriptionText);
descPanel.setVisible(false);
JPanel firstrow = new JPanel();
firstrow.setLayout(null);
- controlPanel.setLayout(new BorderLayout());
- controlPanel.setBounds(new Rectangle(39, 10, PARAM_WIDTH - 70,
+ controlsPanel.setLayout(new BorderLayout());
+ controlsPanel.setBounds(new Rectangle(39, 10, PARAM_WIDTH - 70,
PARAM_CLOSEDHEIGHT - 50));
- firstrow.add(controlPanel);
+ firstrow.add(controlsPanel);
firstrow.setBounds(new Rectangle(10, 20, PARAM_WIDTH - 30,
PARAM_CLOSEDHEIGHT - 30));
- final ParamBox me = this;
-
if (parm.getDescription() != null
&& parm.getDescription().trim().length() > 0)
{
- // Only create description boxes if there actually is a description.
- if (finfo != null)
- {
- showDesc.setToolTipText(JvSwingUtils.wrapTooltip(true,
- MessageManager.formatMessage(
- "label.opt_and_params_show_brief_desc_image_link",
- new String[]
- { linkImageURL.toExternalForm() })));
- showDesc.addMouseListener(this);
- }
- else
- {
- showDesc.setToolTipText(
- JvSwingUtils.wrapTooltip(true, MessageManager.getString(
- "label.opt_and_params_show_brief_desc")));
- }
- showDesc.addActionListener(new ActionListener()
- {
-
- @Override
- public void actionPerformed(ActionEvent e)
- {
- descisvisible = !descisvisible;
- descPanel.setVisible(descisvisible);
- descPanel.getVerticalScrollBar().setValue(0);
- me.setPreferredSize(new Dimension(PARAM_WIDTH,
- (descisvisible) ? PARAM_HEIGHT : PARAM_CLOSEDHEIGHT));
- me.validate();
- pmdialogbox.refreshParamLayout();
- }
- });
- string.setWrapStyleWord(true);
- string.setLineWrap(true);
- string.setColumns(32);
- string.setText(parm.getDescription());
- showDesc.setBounds(new Rectangle(10, 10, 16, 16));
- firstrow.add(showDesc);
+ addExpandableHelp(firstrow, parm);
}
add(firstrow);
validator = parm.getValidValue();
parameter = parm;
if (validator != null)
{
- integ = validator.getType() == ValueType.Integer;
+ isIntegerParameter = validator.getType() == ValueType.Integer;
}
else
{
if (parameter.getPossibleValues() != null)
{
- choice = true;
+ isChoiceParameter = true;
}
}
updateControls(parm);
@@ -451,6 +524,57 @@ public class OptsAndParamsPage
validate();
}
+ /**
+ * Adds a button which can be clicked to show or hide help text
+ *
+ * @param container
+ * @param param
+ */
+ protected void addExpandableHelp(JPanel container, ParameterI param)
+ {
+ JButton showDescBtn = new JButton("+");
+ showDescBtn.setFont(new Font("Verdana", Font.PLAIN, 8));
+ if (finfo != null)
+ {
+ descTooltip = JvSwingUtils.wrapTooltip(true,
+ MessageManager.formatMessage(
+ "label.opt_and_params_show_brief_desc_image_link",
+ new String[]
+ { linkImageURL.toExternalForm() }));
+ showDescBtn.addMouseListener(this);
+ }
+ else
+ {
+ descTooltip = JvSwingUtils.wrapTooltip(true, MessageManager
+ .getString("label.opt_and_params_show_brief_desc"));
+ }
+ showDescBtn.setToolTipText(descTooltip);
+ showDescBtn.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ descriptionIsVisible = !descriptionIsVisible;
+ showDescBtn.setText(descriptionIsVisible ? "-" : "+");
+ showDescBtn.setToolTipText(
+ descriptionIsVisible ? null : descTooltip);
+ descPanel.setVisible(descriptionIsVisible);
+ descPanel.getVerticalScrollBar().setValue(0);
+ ParamBox.this.setPreferredSize(new Dimension(PARAM_WIDTH,
+ (descriptionIsVisible) ? PARAM_HEIGHT
+ : PARAM_CLOSEDHEIGHT));
+ ParamBox.this.validate();
+ pmdialogbox.refreshParamLayout();
+ }
+ });
+ descriptionText.setWrapStyleWord(true);
+ descriptionText.setLineWrap(true);
+ descriptionText.setColumns(32);
+ descriptionText.setText(param.getDescription());
+ showDescBtn.setBounds(new Rectangle(10, 10, 16, 16));
+ container.add(showDescBtn);
+ }
+
@Override
public void actionPerformed(ActionEvent e)
{
@@ -458,33 +582,22 @@ public class OptsAndParamsPage
{
return;
}
- if (!choice)
- {
- updateSliderFromValueField();
- }
checkIfModified();
}
+ /**
+ * Checks whether the value of this parameter has been changed and notifies
+ * the parent page accordingly
+ */
private void checkIfModified()
{
- Object cstate = updateSliderFromValueField();
- boolean notmod = false;
- if (cstate.getClass() == lastVal.getClass())
+ Object newValue = updateSliderFromValueField();
+ boolean modified = true;
+ if (newValue.getClass() == lastVal.getClass())
{
- if (cstate instanceof int[])
- {
- notmod = (((int[]) cstate)[0] == ((int[]) lastVal)[0]);
- }
- else if (cstate instanceof float[])
- {
- notmod = (((float[]) cstate)[0] == ((float[]) lastVal)[0]);
- }
- else if (cstate instanceof String[])
- {
- notmod = (((String[]) cstate)[0].equals(((String[]) lastVal)[0]));
- }
+ modified = !newValue.equals(lastVal);
}
- pmdialogbox.argSetModified(this, !notmod);
+ pmdialogbox.argSetModified(this, modified);
}
@Override
@@ -502,22 +615,30 @@ public class OptsAndParamsPage
return Component.BaselineResizeBehavior.CONSTANT_ASCENT;
}
- public int getBoxHeight()
- {
- return (descisvisible ? PARAM_HEIGHT : PARAM_CLOSEDHEIGHT);
- }
-
- public ParameterI getParameter()
+ /**
+ * Answers an argument holding the value entered or selected in the dialog
+ *
+ * @return
+ */
+ public ArgumentI getParameter()
{
ParameterI prm = parameter.copy();
- if (choice)
+ String value = null;
+ if (parameter instanceof RadioChoiceParameter)
+ {
+ value = buttonGroup.getSelection().getActionCommand();
+ }
+ else if (isChoiceParameter)
{
- prm.setValue((String) choicebox.getSelectedItem());
+ value = getSelectedValue(this.parameter,
+ choicebox.getSelectedIndex());
}
else
{
- prm.setValue(valueField.getText());
+ value = valueField.getText();
}
+ prm.setValue(value);
+
return prm;
}
@@ -539,15 +660,11 @@ public class OptsAndParamsPage
@Override
public void mouseEntered(MouseEvent e)
{
- // TODO Auto-generated method stub
-
}
@Override
public void mouseExited(MouseEvent e)
{
- // TODO Auto-generated method stub
-
}
@Override
@@ -562,52 +679,98 @@ public class OptsAndParamsPage
@Override
public void mouseReleased(MouseEvent e)
{
- // TODO Auto-generated method stub
-
}
@Override
public void stateChanged(ChangeEvent e)
{
- if (!adjusting)
+ if (adjusting)
{
- valueField.setText("" + ((integ) ? ("" + slider.getValue())
- : ("" + slider.getValue() / 1000f)));
+ return;
+ }
+ try
+ {
+ adjusting = true;
+ if (!isLogarithmicParameter)
+ {
+ /*
+ * set (int or float formatted) text field value
+ */
+ valueField.setText(isIntegerParameter
+ ? String.valueOf(slider.getValue())
+ : formatDouble(
+ slider.getValue() / (float) sliderScaleFactor));
+ }
+ else
+ {
+ double value = Math.pow(Math.E,
+ slider.getValue() / (double) sliderScaleFactor);
+ valueField.setText(formatDouble(value));
+ }
checkIfModified();
+ } finally
+ {
+ adjusting = false;
}
+ }
+
+ /**
+ * Answers the value formatted as a string to 3 decimal places - in
+ * scientific notation if the value is less than 0.001
+ *
+ * @param value
+ * @return
+ */
+ String formatDouble(double value)
+ {
+ String format = value < 0.001 ? "%3.1E" : "%3.3f";
+ return String.format(format, value);
+ }
+ /**
+ * Formats a number as integer or float (3dp) or scientific notation (1dp)
+ *
+ * @param n
+ * @return
+ */
+ String formatNumber(Number n)
+ {
+ return n instanceof Integer ? String.valueOf(n.intValue())
+ : formatDouble(n.doubleValue());
}
- public void updateControls(ParameterI parm)
+ void updateControls(ParameterI parm)
{
adjusting = true;
- boolean init = (choicebox == null && valueField == null);
+ boolean init = (choicebox == null && valueField == null
+ && buttonGroup == null);
if (init)
{
- if (choice)
+ if (parm instanceof RadioChoiceParameter)
+ {
+ buttonGroup = addRadioButtons(parameter, controlsPanel);
+ }
+ else if (isChoiceParameter)
{
- choicebox = new JComboBox();
+ choicebox = buildComboBox(parm);
choicebox.addActionListener(this);
- controlPanel.add(choicebox, BorderLayout.CENTER);
+ controlsPanel.add(choicebox, BorderLayout.CENTER);
}
else
{
slider = new JSlider();
slider.addChangeListener(this);
- valueField = new JTextField();
+ int cols = parm instanceof StringParameter ? 20 : 0;
+ valueField = new JTextField(cols);
valueField.addActionListener(this);
- valueField.addKeyListener(new KeyListener()
+ valueField.addKeyListener(new KeyAdapter()
{
-
- @Override
- public void keyTyped(KeyEvent e)
- {
- }
-
@Override
public void keyReleased(KeyEvent e)
{
- if (e.isActionKey())
+ int keyCode = e.getKeyCode();
+ if (e.isActionKey() && keyCode != KeyEvent.VK_LEFT
+ && keyCode != KeyEvent.VK_RIGHT)
{
if (valueField.getText().trim().length() > 0)
{
@@ -615,161 +778,251 @@ public class OptsAndParamsPage
}
}
}
-
- @Override
- public void keyPressed(KeyEvent e)
- {
- }
});
- valueField.setPreferredSize(new Dimension(60, 25));
- controlPanel.add(slider, BorderLayout.WEST);
- controlPanel.add(valueField, BorderLayout.EAST);
-
+ valueField.setPreferredSize(new Dimension(65, 25));
+ if (parm instanceof FileParameter)
+ {
+ valueField.setToolTipText(MessageManager
+ .getString("label.double_click_to_browse"));
+ valueField.addMouseListener(new MouseAdapter()
+ {
+ @Override
+ public void mouseClicked(MouseEvent e)
+ {
+ if (e.getClickCount() == 2)
+ {
+ String dir = Cache.getProperty("LAST_DIRECTORY");
+ JalviewFileChooser chooser = new JalviewFileChooser(dir);
+ chooser.setFileView(new JalviewFileView());
+ chooser.setDialogTitle(
+ MessageManager.getString("action.select_ddbb"));
+
+ int val = chooser.showOpenDialog(ParamBox.this);
+ if (val == JalviewFileChooser.APPROVE_OPTION)
+ {
+ File choice = chooser.getSelectedFile();
+ String path = choice.getPath();
+ valueField.setText(path);
+ Cache.setProperty("LAST_DIRECTORY", choice.getParent());
+ FileLoader.updateRecentlyOpened(path,
+ DataSourceType.FILE);
+ }
+ }
+ }
+ });
+ }
+
+ controlsPanel.add(slider, BorderLayout.WEST);
+ controlsPanel.add(valueField, BorderLayout.EAST);
}
}
- if (parm != null)
+ String value = parm.getValue();
+ if (value != null)
{
- if (choice)
+ if (isChoiceParameter)
{
- if (init)
- {
- List vals = parm.getPossibleValues();
- for (Object val : vals)
- {
- choicebox.addItem(val);
- }
- }
-
- if (parm.getValue() != null)
+ if (!(parm instanceof RadioChoiceParameter))
{
- choicebox.setSelectedItem(parm.getValue());
+ choicebox.setSelectedItem(value);
}
}
else
{
- valueField.setText(parm.getValue());
+ valueField.setText(value);
}
}
lastVal = updateSliderFromValueField();
adjusting = false;
}
- public Object updateSliderFromValueField()
+ /**
+ * Adds a panel to comp, containing a label and radio buttons for the choice
+ * of values of the given option. Returns a ButtonGroup whose members are
+ * the added radio buttons.
+ *
+ * @param option
+ * @param comp
+ *
+ * @return
+ */
+ protected ButtonGroup addRadioButtons(OptionI option, Container comp)
{
- int iVal;
- float fVal;
- if (validator != null)
+ ButtonGroup bg = new ButtonGroup();
+ JPanel radioPanel = new JPanel();
+ radioPanel.add(new JLabel(option.getDescription()));
+
+ String value = option.getValue();
+
+ for (String opt : option.getPossibleValues())
+ {
+ JRadioButton btn = new JRadioButton(opt);
+ btn.setActionCommand(opt);
+ boolean selected = opt.equals(value);
+ btn.setSelected(selected);
+ btn.addActionListener(this);
+ bg.add(btn);
+ radioPanel.add(btn);
+ }
+ comp.add(radioPanel);
+
+ return bg;
+ }
+
+ /**
+ * Action depends on the type of the input parameter:
+ *
+ * if a text input, returns the trimmed value
+ * if a choice list or radio button, returns the selected value
+ * if a value slider and input field, sets the value of the slider from
+ * the value in the text field, limiting it to any defined min-max
+ * range.
+ *
+ * Answers the (possibly modified) input value, as a String, Integer, Float
+ * or Double.
+ *
+ * @return
+ */
+ Object updateSliderFromValueField()
+ {
+ if (validator == null || isStringParameter)
{
- if (integ)
+ if (isChoiceParameter)
{
- iVal = 0;
- try
- {
- valueField.setText(valueField.getText().trim());
- iVal = Integer.valueOf(valueField.getText());
- if (validator.getMin() != null
- && validator.getMin().intValue() > iVal)
- {
- iVal = validator.getMin().intValue();
- // TODO: provide visual indication that hard limit was reached for
- // this parameter
- }
- if (validator.getMax() != null
- && validator.getMax().intValue() < iVal)
- {
- iVal = validator.getMax().intValue();
- // TODO: provide visual indication that hard limit was reached for
- // this parameter
- }
- } catch (Exception e)
+ if (parameter instanceof RadioChoiceParameter)
{
- }
- ;
- // update value field to reflect any bound checking we performed.
- valueField.setText("" + iVal);
- if (validator.getMin() != null && validator.getMax() != null)
- {
- slider.getModel().setRangeProperties(iVal, 1,
- validator.getMin().intValue(),
- validator.getMax().intValue() + 1, true);
+ return buttonGroup.getSelection().getActionCommand();
}
else
{
- slider.setVisible(false);
+ return getSelectedValue(this.parameter,
+ choicebox.getSelectedIndex());
}
- return new int[] { iVal };
}
- else
+ slider.setVisible(false);
+ return valueField.getText().trim();
+ }
+
+ if (validator.getMin() == null || validator.getMax() == null)
+ {
+ slider.setVisible(false);
+ }
+
+ valueField.setText(valueField.getText().trim());
+
+ /*
+ * ensure not outside min-max range
+ * TODO: provide some visual indicator if limit reached
+ */
+ try
+ {
+ valueField.setBackground(Color.WHITE);
+ double d = Double.parseDouble(valueField.getText());
+ if (validator.getMin() != null
+ && validator.getMin().doubleValue() > d)
{
- fVal = 0f;
- try
- {
- valueField.setText(valueField.getText().trim());
- fVal = Float.valueOf(valueField.getText());
- if (validator.getMin() != null
- && validator.getMin().floatValue() > fVal)
- {
- fVal = validator.getMin().floatValue();
- // TODO: provide visual indication that hard limit was reached for
- // this parameter
- // update value field to reflect any bound checking we performed.
- valueField.setText("" + fVal);
- }
- if (validator.getMax() != null
- && validator.getMax().floatValue() < fVal)
- {
- fVal = validator.getMax().floatValue();
- // TODO: provide visual indication that hard limit was reached for
- // this parameter
- // update value field to reflect any bound checking we performed.
- valueField.setText("" + fVal);
- }
- } catch (Exception e)
- {
- }
- ;
- if (validator.getMin() != null && validator.getMax() != null)
- {
- slider.getModel().setRangeProperties((int) (fVal * 1000f), 1,
- (int) (validator.getMin().floatValue() * 1000f),
- 1 + (int) (validator.getMax().floatValue() * 1000f),
- true);
- }
- else
- {
- slider.setVisible(false);
- }
- return new float[] { fVal };
+ valueField.setText(formatNumber(validator.getMin()));
+ }
+ if (validator.getMax() != null
+ && validator.getMax().doubleValue() < d)
+ {
+ valueField.setText(formatNumber(validator.getMax()));
}
+ } catch (NumberFormatException e)
+ {
+ valueField.setBackground(Color.yellow);
+ return Float.NaN;
}
- else
+
+ if (isIntegerParameter)
{
- if (!choice)
+ int iVal = 0;
+ try
+ {
+ iVal = Integer.valueOf(valueField.getText());
+ } catch (Exception e)
+ {
+ valueField.setBackground(Color.yellow);
+ return Integer.valueOf(0);
+ }
+
+ if (validator.getMin() != null && validator.getMax() != null)
+ {
+ slider.getModel().setRangeProperties(iVal, 1,
+ validator.getMin().intValue(),
+ validator.getMax().intValue() + 1, true);
+ }
+ else
{
slider.setVisible(false);
- return new String[] { valueField.getText().trim() };
+ }
+ return Integer.valueOf(iVal);
+ }
+
+ if (isLogarithmicParameter)
+ {
+ double dVal = 0d;
+ try
+ {
+ double eValue = Double.valueOf(valueField.getText());
+ dVal = Math.log(eValue);
+ } catch (Exception e)
+ {
+ // shouldn't be possible here
+ valueField.setBackground(Color.yellow);
+ return Double.NaN;
+ }
+ if (validator.getMin() != null && validator.getMax() != null)
+ {
+ double scaleMin = Math.log(validator.getMin().doubleValue())
+ * sliderScaleFactor;
+ double scaleMax = Math.log(validator.getMax().doubleValue())
+ * sliderScaleFactor;
+ slider.getModel().setRangeProperties(
+ (int) (sliderScaleFactor * dVal), 1,
+ (int) scaleMin, 1 + (int) scaleMax, true);
}
else
{
- return new String[] { (String) choicebox.getSelectedItem() };
+ slider.setVisible(false);
}
+ return Double.valueOf(dVal);
}
+ float fVal = 0f;
+ try
+ {
+ fVal = Float.valueOf(valueField.getText());
+ } catch (Exception e)
+ {
+ return Float.valueOf(0f); // shouldn't happen
+ }
+ if (validator.getMin() != null && validator.getMax() != null)
+ {
+ float scaleMin = validator.getMin().floatValue()
+ * sliderScaleFactor;
+ float scaleMax = validator.getMax().floatValue()
+ * sliderScaleFactor;
+ slider.getModel().setRangeProperties(
+ (int) (fVal * sliderScaleFactor), 1, (int) scaleMin,
+ 1 + (int) scaleMax, true);
+ }
+ else
+ {
+ slider.setVisible(false);
+ }
+ return Float.valueOf(fVal);
}
}
- public static final int PARAM_WIDTH = 340;
-
- public static final int PARAM_HEIGHT = 150;
-
- public static final int PARAM_CLOSEDHEIGHT = 80;
-
- public OptsAndParamsPage(OptsParametersContainerI paramContainer)
- {
- this(paramContainer, false);
- }
-
+ /**
+ * Constructor with the option to show 'compact' format (parameter description
+ * as tooltip) or 'expanded' format (parameter description in a textbox which
+ * may be opened or closed). Use compact for simple description text, expanded
+ * for more wordy or formatted text.
+ *
+ * @param paramContainer
+ */
public OptsAndParamsPage(OptsParametersContainerI paramContainer,
boolean compact)
{
@@ -799,12 +1052,6 @@ public class OptsAndParamsPage
mnu.show(invoker, x, y);
}
- URL linkImageURL = getClass().getResource("/images/link.gif");
-
- Map optSet = new java.util.LinkedHashMap();
-
- Map paramSet = new java.util.LinkedHashMap();
-
public Map getOptSet()
{
return optSet;
@@ -825,8 +1072,6 @@ public class OptsAndParamsPage
this.paramSet = paramSet;
}
- OptsParametersContainerI poparent;
-
OptionBox addOption(OptionI opt)
{
OptionBox cb = optSet.get(opt.getName());
@@ -870,11 +1115,9 @@ public class OptsAndParamsPage
}
else
{
- throw new Error(MessageManager.formatMessage(
- "error.invalid_value_for_option", new String[]
- { string, option.getName() }));
+ throw new Error(String.format("Invalid value '%s' for option '%s'",
+ string, option.getName()));
}
-
}
if (option.isRequired() && !cb.enabled.isSelected())
{
@@ -898,16 +1141,18 @@ public class OptsAndParamsPage
}
/**
- * recover options and parameters from GUI
+ * Answers a list of arguments representing all the options and arguments
+ * selected on the dialog, holding their chosen or input values. Optional
+ * parameters which were not selected are not included.
*
* @return
*/
public List getCurrentSettings()
{
- List argSet = new ArrayList();
+ List argSet = new ArrayList<>();
for (OptionBox opts : getOptSet().values())
{
- OptionI opt = opts.getOptionIfEnabled();
+ ArgumentI opt = opts.getSelectedOption();
if (opt != null)
{
argSet.add(opt);
@@ -915,7 +1160,7 @@ public class OptsAndParamsPage
}
for (ParamBox parambox : getParamSet().values())
{
- ParameterI parm = parambox.getParameter();
+ ArgumentI parm = parambox.getParameter();
if (parm != null)
{
argSet.add(parm);
@@ -925,4 +1170,57 @@ public class OptsAndParamsPage
return argSet;
}
+ /**
+ * A helper method that constructs and returns a CombBox for choice of the
+ * possible option values. If display names are provided, then these are added
+ * as options, otherwise the actual values are added.
+ *
+ * @param opt
+ * @return
+ */
+ protected static JComboBox buildComboBox(OptionI opt)
+ {
+ JComboBox cb = null;
+ List displayNames = opt.getDisplayNames();
+ if (displayNames != null)
+ {
+ List displayNamesObjects = new ArrayList<>();
+ displayNamesObjects.addAll(displayNames);
+ cb = JvSwingUtils.buildComboWithTooltips(displayNamesObjects,
+ opt.getPossibleValues());
+ }
+ else
+ {
+ cb = new JComboBox<>();
+ for (String v : opt.getPossibleValues())
+ {
+ cb.addItem(v);
+ }
+ }
+ return cb;
+ }
+
+ /**
+ * Answers the value corresponding to the selected item in the choice combo
+ * box. Note that this returns the underlying value even if a different
+ * display name is used in the combo box.
+ *
+ * @return
+ */
+ protected static String getSelectedValue(OptionI opt, int sel)
+ {
+ List possibleValues = opt.getPossibleValues();
+ String value = null;
+ if (possibleValues != null && possibleValues.size() == 1)
+ {
+ // Hack to make sure the default value for an enabled option with only
+ // one value is actually returned even if this.val is not displayed
+ value = possibleValues.get(0);
+ }
+ else if (sel >= 0 && sel < possibleValues.size())
+ {
+ value = possibleValues.get(sel);
+ }
+ return value;
+ }
}
diff --git a/src/jalview/gui/OverviewPanel.java b/src/jalview/gui/OverviewPanel.java
index cf15aa1..4b6d79b 100755
--- a/src/jalview/gui/OverviewPanel.java
+++ b/src/jalview/gui/OverviewPanel.java
@@ -20,6 +20,7 @@
*/
package jalview.gui;
+import jalview.api.AlignViewportI;
import jalview.bin.Cache;
import jalview.renderer.OverviewRenderer;
import jalview.util.MessageManager;
@@ -63,7 +64,7 @@ public class OverviewPanel extends JPanel
private OverviewCanvas oviewCanvas;
- protected AlignViewport av;
+ private AlignViewportI av;
private AlignmentPanel ap;
diff --git a/src/jalview/gui/PCAPanel.java b/src/jalview/gui/PCAPanel.java
index 5eca00f..c0d57a6 100644
--- a/src/jalview/gui/PCAPanel.java
+++ b/src/jalview/gui/PCAPanel.java
@@ -607,6 +607,12 @@ public class PCAPanel extends GPCAPanel
// // setMenusForViewport();
// validate();
}
+
+ @Override
+ public void removeProgressBar(long id)
+ {
+ progressBar.removeProgressBar(id);
+ }
@Override
public void registerHandler(final long id,
diff --git a/src/jalview/gui/PairwiseAlignPanel.java b/src/jalview/gui/PairwiseAlignPanel.java
index d081794..e736a11 100755
--- a/src/jalview/gui/PairwiseAlignPanel.java
+++ b/src/jalview/gui/PairwiseAlignPanel.java
@@ -21,13 +21,13 @@
package jalview.gui;
import jalview.analysis.AlignSeq;
+import jalview.api.AlignViewportI;
import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentView;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
import jalview.jbgui.GPairwiseAlignPanel;
import jalview.util.MessageManager;
-import jalview.viewmodel.AlignmentViewport;
import java.awt.event.ActionEvent;
import java.util.Vector;
@@ -43,7 +43,7 @@ public class PairwiseAlignPanel extends GPairwiseAlignPanel
private static final String DASHES = "---------------------\n";
- AlignmentViewport av;
+ AlignViewportI av;
Vector sequences;
@@ -51,14 +51,13 @@ public class PairwiseAlignPanel extends GPairwiseAlignPanel
* Creates a new PairwiseAlignPanel object.
*
* @param viewport
- * DOCUMENT ME!
*/
- public PairwiseAlignPanel(AlignmentViewport viewport)
+ public PairwiseAlignPanel(AlignViewportI viewport)
{
super();
this.av = viewport;
- sequences = new Vector();
+ sequences = new Vector<>();
SequenceGroup selectionGroup = viewport.getSelectionGroup();
boolean isSelection = selectionGroup != null
diff --git a/src/jalview/gui/PopupMenu.java b/src/jalview/gui/PopupMenu.java
index 4469b43..f46bd4e 100644
--- a/src/jalview/gui/PopupMenu.java
+++ b/src/jalview/gui/PopupMenu.java
@@ -64,11 +64,13 @@ import jalview.datamodel.DBRefEntry;
import jalview.datamodel.HiddenColumns;
import jalview.datamodel.MappedFeatures;
import jalview.datamodel.PDBEntry;
+import jalview.datamodel.ResidueCount;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
import jalview.gui.ColourMenuHelper.ColourChangeListener;
import jalview.gui.JalviewColourChooser.ColourChooserListener;
+import jalview.io.CountReader;
import jalview.io.FileFormatI;
import jalview.io.FileFormats;
import jalview.io.FormatAdapter;
@@ -87,6 +89,9 @@ import jalview.util.StringUtils;
import jalview.util.UrlLink;
import jalview.viewmodel.seqfeatures.FeatureRendererModel;
+import java.io.IOException;
+import java.net.MalformedURLException;
+
/**
* The popup menu that is displayed on right-click on a sequence id, or in the
* sequence alignment.
@@ -545,6 +550,36 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
}
}
+ if (seq.hasHMMProfile())
+ {
+ menuItem = new JMenuItem(MessageManager
+ .getString("action.add_background_frequencies"));
+ menuItem.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ try
+ {
+ ResidueCount counts = CountReader.getBackgroundFrequencies(ap,
+ seq);
+ if (counts != null)
+ {
+ seq.getHMM().setBackgroundFrequencies(counts);
+ ap.alignFrame.buildColourMenu();
+ }
+ } catch (MalformedURLException e1)
+ {
+ e1.printStackTrace();
+ } catch (IOException e1)
+ {
+ e1.printStackTrace();
+ }
+ }
+ });
+ add(menuItem);
+ }
+
menuItem = new JMenuItem(
MessageManager.getString("action.hide_sequences"));
menuItem.addActionListener(new ActionListener()
@@ -669,7 +704,8 @@ public class PopupMenu extends JPopupMenu implements ColourChangeListener
buildGroupURLMenu(sg, groupLinks);
}
// Add a 'show all structures' for the current selection
- Hashtable pdbe = new Hashtable<>(), reppdb = new Hashtable<>();
+ Hashtable pdbe = new Hashtable<>();
+ Hashtable reppdb = new Hashtable<>();
SequenceI sqass = null;
for (SequenceI sq : alignPanel.av.getSequenceSelection())
diff --git a/src/jalview/gui/Preferences.java b/src/jalview/gui/Preferences.java
index 4030afa..04851e8 100755
--- a/src/jalview/gui/Preferences.java
+++ b/src/jalview/gui/Preferences.java
@@ -27,6 +27,8 @@ import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
import java.awt.event.MouseEvent;
import java.io.File;
import java.util.ArrayList;
@@ -37,6 +39,7 @@ import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JInternalFrame;
import javax.swing.JPanel;
+import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.RowFilter;
import javax.swing.RowSorter;
@@ -50,6 +53,9 @@ import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
+import jalview.hmmer.HmmerCommand;
+import jalview.util.FileUtils;
+
import ext.edu.ucsf.rbvi.strucviz2.StructureManager;
import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
import jalview.bin.Cache;
@@ -82,6 +88,14 @@ import jalview.ws.sifts.SiftsSettings;
*/
public class Preferences extends GPreferences
{
+ // suggested list delimiter character
+ public static final String COMMA = ",";
+
+ public static final String HMMSEARCH_SEQCOUNT = "HMMSEARCH_SEQCOUNT";
+
+ public static final String HMMINFO_GLOBAL_BACKGROUND = "HMMINFO_GLOBAL_BACKGROUND";
+
+ public static final String HMMALIGN_TRIM_TERMINI = "HMMALIGN_TRIM_TERMINI";
public static final String ADD_SS_ANN = "ADD_SS_ANN";
@@ -126,6 +140,12 @@ public class Preferences extends GPreferences
public static final String FONT_SIZE = "FONT_SIZE";
public static final String FONT_STYLE = "FONT_STYLE";
+
+ public static final String HMMER_PATH = "HMMER_PATH";
+
+ public static final String CYGWIN_PATH = "CYGWIN_PATH";
+
+ public static final String HMMSEARCH_DBS = "HMMSEARCH_DBS";
public static final String GAP_COLOUR = "GAP_COLOUR";
@@ -269,6 +289,8 @@ public class Preferences extends GPreferences
private WsPreferences wsPrefs;
+ private SlivkaPreferences slivkaPrefs;
+
private OptionsParam promptEachTimeOpt = new OptionsParam(
MessageManager.getString("label.prompt_each_time"),
"Prompt each time");
@@ -296,6 +318,8 @@ public class Preferences extends GPreferences
{
wsPrefs = new WsPreferences();
wsTab.add(wsPrefs, BorderLayout.CENTER);
+ slivkaPrefs = new SlivkaPreferences();
+ slivkaTab.add(slivkaPrefs, BorderLayout.CENTER);
}
int width = 500, height = 450;
if (Platform.isAMacAndNotJS())
@@ -309,6 +333,63 @@ public class Preferences extends GPreferences
frame.setMinimumSize(new Dimension(width, height));
/*
+ * Set HMMER tab defaults
+ */
+ hmmrTrimTermini.setSelected(Cache.getDefault(HMMALIGN_TRIM_TERMINI, false));
+ if (Cache.getDefault(HMMINFO_GLOBAL_BACKGROUND, false))
+ {
+ hmmerBackgroundUniprot.setSelected(true);
+ }
+ else
+ {
+ hmmerBackgroundAlignment.setSelected(true);
+ }
+ hmmerSequenceCount
+ .setText(Cache.getProperty(HMMSEARCH_SEQCOUNT));
+ hmmerPath.setText(Cache.getProperty(HMMER_PATH));
+ hmmerPath.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ validateHmmerPath();
+ }
+ });
+ hmmerPath.addFocusListener(new FocusAdapter()
+ {
+ @Override
+ public void focusLost(FocusEvent e)
+ {
+ validateHmmerPath();
+ }
+ });
+ if (cygwinPath != null)
+ {
+ String path = Cache.getProperty(CYGWIN_PATH);
+ if (path == null)
+ {
+ path = FileUtils.getPathTo("bash");
+ }
+ cygwinPath.setText(path);
+ cygwinPath.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ validateCygwinPath();
+ }
+ });
+ cygwinPath.addFocusListener(new FocusAdapter()
+ {
+ @Override
+ public void focusLost(FocusEvent e)
+ {
+ validateCygwinPath();
+ }
+ });
+ }
+
+ /*
* Set Visual tab defaults
*/
seqLimit.setSelected(Cache.getDefault("SHOW_JVSUFFIX", true));
@@ -331,6 +412,9 @@ public class Preferences extends GPreferences
Cache.getDefault("SHOW_CONSENSUS_HISTOGRAM", true));
showConsensLogo
.setSelected(Cache.getDefault("SHOW_CONSENSUS_LOGO", false));
+ showInformationHistogram.setSelected(
+ Cache.getDefault("SHOW_INFORMATION_HISTOGRAM", true));
+ showHMMLogo.setSelected(Cache.getDefault("SHOW_HMM_LOGO", false));
showNpTooltip
.setSelected(Cache.getDefault("SHOW_NPFEATS_TOOLTIP", true));
showDbRefTooltip
@@ -509,7 +593,7 @@ public class Preferences extends GPreferences
doReset.addActionListener(onReset);
// filter to display only custom urls
- final RowFilter customUrlFilter = new RowFilter()
+ final RowFilter customUrlFilter = new RowFilter<>()
{
@Override
public boolean include(
@@ -741,6 +825,10 @@ public class Preferences extends GPreferences
Boolean.toString(showConsensHistogram.isSelected()));
Cache.setPropertyNoSave("SHOW_CONSENSUS_LOGO",
Boolean.toString(showConsensLogo.isSelected()));
+ Cache.setPropertyNoSave("SHOW_INFORMATION_HISTOGRAM",
+ Boolean.toString(showConsensHistogram.isSelected()));
+ Cache.setPropertyNoSave("SHOW_HMM_LOGO",
+ Boolean.toString(showHMMLogo.isSelected()));
Cache.setPropertyNoSave("ANTI_ALIAS",
Boolean.toString(smoothFont.isSelected()));
Cache.setPropertyNoSave(SCALE_PROTEIN_TO_CDNA,
@@ -787,6 +875,42 @@ public class Preferences extends GPreferences
maxColour.getBackground());
/*
+ * Save HMMER settings
+ */
+ Cache.setPropertyNoSave(HMMALIGN_TRIM_TERMINI,
+ Boolean.toString(hmmrTrimTermini.isSelected()));
+ Cache.setPropertyNoSave(HMMINFO_GLOBAL_BACKGROUND,
+ Boolean.toString(hmmerBackgroundUniprot.isSelected()));
+ Cache.setPropertyNoSave(HMMSEARCH_SEQCOUNT,
+ hmmerSequenceCount.getText());
+ Cache.setOrRemove(HMMER_PATH, hmmerPath.getText());
+ if (cygwinPath != null)
+ {
+ Cache.setOrRemove(CYGWIN_PATH, cygwinPath.getText());
+ }
+ AlignFrame[] frames = Desktop.getAlignFrames();
+ if (frames != null && frames.length > 0)
+ {
+ for (AlignFrame f : frames)
+ {
+ f.updateHMMERStatus();
+ }
+ }
+
+ hmmrTrimTermini.setSelected(Cache.getDefault(HMMALIGN_TRIM_TERMINI, false));
+ if (Cache.getDefault(HMMINFO_GLOBAL_BACKGROUND, false))
+ {
+ hmmerBackgroundUniprot.setSelected(true);
+ }
+ else
+ {
+ hmmerBackgroundAlignment.setSelected(true);
+ }
+ hmmerSequenceCount
+ .setText(Cache.getProperty(HMMSEARCH_SEQCOUNT));
+ hmmerPath.setText(Cache.getProperty(HMMER_PATH));
+
+ /*
* Save Overview settings
*/
Cache.setColourPropertyNoSave(GAP_COLOUR, gapColour.getBackground());
@@ -1101,6 +1225,8 @@ public class Preferences extends GPreferences
&& (identity.isSelected() || showGroupConsensus.isSelected()));
showConsensLogo.setEnabled(annotations.isSelected()
&& (identity.isSelected() || showGroupConsensus.isSelected()));
+ showInformationHistogram.setEnabled(annotations.isSelected());
+ showHMMLogo.setEnabled(annotations.isSelected());
}
@Override
@@ -1370,6 +1496,57 @@ public class Preferences extends GPreferences
}
return true;
}
+
+ /**
+ * Returns true if the given text field contains a path to a folder that
+ * contains an executable with the given name, else false (after showing a
+ * warning dialog). The executable name will be tried with .exe appended if not
+ * found.
+ *
+ * @param textField
+ * @param executable
+ */
+ protected boolean validateExecutablePath(JTextField textField, String executable)
+ {
+ String folder = textField.getText().trim();
+
+ if (FileUtils.getExecutable(executable, folder) != null)
+ {
+ return true;
+ }
+ if (folder.length() > 0)
+ {
+ JvOptionPane.showInternalMessageDialog(Desktop.getInstance(),
+ MessageManager.formatMessage("label.executable_not_found",
+ executable),
+ MessageManager.getString("label.invalid_folder"),
+ JvOptionPane.ERROR_MESSAGE);
+ }
+ return false;
+ }
+
+ /**
+ * Checks if a file can be executed
+ *
+ * @param path
+ * the path to the file
+ * @return
+ */
+ public boolean canExecute(String path)
+ {
+ File file = new File(path);
+ if (!file.canExecute())
+ {
+ file = new File(path + ".exe");
+ {
+ if (!file.canExecute())
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
/**
* If Chimera is selected, check it can be found on default or user-specified
@@ -1418,6 +1595,18 @@ public class Preferences extends GPreferences
}
}
+ @Override
+ protected void validateHmmerPath()
+ {
+ validateExecutablePath(hmmerPath, HmmerCommand.HMMBUILD);
+ }
+
+ @Override
+ protected void validateCygwinPath()
+ {
+ validateExecutablePath(cygwinPath, "run");
+ }
+
public class OptionsParam
{
private String name;
diff --git a/src/jalview/gui/ProgressBar.java b/src/jalview/gui/ProgressBar.java
index 011d810..abf096f 100644
--- a/src/jalview/gui/ProgressBar.java
+++ b/src/jalview/gui/ProgressBar.java
@@ -166,6 +166,23 @@ public class ProgressBar implements IProgressIndicator
});
}
+
+ @Override
+ public void removeProgressBar(final long id)
+ {
+ SwingUtilities.invokeLater(() -> {
+ JPanel progressPanel = progressBars.get(id);
+ if (progressPanel != null)
+ {
+ progressBars.remove(id);
+ if (progressBarHandlers.containsKey(id))
+ {
+ progressBarHandlers.remove(id);
+ }
+ removeRow(progressPanel);
+ }
+ });
+ }
/**
* Lays out progress bar container hierarchy
diff --git a/src/jalview/gui/RestServiceEditorPane.java b/src/jalview/gui/RestServiceEditorPane.java
index cda76d9..213a979 100644
--- a/src/jalview/gui/RestServiceEditorPane.java
+++ b/src/jalview/gui/RestServiceEditorPane.java
@@ -476,10 +476,13 @@ public class RestServiceEditorPane extends GRestServiceEditorPane
final Thread runner = Thread.currentThread();
JFrame df = new JFrame();
df.getContentPane().setLayout(new BorderLayout());
- df.getContentPane().add((nulserv = !nulserv)
- ? new RestServiceEditorPane(jalview.ws.rest.RestClient
- .makeShmmrRestClient().getRestDescription())
- : new RestServiceEditorPane(), BorderLayout.CENTER);
+ df.getContentPane().add(
+ (nulserv = !nulserv) ? new RestServiceEditorPane(
+ jalview.ws.rest.clientdefs.ShmrRestClient
+ .makeShmmrRestClient()
+ .getRestDescription())
+ : new RestServiceEditorPane(),
+ BorderLayout.CENTER);
df.setBounds(100, 100, 600, 400);
df.addComponentListener(new ComponentListener()
{
diff --git a/src/jalview/gui/SlivkaPreferences.java b/src/jalview/gui/SlivkaPreferences.java
new file mode 100644
index 0000000..6c365b9
--- /dev/null
+++ b/src/jalview/gui/SlivkaPreferences.java
@@ -0,0 +1,368 @@
+package jalview.gui;
+
+import jalview.bin.Cache;
+import jalview.util.MessageManager;
+import jalview.ws.WSDiscovererI;
+import jalview.ws.slivkaws.SlivkaWSDiscoverer;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.DefaultTableCellRenderer;
+
+@SuppressWarnings("serial")
+public class SlivkaPreferences extends JPanel
+{
+ {
+ setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
+ setPreferredSize(new Dimension(500, 450));
+ }
+
+ WSDiscovererI discoverer;
+
+ private final ArrayList urls = new ArrayList<>();
+
+ private final ArrayList statuses = new ArrayList<>();
+
+ private final AbstractTableModel urlTableModel = new AbstractTableModel()
+ {
+ final String[] columnNames = { "Service URL", "Status" };
+
+ @Override
+ public String getColumnName(int col)
+ {
+ return columnNames[col];
+ }
+
+ @Override
+ public Object getValueAt(int rowIndex, int columnIndex)
+ {
+ switch (columnIndex)
+ {
+ case 0:
+ return urls.get(rowIndex);
+ case 1:
+ return statuses.get(rowIndex);
+ default:
+ throw new NoSuchElementException();
+ }
+ }
+
+ @Override
+ public int getRowCount()
+ {
+ return urls.size();
+ }
+
+ @Override
+ public int getColumnCount()
+ {
+ return 2;
+ }
+ };
+
+ private class WSStatusCellRenderer extends DefaultTableCellRenderer
+ {
+ @Override
+ public Component getTableCellRendererComponent(JTable table,
+ Object value, boolean isSelected, boolean hasFocus, int row,
+ int column)
+ {
+ setHorizontalAlignment(CENTER);
+ super.getTableCellRendererComponent(table, "\u25CF", isSelected,
+ hasFocus, row, column);
+ switch ((Integer) value)
+ {
+ case WSDiscovererI.STATUS_NO_SERVICES:
+ setForeground(Color.ORANGE);
+ break;
+ case WSDiscovererI.STATUS_OK:
+ setForeground(Color.GREEN);
+ break;
+ case WSDiscovererI.STATUS_INVALID:
+ setForeground(Color.RED);
+ break;
+ case WSDiscovererI.STATUS_UNKNOWN:
+ default:
+ setForeground(Color.LIGHT_GRAY);
+ }
+ return this;
+ }
+ }
+
+ private JTable urlListTable = new JTable(urlTableModel);
+ {
+ urlListTable.getColumnModel().getColumn(1).setMaxWidth(60);
+ urlListTable.getColumnModel().getColumn(1)
+ .setCellRenderer(new WSStatusCellRenderer());
+ }
+
+ // URL control panel buttons
+ JButton newWsUrl = new JButton(
+ MessageManager.getString("label.new_service_url"));
+
+ JButton editWsUrl = new JButton(
+ MessageManager.getString("label.edit_service_url"));
+
+ JButton deleteWsUrl = new JButton(
+ MessageManager.getString("label.delete_service_url"));
+
+ JButton moveUrlUp = new JButton(
+ MessageManager.getString("action.move_up"));
+
+ JButton moveUrlDown = new JButton(
+ MessageManager.getString("action.move_down"));
+
+ private String showEditUrlDialog(String oldUrl)
+ {
+ String input = (String) JvOptionPane
+ .showInternalInputDialog(
+ this,
+ MessageManager.getString("label.url:"),
+ UIManager.getString("OptionPane.inputDialogTitle", MessageManager.getLocale()),
+ JOptionPane.QUESTION_MESSAGE,
+ null,
+ null,
+ oldUrl);
+ if (input == null)
+ {
+ return null;
+ }
+ try
+ {
+ new URL(input);
+ } catch (MalformedURLException ex)
+ {
+ JvOptionPane.showInternalMessageDialog(this,
+ MessageManager.getString("label.invalid_url"),
+ UIManager.getString("OptionPane.messageDialogTitle",
+ MessageManager.getLocale()),
+ JOptionPane.WARNING_MESSAGE);
+ return null;
+ }
+ return input;
+ }
+
+ // Button Action Listeners
+ private ActionListener newUrlAction = (ActionEvent e) -> {
+ final String input = showEditUrlDialog("");
+ if (input != null)
+ {
+ urls.add(input);
+ statuses.add(discoverer.getServerStatusFor(input));
+ urlTableModel.fireTableRowsInserted(urls.size(), urls.size());
+ discoverer.setServiceUrls(urls);
+ }
+ };
+
+ private ActionListener editUrlAction = (ActionEvent e) -> {
+ final int i = urlListTable.getSelectedRow();
+ if (i >= 0)
+ {
+ final String input = showEditUrlDialog(urls.get(i));
+ if (input != null)
+ {
+ urls.set(i, input);
+ statuses.set(i, discoverer.getServerStatusFor(input));
+ urlTableModel.fireTableRowsUpdated(i, i);
+ discoverer.setServiceUrls(urls);
+ }
+ }
+ };
+
+ private ActionListener deleteUrlAction = (ActionEvent e) -> {
+ final int i = urlListTable.getSelectedRow();
+ if (i >= 0)
+ {
+ urls.remove(i);
+ statuses.remove(i);
+ urlTableModel.fireTableRowsDeleted(i, i);
+ discoverer.setServiceUrls(urls);
+ }
+ };
+
+ private ActionListener moveUrlUpAction = (ActionEvent e) -> {
+ final int i = urlListTable.getSelectedRow();
+ if (i > 0)
+ {
+ moveTableRow(i, i - 1);
+ discoverer.setServiceUrls(urls);
+ }
+ };
+
+ private ActionListener moveUrlDownAction = (ActionEvent e) -> {
+ final int i = urlListTable.getSelectedRow();
+ if (i >= 0 && i < urls.size() - 1)
+ {
+ moveTableRow(i, i + 1);
+ discoverer.setServiceUrls(urls);
+ }
+ };
+
+ private MouseListener tableClickListener = new MouseAdapter()
+ {
+ final ActionEvent actionEvent = new ActionEvent(urlListTable,
+ ActionEvent.ACTION_PERFORMED, "edit");
+
+ @Override
+ public void mouseClicked(MouseEvent e)
+ {
+ if (e.getClickCount() > 1)
+ {
+ editUrlAction.actionPerformed(actionEvent);
+ }
+ }
+ };
+
+ // Setting up URL list Pane
+ {
+ Font font = new Font("Verdana", Font.PLAIN, 10);
+ JPanel urlPaneContainer = new JPanel(new BorderLayout(5, 5));
+ urlPaneContainer.setBorder(BorderFactory.createCompoundBorder(
+ BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(),
+ "Slivka Web Services"),
+ BorderFactory.createEmptyBorder(10, 5, 5, 5)));
+
+ newWsUrl.setFont(font);
+ editWsUrl.setFont(font);
+ deleteWsUrl.setFont(font);
+ moveUrlUp.setFont(font);
+ moveUrlDown.setFont(font);
+ JPanel editContainer = new JPanel();
+ editContainer.add(newWsUrl);
+ editContainer.add(editWsUrl);
+ editContainer.add(deleteWsUrl);
+ urlPaneContainer.add(editContainer, BorderLayout.PAGE_END);
+
+ JPanel moveContainer = new JPanel();
+ moveContainer
+ .setLayout(new BoxLayout(moveContainer, BoxLayout.PAGE_AXIS));
+ moveContainer.add(moveUrlUp);
+ moveContainer.add(Box.createRigidArea(new Dimension(0, 5)));
+ moveContainer.add(moveUrlDown);
+ urlPaneContainer.add(moveContainer, BorderLayout.LINE_START);
+
+ urlPaneContainer.add(new JScrollPane(urlListTable),
+ BorderLayout.CENTER);
+ this.add(urlPaneContainer);
+
+ // Connecting action listeners
+ urlListTable.addMouseListener(tableClickListener);
+ newWsUrl.addActionListener(newUrlAction);
+ editWsUrl.addActionListener(editUrlAction);
+ deleteWsUrl.addActionListener(deleteUrlAction);
+ moveUrlUp.addActionListener(moveUrlUpAction);
+ moveUrlDown.addActionListener(moveUrlDownAction);
+ }
+
+ private void moveTableRow(int fromIndex, int toIndex)
+ {
+ String url = urls.get(fromIndex);
+ int status = statuses.get(fromIndex);
+ urls.set(fromIndex, urls.get(toIndex));
+ statuses.set(fromIndex, statuses.get(toIndex));
+ urls.set(toIndex, url);
+ statuses.set(toIndex, status);
+ if (urlListTable.getSelectedRow() == fromIndex)
+ {
+ urlListTable.setRowSelectionInterval(toIndex, toIndex);
+ }
+ int firstRow = Math.min(toIndex, fromIndex);
+ int lastRow = Math.max(fromIndex, toIndex);
+ urlTableModel.fireTableRowsUpdated(firstRow, lastRow);
+ }
+
+ // Discoverer reloading buttons
+ JButton refreshServices = new JButton(
+ MessageManager.getString("action.refresh_services"));
+
+ JButton resetServices = new JButton(
+ MessageManager.getString("action.reset_services"));
+
+ JProgressBar progressBar = new JProgressBar();
+
+ // Discoverer buttons action listeners
+ private ActionListener refreshServicesAction = (ActionEvent e) -> {
+ progressBar.setVisible(true);
+ Cache.log.info("Requesting service reload");
+ discoverer.startDiscoverer().handle((_discoverer, exception) -> {
+ if (exception == null)
+ {
+ Cache.log.info("Reloading done");
+ }
+ else
+ {
+ Cache.log.error("Reloading failed", exception);
+ }
+ SwingUtilities.invokeLater(() -> progressBar.setVisible(false));
+ return null;
+ });
+ };
+
+ private ActionListener resetServicesAction = (ActionEvent e) -> {
+ discoverer.setServiceUrls(null);
+ urls.clear();
+ statuses.clear();
+ urls.addAll(discoverer.getServiceUrls());
+ for (String url : urls)
+ {
+ statuses.add(discoverer.getServerStatusFor(url));
+ }
+ urlTableModel.fireTableDataChanged();
+ };
+
+ {
+ Font font = new Font("Verdana", Font.PLAIN, 11);
+ refreshServices.setFont(font);
+ resetServices.setFont(font);
+ JPanel container = new JPanel();
+ container.add(refreshServices);
+ container.add(resetServices);
+ this.add(container);
+
+ // Connecting action listeners
+ refreshServices.addActionListener(refreshServicesAction);
+ resetServices.addActionListener(resetServicesAction);
+ }
+
+ {
+ progressBar.setVisible(false);
+ progressBar.setIndeterminate(true);
+ add(progressBar);
+ }
+
+ SlivkaPreferences()
+ {
+ // Initial URLs loading
+ discoverer = SlivkaWSDiscoverer.getInstance();
+ urls.addAll(discoverer.getServiceUrls());
+ for (String url : urls)
+ {
+ statuses.add(discoverer.getServerStatusFor(url));
+ }
+ }
+}
diff --git a/src/jalview/gui/SplitFrame.java b/src/jalview/gui/SplitFrame.java
index 953755f..c4b47a0 100644
--- a/src/jalview/gui/SplitFrame.java
+++ b/src/jalview/gui/SplitFrame.java
@@ -20,6 +20,19 @@
*/
package jalview.gui;
+import jalview.api.AlignViewportI;
+import jalview.api.AlignViewControllerGuiI;
+import jalview.api.FeatureSettingsControllerI;
+import jalview.api.SplitContainerI;
+import jalview.controller.FeatureSettingsControllerGuiI;
+import jalview.datamodel.AlignmentI;
+import jalview.jbgui.GAlignFrame;
+import jalview.jbgui.GSplitFrame;
+import jalview.structure.StructureSelectionManager;
+import jalview.util.MessageManager;
+import jalview.util.Platform;
+import jalview.viewmodel.AlignmentViewport;
+
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
@@ -49,18 +62,6 @@ import javax.swing.event.ChangeListener;
import javax.swing.event.InternalFrameAdapter;
import javax.swing.event.InternalFrameEvent;
-import jalview.api.AlignViewControllerGuiI;
-import jalview.api.FeatureSettingsControllerI;
-import jalview.api.SplitContainerI;
-import jalview.controller.FeatureSettingsControllerGuiI;
-import jalview.datamodel.AlignmentI;
-import jalview.jbgui.GAlignFrame;
-import jalview.jbgui.GSplitFrame;
-import jalview.structure.StructureSelectionManager;
-import jalview.util.MessageManager;
-import jalview.util.Platform;
-import jalview.viewmodel.AlignmentViewport;
-
/**
* An internal frame on the desktop that hosts a horizontally split view of
* linked DNA and Protein alignments. Additional views can be created in linked
@@ -230,8 +231,8 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
topFrame.alignPanel.adjustAnnotationHeight();
bottomFrame.alignPanel.adjustAnnotationHeight();
- final AlignViewport topViewport = topFrame.viewport;
- final AlignViewport bottomViewport = bottomFrame.viewport;
+ final AlignViewportI topViewport = topFrame.viewport;
+ final AlignViewportI bottomViewport = bottomFrame.viewport;
final AlignmentI topAlignment = topViewport.getAlignment();
final AlignmentI bottomAlignment = bottomViewport.getAlignment();
boolean topAnnotations = topViewport.isShowAnnotation();
@@ -1100,4 +1101,4 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
{
return featureSettingsUI != null && !featureSettingsUI.isClosed();
}
-}
\ No newline at end of file
+}
diff --git a/src/jalview/gui/StructureChooser.java b/src/jalview/gui/StructureChooser.java
index 47c9a00..97b0cfb 100644
--- a/src/jalview/gui/StructureChooser.java
+++ b/src/jalview/gui/StructureChooser.java
@@ -1283,6 +1283,12 @@ public class StructureChooser extends GStructureChooser
{
progressBar.setProgressBar(message, id);
}
+
+ @Override
+ public void removeProgressBar(long id)
+ {
+ progressBar.removeProgressBar(id);
+ }
@Override
public void registerHandler(long id, IProgressIndicatorHandler handler)
diff --git a/src/jalview/gui/WebserviceInfo.java b/src/jalview/gui/WebserviceInfo.java
index ab9444e..b88102e 100644
--- a/src/jalview/gui/WebserviceInfo.java
+++ b/src/jalview/gui/WebserviceInfo.java
@@ -929,6 +929,12 @@ public void hyperlinkUpdate(HyperlinkEvent e)
{
progressBar.setProgressBar(message, id);
}
+
+ @Override
+ public void removeProgressBar(long id)
+ {
+ progressBar.removeProgressBar(id);
+ }
@Override
public void registerHandler(final long id,
diff --git a/src/jalview/gui/WsJobParameters.java b/src/jalview/gui/WsJobParameters.java
index 45822a3..719b7d9 100644
--- a/src/jalview/gui/WsJobParameters.java
+++ b/src/jalview/gui/WsJobParameters.java
@@ -23,10 +23,7 @@ package jalview.gui;
import jalview.gui.OptsAndParamsPage.OptionBox;
import jalview.gui.OptsAndParamsPage.ParamBox;
import jalview.util.MessageManager;
-import jalview.ws.jws2.JabaParamStore;
-import jalview.ws.jws2.JabaPreset;
-import jalview.ws.jws2.Jws2Discoverer;
-import jalview.ws.jws2.jabaws2.Jws2Instance;
+import jalview.ws.api.UIinfo;
import jalview.ws.params.ArgumentI;
import jalview.ws.params.OptionI;
import jalview.ws.params.ParamDatastoreI;
@@ -48,33 +45,21 @@ import java.awt.event.HierarchyBoundsListener;
import java.awt.event.HierarchyEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
-import java.awt.event.WindowEvent;
-import java.awt.event.WindowListener;
-import java.net.URL;
import java.util.Hashtable;
-import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
-import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
-import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.border.TitledBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
-import compbio.metadata.Argument;
-import compbio.metadata.Option;
-import compbio.metadata.Parameter;
-import compbio.metadata.Preset;
-import compbio.metadata.PresetManager;
-import compbio.metadata.RunnerConfig;
import net.miginfocom.swing.MigLayout;
/**
@@ -95,36 +80,35 @@ import net.miginfocom.swing.MigLayout;
public class WsJobParameters extends JPanel implements ItemListener,
ActionListener, DocumentListener, OptsParametersContainerI
{
- URL linkImageURL = getClass().getResource("/images/link.gif");
+ private static final int PREFERRED_WIDTH = 540;
- private static final String SVC_DEF = "Defaults"; // this is the null
- // parameter set as shown to
- // user
+ private static final int DEFAULT_HEIGHT = 640;
+
+ // the default parameter set shown to the user
+ private static final String SVC_DEF = "Defaults";
+
+ private int maxOptWidth = 200;
+
+ // URL linkImageURL = getClass().getResource("/images/link.gif");
+
+ // TODO ABSRACT FROM JABAWS CLASSES
/**
* manager for options and parameters.
*/
- OptsAndParamsPage opanp = new OptsAndParamsPage(this);
+ OptsAndParamsPage opanp;
- /**
+ /*
* panel containing job options
*/
- JPanel jobOptions = new JPanel();
+ JPanel optionsPanel = new JPanel();
- /**
+ /*
* panel containing job parameters
*/
- JPanel paramList = new JPanel();
-
- JPanel SetNamePanel = new JPanel();
-
- JPanel setDetails = new JPanel();
-
- JSplitPane settingsPanel = new JSplitPane();
-
- JPanel jobPanel = new JPanel();
+ JPanel paramsPanel = new JPanel();
- JScrollPane jobOptionsPane = new JScrollPane();
+ JPanel setNamePanel = new JPanel();
JButton createpref = new JButton();
@@ -134,81 +118,80 @@ public class WsJobParameters extends JPanel implements ItemListener,
JButton updatepref = new JButton();
- JButton startjob = new JButton();
-
- JButton canceljob = new JButton();
-
- JComboBox setName = new JComboBox();
+ JComboBox setName = new JComboBox<>();
JTextArea setDescr = new JTextArea();
JScrollPane paramPane = new JScrollPane();
- // ScrollablePanel optsAndparams = new ScrollablePanel();
- JPanel optsAndparams = new JPanel();
-
- RunnerConfig serviceOptions;
-
ParamDatastoreI paramStore;
- private int MAX_OPTWIDTH = 200;
+ // set true when 'Start Job' is clicked
+ boolean startJob = false;
- WsJobParameters(Jws2Instance service)
- {
- this(service, null);
- }
+ JDialog frame = null;
- public WsJobParameters(Jws2Instance service, WsParamSetI preset)
- {
- this(null, service, preset, null);
- }
+ UIinfo service;
- /**
- *
- * @param desktop
- * - if null, create new JFrame outside of desktop
- * @param service
- * @param preset
+ /*
+ * list of service presets in the gui
+ */
+ Hashtable servicePresets = null;
+
+ /*
+ * set if dialog is being set - so handlers will avoid spurious events
*/
- public WsJobParameters(JFrame parent, Jws2Instance service,
- WsParamSetI preset, List jobArgset)
+ boolean settingDialog = false;
+
+ private Hashtable modifiedElements = new Hashtable<>();
+
+ String lastParmSet = null;
+
+ public WsJobParameters(ParamDatastoreI store, WsParamSetI preset,
+ List args)
{
- this(parent, null, service, preset, jobArgset);
+ super();
+
+ // parameters dialog in 'compact' format (help as tooltips)
+ opanp = new OptsAndParamsPage(this, true);
+ jbInit();
+ this.paramStore = store;
+ this.service = null;
+ init(preset, args);
+ validate();
}
/**
+ * Constructor given a set of parameters and presets, a service to be invoked,
+ * and a list of (Jabaws client) arguments
*
- * @param parent
* @param paramStorei
* @param service
* @param preset
* @param jobArgset
*/
- public WsJobParameters(JFrame parent, ParamDatastoreI paramStorei,
- Jws2Instance service, WsParamSetI preset,
- List jobArgset)
+ public WsJobParameters(ParamDatastoreI paramStorei, UIinfo service,
+ WsParamSetI preset, List jobArgset)
{
super();
+
+ // parameters dialog in 'expanded' format (help text boxes)
+ opanp = new OptsAndParamsPage(this, false);
+
jbInit();
this.paramStore = paramStorei;
- if (paramStore == null)
+ if (paramStore == null && service != null)
{
paramStore = service.getParamStore();
}
this.service = service;
- // argSetModified(false);
- // populate parameter table
- initForService(service, preset, jobArgset);
- // display in new JFrame attached to parent.
+ initForService(preset, jobArgset);
validate();
}
- int response = -1;
-
- JDialog frame = null;
-
/**
- * shows a modal dialog containing the parameters.
+ * Shows a modal dialog containing the parameters and Start or Cancel options.
+ * Answers true if the job is started, false if cancelled.
*
* @return
*/
@@ -216,7 +199,12 @@ public class WsJobParameters extends JPanel implements ItemListener,
{
frame = new JDialog(Desktop.getInstance(), true);
-
+ if (service != null)
+ {
+ frame.setTitle(MessageManager.formatMessage("label.edit_params_for",
+ new String[]
+ { service.getActionText() }));
+ }
frame.setTitle(MessageManager.formatMessage("label.edit_params_for",
new String[]
{ service.getActionText() }));
@@ -242,11 +230,7 @@ public class WsJobParameters extends JPanel implements ItemListener,
});
frame.setVisible(true);
- if (response > 0)
- {
- return true;
- }
- return false;
+ return startJob;
}
private void jbInit()
@@ -276,7 +260,7 @@ public class WsJobParameters extends JPanel implements ItemListener,
@Override
public void actionPerformed(ActionEvent e)
{
- update_actionPerformed(e);
+ update_actionPerformed();
}
});
deletepref = JvSwingUtils.makeButton(
@@ -288,7 +272,7 @@ public class WsJobParameters extends JPanel implements ItemListener,
@Override
public void actionPerformed(ActionEvent e)
{
- delete_actionPerformed(e);
+ delete_actionPerformed();
}
});
createpref = JvSwingUtils.makeButton(
@@ -300,7 +284,7 @@ public class WsJobParameters extends JPanel implements ItemListener,
@Override
public void actionPerformed(ActionEvent e)
{
- create_actionPerformed(e);
+ create_actionPerformed();
}
});
revertpref = JvSwingUtils.makeButton(
@@ -313,10 +297,11 @@ public class WsJobParameters extends JPanel implements ItemListener,
@Override
public void actionPerformed(ActionEvent e)
{
- revert_actionPerformed(e);
+ revert_actionPerformed();
}
});
- startjob = JvSwingUtils.makeButton(
+
+ JButton startjob = JvSwingUtils.makeButton(
MessageManager.getString("action.start_job"),
MessageManager.getString("label.start_job_current_settings"),
new ActionListener()
@@ -324,10 +309,10 @@ public class WsJobParameters extends JPanel implements ItemListener,
@Override
public void actionPerformed(ActionEvent e)
{
- startjob_actionPerformed(e);
+ startjob_actionPerformed();
}
});
- canceljob = JvSwingUtils.makeButton(
+ JButton canceljob = JvSwingUtils.makeButton(
MessageManager.getString("action.cancel_job"),
MessageManager.getString("label.cancel_job_close_dialog"),
new ActionListener()
@@ -335,10 +320,11 @@ public class WsJobParameters extends JPanel implements ItemListener,
@Override
public void actionPerformed(ActionEvent e)
{
- canceljob_actionPerformed(e);
+ canceljob_actionPerformed();
}
});
+ JPanel setDetails = new JPanel();
setDetails.setBorder(
new TitledBorder(MessageManager.getString("label.details")));
setDetails.setLayout(new BorderLayout());
@@ -357,7 +343,7 @@ public class WsJobParameters extends JPanel implements ItemListener,
setName.getEditor().addActionListener(this);
JPanel setNameInfo = new JPanel(new FlowLayout(FlowLayout.LEFT));
GridBagLayout gbl = new GridBagLayout();
- SetNamePanel.setLayout(gbl);
+ setNamePanel.setLayout(gbl);
JLabel setNameLabel = new JLabel(
MessageManager.getString("label.current_parameter_set_name"));
@@ -372,9 +358,7 @@ public class WsJobParameters extends JPanel implements ItemListener,
revertpref.setVisible(false);
createpref.setVisible(false);
JPanel setsavebuts = new JPanel();
- setsavebuts.setLayout(new FlowLayout(FlowLayout.LEFT)); // GridLayout(1,2));
- ((FlowLayout) setsavebuts.getLayout()).setHgap(10);
- ((FlowLayout) setsavebuts.getLayout()).setVgap(0);
+ setsavebuts.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 0)); // GridLayout(1,2));
JPanel spacer = new JPanel();
spacer.setPreferredSize(new Dimension(2, 30));
setsavebuts.add(spacer);
@@ -385,11 +369,11 @@ public class WsJobParameters extends JPanel implements ItemListener,
// setsavebuts.setSize(new Dimension(150, 30));
JPanel buttonArea = new JPanel(new GridLayout(1, 1));
buttonArea.add(setsavebuts);
- SetNamePanel.add(setNameInfo);
+ setNamePanel.add(setNameInfo);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridheight = 2;
gbl.setConstraints(setNameInfo, gbc);
- SetNamePanel.add(buttonArea);
+ setNamePanel.add(buttonArea);
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 2;
@@ -399,36 +383,33 @@ public class WsJobParameters extends JPanel implements ItemListener,
// paramPane.setPreferredSize(new Dimension(360, 400));
// paramPane.setPreferredSize(null);
- jobOptions.setBorder(
+ optionsPanel.setBorder(
new TitledBorder(MessageManager.getString("label.options")));
- jobOptions.setOpaque(true);
- paramList.setBorder(
+ optionsPanel.setOpaque(true);
+ paramsPanel.setBorder(
new TitledBorder(MessageManager.getString("label.parameters")));
- paramList.setOpaque(true);
- JPanel bjo = new JPanel(new BorderLayout()),
- bjp = new JPanel(new BorderLayout());
- bjo.add(jobOptions, BorderLayout.CENTER);
- bjp.add(paramList, BorderLayout.CENTER);
- bjp.setOpaque(true);
- bjo.setOpaque(true);
+ paramsPanel.setOpaque(true);
// optsAndparams.setScrollableWidth(ScrollableSizeHint.FIT);
// optsAndparams.setScrollableHeight(ScrollableSizeHint.NONE);
// optsAndparams.setLayout(new BorderLayout());
+ JPanel optsAndparams = new JPanel();
optsAndparams.setLayout(new BorderLayout());
- optsAndparams.add(jobOptions, BorderLayout.NORTH);
- optsAndparams.add(paramList, BorderLayout.CENTER);
+ optsAndparams.add(optionsPanel, BorderLayout.NORTH);
+ optsAndparams.add(paramsPanel, BorderLayout.CENTER);
JPanel jp = new JPanel(new BorderLayout());
jp.add(optsAndparams, BorderLayout.CENTER);
paramPane.getViewport().setView(jp);
paramPane.setBorder(null);
setLayout(new BorderLayout());
+
+ JPanel jobPanel = new JPanel();
jobPanel.setPreferredSize(null);
jobPanel.setLayout(new BorderLayout());
jobPanel.add(setDetails, BorderLayout.NORTH);
jobPanel.add(paramPane, BorderLayout.CENTER);
// jobPanel.setOrientation(JSplitPane.VERTICAL_SPLIT);
- add(SetNamePanel, BorderLayout.NORTH);
+ add(setNamePanel, BorderLayout.NORTH);
add(jobPanel, BorderLayout.CENTER);
JPanel dialogpanel = new JPanel();
@@ -436,20 +417,20 @@ public class WsJobParameters extends JPanel implements ItemListener,
dialogpanel.add(canceljob);
// JAL-1580: setMaximumSize() doesn't work, so just size for the worst case:
// check for null is for JUnit usage
- final int windowHeight = Desktop.getInstance() == null ? 540
+ final int windowHeight = Desktop.getInstance() == null ? DEFAULT_HEIGHT
: Desktop.getInstance().getHeight();
setPreferredSize(new Dimension(540, windowHeight));
add(dialogpanel, BorderLayout.SOUTH);
validate();
}
- protected void revert_actionPerformed(ActionEvent e)
+ protected void revert_actionPerformed()
{
reInitDialog(lastParmSet);
updateWebServiceMenus();
}
- protected void update_actionPerformed(ActionEvent e)
+ protected void update_actionPerformed()
{
if (isUserPreset)
{
@@ -467,7 +448,7 @@ public class WsJobParameters extends JPanel implements ItemListener,
paramStore.deletePreset(lastParmSet2);
}
- protected void delete_actionPerformed(ActionEvent e)
+ protected void delete_actionPerformed()
{
if (isUserPreset)
{
@@ -478,7 +459,7 @@ public class WsJobParameters extends JPanel implements ItemListener,
updateWebServiceMenus();
}
- protected void create_actionPerformed(ActionEvent e)
+ protected void create_actionPerformed()
{
String curname = ((String) setName.getSelectedItem()).trim();
if (curname.length() > 0)
@@ -497,55 +478,40 @@ public class WsJobParameters extends JPanel implements ItemListener,
}
}
- protected void canceljob_actionPerformed(ActionEvent e)
+ protected void canceljob_actionPerformed()
{
- response = 0;
+ startJob = false;
if (frame != null)
{
frame.setVisible(false);
}
}
- protected void startjob_actionPerformed(ActionEvent e)
+ protected void startjob_actionPerformed()
{
- response = 1;
+ startJob = true;
if (frame != null)
{
frame.setVisible(false);
}
}
- Jws2Instance service;
+ void initForService(WsParamSetI paramSet, List jobArgset)
+ {
+ settingDialog = true;
- /**
- * list of service presets in the gui
- */
- Hashtable servicePresets = null;
+ init(paramSet, jobArgset);
- /**
- * set if dialog is being set - so handlers will avoid spurious events
- */
- boolean settingDialog = false;
+ }
- void initForService(Jws2Instance service, WsParamSetI jabap,
- List jabajobArgset)
+ void init(WsParamSetI p, List jobArgset)
{
- WsParamSetI p = null;
- List jobArgset = null;
- settingDialog = true;
- { // instantiate the abstract proxy for Jaba objects
- jobArgset = jabajobArgset == null ? null
- : JabaParamStore.getJwsArgsfromJaba(jabajobArgset);
- p = jabap; // (jabap != null) ? paramStore.getPreset(jabap.getName()) :
- // null;
- }
-
- Hashtable exnames = new Hashtable();
+ Hashtable exnames = new Hashtable<>();
for (int i = 0, iSize = setName.getItemCount(); i < iSize; i++)
{
exnames.put(setName.getItemAt(i), setName.getItemAt(i));
}
- servicePresets = new Hashtable();
+ servicePresets = new Hashtable<>();
// Add the default entry - if not present already.
if (!exnames.contains(SVC_DEF))
{
@@ -553,7 +519,8 @@ public class WsJobParameters extends JPanel implements ItemListener,
exnames.put(SVC_DEF, SVC_DEF);
servicePresets.put(SVC_DEF, SVC_DEF);
}
- String curname = (p == null ? "" : p.getName());
+
+ // String curname = (p == null ? "" : p.getName());
for (WsParamSetI pr : paramStore.getPresets())
{
if (!pr.isModifiable())
@@ -593,10 +560,8 @@ public class WsJobParameters extends JPanel implements ItemListener,
}
}
settingDialog = false;
-
}
- @SuppressWarnings("unchecked")
private void updateTable(WsParamSetI p, List jobArgset)
{
boolean setDefaultParams = false;
@@ -633,9 +598,9 @@ public class WsJobParameters extends JPanel implements ItemListener,
OptionI opt = (OptionI) myarg;
OptionBox ob = opanp.addOption(opt);
ob.resetToDefault(setDefaultParams);
- if (MAX_OPTWIDTH < ob.getPreferredSize().width)
+ if (maxOptWidth < ob.getPreferredSize().width)
{
- MAX_OPTWIDTH = ob.getPreferredSize().width;
+ maxOptWidth = ob.getPreferredSize().width;
}
ob.validate();
cw += ob.getPreferredSize().width + 5;
@@ -704,8 +669,6 @@ public class WsJobParameters extends JPanel implements ItemListener,
return modifiedElements.size() > 0;
}
- private Hashtable modifiedElements = new Hashtable();
-
/**
* reset gui and modification state settings
*/
@@ -770,7 +733,7 @@ public class WsJobParameters extends JPanel implements ItemListener,
if (b && modifiedElements.size() > 0)
{
makeSetNameValid(!isUserPreset);
- SetNamePanel.revalidate();
+ setNamePanel.revalidate();
}
updateButtonDisplay();
}
@@ -817,7 +780,7 @@ public class WsJobParameters extends JPanel implements ItemListener,
// sync the gui with the preset database
for (int i = 0, iS = setName.getItemCount(); i < iS; i++)
{
- String snm = (String) setName.getItemAt(i);
+ String snm = setName.getItemAt(i);
if (snm.equals(nm))
{
makeupdate = true;
@@ -837,96 +800,88 @@ public class WsJobParameters extends JPanel implements ItemListener,
settingDialog = stn;
}
+ /**
+ * Rebuilds the Options and Parameters panels
+ */
@Override
public void refreshParamLayout()
{
- // optsAndparams.setPreferredSize(null);
- FlowLayout fl = new FlowLayout(FlowLayout.LEFT);
- int sep = fl.getVgap();
- boolean fh = true;
- int os = 0,
- s = jobOptions.getBorder().getBorderInsets(jobOptions).bottom
- + jobOptions.getBorder().getBorderInsets(jobOptions).top
- + 2 * sep;
- /**
- * final height for viewport
- */
- int finalh = s;
- int panewidth = paramPane.getViewport().getSize().width - 120
- - jobOptions.getBorder().getBorderInsets(jobOptions).left
- + jobOptions.getBorder().getBorderInsets(jobOptions).right;
-
- int w = 2 * fl.getHgap()
- + (MAX_OPTWIDTH > OptsAndParamsPage.PARAM_WIDTH ? MAX_OPTWIDTH
- : OptsAndParamsPage.PARAM_WIDTH);
- int hgap = fl.getHgap(), cw = hgap;
+ final int rightMargin = 40;
+ final int availableWidth = paramPane.getViewport().getSize().width
+ - rightMargin
+ - optionsPanel.getBorder().getBorderInsets(optionsPanel).left
+ + optionsPanel.getBorder().getBorderInsets(optionsPanel).right;
if (opanp.getOptSet().size() > 0)
{
+ int hgap = 5;
+ int currentWidth = hgap;
- jobOptions.setLayout(new MigLayout("", "", ""));
- jobOptions.removeAll();
+ /*
+ * layout constraint 'nogrid' prevents vertical column alignment,
+ * allowing controls to flow without extra space inserted to align
+ */
+ optionsPanel.setLayout(new MigLayout("nogrid", "", ""));
+ optionsPanel.removeAll();
+ JPanel lastAdded = null;
+ /*
+ * add each control in turn; if adding would overflow the right margin,
+ * remove and re-add the previous parameter with "wrap" (after)
+ * in order to start a new row
+ */
for (OptionBox pbox : opanp.getOptSet().values())
{
pbox.validate();
- cw += pbox.getSize().width + hgap;
- if (cw + 120 > panewidth)
- {
- jobOptions.add(pbox, "wrap");
- // System.out.println("Wrap on "+pbox.option.getName());
- cw = hgap + pbox.getSize().width;
- fh = true;
- }
- else
- {
- jobOptions.add(pbox);
- }
- if (fh)
+ int boxWidth = pbox.getSize().width;
+ currentWidth += boxWidth + hgap;
+ boolean wrapAfterLast = currentWidth > availableWidth
+ && lastAdded != null;
+ // System.out.println(String.format(
+ // "%s width=%d, paneWidth=%d, currentWidth=%d, wrapAfterLast=%s",
+ // pbox.toString(), boxWidth, panewidth, currentWidth,
+ // wrapAfterLast));
+ if (wrapAfterLast)
{
- finalh += pbox.getSize().height + fl.getVgap();
- fh = false;
+ optionsPanel.remove(lastAdded);
+ optionsPanel.add(lastAdded, "wrap");
+ currentWidth = hgap + boxWidth;
}
+ optionsPanel.add(pbox);
+ lastAdded = pbox;
}
- jobOptions.revalidate();
+ optionsPanel.revalidate();
}
else
{
- jobOptions.setVisible(false);
+ optionsPanel.setVisible(false);
}
- // Now layout the parameters assuming they occupy one column - to calculate
- // total height of options+parameters
- fl = new FlowLayout(FlowLayout.LEFT);
- // helpful hint from
- // http://stackoverflow.com/questions/2743177/top-alignment-for-flowlayout
- fl.setAlignOnBaseline(true);
if (opanp.getParamSet().size() > 0)
{
- paramList.removeAll();
- paramList.setLayout(new MigLayout("", "", ""));
- fh = true;
+ paramsPanel.removeAll();
+ paramsPanel.setLayout(new MigLayout("", "", ""));
+ int hgap = 5;
+ int currentWidth = hgap;
+
+ JPanel lastAdded = null;
for (ParamBox pbox : opanp.getParamSet().values())
{
pbox.validate();
- cw += pbox.getSize().width + hgap;
- if (cw + 160 > panewidth)
+ int boxWidth = pbox.getSize().width;
+ currentWidth += boxWidth + hgap;
+ boolean wrapAfterLast = currentWidth > availableWidth
+ && lastAdded != null;
+ if (wrapAfterLast)
{
- paramList.add(pbox, "wrap");
- cw = pbox.getSize().width + hgap;
- fh = true;
+ paramsPanel.remove(lastAdded);
+ paramsPanel.add(lastAdded, "wrap");
+ currentWidth = pbox.getSize().width + hgap;
}
- else
- {
- paramList.add(pbox);
- }
- if (fh)
- {
- finalh += pbox.getSize().height + fl.getVgap();
- fh = false;
- }
-
+ paramsPanel.add(pbox);
+ lastAdded = pbox;
}
+
/*
* s = 2 * sep; for (ParamBox pbox : opanp.getParamSet().values()) {
* pbox.validate(); s += sep +
@@ -938,11 +893,11 @@ public class WsJobParameters extends JPanel implements ItemListener,
* .getBorder().getBorderInsets(paramList).bottom+paramList
* .getBorder().getBorderInsets(paramList).top;
*/
- paramList.revalidate();
+ paramsPanel.revalidate();
}
else
{
- paramList.setVisible(false);
+ paramsPanel.setVisible(false);
}
// TODO: waste some time trying to eliminate any unnecessary .validate calls
// here
@@ -953,244 +908,6 @@ public class WsJobParameters extends JPanel implements ItemListener,
paramPane.revalidate();
revalidate();
}
-
- /**
- * testing method - grab a service and parameter set and show the window
- *
- * @param args
- * @j2sIgnore
- */
- public static void main(String[] args)
- {
- jalview.ws.jws2.Jws2Discoverer disc = jalview.ws.jws2.Jws2Discoverer
- .getInstance();
- int p = 0;
- if (args.length > 0)
- {
- Vector services = new Vector<>();
- services.addElement(args[p++]);
- Jws2Discoverer.getInstance().setServiceUrls(services);
- }
- try
- {
- disc.run();
- } catch (Exception e)
- {
- System.err.println("Aborting. Problem discovering services.");
- e.printStackTrace();
- return;
- }
- Jws2Instance lastserv = null;
- for (Jws2Instance service : disc.getServices())
- {
- lastserv = service;
- if (p >= args.length || service.serviceType.equalsIgnoreCase(args[p]))
- {
- if (lastserv != null)
- {
- List prl = null;
- Preset pr = null;
- if (++p < args.length)
- {
- PresetManager prman = lastserv.getPresets();
- if (prman != null)
- {
- pr = prman.getPresetByName(args[p]);
- if (pr == null)
- {
- // just grab the last preset.
- prl = prman.getPresets();
- }
- }
- }
- else
- {
- PresetManager prman = lastserv.getPresets();
- if (prman != null)
- {
- prl = prman.getPresets();
- }
- }
- Iterator en = (prl == null) ? null : prl.iterator();
- while (en != null && en.hasNext())
- {
- if (en != null)
- {
- if (!en.hasNext())
- {
- en = prl.iterator();
- }
- pr = en.next();
- }
- {
- System.out.println("Testing opts dupes for "
- + lastserv.getUri() + " : " + lastserv.getActionText()
- + ":" + pr.getName());
- List rg = lastserv.getRunnerConfig().getOptions();
- for (Option o : rg)
- {
- try
- {
- Option cpy = jalview.ws.jws2.ParameterUtils.copyOption(o);
- } catch (Exception e)
- {
- System.err.println("Failed to copy " + o.getName());
- e.printStackTrace();
- } catch (Error e)
- {
- System.err.println("Failed to copy " + o.getName());
- e.printStackTrace();
- }
- }
- }
- {
- System.out.println("Testing param dupes:");
- List rg = lastserv.getRunnerConfig()
- .getParameters();
- for (Parameter o : rg)
- {
- try
- {
- Parameter cpy = jalview.ws.jws2.ParameterUtils
- .copyParameter(o);
- } catch (Exception e)
- {
- System.err.println("Failed to copy " + o.getName());
- e.printStackTrace();
- } catch (Error e)
- {
- System.err.println("Failed to copy " + o.getName());
- e.printStackTrace();
- }
- }
- }
- {
- System.out.println("Testing param write:");
- List writeparam = null, readparam = null;
- try
- {
- writeparam = jalview.ws.jws2.ParameterUtils
- .writeParameterSet(
- pr.getArguments(lastserv.getRunnerConfig()),
- " ");
- System.out.println("Testing param read :");
- List pset = jalview.ws.jws2.ParameterUtils
- .processParameters(writeparam,
- lastserv.getRunnerConfig(), " ");
- readparam = jalview.ws.jws2.ParameterUtils
- .writeParameterSet(pset, " ");
- Iterator o = pr.getOptions().iterator(),
- s = writeparam.iterator(), t = readparam.iterator();
- boolean failed = false;
- while (s.hasNext() && t.hasNext())
- {
- String on = o.next(), sn = s.next(), st = t.next();
- if (!sn.equals(st))
- {
- System.out.println(
- "Original was " + on + " Phase 1 wrote " + sn
- + "\tPhase 2 wrote " + st);
- failed = true;
- }
- }
- if (failed)
- {
- System.out.println(
- "Original parameters:\n" + pr.getOptions());
- System.out.println(
- "Wrote parameters in first set:\n" + writeparam);
- System.out.println(
- "Wrote parameters in second set:\n" + readparam);
-
- }
- } catch (Exception e)
- {
- e.printStackTrace();
- }
- }
- WsJobParameters pgui = new WsJobParameters(lastserv,
- new JabaPreset(lastserv, pr));
- JFrame jf = new JFrame(MessageManager
- .formatMessage("label.ws_parameters_for", new String[]
- { lastserv.getActionText() }));
- JPanel cont = new JPanel(new BorderLayout());
- pgui.validate();
- cont.setPreferredSize(pgui.getPreferredSize());
- cont.add(pgui, BorderLayout.CENTER);
- jf.setLayout(new BorderLayout());
- jf.add(cont, BorderLayout.CENTER);
- jf.validate();
- final Thread thr = Thread.currentThread();
- jf.addWindowListener(new WindowListener()
- {
-
- @Override
- public void windowActivated(WindowEvent e)
- {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void windowClosed(WindowEvent e)
- {
- }
-
- @Override
- public void windowClosing(WindowEvent e)
- {
- thr.interrupt();
-
- }
-
- @Override
- public void windowDeactivated(WindowEvent e)
- {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void windowDeiconified(WindowEvent e)
- {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void windowIconified(WindowEvent e)
- {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void windowOpened(WindowEvent e)
- {
- // TODO Auto-generated method stub
-
- }
-
- });
- jf.setVisible(true);
- boolean inter = false;
- while (!inter)
- {
- try
- {
- Thread.sleep(10000);
- } catch (Exception e)
- {
- inter = true;
- }
- }
- jf.dispose();
- }
- }
- }
- }
- }
-
public boolean isServiceDefaults()
{
return (!isModified()
@@ -1202,8 +919,6 @@ public class WsJobParameters extends JPanel implements ItemListener,
return opanp.getCurrentSettings();
}
- String lastParmSet = null;
-
/*
* Hashtable editedParams = new Hashtable();
@@ -1243,10 +958,10 @@ public class WsJobParameters extends JPanel implements ItemListener,
int n = 0;
// remove any set names in the drop down menu that aren't either a reserved
// setting, or a user defined or service preset.
- Vector items = new Vector();
+ Vector items = new Vector<>();
while (n < setName.getItemCount())
{
- String item = (String) setName.getItemAt(n);
+ String item = setName.getItemAt(n);
if (!item.equals(SVC_DEF) && !paramStore.presetExists(item))
{
setName.removeItemAt(n);
@@ -1314,7 +1029,7 @@ public class WsJobParameters extends JPanel implements ItemListener,
initArgSetModified();
syncSetNamesWithStore();
setName.setSelectedItem(lastParmSet);
- SetNamePanel.validate();
+ setNamePanel.validate();
validate();
settingDialog = false;
}
@@ -1325,9 +1040,13 @@ public class WsJobParameters extends JPanel implements ItemListener,
*/
protected void updateWebServiceMenus()
{
+ if (Desktop.getInstance() == null)
+ {
+ return;
+ }
for (AlignFrame alignFrame : Desktop.getAlignFrames())
{
- alignFrame.BuildWebServiceMenu();
+ alignFrame.buildWebServicesMenu();
}
}
@@ -1336,11 +1055,12 @@ public class WsJobParameters extends JPanel implements ItemListener,
@Override
public void itemStateChanged(ItemEvent e)
{
- if (e.getSource() == setName && e.getStateChange() == e.SELECTED)
+ if (e.getSource() == setName
+ && e.getStateChange() == ItemEvent.SELECTED)
{
final String setname = (String) setName.getSelectedItem();
- System.out.println("Item state changed for " + setname
- + " (handling ? " + !settingDialog + ")");
+ // System.out.println("Item state changed for " + setname
+ // + " (handling ? " + !settingDialog + ")");
if (settingDialog)
{
// ignore event
@@ -1396,12 +1116,6 @@ public class WsJobParameters extends JPanel implements ItemListener,
}
- private void _renameExistingPreset(String oldName, String curSetName2)
- {
- paramStore.updatePreset(oldName, curSetName2, setDescr.getText(),
- getJobParams());
- }
-
/**
* store current settings as given name. You should then reset gui.
*
diff --git a/src/jalview/gui/WsParamSetManager.java b/src/jalview/gui/WsParamSetManager.java
index 0f315eb..272e05b 100644
--- a/src/jalview/gui/WsParamSetManager.java
+++ b/src/jalview/gui/WsParamSetManager.java
@@ -56,13 +56,14 @@ import javax.xml.stream.XMLStreamReader;
*/
public class WsParamSetManager implements ParamManager
{
+ private static final String WS_PARAM_FILES = "WS_PARAM_FILES";
Hashtable paramparsers = new Hashtable<>();
@Override
public WsParamSetI[] getParameterSet(String name, String serviceUrl,
boolean modifiable, boolean unmodifiable)
{
- String files = Cache.getProperty("WS_PARAM_FILES");
+ String files = Cache.getProperty(WS_PARAM_FILES);
if (files == null)
{
return null;
@@ -107,7 +108,8 @@ public class WsParamSetManager implements ParamManager
} catch (IOException e)
{
Cache.log.info("Failed to parse parameter file " + pfile
- + " (Check that all JALVIEW_WSPARAMFILES entries are valid!)",
+ + " (Check that all " + WS_PARAM_FILES
+ + " entries are valid!)",
e);
}
}
@@ -218,7 +220,7 @@ public class WsParamSetManager implements ParamManager
}
if (outfile != null)
{
- String paramFiles = jalview.bin.Cache.getDefault("WS_PARAM_FILES",
+ String paramFiles = jalview.bin.Cache.getDefault(WS_PARAM_FILES,
filename);
if (paramFiles.indexOf(filename) == -1)
{
@@ -228,7 +230,8 @@ public class WsParamSetManager implements ParamManager
}
paramFiles = paramFiles.concat(filename);
}
- Cache.setProperty("WS_PARAM_FILES", paramFiles);
+
+ Cache.setProperty(WS_PARAM_FILES, paramFiles);
WebServiceParameterSet paramxml = new WebServiceParameterSet();
@@ -290,7 +293,7 @@ public class WsParamSetManager implements ParamManager
{
return;
}
- String paramFiles = jalview.bin.Cache.getDefault("WS_PARAM_FILES", "");
+ String paramFiles = jalview.bin.Cache.getDefault(WS_PARAM_FILES, "");
if (paramFiles.indexOf(filename) > -1)
{
String nparamFiles = new String();
@@ -303,7 +306,7 @@ public class WsParamSetManager implements ParamManager
nparamFiles = nparamFiles.concat("|").concat(fl);
}
}
- jalview.bin.Cache.setProperty("WS_PARAM_FILES", nparamFiles);
+ jalview.bin.Cache.setProperty(WS_PARAM_FILES, nparamFiles);
}
try
diff --git a/src/jalview/gui/WsPreferences.java b/src/jalview/gui/WsPreferences.java
index 8b5e664..cf88718 100644
--- a/src/jalview/gui/WsPreferences.java
+++ b/src/jalview/gui/WsPreferences.java
@@ -20,6 +20,7 @@
*/
package jalview.gui;
+
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
@@ -27,6 +28,7 @@ import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.URL;
+import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
@@ -40,6 +42,7 @@ import javax.swing.table.TableCellRenderer;
import jalview.bin.Cache;
import jalview.jbgui.GWsPreferences;
import jalview.util.MessageManager;
+import jalview.ws.WSDiscovererI;
import jalview.ws.jws2.Jws2Discoverer;
import jalview.ws.rest.RestServiceDescription;
@@ -155,21 +158,22 @@ public class WsPreferences extends GWsPreferences
String t = new String("");
switch (((Integer) status).intValue())
{
- case 1:
+ case WSDiscovererI.STATUS_OK:
// cb.setSelected(true);
// cb.setBackground(
c = Color.green;
break;
- case 0:
+ case WSDiscovererI.STATUS_NO_SERVICES:
// cb.setSelected(true);
// cb.setBackground(
c = Color.lightGray;
break;
- case -1:
+ case WSDiscovererI.STATUS_INVALID:
// cb.setSelected(false);
// cb.setBackground(
c = Color.red;
break;
+ case WSDiscovererI.STATUS_UNKNOWN:
default:
// cb.setSelected(false);
// cb.setBackground(
@@ -484,7 +488,7 @@ public class WsPreferences extends GWsPreferences
if (validate == JvOptionPane.OK_OPTION)
{
- if (Jws2Discoverer.testServiceUrl(foo))
+ if (Jws2Discoverer.getInstance().testServiceUrl(foo))
{
return foo.toString();
}
diff --git a/src/jalview/hmmer/HMMAlign.java b/src/jalview/hmmer/HMMAlign.java
new file mode 100644
index 0000000..d66ec33
--- /dev/null
+++ b/src/jalview/hmmer/HMMAlign.java
@@ -0,0 +1,338 @@
+package jalview.hmmer;
+
+import jalview.analysis.AlignmentSorter;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.AlignmentOrder;
+import jalview.datamodel.AlignmentView;
+import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.HiddenMarkovModel;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.gui.Desktop;
+import jalview.gui.JvOptionPane;
+import jalview.gui.SplitFrame;
+import jalview.io.DataSourceType;
+import jalview.io.StockholmFile;
+import jalview.util.FileUtils;
+import jalview.util.MessageManager;
+import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
+import jalview.ws.params.ArgumentI;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+
+import javax.swing.JInternalFrame;
+
+public class HMMAlign extends HmmerCommand
+{
+ static final String HMMALIGN = "hmmalign";
+
+ private final AlignmentI dataset;
+
+ /**
+ * Constructor for the HMMAlignThread
+ *
+ * @param af
+ * @param args
+ */
+ public HMMAlign(AlignFrame af, List args)
+ {
+ super(af, args);
+ if (alignment.getDataset() != null)
+ {
+ dataset = alignment.getDataset();
+ }
+ else
+ {
+ dataset = null;
+ }
+ }
+
+ /**
+ * Runs the HMMAlignThread: the data on the alignment or group is exported,
+ * then the command is executed in the command line and then the data is
+ * imported and displayed in a new frame (if true). The command is executed
+ * for each segment of the alignment. Call this method directly to execute
+ * synchronously, or via start() in a new Thread for asynchronously.
+ */
+ @Override
+ public void run()
+ {
+ HiddenMarkovModel hmm = getHmmProfile();
+
+ long msgId = System.currentTimeMillis();
+ af.setProgressBar(MessageManager.getString("status.running_hmmalign"),
+ msgId);
+
+ // ensure alignments are the same length
+ alignment.padGaps();
+
+ AlignmentView msa = af.gatherSequencesForAlignment();
+ SequenceI[][] subAlignments = msa.getVisibleContigs(alignment.getGapCharacter());
+
+ List allOrders = new ArrayList<>();
+
+ SequenceI[][] allResults = new SequenceI[subAlignments.length][];
+ int job = 0;
+ for (SequenceI[] seqs : subAlignments)
+ {
+ Hashtable sequencesHash = stashSequences(seqs);
+ try
+ {
+ File modelFile = FileUtils.createTempFile("hmm", ".hmm");
+ File alignmentFile = FileUtils.createTempFile("output", ".sto");
+ File resultFile = FileUtils.createTempFile("input", ".sto");
+
+ exportStockholm(seqs, alignmentFile.getAbsoluteFile(), null);
+ exportHmm(hmm, modelFile.getAbsoluteFile());
+
+ boolean ran = runCommand(modelFile, alignmentFile, resultFile);
+ if (!ran)
+ {
+ JvOptionPane.showInternalMessageDialog(af, MessageManager
+ .formatMessage("warn.command_failed", "hmmalign"));
+ return;
+ }
+
+ SequenceI[] result = importData(resultFile, allOrders);
+ recoverSequences(sequencesHash, result);
+ allResults[job] = result;
+ modelFile.delete();
+ alignmentFile.delete();
+ resultFile.delete();
+ } catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ job++;
+ }
+
+ String title = "hmmalign to " + hmm.getConsensusSequence().getName();
+ displayResults(allResults, allOrders, msa, title);
+
+ af.setProgressBar("", msgId);
+ }
+
+ /**
+ * Executes the hmmalign command and returns true if successful, false if an
+ * error is detected
+ *
+ * @param modelFile
+ * the HMM to align to
+ * @param alignmentFile
+ * the sequences to align
+ * @param resultFile
+ * the file to hold the results of alignment
+ * @return
+ * @throws IOException
+ */
+ private boolean runCommand(File modelFile, File alignmentFile,
+ File resultFile) throws IOException
+ {
+ String command = getCommandPath(HMMALIGN);
+ if (command == null)
+ {
+ return false;
+ }
+ List args = new ArrayList<>();
+ args.add(command);
+
+ if (params != null)
+ {
+ for (ArgumentI arg : params)
+ {
+ String name = arg.getName();
+ if (MessageManager.getString("label.trim_termini").equals(name))
+ {
+ args.add(ARG_TRIM);
+ }
+ }
+ }
+ args.add("-o");
+ args.add(getFilePath(resultFile, true));
+ args.add(getFilePath(modelFile, true));
+ args.add(getFilePath(alignmentFile, true));
+
+ return runCommand(args);
+ }
+
+ /**
+ * Imports the data from the file holding the output of hmmalign
+ *
+ * @param resultFile
+ * @param allOrders
+ * a list of alignment orders to add to
+ *
+ * @return
+ * @throws IOException
+ */
+ private SequenceI[] importData(File resultFile,
+ List allOrders) throws IOException
+ {
+ StockholmFile file = new StockholmFile(getFilePath(resultFile, false),
+ DataSourceType.FILE);
+ SequenceI[] result = file.getSeqsAsArray();
+ AlignmentOrder msaorder = new AlignmentOrder(result);
+ AlignmentSorter.recoverOrder(result);
+ allOrders.add(msaorder);
+
+ return result;
+ }
+
+ /**
+ * Displays the results of all 'jobs' in a new frame
+ *
+ * @param allResults
+ *
+ * @param allOrders
+ * @param msa
+ * @param title
+ */
+ private void displayResults(SequenceI[][] allResults,
+ List allOrders, AlignmentView msa, String title)
+ {
+ AlignmentOrder[] arrOrders = allOrders
+ .toArray(new AlignmentOrder[allOrders.size()]);
+ Object[] newview = msa.getUpdatedView(allResults, arrOrders,
+ alignment.getGapCharacter());
+ SequenceI[] seqs = (SequenceI[]) newview[0];
+ HiddenColumns hidden = (HiddenColumns) newview[1];
+ Alignment al = new Alignment(seqs);
+ al.setProperty("Alignment Program", "hmmalign");
+ if (dataset != null)
+ {
+ al.setDataset(dataset);
+ }
+
+ displayInNewFrame(al, allOrders, hidden, title);
+ }
+
+ /**
+ * Displays the results in a new frame
+ *
+ * @param al
+ * The alignment containing the results
+ * @param alorders
+ * The order of the sequences in the alignment on which the jobs were
+ * run
+ * @param hidden
+ * Hidden columns in the previous alignment
+ * @param title
+ */
+ private void displayInNewFrame(AlignmentI al,
+ List alorders, HiddenColumns hidden, String title)
+ {
+ AlignFrame alignFrame = new AlignFrame(al, hidden, AlignFrame.DEFAULT_WIDTH,
+ AlignFrame.DEFAULT_HEIGHT);
+ alignFrame.setTitle(title);
+
+ FeatureRendererSettings featureSettings = af.getFeatureRenderer()
+ .getSettings();
+ // initialise with same renderer settings as in parent alignframe.
+ alignFrame.getFeatureRenderer().transferSettings(featureSettings);
+
+ addSortByMenuItems(alignFrame, alorders);
+
+ // TODO: refactor retrieve and show as new splitFrame as Desktop method
+
+ /*
+ * If alignment was requested from one half of a SplitFrame, show in a
+ * SplitFrame with the other pane similarly aligned.
+ */
+ AlignFrame requestedBy = this.af;
+ if (requestedBy != null && requestedBy.getSplitViewContainer() != null
+ && requestedBy.getSplitViewContainer()
+ .getComplement(requestedBy) != null)
+ {
+ AlignmentI complement = requestedBy.getSplitViewContainer()
+ .getComplement(requestedBy);
+ String complementTitle = requestedBy.getSplitViewContainer()
+ .getComplementTitle(requestedBy);
+ // becomes null if the alignment window was closed before the alignment
+ // job finished.
+ AlignmentI copyComplement = new Alignment(complement);
+ // todo should this be done by copy constructor?
+ copyComplement.setGapCharacter(complement.getGapCharacter());
+ // share the same dataset (and the mappings it holds)
+ copyComplement.setDataset(complement.getDataset());
+ copyComplement.alignAs(al);
+ if (copyComplement.getHeight() > 0)
+ {
+ alignFrame.setTitle(this.af.getTitle());
+ AlignFrame af2 = new AlignFrame(copyComplement,
+ AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
+ af2.setTitle(complementTitle);
+ String linkedTitle = MessageManager
+ .getString("label.linked_view_title");
+ JInternalFrame splitFrame = new SplitFrame(
+ al.isNucleotide() ? alignFrame : af2, al.isNucleotide() ? af2 : alignFrame);
+ Desktop.addInternalFrame(splitFrame, linkedTitle, -1, -1);
+ return;
+ }
+ }
+
+ /*
+ * Not from SplitFrame, or failed to created a complementary alignment
+ */
+ Desktop.addInternalFrame(alignFrame, alignFrame.getTitle(), AlignFrame.DEFAULT_WIDTH,
+ AlignFrame.DEFAULT_HEIGHT);
+ }
+
+ /**
+ * Adds sort order options to the AlignFrame menus
+ *
+ * @param alignFrame
+ * @param alorders
+ */
+ protected void addSortByMenuItems(AlignFrame alignFrame,
+ List alorders)
+ {
+ // update orders
+ if (alorders.size() == 1)
+ {
+ alignFrame.addSortByOrderMenuItem("hmmalign" + " Ordering", alorders.get(0));
+ }
+ else
+ {
+ // construct a non-redundant ordering set
+ List names = new ArrayList<>();
+ for (int i = 0, l = alorders.size(); i < l; i++)
+ {
+ String orderName = " Region " + i;
+ int j = i + 1;
+
+ while (j < l)
+ {
+ if (alorders.get(i).equals(alorders.get(j)))
+ {
+ alorders.remove(j);
+ l--;
+ orderName += "," + j;
+ }
+ else
+ {
+ j++;
+ }
+ }
+
+ if (i == 0 && j == 1)
+ {
+ names.add("");
+ }
+ else
+ {
+ names.add(orderName);
+ }
+ }
+ for (int i = 0, l = alorders.size(); i < l; i++)
+ {
+ alignFrame.addSortByOrderMenuItem("hmmalign" + (names.get(i)) + " Ordering",
+ alorders.get(i));
+ }
+ }
+ }
+}
diff --git a/src/jalview/hmmer/HMMBuild.java b/src/jalview/hmmer/HMMBuild.java
new file mode 100644
index 0000000..0c47c1d
--- /dev/null
+++ b/src/jalview/hmmer/HMMBuild.java
@@ -0,0 +1,370 @@
+package jalview.hmmer;
+
+import jalview.api.AlignViewportI;
+import jalview.bin.Cache;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.AnnotatedCollectionI;
+import jalview.datamodel.ResidueCount;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.gui.JvOptionPane;
+import jalview.io.DataSourceType;
+import jalview.io.FileParse;
+import jalview.io.HMMFile;
+import jalview.util.FileUtils;
+import jalview.util.MessageManager;
+import jalview.ws.params.ArgumentI;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+
+/**
+ * A class that runs the hmmbuild command as a separate process.
+ *
+ * @author gmcarstairs
+ *
+ */
+public class HMMBuild extends HmmerCommand
+{
+ static final String ARG_AMINO = "--amino";
+
+ static final String ARG_DNA = "--dna";
+
+ static final String ARG_RNA = "--rna";
+
+ /**
+ * Constructor
+ *
+ * @param alignFrame
+ * @param args
+ */
+ public HMMBuild(AlignFrame alignFrame, List args)
+ {
+ super(alignFrame, args);
+ }
+
+ /**
+ * Builds a HMM from an alignment (and/or groups), then imports and adds it to
+ * the alignment (and/or groups). Call this method directly to execute
+ * synchronously, or via start() in a new Thread for asynchronously.
+ */
+ @Override
+ public void run()
+ {
+ if (params == null || params.isEmpty())
+ {
+ Cache.log.error("No parameters to HMMBuild!|");
+ return;
+ }
+
+ long msgID = System.currentTimeMillis();
+ af.setProgressBar(MessageManager.getString("status.running_hmmbuild"),
+ msgID);
+
+ AlignViewportI viewport = af.getViewport();
+ try
+ {
+ /*
+ * run hmmbuild for alignment and/or groups as selected
+ */
+ List runBuildFor = parseParameters(viewport);
+
+ for (AnnotatedCollectionI grp : runBuildFor)
+ {
+ runHMMBuild(grp);
+ }
+ } finally
+ {
+ af.setProgressBar("", msgID);
+ viewport.alignmentChanged(af.alignPanel);
+ af.buildColourMenu(); // to enable HMMER colour schemes
+ }
+ }
+
+ /**
+ * Scans the parameters to determine whether to run hmmmbuild for the whole
+ * alignment or specified subgroup(s) or both
+ *
+ * @param viewport
+ * @return
+ */
+ protected List parseParameters(
+ AlignViewportI viewport)
+ {
+ List runBuildFor = new ArrayList<>();
+ boolean foundArg = false;
+
+ for (ArgumentI arg : params)
+ {
+ String name = arg.getName();
+ if (MessageManager.getString("label.hmmbuild_for").equals(name))
+ {
+ foundArg = true;
+ String value = arg.getValue();
+
+ if (MessageManager.getString("label.alignment").equals(value))
+ {
+ runBuildFor.add(viewport.getAlignmentView(false)
+ .getVisibleAlignment('-'));
+ }
+ else if (MessageManager.getString("label.groups_and_alignment")
+ .equals(value))
+ {
+ runBuildFor.add(viewport.getAlignmentView(false)
+ .getVisibleAlignment('-'));
+ runBuildFor.addAll(viewport.getAlignment().getGroups());
+ }
+ else if (MessageManager.getString("label.groups").equals(value))
+ {
+ runBuildFor.addAll(viewport.getAlignment().getGroups());
+ }
+ else if (MessageManager.getString("label.selected_group")
+ .equals(value))
+ {
+ runBuildFor.add(viewport.getSelectionGroup());
+ }
+ }
+ else if (MessageManager.getString("label.use_reference")
+ .equals(name))
+ {
+ // todo disable this option if no RF annotation on alignment
+ if (!af.getViewport().hasReferenceAnnotation())
+ {
+ JvOptionPane.showInternalMessageDialog(af, MessageManager
+ .getString("warn.no_reference_annotation"));
+ // return;
+ }
+ }
+ }
+
+ /*
+ * default is to build for the whole alignment
+ */
+ if (!foundArg)
+ {
+ runBuildFor.add(alignment);
+ }
+
+ return runBuildFor;
+ }
+
+ /**
+ * Runs hmmbuild on the given sequences (alignment or group)
+ *
+ * @param grp
+ */
+ private void runHMMBuild(AnnotatedCollectionI ac)
+ {
+ File hmmFile = null;
+ File alignmentFile = null;
+ try
+ {
+ hmmFile = FileUtils.createTempFile("hmm", ".hmm");
+ alignmentFile = FileUtils.createTempFile("output", ".sto");
+
+ if (ac instanceof Alignment)
+ {
+ AlignmentI al = (Alignment) ac;
+ // todo pad gaps in an unaligned SequenceGroup as well?
+ if (!al.isAligned())
+ {
+ al.padGaps();
+ }
+ }
+
+ deleteHmmSequences(ac);
+
+ List copy = new ArrayList<>();
+ if (ac instanceof Alignment)
+ {
+ copy.addAll(ac.getSequences());
+ }
+ else
+ {
+ SequenceI[] sel = ((SequenceGroup) ac)
+ .getSelectionAsNewSequences((AlignmentI) ac.getContext());
+ for (SequenceI seq : sel)
+ {
+ if (seq != null)
+ {
+ copy.add(seq);
+ }
+ }
+ }
+ // TODO rather than copy alignment data we should anonymize in situ -
+ // export/File import could use anonymization hash to reinstate references
+ // at import level ?
+
+ SequenceI[] copyArray = copy.toArray(new SequenceI[copy.size()]);
+ Hashtable sequencesHash = stashSequences(copyArray);
+
+ exportStockholm(copyArray, alignmentFile, ac);
+
+ recoverSequences(sequencesHash, copy.toArray(new SequenceI[] {}));
+
+ boolean ran = runCommand(alignmentFile, hmmFile, ac);
+ if (!ran)
+ {
+ JvOptionPane.showInternalMessageDialog(af, MessageManager
+ .formatMessage("warn.command_failed", "hmmbuild"));
+ return;
+ }
+ importData(hmmFile, ac);
+ } catch (Exception e)
+ {
+ e.printStackTrace();
+ } finally
+ {
+ if (hmmFile != null)
+ {
+ hmmFile.delete();
+ }
+ if (alignmentFile != null)
+ {
+ alignmentFile.delete();
+ }
+ }
+ }
+
+ /**
+ * Constructs and executes the hmmbuild command as a separate process
+ *
+ * @param sequencesFile
+ * the alignment from which the HMM is built
+ * @param hmmFile
+ * the output file to which the HMM is written
+ * @param group
+ * alignment or group for which the hmm is generated
+ *
+ * @return
+ * @throws IOException
+ */
+ private boolean runCommand(File sequencesFile, File hmmFile,
+ AnnotatedCollectionI group) throws IOException
+ {
+ String cmd = getCommandPath(HMMBUILD);
+ if (cmd == null)
+ {
+ return false; // executable not found
+ }
+ List args = new ArrayList<>();
+ args.add(cmd);
+
+ /*
+ * HMM name (will be given to consensus sequence) is
+ * - as specified by an input parameter if set
+ * - else group name with _HMM appended (if for a group)
+ * - else align frame title with _HMM appended (if title is not too long)
+ * - else "Alignment_HMM"
+ */
+ String name = "";
+
+ if (params != null)
+ {
+ for (ArgumentI arg : params)
+ {
+ String argName = arg.getName();
+ switch (argName)
+ {
+ case "HMM Name":
+ name = arg.getValue().trim();
+ break;
+ case "Use Reference Annotation":
+ args.add("--hand");
+ break;
+ }
+ }
+ }
+
+ if (group instanceof SequenceGroup)
+ {
+ name = ((SequenceGroup) group).getName() + "_HMM";
+ }
+
+ if ("".equals(name))
+ {
+ if (af != null && af.getTitle().length() < 15)
+ {
+ name = af.getTitle();
+ }
+ else
+ {
+ name = "Alignment_HMM";
+ }
+ }
+
+ args.add("-n");
+ args.add(name.replace(' ', '_'));
+ if (!alignment.isNucleotide())
+ {
+ args.add(ARG_AMINO); // TODO check for rna
+ }
+ else
+ {
+ args.add(ARG_DNA);
+ }
+
+ args.add(getFilePath(hmmFile, true));
+ args.add(getFilePath(sequencesFile, true));
+
+ return runCommand(args);
+ }
+
+ /**
+ * Imports the .hmm file produced by hmmbuild, and inserts the HMM consensus
+ * sequence (with attached HMM profile) as the first sequence in the alignment
+ * or group for which it was generated
+ *
+ * @param hmmFile
+ * @param ac
+ * (optional) the group for which the hmm was generated
+ * @throws IOException
+ */
+ private void importData(File hmmFile, AnnotatedCollectionI ac)
+ throws IOException
+ {
+ if (hmmFile.length() == 0L)
+ {
+ Cache.log.error("Error: hmmbuild produced empty hmm file");
+ return;
+ }
+
+ HMMFile file = new HMMFile(
+ new FileParse(hmmFile.getAbsolutePath(), DataSourceType.FILE));
+ SequenceI hmmSeq = file.getHMM().getConsensusSequence();
+
+
+
+ ResidueCount counts = new ResidueCount(alignment.getSequences());
+ hmmSeq.getHMM().setBackgroundFrequencies(counts);
+
+ if (hmmSeq == null)
+ {
+ // hmmbuild failure not detected earlier
+ return;
+ }
+
+ if (ac instanceof SequenceGroup)
+ {
+ SequenceGroup grp = (SequenceGroup) ac;
+ char gapChar = alignment.getGapCharacter();
+ hmmSeq.insertCharAt(0, ac.getStartRes(), gapChar);
+ hmmSeq.insertCharAt(ac.getEndRes() + 1,
+ alignment.getWidth() - ac.getEndRes() - 1, gapChar);
+ SequenceI topSeq = grp.getSequencesInOrder(alignment)[0];
+ int topIndex = alignment.findIndex(topSeq);
+ alignment.insertSequenceAt(topIndex, hmmSeq);
+ ac.setSeqrep(hmmSeq);
+ grp.addSequence(hmmSeq, false);
+ }
+ else
+ {
+ alignment.insertSequenceAt(0, hmmSeq);
+ }
+ }
+}
diff --git a/src/jalview/hmmer/HMMERParamStore.java b/src/jalview/hmmer/HMMERParamStore.java
new file mode 100644
index 0000000..df9ab55
--- /dev/null
+++ b/src/jalview/hmmer/HMMERParamStore.java
@@ -0,0 +1,481 @@
+package jalview.hmmer;
+
+import jalview.bin.Cache;
+import jalview.datamodel.SequenceI;
+import jalview.gui.Preferences;
+import jalview.util.MessageManager;
+import jalview.viewmodel.AlignmentViewport;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.ParamDatastoreI;
+import jalview.ws.params.WsParamSetI;
+import jalview.ws.params.simple.BooleanOption;
+import jalview.ws.params.simple.DoubleParameter;
+import jalview.ws.params.simple.FileParameter;
+import jalview.ws.params.simple.IntegerParameter;
+import jalview.ws.params.simple.LogarithmicParameter;
+import jalview.ws.params.simple.Option;
+import jalview.ws.params.simple.RadioChoiceParameter;
+import jalview.ws.params.simple.StringParameter;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Scanner;
+
+public final class HMMERParamStore implements ParamDatastoreI
+{
+ private static final String HMMBUILD = "hmmbuild";
+
+ private static final String HMMALIGN = "hmmalign";
+
+ private static final String HMMSEARCH = "hmmsearch";
+
+ private static final String JACKHMMER = "jackhmmer";
+
+ private String name;
+
+ private List presets = new ArrayList<>();
+
+ private AlignmentViewport viewport;
+
+ private HMMERParamStore(String nam, AlignmentViewport av)
+ {
+ this.viewport = av;
+ this.name = nam;
+ }
+
+ public static HMMERParamStore forBuild(AlignmentViewport viewport)
+ {
+ return new HMMERParamStore(HMMBUILD, viewport);
+ }
+
+ public static HMMERParamStore forAlign(AlignmentViewport viewport)
+ {
+ return new HMMERParamStore(HMMALIGN, viewport);
+ }
+
+ public static HMMERParamStore forSearch(AlignmentViewport viewport)
+ {
+ return new HMMERParamStore(HMMSEARCH, viewport);
+ }
+
+ public static HMMERParamStore forJackhmmer(AlignmentViewport viewport)
+ {
+ return new HMMERParamStore(JACKHMMER, viewport);
+ }
+
+ @Override
+ public List getPresets()
+ {
+ return presets;
+ }
+
+ @Override
+ public WsParamSetI getPreset(String nam)
+ {
+ return null;
+ }
+
+ @Override
+ public List getServiceParameters()
+ {
+ List args = new ArrayList<>();
+ switch (name)
+ {
+ case HMMSEARCH:
+ getHMMSearchParams(args);
+ break;
+ case HMMALIGN:
+ getHMMAlignParams(args);
+ break;
+ case HMMBUILD:
+ getHMMBuildParams(args);
+ break;
+ case JACKHMMER:
+ getJackhmmerParams(args);
+ default:
+ }
+
+ return args;
+ }
+
+ /**
+ * Answers default parameters for hmmsearch, taking into account any
+ * configured as user preferences
+ *
+ * @param args
+ */
+ private void getHMMSearchParams(List args)
+ {
+ /*
+ * 'Options'
+ */
+ args.add(new BooleanOption(
+ MessageManager.getString(HMMSearch.AUTO_ALIGN_SEQS_KEY),
+ MessageManager.getString("label.auto_align_seqs_desc"), false,
+ false, false, null));
+ args.add(new BooleanOption(
+ MessageManager.getString(HMMSearch.USE_ACCESSIONS_KEY),
+ MessageManager.getString("label.use_accessions_desc"), false,
+ false, true, null));
+ args.add(new BooleanOption(
+ MessageManager.getString(HMMSearch.TRIM_TERMINI_KEY),
+ MessageManager.getString("label.trim_termini_desc"), false,
+ false, true, null));
+ args.add(new BooleanOption(
+ MessageManager.getString(HMMSearch.RETURN_N_NEW_SEQ),
+ MessageManager.getString("label.check_for_new_sequences_desc"),
+ false, false, false, null));
+
+ /*
+ * 'Parameters'
+ */
+ addChoiceOfHmm(args);
+
+ // addChoiceOfDatabase(args);
+
+ String thisAlignment = MessageManager
+ .getString(HMMSearch.THIS_ALIGNMENT_KEY);
+ String database = MessageManager.getString("label.database");
+ args.add(new FileParameter(database, "", false, "", ""));
+ args.add(new IntegerParameter(
+ MessageManager.getString(HMMSearch.NUMBER_OF_RESULTS_KEY),
+ MessageManager.getString("label.number_of_results_desc"), true,
+ 100, 0, 100000));
+ args.add(new RadioChoiceParameter(
+ MessageManager.getString(HMMSearch.REPORTING_CUTOFF_KEY), null,
+ Arrays.asList(MessageManager.getString(HMMSearch.CUTOFF_EVALUE),
+ MessageManager.getString(HMMSearch.CUTOFF_SCORE)),
+ MessageManager.getString(HMMSearch.CUTOFF_EVALUE)));
+ args.add(new LogarithmicParameter(
+ MessageManager.getString(HMMSearch.REPORTING_SEQ_EVALUE_KEY),
+ MessageManager.getString("label.reporting_seq_e_value_desc"),
+ false, 1D,
+ 1E-100, 10D));
+ args.add(new LogarithmicParameter(
+ MessageManager.getString(HMMSearch.REPORTING_DOM_EVALUE_KEY),
+ MessageManager.getString("label.reporting_dom_e_value_desc"),
+ false, 1D,
+ 1E-100, 10D));
+ args.add(
+ new DoubleParameter(
+ MessageManager
+ .getString(HMMSearch.REPORTING_SEQ_SCORE_KEY),
+ MessageManager.getString(
+ "label.reporting_seq_score_desc"),
+ false,
+ 0d, 0d, 1000d));
+ args.add(
+ new DoubleParameter(
+ MessageManager
+ .getString(HMMSearch.REPORTING_DOM_SCORE_KEY),
+ MessageManager.getString(
+ "label.reporting_dom_score_desc"),
+ false,
+ 0d, 0d, 1000d));
+ args.add(new RadioChoiceParameter(
+ MessageManager.getString(HMMSearch.INCLUSION_THRESHOLD_KEY),
+ null,
+ Arrays.asList(MessageManager.getString(HMMSearch.CUTOFF_EVALUE),
+ MessageManager.getString(HMMSearch.CUTOFF_SCORE)),
+ MessageManager.getString(HMMSearch.CUTOFF_EVALUE)));
+ args.add(new LogarithmicParameter(
+ MessageManager.getString(HMMSearch.INCLUSION_SEQ_EVALUE_KEY),
+ MessageManager.getString("label.inclusion_seq_e_value_desc"),
+ false, 1D,
+ 1E-100, 10D));
+ args.add(new LogarithmicParameter(
+ MessageManager.getString(HMMSearch.INCLUSION_DOM_EVALUE_KEY),
+ MessageManager.getString("label.inclusion_dom_e_value_desc"),
+ false, 1D,
+ 1E-100, 10D));
+ args.add(new DoubleParameter(
+ MessageManager.getString(HMMSearch.INCLUSION_SEQ_SCORE_KEY),
+ MessageManager.getString("label.inclusion_seq_score_desc"),
+ false, 0d, 0d,
+ 1000d));
+ args.add(new DoubleParameter(
+ MessageManager.getString(HMMSearch.INCLUSION_DOM_SCORE_KEY),
+ MessageManager.getString("label.inclusion_dom_score_desc"),
+ false, 0d, 0d,
+ 1000d));
+ }
+
+ /**
+ * Answers default parameters for jackhmmer, taking into account any configured
+ * as user preferences
+ *
+ * @param args
+ */
+ private void getJackhmmerParams(List args)
+ {
+
+ /*
+ * 'Parameters'
+ */
+ addChoiceOfSequence(args);
+
+ // addChoiceOfDatabase(args);
+
+ String database = MessageManager.getString("label.database");
+ args.add(new FileParameter(database, "", false, "", ""));
+ args.add(new IntegerParameter(
+ MessageManager.getString(HMMSearch.NUMBER_OF_ITERATIONS),
+ MessageManager.getString("label.number_of_iterations_desc"),
+ true, 5, 1, 20));
+ args.add(new RadioChoiceParameter(
+ MessageManager.getString(JackHMMER.REPORTING_CUTOFF_KEY), null,
+ Arrays.asList(MessageManager.getString(JackHMMER.CUTOFF_NONE),
+ MessageManager.getString(JackHMMER.CUTOFF_EVALUE),
+ MessageManager.getString(JackHMMER.CUTOFF_SCORE)),
+ MessageManager.getString(JackHMMER.CUTOFF_EVALUE)));
+ args.add(new LogarithmicParameter(
+ MessageManager.getString(JackHMMER.REPORTING_SEQ_EVALUE_KEY),
+ MessageManager.getString("label.reporting_seq_e_value_desc"),
+ false, 1D,
+ 1E-38, 10D));
+ args.add(new LogarithmicParameter(
+ MessageManager.getString(JackHMMER.REPORTING_DOM_EVALUE_KEY),
+ MessageManager.getString(
+ "label.reporting_dom_e_value_desc"),
+ false, 1D,
+ 1E-38, 10D));
+ args.add(new DoubleParameter(
+ MessageManager.getString(JackHMMER.REPORTING_SEQ_SCORE_KEY),
+ MessageManager.getString("label.reporting_seq_score_desc"),
+ false, 0d, 0d,
+ 1000d));
+ args.add(new DoubleParameter(
+ MessageManager.getString(JackHMMER.REPORTING_DOM_SCORE_KEY),
+ MessageManager.getString("label.reporting_dom_score_desc"),
+ false, 0d, 0d,
+ 1000d));
+ args.add(new RadioChoiceParameter(
+ MessageManager.getString(HMMSearch.INCLUSION_THRESHOLD_KEY),
+ null,
+ Arrays.asList(MessageManager.getString(HMMSearch.CUTOFF_EVALUE),
+ MessageManager.getString(HMMSearch.CUTOFF_SCORE)),
+ MessageManager.getString(HmmerCommand.CUTOFF_EVALUE)));
+ args.add(new LogarithmicParameter(
+ MessageManager.getString(HMMSearch.INCLUSION_SEQ_EVALUE_KEY),
+ MessageManager.getString("label.inclusion_seq_e_value_desc"),
+ false, 1D, 1E-100, 10D));
+ args.add(new LogarithmicParameter(
+ MessageManager.getString(HMMSearch.INCLUSION_DOM_EVALUE_KEY),
+ MessageManager.getString("label.inclusion_dom_e_value_desc"),
+ false, 1D, 1E-100, 10D));
+ args.add(new DoubleParameter(
+ MessageManager.getString(HMMSearch.INCLUSION_SEQ_SCORE_KEY),
+ MessageManager.getString("label.inclusion_seq_score_desc"),
+ false, 0d, 0d, 1000d));
+ args.add(new DoubleParameter(
+ MessageManager.getString(HMMSearch.INCLUSION_DOM_SCORE_KEY),
+ MessageManager.getString("label.inclusion_dom_score_desc"),
+ false, 0d, 0d, 1000d));
+ }
+
+ /**
+ * Constructs a choice parameter for database to search; always includes 'this
+ * alignment', and also includes any databases held under user preferences key
+ * "HMMSEARCH_DBS" as a comma-delimited list
+ *
+ * @param args
+ */
+ protected void addChoiceOfDatabase(List args)
+ {
+ String names = Cache.getProperty(Preferences.HMMSEARCH_DBS);
+ if (names == null || names.isEmpty())
+ {
+ return;
+ }
+
+ List filePaths = new ArrayList<>();
+ List fileNames = new ArrayList<>();
+
+ String thisAlignment = MessageManager.getString(HMMSearch.THIS_ALIGNMENT_KEY);
+ filePaths.add(thisAlignment);
+ fileNames.add(thisAlignment);
+
+ Scanner nameScanner = new Scanner(names);
+ nameScanner.useDelimiter(Preferences.COMMA);
+
+ while (nameScanner.hasNext())
+ {
+ String next = nameScanner.next();
+ if ("null".equals(next))
+ {
+ Cache.setProperty(Preferences.HMMSEARCH_DBS, "");
+ }
+ else
+ {
+ filePaths.add(next);
+ int pos = next.lastIndexOf(File.separator);
+ String fileName = next.substring(pos + 1);
+ fileNames.add(fileName);
+ }
+ }
+ nameScanner.close();
+ ArgumentI databasesOption = new StringParameter(
+ MessageManager.getString(HMMSearch.DATABASE_KEY),
+ MessageManager.getString("label.database_for_hmmsearch"), true,
+ thisAlignment,
+ thisAlignment,
+ filePaths, fileNames);
+ args.add(databasesOption);
+ }
+
+ /**
+ * Answers default parameters for hmmalign, taking into account any configured
+ * as user preferences
+ *
+ * @param args
+ */
+ private void getHMMAlignParams(List args)
+ {
+ addChoiceOfHmm(args);
+
+ boolean def = Cache.getDefault(Preferences.HMMALIGN_TRIM_TERMINI,
+ false);
+ args.add(new BooleanOption(
+ MessageManager.getString("label.trim_termini"),
+ MessageManager.getString("label.trim_termini_desc"),
+ false, false, def, null));
+ }
+
+ /**
+ * Adds an argument representing the choice of HMM sequences (profiles)
+ * against which to perform align or search, provided at least one is found
+ *
+ * @param args
+ */
+ protected void addChoiceOfHmm(List args)
+ {
+ List hmms = viewport.getAlignment().getHmmSequences();
+ if (!hmms.isEmpty())
+ {
+ List options = new ArrayList<>();
+ for (SequenceI hmmSeq : hmms)
+ {
+ options.add(hmmSeq.getName());
+ }
+ String defseq = options.get(0);
+ ArgumentI arg = new StringParameter(
+ MessageManager.getString("label.use_hmm"), null, true, defseq,
+ defseq, options, null);
+ args.add(arg);
+ }
+ }
+
+ /**
+ * Adds an argument representing the choice of sequence against which to perform
+ * jackhmmer
+ *
+ * @param args
+ */
+ protected void addChoiceOfSequence(List args)
+ {
+ List sequences = viewport.getAlignment().getSequences();
+
+ List options = new ArrayList<>();
+
+ for (SequenceI seq : sequences)
+ {
+ options.add(seq.getName());
+ }
+
+ String defseq = options.get(0);
+ ArgumentI arg = new StringParameter(
+ MessageManager.getString("label.use_sequence"), null, true,
+ defseq,
+ defseq, options, null);
+ args.add(arg);
+ }
+
+ /**
+ * Answers default parameters for hmmbuild, taking into account any configured
+ * as user preferences
+ *
+ * @param args
+ */
+ private void getHMMBuildParams(List args)
+ {
+ /*
+ * name to give the computed alignment HMM consensus sequence
+ * (Jalview constructs group HMM consensus sequence names)
+ */
+ String defValue = "Alignment_HMM";
+ StringParameter nameParam = new StringParameter(MessageManager.getString("label.hmm_name"),
+ MessageManager.getString("label.hmm_name_desc"), true, defValue,
+ defValue);
+ args.add(nameParam);
+
+ /*
+ * only enable Use Reference Annotation if RF is present
+ */
+ if (viewport.hasReferenceAnnotation())
+ {
+ args.add(new BooleanOption(
+ MessageManager.getString("label.use_reference"),
+ MessageManager.getString("label.use_reference_desc"), true,
+ true, true, null));
+ }
+
+ /*
+ * choice of whether to compute HMM for alignment and/or group(s)
+ * - only if there are any groups
+ */
+ if (!viewport.getAlignment().getGroups().isEmpty())
+ {
+ List options = new ArrayList<>();
+ options.add(MessageManager.getString("label.alignment"));
+ options.add(MessageManager.getString("label.groups_and_alignment"));
+ options.add(MessageManager.getString("label.groups"));
+ options.add(MessageManager.getString("label.selected_group"));
+ args.add(new Option(MessageManager.getString("label.hmmbuild_for"),
+ MessageManager.getString("label.hmmbuild_for_desc"), true,
+ MessageManager.getString("label.alignment"),
+ MessageManager.getString("label.alignment"), options, null));
+ }
+ }
+
+ @Override
+ public boolean presetExists(String forName)
+ {
+ return false;
+ }
+
+ @Override
+ public void deletePreset(String forName)
+ {
+ }
+
+ @Override
+ public void storePreset(String presetName, String text,
+ List jobParams)
+ {
+ }
+
+ @Override
+ public void updatePreset(String oldName, String presetName, String text,
+ List jobParams)
+ {
+ }
+
+ @Override
+ public WsParamSetI parseServiceParameterFile(String forName,
+ String description, String[] serviceURL, String parameters)
+ throws IOException
+ {
+ return null;
+ }
+
+ @Override
+ public String generateServiceParameterFile(WsParamSetI pset)
+ throws IOException
+ {
+ return null;
+ }
+
+}
diff --git a/src/jalview/hmmer/HMMERPreset.java b/src/jalview/hmmer/HMMERPreset.java
new file mode 100644
index 0000000..2712259
--- /dev/null
+++ b/src/jalview/hmmer/HMMERPreset.java
@@ -0,0 +1,57 @@
+package jalview.hmmer;
+
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.WsParamSetI;
+
+import java.util.List;
+
+public class HMMERPreset implements WsParamSetI
+{
+
+ @Override
+ public String getName()
+ {
+ return null;
+ }
+
+ @Override
+ public String getDescription()
+ {
+ return null;
+ }
+
+ @Override
+ public String[] getApplicableUrls()
+ {
+ return null;
+ }
+
+ @Override
+ public String getSourceFile()
+ {
+ return null;
+ }
+
+ @Override
+ public void setSourceFile(String newfile)
+ {
+ }
+
+ @Override
+ public boolean isModifiable()
+ {
+ return false;
+ }
+
+ @Override
+ public List getArguments()
+ {
+ return null;
+ }
+
+ @Override
+ public void setArguments(List args)
+ {
+ }
+
+}
diff --git a/src/jalview/hmmer/HMMSearch.java b/src/jalview/hmmer/HMMSearch.java
new file mode 100644
index 0000000..f05823e
--- /dev/null
+++ b/src/jalview/hmmer/HMMSearch.java
@@ -0,0 +1,318 @@
+package jalview.hmmer;
+
+import jalview.bin.Cache;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.HiddenMarkovModel;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.gui.Desktop;
+import jalview.gui.JvOptionPane;
+import jalview.io.DataSourceType;
+import jalview.io.FileParse;
+import jalview.io.StockholmFile;
+import jalview.util.FileUtils;
+import jalview.util.MessageManager;
+import jalview.ws.params.ArgumentI;
+import jalview.ws.params.simple.BooleanOption;
+import jalview.ws.params.simple.Option;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.swing.JOptionPane;
+
+public class HMMSearch extends Search
+{
+
+ boolean realign = false;
+
+ boolean trim = false;
+
+ boolean returnNoOfNewSeqs = false;
+
+ int seqsToReturn = Integer.MAX_VALUE;
+
+
+ /**
+ * Constructor for the HMMSearchThread
+ *
+ * @param af
+ */
+ public HMMSearch(AlignFrame af, List args)
+ {
+ super(af, args);
+ }
+
+ /**
+ * Runs the HMMSearchThread: the data on the alignment or group is exported,
+ * then the command is executed in the command line and then the data is
+ * imported and displayed in a new frame. Call this method directly to execute
+ * synchronously, or via start() in a new Thread for asynchronously.
+ */
+ @Override
+ public void run()
+ {
+ HiddenMarkovModel hmm = getHmmProfile();
+ if (hmm == null)
+ {
+ // shouldn't happen if we got this far
+ Cache.log.error("Error: no hmm for hmmsearch");
+ return;
+ }
+
+ SequenceI hmmSeq = hmm.getConsensusSequence();
+ long msgId = System.currentTimeMillis();
+ af.setProgressBar(MessageManager.getString("status.running_search"),
+ msgId);
+
+ try
+ {
+ File hmmFile = FileUtils.createTempFile("hmm", ".hmm");
+ File hitsAlignmentFile = FileUtils.createTempFile("hitAlignment",
+ ".sto");
+ File searchOutputFile = FileUtils.createTempFile("searchOutput",
+ ".sto");
+
+ exportHmm(hmm, hmmFile.getAbsoluteFile());
+
+ boolean ran = runCommand(searchOutputFile, hitsAlignmentFile, hmmFile);
+ if (!ran)
+ {
+ JvOptionPane.showInternalMessageDialog(af, MessageManager
+ .formatMessage("warn.command_failed", "hmmsearch"));
+ return;
+ }
+
+ importData(hmmSeq, hitsAlignmentFile, hmmFile, searchOutputFile);
+ // TODO make realignment of search results a step at this level
+ // and make it conditional on this.realign
+ } catch (IOException | InterruptedException e)
+ {
+ e.printStackTrace();
+ }
+ finally
+ {
+ af.setProgressBar("", msgId);
+ }
+ }
+
+ /**
+ * Executes an hmmsearch with the given hmm as input. The database to be
+ * searched is a local file as specified by the 'Database' parameter, or the
+ * current alignment (written to file) if none is specified.
+ *
+ * @param searchOutputFile
+ * @param hitsAlignmentFile
+ * @param hmmFile
+ *
+ * @return
+ * @throws IOException
+ */
+ private boolean runCommand(File searchOutputFile, File hitsAlignmentFile,
+ File hmmFile) throws IOException
+ {
+ String command = getCommandPath(HMMSEARCH);
+ if (command == null)
+ {
+ return false;
+ }
+
+ List args = new ArrayList<>();
+ args.add(command);
+ buildArguments(args, searchOutputFile, hitsAlignmentFile, hmmFile);
+
+ return runCommand(args);
+ }
+
+
+ /**
+ * Imports the data from the temporary file to which the output of hmmsearch
+ * was directed. The results are optionally realigned using hmmalign.
+ *
+ * @param hmmSeq
+ */
+ private void importData(SequenceI hmmSeq, File inputAlignmentTemp,
+ File hmmTemp, File searchOutputFile)
+ throws IOException, InterruptedException
+ {
+ BufferedReader br = new BufferedReader(
+ new FileReader(inputAlignmentTemp));
+ try
+ {
+ if (br.readLine() == null)
+ {
+ JOptionPane.showMessageDialog(af,
+ MessageManager.getString("label.no_sequences_found"));
+ return;
+ }
+ StockholmFile file = new StockholmFile(new FileParse(
+ inputAlignmentTemp.getAbsolutePath(), DataSourceType.FILE));
+ seqs = file.getSeqsAsArray();
+
+ readDomainTable(searchOutputFile, false);
+
+ if (searchAlignment)
+ {
+ recoverSequences(sequencesHash, seqs);
+ }
+
+ // look for PP cons and ref seq in alignment only annotation
+ AlignmentAnnotation modelpos = null, ppcons = null;
+ for (AlignmentAnnotation aa : file.getAnnotations())
+ {
+ if (aa.sequenceRef == null)
+ {
+ if (aa.label.equals("Reference Positions")) // RF feature type in
+ // stockholm parser
+ {
+ modelpos = aa;
+ }
+ if (aa.label.equals("Posterior Probability"))
+ {
+ ppcons = aa;
+ }
+ }
+ }
+
+
+ int seqCount = Math.min(seqs.length, seqsToReturn);
+ SequenceI[] hmmAndSeqs = new SequenceI[seqCount + 1];
+ hmmSeq = hmmSeq.deriveSequence(); // otherwise all bad things happen
+ hmmAndSeqs[0] = hmmSeq;
+ System.arraycopy(seqs, 0, hmmAndSeqs, 1, seqCount);
+ if (modelpos != null)
+ {
+ // TODO need - get ungapped sequence method
+ hmmSeq.setSequence(
+ hmmSeq.getDatasetSequence().getSequenceAsString());
+ Annotation[] refpos = modelpos.annotations;
+ // insert gaps to match with refseq positions
+ int gc = 0, lcol = 0;
+ for (int c = 0; c < refpos.length; c++)
+ {
+ if (refpos[c] != null && ("x".equals(refpos[c].displayCharacter)))
+ {
+ if (gc > 0)
+ {
+ hmmSeq.insertCharAt(lcol + 1, gc, '-');
+ }
+ gc = 0;
+ lcol = c;
+ }
+ else
+ {
+ gc++;
+ }
+ }
+ }
+
+ if (realign)
+ {
+ realignResults(hmmAndSeqs);
+ }
+ else
+ {
+ AlignmentI al = new Alignment(hmmAndSeqs);
+ if (ppcons != null)
+ {
+ al.addAnnotation(ppcons);
+ }
+ if (modelpos != null)
+ {
+ al.addAnnotation(modelpos);
+ }
+ AlignFrame alignFrame = new AlignFrame(al, AlignFrame.DEFAULT_WIDTH,
+ AlignFrame.DEFAULT_HEIGHT);
+ String ttl = "hmmSearch of " + databaseName + " using "
+ + hmmSeq.getName();
+ Desktop.addInternalFrame(alignFrame, ttl, AlignFrame.DEFAULT_WIDTH,
+ AlignFrame.DEFAULT_HEIGHT);
+
+ if (returnNoOfNewSeqs)
+ {
+ int nNew = checkForNewSequences();
+ JvOptionPane.showMessageDialog(af.alignPanel, nNew + " "
+ + MessageManager.getString("label.new_returned"));
+ }
+
+ }
+
+
+ hmmTemp.delete();
+ inputAlignmentTemp.delete();
+ searchOutputFile.delete();
+ } finally
+ {
+ if (br != null)
+ {
+ br.close();
+ }
+ }
+ }
+
+ private int checkForNewSequences()
+ {
+ int nNew = seqs.length;
+
+ for (SequenceI resultSeq : seqs)
+ {
+ for (SequenceI aliSeq : alignment.getSequencesArray())
+ {
+ if (resultSeq.getName().equals(aliSeq.getName()))
+ {
+ nNew--;
+ break;
+ }
+ }
+ }
+
+ return nNew;
+
+ }
+
+ /**
+ * Realigns the given sequences using hmmalign, to the HMM profile sequence
+ * which is the first in the array, and opens the results in a new frame
+ *
+ * @param hmmAndSeqs
+ */
+ protected void realignResults(SequenceI[] hmmAndSeqs)
+ {
+ /*
+ * and align the search results to the HMM profile
+ */
+ AlignmentI al = new Alignment(hmmAndSeqs);
+ AlignFrame frame = new AlignFrame(al, 1, 1);
+ List alignArgs = new ArrayList<>();
+ String alignTo = hmmAndSeqs[0].getName();
+ List options = Collections.singletonList(alignTo);
+ Option option = new Option(MessageManager.getString("label.use_hmm"),
+ "", true, alignTo, alignTo, options, null);
+ alignArgs.add(option);
+ if (trim)
+ {
+ alignArgs.add(new BooleanOption(
+ MessageManager.getString(TRIM_TERMINI_KEY),
+ MessageManager.getString("label.trim_termini_desc"), true,
+ true, true, null));
+ }
+ HmmerCommand hmmalign = new HMMAlign(frame, alignArgs);
+ hmmalign.run();
+
+ if (returnNoOfNewSeqs)
+ {
+ int nNew = checkForNewSequences();
+ JvOptionPane.showMessageDialog(frame.alignPanel,
+ nNew + " " + MessageManager.getString("label.new_returned"));
+ }
+ }
+
+}
diff --git a/src/jalview/hmmer/HmmerCommand.java b/src/jalview/hmmer/HmmerCommand.java
new file mode 100644
index 0000000..0240352
--- /dev/null
+++ b/src/jalview/hmmer/HmmerCommand.java
@@ -0,0 +1,536 @@
+package jalview.hmmer;
+
+import jalview.analysis.SeqsetUtils;
+import jalview.bin.Cache;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.AnnotatedCollectionI;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.HiddenMarkovModel;
+import jalview.datamodel.SequenceGroup;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.gui.JvOptionPane;
+import jalview.gui.Preferences;
+import jalview.io.FastaFile;
+import jalview.io.HMMFile;
+import jalview.io.StockholmFile;
+import jalview.util.FileUtils;
+import jalview.util.MessageManager;
+import jalview.util.Platform;
+import jalview.ws.params.ArgumentI;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+
+/**
+ * Base class for hmmbuild, hmmalign and hmmsearch
+ *
+ * @author TZVanaalten
+ *
+ */
+public abstract class HmmerCommand implements Runnable
+{
+ public static final String HMMBUILD = "hmmbuild";
+
+ protected final AlignFrame af;
+
+ protected final AlignmentI alignment;
+
+ protected final List params;
+
+ /*
+ * constants for i18n lookup of passed parameter names
+ */
+ static final String DATABASE_KEY = "label.database";
+
+ static final String THIS_ALIGNMENT_KEY = "label.this_alignment";
+
+ static final String USE_ACCESSIONS_KEY = "label.use_accessions";
+
+ static final String AUTO_ALIGN_SEQS_KEY = "label.auto_align_seqs";
+
+ static final String NUMBER_OF_RESULTS_KEY = "label.number_of_results";
+
+ static final String NUMBER_OF_ITERATIONS = "label.number_of_iterations";
+
+ static final String TRIM_TERMINI_KEY = "label.trim_termini";
+
+ static final String RETURN_N_NEW_SEQ = "label.check_for_new_sequences";
+
+ static final String REPORTING_CUTOFF_KEY = "label.reporting_cutoff";
+
+ static final String CUTOFF_NONE = "label.default";
+
+ static final String CUTOFF_SCORE = "label.score";
+
+ static final String CUTOFF_EVALUE = "label.evalue";
+
+ static final String REPORTING_SEQ_EVALUE_KEY = "label.reporting_seq_evalue";
+
+ static final String REPORTING_DOM_EVALUE_KEY = "label.reporting_dom_evalue";
+
+ static final String REPORTING_SEQ_SCORE_KEY = "label.reporting_seq_score";
+
+ static final String REPORTING_DOM_SCORE_KEY = "label.reporting_dom_score";
+
+ static final String INCLUSION_SEQ_EVALUE_KEY = "label.inclusion_seq_evalue";
+
+ static final String INCLUSION_DOM_EVALUE_KEY = "label.inclusion_dom_evalue";
+
+ static final String INCLUSION_SEQ_SCORE_KEY = "label.inclusion_seq_score";
+
+ static final String INCLUSION_DOM_SCORE_KEY = "label.inclusion_dom_score";
+
+ static final String ARG_TRIM = "--trim";
+
+ static final String INCLUSION_THRESHOLD_KEY = "label.inclusion_threshold";
+
+ /**
+ * Constructor
+ *
+ * @param alignFrame
+ * @param args
+ */
+ public HmmerCommand(AlignFrame alignFrame, List args)
+ {
+ af = alignFrame;
+ alignment = af.getViewport().getAlignment();
+ params = args;
+ }
+
+ /**
+ * Answers true if preference HMMER_PATH is set, and its value is the path to
+ * a directory that contains an executable hmmbuild
or
+ * hmmbuild.exe
, else false
+ *
+ * @return
+ */
+ public static boolean isHmmerAvailable()
+ {
+ File exec = FileUtils.getExecutable(HMMBUILD,
+ Cache.getProperty(Preferences.HMMER_PATH));
+ return exec != null;
+ }
+
+ /**
+ * Uniquifies the sequences when exporting and stores their details in a
+ * hashtable
+ *
+ * @param seqs
+ */
+ protected Hashtable stashSequences(SequenceI[] seqs)
+ {
+ return SeqsetUtils.uniquify(seqs, true);
+ }
+
+ /**
+ * Restores the sequence data lost by uniquifying
+ *
+ * @param hashtable
+ * @param seqs
+ */
+ protected void recoverSequences(Hashtable hashtable, SequenceI[] seqs)
+ {
+ SeqsetUtils.deuniquify(hashtable, seqs);
+ }
+
+ /**
+ * Runs a command as a separate process and waits for it to complete. Answers
+ * true if the process return status is zero, else false.
+ *
+ * @param commands
+ * the executable command and any arguments to it
+ * @throws IOException
+ */
+ public boolean runCommand(List commands)
+ throws IOException
+ {
+ List args = Platform.isWindowsAndNotJS() ? wrapWithCygwin(commands)
+ : commands;
+
+ try
+ {
+ ProcessBuilder pb = new ProcessBuilder(args);
+ pb.redirectErrorStream(true); // merge syserr to sysout
+ if (Platform.isWindowsAndNotJS())
+ {
+ String path = pb.environment().get("Path");
+ path = jalview.bin.Cache.getProperty("CYGWIN_PATH") + ";" + path;
+ pb.environment().put("Path", path);
+ }
+ final Process p = pb.start();
+ new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ BufferedReader input = new BufferedReader(
+ new InputStreamReader(p.getInputStream()));
+ try
+ {
+ String line = input.readLine();
+ while (line != null)
+ {
+ System.out.println(line);
+ line = input.readLine();
+ }
+ } catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ }).start();
+
+ p.waitFor();
+ int exitValue = p.exitValue();
+ if (exitValue != 0)
+ {
+ Cache.log.error("Command failed, return code = " + exitValue);
+ Cache.log.error("Command/args were: " + args.toString());
+ }
+ return exitValue == 0; // 0 is success, by convention
+ } catch (Exception e)
+ {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ /**
+ * Converts the given command to a Cygwin "bash" command wrapper. The hmmer
+ * command and any arguments to it are converted into a single parameter to the
+ * bash command.
+ *
+ * @param commands
+ */
+ protected List wrapWithCygwin(List commands)
+ {
+ File bash = FileUtils.getExecutable("bash",
+ Cache.getProperty(Preferences.CYGWIN_PATH));
+ if (bash == null)
+ {
+ Cache.log.error("Cygwin shell not found");
+ return commands;
+ }
+
+ List wrapped = new ArrayList<>();
+ // wrapped.add("C:\Users\tva\run");
+ wrapped.add(bash.getAbsolutePath());
+ wrapped.add("-c");
+
+ /*
+ * combine hmmbuild/search/align and arguments to a single string
+ */
+ StringBuilder sb = new StringBuilder();
+ for (String cmd : commands)
+ {
+ sb.append(" ").append(cmd);
+ }
+ wrapped.add(sb.toString());
+
+ return wrapped;
+ }
+
+ /**
+ * Exports an alignment, and reference (RF) annotation if present, to the
+ * specified file, in Stockholm format, removing all HMM sequences
+ *
+ * @param seqs
+ * @param toFile
+ * @param annotated
+ * @throws IOException
+ */
+ public void exportStockholm(SequenceI[] seqs, File toFile,
+ AnnotatedCollectionI annotated)
+ throws IOException
+ {
+ if (seqs == null)
+ {
+ return;
+ }
+ AlignmentI newAl = new Alignment(seqs);
+
+ if (!newAl.isAligned())
+ {
+ newAl.padGaps();
+ }
+
+ if (toFile != null && annotated != null)
+ {
+ AlignmentAnnotation[] annots = annotated.getAlignmentAnnotation();
+ if (annots != null)
+ {
+ for (AlignmentAnnotation annot : annots)
+ {
+ if (annot.label.contains("Reference") || "RF".equals(annot.label))
+ {
+ AlignmentAnnotation newRF;
+ if (annot.annotations.length > newAl.getWidth())
+ {
+ Annotation[] rfAnnots = new Annotation[newAl.getWidth()];
+ System.arraycopy(annot.annotations, 0, rfAnnots, 0,
+ rfAnnots.length);
+ newRF = new AlignmentAnnotation("RF", "Reference Positions",
+ rfAnnots);
+ }
+ else
+ {
+ newRF = new AlignmentAnnotation(annot);
+ }
+ newAl.addAnnotation(newRF);
+ }
+ }
+ }
+ }
+
+ for (SequenceI seq : newAl.getSequencesArray())
+ {
+ if (seq.getAnnotation() != null)
+ {
+ for (AlignmentAnnotation ann : seq.getAnnotation())
+ {
+ seq.removeAlignmentAnnotation(ann);
+ }
+ }
+ }
+
+ StockholmFile file = new StockholmFile(newAl);
+ String output = file.print(seqs, false);
+ PrintWriter writer = new PrintWriter(toFile);
+ writer.println(output);
+ writer.close();
+ }
+
+ /**
+ * Answers the full path to the given hmmer executable, or null if file cannot
+ * be found or is not executable
+ *
+ * @param cmd
+ * command short name e.g. hmmalign
+ * @return
+ * @throws IOException
+ */
+ protected String getCommandPath(String cmd)
+ throws IOException
+ {
+ String binariesFolder = Cache.getProperty(Preferences.HMMER_PATH);
+ // ensure any symlink to the directory is resolved:
+ binariesFolder = Paths.get(binariesFolder).toRealPath().toString();
+ File file = FileUtils.getExecutable(cmd, binariesFolder);
+ if (file == null && af != null)
+ {
+ JvOptionPane.showInternalMessageDialog(af, MessageManager
+ .formatMessage("label.executable_not_found", cmd));
+ }
+
+ return file == null ? null : getFilePath(file, true);
+ }
+
+ /**
+ * Exports an HMM to the specified file
+ *
+ * @param hmm
+ * @param hmmFile
+ * @throws IOException
+ */
+ public void exportHmm(HiddenMarkovModel hmm, File hmmFile)
+ throws IOException
+ {
+ if (hmm != null)
+ {
+ HMMFile file = new HMMFile(hmm);
+ PrintWriter writer = new PrintWriter(hmmFile);
+ writer.print(file.print());
+ writer.close();
+ }
+ }
+
+ // TODO is needed?
+ /**
+ * Exports a sequence to the specified file
+ *
+ * @param hmm
+ * @param hmmFile
+ * @throws IOException
+ */
+ public void exportSequence(SequenceI seq, File seqFile) throws IOException
+ {
+ if (seq != null)
+ {
+ FastaFile file = new FastaFile();
+ PrintWriter writer = new PrintWriter(seqFile);
+ writer.print(file.print(new SequenceI[] { seq }, false));
+ writer.close();
+ }
+ }
+
+ /**
+ * Answers the HMM profile for the profile sequence the user selected (default
+ * is just the first HMM sequence in the alignment)
+ *
+ * @return
+ */
+ protected HiddenMarkovModel getHmmProfile()
+ {
+ String alignToParamName = MessageManager.getString("label.use_hmm");
+ for (ArgumentI arg : params)
+ {
+ String name = arg.getName();
+ if (name.equals(alignToParamName))
+ {
+ String seqName = arg.getValue();
+ SequenceI hmmSeq = alignment.findName(seqName);
+ if (hmmSeq.hasHMMProfile())
+ {
+ return hmmSeq.getHMM();
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Answers the query sequence the user selected (default is just the first
+ * sequence in the alignment)
+ *
+ * @return
+ */
+ protected SequenceI getSequence()
+ {
+ String alignToParamName = MessageManager
+ .getString("label.use_sequence");
+ for (ArgumentI arg : params)
+ {
+ String name = arg.getName();
+ if (name.equals(alignToParamName))
+ {
+ String seqName = arg.getValue();
+ SequenceI seq = alignment.findName(seqName);
+ return seq;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Answers an absolute path to the given file, in a format suitable for
+ * processing by a hmmer command. On a Windows platform, the native Windows file
+ * path is converted to Cygwin format, by replacing '\'with '/' and drive letter
+ * X with /cygdrive/x.
+ *
+ * @param resultFile
+ * @param isInCygwin
+ * True if file is to be read/written from within the Cygwin
+ * shell. Should be false for any imports.
+ * @return
+ */
+ protected String getFilePath(File resultFile, boolean isInCygwin)
+ {
+ String path = resultFile.getAbsolutePath();
+ if (Platform.isWindowsAndNotJS() && isInCygwin)
+ {
+ // the first backslash escapes '\' for the regular expression argument
+ path = path.replaceAll("\\" + File.separator, "/");
+ int colon = path.indexOf(':');
+ if (colon > 0)
+ {
+ String drive = path.substring(0, colon);
+ path = path.replaceAll(drive + ":", "/cygdrive/" + drive);
+ }
+ }
+
+ return path;
+ }
+
+ /**
+ * A helper method that deletes any HMM consensus sequence from the given
+ * collection, and from the parent alignment if ac
is a subgroup
+ *
+ * @param ac
+ */
+ void deleteHmmSequences(AnnotatedCollectionI ac)
+ {
+ List hmmSeqs = ac.getHmmSequences();
+ for (SequenceI hmmSeq : hmmSeqs)
+ {
+ if (ac instanceof SequenceGroup)
+ {
+ ((SequenceGroup) ac).deleteSequence(hmmSeq, false);
+ AnnotatedCollectionI context = ac.getContext();
+ if (context != null && context instanceof AlignmentI)
+ {
+ ((AlignmentI) context).deleteSequence(hmmSeq);
+ }
+ }
+ else
+ {
+ ((AlignmentI) ac).deleteSequence(hmmSeq);
+ }
+ }
+ }
+
+ /**
+ * Sets the names of any duplicates within the given sequences to include their
+ * respective lengths. Deletes any duplicates that have the same name after this
+ * step
+ *
+ * @param seqs
+ */
+ void renameDuplicates(AlignmentI al)
+ {
+
+ SequenceI[] seqs = al.getSequencesArray();
+ List wasRenamed = new ArrayList<>();
+
+ for (SequenceI seq : seqs)
+ {
+ wasRenamed.add(false);
+ }
+
+ for (int i = 0; i < seqs.length; i++)
+ {
+ for (int j = 0; j < seqs.length; j++)
+ {
+ if (seqs[i].getName().equals(seqs[j].getName()) && i != j
+ && !wasRenamed.get(j))
+ {
+
+ wasRenamed.set(i, true);
+ String range = "/" + seqs[j].getStart() + "-" + seqs[j].getEnd();
+ // setting sequence name to include range - to differentiate between
+ // sequences of the same name. Currently have to include the range twice
+ // because the range is removed (once) when setting the name
+ // TODO come up with a better way of doing this
+ seqs[j].setName(seqs[j].getName() + range + range);
+ }
+
+ }
+ if (wasRenamed.get(i))
+ {
+ String range = "/" + seqs[i].getStart() + "-" + seqs[i].getEnd();
+ seqs[i].setName(seqs[i].getName() + range + range);
+ }
+ }
+
+ for (int i = 0; i < seqs.length; i++)
+ {
+ for (int j = 0; j < seqs.length; j++)
+ {
+ if (seqs[i].getName().equals(seqs[j].getName()) && i != j)
+ {
+ al.deleteSequence(j);
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/jalview/hmmer/JackHMMER.java b/src/jalview/hmmer/JackHMMER.java
new file mode 100644
index 0000000..12c0492
--- /dev/null
+++ b/src/jalview/hmmer/JackHMMER.java
@@ -0,0 +1,179 @@
+package jalview.hmmer;
+
+import jalview.bin.Cache;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.gui.Desktop;
+import jalview.gui.JvOptionPane;
+import jalview.io.DataSourceType;
+import jalview.io.FileParse;
+import jalview.io.StockholmFile;
+import jalview.util.FileUtils;
+import jalview.util.MessageManager;
+import jalview.ws.params.ArgumentI;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.JOptionPane;
+
+public class JackHMMER extends Search
+{
+
+ SequenceI seq = null;
+
+ /**
+ * Constructor for the JackhmmerThread
+ *
+ * @param af
+ */
+ public JackHMMER(AlignFrame af, List args)
+ {
+ super(af, args);
+ }
+
+ /**
+ * Runs the JackhmmerThread: the data on the alignment or group is exported,
+ * then the command is executed in the command line and then the data is
+ * imported and displayed in a new frame. Call this method directly to execute
+ * synchronously, or via start() in a new Thread for asynchronously.
+ */
+ @Override
+ public void run()
+ {
+ seq = getSequence();
+ if (seq == null)
+ {
+ // shouldn't happen if we got this far
+ Cache.log.error("Error: no sequence for jackhmmer");
+ return;
+ }
+
+ long msgId = System.currentTimeMillis();
+ af.setProgressBar(MessageManager.getString("status.running_search"),
+ msgId);
+
+ try
+ {
+ File seqFile = FileUtils.createTempFile("seq", ".sto");
+ File hitsAlignmentFile = FileUtils.createTempFile("hitAlignment",
+ ".sto");
+ File searchOutputFile = FileUtils.createTempFile("searchOutput",
+ ".txt");
+
+ exportStockholm(new SequenceI[] { seq }, seqFile.getAbsoluteFile(),
+ null);
+
+ boolean ran = runCommand(searchOutputFile, hitsAlignmentFile,
+ seqFile);
+ if (!ran)
+ {
+ JvOptionPane.showInternalMessageDialog(af, MessageManager
+ .formatMessage("warn.command_failed", "jackhmmer"));
+ return;
+ }
+
+ importData(hitsAlignmentFile, seqFile, searchOutputFile);
+ // TODO make realignment of search results a step at this level
+ // and make it conditional on this.realign
+ } catch (IOException | InterruptedException e)
+ {
+ e.printStackTrace();
+ } finally
+ {
+ af.setProgressBar("", msgId);
+ }
+ }
+
+ /**
+ * Executes an jackhmmer search with the given sequence as input. The database
+ * to be searched is a local file as specified by the 'Database' parameter, or
+ * the current alignment (written to file) if none is specified.
+ *
+ * @param searchOutputFile
+ * @param hitsAlignmentFile
+ * @param seqFile
+ *
+ * @return
+ * @throws IOException
+ */
+ private boolean runCommand(File searchOutputFile, File hitsAlignmentFile,
+ File seqFile) throws IOException
+ {
+ String command = getCommandPath(JACKHMMER);
+ if (command == null)
+ {
+ return false;
+ }
+
+ List args = new ArrayList<>();
+ args.add(command);
+ buildArguments(args, searchOutputFile, hitsAlignmentFile, seqFile);
+
+ return runCommand(args);
+ }
+
+ /**
+ * Imports the data from the temporary file to which the output of jackhmmer was
+ * directed.
+ */
+ private void importData(File inputAlignmentTemp, File seqTemp,
+ File searchOutputFile) throws IOException, InterruptedException
+ {
+ BufferedReader br = new BufferedReader(
+ new FileReader(inputAlignmentTemp));
+ try
+ {
+ if (br.readLine() == null)
+ {
+ JOptionPane.showMessageDialog(af,
+ MessageManager.getString("label.no_sequences_found"));
+ return;
+ }
+ StockholmFile file = new StockholmFile(new FileParse(
+ inputAlignmentTemp.getAbsolutePath(), DataSourceType.FILE));
+ seqs = file.getSeqsAsArray();
+
+ readDomainTable(searchOutputFile, true);
+
+ if (searchAlignment)
+ {
+ recoverSequences(sequencesHash, seqs);
+ }
+
+
+
+ int seqCount = seqs.length;
+
+
+ AlignmentI al = new Alignment(seqs);
+
+ AlignFrame alignFrame = new AlignFrame(al, AlignFrame.DEFAULT_WIDTH,
+ AlignFrame.DEFAULT_HEIGHT);
+ String ttl = "jackhmmer search of " + databaseName + " using "
+ + seqs[0].getName();
+ Desktop.addInternalFrame(alignFrame, ttl, AlignFrame.DEFAULT_WIDTH,
+ AlignFrame.DEFAULT_HEIGHT);
+
+ seqTemp.delete();
+ inputAlignmentTemp.delete();
+ searchOutputFile.delete();
+ } finally
+ {
+ if (br != null)
+ {
+ br.close();
+ }
+ }
+ }
+
+
+
+
+}
diff --git a/src/jalview/hmmer/Search.java b/src/jalview/hmmer/Search.java
new file mode 100644
index 0000000..ceb79e5
--- /dev/null
+++ b/src/jalview/hmmer/Search.java
@@ -0,0 +1,394 @@
+package jalview.hmmer;
+
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignFrame;
+import jalview.util.FileUtils;
+import jalview.util.MessageManager;
+import jalview.ws.params.ArgumentI;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Scanner;
+
+public abstract class Search extends HmmerCommand
+{
+
+ static final String JACKHMMER = "jackhmmer";
+
+ static final String HMMSEARCH = "hmmsearch";
+
+ boolean realign = false;
+
+ boolean trim = false;
+
+ SequenceI[] seqs;
+
+ String databaseName;
+
+ boolean searchAlignment = true;
+
+ Hashtable sequencesHash;
+
+ public Search(AlignFrame alignFrame, List args)
+ {
+ super(alignFrame, args);
+ }
+
+ @Override
+ public void run()
+ {
+ }
+
+ /*
+ void readOutputFile(File inputTableTemp) throws IOException
+ {
+ BufferedReader br = new BufferedReader(new FileReader(inputTableTemp));
+
+
+ String line = "";
+ while (!line.startsWith("//"))
+ {
+
+ while (!line.startsWith(">> ") && !line.startsWith("//"))
+ {
+ line = br.readLine();
+ }
+
+ if (line.startsWith("//"))
+ {
+ break;
+ }
+
+ Scanner scanner = new Scanner(line);
+ String name = scanner.next();
+ name = scanner.next();
+
+ br.readLine();
+ br.readLine();
+
+ List domains = new ArrayList<>();
+
+ for (SequenceI seq : seqs)
+ {
+ if (seq.getName().contains(name))
+ {
+ domains.add(seq);
+ }
+ }
+
+ if (domains.contains(getSequence()))
+ {
+ domains.remove(getSequence());
+ }
+
+ if (domains.size() > 0)
+ {
+ readOutputTable(br, domains);
+ }
+
+ line = br.readLine();
+ }
+
+ }
+
+
+ /**
+ * Reads in the scores table output by jackhmmer and adds annotation to
+ * sequences for E-value and bit score
+ *
+ * @param inputTableTemp
+ * @throws IOException
+ */
+ /*
+ void readOutputTable(BufferedReader br, List seqs) throws IOException
+ {
+ String line = br.readLine();
+
+ while (!"".equals(line) && line != null)
+ {
+ if (" ------ inclusion threshold ------".equals(line))
+ {
+ line = br.readLine();
+ continue;
+ }
+
+ Scanner scanner = new Scanner(line);
+ scanner.next();
+ scanner.next();
+ String score = scanner.next();
+
+ scanner.next();
+
+ String evalue = scanner.next();
+
+ scanner.next();
+ scanner.next();
+ scanner.next();
+ scanner.next();
+
+ int start = scanner.nextInt();
+ int end = scanner.nextInt();
+
+ SequenceI seq = null;
+ for (SequenceI sequence : seqs)
+ {
+ if (sequence.getStart() >= start && sequence.getEnd() <= end)
+ {
+ seq = sequence;
+ break;
+ }
+ }
+
+ if (seq != null)
+ {
+ addScoreAnnotations(evalue, score, seq);
+ }
+
+ scanner.close();
+ line = br.readLine();
+ }
+ }
+ */
+
+ void readDomainTable(File inputTableTemp, boolean includesQuery)
+ throws IOException
+ {
+ BufferedReader br = new BufferedReader(new FileReader(inputTableTemp));
+
+ String line = br.readLine();
+ br.readLine();
+ br.readLine();
+ line = br.readLine();
+
+ int index;
+
+ if (includesQuery)
+ {
+ index = 1;
+ }
+ else
+ {
+ index = 0;
+ }
+ while (!line.startsWith("#"))
+ {
+ if (line.contains("inclusion threshold"))
+ {
+ line = br.readLine();
+ continue;
+ }
+
+ Scanner scanner = new Scanner(line);
+ String name = scanner.next();
+
+ for (int i = 0; i < 10; i++)
+ {
+ scanner.next();
+ }
+
+ String evalue = scanner.next();
+ scanner.next();
+ String score = scanner.next();
+
+ addScoreAnnotations(evalue, score, seqs[index]);
+ index++;
+
+ scanner.close();
+ line = br.readLine();
+ }
+ br.close();
+ }
+
+
+
+
+ void addScoreAnnotations(String eValue, String bitScore, SequenceI seq)
+ {
+ String label = "Search Scores";
+ String description = "Full sequence bit score and E-Value";
+
+ try
+ {
+ AlignmentAnnotation annot = new AlignmentAnnotation(label,
+ description, null);
+
+ annot.label = label;
+ annot.description = description;
+
+ annot.setCalcId(JACKHMMER);
+
+ double dEValue = Double.parseDouble(eValue);
+ annot.setEValue(dEValue);
+
+ double dBitScore = Double.parseDouble(bitScore);
+ annot.setBitScore(dBitScore);
+
+ annot.setSequenceRef(seq);
+ seq.addAlignmentAnnotation(annot);
+
+ } catch (NumberFormatException e)
+ {
+ System.err.println("Error parsing " + label + " from " + eValue
+ + " & " + bitScore);
+ }
+ }
+
+ void buildArguments(List args, File searchOutputFile,
+ File hitsAlignmentFile, File queryFile) throws IOException
+ {
+ args.add("--domtblout");
+ args.add(getFilePath(searchOutputFile, true));
+ args.add("-A");
+ args.add(getFilePath(hitsAlignmentFile, true));
+
+ File databaseFile = null;
+
+ boolean useEvalueCutoff = false;
+ boolean useScoreCutoff = false;
+ String seqReportingEvalueCutoff = null;
+ String domReportingEvalueCutoff = null;
+ String seqReportingScoreCutoff = null;
+ String domReportingScoreCutoff = null;
+ String seqInclusionEvalueCutoff = null;
+ String domInclusionEvalueCutoff = null;
+ String seqInclusionScoreCutoff = null;
+ String domInclusionScoreCutoff = null;
+ databaseName = "Alignment";
+
+ if (params != null)
+ {
+ for (ArgumentI arg : params)
+ {
+ String name = arg.getName();
+
+ if (MessageManager.getString(REPORTING_CUTOFF_KEY).equals(name))
+ {
+ if (MessageManager.getString(CUTOFF_EVALUE)
+ .equals(arg.getValue()))
+ {
+ useEvalueCutoff = true;
+ }
+ else if (MessageManager.getString(CUTOFF_SCORE)
+ .equals(arg.getValue()))
+ {
+ useScoreCutoff = true;
+ }
+ }
+ else if (MessageManager.getString(REPORTING_SEQ_EVALUE_KEY)
+ .equals(name))
+ {
+ seqReportingEvalueCutoff = arg.getValue();
+ }
+ else if (MessageManager.getString(REPORTING_SEQ_SCORE_KEY)
+ .equals(name))
+ {
+ seqReportingScoreCutoff = arg.getValue();
+ }
+ else if (MessageManager.getString(REPORTING_DOM_EVALUE_KEY)
+ .equals(name))
+ {
+ domReportingEvalueCutoff = arg.getValue();
+ }
+ else if (MessageManager.getString(REPORTING_DOM_SCORE_KEY)
+ .equals(name))
+ {
+ domReportingScoreCutoff = arg.getValue();
+ }
+ else if (MessageManager.getString(INCLUSION_SEQ_EVALUE_KEY)
+ .equals(name))
+ {
+ seqInclusionEvalueCutoff = arg.getValue();
+ }
+ else if (MessageManager.getString(INCLUSION_SEQ_SCORE_KEY)
+ .equals(name))
+ {
+ seqInclusionScoreCutoff = arg.getValue();
+ }
+ else if (MessageManager.getString(INCLUSION_DOM_EVALUE_KEY)
+ .equals(name))
+ {
+ domInclusionEvalueCutoff = arg.getValue();
+ }
+ else if (MessageManager.getString(INCLUSION_DOM_SCORE_KEY)
+ .equals(name))
+ {
+ domInclusionScoreCutoff = arg.getValue();
+ }
+ else if (MessageManager.getString(DATABASE_KEY).equals(name))
+ {
+ databaseFile = new File(arg.getValue());
+ if (!arg.getValue().isEmpty())
+ {
+ searchAlignment = false;
+ }
+ }
+ else if (MessageManager.getString(NUMBER_OF_ITERATIONS)
+ .equals(name))
+ {
+ if (!arg.getValue().isEmpty())
+ {
+ args.add("-N");
+ args.add(arg.getValue());
+ }
+ }
+ }
+ }
+
+ if (useEvalueCutoff)
+ {
+ args.add("-E");
+ args.add(seqReportingEvalueCutoff);
+ args.add("--domE");
+ args.add(domReportingEvalueCutoff);
+
+ args.add("--incE");
+ args.add(seqInclusionEvalueCutoff);
+ args.add("--incdomE");
+ args.add(domInclusionEvalueCutoff);
+ }
+ else if (useScoreCutoff)
+ {
+ args.add("-T");
+ args.add(seqReportingScoreCutoff);
+ args.add("--domT");
+ args.add(domReportingScoreCutoff);
+
+ args.add("--incT");
+ args.add(seqInclusionEvalueCutoff);
+ args.add("--incdomT");
+ args.add(domInclusionEvalueCutoff);
+ }
+
+ // if (!dbFound || MessageManager.getString(THIS_ALIGNMENT_KEY)
+ // .equals(dbPath))
+ if (searchAlignment)
+ {
+ /*
+ * no external database specified for search, so
+ * export current alignment as 'database' to search
+ */
+ databaseFile = FileUtils.createTempFile("database", ".sto");
+ AlignmentI al = af.getViewport().getAlignment();
+ AlignmentI copy = new Alignment(al);
+
+ deleteHmmSequences(copy);
+
+ if (searchAlignment)
+ {
+ sequencesHash = stashSequences(copy.getSequencesArray());
+ }
+
+ exportStockholm(copy.getSequencesArray(), databaseFile, null);
+ }
+
+ args.add(getFilePath(queryFile, true));
+ args.add(getFilePath(databaseFile, true));
+ }
+}
diff --git a/src/jalview/io/AlignFile.java b/src/jalview/io/AlignFile.java
index cea2870..41f2586 100755
--- a/src/jalview/io/AlignFile.java
+++ b/src/jalview/io/AlignFile.java
@@ -323,9 +323,9 @@ public abstract class AlignFile extends FileParse
*/
protected void initData()
{
- seqs = new Vector();
- annotations = new Vector();
- seqGroups = new ArrayList();
+ seqs = new Vector<>();
+ annotations = new Vector<>();
+ seqGroups = new ArrayList<>();
parseCalled = false;
}
@@ -338,7 +338,7 @@ public abstract class AlignFile extends FileParse
@Override
public void setSeqs(SequenceI[] s)
{
- seqs = new Vector();
+ seqs = new Vector<>();
for (int i = 0; i < s.length; i++)
{
@@ -409,7 +409,7 @@ public abstract class AlignFile extends FileParse
{
if (newickStrings == null)
{
- newickStrings = new Vector();
+ newickStrings = new Vector<>();
}
newickStrings.addElement(new String[] { treeName, newickString });
}
@@ -433,4 +433,16 @@ public abstract class AlignFile extends FileParse
{
seqs.add(seq);
}
+
+ /**
+ * Used only for hmmer statistics, so should probably be removed at some
+ * point. TODO remove this
+ *
+ * @return
+ */
+ public Vector getAnnotations()
+ {
+ return annotations;
+ }
+
}
diff --git a/src/jalview/io/CountReader.java b/src/jalview/io/CountReader.java
new file mode 100644
index 0000000..a691c53
--- /dev/null
+++ b/src/jalview/io/CountReader.java
@@ -0,0 +1,63 @@
+package jalview.io;
+
+import jalview.bin.Jalview;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.ResidueCount;
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignmentPanel;
+import jalview.gui.Desktop;
+import jalview.gui.JvOptionPane;
+import jalview.util.MessageManager;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+
+import javax.swing.JFileChooser;
+
+public class CountReader
+{
+ public static ResidueCount getBackgroundFrequencies(AlignmentPanel ap, SequenceI seq) throws MalformedURLException, IOException
+ {
+ JFileChooser bkgdFreqChooser = new JFileChooser();
+
+ bkgdFreqChooser.showOpenDialog(ap);
+
+ File file = bkgdFreqChooser.getSelectedFile();
+ if (file == null)
+ {
+ return null;
+ }
+
+ IdentifyFile identifier = new IdentifyFile();
+ FileFormatI format = null;
+ try
+ {
+ format = identifier.identify(file.getPath(), DataSourceType.FILE);
+ } catch (Exception e)
+ {
+
+ }
+
+ if (format == null)
+ {
+ if (!Jalview.isHeadlessMode())
+ {
+ JvOptionPane.showInternalMessageDialog(Desktop.getInstance(),
+ MessageManager.getString("label.couldnt_read_data") + " in "
+ + file + "\n"
+ + AppletFormatAdapter.getSupportedFormats(),
+ MessageManager.getString("label.couldnt_read_data"),
+ JvOptionPane.WARNING_MESSAGE);
+ }
+ }
+
+ FileParse parser = new FileParse(file.getPath(), DataSourceType.FILE);
+ AlignmentI al = new FormatAdapter().readFromFile(parser, format);
+ parser.close();
+
+ ResidueCount counts = new ResidueCount(al.getSequences());
+
+ return counts;
+ }
+}
diff --git a/src/jalview/io/FileFormat.java b/src/jalview/io/FileFormat.java
index 0ad2901..b7df731 100644
--- a/src/jalview/io/FileFormat.java
+++ b/src/jalview/io/FileFormat.java
@@ -373,6 +373,21 @@ public enum FileFormat implements FileFormatI
{
return true;
}
+ },
+ HMMER3("HMMER3", "hmm", true, true)
+ {
+ @Override
+ public AlignmentFileReaderI getReader(FileParse source)
+ throws IOException
+ {
+ return new HMMFile(source);
+ }
+
+ @Override
+ public AlignmentFileWriterI getWriter(AlignmentI al)
+ {
+ return new HMMFile();
+ }
}, BSML("BSML", "bbb", true, false)
{
@Override
@@ -389,6 +404,7 @@ public enum FileFormat implements FileFormatI
}
};
+
private boolean writable;
private boolean readable;
diff --git a/src/jalview/io/FileLoader.java b/src/jalview/io/FileLoader.java
index 0317c7d..df64702 100755
--- a/src/jalview/io/FileLoader.java
+++ b/src/jalview/io/FileLoader.java
@@ -50,8 +50,13 @@ import jalview.util.MessageManager;
import jalview.util.Platform;
import jalview.ws.utils.UrlDownloadClient;
+import java.util.ArrayList;
+import java.util.List;
+
public class FileLoader implements Runnable
{
+ private static final String TAB = "\t";
+
String file;
DataSourceType protocol;
@@ -214,56 +219,79 @@ public class FileLoader implements Runnable
return alignFrame;
}
- public void updateRecentlyOpened()
+ public void LoadFileOntoAlignmentWaitTillLoaded(AlignViewport viewport,
+ String file, DataSourceType sourceType, FileFormatI format)
{
Vector recent = new Vector<>();
if (protocol == DataSourceType.PASTE)
+ this.viewport = viewport;
+ this.file = file;
+ this.protocol = sourceType;
+ this.format = format;
+ _LoadFileWaitTillLoaded();
+ }
+
+
+ /**
+ * Updates (or creates) the tab-separated list of recently opened files held
+ * under the given property name by inserting the filePath at the front of the
+ * list. Duplicates are removed, and the list is limited to 11 entries. The
+ * method returns the updated value of the property.
+ *
+ * @param filePath
+ * @param sourceType
+ */
+ public static String updateRecentlyOpened(String filePath,
+ DataSourceType sourceType)
+ {
+ if (sourceType != DataSourceType.FILE
+ && sourceType != DataSourceType.URL)
{
- // do nothing if the file was pasted in as text... there is no filename to
- // refer to it as.
- return;
+ return null;
}
- if (file != null
- && file.indexOf(System.getProperty("java.io.tmpdir")) > -1)
+
+ String propertyName = sourceType == DataSourceType.FILE ? "RECENT_FILE"
+ : "RECENT_URL";
+ String historyItems = Cache.getProperty(propertyName);
+ if (filePath != null
+ && filePath.indexOf(System.getProperty("java.io.tmpdir")) > -1)
{
// ignore files loaded from the system's temporary directory
- return;
+ return null;
}
- String type = protocol == DataSourceType.FILE ? "RECENT_FILE"
- : "RECENT_URL";
- String historyItems = Cache.getProperty(type);
-
- StringTokenizer st;
+ List recent = new ArrayList<>();
if (historyItems != null)
{
- st = new StringTokenizer(historyItems, "\t");
+ StringTokenizer st = new StringTokenizer(historyItems, TAB);
while (st.hasMoreTokens())
{
- recent.addElement(st.nextToken().trim());
+ String trimmed = st.nextToken().trim();
+ recent.add(trimmed);
}
}
- if (recent.contains(file))
+ /*
+ * if file was already in the list, it moves to the top
+ */
+ if (recent.contains(filePath))
{
- recent.remove(file);
+ recent.remove(filePath);
}
- StringBuffer newHistory = new StringBuffer(file);
+ StringBuilder newHistory = new StringBuilder(filePath);
for (int i = 0; i < recent.size() && i < 10; i++)
{
- newHistory.append("\t");
- newHistory.append(recent.elementAt(i));
+ newHistory.append(TAB);
+ newHistory.append(recent.get(i));
}
- Cache.setProperty(type, newHistory.toString());
+ String newProperty = newHistory.toString();
+ Cache.setProperty(propertyName, newProperty);
- if (protocol == DataSourceType.FILE)
- {
- Cache.setProperty("DEFAULT_FILE_FORMAT", format.getName());
- }
+ return newProperty;
}
@Override
@@ -424,6 +452,22 @@ public class FileLoader implements Runnable
}
// append to existing alignment
viewport.addAlignment(al, title);
+ if (source instanceof HMMFile)
+ {
+ AlignmentI alignment = viewport.getAlignment();
+ SequenceI seq = alignment
+ .getSequenceAt(alignment.getHeight() - 1);
+ if (seq.hasHMMProfile())
+ {
+ /*
+ * fudge: move HMM consensus sequence from last to first
+ */
+ alignment.deleteSequence(alignment.getAbsoluteHeight() - 1);
+ alignment.insertSequenceAt(0, seq);
+ }
+ viewport.getAlignPanel().adjustAnnotationHeight();
+ viewport.updateSequenceIdColours();
+ }
}
else
{
@@ -531,7 +575,12 @@ public class FileLoader implements Runnable
}
}
- updateRecentlyOpened();
+ updateRecentlyOpened(file, protocol);
+
+ if (protocol == DataSourceType.FILE && format != null)
+ {
+ Cache.setProperty("DEFAULT_FILE_FORMAT", format.getName());
+ }
} catch (Exception er)
{
diff --git a/src/jalview/io/HMMFile.java b/src/jalview/io/HMMFile.java
new file mode 100644
index 0000000..2fce4cc
--- /dev/null
+++ b/src/jalview/io/HMMFile.java
@@ -0,0 +1,716 @@
+package jalview.io;
+
+import jalview.api.AlignExportSettingsI;
+import jalview.api.AlignmentViewPanel;
+import jalview.datamodel.HMMNode;
+import jalview.datamodel.HiddenMarkovModel;
+import jalview.datamodel.SequenceI;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Scanner;
+
+
+/**
+ * Adds capability to read in and write out HMMER3 files. .
+ *
+ *
+ * @author TZVanaalten
+ *
+ */
+public class HMMFile extends AlignFile
+ implements AlignmentFileReaderI, AlignmentFileWriterI
+{
+ private static final String TERMINATOR = "//";
+
+ /*
+ * keys to data in HMM file, used to store as properties of the HiddenMarkovModel
+ */
+ public static final String HMM = "HMM";
+
+ public static final String NAME = "NAME";
+
+ public static final String ACCESSION_NUMBER = "ACC";
+
+ public static final String DESCRIPTION = "DESC";
+
+ public static final String LENGTH = "LENG";
+
+ public static final String MAX_LENGTH = "MAXL";
+
+ public static final String ALPHABET = "ALPH";
+
+ public static final String DATE = "DATE";
+
+ public static final String COMMAND_LOG = "COM";
+
+ public static final String NUMBER_OF_SEQUENCES = "NSEQ";
+
+ public static final String EFF_NUMBER_OF_SEQUENCES = "EFFN";
+
+ public static final String CHECK_SUM = "CKSUM";
+
+ public static final String STATISTICS = "STATS";
+
+ public static final String COMPO = "COMPO";
+
+ public static final String GATHERING_THRESHOLD = "GA";
+
+ public static final String TRUSTED_CUTOFF = "TC";
+
+ public static final String NOISE_CUTOFF = "NC";
+
+ public static final String VITERBI = "VITERBI";
+
+ public static final String MSV = "MSV";
+
+ public static final String FORWARD = "FORWARD";
+
+ public static final String MAP = "MAP";
+
+ public static final String REFERENCE_ANNOTATION = "RF";
+
+ public static final String CONSENSUS_RESIDUE = "CONS";
+
+ public static final String CONSENSUS_STRUCTURE = "CS";
+
+ public static final String MASKED_VALUE = "MM";
+
+ private static final String ALPH_AMINO = "amino";
+
+ private static final String ALPH_DNA = "DNA";
+
+ private static final String ALPH_RNA = "RNA";
+
+ private static final String ALPHABET_AMINO = "ACDEFGHIKLMNPQRSTVWY";
+
+ private static final String ALPHABET_DNA = "ACGT";
+
+ private static final String ALPHABET_RNA = "ACGU";
+
+ private static final int NUMBER_OF_TRANSITIONS = 7;
+
+ private static final String SPACE = " ";
+
+ /*
+ * optional guide line added to an output HMMER file, purely for readability
+ */
+ private static final String TRANSITIONTYPELINE = " m->m m->i m->d i->m i->i d->m d->d";
+
+ private static String NL = System.lineSeparator();
+
+ private HiddenMarkovModel hmm;
+
+ // number of symbols in the alphabet used in the hidden Markov model
+ private int numberOfSymbols;
+
+ /**
+ * Constructor that parses immediately
+ *
+ * @param inFile
+ * @param type
+ * @throws IOException
+ */
+ public HMMFile(String inFile, DataSourceType type) throws IOException
+ {
+ super(inFile, type);
+ }
+
+ /**
+ * Constructor that parses immediately
+ *
+ * @param source
+ * @throws IOException
+ */
+ public HMMFile(FileParse source) throws IOException
+ {
+ super(source);
+ }
+
+ /**
+ * Default constructor
+ */
+ public HMMFile()
+ {
+ }
+
+ /**
+ * Constructor for HMMFile used for exporting
+ *
+ * @param hmm
+ */
+ public HMMFile(HiddenMarkovModel markov)
+ {
+ hmm = markov;
+ }
+
+ /**
+ * Returns the HMM produced by parsing a HMMER3 file
+ *
+ * @return
+ */
+ public HiddenMarkovModel getHMM()
+ {
+ return hmm;
+ }
+
+ /**
+ * Gets the name of the hidden Markov model
+ *
+ * @return
+ */
+ public String getName()
+ {
+ return hmm.getName();
+ }
+
+ /**
+ * Reads the data from HMM file into the HMM model
+ */
+ @Override
+ public void parse()
+ {
+ try
+ {
+ hmm = new HiddenMarkovModel();
+ parseHeaderLines(dataIn);
+ parseModel(dataIn);
+ } catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Reads the header properties from a HMMER3 file and saves them in the
+ * HiddeMarkovModel. This method exits after reading the next line after the
+ * HMM line.
+ *
+ * @param input
+ * @throws IOException
+ */
+ void parseHeaderLines(BufferedReader input) throws IOException
+ {
+ boolean readingHeaders = true;
+ hmm.setFileHeader(input.readLine());
+ String line = input.readLine();
+ while (readingHeaders && line != null)
+ {
+ Scanner parser = new Scanner(line);
+ String next = parser.next();
+ if (ALPHABET.equals(next))
+ {
+ String alphabetType = parser.next();
+ hmm.setProperty(ALPHABET, alphabetType);
+ String alphabet = ALPH_DNA.equalsIgnoreCase(alphabetType)
+ ? ALPHABET_DNA
+ : (ALPH_RNA.equalsIgnoreCase(alphabetType) ? ALPHABET_RNA
+ : ALPHABET_AMINO);
+ numberOfSymbols = hmm.setAlphabet(alphabet);
+ }
+ else if (HMM.equals(next))
+ {
+ readingHeaders = false;
+ String symbols = line.substring(line.indexOf(HMM) + HMM.length());
+ numberOfSymbols = hmm.setAlphabet(symbols);
+ }
+ else if (STATISTICS.equals(next))
+ {
+ parser.next();
+ String key;
+ String value;
+ key = parser.next();
+ value = parser.next() + SPACE + SPACE + parser.next();
+ hmm.setProperty(key, value);
+ }
+ else
+ {
+ String key = next;
+ String value = parser.next();
+ while (parser.hasNext())
+ {
+ value = value + SPACE + parser.next();
+ }
+ hmm.setProperty(key, value);
+ }
+ parser.close();
+ line = input.readLine();
+ }
+ }
+
+ /**
+ * Parses the model data from the HMMER3 file. The input buffer should be
+ * positioned at the (optional) COMPO line if there is one, else at the insert
+ * emissions line for the BEGIN node of the model.
+ *
+ * @param input
+ * @throws IOException
+ */
+ void parseModel(BufferedReader input) throws IOException
+ {
+ /*
+ * specification says there must always be an HMM header (already read)
+ * and one more header (guide headings) which is skipped here
+ */
+ int nodeNo = 0;
+ String line = input.readLine();
+ List nodes = new ArrayList<>();
+
+ while (line != null && !TERMINATOR.equals(line))
+ {
+ HMMNode node = new HMMNode();
+ nodes.add(node);
+ Scanner scanner = new Scanner(line);
+ String next = scanner.next();
+
+ /*
+ * expect COMPO (optional) for average match emissions
+ * or a node number followed by node's match emissions
+ */
+ if (COMPO.equals(next) || nodeNo > 0)
+ {
+ /*
+ * parse match emissions
+ */
+ double[] matches = parseDoubles(scanner, numberOfSymbols);
+ node.setMatchEmissions(matches);
+ if (!COMPO.equals(next))
+ {
+ int resNo = parseAnnotations(scanner, node);
+ if (resNo == 0)
+ {
+ /*
+ * no MAP annotation provided, just number off from 0 (begin node)
+ */
+ resNo = nodeNo;
+ }
+ node.setResidueNumber(resNo);
+ }
+ line = input.readLine();
+ }
+ scanner.close();
+
+ /*
+ * parse insert emissions
+ */
+ scanner = new Scanner(line);
+ double[] inserts = parseDoubles(scanner, numberOfSymbols);
+ node.setInsertEmissions(inserts);
+ scanner.close();
+
+ /*
+ * parse state transitions
+ */
+ line = input.readLine();
+ scanner = new Scanner(line);
+ double[] transitions = parseDoubles(scanner,
+ NUMBER_OF_TRANSITIONS);
+ node.setStateTransitions(transitions);
+ scanner.close();
+ line = input.readLine();
+
+ nodeNo++;
+ }
+
+ hmm.setNodes(nodes);
+ }
+
+ /**
+ * Parses the annotations on the match emission line and add them to the node.
+ * (See p109 of the HMMER User Guide (V3.1b2) for the specification.) Returns
+ * the residue position that the node maps to, if provided, else zero.
+ *
+ * @param scanner
+ * @param node
+ */
+ int parseAnnotations(Scanner scanner, HMMNode node)
+ {
+ int mapTo = 0;
+
+ /*
+ * map from hmm node to sequence position, if provided
+ */
+ if (scanner.hasNext())
+ {
+ String value = scanner.next();
+ if (!"-".equals(value))
+ {
+ try
+ {
+ mapTo = Integer.parseInt(value);
+ node.setResidueNumber(mapTo);
+ } catch (NumberFormatException e)
+ {
+ // ignore
+ }
+ }
+ }
+
+ /*
+ * hmm consensus residue if provided, else '-'
+ */
+ if (scanner.hasNext())
+ {
+ node.setConsensusResidue(scanner.next().charAt(0));
+ }
+
+ /*
+ * RF reference annotation, if provided, else '-'
+ */
+ if (scanner.hasNext())
+ {
+ node.setReferenceAnnotation(scanner.next().charAt(0));
+ }
+
+ /*
+ * 'm' for masked position, if provided, else '-'
+ */
+ if (scanner.hasNext())
+ {
+ node.setMaskValue(scanner.next().charAt(0));
+ }
+
+ /*
+ * structure consensus symbol, if provided, else '-'
+ */
+ if (scanner.hasNext())
+ {
+ node.setConsensusStructure(scanner.next().charAt(0));
+ }
+
+ return mapTo;
+ }
+
+ /**
+ * Fills an array of doubles parsed from an input line
+ *
+ * @param input
+ * @param numberOfElements
+ * @return
+ * @throws IOException
+ */
+ static double[] parseDoubles(Scanner input,
+ int numberOfElements) throws IOException
+ {
+ double[] values = new double[numberOfElements];
+ for (int i = 0; i < numberOfElements; i++)
+ {
+ if (!input.hasNext())
+ {
+ throw new IOException("Incomplete data");
+ }
+ String next = input.next();
+ if (next.contains("*"))
+ {
+ values[i] = Double.NEGATIVE_INFINITY;
+ }
+ else
+ {
+ double prob = Double.valueOf(next);
+ prob = Math.pow(Math.E, -prob);
+ values[i] = prob;
+ }
+ }
+ return values;
+ }
+
+ /**
+ * Returns a string to be added to the StringBuilder containing the entire
+ * output String.
+ *
+ * @param initialColumnSeparation
+ * The initial whitespace separation between the left side of the
+ * file and first character.
+ * @param columnSeparation
+ * The separation between subsequent data entries.
+ * @param data
+ * The list of data to be added to the String.
+ * @return
+ */
+ String addData(int initialColumnSeparation,
+ int columnSeparation, List data)
+ {
+ String line = "";
+ boolean first = true;
+ for (String value : data)
+ {
+ int sep = first ? initialColumnSeparation : columnSeparation;
+ line += String.format("%" + sep + "s", value);
+ first = false;
+ }
+ return line;
+ }
+
+ /**
+ * Converts list of characters into a list of Strings.
+ *
+ * @param list
+ * @return Returns the list of Strings.
+ */
+ List charListToStringList(List list)
+ {
+ List strList = new ArrayList<>();
+ for (char value : list)
+ {
+ String strValue = Character.toString(value);
+ strList.add(strValue);
+ }
+ return strList;
+ }
+
+ /**
+ * Converts an array of doubles into a list of Strings, rounded to the nearest
+ * 5th decimal place
+ *
+ * @param doubles
+ * @param noOfDecimals
+ * @return
+ */
+ List doublesToStringList(double[] doubles)
+ {
+ List strList = new ArrayList<>();
+ for (double value : doubles)
+ {
+ String strValue;
+ if (value > 0)
+ {
+ strValue = String.format("%.5f", value);
+ }
+ else if (value == -0.00000d)
+ {
+ strValue = "0.00000";
+ }
+ else
+ {
+ strValue = "*";
+ }
+ strList.add(strValue);
+ }
+ return strList;
+ }
+
+ /**
+ * Appends model data in string format to the string builder
+ *
+ * @param output
+ */
+ void appendModelAsString(StringBuilder output)
+ {
+ output.append(HMM).append(" ");
+ String charSymbols = hmm.getSymbols();
+ for (char c : charSymbols.toCharArray())
+ {
+ output.append(String.format("%9s", c));
+ }
+ output.append(NL).append(TRANSITIONTYPELINE);
+
+ int length = hmm.getLength();
+
+ for (int nodeNo = 0; nodeNo <= length; nodeNo++)
+ {
+ String matchLine = String.format("%7s",
+ nodeNo == 0 ? COMPO : Integer.toString(nodeNo));
+
+ double[] doubleMatches = convertToLogSpace(
+ hmm.getNode(nodeNo).getMatchEmissions());
+ List strMatches = doublesToStringList(doubleMatches);
+ matchLine += addData(10, 9, strMatches);
+
+ if (nodeNo != 0)
+ {
+ matchLine += SPACE + (hmm.getNodeMapPosition(nodeNo));
+ matchLine += SPACE + hmm.getConsensusResidue(nodeNo);
+ matchLine += SPACE + hmm.getReferenceAnnotation(nodeNo);
+ if (hmm.getFileHeader().contains("HMMER3/f"))
+ {
+ matchLine += SPACE + hmm.getMaskedValue(nodeNo);
+ matchLine += SPACE + hmm.getConsensusStructure(nodeNo);
+ }
+ }
+
+ output.append(NL).append(matchLine);
+
+ String insertLine = "";
+
+ double[] doubleInserts = convertToLogSpace(
+ hmm.getNode(nodeNo).getInsertEmissions());
+ List strInserts = doublesToStringList(doubleInserts);
+ insertLine += addData(17, 9, strInserts);
+
+ output.append(NL).append(insertLine);
+
+ String transitionLine = "";
+ double[] doubleTransitions = convertToLogSpace(
+ hmm.getNode(nodeNo).getStateTransitions());
+ List strTransitions = doublesToStringList(
+ doubleTransitions);
+ transitionLine += addData(17, 9, strTransitions);
+
+ output.append(NL).append(transitionLine);
+ }
+ }
+
+ /**
+ * Appends formatted HMM file properties to the string builder
+ *
+ * @param output
+ */
+ void appendProperties(StringBuilder output)
+ {
+ output.append(hmm.getFileHeader());
+
+ String format = "%n%-5s %1s";
+ appendProperty(output, format, NAME);
+ appendProperty(output, format, ACCESSION_NUMBER);
+ appendProperty(output, format, DESCRIPTION);
+ appendProperty(output, format, LENGTH);
+ appendProperty(output, format, MAX_LENGTH);
+ appendProperty(output, format, ALPHABET);
+ appendBooleanProperty(output, format, REFERENCE_ANNOTATION);
+ appendBooleanProperty(output, format, MASKED_VALUE);
+ appendBooleanProperty(output, format, CONSENSUS_RESIDUE);
+ appendBooleanProperty(output, format, CONSENSUS_STRUCTURE);
+ appendBooleanProperty(output, format, MAP);
+ appendProperty(output, format, DATE);
+ appendProperty(output, format, NUMBER_OF_SEQUENCES);
+ appendProperty(output, format, EFF_NUMBER_OF_SEQUENCES);
+ appendProperty(output, format, CHECK_SUM);
+ appendProperty(output, format, GATHERING_THRESHOLD);
+ appendProperty(output, format, TRUSTED_CUTOFF);
+ appendProperty(output, format, NOISE_CUTOFF);
+
+ if (hmm.getMSV() != null)
+ {
+ format = "%n%-19s %18s";
+ output.append(String.format(format, "STATS LOCAL MSV", hmm.getMSV()));
+
+ output.append(String.format(format, "STATS LOCAL VITERBI",
+ hmm.getViterbi()));
+
+ output.append(String.format(format, "STATS LOCAL FORWARD",
+ hmm.getForward()));
+ }
+ }
+
+ /**
+ * Appends 'yes' or 'no' for the given property, according to whether or not
+ * it is set in the HMM
+ *
+ * @param output
+ * @param format
+ * @param propertyName
+ */
+ private void appendBooleanProperty(StringBuilder output, String format,
+ String propertyName)
+ {
+ boolean set = hmm.getBooleanProperty(propertyName);
+ output.append(String.format(format, propertyName,
+ set ? HiddenMarkovModel.YES : HiddenMarkovModel.NO));
+ }
+
+ /**
+ * Appends the value of the given property to the output, if not null
+ *
+ * @param output
+ * @param format
+ * @param propertyName
+ */
+ private void appendProperty(StringBuilder output, String format,
+ String propertyName)
+ {
+ String value = hmm.getProperty(propertyName);
+ if (value != null)
+ {
+ output.append(String.format(format, propertyName, value));
+ }
+ }
+
+ @Override
+ public String print(SequenceI[] sequences, boolean jvsuffix)
+ {
+ if (sequences[0].getHMM() != null)
+ {
+ hmm = sequences[0].getHMM();
+ }
+ return print();
+ }
+
+ /**
+ * Prints the .hmm file to a String.
+ *
+ * @return
+ */
+ public String print()
+ {
+ StringBuilder output = new StringBuilder();
+ appendProperties(output);
+ output.append(NL);
+ appendModelAsString(output);
+ output.append(NL).append(TERMINATOR).append(NL);
+ return output.toString();
+ }
+
+ /**
+ * Converts the probabilities contained in an array into log space
+ *
+ * @param ds
+ */
+ double[] convertToLogSpace(double[] ds)
+ {
+ double[] converted = new double[ds.length];
+ for (int i = 0; i < ds.length; i++)
+ {
+ double prob = ds[i];
+ double logProb = -1 * Math.log(prob);
+
+ converted[i] = logProb;
+ }
+ return converted;
+ }
+
+ /**
+ * Returns the HMM sequence produced by reading a .hmm file.
+ */
+ @Override
+ public SequenceI[] getSeqsAsArray()
+ {
+ SequenceI hmmSeq = hmm.getConsensusSequence();
+ SequenceI[] seq = new SequenceI[1];
+ seq[0] = hmmSeq;
+ return seq;
+ }
+
+ @Override
+ public void setNewlineString(String newLine)
+ {
+ NL = newLine;
+ }
+
+ @Override
+ public void setExportSettings(AlignExportSettingsI exportSettings)
+ {
+
+ }
+
+ @Override
+ public void configureForView(AlignmentViewPanel viewpanel)
+ {
+
+ }
+
+ @Override
+ public boolean hasWarningMessage()
+ {
+ return false;
+ }
+
+ @Override
+ public String getWarningMessage()
+ {
+ return "warning message";
+ }
+
+}
+
diff --git a/src/jalview/io/IdentifyFile.java b/src/jalview/io/IdentifyFile.java
index df40ec1..b8a4d6a 100755
--- a/src/jalview/io/IdentifyFile.java
+++ b/src/jalview/io/IdentifyFile.java
@@ -185,6 +185,11 @@ public class IdentifyFile
reply = FileFormat.ScoreMatrix;
break;
}
+ if (data.startsWith("HMMER3"))
+ {
+ reply = FileFormat.HMMER3;
+ break;
+ }
if (data.startsWith("H ") && !aaIndexHeaderRead)
{
aaIndexHeaderRead = true;
diff --git a/src/jalview/io/SequenceAnnotationReport.java b/src/jalview/io/SequenceAnnotationReport.java
index 4d0bec7..d5c3ed3 100644
--- a/src/jalview/io/SequenceAnnotationReport.java
+++ b/src/jalview/io/SequenceAnnotationReport.java
@@ -27,6 +27,7 @@ import java.util.List;
import java.util.Map;
import jalview.api.FeatureColourI;
+import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.DBRefEntry;
import jalview.datamodel.DBRefSource;
import jalview.datamodel.GeneLociI;
@@ -480,12 +481,27 @@ public class SequenceAnnotationReport
sb.append(tmp);
maxWidth = Math.max(maxWidth, tmp.length());
}
+
SequenceI ds = sequence;
while (ds.getDatasetSequence() != null)
{
ds = ds.getDatasetSequence();
}
+ /*
+ * add any annotation scores
+ */
+ AlignmentAnnotation[] anns = ds.getAnnotation();
+ for (int i = 0; anns != null && i < anns.length; i++)
+ {
+ AlignmentAnnotation aa = anns[i];
+ if (aa != null && aa.hasScore() && aa.sequenceRef != null)
+ {
+ sb.append(" ").append(aa.label).append(": ")
+ .append(aa.getScore());
+ }
+ }
+
if (showDbRefs)
{
maxWidth = Math.max(maxWidth, appendDbRefs(sb, ds, summary));
@@ -505,7 +521,24 @@ public class SequenceAnnotationReport
maxWidth = Math.max(maxWidth, sz);
}
}
+
+
+ if (sequence.getAnnotation("Search Scores") != null)
+ {
+ sb.append(" ");
+ String eValue = " E-Value: "
+ + sequence.getAnnotation("Search Scores")[0].getEValue();
+ String bitScore = " Bit Score: "
+ + sequence.getAnnotation("Search Scores")[0].getBitScore();
+ sb.append(eValue);
+ sb.append(" ");
+ sb.append(bitScore);
+ maxWidth = Math.max(maxWidth, eValue.length());
+ maxWidth = Math.max(maxWidth, bitScore.length());
+ }
+ sb.append(" ");
sb.append("");
+
return maxWidth;
}
diff --git a/src/jalview/io/StockholmFile.java b/src/jalview/io/StockholmFile.java
index 3d07e5a..50112c8 100644
--- a/src/jalview/io/StockholmFile.java
+++ b/src/jalview/io/StockholmFile.java
@@ -79,8 +79,9 @@ public class StockholmFile extends AlignFile
{
private static final String ANNOTATION = "annotation";
- // WUSS extended symbols. Avoid ambiguity with protein SS annotations by using
- // NOT_RNASS first.
+ private static final char UNDERSCORE = '_';
+
+ // WUSS extended symbols. Avoid ambiguity with protein SS annotations by using NOT_RNASS first.
public static final String RNASS_BRACKETS = "<>[](){}AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz";
@@ -118,7 +119,7 @@ public class StockholmFile extends AlignFile
/**
* Centralize all actual Regex instantialization in Platform.
- *
+ * // JBPNote: Why is this 'centralisation' better ?
* @param id
* @return
*/
@@ -181,14 +182,14 @@ public class StockholmFile extends AlignFile
StringBuffer out; // output buffer
- AlignmentI al;
+ private AlignmentI al;
public StockholmFile()
{
}
/**
- * Creates a new StockholmFile object for output.
+ * Creates a new StockholmFile object for output
*/
public StockholmFile(AlignmentI al)
{
@@ -726,14 +727,15 @@ public class StockholmFile extends AlignFile
if (features.containsKey(this.id2type(type)))
{
// logger.debug("Found content for " + this.id2type(type));
- content = (Hashtable) features.get(this.id2type(type));
+ content = (Hashtable) features
+ .get(this.id2type(type));
}
else
{
// logger.debug("Creating new content holder for " +
// this.id2type(type));
content = new Hashtable();
- features.put(this.id2type(type), content);
+ features.put(id2type(type), content);
}
String ns = (String) content.get(ANNOTATION);
@@ -914,10 +916,9 @@ public class StockholmFile extends AlignFile
Vector annotation, String label,
String annots)
{
- String convert1, convert2 = null;
-
- // convert1 = OPEN_PAREN.replaceAll(annots);
- // convert2 = CLOSE_PAREN.replaceAll(convert1);
+ String convert1, convert2 = null;
+ // String convert1 = OPEN_PAREN.replaceAll(annots);
+ // String convert2 = CLOSE_PAREN.replaceAll(convert1);
// annots = convert2;
String type = label;
@@ -931,6 +932,7 @@ public class StockholmFile extends AlignFile
type = id2type(type);
boolean isrnass = false;
+
if (type.equalsIgnoreCase("secondary structure"))
{
ss = true;
@@ -948,6 +950,10 @@ public class StockholmFile extends AlignFile
for (int i = 0; i < annots.length(); i++)
{
String pos = annots.substring(i, i + 1);
+ if (UNDERSCORE == pos.charAt(0))
+ {
+ pos = " ";
+ }
Annotation ann;
ann = new Annotation(pos, "", ' ', 0f); // 0f is 'valid' null - will not
// be written out
@@ -1137,36 +1143,38 @@ public class StockholmFile extends AlignFile
if (alAnot != null)
{
Annotation[] ann;
- for (int j = 0, nj = alAnot.length; j < nj; j++)
+ for (int j = 0; j < alAnot.length; j++)
{
-
- String key = type2id(alAnot[j].label);
- boolean isrna = alAnot[j].isValidStruc();
-
- if (isrna)
- {
- // hardwire to secondary structure if there is RNA secondary
- // structure on the annotation
- key = "SS";
- }
- if (key == null)
+ if (alAnot[j].annotations != null)
{
+ String key = type2id(alAnot[j].label);
+ boolean isrna = alAnot[j].isValidStruc();
- continue;
- }
+ if (isrna)
+ {
+ // hardwire to secondary structure if there is RNA secondary
+ // structure on the annotation
+ key = "SS";
+ }
+ if (key == null)
+ {
+ continue;
+ }
- // out.append("#=GR ");
- out.append(new Format("%-" + maxid + "s").form(
- "#=GR " + printId(seq, jvSuffix) + " " + key + " "));
- ann = alAnot[j].annotations;
- String sseq = "";
- for (int k = 0, nk = ann.length; k < nk; k++)
- {
- sseq += outputCharacter(key, k, isrna, ann, seq);
- }
- out.append(sseq);
- out.append(newline);
+ // out.append("#=GR ");
+ out.append(new Format("%-" + maxid + "s").form(
+ "#=GR " + printId(s[i], jvSuffix) + " " + key + " "));
+ ann = alAnot[j].annotations;
+ String sseq = "";
+ for (int k = 0; k < ann.length; k++)
+ {
+ sseq += outputCharacter(key, k, isrna, ann, s[i]);
+ }
+ out.append(sseq);
+ out.append(newline);
+ }
}
+
}
out.append(new Format("%-" + maxid + "s")
@@ -1231,6 +1239,7 @@ public class StockholmFile extends AlignFile
return out.toString();
}
+
/**
* add an annotation character to the output row
*
@@ -1298,6 +1307,26 @@ public class StockholmFile extends AlignFile
: seq;
}
+ /**
+ * make a friendly ID string.
+ *
+ * @param dataName
+ * @return truncated dataName to after last '/'
+ */
+ private String safeName(String dataName)
+ {
+ int b = 0;
+ while ((b = dataName.indexOf("/")) > -1 && b < dataName.length())
+ {
+ dataName = dataName.substring(b + 1).trim();
+
+ }
+ int e = (dataName.length() - dataName.indexOf(".")) + 1;
+ dataName = dataName.substring(1, e).trim();
+ return dataName;
+ }
+
+
public String print()
{
out = new StringBuffer();
@@ -1335,7 +1364,7 @@ public class StockholmFile extends AlignFile
}
}
-
+
protected static String id2type(String id)
{
if (typeIds.containsKey(id))
@@ -1368,23 +1397,4 @@ public class StockholmFile extends AlignFile
"Warning : Unknown Stockholm annotation type: " + type);
return key;
}
-
- /**
- * make a friendly ID string.
- *
- * @param dataName
- * @return truncated dataName to after last '/'
- */
- private String safeName(String dataName)
- {
- int b = 0;
- while ((b = dataName.indexOf("/")) > -1 && b < dataName.length())
- {
- dataName = dataName.substring(b + 1).trim();
-
- }
- int e = (dataName.length() - dataName.indexOf(".")) + 1;
- dataName = dataName.substring(1, e).trim();
- return dataName;
- }
}
diff --git a/src/jalview/jbgui/GAlignFrame.java b/src/jalview/jbgui/GAlignFrame.java
index 6c6d123..25db31a 100755
--- a/src/jalview/jbgui/GAlignFrame.java
+++ b/src/jalview/jbgui/GAlignFrame.java
@@ -31,6 +31,7 @@ import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
+import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@@ -57,11 +58,14 @@ import jalview.api.SplitContainerI;
import jalview.bin.Cache;
import jalview.gui.JvSwingUtils;
import jalview.gui.Preferences;
+import jalview.hmmer.HmmerCommand;
+import jalview.io.FileFormatException;
import jalview.io.FileFormats;
import jalview.schemes.ResidueColourScheme;
import jalview.util.MessageManager;
import jalview.util.Platform;
+
@SuppressWarnings("serial")
public class GAlignFrame extends JInternalFrame
{
@@ -71,9 +75,11 @@ public class GAlignFrame extends JInternalFrame
public JMenu webService = new JMenu();// BH 2019 was protected, but not
// sufficient for AlignFrame thread run
+ // JBP - followed suite for these other service related GUI elements.
+ // TODO: check we really need these to be public
+ public JMenu hmmerMenu = new JMenu();
- public JMenuItem webServiceNoServices;// BH 2019 was protected, but not
- // sufficient for AlignFrame thread run
+ public JMenuItem webServiceNoServices;
protected JCheckBoxMenuItem viewBoxesMenuItem = new JCheckBoxMenuItem();
@@ -203,6 +209,12 @@ public class GAlignFrame extends JInternalFrame
protected JCheckBoxMenuItem normaliseSequenceLogo = new JCheckBoxMenuItem();
+ protected JCheckBoxMenuItem showInformationHistogram = new JCheckBoxMenuItem();
+
+ protected JCheckBoxMenuItem showHMMSequenceLogo = new JCheckBoxMenuItem();
+
+ protected JCheckBoxMenuItem normaliseHMMSequenceLogo = new JCheckBoxMenuItem();
+
protected JCheckBoxMenuItem applyAutoAnnotationSettings = new JCheckBoxMenuItem();
protected JMenuItem openFeatureSettings;
@@ -264,7 +276,7 @@ public class GAlignFrame extends JInternalFrame
private void jbInit() throws Exception
{
initColourMenu();
-
+
JMenuItem saveAs = new JMenuItem(
MessageManager.getString("action.save_as"));
ActionListener al = new ActionListener()
@@ -275,12 +287,12 @@ public class GAlignFrame extends JInternalFrame
saveAs_actionPerformed();
}
};
-
+
// FIXME getDefaultToolkit throws an exception in Headless mode
KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_S, Platform.SHORTCUT_KEY_MASK | InputEvent.SHIFT_DOWN_MASK,
false);
addMenuActionAndAccelerator(keyStroke, saveAs, al);
-
+
closeMenuItem.setText(MessageManager.getString("action.close"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_W, Platform.SHORTCUT_KEY_MASK, false);
al = new ActionListener()
@@ -292,7 +304,7 @@ public class GAlignFrame extends JInternalFrame
}
};
addMenuActionAndAccelerator(keyStroke, closeMenuItem, al);
-
+
JMenu editMenu = new JMenu(MessageManager.getString("action.edit"));
JMenu viewMenu = new JMenu(MessageManager.getString("action.view"));
JMenu annotationsMenu = new JMenu(
@@ -302,6 +314,9 @@ public class GAlignFrame extends JInternalFrame
JMenu calculateMenu = new JMenu(
MessageManager.getString("action.calculate"));
webService.setText(MessageManager.getString("action.web_service"));
+
+ initHMMERMenu();
+
JMenuItem selectAllSequenceMenuItem = new JMenuItem(
MessageManager.getString("action.select_all"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_A,
@@ -315,7 +330,7 @@ public class GAlignFrame extends JInternalFrame
}
};
addMenuActionAndAccelerator(keyStroke, selectAllSequenceMenuItem, al);
-
+
JMenuItem deselectAllSequenceMenuItem = new JMenuItem(
MessageManager.getString("action.deselect_all"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false);
@@ -328,7 +343,7 @@ public class GAlignFrame extends JInternalFrame
}
};
addMenuActionAndAccelerator(keyStroke, deselectAllSequenceMenuItem, al);
-
+
JMenuItem invertSequenceMenuItem = new JMenuItem(
MessageManager.getString("action.invert_sequence_selection"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_I,
@@ -342,7 +357,7 @@ public class GAlignFrame extends JInternalFrame
}
};
addMenuActionAndAccelerator(keyStroke, invertSequenceMenuItem, al);
-
+
JMenuItem grpsFromSelection = new JMenuItem(
MessageManager.getString("action.make_groups_selection"));
grpsFromSelection.addActionListener(new ActionListener()
@@ -378,7 +393,7 @@ public class GAlignFrame extends JInternalFrame
}
};
addMenuActionAndAccelerator(keyStroke, remove2LeftMenuItem, al);
-
+
JMenuItem remove2RightMenuItem = new JMenuItem(
MessageManager.getString("action.remove_right"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_R,
@@ -392,7 +407,7 @@ public class GAlignFrame extends JInternalFrame
}
};
addMenuActionAndAccelerator(keyStroke, remove2RightMenuItem, al);
-
+
JMenuItem removeGappedColumnMenuItem = new JMenuItem(
MessageManager.getString("action.remove_empty_columns"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_E,
@@ -406,7 +421,7 @@ public class GAlignFrame extends JInternalFrame
}
};
addMenuActionAndAccelerator(keyStroke, removeGappedColumnMenuItem, al);
-
+
JMenuItem removeAllGapsMenuItem = new JMenuItem(
MessageManager.getString("action.remove_all_gaps"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_E,
@@ -422,7 +437,7 @@ public class GAlignFrame extends JInternalFrame
}
};
addMenuActionAndAccelerator(keyStroke, removeAllGapsMenuItem, al);
-
+
JMenuItem justifyLeftMenuItem = new JMenuItem(
MessageManager.getString("action.left_justify_alignment"));
justifyLeftMenuItem.addActionListener(new ActionListener()
@@ -514,7 +529,27 @@ public class GAlignFrame extends JInternalFrame
sortGroupMenuItem_actionPerformed(e);
}
});
-
+ JMenuItem sortEValueMenuItem = new JMenuItem(
+ MessageManager.getString("action.by_evalue"));
+ sortEValueMenuItem.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ sortEValueMenuItem_actionPerformed(e);
+ }
+ });
+ JMenuItem sortBitScoreMenuItem = new JMenuItem(
+ MessageManager.getString("action.by_bit_score"));
+ sortBitScoreMenuItem.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ sortBitScoreMenuItem_actionPerformed(e);
+ }
+ });
+
JMenuItem removeRedundancyMenuItem = new JMenuItem(
MessageManager.getString("action.remove_redundancy"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_D,
@@ -529,6 +564,30 @@ public class GAlignFrame extends JInternalFrame
};
addMenuActionAndAccelerator(keyStroke, removeRedundancyMenuItem, al);
+ JMenuItem filterByEValue = new JMenuItem(
+ MessageManager.getString("action.filter_by_evalue"));
+ filterByEValue.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ filterByEValue_actionPerformed();
+ }
+
+ });
+
+ JMenuItem filterByScore = new JMenuItem(
+ MessageManager.getString("action.filter_by_score"));
+ filterByScore.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ filterByScore_actionPerformed();
+ }
+
+ });
+
JMenuItem pairwiseAlignmentMenuItem = new JMenuItem(
MessageManager.getString("action.pairwise_alignment"));
pairwiseAlignmentMenuItem.addActionListener(new ActionListener()
@@ -539,16 +598,18 @@ public class GAlignFrame extends JInternalFrame
pairwiseAlignmentMenuItem_actionPerformed(e);
}
});
-
+
this.getContentPane().setLayout(new BorderLayout());
alignFrameMenuBar.setFont(new java.awt.Font("Verdana", 0, 11));
statusBar.setBackground(Color.white);
statusBar.setFont(new java.awt.Font("Verdana", 0, 11));
statusBar.setBorder(BorderFactory.createLineBorder(Color.black));
statusBar.setText(MessageManager.getString("label.status_bar"));
+
outputTextboxMenu
.setText(MessageManager.getString("label.out_to_textbox"));
+
annotationPanelMenuItem.setActionCommand("");
annotationPanelMenuItem
.setText(MessageManager.getString("label.show_annotations"));
@@ -616,6 +677,7 @@ public class GAlignFrame extends JInternalFrame
final JCheckBoxMenuItem sortAnnByLabel = new JCheckBoxMenuItem(
MessageManager.getString("label.sort_annotations_by_label"));
+
sortAnnBySequence.setSelected(
sortAnnotationsBy == SequenceAnnotationOrder.SEQUENCE_AND_LABEL);
sortAnnBySequence.addActionListener(new ActionListener()
@@ -656,7 +718,7 @@ public class GAlignFrame extends JInternalFrame
colourTextMenuItem_actionPerformed(e);
}
});
-
+
JMenuItem htmlMenuItem = new JMenuItem(
MessageManager.getString("label.html"));
htmlMenuItem.addActionListener(new ActionListener()
@@ -667,7 +729,7 @@ public class GAlignFrame extends JInternalFrame
htmlMenuItem_actionPerformed(e);
}
});
-
+
JMenuItem createBioJS = new JMenuItem(
MessageManager.getString("label.biojs_html_export"));
createBioJS.addActionListener(new java.awt.event.ActionListener()
@@ -678,7 +740,7 @@ public class GAlignFrame extends JInternalFrame
bioJSMenuItem_actionPerformed(e);
}
});
-
+
JMenuItem overviewMenuItem = new JMenuItem(
MessageManager.getString("label.overview_window"));
overviewMenuItem.addActionListener(new ActionListener()
@@ -689,7 +751,7 @@ public class GAlignFrame extends JInternalFrame
overviewMenuItem_actionPerformed(e);
}
});
-
+
undoMenuItem.setEnabled(false);
undoMenuItem.setText(MessageManager.getString("action.undo"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_Z,
@@ -703,7 +765,7 @@ public class GAlignFrame extends JInternalFrame
}
};
addMenuActionAndAccelerator(keyStroke, undoMenuItem, al);
-
+
redoMenuItem.setEnabled(false);
redoMenuItem.setText(MessageManager.getString("action.redo"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_Y,
@@ -717,7 +779,7 @@ public class GAlignFrame extends JInternalFrame
}
};
addMenuActionAndAccelerator(keyStroke, redoMenuItem, al);
-
+
wrapMenuItem.setText(MessageManager.getString("label.wrap"));
wrapMenuItem.addActionListener(new ActionListener()
{
@@ -727,7 +789,7 @@ public class GAlignFrame extends JInternalFrame
wrapMenuItem_actionPerformed(e);
}
});
-
+
JMenuItem printMenuItem = new JMenuItem(
MessageManager.getString("action.print"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_P,
@@ -741,7 +803,7 @@ public class GAlignFrame extends JInternalFrame
}
};
addMenuActionAndAccelerator(keyStroke, printMenuItem, al);
-
+
renderGapsMenuItem
.setText(MessageManager.getString("action.show_gaps"));
renderGapsMenuItem.setState(true);
@@ -753,7 +815,7 @@ public class GAlignFrame extends JInternalFrame
renderGapsMenuItem_actionPerformed(e);
}
});
-
+
JMenuItem findMenuItem = new JMenuItem(
MessageManager.getString("action.find"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_F,
@@ -772,6 +834,7 @@ public class GAlignFrame extends JInternalFrame
showSeqFeatures.setText(
MessageManager.getString("label.show_sequence_features"));
+
showSeqFeatures.addActionListener(new ActionListener()
{
@Override
@@ -790,86 +853,86 @@ public class GAlignFrame extends JInternalFrame
.setText(MessageManager.getString("label.show_database_refs"));
showDbRefsMenuitem.addActionListener(new ActionListener()
{
-
+
@Override
public void actionPerformed(ActionEvent e)
{
showDbRefs_actionPerformed(e);
}
-
+
});
showNpFeatsMenuitem.setText(
MessageManager.getString("label.show_non_positional_features"));
showNpFeatsMenuitem.addActionListener(new ActionListener()
{
-
+
@Override
public void actionPerformed(ActionEvent e)
{
showNpFeats_actionPerformed(e);
}
-
+
});
showGroupConservation
.setText(MessageManager.getString("label.group_conservation"));
showGroupConservation.addActionListener(new ActionListener()
{
-
+
@Override
public void actionPerformed(ActionEvent e)
{
showGroupConservation_actionPerformed(e);
}
-
+
});
showGroupConsensus
.setText(MessageManager.getString("label.group_consensus"));
showGroupConsensus.addActionListener(new ActionListener()
{
-
+
@Override
public void actionPerformed(ActionEvent e)
{
showGroupConsensus_actionPerformed(e);
}
-
+
});
showConsensusHistogram.setText(
MessageManager.getString("label.show_consensus_histogram"));
showConsensusHistogram.addActionListener(new ActionListener()
{
-
+
@Override
public void actionPerformed(ActionEvent e)
{
showConsensusHistogram_actionPerformed(e);
}
-
+
});
showSequenceLogo
.setText(MessageManager.getString("label.show_consensus_logo"));
showSequenceLogo.addActionListener(new ActionListener()
{
-
+
@Override
public void actionPerformed(ActionEvent e)
{
showSequenceLogo_actionPerformed(e);
}
-
+
});
normaliseSequenceLogo
.setText(MessageManager.getString("label.norm_consensus_logo"));
normaliseSequenceLogo.addActionListener(new ActionListener()
{
-
+
@Override
public void actionPerformed(ActionEvent e)
{
normaliseSequenceLogo_actionPerformed(e);
}
-
+
});
applyAutoAnnotationSettings
.setText(MessageManager.getString("label.apply_all_groups"));
@@ -883,7 +946,7 @@ public class GAlignFrame extends JInternalFrame
applyAutoAnnotationSettings_actionPerformed(e);
}
});
-
+
ButtonGroup buttonGroup = new ButtonGroup();
final JRadioButtonMenuItem showAutoFirst = new JRadioButtonMenuItem(
MessageManager.getString("label.show_first"));
@@ -914,7 +977,7 @@ public class GAlignFrame extends JInternalFrame
sortAnnotations_actionPerformed();
}
});
-
+
JMenuItem deleteGroups = new JMenuItem(
MessageManager.getString("action.undefine_groups"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_U,
@@ -928,7 +991,7 @@ public class GAlignFrame extends JInternalFrame
}
};
addMenuActionAndAccelerator(keyStroke, deleteGroups, al);
-
+
JMenuItem annotationColumn = new JMenuItem(
MessageManager.getString("action.select_by_annotation"));
annotationColumn.addActionListener(new ActionListener()
@@ -939,7 +1002,7 @@ public class GAlignFrame extends JInternalFrame
annotationColumn_actionPerformed(e);
}
});
-
+
JMenuItem createGroup = new JMenuItem(
MessageManager.getString("action.create_group"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_G,
@@ -953,7 +1016,7 @@ public class GAlignFrame extends JInternalFrame
}
};
addMenuActionAndAccelerator(keyStroke, createGroup, al);
-
+
JMenuItem unGroup = new JMenuItem(
MessageManager.getString("action.remove_group"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_G,
@@ -969,7 +1032,7 @@ public class GAlignFrame extends JInternalFrame
}
};
addMenuActionAndAccelerator(keyStroke, unGroup, al);
-
+
copy.setText(MessageManager.getString("action.copy"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_C,
Platform.SHORTCUT_KEY_MASK, false);
@@ -983,7 +1046,7 @@ public class GAlignFrame extends JInternalFrame
}
};
addMenuActionAndAccelerator(keyStroke, copy, al);
-
+
cut.setText(MessageManager.getString("action.cut"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_X,
Platform.SHORTCUT_KEY_MASK, false);
@@ -996,7 +1059,7 @@ public class GAlignFrame extends JInternalFrame
}
};
addMenuActionAndAccelerator(keyStroke, cut, al);
-
+
JMenuItem delete = new JMenuItem(
MessageManager.getString("action.delete"));
delete.addActionListener(new ActionListener()
@@ -1007,7 +1070,7 @@ public class GAlignFrame extends JInternalFrame
delete_actionPerformed();
}
});
-
+
pasteMenu.setText(MessageManager.getString("action.paste"));
JMenuItem pasteNew = new JMenuItem(
MessageManager.getString("label.to_new_alignment"));
@@ -1020,11 +1083,18 @@ public class GAlignFrame extends JInternalFrame
@Override
public void actionPerformed(ActionEvent e)
{
- pasteNew_actionPerformed(e);
+ try
+ {
+ pasteNew_actionPerformed(e);
+ } catch (IOException | InterruptedException e1)
+ {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ }
}
};
addMenuActionAndAccelerator(keyStroke, pasteNew, al);
-
+
JMenuItem pasteThis = new JMenuItem(
MessageManager.getString("label.to_this_alignment"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_V,
@@ -1034,11 +1104,18 @@ public class GAlignFrame extends JInternalFrame
@Override
public void actionPerformed(ActionEvent e)
{
- pasteThis_actionPerformed(e);
+ try
+ {
+ pasteThis_actionPerformed(e);
+ } catch (IOException | InterruptedException e1)
+ {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ }
}
};
addMenuActionAndAccelerator(keyStroke, pasteThis, al);
-
+
JMenuItem createPNG = new JMenuItem("PNG");
createPNG.addActionListener(new ActionListener()
{
@@ -1050,7 +1127,6 @@ public class GAlignFrame extends JInternalFrame
});
createPNG.setActionCommand(
MessageManager.getString("label.save_png_image"));
-
JMenuItem font = new JMenuItem(MessageManager.getString("action.font"));
font.addActionListener(new ActionListener()
{
@@ -1080,7 +1156,7 @@ public class GAlignFrame extends JInternalFrame
createEPS(null);
}
});
-
+
JMenuItem createSVG = new JMenuItem("SVG");
createSVG.addActionListener(new ActionListener()
{
@@ -1090,7 +1166,7 @@ public class GAlignFrame extends JInternalFrame
createSVG(null);
}
});
-
+
JMenuItem loadTreeMenuItem = new JMenuItem(
MessageManager.getString("label.load_associated_tree"));
loadTreeMenuItem.setActionCommand(
@@ -1103,7 +1179,7 @@ public class GAlignFrame extends JInternalFrame
loadTreeMenuItem_actionPerformed(e);
}
});
-
+
scaleAbove.setVisible(false);
scaleAbove.setText(MessageManager.getString("action.scale_above"));
scaleAbove.addActionListener(new ActionListener()
@@ -1154,15 +1230,15 @@ public class GAlignFrame extends JInternalFrame
.setText(MessageManager.getString("label.automatic_scrolling"));
followHighlightMenuItem.addActionListener(new ActionListener()
{
-
+
@Override
public void actionPerformed(ActionEvent e)
{
followHighlight_actionPerformed();
}
-
+
});
-
+
sortByTreeMenu
.setText(MessageManager.getString("action.by_tree_order"));
sort.setText(MessageManager.getString("action.sort"));
@@ -1191,12 +1267,12 @@ public class GAlignFrame extends JInternalFrame
{
buildTreeSortMenu();
}
-
+
@Override
public void menuDeselected(MenuEvent e)
{
}
-
+
@Override
public void menuCanceled(MenuEvent e)
{
@@ -1207,17 +1283,17 @@ public class GAlignFrame extends JInternalFrame
sort.add(sortByAnnotScore);
sort.addMenuListener(new javax.swing.event.MenuListener()
{
-
+
@Override
public void menuCanceled(MenuEvent e)
{
}
-
+
@Override
public void menuDeselected(MenuEvent e)
{
}
-
+
@Override
public void menuSelected(MenuEvent e)
{
@@ -1297,7 +1373,7 @@ public class GAlignFrame extends JInternalFrame
showReverse_actionPerformed(true);
}
});
-
+
JMenuItem extractScores = new JMenuItem(
MessageManager.getString("label.extract_scores"));
extractScores.addActionListener(new ActionListener()
@@ -1310,10 +1386,10 @@ public class GAlignFrame extends JInternalFrame
});
extractScores.setVisible(true);
// JBPNote: TODO: make gui for regex based score extraction
-
+
// for show products actions see AlignFrame.canShowProducts
showProducts.setText(MessageManager.getString("label.get_cross_refs"));
-
+
runGroovy.setText(MessageManager.getString("label.run_groovy"));
runGroovy.setToolTipText(
MessageManager.getString("label.run_groovy_tip"));
@@ -1350,7 +1426,7 @@ public class GAlignFrame extends JInternalFrame
fetchSequence_actionPerformed();
}
});
-
+
JMenuItem associatedData = new JMenuItem(
MessageManager.getString("label.load_features_annotations"));
associatedData.addActionListener(new ActionListener()
@@ -1358,7 +1434,14 @@ public class GAlignFrame extends JInternalFrame
@Override
public void actionPerformed(ActionEvent e)
{
- associatedData_actionPerformed(e);
+ try
+ {
+ associatedData_actionPerformed(e);
+ } catch (IOException | InterruptedException e1)
+ {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ }
}
});
loadVcf = new JMenuItem(
@@ -1413,7 +1496,7 @@ public class GAlignFrame extends JInternalFrame
listenToViewSelections_actionPerformed(e);
}
});
-
+
JMenu addSequenceMenu = new JMenu(
MessageManager.getString("label.add_sequences"));
JMenuItem addFromFile = new JMenuItem(
@@ -1559,7 +1642,7 @@ public class GAlignFrame extends JInternalFrame
hiddenMarkers_actionPerformed(e);
}
});
-
+
JMenuItem invertColSel = new JMenuItem(
MessageManager.getString("action.invert_column_selection"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_I,
@@ -1575,7 +1658,7 @@ public class GAlignFrame extends JInternalFrame
}
};
addMenuActionAndAccelerator(keyStroke, invertColSel, al);
-
+
showComplementMenuItem.setVisible(false);
showComplementMenuItem.addActionListener(new ActionListener()
{
@@ -1585,7 +1668,7 @@ public class GAlignFrame extends JInternalFrame
showComplement_actionPerformed(showComplementMenuItem.getState());
}
});
-
+
tabbedPane.addChangeListener(new javax.swing.event.ChangeListener()
{
@Override
@@ -1606,7 +1689,7 @@ public class GAlignFrame extends JInternalFrame
tabbedPane_mousePressed(e);
}
}
-
+
@Override
public void mouseReleased(MouseEvent e)
{
@@ -1624,7 +1707,7 @@ public class GAlignFrame extends JInternalFrame
tabbedPane_focusGained(e);
}
});
-
+
JMenuItem save = new JMenuItem(MessageManager.getString("action.save"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_S,
Platform.SHORTCUT_KEY_MASK, false);
@@ -1637,7 +1720,7 @@ public class GAlignFrame extends JInternalFrame
}
};
addMenuActionAndAccelerator(keyStroke, save, al);
-
+
reload.setEnabled(false);
reload.setText(MessageManager.getString("action.reload"));
reload.addActionListener(new ActionListener()
@@ -1648,7 +1731,7 @@ public class GAlignFrame extends JInternalFrame
reload_actionPerformed(e);
}
});
-
+
JMenuItem newView = new JMenuItem(
MessageManager.getString("action.new_view"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_T,
@@ -1662,11 +1745,11 @@ public class GAlignFrame extends JInternalFrame
}
};
addMenuActionAndAccelerator(keyStroke, newView, al);
-
+
tabbedPane.setToolTipText(""
+ MessageManager.getString("label.rename_tab_eXpand_reGroup")
+ " ");
-
+
formatMenu.setText(MessageManager.getString("action.format"));
JMenu selectMenu = new JMenu(MessageManager.getString("action.select"));
@@ -1680,7 +1763,7 @@ public class GAlignFrame extends JInternalFrame
idRightAlign_actionPerformed(e);
}
});
-
+
gatherViews.setEnabled(false);
gatherViews.setText(MessageManager.getString("action.gather_views"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_G, 0, false);
@@ -1693,7 +1776,7 @@ public class GAlignFrame extends JInternalFrame
}
};
addMenuActionAndAccelerator(keyStroke, gatherViews, al);
-
+
expandViews.setEnabled(false);
expandViews.setText(MessageManager.getString("action.expand_views"));
keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_X, 0, false);
@@ -1706,7 +1789,7 @@ public class GAlignFrame extends JInternalFrame
}
};
addMenuActionAndAccelerator(keyStroke, expandViews, al);
-
+
JMenuItem pageSetup = new JMenuItem(
MessageManager.getString("action.page_setup"));
pageSetup.addActionListener(new ActionListener()
@@ -1739,12 +1822,24 @@ public class GAlignFrame extends JInternalFrame
selectHighlightedColumns_actionPerformed(actionEvent);
}
};
+ JMenuItem Filter = new JMenuItem(
+ MessageManager.getString("action.select_highlighted_columns"));
+ selectHighlighted.setToolTipText(
+ MessageManager.getString("tooltip.select_highlighted_columns"));
+ al = new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent actionEvent)
+ {
+ selectHighlightedColumns_actionPerformed(actionEvent);
+ }
+ };
selectHighlighted.addActionListener(al);
JMenu tooltipSettingsMenu = new JMenu(
MessageManager.getString("label.sequence_id_tooltip"));
JMenu autoAnnMenu = new JMenu(
MessageManager.getString("label.autocalculated_annotation"));
-
+
JMenu exportImageMenu = new JMenu(
MessageManager.getString("label.export_image"));
JMenu fileMenu = new JMenu(MessageManager.getString("action.file"));
@@ -1756,11 +1851,12 @@ public class GAlignFrame extends JInternalFrame
alignFrameMenuBar.add(formatMenu);
alignFrameMenuBar.add(colourMenu);
alignFrameMenuBar.add(calculateMenu);
+ alignFrameMenuBar.add(webService);
if (!Platform.isJS())
{
- alignFrameMenuBar.add(webService);
+ alignFrameMenuBar.add(hmmerMenu);
}
-
+
fileMenu.add(fetchSequence);
fileMenu.add(addSequenceMenu);
fileMenu.add(reload);
@@ -1783,7 +1879,7 @@ public class GAlignFrame extends JInternalFrame
}
fileMenu.addSeparator();
fileMenu.add(closeMenuItem);
-
+
pasteMenu.add(pasteNew);
pasteMenu.add(pasteThis);
editMenu.add(undoMenuItem);
@@ -1805,7 +1901,10 @@ public class GAlignFrame extends JInternalFrame
// editMenu.add(justifyRightMenuItem);
// editMenu.addSeparator();
editMenu.add(padGapsMenuitem);
-
+ editMenu.addSeparator();
+ editMenu.add(filterByEValue);
+ editMenu.add(filterByScore);
+
showMenu.add(showAllColumns);
showMenu.add(showAllSeqs);
showMenu.add(showAllhidden);
@@ -1833,7 +1932,7 @@ public class GAlignFrame extends JInternalFrame
viewMenu.add(alignmentProperties);
viewMenu.addSeparator();
viewMenu.add(overviewMenuItem);
-
+
annotationsMenu.add(annotationPanelMenuItem);
annotationsMenu.addSeparator();
annotationsMenu.add(showAllAlAnnotations);
@@ -1860,6 +1959,8 @@ public class GAlignFrame extends JInternalFrame
sort.add(sortLengthMenuItem);
sort.add(sortGroupMenuItem);
sort.add(sortPairwiseMenuItem);
+ sort.add(sortEValueMenuItem);
+ sort.add(sortBitScoreMenuItem);
sort.add(sortByTreeMenu);
calculateMenu.add(sort);
calculateMenu.add(calculateTree);
@@ -1880,7 +1981,6 @@ public class GAlignFrame extends JInternalFrame
calculateMenu.addSeparator();
calculateMenu.add(runGroovy);
}
-
webServiceNoServices = new JMenuItem(
MessageManager.getString("label.no_services"));
webService.add(webServiceNoServices);
@@ -1901,7 +2001,7 @@ public class GAlignFrame extends JInternalFrame
this.getContentPane().add(statusPanel, java.awt.BorderLayout.SOUTH);
statusPanel.add(statusBar, null);
this.getContentPane().add(tabbedPane, java.awt.BorderLayout.CENTER);
-
+
formatMenu.add(font);
formatMenu.addSeparator();
formatMenu.add(wrapMenuItem);
@@ -1935,6 +2035,170 @@ public class GAlignFrame extends JInternalFrame
// selectMenu.add(listenToViewSelections);
}
+ /**
+ * Constructs the entries on the HMMER menu
+ */
+ protected void initHMMERMenu()
+ {
+ /*
+ * hmmbuild
+ */
+ JMenu hmmBuild = new JMenu(MessageManager.getString("label.hmmbuild"));
+ JMenuItem hmmBuildSettings = new JMenuItem(
+ MessageManager.getString("label.edit_settings_and_run"));
+ hmmBuildSettings.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ hmmBuild_actionPerformed(false);
+ }
+ });
+ JMenuItem hmmBuildRun = new JMenuItem(MessageManager.formatMessage(
+ "label.action_with_default_settings", "hmmbuild"));
+ hmmBuildRun.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ hmmBuild_actionPerformed(true);
+ }
+ });
+ hmmBuild.add(hmmBuildRun);
+ hmmBuild.add(hmmBuildSettings);
+
+ /*
+ * hmmalign
+ */
+ JMenu hmmAlign = new JMenu(MessageManager.getString("label.hmmalign"));
+ JMenuItem hmmAlignRun = new JMenuItem(MessageManager.formatMessage(
+ "label.action_with_default_settings", "hmmalign"));
+ hmmAlignRun.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ hmmAlign_actionPerformed(true);
+ }
+ });
+ JMenuItem hmmAlignSettings = new JMenuItem(
+ MessageManager.getString("label.edit_settings_and_run"));
+ hmmAlignSettings.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ hmmAlign_actionPerformed(false);
+ }
+ });
+ hmmAlign.add(hmmAlignRun);
+ hmmAlign.add(hmmAlignSettings);
+
+ /*
+ * hmmsearch
+ */
+ JMenu hmmSearch = new JMenu(
+ MessageManager.getString("label.hmmsearch"));
+ JMenuItem hmmSearchSettings = new JMenuItem(
+ MessageManager.getString("label.edit_settings_and_run"));
+ hmmSearchSettings.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ hmmSearch_actionPerformed(false);
+ }
+ });
+ JMenuItem hmmSearchRun = new JMenuItem(MessageManager.formatMessage(
+ "label.action_with_default_settings", "hmmsearch"));
+ hmmSearchRun.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ hmmSearch_actionPerformed(true);
+ }
+ });
+ JMenuItem addDatabase = new JMenuItem(
+ MessageManager.getString("label.add_database"));
+ addDatabase.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ try
+ {
+ addDatabase_actionPerformed();
+ } catch (IOException e1)
+ {
+ e1.printStackTrace();
+ }
+ }
+ });
+ hmmSearch.add(hmmSearchRun);
+ hmmSearch.add(hmmSearchSettings);
+ // hmmSearch.add(addDatabase);
+
+ /*
+ * jackhmmer
+ */
+ JMenu jackhmmer = new JMenu(
+ MessageManager.getString("label.jackhmmer"));
+ JMenuItem jackhmmerSettings = new JMenuItem(
+ MessageManager.getString("label.edit_settings_and_run"));
+ jackhmmerSettings.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ jackhmmer_actionPerformed(false);
+ }
+ });
+ JMenuItem jackhmmerRun = new JMenuItem(MessageManager.formatMessage(
+ "label.action_with_default_settings", "jackhmmer"));
+ jackhmmerRun.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ jackhmmer_actionPerformed(true);
+ }
+
+ });
+ /*
+ JMenuItem addDatabase = new JMenuItem(
+ MessageManager.getString("label.add_database"));
+ addDatabase.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ try
+ {
+ addDatabase_actionPerformed();
+ } catch (IOException e1)
+ {
+ e1.printStackTrace();
+ }
+ }
+ });
+ */
+ jackhmmer.add(jackhmmerRun);
+ jackhmmer.add(jackhmmerSettings);
+ // hmmSearch.add(addDatabase);
+
+ /*
+ * top level menu
+ */
+ hmmerMenu.setText(MessageManager.getString("action.hmmer"));
+ hmmerMenu.setEnabled(HmmerCommand.isHmmerAvailable());
+ hmmerMenu.add(hmmBuild);
+ hmmerMenu.add(hmmAlign);
+ hmmerMenu.add(hmmSearch);
+ hmmerMenu.add(jackhmmer);
+
+ }
+
protected void enableSortMenuOptions()
{
}
@@ -2354,6 +2618,14 @@ public class GAlignFrame extends JInternalFrame
{
}
+ protected void sortEValueMenuItem_actionPerformed(ActionEvent e)
+ {
+ }
+
+ protected void sortBitScoreMenuItem_actionPerformed(ActionEvent e)
+ {
+ }
+
protected void removeRedundancyMenuItem_actionPerformed(ActionEvent e)
{
}
@@ -2415,10 +2687,12 @@ public class GAlignFrame extends JInternalFrame
}
protected void pasteNew_actionPerformed(ActionEvent e)
+ throws IOException, InterruptedException
{
}
protected void pasteThis_actionPerformed(ActionEvent e)
+ throws IOException, InterruptedException
{
}
@@ -2426,6 +2700,27 @@ public class GAlignFrame extends JInternalFrame
{
}
+ protected void hmmBuild_actionPerformed(boolean withDefaults)
+ {
+ }
+
+ protected void hmmSearch_actionPerformed(boolean withDefaults)
+ {
+ }
+
+ protected void jackhmmer_actionPerformed(boolean b)
+ {
+ }
+
+ protected void addDatabase_actionPerformed()
+ throws FileFormatException, IOException
+ {
+ }
+
+ protected void hmmAlign_actionPerformed(boolean withDefaults)
+ {
+ }
+
public void createPNG(java.io.File f)
{
}
@@ -2482,6 +2777,14 @@ public class GAlignFrame extends JInternalFrame
{
}
+ protected void filterByEValue_actionPerformed()
+ {
+ }
+
+ protected void filterByScore_actionPerformed()
+ {
+ }
+
protected void scaleRight_actionPerformed(ActionEvent e)
{
}
@@ -2541,6 +2844,7 @@ public class GAlignFrame extends JInternalFrame
}
public void associatedData_actionPerformed(ActionEvent e)
+ throws IOException, InterruptedException
{
}
diff --git a/src/jalview/jbgui/GPreferences.java b/src/jalview/jbgui/GPreferences.java
index 08fbea3..26c37d0 100755
--- a/src/jalview/jbgui/GPreferences.java
+++ b/src/jalview/jbgui/GPreferences.java
@@ -49,7 +49,6 @@ import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
-import java.awt.event.FocusEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
@@ -57,13 +56,16 @@ import java.awt.event.MouseEvent;
import java.util.Arrays;
import java.util.List;
+import javax.swing.AbstractButton;
import javax.swing.AbstractCellEditor;
import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
+import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
@@ -87,6 +89,8 @@ import javax.swing.event.ChangeListener;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
+import net.miginfocom.swing.MigLayout;
+
/**
* Base class for the Preferences panel.
*
@@ -161,10 +165,15 @@ public class GPreferences extends JPanel
protected JCheckBox showConsensLogo = new JCheckBox();
+ protected JCheckBox showInformationHistogram = new JCheckBox();
+
+ protected JCheckBox showHMMLogo = new JCheckBox();
+
protected JCheckBox showDbRefTooltip = new JCheckBox();
protected JCheckBox showNpTooltip = new JCheckBox();
+
/*
* Structure tab and components
*/
@@ -288,10 +297,29 @@ public class GPreferences extends JPanel
protected JCheckBox sortByTree = new JCheckBox();
/*
+ * hmmer tab and components
+ */
+ protected JPanel hmmerTab;
+
+ protected JCheckBox hmmrTrimTermini;
+
+ protected AbstractButton hmmerBackgroundUniprot;
+
+ protected AbstractButton hmmerBackgroundAlignment;
+
+ protected JTextField hmmerSequenceCount;
+
+ protected JTextField hmmerPath;
+
+ protected JTextField cygwinPath;
+
+ /*
* Web Services tab
*/
protected JPanel wsTab = new JPanel();
+ protected JPanel slivkaTab = new JPanel();
+
/*
* Backups tab components
* a lot of these are member variables instead of local variables only so that they
@@ -395,6 +423,8 @@ public class GPreferences extends JPanel
tabbedPane.add(initEditingTab(),
MessageManager.getString("label.editing"));
+ tabbedPane.add(initHMMERTab(), MessageManager.getString("label.hmmer"));
+
/*
* See WsPreferences for the real work of configuring this tab.
*/
@@ -402,11 +432,13 @@ public class GPreferences extends JPanel
{
wsTab.setLayout(new BorderLayout());
tabbedPane.add(wsTab, MessageManager.getString("label.web_services"));
+ slivkaTab.setLayout(new BorderLayout());
+ tabbedPane.add(slivkaTab, "Slivka Services");
}
/*
* Handler to validate a tab before leaving it - currently only for
- * Structure.
+ * Structure
*/
tabbedPane.addChangeListener(new ChangeListener()
{
@@ -460,7 +492,135 @@ public class GPreferences extends JPanel
}
/**
- * Initialises the Output tab
+ * Initialises the hmmer tabbed panel
+ *
+ * @return
+ */
+ private JPanel initHMMERTab()
+ {
+ hmmerTab = new JPanel();
+ hmmerTab.setLayout(new BoxLayout(hmmerTab, BoxLayout.Y_AXIS));
+ hmmerTab.setLayout(new MigLayout("flowy"));
+
+ /*
+ * path to hmmer binaries folder
+ */
+ JPanel installationPanel = new JPanel(new MigLayout("flowy"));
+ // new FlowLayout(FlowLayout.LEFT));
+ JvSwingUtils.createTitledBorder(installationPanel,
+ MessageManager.getString("label.installation"), true);
+ hmmerTab.add(installationPanel);
+ JLabel hmmerLocation = new JLabel(
+ MessageManager.getString("label.hmmer_location"));
+ hmmerLocation.setFont(LABEL_FONT);
+ final int pathFieldLength = 40;
+ hmmerPath = new JTextField(pathFieldLength);
+ hmmerPath.addMouseListener(new MouseAdapter()
+ {
+ @Override
+ public void mouseClicked(MouseEvent e)
+ {
+ if (e.getClickCount() == 2)
+ {
+ String chosen = openFileChooser(true);
+ if (chosen != null)
+ {
+ hmmerPath.setText(chosen);
+ validateHmmerPath();
+ }
+ }
+ }
+ });
+ installationPanel.add(hmmerLocation);
+ installationPanel.add(hmmerPath);
+
+ /*
+ * path to Cygwin binaries folder (for Windows)
+ */
+ if (Platform.isWindowsAndNotJS())
+ {
+ JLabel cygwinLocation = new JLabel(
+ MessageManager.getString("label.cygwin_location"));
+ cygwinLocation.setFont(LABEL_FONT);
+ cygwinPath = new JTextField(pathFieldLength);
+ cygwinPath.addMouseListener(new MouseAdapter()
+ {
+ @Override
+ public void mouseClicked(MouseEvent e)
+ {
+ if (e.getClickCount() == 2)
+ {
+ String chosen = openFileChooser(true);
+ if (chosen != null)
+ {
+ cygwinPath.setText(chosen);
+ validateCygwinPath();
+ }
+ }
+ }
+ });
+ installationPanel.add(cygwinLocation);
+ installationPanel.add(cygwinPath);
+ }
+
+ /*
+ * preferences for hmmalign
+ */
+ JPanel alignOptionsPanel = new JPanel(new MigLayout());
+ // new FlowLayout(FlowLayout.LEFT));
+ JvSwingUtils.createTitledBorder(alignOptionsPanel,
+ MessageManager.getString("label.hmmalign_options"), true);
+ hmmerTab.add(alignOptionsPanel);
+ hmmrTrimTermini = new JCheckBox();
+ hmmrTrimTermini.setFont(LABEL_FONT);
+ hmmrTrimTermini.setText(MessageManager.getString("label.trim_termini"));
+ alignOptionsPanel.add(hmmrTrimTermini);
+
+ /*
+ * preferences for hmmsearch
+ */
+ JPanel searchOptions = new JPanel(new MigLayout());
+ // FlowLayout(FlowLayout.LEFT));
+ JvSwingUtils.createTitledBorder(searchOptions,
+ MessageManager.getString("label.hmmsearch_options"), true);
+ hmmerTab.add(searchOptions);
+ JLabel sequencesToKeep = new JLabel(
+ MessageManager.getString("label.no_of_sequences"));
+ sequencesToKeep.setFont(LABEL_FONT);
+ searchOptions.add(sequencesToKeep);
+ hmmerSequenceCount = new JTextField(5);
+ searchOptions.add(hmmerSequenceCount);
+
+ /*
+ * preferences for Information Content annotation
+ */
+ // JPanel dummy = new JPanel(new FlowLayout(FlowLayout.LEFT));
+ JPanel annotationOptions = new JPanel(new MigLayout("left"));
+ JvSwingUtils.createTitledBorder(annotationOptions,
+ MessageManager.getString("label.information_annotation"), true);
+ // dummy.add(annotationOptions);
+ hmmerTab.add(annotationOptions);
+ ButtonGroup backgroundOptions = new ButtonGroup();
+ hmmerBackgroundUniprot = new JRadioButton(
+ MessageManager.getString("label.freq_uniprot"));
+ hmmerBackgroundUniprot.setFont(LABEL_FONT);
+ hmmerBackgroundAlignment = new JRadioButton(
+ MessageManager.getString("label.freq_alignment"));
+ hmmerBackgroundAlignment.setFont(LABEL_FONT);
+ backgroundOptions.add(hmmerBackgroundUniprot);
+ backgroundOptions.add(hmmerBackgroundAlignment);
+ backgroundOptions.setSelected(hmmerBackgroundUniprot.getModel(), true);
+ // disable buttons for now as annotation only uses Uniprot background
+ hmmerBackgroundAlignment.setEnabled(false);
+ hmmerBackgroundUniprot.setEnabled(false);
+ annotationOptions.add(hmmerBackgroundUniprot, "wrap");
+ annotationOptions.add(hmmerBackgroundAlignment);
+
+ return hmmerTab;
+ }
+
+ /**
+ * Initialises the Output tabbed panel.
*
* @return
*/
@@ -1044,7 +1204,7 @@ public class GPreferences extends JPanel
protColourLabel.setHorizontalAlignment(SwingConstants.LEFT);
protColourLabel.setText(
MessageManager.getString("label.prot_alignment_colour") + " ");
- JvSwingUtils.addtoLayout(coloursTab,
+ GPreferences.addtoLayout(coloursTab,
MessageManager
.getString("label.default_colour_scheme_for_alignment"),
protColourLabel, protColour);
@@ -1056,7 +1216,7 @@ public class GPreferences extends JPanel
nucColourLabel.setHorizontalAlignment(SwingConstants.LEFT);
nucColourLabel.setText(
MessageManager.getString("label.nuc_alignment_colour") + " ");
- JvSwingUtils.addtoLayout(coloursTab,
+ GPreferences.addtoLayout(coloursTab,
MessageManager
.getString("label.default_colour_scheme_for_alignment"),
nucColourLabel, nucColour);
@@ -1065,11 +1225,11 @@ public class GPreferences extends JPanel
annotationShding.setBorder(new TitledBorder(
MessageManager.getString("label.annotation_shading_default")));
annotationShding.setLayout(new GridLayout(1, 2));
- JvSwingUtils.addtoLayout(annotationShding,
+ GPreferences.addtoLayout(annotationShding,
MessageManager.getString(
"label.default_minimum_colour_annotation_shading"),
mincolourLabel, minColour);
- JvSwingUtils.addtoLayout(annotationShding,
+ GPreferences.addtoLayout(annotationShding,
MessageManager.getString(
"label.default_maximum_colour_annotation_shading"),
maxcolourLabel, maxColour);
@@ -1323,7 +1483,7 @@ public class GPreferences extends JPanel
{
if (e.getClickCount() == 2)
{
- String chosen = openFileChooser();
+ String chosen = openFileChooser(false);
if (chosen != null)
{
chimeraPath.setText(chosen);
@@ -1389,10 +1549,14 @@ public class GPreferences extends JPanel
*
* @return
*/
- protected String openFileChooser()
+ protected String openFileChooser(boolean forFolder)
{
String choice = null;
JFileChooser chooser = new JFileChooser();
+ if (forFolder)
+ {
+ chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+ }
// chooser.setFileView(new JalviewFileView());
chooser.setDialogTitle(
@@ -1408,21 +1572,6 @@ public class GPreferences extends JPanel
return choice;
}
- /**
- * Validate the structure tab preferences; if invalid, set focus on this tab.
- *
- * @param e
- */
- protected boolean validateStructure(FocusEvent e)
- {
- if (!validateStructure())
- {
- e.getComponent().requestFocusInWindow();
- return false;
- }
- return true;
- }
-
protected boolean validateStructure()
{
return false;
@@ -2895,5 +3044,41 @@ public class GPreferences extends JPanel
}
}
+
+ protected void validateHmmerPath()
+ {
+ }
+
+ protected void validateCygwinPath()
+ {
+ }
+
+ /**
+ * A helper method to add a panel containing a label and a component to a
+ * panel
+ *
+ * @param panel
+ * @param tooltip
+ * @param label
+ * @param valBox
+ */
+ protected static void addtoLayout(JPanel panel, String tooltip,
+ JComponent label, JComponent valBox)
+ {
+ JPanel laypanel = new JPanel(new GridLayout(1, 2));
+ JPanel labPanel = new JPanel(new BorderLayout());
+ JPanel valPanel = new JPanel();
+ labPanel.setBounds(new Rectangle(7, 7, 158, 23));
+ valPanel.setBounds(new Rectangle(172, 7, 270, 23));
+ labPanel.add(label, BorderLayout.WEST);
+ valPanel.add(valBox);
+ laypanel.add(labPanel);
+ laypanel.add(valPanel);
+ valPanel.setToolTipText(tooltip);
+ labPanel.setToolTipText(tooltip);
+ valBox.setToolTipText(tooltip);
+ panel.add(laypanel);
+ panel.validate();
+ }
}
diff --git a/src/jalview/jbgui/GRestInputParamEditDialog.java b/src/jalview/jbgui/GRestInputParamEditDialog.java
index 5170a6c..14ebbc0 100644
--- a/src/jalview/jbgui/GRestInputParamEditDialog.java
+++ b/src/jalview/jbgui/GRestInputParamEditDialog.java
@@ -103,7 +103,7 @@ public class GRestInputParamEditDialog
optionsPanel = new JPanel(new MigLayout("", "[fill]", "[fill]"));
JScrollPane optionView = new JScrollPane();
optionView.setViewportView(options);
- JvSwingUtils.mgAddtoLayout(dpane,
+ JvSwingUtils.addtoLayout(dpane,
MessageManager.getString("label.input_parameter_name"),
new JLabel(MessageManager.getString("label.name")), tok,
"grow,spanx 3,wrap");
diff --git a/src/jalview/jbgui/GRestServiceEditorPane.java b/src/jalview/jbgui/GRestServiceEditorPane.java
index a4dca4b..db68757 100644
--- a/src/jalview/jbgui/GRestServiceEditorPane.java
+++ b/src/jalview/jbgui/GRestServiceEditorPane.java
@@ -109,20 +109,20 @@ public class GRestServiceEditorPane extends JPanel
cpanel = details;
name = new JTextArea(1, 12);
- JvSwingUtils.mgAddtoLayout(cpanel,
+ JvSwingUtils.addtoLayout(cpanel,
MessageManager
.getString("label.short_descriptive_name_for_service"),
new JLabel(MessageManager.getString("label.name")), name,
"wrap");
action = new JComboBox();
- JvSwingUtils.mgAddtoLayout(cpanel,
+ JvSwingUtils.addtoLayout(cpanel,
MessageManager.getString("label.function_service_performs"),
new JLabel(MessageManager.getString("label.service_action")),
action, "wrap");
descr = new JTextArea(4, 60);
descrVp = new JScrollPane();
descrVp.setViewportView(descr);
- JvSwingUtils.mgAddtoLayout(cpanel,
+ JvSwingUtils.addtoLayout(cpanel,
MessageManager.getString("label.brief_description_service"),
new JLabel(MessageManager.getString("label.description")),
descrVp, "wrap");
@@ -130,7 +130,7 @@ public class GRestServiceEditorPane extends JPanel
url = new JTextArea(2, 60);
urlVp = new JScrollPane();
urlVp.setViewportView(url);
- JvSwingUtils.mgAddtoLayout(cpanel,
+ JvSwingUtils.addtoLayout(cpanel,
MessageManager.getString("label.url_post_data_service"),
new JLabel(MessageManager.getString("label.post_url")), urlVp,
"wrap");
@@ -138,7 +138,7 @@ public class GRestServiceEditorPane extends JPanel
urlsuff = new JTextArea();
urlsuff.setColumns(60);
- JvSwingUtils.mgAddtoLayout(cpanel,
+ JvSwingUtils.addtoLayout(cpanel,
MessageManager.getString("label.optional_suffix"),
new JLabel(MessageManager.getString("label.url_suffix")),
urlsuff, "wrap");
@@ -175,7 +175,7 @@ public class GRestServiceEditorPane extends JPanel
}
});
gapChar = new JComboBox();
- JvSwingUtils.mgAddtoLayout(cpanel,
+ JvSwingUtils.addtoLayout(cpanel,
MessageManager.getString("label.preferred_gap_character"),
new JLabel(
MessageManager.getString("label.gap_character") + ":"),
diff --git a/src/jalview/project/Jalview2XML.java b/src/jalview/project/Jalview2XML.java
index b4b5003..e88a4a1 100644
--- a/src/jalview/project/Jalview2XML.java
+++ b/src/jalview/project/Jalview2XML.java
@@ -42,6 +42,7 @@ import jalview.datamodel.AlignmentI;
import jalview.datamodel.DBRefEntry;
import jalview.datamodel.GeneLocus;
import jalview.datamodel.GraphLine;
+import jalview.datamodel.HiddenMarkovModel;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.Point;
import jalview.datamodel.RnaViewerModel;
@@ -74,6 +75,7 @@ import jalview.gui.TreePanel;
import jalview.io.BackupFiles;
import jalview.io.DataSourceType;
import jalview.io.FileFormat;
+import jalview.io.HMMFile;
import jalview.io.NewickFile;
import jalview.math.Matrix;
import jalview.math.MatrixI;
@@ -97,9 +99,9 @@ import jalview.viewmodel.ViewportRanges;
import jalview.viewmodel.seqfeatures.FeatureRendererModel;
import jalview.viewmodel.seqfeatures.FeatureRendererSettings;
import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
-import jalview.ws.jws2.Jws2Discoverer;
+import jalview.ws.api.ServiceWithParameters;
+import jalview.ws.jws2.PreferredServiceRegistry;
import jalview.ws.jws2.dm.AAConSettings;
-import jalview.ws.jws2.jabaws2.Jws2Instance;
import jalview.ws.params.ArgumentI;
import jalview.ws.params.AutoCalcSetting;
import jalview.ws.params.WsParamSetI;
@@ -226,6 +228,8 @@ public class Jalview2XML
private static final String RNA_PREFIX = "rna_";
+ private static final String HMMER_PREFIX = "hmmer_";
+
private static final String UTF_8 = "UTF-8";
/**
@@ -1105,6 +1109,9 @@ public class Jalview2XML
jseq.getFeatures().add(features);
}
+ /*
+ * save PDB entries for sequence
+ */
if (jdatasq.getAllPDBEntries() != null)
{
Enumeration en = jdatasq.getAllPDBEntries().elements();
@@ -1197,6 +1204,11 @@ public class Jalview2XML
saveRnaViewers(jout, jseq, jds, viewIds, ap, storeDS);
+ if (jds.hasHMMProfile())
+ {
+ saveHmmerProfile(jout, jseq, jds);
+ }
+
// jms.addJSeq(jseq);
object.getJSeq().add(jseq);
}
@@ -1745,7 +1757,39 @@ public class Jalview2XML
}
return object;
}
+ /**
+ * Saves the HMMER profile associated with the sequence as a file in the jar,
+ * in HMMER format, and saves the name of the file as a child element of the
+ * XML sequence element
+ *
+ * @param jout
+ * @param xmlSeq
+ * @param seq
+ */
+ protected void saveHmmerProfile(JarOutputStream jout, JSeq xmlSeq,
+ SequenceI seq)
+ {
+ HiddenMarkovModel profile = seq.getHMM();
+ if (profile == null)
+ {
+ warn("Want to save HMM profile for " + seq.getName()
+ + " but none found");
+ return;
+ }
+ HMMFile hmmFile = new HMMFile(profile);
+ String hmmAsString = hmmFile.print();
+ String jarEntryName = HMMER_PREFIX + nextCounter();
+ try
+ {
+ writeJarEntry(jout, jarEntryName, hmmAsString.getBytes());
+ xmlSeq.setHmmerProfile(jarEntryName);
+ } catch (IOException e)
+ {
+ warn("Error saving HMM profile: " + e.getMessage());
+ }
+ }
+
/**
* Writes PCA viewer attributes and computed values to an XML model object and
* adds it to the JalviewModel. Any exceptions are reported by logging.
@@ -2140,9 +2184,9 @@ public class Jalview2XML
}
else if (!matchedFile.equals(pdbentry.getFile()))
{
- Cache.log.warn(
- "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
- + pdbentry.getFile());
+ Cache.log.warn(
+ "Probably lost some PDB-Sequence mappings for this structure file (which apparently has same PDB Entry code): "
+ + pdbentry.getFile());
}
// record the
// file so we
@@ -2424,7 +2468,7 @@ public class Jalview2XML
if (calcIdParam.getVersion().equals("1.0"))
{
final String[] calcIds = calcIdParam.getServiceURL().toArray(new String[0]);
- Jws2Instance service = Jws2Discoverer.getInstance()
+ ServiceWithParameters service = PreferredServiceRegistry.getRegistry()
.getPreferredServiceFor(calcIds);
if (service != null)
{
@@ -2457,7 +2501,7 @@ public class Jalview2XML
argList = parmSet.getArguments();
parmSet = null;
}
- AAConSettings settings = new AAConSettings(
+ AutoCalcSetting settings = new AAConSettings(
calcIdParam.isAutoUpdate(), service, parmSet, argList);
av.setCalcIdSettingsFor(calcIdParam.getCalcId(), settings,
calcIdParam.isNeedsUpdate());
@@ -2465,7 +2509,7 @@ public class Jalview2XML
}
else
{
- warn("Cannot resolve a service for the parameters used in this project. Try configuring a JABAWS server.");
+ warn("Cannot resolve a service for the parameters used in this project. Try configuring a server in the Web Services preferences tab.");
return false;
}
}
@@ -3687,6 +3731,16 @@ public class Jalview2XML
}
}
+ /*
+ * load any HMMER profile
+ */
+ // TODO fix this
+
+ String hmmJarFile = jseqs.get(i).getHmmerProfile();
+ if (hmmJarFile != null && jprovider != null)
+ {
+ loadHmmerProfile(jprovider, hmmJarFile, al.getSequenceAt(i));
+ }
}
} // end !multipleview
@@ -4211,6 +4265,31 @@ public class Jalview2XML
}
/**
+ * Loads a HMMER profile from a file stored in the project, and associates it
+ * with the specified sequence
+ *
+ * @param jprovider
+ * @param hmmJarFile
+ * @param seq
+ */
+ protected void loadHmmerProfile(jarInputStreamProvider jprovider,
+ String hmmJarFile, SequenceI seq)
+ {
+ try
+ {
+ String hmmFile = copyJarEntry(jprovider, hmmJarFile, "hmm", null);
+ HMMFile parser = new HMMFile(hmmFile, DataSourceType.FILE);
+ HiddenMarkovModel hmmModel = parser.getHMM();
+ hmmModel = new HiddenMarkovModel(hmmModel, seq);
+ seq.setHMM(hmmModel);
+ } catch (IOException e)
+ {
+ warn("Error loading HMM profile for " + seq.getName() + ": "
+ + e.getMessage());
+ }
+ }
+
+ /**
* Instantiate and link any saved RNA (Varna) viewers. The state of the Varna
* panel is restored from separate jar entries, two (gapped and trimmed) per
* sequence and secondary structure.
@@ -5619,10 +5698,10 @@ public class Jalview2XML
String id = object.getViewport().get(0).getSequenceSetId();
if (skipList.containsKey(id))
{
- if (Cache.log != null && Cache.log.isDebugEnabled())
- {
- Cache.log.debug("Skipping seuqence set id " + id);
- }
+ if (Cache.log != null && Cache.log.isDebugEnabled())
+ {
+ Cache.log.debug("Skipping seuqence set id " + id);
+ }
return true;
}
return false;
@@ -6096,7 +6175,6 @@ public class Jalview2XML
jmap.setTo(djs);
incompleteSeqs.put(sqid, djs);
seqRefIds.put(sqid, djs);
-
}
jalview.bin.Cache.log.debug("about to recurse on addDBRefs.");
addDBRefs(djs, ms);
@@ -6282,7 +6360,7 @@ public class Jalview2XML
}
else
{
- Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
+ Cache.log.debug("Ignoring " + jvobj.getClass() + " (ID = " + id);
}
}
}
@@ -6758,7 +6836,7 @@ public class Jalview2XML
maxcol = new Color(Integer.parseInt(colourModel.getRGB(), 16));
} catch (Exception e)
{
- Cache.log.warn("Couldn't parse out graduated feature color.", e);
+ Cache.log.warn("Couldn't parse out graduated feature color.", e);
}
NoValueColour noCol = colourModel.getNoValueColour();
diff --git a/src/jalview/renderer/AnnotationRenderer.java b/src/jalview/renderer/AnnotationRenderer.java
index c61606e..70991c6 100644
--- a/src/jalview/renderer/AnnotationRenderer.java
+++ b/src/jalview/renderer/AnnotationRenderer.java
@@ -29,12 +29,14 @@ import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.Annotation;
import jalview.datamodel.ColumnSelection;
import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.HiddenMarkovModel;
import jalview.datamodel.ProfilesI;
import jalview.schemes.ColourSchemeI;
import jalview.schemes.NucleotideColourScheme;
import jalview.schemes.ResidueProperties;
import jalview.schemes.ZappoColourScheme;
import jalview.util.Platform;
+import jalview.workers.InformationThread;
import java.awt.BasicStroke;
import java.awt.Color;
@@ -69,8 +71,14 @@ public class AnnotationRenderer
private final boolean USE_FILL_ROUND_RECT = Platform.isAMacAndNotJS();
- boolean av_renderHistogram = true, av_renderProfile = true,
- av_normaliseProfile = false;
+ // todo remove these flags, read from group/viewport where needed
+ boolean av_renderHistogram = true;
+
+ boolean av_renderProfile = true;
+
+ boolean av_normaliseProfile = false;
+
+ boolean av_infoHeight = false;
ResidueShaderI profcolour = null;
@@ -86,6 +94,8 @@ public class AnnotationRenderer
private boolean av_ignoreGapsConsensus;
+ private boolean av_ignoreBelowBackground;
+
/**
* attributes set from AwtRenderPanelI
*/
@@ -344,8 +354,12 @@ public class AnnotationRenderer
complementConsensus = av.getComplementConsensusHash();
hStrucConsensus = av.getRnaStructureConsensusHash();
av_ignoreGapsConsensus = av.isIgnoreGapsConsensus();
+ av_ignoreBelowBackground = av.isIgnoreBelowBackground();
+ av_infoHeight = av.isInfoLetterHeight();
}
+
+
/**
* Returns profile data; the first element is the profile type, the second is
* the number of distinct values, the third the total count, and the remainder
@@ -361,17 +375,25 @@ public class AnnotationRenderer
// properties/rendering attributes as a global 'alignment group' which holds
// all vis settings for the alignment as a whole rather than a subset
//
- if (aa.autoCalculated && (aa.label.startsWith("Consensus")
- || aa.label.startsWith("cDNA Consensus")))
+ if (InformationThread.HMM_CALC_ID.equals(aa.getCalcId()))
+ {
+ HiddenMarkovModel hmm = aa.sequenceRef.getHMM();
+ return AAFrequency.extractHMMProfile(hmm, column,
+ av_ignoreBelowBackground, av_infoHeight); // TODO check if this follows standard
+ // pipeline
+ }
+ if (aa.autoCalculated
+ && (aa.label.startsWith("Consensus") || aa.label
+ .startsWith("cDNA Consensus")))
{
boolean forComplement = aa.label.startsWith("cDNA Consensus");
- if (aa.groupRef != null && aa.groupRef.consensusData != null
+ if (aa.groupRef != null && aa.groupRef.getConsensusData() != null
&& aa.groupRef.isShowSequenceLogo())
{
// TODO? group consensus for cDNA complement
return AAFrequency.extractProfile(
- aa.groupRef.consensusData.get(column),
- aa.groupRef.getIgnoreGapsConsensus());
+ aa.groupRef.getConsensusData().get(column),
+ aa.groupRef.getIgnoreGapsConsensus());
}
// TODO extend annotation row to enable dynamic and static profile data to
// be stored
@@ -500,6 +522,28 @@ public class AnnotationRenderer
renderProfile = av_renderProfile;
normaliseProfile = av_normaliseProfile;
}
+ else if (InformationThread.HMM_CALC_ID.equals(row.getCalcId()))
+ {
+ if (row.groupRef != null)
+ {
+ renderHistogram = row.groupRef.isShowInformationHistogram();
+ renderProfile = row.groupRef.isShowHMMSequenceLogo();
+ normaliseProfile = row.groupRef.isNormaliseHMMSequenceLogo();
+ }
+ else
+ {
+ renderHistogram = av.isShowInformationHistogram();
+ renderProfile = av.isShowHMMSequenceLogo();
+ normaliseProfile = av.isNormaliseHMMSequenceLogo();
+ }
+ }
+ else if (row == consensusAnnot || row == structConsensusAnnot
+ || row == complementConsensusAnnot)
+ {
+ renderHistogram = av_renderHistogram;
+ renderProfile = av_renderProfile;
+ normaliseProfile = av_normaliseProfile;
+ }
Annotation[] row_annotations = row.annotations;
if (!row.visible)
diff --git a/src/jalview/renderer/ResidueShaderI.java b/src/jalview/renderer/ResidueShaderI.java
index 4d97171..7e67598 100644
--- a/src/jalview/renderer/ResidueShaderI.java
+++ b/src/jalview/renderer/ResidueShaderI.java
@@ -5,16 +5,16 @@
* 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
+ * modify it under the terms of the GNU General 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.
+ * PURPOSE. See the GNU General License for more details.
*
- * You should have received a copy of the GNU General Public License
+ * You should have received a copy of the GNU General License
* along with Jalview. If not, see .
* The Jalview Authors are detailed in the 'AUTHORS' file.
*/
@@ -32,16 +32,15 @@ import java.util.Map;
public interface ResidueShaderI
{
+ void setConsensus(ProfilesI cons);
- public abstract void setConsensus(ProfilesI cons);
+ boolean conservationApplied();
- public abstract boolean conservationApplied();
+ void setConservationApplied(boolean conservationApplied);
- public abstract void setConservationApplied(boolean conservationApplied);
+ void setConservation(Conservation cons);
- public abstract void setConservation(Conservation cons);
-
- public abstract void alignmentChanged(AnnotatedCollectionI alignment,
+ void alignmentChanged(AnnotatedCollectionI alignment,
Map hiddenReps);
/**
@@ -51,19 +50,19 @@ public interface ResidueShaderI
* @param consensusThreshold
* @param ignoreGaps
*/
- public abstract void setThreshold(int consensusThreshold,
+ void setThreshold(int consensusThreshold,
boolean ignoreGaps);
- public abstract void setConservationInc(int i);
+ void setConservationInc(int i);
- public abstract int getConservationInc();
+ int getConservationInc();
/**
* Get the percentage threshold for this colour scheme
*
* @return Returns the percentage threshold
*/
- public abstract int getThreshold();
+ int getThreshold();
/**
* Returns the possibly context dependent colour for the given symbol at the
@@ -75,11 +74,11 @@ public interface ResidueShaderI
* @param seq
* @return
*/
- public abstract Color findColour(char symbol, int position,
+ Color findColour(char symbol, int position,
SequenceI seq);
- public abstract ColourSchemeI getColourScheme();
+ ColourSchemeI getColourScheme();
- public abstract void setColourScheme(ColourSchemeI cs);
+ void setColourScheme(ColourSchemeI cs);
}
\ No newline at end of file
diff --git a/src/jalview/schemes/AnnotationColourGradient.java b/src/jalview/schemes/AnnotationColourGradient.java
index 75a07b9..a84ea52 100755
--- a/src/jalview/schemes/AnnotationColourGradient.java
+++ b/src/jalview/schemes/AnnotationColourGradient.java
@@ -37,6 +37,16 @@ import java.util.Map;
public class AnnotationColourGradient extends FollowerColourScheme
{
+ /**
+ * map positional scores to transparency rather than colour
+ */
+ boolean positionToTransparency = true;
+
+ /**
+ * compute shade based on annotation row score
+ */
+ boolean perLineScore = true;
+
public static final int NO_THRESHOLD = -1;
public static final int BELOW_THRESHOLD = 0;
@@ -94,6 +104,8 @@ public class AnnotationColourGradient extends FollowerColourScheme
acg.predefinedColours = predefinedColours;
acg.seqAssociated = seqAssociated;
acg.noGradient = noGradient;
+ acg.positionToTransparency = positionToTransparency;
+ acg.perLineScore = perLineScore;
return acg;
}
@@ -192,14 +204,16 @@ public class AnnotationColourGradient extends FollowerColourScheme
AnnotatedCollectionI alcontext = alignment instanceof AlignmentI
? alignment
: alignment.getContext();
- boolean f = true, rna = false;
- for (AlignmentAnnotation alan : alcontext
- .findAnnotation(annotation.getCalcId()))
+ boolean f = true, sf = true, rna = false;
+ long plcount = 0, ancount = 0;
+ for (AlignmentAnnotation alan : alcontext.findAnnotation(annotation
+ .getCalcId()))
{
if (alan.sequenceRef != null
&& (alan.label != null && annotation != null
&& alan.label.equals(annotation.label)))
{
+ ancount++;
if (!rna && alan.isRNA())
{
rna = true;
@@ -214,8 +228,30 @@ public class AnnotationColourGradient extends FollowerColourScheme
aamin = alan.graphMin;
}
f = false;
+ if (alan.score == alan.score)
+ {
+ if (sf || alan.score < plmin)
+ {
+ plmin = alan.score;
+ }
+ if (sf || alan.score > plmax)
+ {
+ plmax = alan.score;
+ }
+ sf = false;
+ plcount++;
+ }
}
}
+ if (plcount > 0 && plcount == ancount)
+ {
+ perLineScore = plcount == ancount;
+ aamax=plmax;
+ }
+ else
+ {
+ perLineScore = false;
+ }
if (rna)
{
ColourSchemeProperty.initRnaHelicesShading(1 + (int) aamax);
@@ -223,7 +259,15 @@ public class AnnotationColourGradient extends FollowerColourScheme
}
}
- float aamin = 0f, aamax = 0f;
+ /**
+ * positional annotation max/min
+ */
+ double aamin = 0.0, aamax = 0.0;
+
+ /**
+ * per line score max/min
+ */
+ double plmin = Double.NaN, plmax = Double.NaN;
public AlignmentAnnotation getAnnotation()
{
@@ -439,11 +483,25 @@ public class AnnotationColourGradient extends FollowerColourScheme
}
}
- int dr = (int) (redRange * range + redMin);
- int dg = (int) (greenRange * range + greenMin);
- int db = (int) (blueRange * range + blueMin);
-
- return new Color(dr, dg, db);
+ // midtr sets the ceiling for bleaching out the shading
+ int trans = 0, midtr = 239;
+ if (perLineScore)
+ {
+ trans = (int) ((1f - range) * midtr);
+ range = (float) ((ann.score - plmin) / (plmax - aamin));
+ }
+ int dr = (int) (redRange * range + redMin),
+ dg = (int) (greenRange * range + greenMin),
+ db = (int) (blueRange * range + blueMin);
+ if (ann.score == ann.score && positionToTransparency)
+ {
+ return new Color(Math.min(dr + trans, midtr), Math.min(dg
+ + trans, midtr), Math.min(db + trans, midtr));
+ }
+ else
+ {
+ return new Color(dr, dg, db);
+ }
}
public boolean isPredefinedColours()
diff --git a/src/jalview/schemes/FeatureSettingsAdapter.java b/src/jalview/schemes/FeatureSettingsAdapter.java
index b15e4cf..3d82f9b 100644
--- a/src/jalview/schemes/FeatureSettingsAdapter.java
+++ b/src/jalview/schemes/FeatureSettingsAdapter.java
@@ -22,6 +22,7 @@ package jalview.schemes;
import jalview.api.FeatureColourI;
import jalview.api.FeatureSettingsModelI;
+import jalview.datamodel.features.FeatureMatcherSetI;
/**
* An adapter class that may be extended to instantiate feature colour schemes
@@ -65,4 +66,10 @@ public class FeatureSettingsAdapter implements FeatureSettingsModelI
return false;
}
+ @Override
+ public FeatureMatcherSetI getFeatureFilters(String type)
+ {
+ return null;
+ }
+
}
diff --git a/src/jalview/schemes/HMMMatchScoreColourScheme.java b/src/jalview/schemes/HMMMatchScoreColourScheme.java
new file mode 100644
index 0000000..96eb26a
--- /dev/null
+++ b/src/jalview/schemes/HMMMatchScoreColourScheme.java
@@ -0,0 +1,369 @@
+package jalview.schemes;
+
+import jalview.api.AlignViewportI;
+import jalview.datamodel.AnnotatedCollectionI;
+import jalview.datamodel.HiddenMarkovModel;
+import jalview.datamodel.SequenceI;
+import jalview.util.ColorUtils;
+import jalview.util.Comparison;
+
+import java.awt.Color;
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+
+
+public class HMMMatchScoreColourScheme extends ResidueColourScheme
+{
+
+ private Map>> probabilities;
+
+ private List ranges;
+
+ private static double binSize;
+
+ public class MatchProbReader
+ {
+ private BufferedReader reader;
+
+ MatchProbReader() throws FileNotFoundException
+ {
+ reader = new BufferedReader(
+ new FileReader("resources/ProbabilityOfMatch"));
+ }
+
+ /*
+ public Map> getProbabilities() throws IOException
+ {
+ Map> probabilities = new HashMap<>();
+
+ String[] alphabet = reader.readLine().split("\\,");
+ for (int i = 1; i < alphabet.length - 1; i++)
+ {
+ probabilities.put(alphabet[i].replaceAll("\\ ", "").charAt(0),
+ new HashMap<>());
+ }
+
+ String line = reader.readLine();
+ while(line != null)
+ {
+ String[] contents = line.split("\\,");
+
+ for(int i = 1; i < contents.length; i++)
+ {
+ probabilities.get(alphabet[i].replaceAll("\\ ", "").charAt(0))
+ .put(contents[0], Double
+ .valueOf(contents[i].replaceAll("\\ ", "")));
+ }
+ line = reader.readLine();
+
+ }
+ reader.close();
+ return probabilities;
+ }
+ */
+
+ public Map>> getProbabilities()
+ throws IOException
+ {
+
+ Map>> probabilities = new HashMap<>();
+
+ ranges = new ArrayList<>();
+ ranges.add(0);
+
+ binSize = Double.valueOf((reader.readLine().replaceAll("\\ ", "")));
+ String line = reader.readLine();
+ char c = line.charAt(0);
+
+ while (line != null)
+ {
+ line = reader.readLine();
+ while (line != null && line.split("\\,").length != 1)
+ {
+ String[] llrs = line.split("\\,");
+ String[] counts = reader.readLine().split("\\,");
+ int range = Integer.valueOf(llrs[0]);
+
+ if (!ranges.contains(range))
+ {
+ ranges.add(range);
+ }
+ if (!probabilities.containsKey(c))
+ {
+ probabilities.put(c, new HashMap<>());
+ }
+ probabilities.get(c).put(range, new HashMap<>());
+
+ for (int i = 1; i < llrs.length; i++)
+ {
+ probabilities.get(c).get(range).put(
+ llrs[i].replaceAll("\\ ", ""),
+ Double.valueOf(counts[i].replaceAll("\\ ", "")));
+ }
+
+ line = reader.readLine();
+ }
+ if (line != null)
+ {
+ c = line.charAt(0);
+ }
+ }
+
+ return probabilities;
+ }
+
+ }
+
+ private static final Color INSERTION_COLOUR = Color.white;
+
+ /*
+ * the aligned HMM consensus sequence to use as reference for colouring
+ */
+ private SequenceI hmmSeq;
+
+ private HiddenMarkovModel hmm;
+
+ private Map frequencies;
+
+ /**
+ * Constructor given a list of Hidden Markov Model consensus sequences. The
+ * first sequence provides the HMM profile from which we can read the emission
+ * probabilities that determine the colour.
+ *
+ * @param hmmSeqs
+ * @throws IOException
+ */
+ public HMMMatchScoreColourScheme(List hmmSeqs)
+ {
+ hmmSeq = hmmSeqs.isEmpty() ? null : hmmSeqs.get(0);
+ hmm = hmmSeq == null ? null : hmmSeq.getHMM();
+
+ try
+ {
+ MatchProbReader probabilityReader = new MatchProbReader();
+ probabilities = probabilityReader.getProbabilities();
+ } catch (IOException e)
+ {
+ System.out.println(e.getStackTrace());
+ }
+ }
+
+ /**
+ * Default constructor (required by ColourSchemes.loadColourSchemes)
+ */
+ public HMMMatchScoreColourScheme()
+ {
+ }
+
+ @Override
+ public Color findColour(char symbol, int column, SequenceI seq,
+ String consensusResidue, float pid)
+ {
+ if (seq == null)
+ {
+ return null;
+ }
+ return findColour(symbol, column, seq.gapMap().length);
+ }
+
+ // TODO change documentation
+ /**
+ * Returns the colour at a particular symbol at a column in the alignment:
+ *
+ * white for a gap
+ * red for an insertion
+ * orange for negative information content
+ * white to blue for increasing information content
+ *
+ *
+ * @param symbol
+ * @param column
+ * @return
+ */
+ private Color findColour(char symbol, int column, int length)
+ {
+ if (getHmm() == null || Comparison.isGap(symbol))
+ {
+ return Color.white;
+ }
+ if (Comparison.isGap(hmmSeq.getCharAt(column)))
+ {
+ return INSERTION_COLOUR;
+ }
+ if (Character.isLowerCase(symbol))
+ {
+ symbol = Character.toUpperCase(symbol);
+ }
+
+ double prob = 0;
+ if (hmm.getBackgroundFrequencies().containsKey(symbol))
+ {
+ int lengthBin = getLengthBin(length);
+
+ double llr = Math
+ .log(getHmm().getMatchEmissionProbability(column, symbol)
+ / hmm.getBackgroundFrequencies().get(symbol));
+
+ if (!probabilities.containsKey(symbol)
+ || !probabilities.get(symbol).get(lengthBin)
+ .containsKey(format(llr)))
+ {
+ return new Color(140, 140, 140);
+ }
+
+
+ prob = probabilities.get(symbol).get(lengthBin).get(format(llr));
+ }
+ else
+ {
+ return new Color(140, 140, 140);
+ }
+
+ Color colour = Color.ORANGE;
+ if (prob >= 0.5)
+ {
+
+ colour = ColorUtils.getGraduatedColour((float) prob, 0.5f,
+ Color.WHITE, 1f,
+ Color.blue);
+ }
+ else
+ {
+ colour = ColorUtils.getGraduatedColour((float) prob, 0f, Color.red,
+ 0.5f, Color.WHITE);
+ }
+
+ return colour;
+ }
+
+ public static String format(Double d)
+ {
+ String formatArg = String.valueOf(binSize);
+
+ // if bin size, need format "%.n" where n is number of decimal places
+ if (binSize < 1)
+ {
+ formatArg = "." + formatArg.split("\\.")[1].length();
+ }
+
+ Double rounded = Math.round(d / binSize) * binSize;
+ String formatted = String.format("%" + formatArg + "f", rounded);
+
+ // format sometimes returns a number rounded to 0 as -0
+ // this ensures output will always be 0
+ if (Double.valueOf(formatted) == 0)
+ {
+ formatted = "0";
+ }
+ return formatted;
+
+ }
+
+ /**
+ * Answers the maximum possible value of information score (log ratio), for use
+ * in scaling a graduated colour range
+ *
+ * @return
+ */
+ protected float getMaxInformationScore()
+ {
+ return 0f;
+ }
+
+ /**
+ * Answers a new colour scheme instance based on the HMM of the first sequence
+ * in ac that has an HMM
+ */
+ @Override
+ public ColourSchemeI getInstance(AlignViewportI viewport,
+ AnnotatedCollectionI ac)
+ {
+ return newInstance(ac);
+ }
+
+ /**
+ * Constructor given a sequence collection
+ *
+ * @param ac
+ */
+ public HMMMatchScoreColourScheme(AnnotatedCollectionI ac)
+ {
+ this(ac.getHmmSequences());
+ }
+
+ /**
+ * Answers a new instance of the colour scheme for the given HMM
+ *
+ * @param ac
+ * @return
+ */
+ protected HMMMatchScoreColourScheme newInstance(AnnotatedCollectionI ac)
+ {
+ return new HMMMatchScoreColourScheme(ac);
+ }
+
+ @Override
+ public boolean isSimple()
+ {
+ return false;
+ }
+
+ /**
+ * Answers true if the sequence collection has an HMM consensus sequence and
+ * that the first HMM sequence contains background frequencies, else false
+ */
+ @Override
+ public boolean isApplicableTo(AnnotatedCollectionI ac)
+ {
+ return !ac.getHmmSequences().isEmpty() && ac.getHmmSequences().get(0)
+ .getHMM().getBackgroundFrequencies() != null;
+ }
+
+ protected Map getFrequencies()
+ {
+ return frequencies;
+ }
+
+ protected void setFrequencies(Map frequencies)
+ {
+ this.frequencies = frequencies;
+ }
+
+ protected HiddenMarkovModel getHmm()
+ {
+ return hmm;
+ }
+
+ protected SequenceI getHmmSequence()
+ {
+ return hmmSeq;
+ }
+
+ @Override
+ public String getSchemeName()
+ {
+ return JalviewColourScheme.HMMMatchScore.toString();
+ }
+
+ private int getLengthBin(int l)
+ {
+ for (int i = 1; i < ranges.size(); i++)
+ {
+ if (l >= ranges.get(i - 1) && l < ranges.get(i))
+ {
+ return ranges.get(i);
+ }
+ }
+ return -1;
+ }
+}
+
+
diff --git a/src/jalview/schemes/HmmerColourScheme.java b/src/jalview/schemes/HmmerColourScheme.java
new file mode 100644
index 0000000..05c9b66
--- /dev/null
+++ b/src/jalview/schemes/HmmerColourScheme.java
@@ -0,0 +1,197 @@
+package jalview.schemes;
+
+import jalview.api.AlignViewportI;
+import jalview.datamodel.AnnotatedCollectionI;
+import jalview.datamodel.HiddenMarkovModel;
+import jalview.datamodel.SequenceI;
+import jalview.util.ColorUtils;
+import jalview.util.Comparison;
+
+import java.awt.Color;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Base class for colour schemes based on a selected Hidden Markov Model. The
+ * colour is with reference to an HMM consensus sequence and HMM profile
+ *
+ * white for a gap
+ * red for an insertion (position is gapped in the HMM consensus)
+ * orange for negative information content
+ * white to blue for increasing information content
+ *
+ * where information content is the log ratio
+ *
+ *
+ * log(profile match emission probability / residue background probability)
+ *
+ *
+ * Sub-class implementations use either global ('Uniprot') or local
+ * ('alignment') background frequencies.
+ *
+ * @author tzvanaalten
+ * @author gmcarstairs
+ */
+public abstract class HmmerColourScheme extends ResidueColourScheme
+{
+ private static final Color INSERTION_COLOUR = new Color(230, 0, 0); // reddish
+
+ /*
+ * the aligned HMM consensus sequence to use as reference for colouring
+ */
+ private SequenceI hmmSeq;
+
+ private HiddenMarkovModel hmm;
+
+ private Map frequencies;
+
+ /**
+ * Constructor given a list of Hidden Markov Model consensus sequences. The
+ * first sequence provides the HMM profile from which we can read the emission
+ * probabilities that determine the colour.
+ *
+ * @param hmmSeqs
+ */
+ public HmmerColourScheme(List hmmSeqs)
+ {
+ hmmSeq = hmmSeqs.isEmpty() ? null : hmmSeqs.get(0);
+ hmm = hmmSeq == null ? null : hmmSeq.getHMM();
+ }
+
+ /**
+ * Default constructor (required by ColourSchemes.loadColourSchemes)
+ */
+ public HmmerColourScheme()
+ {
+ }
+
+ @Override
+ public Color findColour(char symbol, int column, SequenceI seq,
+ String consensusResidue, float pid)
+ {
+ return findColour(symbol, column);
+ }
+
+ /**
+ * Returns the colour at a particular symbol at a column in the alignment:
+ *
+ * white for a gap
+ * red for an insertion
+ * orange for negative information content
+ * white to blue for increasing information content
+ *
+ *
+ * @param symbol
+ * @param column
+ * @return
+ */
+ private Color findColour(char symbol, int column)
+ {
+ if (getHmm() == null || Comparison.isGap(symbol))
+ {
+ return Color.white;
+ }
+ if (Comparison.isGap(hmmSeq.getCharAt(column)))
+ {
+ return INSERTION_COLOUR;
+ }
+ if (Character.isLowerCase(symbol))
+ {
+ symbol = Character.toUpperCase(symbol);
+ }
+
+ final double prob = getHmm().getMatchEmissionProbability(column,
+ symbol);
+
+ Float freq = 0f;
+
+ if (!frequencies.containsKey(symbol))
+ {
+ return Color.WHITE;
+ }
+ else
+ {
+ freq = frequencies.get(symbol);
+ }
+
+ /*
+ * Orange if match emission probability is less than background probability
+ */
+ double infoRatio = prob / freq.floatValue();
+ Color colour = Color.ORANGE;
+ if (infoRatio >= 1)
+ {
+ /*
+ * log-scale graduated shade of blue if prob is greater than background
+ */
+ float infoLog = (float) Math.log(infoRatio);
+ colour = ColorUtils.getGraduatedColour(infoLog, 0, Color.WHITE,
+ getMaxInformationScore(), Color.blue);
+ }
+
+ return colour;
+ }
+
+ /**
+ * Answers the maximum possible value of information score (log ratio), for
+ * use in scaling a graduated colour range
+ *
+ * @return
+ */
+ abstract float getMaxInformationScore();
+
+ /**
+ * Answers a new colour scheme instance based on the HMM of the first sequence
+ * in ac that has an HMM
+ */
+ @Override
+ public ColourSchemeI getInstance(AlignViewportI viewport,
+ AnnotatedCollectionI ac)
+ {
+ return newInstance(ac);
+ }
+
+ /**
+ * Answers a new instance of the colour scheme for the given HMM
+ *
+ * @param ac
+ * @return
+ */
+ protected abstract HmmerColourScheme newInstance(AnnotatedCollectionI ac);
+
+ @Override
+ public boolean isSimple()
+ {
+ return false;
+ }
+
+ /**
+ * Answers true if the sequence collection has an HMM consensus sequence, else
+ * false
+ */
+ @Override
+ public boolean isApplicableTo(AnnotatedCollectionI ac)
+ {
+ return !ac.getHmmSequences().isEmpty();
+ }
+
+ protected Map getFrequencies()
+ {
+ return frequencies;
+ }
+
+ protected void setFrequencies(Map frequencies)
+ {
+ this.frequencies = frequencies;
+ }
+
+ protected HiddenMarkovModel getHmm()
+ {
+ return hmm;
+ }
+
+ protected SequenceI getHmmSequence()
+ {
+ return hmmSeq;
+ }
+}
diff --git a/src/jalview/schemes/HmmerGlobalBackground.java b/src/jalview/schemes/HmmerGlobalBackground.java
new file mode 100644
index 0000000..a24b7ab
--- /dev/null
+++ b/src/jalview/schemes/HmmerGlobalBackground.java
@@ -0,0 +1,73 @@
+package jalview.schemes;
+
+import jalview.api.AlignViewportI;
+import jalview.datamodel.AnnotatedCollectionI;
+import jalview.datamodel.SequenceCollectionI;
+
+/**
+ * An HMM colour scheme that uses global ('Uniprot') background frequencies for
+ * residues
+ *
+ * @author tzvanaalten
+ */
+public class HmmerGlobalBackground extends HmmerColourScheme
+{
+ /*
+ * The highest possible log ratio is when match emission probability in
+ * the HMM model is 1, and background (for W) is 0.0109 giving
+ * log(1/0.0109) = log(91.743) = 4.519
+ */
+ private static final float MAX_LOG_RATIO = 4.519f;
+
+ /**
+ * Constructor given a sequence collection
+ *
+ * @param ac
+ */
+ public HmmerGlobalBackground(SequenceCollectionI ac)
+ {
+ super(ac.getHmmSequences());
+ String alphabetType = getHmm() == null
+ ? ResidueProperties.ALPHABET_AMINO
+ : getHmm().getAlphabetType();
+ setFrequencies(
+ ResidueProperties.backgroundFrequencies.get(alphabetType));
+ }
+
+ /**
+ * Default constructor (required by ColourSchemes.loadColourSchemes)
+ */
+ public HmmerGlobalBackground()
+ {
+ }
+
+ @Override
+ public String getSchemeName()
+ {
+ return JalviewColourScheme.HMMERU.toString();
+ }
+
+ @Override
+ protected HmmerColourScheme newInstance(AnnotatedCollectionI ac)
+ {
+ return new HmmerGlobalBackground(ac);
+ }
+
+ @Override
+ float getMaxInformationScore()
+ {
+ return MAX_LOG_RATIO;
+ }
+
+ /**
+ * Answers a new colour scheme instance based on the HMM of the first sequence
+ * in alignment that has an HMM
+ */
+ @Override
+ public ColourSchemeI getInstance(AlignViewportI viewport,
+ AnnotatedCollectionI ac)
+ {
+ return newInstance(ac);
+ }
+
+}
diff --git a/src/jalview/schemes/HmmerLocalBackground.java b/src/jalview/schemes/HmmerLocalBackground.java
new file mode 100644
index 0000000..2fe775c
--- /dev/null
+++ b/src/jalview/schemes/HmmerLocalBackground.java
@@ -0,0 +1,96 @@
+package jalview.schemes;
+
+import jalview.datamodel.AnnotatedCollectionI;
+import jalview.datamodel.ResidueCount;
+import jalview.datamodel.SequenceCollectionI;
+import jalview.datamodel.SequenceI;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * An HMM colour scheme that uses local (alignment or sub-group) background
+ * frequencies for residues
+ *
+ * @author tzvanaalten
+ */
+public class HmmerLocalBackground extends HmmerColourScheme
+{
+ float logTotalCount;
+
+ /**
+ * Constructor given a sequence collection
+ *
+ * @param ac
+ */
+ public HmmerLocalBackground(AnnotatedCollectionI ac)
+ {
+ super(ac.getHmmSequences());
+ countFrequencies(ac);
+ }
+
+ /**
+ * Default constructor (required by ColourSchemes.loadColourSchemes)
+ */
+ public HmmerLocalBackground()
+ {
+ }
+
+ @Override
+ public String getSchemeName()
+ {
+ return JalviewColourScheme.HMMERA.toString();
+ }
+
+ /**
+ * Counts and stores the relative frequency of every residue in the alignment
+ * (apart from any HMM consensus sequences)
+ *
+ * @param sc
+ */
+ public void countFrequencies(SequenceCollectionI sc)
+ {
+ // TODO or total counts in Consensus Profile (how do we get at it?)?
+ Map freqs = new HashMap<>();
+
+ /*
+ * count symbols, excluding any HMM consensus sequences
+ */
+ ResidueCount counts = new ResidueCount();
+ List seqs = sc.getSequences();
+ for (SequenceI seq : seqs)
+ {
+ if (!seq.hasHMMProfile())
+ {
+ for (char c : seq.getSequence())
+ {
+ counts.add(c);
+ }
+ }
+ }
+ int total = counts.getTotalResidueCount(); // excludes gaps
+
+ for (char symbol : counts.getSymbolCounts().symbols)
+ {
+ double freq = counts.getCount(symbol) / (double) total;
+ freqs.put(symbol, (float) freq);
+ }
+
+ setFrequencies(freqs);
+
+ logTotalCount = (float) Math.log(total);
+ }
+
+ @Override
+ float getMaxInformationScore()
+ {
+ return logTotalCount;
+ }
+
+ @Override
+ protected HmmerColourScheme newInstance(AnnotatedCollectionI ac)
+ {
+ return new HmmerLocalBackground(ac);
+ }
+}
diff --git a/src/jalview/schemes/JalviewColourScheme.java b/src/jalview/schemes/JalviewColourScheme.java
index 456397e..eb1edf1 100644
--- a/src/jalview/schemes/JalviewColourScheme.java
+++ b/src/jalview/schemes/JalviewColourScheme.java
@@ -43,7 +43,10 @@ public enum JalviewColourScheme
PurinePyrimidine("Purine/Pyrimidine", PurinePyrimidineColourScheme.class),
RNAHelices("RNA Helices", RNAHelicesColour.class),
TCoffee("T-Coffee Scores", TCoffeeColourScheme.class),
- IdColour("Sequence ID", IdColourScheme.class);
+ IdColour("Sequence ID", IdColourScheme.class),
+ HMMERU("HMMER-Uniprot", HmmerGlobalBackground.class),
+ HMMERA("HMMER-Alignment", HmmerLocalBackground.class),
+ HMMMatchScore("HMM Match Score", HMMMatchScoreColourScheme.class);
// RNAInteraction("RNA Interaction type", RNAInteractionColourScheme.class)
private String name;
diff --git a/src/jalview/schemes/ResidueProperties.java b/src/jalview/schemes/ResidueProperties.java
index 5f84ca0..0b62bb6 100755
--- a/src/jalview/schemes/ResidueProperties.java
+++ b/src/jalview/schemes/ResidueProperties.java
@@ -34,6 +34,13 @@ import java.util.Vector;
public class ResidueProperties
{
+ // alphabet names used in Hidden Markov Model files
+ public static final String ALPHABET_RNA = "RNA";
+
+ public static final String ALPHABET_DNA = "DNA";
+
+ public static final String ALPHABET_AMINO = "amino";
+
// Stores residue codes/names and colours and other things
public static final int[] aaIndex; // aaHash version 2.1.1 and below
@@ -50,6 +57,9 @@ public class ResidueProperties
// lookup from modified amino acid (e.g. MSE) to canonical form (e.g. MET)
public static final Map modifications = new HashMap<>();
+ // residue background frequencies across different alphabets
+ public static final Map> backgroundFrequencies = new HashMap<>();
+
static
{
aaIndex = new int[255];
@@ -2270,6 +2280,58 @@ public class ResidueProperties
}
+ static
+ {
+ Map amino = new HashMap<>();
+ amino.put('A', 0.0826f);
+ amino.put('Q', 0.0393f);
+ amino.put('L', 0.0965f);
+ amino.put('S', 0.0661f);
+ amino.put('R', 0.0553f);
+ amino.put('E', 0.0674f);
+ amino.put('K', 0.0582f);
+ amino.put('T', 0.0535f);
+ amino.put('N', 0.0406f);
+ amino.put('G', 0.0708f);
+ amino.put('M', 0.0241f);
+ amino.put('W', 0.0109f);
+ amino.put('D', 0.0546f);
+ amino.put('H', 0.0227f);
+ amino.put('F', 0.0386f);
+ amino.put('Y', 0.0292f);
+ amino.put('C', 0.0137f);
+ amino.put('I', 0.0593f);
+ amino.put('P', 0.0472f);
+ amino.put('V', 0.0686f);
+ backgroundFrequencies.put(ALPHABET_AMINO, amino);
+ // todo: these don't match https://www.ebi.ac.uk/uniprot/TrEMBLstats - what
+ // are they?
+ }
+
+ // TODO get correct frequencies
+
+ static
+ {
+ Map dna = new HashMap<>();
+ dna.put('A', 0.25f);
+ dna.put('C', 0.25f);
+ dna.put('T', 0.25f);
+ dna.put('G', 0.25f);
+ backgroundFrequencies.put(ALPHABET_DNA, dna);
+
+ }
+
+ static
+ {
+ Map rna = new HashMap<>();
+ rna.put('A', 0.25f);
+ rna.put('C', 0.25f);
+ rna.put('T', 0.25f);
+ rna.put('G', 0.25f);
+ backgroundFrequencies.put(ALPHABET_RNA, rna);
+
+ }
+
public static String getCanonicalAminoAcid(String aA)
{
String canonical = modifications.get(aA);
diff --git a/src/jalview/util/Comparison.java b/src/jalview/util/Comparison.java
index d4fc233..4afa12d 100644
--- a/src/jalview/util/Comparison.java
+++ b/src/jalview/util/Comparison.java
@@ -256,7 +256,7 @@ public class Comparison
*/
public static final boolean isGap(char c)
{
- return (c == GAP_DASH || c == GAP_DOT || c == GAP_SPACE) ? true : false;
+ return (c == GAP_DASH || c == GAP_DOT || c == GAP_SPACE);
}
/**
diff --git a/src/jalview/util/FileUtils.java b/src/jalview/util/FileUtils.java
new file mode 100644
index 0000000..7e607ab
--- /dev/null
+++ b/src/jalview/util/FileUtils.java
@@ -0,0 +1,208 @@
+package jalview.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Miscellaneous file-related functions
+ */
+public final class FileUtils
+{
+
+ /**
+ * Answers the executable file for the given command, or null if not found or
+ * not executable. The path to the executable is the command name prefixed by
+ * the given folder path, optionally with .exe appended.
+ *
+ * @param cmd
+ * command short name, for example hmmbuild
+ * @param binaryPath
+ * parent folder for the executable
+ * @return
+ */
+ public static File getExecutable(String cmd, String binaryPath)
+ {
+ File file = new File(binaryPath, cmd);
+ if (!file.canExecute())
+ {
+ file = new File(binaryPath, cmd + ".exe");
+ {
+ if (!file.canExecute())
+ {
+ file = null;
+ }
+ }
+ }
+ return file;
+ }
+
+ /**
+ * Answers the path to the folder containing the given executable file, by
+ * searching the PATH environment variable. Answers null if no such executable
+ * can be found.
+ *
+ * @param cmd
+ * @return
+ */
+ public static String getPathTo(String cmd)
+ {
+ String paths = System.getenv("PATH");
+ // backslash is to escape regular expression argument
+ for (String path : paths.split("\\" + File.pathSeparator))
+ {
+ if (getExecutable(cmd, path) != null)
+ {
+ return path;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * A convenience method to create a temporary file that is deleted on exit of
+ * the JVM
+ *
+ * @param prefix
+ * @param suffix
+ * @return
+ * @throws IOException
+ */
+ public static File createTempFile(String prefix, String suffix)
+ throws IOException
+ {
+ File f = File.createTempFile(prefix, suffix);
+ f.deleteOnExit();
+ return f;
+ }
+
+ /**
+ * Answers a (possibly empty) list of file paths found by searching below
+ * from
that match the supplied regular expression
+ * pattern
. Results may include from
itself if it
+ * matches. If an exception occurs it is written to syserr and any results up to
+ * that point are returned. Note that the regular expression match applies to
+ * the whole path of any matched file.
+ *
+ * WARNING: because the whole directory tree below from
is
+ * searched, this method may be slow if used for a high level directory, or may
+ * exit prematurely if security or other exceptions occur.
+ *
+ *
+ * Example:
+ * findMatchingPaths(Paths.get("C:/Program Files"), ".*/chimera.exe$")
+ *
+ *
+ * @param from
+ * @param pattern
+ *
+ * @return
+ * @see https://stackoverflow.com/questions/794381/how-to-find-files-that-match-a-wildcard-string-in-java/31685610#comment62441832_31685610
+ */
+ public static List findMatchingPaths(Path from, String pattern)
+ {
+ List matches = new ArrayList<>();
+ PathMatcher pathMatcher = FileSystems.getDefault()
+ .getPathMatcher("regex:" + pattern);
+ try
+ {
+ Files.walk(from).filter(pathMatcher::matches)
+ .forEach(m -> matches.add(m.toString()));
+ } catch (IOException e)
+ {
+ System.err.println(
+ "Error searching for " + pattern + " : " + e.toString());
+ }
+
+ return matches;
+ }
+
+ /**
+ * Answers a (possibly empty) list of paths to files below the given root path,
+ * that match the given pattern. The pattern should be a '/' delimited set of
+ * glob patterns, each of which is used to match child file names (not full
+ * paths). Note that 'directory spanning' glob patterns (**) are not
+ * supported by this method.
+ *
+ * For example
+ *
+ *
+ * findMatches("C:\\", "Program Files*/Chimera*/bin/{chimera,chimera.exe}"
+ *
+ *
+ * would match "C:\Program Files\Chimera 1.11\bin\chimera.exe" and "C:\Program
+ * Files (x86)\Chimera 1.10.1\bin\chimera"
+ *
+ * @param root
+ * @param pattern
+ * @return
+ * @see https://docs.oracle.com/javase/tutorial/essential/io/fileOps.html#glob
+ */
+ public static List findMatches(String root, String pattern)
+ {
+ List results = new ArrayList<>();
+ try
+ {
+ Path from = Paths.get(root);
+ findMatches(results, from, Arrays.asList(pattern.split("/")));
+ } catch (Throwable e)
+ {
+ // Paths.get can throw IllegalArgumentException
+ System.err.println(String.format("Error searching %s for %s: %s",
+ root, pattern, e.toString()));
+ }
+
+ return results;
+ }
+
+ /**
+ * A helper method that performs recursive search of file patterns and adds any
+ * 'leaf node' matches to the results list
+ *
+ * @param results
+ * @param from
+ * @param patterns
+ */
+ protected static void findMatches(List results, Path from,
+ List patterns)
+ {
+ if (patterns.isEmpty())
+ {
+ /*
+ * reached end of recursion with all components matched
+ */
+ results.add(from.toString());
+ return;
+ }
+
+ String pattern = patterns.get(0);
+ try (DirectoryStream dirStream = Files.newDirectoryStream(from,
+ pattern))
+ {
+ dirStream.forEach(p -> {
+
+ /*
+ * matched a next level file - search below it
+ * (ignore non-directory non-leaf matches)
+ */
+ List subList = patterns.subList(1, patterns.size());
+ if (subList.isEmpty() || p.toFile().isDirectory())
+ {
+ findMatches(results, p, subList);
+ }
+ });
+ } catch (IOException e)
+ {
+ System.err.println(String.format("Error searching %s: %s", pattern,
+ e.toString()));
+ }
+ }
+}
diff --git a/src/jalview/util/HMMProbabilityDistributionAnalyser.java b/src/jalview/util/HMMProbabilityDistributionAnalyser.java
new file mode 100644
index 0000000..66ae552
--- /dev/null
+++ b/src/jalview/util/HMMProbabilityDistributionAnalyser.java
@@ -0,0 +1,978 @@
+package jalview.util;
+
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.HiddenMarkovModel;
+import jalview.datamodel.SequenceI;
+import jalview.io.DataSourceType;
+import jalview.io.FileParse;
+import jalview.io.HMMFile;
+import jalview.io.StockholmFile;
+import jalview.schemes.ResidueProperties;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Scanner;
+import java.util.Vector;
+
+/**
+ * Processes probability data. The file indexes used in this program represent
+ * the index of the location of a family or hmm in their respective files,
+ * starting from 0.
+ *
+ * @author TZVanaalten
+ *
+ */
+public class HMMProbabilityDistributionAnalyser
+{
+ AlignmentAnnotation reference = null;
+
+ Vector sequences;
+
+ HiddenMarkovModel hmm;
+
+ // contains the raw data produced
+ List> raw = new ArrayList<>();
+
+ // contains binned data
+ Map binned = new HashMap<>();
+
+ // location of the family file
+ String families = "/media/sf_Shared_Folder/PFAM/Family/SeedFamilies.seed";
+
+ // location of the file containing the family-clan links
+ final static String FAMILIESTOCLAN = "/media/sf_Shared_Folder/PFAM/Family/Clanlinks.dat";
+
+ // location of the HMM file
+ String hmms = "/media/sf_Shared_Folder/PFAM/HMMs/Pfam-A.hmm";
+
+ // suffix for raw file
+ final static String RAW = "/Raw.csv";
+
+ // suffix for binned file
+ final static String BINNED = "/Binned.csv";
+
+ // normalisation scale
+ final static double SCALE = 1;
+
+ // current position in file
+ int currentFilePosition = 0;
+
+ final static String NL = "\n";
+
+ Random generator = new Random();
+
+ // current directory
+ String currentFolder;
+
+ boolean keepRaw = false;
+
+ /**
+ * Sets the working directory.
+ *
+ * @param path
+ */
+ public void setFolder(String path)
+ {
+ currentFolder = path;
+ }
+
+ /**
+ * Moves a buffered reader forward in the file by a certain amount of entries.
+ * Each entry in the file is delimited by '//'.
+ *
+ * @param index
+ * The index of the location in the file.
+ * @param br
+ * @throws IOException
+ */
+ public void moveLocationBy(int index, BufferedReader br)
+ throws IOException
+ {
+ for (int i = 0; i < index; i++)
+ {
+ String line = br.readLine();
+ while (!"//".equals(line))
+ {
+ line = br.readLine();
+
+ }
+ }
+
+ }
+
+ /**
+ * Analyses a specified number of families and then saves the data. Before
+ * analysing the data, the previous saved data will be imported and after
+ * analysing this, the data is exported back into the file. The file must be
+ * in flat file format.
+ *
+ * @param increments
+ * The number of families to read before saving.
+ * @throws IOException
+ */
+ public void run(int increments, boolean keepRawData) throws IOException
+ {
+ keepRaw = keepRawData;
+ try
+ {
+ readPreviousData(currentFolder);
+ BufferedReader posReader = new BufferedReader(
+ new FileReader(currentFolder + "/CurrentPosition.txt"));
+
+ String line = posReader.readLine();
+ posReader.close();
+ currentFilePosition = Integer.parseInt(line);
+ } catch (Exception e)
+ {
+ System.out.println("No previous data found");
+ }
+
+
+
+ BufferedReader inputSTO = new BufferedReader(new FileReader(families));
+ BufferedReader inputHMM = new BufferedReader(new FileReader(hmms));
+
+
+
+ moveLocationBy(currentFilePosition, inputHMM);
+ moveLocationBy(currentFilePosition, inputSTO);
+
+ int filesRead = 0;
+ int i = 0;
+ while (filesRead < increments)
+ {
+
+ readStockholm(inputSTO);
+
+ readHMM(inputHMM);
+
+ int count = countValidResidues();
+ processData(count);
+ filesRead++;
+
+ currentFilePosition++;
+ System.out.println(i);
+ i++;
+ }
+
+ PrintWriter p = new PrintWriter(
+ new File(currentFolder + "/CurrentPosition.txt"));
+ p.print(currentFilePosition);
+ p.close();
+ exportData(currentFolder);
+ raw.clear();
+ binned.clear();
+
+ }
+
+ /**
+ * Analyses all families and then saves the data. Before analysing the data,
+ * the previous saved data will be imported and after analysing this, the data
+ * is exported back into the file. The file must be in flat file format.
+ *
+ * @param increments
+ * The number of families to read before saving.
+ * @throws IOException
+ */
+ public void runToEnd(int minCount, int maxCount, boolean keepRawData,
+ boolean forClans)
+ throws IOException
+ {
+ keepRaw = keepRawData;
+ BufferedReader inputSTO = null;
+ BufferedReader inputHMM = null;
+ int size = 0;
+ int files = 1;
+ try
+ {
+ if (forClans)
+ {
+ files = 603;
+ }
+ int filesRead = 0;
+ for (int clan = 0; clan < files; clan++)
+ {
+ System.out.println(clan);
+ String clanPath = "";
+ int numberOfFamilies = 0;
+ if (forClans)
+ {
+ clanPath = currentFolder + "/Clan" + clan;
+ if (!new File(clanPath).exists())
+ {
+ continue;
+ }
+ BufferedReader famCountReader = new BufferedReader(
+ new FileReader(clanPath + "/NumberOfFamilies.txt"));
+ numberOfFamilies = Integer.parseInt(famCountReader.readLine());
+ }
+ else
+ {
+ numberOfFamilies = 1;
+ }
+
+ for (int fam = 0; fam < numberOfFamilies; fam++)
+ {
+ if (forClans)
+ {
+ families = clanPath + "/Families/Fam" + fam + ".sto";
+ hmms = clanPath + "/HMMs/HMM" + fam + ".hmm";
+ }
+
+ inputSTO = new BufferedReader(new FileReader(families));
+ inputHMM = new BufferedReader(new FileReader(hmms));
+
+
+ int i = 0;
+ boolean endReached = atEnd(inputSTO);
+ while (!endReached)
+ {
+ readStockholm(inputSTO);
+ readHMM(inputHMM);
+
+ int count = countValidResidues();
+ if (count >= minCount && count < maxCount)
+ {
+ processData(count);
+ }
+ filesRead++;
+ System.out.println(filesRead);
+ endReached = atEnd(inputSTO);
+ }
+ }
+ }
+ } catch (Exception e)
+ {
+ e.printStackTrace();
+ } finally
+ {
+ exportData(currentFolder);
+ raw.clear();
+ binned.clear();
+ }
+ }
+
+ /**
+ * Reads the previous data from both files
+ *
+ * @param source
+ * @throws IOException
+ */
+ public void readPreviousData(String source) throws IOException
+ {
+ readBinned(source);
+ if (keepRaw)
+ {
+ readRaw(source);
+ }
+ }
+
+ /**
+ * Reads the previous data from the binned file.
+ *
+ * @param source
+ * @throws IOException
+ */
+ public void readBinned(String source) throws IOException
+ {
+ BufferedReader input = new BufferedReader(
+ new FileReader(source + BINNED));
+ String line = input.readLine();
+ binned = new HashMap<>();
+ while (!("".equals(line) || line == null))
+ {
+ Scanner scanner = new Scanner(line);
+ scanner.useDelimiter(",");
+ String key = scanner.next();
+ String value = scanner.next();
+ binned.put(key, Double.valueOf(value));
+ scanner.close();
+ line = input.readLine();
+ }
+
+ input.close();
+ }
+
+ /**
+ * Reads the previous data from the raw file.
+ *
+ * @param source
+ * @throws IOException
+ */
+ public void readRaw(String source) throws IOException
+ {
+ BufferedReader input = new BufferedReader(new FileReader(source + RAW));
+ String line = input.readLine();
+ if (line == null)
+ {
+ input.close();
+ return;
+ }
+ Scanner numberScanner = new Scanner(line);
+ numberScanner.useDelimiter(",");
+ raw = new ArrayList<>();
+ while (numberScanner.hasNext())
+ {
+ numberScanner.next();
+ raw.add(new ArrayList());
+ }
+ numberScanner.close();
+
+ line = input.readLine();
+ while (!("".equals(line) || line == null))
+ {
+ Scanner scanner = new Scanner(line);
+ scanner.useDelimiter(",");
+
+ int i = 0;
+ while (scanner.hasNext())
+ {
+ String value;
+ value = scanner.next();
+ if (!value.equals("EMPTY"))
+ {
+ raw.get(i).add(Double.parseDouble(value));
+ }
+ else
+ {
+ raw.get(i).add(null);
+ }
+
+ i++;
+ }
+ scanner.close();
+ line = input.readLine();
+ }
+
+ input.close();
+ }
+
+ /**
+ * Counts the number of valid residues in the sequence.
+ *
+ * @return
+ */
+ public int countValidResidues()
+ {
+ int count = 0;
+
+ for (int width = 0; width < sequences.size(); width++)
+ {
+ for (int length = 1; length < hmm.getLength() + 1; length++)
+ {
+ char symbol;
+ int alignPos;
+ alignPos = hmm.getNodeMapPosition(length);
+
+ symbol = sequences.get(width).getCharAt(alignPos);
+ if (ResidueProperties.backgroundFrequencies.get("amino")
+ .containsKey(symbol))
+ {
+ count++;
+ }
+ }
+ }
+
+ return count;
+ }
+
+ /**
+ * Processes data, and stores it in both a raw and binned format.
+ *
+ * @param count
+ */
+ public void processData(int count)
+ {
+ int rawPos = 0;
+ if (keepRaw)
+ {
+ raw.add(new ArrayList());
+ rawPos = raw.size() - 1;
+ }
+ Double total = 0d;
+ for (int width = 0; width < sequences.size(); width++)
+ {
+ for (int length = 1; length < hmm.getLength() + 1; length++)
+ {
+ char symbol;
+ int alignPos;
+ alignPos = hmm.getNodeMapPosition(length);
+
+ symbol = sequences.get(width).getCharAt(alignPos);
+ if (ResidueProperties.backgroundFrequencies.get("amino")
+ .containsKey(symbol))
+ {
+ Double prob;
+ Float bfreq;
+ Double llr;
+ prob = hmm.getMatchEmissionProbability(alignPos, symbol);
+ bfreq = ResidueProperties.backgroundFrequencies.get("amino")
+ .get(symbol);
+ if (prob == 0 || bfreq == 0)
+ {
+ System.out.println("error");
+ }
+ llr = Math.log(prob / bfreq);
+ if (keepRaw)
+ {
+ raw.get(rawPos).add(llr);
+ }
+
+ String output;
+ output = String.format("%.1f", llr);
+ total += Double.parseDouble(output);
+ if ("-0.0".equals(output))
+ {
+ output = "0.0";
+ }
+ if (binned.containsKey(output))
+ {
+ double prev = binned.get(output);
+ prev += (SCALE / count);
+ binned.put(output, prev);
+
+ }
+ else
+ {
+ binned.put(output, SCALE / count);
+ }
+ }
+ }
+ }
+ System.out.println(total / count);
+ }
+
+
+ /**
+ * Reads in the sequence data from a Stockholm file.
+ *
+ * @param source
+ * @throws IOException
+ */
+ public void readStockholm(BufferedReader inputSTO) throws IOException
+ {
+ FileParse parserSTO = new FileParse(inputSTO, "", DataSourceType.FILE);
+ StockholmFile file = new StockholmFile(parserSTO);
+ Vector annots = file.getAnnotations();
+
+ for (AlignmentAnnotation annot : annots)
+ {
+ if (annot.label.contains("Reference"))
+ {
+ reference = annot;
+ }
+ }
+ sequences = file.getSeqs();
+ }
+
+ /**
+ * Reads in the HMM data from a HMMer file.
+ *
+ * @param source
+ * @throws IOException
+ */
+ public void readHMM(BufferedReader inputHMM) throws IOException
+ {
+ FileParse parserHMM = new FileParse(inputHMM, "", DataSourceType.FILE);
+ HMMFile file = new HMMFile(parserHMM);
+ hmm = file.getHMM();
+
+
+ }
+
+ /**
+ * Exports both the binned and raw data into separate files.
+ *
+ * @param location
+ * @throws FileNotFoundException
+ */
+ public void exportData(String location) throws FileNotFoundException
+ {
+ PrintWriter writerBin = new PrintWriter(new File(location + BINNED));
+ for (Map.Entry entry : binned.entrySet())
+ {
+ writerBin.println(entry.getKey() + "," + entry.getValue());
+ }
+ writerBin.close();
+ if (keepRaw)
+ {
+
+ PrintWriter writerRaw = new PrintWriter(new File(location + RAW));
+
+ StringBuilder identifier = new StringBuilder();
+
+ for (int i = 1; i < raw.size() + 1; i++)
+ {
+ identifier.append("Fam " + i + ",");
+ }
+
+ writerRaw.println(identifier);
+
+ boolean rowIsEmpty = false;
+ int row = 0;
+ while (!rowIsEmpty)
+ {
+ rowIsEmpty = true;
+ StringBuilder string = new StringBuilder();
+ for (int column = 0; column < raw.size(); column++)
+ {
+ if (raw.get(column).size() <= row)
+ {
+ string.append("EMPTY,");
+ }
+ else
+ {
+ string.append(raw.get(column).get(row) + ",");
+ rowIsEmpty = false;
+ }
+ }
+ row++;
+ writerRaw.println(string);
+ }
+ writerRaw.close();
+
+ }
+
+ }
+
+ /**
+ * Prints the specified family on the console.
+ *
+ * @param index
+ * @throws IOException
+ */
+ public void printFam(int index) throws IOException
+ {
+ BufferedReader br = new BufferedReader(new FileReader(families));
+
+ moveLocationBy(index, br);
+
+ String line = br.readLine();
+
+ while (!"//".equals(line))
+ {
+ System.out.println(line);
+ line = br.readLine();
+ }
+ System.out.println(line);
+ br.close();
+
+ }
+
+ /**
+ * Prints the specified HMM on the console.
+ *
+ * @param index
+ * @throws IOException
+ */
+ public void printHMM(int index) throws IOException
+ {
+ BufferedReader br = new BufferedReader(new FileReader(hmms));
+
+ moveLocationBy(index, br);
+
+ String line = br.readLine();
+
+ while (!"//".equals(line))
+ {
+ System.out.println(line);
+ line = br.readLine();
+ }
+ System.out.println(line);
+ br.close();
+
+ }
+
+ /**
+ * Prints the specified family to a .sto file.
+ *
+ * @param index
+ * @throws IOException
+ */
+ public void exportFam(int index, String location) throws IOException
+ {
+ BufferedReader br = new BufferedReader(new FileReader(families));
+
+ moveLocationBy(index, br);
+
+ String line = br.readLine();
+ PrintWriter writer = new PrintWriter(
+ new FileOutputStream(new File(location), true));
+ while (!"//".equals(line))
+ {
+ writer.println(line);
+ line = br.readLine();
+ }
+ writer.println(line);
+ writer.close();
+ br.close();
+
+ }
+
+ public void exportFile(BufferedReader br, String location, boolean append)
+ throws IOException
+ {
+ String line = br.readLine();
+ PrintWriter writer = new PrintWriter(
+ new FileOutputStream(location, append));
+ while (!"//".equals(line))
+ {
+ writer.println(line);
+ line = br.readLine();
+ }
+ writer.println(line);
+ writer.close();
+
+
+ }
+
+ public String getHMMName(int index) throws IOException
+ {
+ String name;
+
+ BufferedReader nameFinder = new BufferedReader(new FileReader(hmms));
+
+ moveLocationBy(index, nameFinder);
+
+ nameFinder.readLine();
+
+ Scanner scanner = new Scanner(nameFinder.readLine());
+ name = scanner.next();
+ name = scanner.next();
+ scanner.close();
+ return name;
+ }
+
+ public String getFamilyName(int index) throws IOException
+ {
+ String name;
+
+ BufferedReader nameFinder = new BufferedReader(
+ new FileReader(families));
+
+ moveLocationBy(index, nameFinder);
+
+ nameFinder.readLine();
+
+ Scanner scanner = new Scanner(nameFinder.readLine());
+ name = scanner.next();
+ name = scanner.next();
+ name = scanner.next();
+ scanner.close();
+ return name;
+ }
+
+ /**
+ * Prints the specified family to a .hmm file.
+ *
+ * @param index
+ * @throws IOException
+ */
+ public void exportHMM(int index, String location) throws IOException
+ {
+
+
+ BufferedReader br = new BufferedReader(new FileReader(hmms));
+
+ moveLocationBy(index, br);
+
+ String line = br.readLine();
+
+ PrintWriter writer = new PrintWriter(
+ new FileOutputStream(new File(location), true));
+ while (!"//".equals(line))
+ {
+ writer.println(line);
+ line = br.readLine();
+ }
+ writer.println(line);
+ writer.close();
+ br.close();
+
+ }
+
+ /**
+ * Clears all raw, binned and current position data in the current directory.
+ *
+ * @throws FileNotFoundException
+ */
+ public void clear() throws FileNotFoundException
+ {
+ PrintWriter pos = new PrintWriter(
+ currentFolder + "/CurrentPosition.txt");
+ pos.println("0");
+
+ PrintWriter raw = new PrintWriter(currentFolder + RAW);
+
+ PrintWriter bin = new PrintWriter(currentFolder + BINNED);
+
+ pos.close();
+ bin.close();
+ raw.close();
+ }
+
+ public void sortIntoClans(String directory) throws IOException
+ {
+ BufferedReader clanFinder = new BufferedReader(new FileReader(FAMILIESTOCLAN));
+ BufferedReader familyReader = new BufferedReader(
+ new FileReader(families));
+ BufferedReader hmmReader = new BufferedReader(new FileReader(hmms));
+ int families = 0;
+ // moveLocationBy(7000, familyReader);
+ // moveLocationBy(7000, clanFinder);
+ // moveLocationBy(7000, hmmReader);
+ HashMap clanIndexes = new HashMap<>();
+ ArrayList familyCounts = new ArrayList<>();
+ int filePos = 0;
+ int clanCount = 0;
+ String line;
+ line = clanFinder.readLine();
+
+ while (!"".equals(line) && !" ".equals(line) && line != null)
+ {
+ String clanName;
+ boolean inClan = false;
+ while (!(line.indexOf("//") > -1))
+ {
+
+ if (line.indexOf("#=GF CL") > -1)
+ {
+ families++;
+ System.out.println(families);
+ inClan = true;
+ Scanner scanner = new Scanner(line);
+ scanner.next();
+ scanner.next();
+ clanName = scanner.next();
+ scanner.close();
+
+ if (!clanIndexes.containsKey(clanName))
+ {
+ clanIndexes.put(clanName, clanCount);
+ clanCount++;
+ familyCounts.add(0);
+ }
+
+
+ Integer clanI = clanIndexes.get(clanName);
+ String clanPath = directory + "/Clan" + clanI.toString();
+ createFolders(clanPath);
+
+ int index = clanIndexes.get(clanName);
+ exportFile(familyReader,
+ clanPath + "/Families/Fam" + familyCounts.get(index)
+ + ".sto",
+ false);
+ exportFile(hmmReader,
+ clanPath + "/HMMs/HMM" + familyCounts.get(index) + ".hmm",
+ false);
+
+ int count = familyCounts.get(index);
+ count++;
+ familyCounts.set(index, count);
+ }
+ line = clanFinder.readLine();
+
+ }
+ if (!inClan)
+ {
+ moveLocationBy(1, familyReader);
+ moveLocationBy(1, hmmReader);
+ }
+ filePos++;
+ // System.out.println(filePos + " files read.");
+ line = clanFinder.readLine();
+
+ }
+ clanFinder.close();
+
+ for (int clan = 0; clan < clanCount; clan++)
+ {
+ PrintWriter writer = new PrintWriter(
+ directory + "/Clan" + clan + "/NumberOfFamilies.txt");
+ int count = familyCounts.get(clan);
+ writer.print(count);
+ writer.close();
+ }
+
+ }
+
+ public String getFamilies()
+ {
+ return families;
+ }
+
+ public void setFamilies(String families)
+ {
+ this.families = currentFolder + families;
+ }
+
+ public String getHmms()
+ {
+ return hmms;
+ }
+
+ public void setHmms(String hmms)
+ {
+ this.hmms = currentFolder + hmms;
+ }
+
+ public void alignWithinClan(String exportLocation, String clansLocation)
+ throws IOException, InterruptedException
+ {
+ int alignmentsExported = 0;
+ for (int clan = 0; clan < 604; clan++)
+ {
+ System.out.println(clan);
+ int famCount = 0;
+ String clanPath = clansLocation + "/Clan" + clan;
+ int numberOfFamilies;
+ BufferedReader br = new BufferedReader(
+ new FileReader(clanPath + "/NumberOfFamilies.txt"));
+ String line = br.readLine();
+ numberOfFamilies = Integer.parseInt(line);
+ br.close();
+ if (numberOfFamilies == 1)
+ {
+ continue;
+ }
+ final String commandExportLocation = exportLocation + "/Clan" + clan;
+ createFolders(commandExportLocation);
+ for (int family = 0; family < numberOfFamilies; family++)
+ {
+ famCount++;
+ ArrayList indexes = new ArrayList<>();
+ for (int i = 0; i < numberOfFamilies; i++)
+ {
+ if (i != family)
+ {
+ indexes.add(i);
+ }
+ }
+
+ int hmmIndex = getRandom(indexes);
+ String famPath = clanPath + "/Families/Fam" + family + ".sto";
+ String hmmPath = clanPath + "/HMMs/HMM" + hmmIndex + ".hmm";
+ String command = "/media/sf_Shared_Folder/hmmer/binaries/hmmalign --mapali "
+ + clanPath + "/Families/Fam" + hmmIndex + ".sto"
+ + " --trim ";
+ command += hmmPath + " ";
+ command += famPath;
+ final int familyIndex = family;
+ final Process p = Runtime.getRuntime().exec(command);
+
+ new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ BufferedReader input = new BufferedReader(
+ new InputStreamReader(p.getInputStream()));
+ String line = null;
+
+ try
+ {
+ PrintWriter writer = new PrintWriter(commandExportLocation
+ + "/Families/Fam" + familyIndex + ".sto");
+ String lastLine = "";
+ boolean dataFound = false;
+ while ((line = input.readLine()) != null)
+ {
+ if (line.contains("#=GR") && !dataFound)
+ {
+ writer.println(lastLine);
+ dataFound = true;
+ }
+ if (line.contains("#") || dataFound || " ".equals(line)
+ || "".equals(line) || "//".equals(line))
+ {
+ writer.println(line);
+ }
+ lastLine = line;
+ }
+ writer.close();
+ } catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ }).start();
+
+ p.waitFor();
+
+ BufferedReader hmmExporter = new BufferedReader(
+ new FileReader(hmmPath));
+
+ exportFile(hmmExporter,
+ commandExportLocation + "/HMMs/HMM" + family + ".hmm",
+ false);
+
+ alignmentsExported++;
+
+
+ }
+ PrintWriter writer = new PrintWriter(
+ commandExportLocation + "/NumberOfFamilies.txt");
+ writer.print(famCount);
+ writer.close();
+ }
+
+ }
+
+ public boolean atEnd(BufferedReader br) throws IOException
+ {
+ boolean end = false;
+ br.mark(80);
+ String line = br.readLine();
+ if ("".equals(line) || line == null)
+ {
+ end = true;
+ }
+ br.reset();
+ return end;
+ }
+
+ public int getRandom(ArrayList list)
+ {
+ if (!(list.size() > 0))
+ {
+ System.out.println("Error - size = " + list.size());
+ }
+ int index = generator.nextInt(list.size());
+ int value = list.get(index);
+ list.remove(index);
+ return value;
+ }
+
+ public void createFolders(String clanPath)
+ {
+ File clanFolder = new File(clanPath);
+ if (!clanFolder.exists())
+ {
+ clanFolder.mkdir();
+ }
+
+ File famFolder = new File(clanPath + "/Families");
+ File hmmFolder = new File(clanPath + "/HMMs");
+ if (!famFolder.exists())
+ {
+ famFolder.mkdir();
+ hmmFolder.mkdir();
+ }
+ }
+}
+
+
+
+
diff --git a/src/jalview/util/HttpUtils.java b/src/jalview/util/HttpUtils.java
index a5a9460..97c84bc 100644
--- a/src/jalview/util/HttpUtils.java
+++ b/src/jalview/util/HttpUtils.java
@@ -20,6 +20,9 @@
*/
package jalview.util;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
@@ -64,4 +67,46 @@ public class HttpUtils
return false;
}
+ /**
+ * download from given URL and return a pointer to temporary file
+ */
+ public static File fetchURLToTemp(String url) throws OutOfMemoryError,
+ IOException
+ {
+ long time = System.currentTimeMillis();
+ URL rcall = new URL(url);
+
+ InputStream is = new BufferedInputStream(rcall.openStream());
+ File outFile = null;
+ try
+ {
+ outFile = File.createTempFile("jalview", ".xml");
+ outFile.deleteOnExit();
+ if (outFile.length() == 0)
+ {
+ outFile.delete();
+ return null;
+ }
+ } catch (Exception ex)
+ {
+ }
+
+ if (outFile != null)
+ {
+ FileOutputStream fio = new FileOutputStream(outFile);
+ byte[] bb = new byte[32 * 1024];
+ int l;
+ while ((l = is.read(bb)) > 0)
+ {
+ fio.write(bb, 0, l);
+ }
+ fio.close();
+ is.close();
+ return outFile;
+ }
+ else
+ {
+ return null;
+ }
+ }
}
diff --git a/src/jalview/util/MapList.java b/src/jalview/util/MapList.java
index 731e976..986b18c 100644
--- a/src/jalview/util/MapList.java
+++ b/src/jalview/util/MapList.java
@@ -1044,70 +1044,15 @@ public class MapList
for (int[] range : map.getFromRanges())
{
- addRange(range, fromShifts);
+ MappingUtils.addRange(range, fromShifts);
}
for (int[] range : map.getToRanges())
{
- addRange(range, toShifts);
+ MappingUtils.addRange(range, toShifts);
}
}
/**
- * Adds the given range to a list of ranges. If the new range just extends
- * existing ranges, the current endpoint is updated instead.
- *
- * @param range
- * @param addTo
- */
- static void addRange(int[] range, List addTo)
- {
- /*
- * list is empty - add to it!
- */
- if (addTo.size() == 0)
- {
- addTo.add(range);
- return;
- }
-
- int[] last = addTo.get(addTo.size() - 1);
- boolean lastForward = last[1] >= last[0];
- boolean newForward = range[1] >= range[0];
-
- /*
- * contiguous range in the same direction - just update endpoint
- */
- if (lastForward == newForward && last[1] == range[0])
- {
- last[1] = range[1];
- return;
- }
-
- /*
- * next range starts at +1 in forward sense - update endpoint
- */
- if (lastForward && newForward && range[0] == last[1] + 1)
- {
- last[1] = range[1];
- return;
- }
-
- /*
- * next range starts at -1 in reverse sense - update endpoint
- */
- if (!lastForward && !newForward && range[0] == last[1] - 1)
- {
- last[1] = range[1];
- return;
- }
-
- /*
- * just add the new range
- */
- addTo.add(range);
- }
-
- /**
* Returns true if mapping is from forward strand, false if from reverse
* strand. Result is just based on the first 'from' range that is not a single
* position. Default is true unless proven to be false. Behaviour is not well
diff --git a/src/jalview/util/MappingUtils.java b/src/jalview/util/MappingUtils.java
index b552c21..cd8821d 100644
--- a/src/jalview/util/MappingUtils.java
+++ b/src/jalview/util/MappingUtils.java
@@ -1020,4 +1020,59 @@ public final class MappingUtils
}
}
}
+
+ /**
+ * Adds the given range to a list of ranges. If the new range just extends
+ * existing ranges, the current endpoint is updated instead.
+ *
+ * @param range
+ * @param addTo
+ */
+ public static void addRange(int[] range, List addTo)
+ {
+ /*
+ * list is empty - add to it!
+ */
+ if (addTo.size() == 0)
+ {
+ addTo.add(range);
+ return;
+ }
+
+ int[] last = addTo.get(addTo.size() - 1);
+ boolean lastForward = last[1] >= last[0];
+ boolean newForward = range[1] >= range[0];
+
+ /*
+ * contiguous range in the same direction - just update endpoint
+ */
+ if (lastForward == newForward && last[1] == range[0])
+ {
+ last[1] = range[1];
+ return;
+ }
+
+ /*
+ * next range starts at +1 in forward sense - update endpoint
+ */
+ if (lastForward && newForward && range[0] == last[1] + 1)
+ {
+ last[1] = range[1];
+ return;
+ }
+
+ /*
+ * next range starts at -1 in reverse sense - update endpoint
+ */
+ if (!lastForward && !newForward && range[0] == last[1] - 1)
+ {
+ last[1] = range[1];
+ return;
+ }
+
+ /*
+ * just add the new range
+ */
+ addTo.add(range);
+ }
}
diff --git a/src/jalview/util/Platform.java b/src/jalview/util/Platform.java
index c068acc..daaab3a 100644
--- a/src/jalview/util/Platform.java
+++ b/src/jalview/util/Platform.java
@@ -192,7 +192,7 @@ public class Platform
}
/**
- * Check if we are on a Microsoft plaform...
+ * Check if we are on a Microsoft platform...
*
* @return true if we have to cope with another platform variation
*/
diff --git a/src/jalview/util/ProbabilityAnalyserKickstarter.java b/src/jalview/util/ProbabilityAnalyserKickstarter.java
new file mode 100644
index 0000000..59c0a9f
--- /dev/null
+++ b/src/jalview/util/ProbabilityAnalyserKickstarter.java
@@ -0,0 +1,221 @@
+package jalview.util;
+
+import java.io.IOException;
+import java.util.Scanner;
+
+/**
+ * This class contains the brain of the analyser program, and contains a number
+ * of commands for the processing of data.
+ *
+ * @author TZVanaalten
+ *
+ */
+
+public class ProbabilityAnalyserKickstarter
+{
+
+ public static void main(String[] args)
+ throws IOException, InterruptedException
+ {
+
+ // this does all of the processing
+ HMMProbabilityDistributionAnalyser analyser = new HMMProbabilityDistributionAnalyser();
+
+ boolean running = true;
+ System.out.println("ACTIVATED");
+ while (running)
+ {
+ Scanner keyboard = new Scanner(System.in);
+ String command = keyboard.nextLine();
+
+ Scanner inputScanner = new Scanner(command);
+ // prints family to console. Syntax is printFam
+ if (command.indexOf("printFam") > -1)
+ {
+ try
+ {
+ inputScanner.next();
+ int index = inputScanner.nextInt();
+ analyser.printFam(index);
+ continue;
+ } catch (Exception e)
+ {
+ System.out.println("Command failed");
+ }
+
+ }
+ // prints HMM to console. Syntax is printHMM
+ if (command.indexOf("printHMM") > -1)
+ {
+ try
+ {
+ inputScanner.next();
+ int index = inputScanner.nextInt();
+ analyser.printHMM(index);
+ continue;
+ } catch (Exception e)
+ {
+ System.out.println("Command failed");
+ }
+ }
+ // prints family to file in current folder. Syntax is exportFam .
+ if (command.indexOf("exportFam") > -1)
+ {
+ try
+ {
+ inputScanner.next();
+ int index = inputScanner.nextInt();
+ String location = inputScanner.next();
+ analyser.exportFam(index, location);
+ continue;
+ } catch (Exception e)
+ {
+ System.out.println("Command failed");
+ }
+ }
+ // prints HMM to file in current folder. Syntax is exportHMM .
+ if (command.indexOf("exportHMM") > -1)
+ {
+ try
+ {
+ inputScanner.next();
+ int index = inputScanner.nextInt();
+ String location = inputScanner.next();
+ analyser.exportHMM(index, location);
+ continue;
+ } catch (Exception e)
+ {
+ System.out.println("Command failed");
+ }
+ }
+ // Processes data. Syntax is run . The
+ // number loops specifies the number of increments the program will run.
+ // After each increment, the data stored currently in the program is
+ // exported and re-read back into the program. This is to ensure that the
+ // program can be terminated without losing a large quantity of data. The
+ // increment is the number of families read per 'save'.
+ if (command.indexOf("run") > -1 && !(command.indexOf("ToEnd") > -1))
+ {
+ try
+ {
+
+ inputScanner.next();
+
+ int loops = inputScanner.nextInt();
+ int increments = inputScanner.nextInt();
+ boolean keepRaw = inputScanner.nextBoolean();
+
+ for (int i = 0; i < loops; i++)
+ {
+ analyser.run(increments, keepRaw);
+ System.out.println("Saved");
+ }
+ System.out.println("Task completed");
+ continue;
+ } catch (Exception e)
+ {
+ System.out.println("Command failed");
+ }
+ continue;
+ }
+ if ((command.indexOf("runToEnd") > -1))
+ {
+ try
+ {
+
+ inputScanner.next();
+ int minCount = inputScanner.nextInt();
+ int maxCount = inputScanner.nextInt();
+ boolean keepRaw = inputScanner.nextBoolean();
+ boolean forClans = inputScanner.nextBoolean();
+ analyser.runToEnd(minCount, maxCount, keepRaw, forClans);
+ System.out.println("Task completed");
+ } catch (Exception e)
+ {
+ System.out.println("Command failed");
+ }
+ continue;
+ }
+ // terminates program. Syntax is terminate.
+ if (command.indexOf("terminate") > -1)
+ {
+ running = false;
+ continue;
+ }
+ // clears files in current directory (Only a specific set of files).
+ // Syntax is clear.
+ if (command.indexOf("clear") > -1)
+ {
+ analyser.clear();
+ continue;
+ }
+ // changes current directory. Syntax is cd
+ if (command.indexOf("cd") > -1)
+ {
+ try
+ {
+ inputScanner.next();
+ analyser.setFolder(inputScanner.next());
+ } catch (Exception e)
+ {
+ System.out.println("Command failed");
+
+ }
+ continue;
+ }
+
+ if (command.indexOf("getFamName") > -1)
+ {
+ try
+ {
+ inputScanner.next();
+ System.out.println(analyser.getFamilyName(inputScanner.nextInt()));
+
+ } catch (Exception e)
+ {
+ System.out.println("Command failed");
+ }
+ continue;
+ }
+ if (command.indexOf("sortIntoClans") > -1)
+ {
+ inputScanner.next();
+ analyser.sortIntoClans(inputScanner.next());
+ continue;
+
+ }
+ if (command.indexOf("setFamilies") > -1)
+ {
+ inputScanner.next();
+ analyser.setFamilies(inputScanner.next());
+ continue;
+
+ }
+
+ if (command.indexOf("setHMMs") > -1)
+ {
+ inputScanner.next();
+ analyser.setHmms(inputScanner.next());
+ continue;
+
+ }
+
+ if (command.indexOf("alignWithinClans") > -1)
+ {
+ inputScanner.next();
+ String export = inputScanner.next();
+ String clans = inputScanner.next();
+ analyser.alignWithinClan(export, clans);
+ continue;
+
+ }
+
+ System.out.println("Unrecognised command");
+ }
+
+
+
+
+ }
+
+}
diff --git a/src/jalview/util/StringUtils.java b/src/jalview/util/StringUtils.java
index c6af7f0..f0bc177 100644
--- a/src/jalview/util/StringUtils.java
+++ b/src/jalview/util/StringUtils.java
@@ -117,29 +117,6 @@ public class StringUtils
}
/**
- * Returns the last part of 'input' after the last occurrence of 'token'. For
- * example to extract only the filename from a full path or URL.
- *
- * @param input
- * @param token
- * a delimiter which must be in regular expression format
- * @return
- */
- public static String getLastToken(String input, String token)
- {
- if (input == null)
- {
- return null;
- }
- if (token == null)
- {
- return input;
- }
- String[] st = input.split(token);
- return st[st.length - 1];
- }
-
- /**
* Parses the input string into components separated by the delimiter. Unlike
* String.split(), this method will ignore occurrences of the delimiter which
* are nested within single quotes in name-value pair values, e.g. a='b,c'.
diff --git a/src/jalview/viewmodel/AlignmentViewport.java b/src/jalview/viewmodel/AlignmentViewport.java
index 4148c72..4aec9d2 100644
--- a/src/jalview/viewmodel/AlignmentViewport.java
+++ b/src/jalview/viewmodel/AlignmentViewport.java
@@ -24,6 +24,8 @@ import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
import jalview.analysis.Conservation;
import jalview.analysis.TreeModel;
import jalview.api.AlignCalcManagerI;
+import jalview.api.AlignCalcManagerI2;
+import jalview.api.AlignCalcWorkerI;
import jalview.api.AlignExportSettingsI;
import jalview.api.AlignViewportI;
import jalview.api.AlignmentViewPanel;
@@ -57,8 +59,10 @@ import jalview.util.MappingUtils;
import jalview.util.MessageManager;
import jalview.viewmodel.styles.ViewStyle;
import jalview.workers.AlignCalcManager;
+import jalview.workers.AlignCalcManager2;
import jalview.workers.ComplementConsensusThread;
import jalview.workers.ConsensusThread;
+import jalview.workers.InformationThread;
import jalview.workers.StrucConsensusThread;
import java.awt.Color;
@@ -106,6 +110,27 @@ public abstract class AlignmentViewport
* alignment displayed in the viewport. Please use get/setter
*/
protected AlignmentI alignment;
+
+ /*
+ * probably unused indicator that view is of a dataset rather than an
+ * alignment
+ */
+
+ protected boolean ignoreBelowBackGroundFrequencyCalculation = false;
+
+ protected boolean infoLetterHeight = false;
+
+ protected AlignmentAnnotation occupancy;
+
+ /**
+ * results of alignment consensus analysis for visible portion of view
+ */
+ protected ProfilesI consensusProfiles;
+
+ /**
+ * HMM profile for the alignment
+ */
+ protected ProfilesI hmmProfiles;
public AlignmentViewport(AlignmentI al)
{
@@ -593,7 +618,7 @@ public abstract class AlignmentViewport
* alignment
*/
protected boolean isDataset = false;
-
+
public void setDataset(boolean b)
{
isDataset = b;
@@ -636,7 +661,7 @@ public abstract class AlignmentViewport
protected boolean ignoreGapsInConsensusCalculation = false;
protected ResidueShaderI residueShading = new ResidueShader();
-
+
@Override
public void setGlobalColourScheme(ColourSchemeI cs)
{
@@ -710,7 +735,7 @@ public abstract class AlignmentViewport
{
return residueShading;
}
-
+
protected AlignmentAnnotation consensus;
protected AlignmentAnnotation complementConsensus;
@@ -744,7 +769,7 @@ public abstract class AlignmentViewport
protected Hashtable[] hStrucConsensus = null;
protected Conservation hconservation = null;
-
+
@Override
public void setConservation(Conservation cons)
{
@@ -783,6 +808,18 @@ public abstract class AlignmentViewport
}
@Override
+ public void setHmmProfiles(ProfilesI info)
+ {
+ hmmProfiles = info;
+ }
+
+ @Override
+ public ProfilesI getHmmProfiles()
+ {
+ return hmmProfiles;
+ }
+
+ @Override
public Hashtable[] getComplementConsensusHash()
{
return hcomplementConsensus;
@@ -838,7 +875,7 @@ public abstract class AlignmentViewport
return strucConsensus;
}
- protected AlignCalcManagerI calculator = new AlignCalcManager();
+ protected AlignCalcManagerI2 calculator = new AlignCalcManager2();
/**
* trigger update of conservation annotation
@@ -852,8 +889,8 @@ public abstract class AlignmentViewport
{
return;
}
- if (calculator.getRegisteredWorkersOfClass(
- jalview.workers.ConservationThread.class) == null)
+ if (calculator.getWorkersOfClass(
+ jalview.workers.ConservationThread.class).isEmpty())
{
calculator.registerWorker(
new jalview.workers.ConservationThread(this, ap));
@@ -870,8 +907,7 @@ public abstract class AlignmentViewport
{
return;
}
- if (calculator
- .getRegisteredWorkersOfClass(ConsensusThread.class) == null)
+ if (calculator.getWorkersOfClass(ConsensusThread.class).isEmpty())
{
calculator.registerWorker(new ConsensusThread(this, ap));
}
@@ -902,16 +938,23 @@ public abstract class AlignmentViewport
}
if (doConsensus)
{
- if (calculator.getRegisteredWorkersOfClass(
- ComplementConsensusThread.class) == null)
+ if (calculator.getWorkersOfClass(ComplementConsensusThread.class).isEmpty())
{
- calculator
- .registerWorker(new ComplementConsensusThread(this, ap));
+ calculator.registerWorker(new ComplementConsensusThread(this, ap));
}
}
}
}
+ @Override
+ public void initInformationWorker(final AlignmentViewPanel ap)
+ {
+ if (calculator.getWorkersOfClass(InformationThread.class).isEmpty())
+ {
+ calculator.registerWorker(new InformationThread(this, ap));
+ }
+ }
+
// --------START Structure Conservation
public void updateStrucConsensus(final AlignmentViewPanel ap)
{
@@ -927,8 +970,7 @@ public abstract class AlignmentViewport
{
return;
}
- if (calculator.getRegisteredWorkersOfClass(
- StrucConsensusThread.class) == null)
+ if (calculator.getWorkersOfClass(StrucConsensusThread.class).isEmpty())
{
calculator.registerWorker(new StrucConsensusThread(this, ap));
}
@@ -947,7 +989,7 @@ public abstract class AlignmentViewport
{
return false;
}
- if (calculator.workingInvolvedWith(alignmentAnnotation))
+ if (calculator.isWorkingWithAnnotation(alignmentAnnotation))
{
// System.err.println("grey out ("+alignmentAnnotation.label+")");
return true;
@@ -975,12 +1017,14 @@ public abstract class AlignmentViewport
strucConsensus = null;
conservation = null;
quality = null;
+ consensusProfiles = null;
groupConsensus = null;
groupConservation = null;
hconsensus = null;
hconservation = null;
hcomplementConsensus = null;
gapcounts = null;
+ calculator.shutdown();
calculator = null;
residueShading = null; // may hold a reference to Consensus
changeSupport = null;
@@ -999,7 +1043,7 @@ public abstract class AlignmentViewport
}
@Override
- public AlignCalcManagerI getCalcManager()
+ public AlignCalcManagerI2 getCalcManager()
{
return calculator;
}
@@ -1030,6 +1074,21 @@ public abstract class AlignmentViewport
protected boolean showConsensusHistogram = true;
/**
+ * should hmm profile be rendered by default
+ */
+ protected boolean hmmShowSequenceLogo = false;
+
+ /**
+ * should hmm profile be rendered normalised to row height
+ */
+ protected boolean hmmNormaliseSequenceLogo = false;
+
+ /**
+ * should information histograms be rendered by default
+ */
+ protected boolean hmmShowHistogram = true;
+
+ /**
* @return the showConsensusProfile
*/
@Override
@@ -1039,6 +1098,15 @@ public abstract class AlignmentViewport
}
/**
+ * @return the showInformationProfile
+ */
+ @Override
+ public boolean isShowHMMSequenceLogo()
+ {
+ return hmmShowSequenceLogo;
+ }
+
+ /**
* @param showSequenceLogo
* the new value
*/
@@ -1049,13 +1117,31 @@ public abstract class AlignmentViewport
// 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);
+ for (AlignCalcWorkerI worker : calculator.getWorkers())
+ {
+ if (worker.getClass().equals(ConsensusThread.class) ||
+ worker.getClass().equals(ComplementConsensusThread.class) ||
+ worker.getClass().equals(StrucConsensusThread.class))
+ {
+ worker.updateAnnotation();
+ }
+ }
}
this.showSequenceLogo = showSequenceLogo;
}
+ public void setShowHMMSequenceLogo(boolean showHMMSequenceLogo)
+ {
+ if (showHMMSequenceLogo != this.hmmShowSequenceLogo)
+ {
+ this.hmmShowSequenceLogo = showHMMSequenceLogo;
+ // TODO: updateAnnotation if description (tooltip) will show
+ // profile in place of information content?
+ // calculator.updateAnnotationFor(InformationThread.class);
+ }
+ this.hmmShowSequenceLogo = showHMMSequenceLogo;
+ }
+
/**
* @param showConsensusHistogram
* the showConsensusHistogram to set
@@ -1066,6 +1152,14 @@ public abstract class AlignmentViewport
}
/**
+ * @param showInformationHistogram
+ */
+ public void setShowInformationHistogram(boolean showInformationHistogram)
+ {
+ this.hmmShowHistogram = showInformationHistogram;
+ }
+
+ /**
* @return the showGroupConservation
*/
public boolean isShowGroupConservation()
@@ -1111,6 +1205,17 @@ public abstract class AlignmentViewport
}
/**
+ *
+ * @return flag to indicate if the information content histogram should be
+ * rendered by default
+ */
+ @Override
+ public boolean isShowInformationHistogram()
+ {
+ return this.hmmShowHistogram;
+ }
+
+ /**
* when set, updateAlignment will always ensure sequences are of equal length
*/
private boolean padGaps = false;
@@ -1266,7 +1371,16 @@ public abstract class AlignmentViewport
ignoreGapsInConsensusCalculation);
}
}
+ }
+
+ public void setIgnoreBelowBackground(boolean b, AlignmentViewPanel ap)
+ {
+ ignoreBelowBackGroundFrequencyCalculation = b;
+ }
+ public void setInfoLetterHeight(boolean b, AlignmentViewPanel ap)
+ {
+ infoLetterHeight = b;
}
private long sgrouphash = -1, colselhash = -1;
@@ -1324,6 +1438,18 @@ public abstract class AlignmentViewport
return ignoreGapsInConsensusCalculation;
}
+ @Override
+ public boolean isIgnoreBelowBackground()
+ {
+ return ignoreBelowBackGroundFrequencyCalculation;
+ }
+
+ @Override
+ public boolean isInfoLetterHeight()
+ {
+ return infoLetterHeight;
+ }
+
// property change stuff
// JBPNote Prolly only need this in the applet version.
private PropertyChangeSupport changeSupport = new PropertyChangeSupport(
@@ -1902,7 +2028,6 @@ public abstract class AlignmentViewport
updateAllColourSchemes();
calculator.restartWorkers();
- // alignment.adjustSequenceAnnotations();
}
/**
@@ -1955,6 +2080,7 @@ public abstract class AlignmentViewport
MessageManager.getString("label.consensus_descr"),
new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH);
initConsensus(consensus);
+
initGapCounts();
initComplementConsensus();
@@ -2161,6 +2287,9 @@ public abstract class AlignmentViewport
boolean showprf = isShowSequenceLogo();
boolean showConsHist = isShowConsensusHistogram();
boolean normLogo = isNormaliseSequenceLogo();
+ boolean showHMMPrf = isShowHMMSequenceLogo();
+ boolean showInfoHist = isShowInformationHistogram();
+ boolean normHMMLogo = isNormaliseHMMSequenceLogo();
/**
* TODO reorder the annotation rows according to group/sequence ordering on
@@ -2198,6 +2327,9 @@ public abstract class AlignmentViewport
sg.setshowSequenceLogo(showprf);
sg.setShowConsensusHistogram(showConsHist);
sg.setNormaliseSequenceLogo(normLogo);
+ sg.setShowHMMSequenceLogo(showHMMPrf);
+ sg.setShowInformationHistogram(showInfoHist);
+ sg.setNormaliseHMMSequenceLogo(normHMMLogo);
}
if (conv)
{
@@ -2982,6 +3114,19 @@ public abstract class AlignmentViewport
return sq;
}
+ public boolean hasReferenceAnnotation()
+ {
+ AlignmentAnnotation[] annots = this.alignment.getAlignmentAnnotation();
+ for (AlignmentAnnotation annot : annots)
+ {
+ if ("RF".equals(annot.label) || annot.label.contains("Reference"))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
@Override
public void setCurrentTree(TreeModel tree)
{
@@ -3024,6 +3169,27 @@ public abstract class AlignmentViewport
return ed;
}
+ @Override
+ public boolean isNormaliseSequenceLogo()
+ {
+ return normaliseSequenceLogo;
+ }
+
+ public void setNormaliseSequenceLogo(boolean state)
+ {
+ normaliseSequenceLogo = state;
+ }
+
+ @Override
+ public boolean isNormaliseHMMSequenceLogo()
+ {
+ return hmmNormaliseSequenceLogo;
+ }
+
+ public void setNormaliseHMMSequenceLogo(boolean state)
+ {
+ hmmNormaliseSequenceLogo = state;
+ }
/**
* flag set to indicate if structure views might be out of sync with sequences
* in the alignment
@@ -3087,7 +3253,47 @@ public abstract class AlignmentViewport
codingComplement.setUpdateStructures(needToUpdateStructureViews);
}
}
-
+ /**
+ * Filters out sequences with an eValue higher than the specified value. The
+ * filtered sequences are hidden or deleted. Sequences with no eValues are also
+ * filtered out.
+ *
+ * @param eValue
+ * @param delete
+ */
+ public void filterByEvalue(double eValue)
+ {
+ for (SequenceI seq : alignment.getSequencesArray())
+ {
+ if ((seq.getAnnotation("Search Scores") == null
+ || seq.getAnnotation("Search Scores")[0].getEValue() > eValue)
+ && seq.getHMM() == null)
+ {
+ hideSequence(new SequenceI[] { seq });
+ }
+ }
+ }
+
+ /**
+ * Filters out sequences with an score lower than the specified value. The
+ * filtered sequences are hidden or deleted.
+ *
+ * @param score
+ * @param delete
+ */
+ public void filterByScore(double score)
+ {
+ for (SequenceI seq : alignment.getSequencesArray())
+ {
+ if ((seq.getAnnotation("Search Scores") == null
+ || seq.getAnnotation("Search Scores")[0]
+ .getBitScore() < score)
+ && seq.getHMM() == null)
+ {
+ hideSequence(new SequenceI[] { seq });
+ }
+ }
+ }
/**
* Notify TreePanel and AlignmentPanel of some sort of alignment change.
@@ -3104,5 +3310,4 @@ public abstract class AlignmentViewport
{
changeSupport.firePropertyChange(PROPERTY_SEQUENCE, null, null);
}
-
}
diff --git a/src/jalview/workers/AlignCalcManager.java b/src/jalview/workers/AlignCalcManager.java
index c596f05..ec80576 100644
--- a/src/jalview/workers/AlignCalcManager.java
+++ b/src/jalview/workers/AlignCalcManager.java
@@ -22,10 +22,12 @@ package jalview.workers;
import jalview.api.AlignCalcManagerI;
import jalview.api.AlignCalcWorkerI;
+import jalview.bin.Cache;
import jalview.datamodel.AlignmentAnnotation;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
@@ -37,48 +39,49 @@ public class AlignCalcManager implements AlignCalcManagerI
/*
* list of registered workers
*/
- private volatile List restartable;
+ private final List