();
+ otherDetails = new HashMap<>();
}
otherDetails.put(key, value);
@@ -463,8 +458,8 @@ public class SequenceFeature implements FeatureLocationI
.getAttributeName(key);
}
- FeatureAttributes.getInstance().addAttribute(this.type, key, attDesc,
- value.toString());
+ FeatureAttributes.getInstance().addAttribute(this.type, attDesc, value,
+ key);
}
/*
@@ -642,30 +637,33 @@ public class SequenceFeature implements FeatureLocationI
{
continue; // to avoid double reporting
}
- if (INFO_KEYS.containsKey(key))
+
+ Object value = entry.getValue();
+ if (value instanceof Map, ?>)
{
/*
- * split selected INFO data by delimiter over multiple lines
+ * expand values in a Map attribute across separate lines
*/
- String delimiter = INFO_KEYS.get(key);
- String[] values = entry.getValue().toString().split(delimiter);
- for (String value : values)
+ Map, ?> values = (Map, ?>) value;
+ for (Entry, ?> e : values.entrySet())
{
- sb.append(String.format(ROW_DATA, key, "", value));
+ sb.append(String.format(ROW_DATA, key, e.getKey().toString(), e
+ .getValue().toString()));
}
}
else
- { // tried but it failed to provide a tooltip :-(
+ {
+ // tried | but it failed to provide a tooltip :-(
String attDesc = null;
if (metadata != null)
{
attDesc = metadata.getAttributeName(key);
}
- String value = entry.getValue().toString();
- if (isValueInteresting(key, value, metadata))
+ String s = entry.getValue().toString();
+ if (isValueInteresting(key, s, metadata))
{
sb.append(String.format(ROW_DATA, key, attDesc == null ? ""
- : attDesc, value));
+ : attDesc, s));
}
}
}
diff --git a/src/jalview/datamodel/SequenceI.java b/src/jalview/datamodel/SequenceI.java
index 28be85f..c064373 100755
--- a/src/jalview/datamodel/SequenceI.java
+++ b/src/jalview/datamodel/SequenceI.java
@@ -450,17 +450,6 @@ public interface SequenceI extends ASequenceI
public void transferAnnotation(SequenceI entry, Mapping mp);
/**
- * @param index
- * The sequence index in the MSA
- */
- public void setIndex(int index);
-
- /**
- * @return The index of the sequence in the alignment
- */
- public int getIndex();
-
- /**
* @return The RNA of the sequence in the alignment
*/
diff --git a/src/jalview/datamodel/features/FeatureAttributes.java b/src/jalview/datamodel/features/FeatureAttributes.java
index 3dc4f19..7221d62 100644
--- a/src/jalview/datamodel/features/FeatureAttributes.java
+++ b/src/jalview/datamodel/features/FeatureAttributes.java
@@ -2,9 +2,11 @@ package jalview.datamodel.features;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.TreeMap;
/**
@@ -14,7 +16,45 @@ public class FeatureAttributes
{
private static FeatureAttributes instance = new FeatureAttributes();
- private Map> attributes;
+ /*
+ * map, by feature type, of a map, by attribute name, of
+ * attribute description and min-max range (if known)
+ */
+ private Map> attributes;
+
+ /*
+ * a case-insensitive comparator so that attributes are ordered e.g.
+ * AC
+ * af
+ * CSQ:AFR_MAF
+ * CSQ:Allele
+ */
+ private Comparator comparator = new Comparator()
+ {
+ @Override
+ public int compare(String[] o1, String[] o2)
+ {
+ int i = 0;
+ while (i < o1.length || i < o2.length)
+ {
+ if (o2.length <= i)
+ {
+ return o1.length <= i ? 0 : 1;
+ }
+ if (o1.length <= i)
+ {
+ return -1;
+ }
+ int comp = String.CASE_INSENSITIVE_ORDER.compare(o1[i], o2[i]);
+ if (comp != 0)
+ {
+ return comp;
+ }
+ i++;
+ }
+ return 0; // same length and all matched
+ }
+ };
private class AttributeData
{
@@ -116,17 +156,19 @@ public class FeatureAttributes
}
/**
- * Answers the attributes known for the given feature type, in alphabetical
- * order (not case sensitive), or an empty set if no attributes are known
+ * Answers the attribute names known for the given feature type, in
+ * alphabetical order (not case sensitive), or an empty set if no attributes
+ * are known. An attribute name is typically 'simple' e.g. "AC", but may be
+ * 'compound' e.g. {"CSQ", "Allele"} where a feature has map-valued attributes
*
* @param featureType
* @return
*/
- public List getAttributes(String featureType)
+ public List getAttributes(String featureType)
{
if (!attributes.containsKey(featureType))
{
- return Collections. emptyList();
+ return Collections. emptyList();
}
return new ArrayList<>(attributes.get(featureType).keySet());
@@ -156,23 +198,39 @@ public class FeatureAttributes
* type, and updates the min-max for any numeric value
*
* @param featureType
- * @param attName
* @param description
* @param value
+ * @param attName
*/
- public void addAttribute(String featureType, String attName,
- String description, String value)
+ public void addAttribute(String featureType, String description,
+ Object value, String... attName)
{
if (featureType == null || attName == null)
{
return;
}
- Map atts = attributes.get(featureType);
+ /*
+ * if attribute value is a map, drill down one more level to
+ * record its sub-fields
+ */
+ if (value instanceof Map, ?>)
+ {
+ for (Entry, ?> entry : ((Map, ?>) value).entrySet())
+ {
+ String[] attNames = new String[attName.length + 1];
+ System.arraycopy(attName, 0, attNames, 0, attName.length);
+ attNames[attName.length] = entry.getKey().toString();
+ addAttribute(featureType, description, entry.getValue(), attNames);
+ }
+ return;
+ }
+
+ String valueAsString = value.toString();
+ Map atts = attributes.get(featureType);
if (atts == null)
{
- atts = new TreeMap(
- String.CASE_INSENSITIVE_ORDER);
+ atts = new TreeMap<>(comparator);
attributes.put(featureType, atts);
}
AttributeData attData = atts.get(attName);
@@ -181,7 +239,7 @@ public class FeatureAttributes
attData = new AttributeData();
atts.put(attName, attData);
}
- attData.addInstance(description, value);
+ attData.addInstance(description, valueAsString);
}
/**
@@ -192,10 +250,10 @@ public class FeatureAttributes
* @param attName
* @return
*/
- public String getDescription(String featureType, String attName)
+ public String getDescription(String featureType, String... attName)
{
String desc = null;
- Map atts = attributes.get(featureType);
+ Map atts = attributes.get(featureType);
if (atts != null)
{
AttributeData attData = atts.get(attName);
@@ -217,9 +275,9 @@ public class FeatureAttributes
* @param attName
* @return
*/
- public float[] getMinMax(String featureType, String attName)
+ public float[] getMinMax(String featureType, String... attName)
{
- Map atts = attributes.get(featureType);
+ Map atts = attributes.get(featureType);
if (atts != null)
{
AttributeData attData = atts.get(attName);
@@ -238,19 +296,18 @@ public class FeatureAttributes
* @param attName
* @param description
*/
- public void addDescription(String featureType, String attName,
- String description)
+ public void addDescription(String featureType, String description,
+ String... attName)
{
if (featureType == null || attName == null)
{
return;
}
- Map atts = attributes.get(featureType);
+ Map atts = attributes.get(featureType);
if (atts == null)
{
- atts = new TreeMap(
- String.CASE_INSENSITIVE_ORDER);
+ atts = new TreeMap<>(comparator);
attributes.put(featureType, atts);
}
AttributeData attData = atts.get(attName);
diff --git a/src/jalview/ext/ensembl/EnsemblGenomes.java b/src/jalview/ext/ensembl/EnsemblGenomes.java
index b40df50..bbd1f26 100644
--- a/src/jalview/ext/ensembl/EnsemblGenomes.java
+++ b/src/jalview/ext/ensembl/EnsemblGenomes.java
@@ -44,11 +44,13 @@ public class EnsemblGenomes extends EnsemblGene
return "EnsemblGenomes";
}
- private String Wrong[];
@Override
public String getTestQuery()
{
- return "DDB_G0283883";
+ /*
+ * Salmonella gene, Uniprot Q8Z9G6, EMBLCDS CAD01290
+ */
+ return "CAD01290";
}
@Override
diff --git a/src/jalview/fts/api/GFTSPanelI.java b/src/jalview/fts/api/GFTSPanelI.java
index 99c0c51..974cc88 100644
--- a/src/jalview/fts/api/GFTSPanelI.java
+++ b/src/jalview/fts/api/GFTSPanelI.java
@@ -145,4 +145,11 @@ public interface GFTSPanelI
* @return
*/
public String getCacheKey();
+
+ /**
+ *
+ * @return user preference name for configuring this FTS search's autosearch
+ * checkbox
+ */
+ public String getAutosearchPreference();
}
diff --git a/src/jalview/fts/core/GFTSPanel.java b/src/jalview/fts/core/GFTSPanel.java
index c0d005f..9802d4b 100644
--- a/src/jalview/fts/core/GFTSPanel.java
+++ b/src/jalview/fts/core/GFTSPanel.java
@@ -56,6 +56,7 @@ import java.util.List;
import javax.swing.ImageIcon;
import javax.swing.JButton;
+import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
@@ -88,6 +89,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
protected JInternalFrame mainFrame = new JInternalFrame(
getFTSFrameTitle());
+ protected JTabbedPane tabs = new JTabbedPane();
protected IProgressIndicator progressIndicator;
protected JComboBox cmb_searchTarget = new JComboBox();
@@ -98,6 +100,8 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
protected JButton btn_cancel = new JButton();
+ protected JCheckBox btn_autosearch = new JCheckBox();
+
protected JvCacheableInputBox txt_search;
protected SequenceFetcher seqFetcher;
@@ -239,16 +243,38 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
public GFTSPanel()
{
+ this(null);
+ }
+
+ public GFTSPanel(SequenceFetcher fetcher)
+ {
try
{
+ if (fetcher == null)
+ {
+ tabs = null;
+ }
jbInit();
+ if (fetcher != null)
+ {
+ tabs.addTab(MessageManager.getString("label.retrieve_ids"),
+ fetcher);
+ fetcher.setDatabaseChooserVisible(false);
+ fetcher.embedWithFTSPanel(this);
+ }
mainFrame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
+ final JPanel ftsPanel = this;
mainFrame.addFocusListener(new FocusAdapter()
{
@Override
public void focusGained(FocusEvent e)
{
- txt_search.requestFocusInWindow();
+ // TODO: make selected tab gain focus in correct widget
+ if (tabs != null
+ && tabs.getSelectedComponent() == ftsPanel)
+ {
+ txt_search.requestFocusInWindow();
+ }
}
});
mainFrame.invalidate();
@@ -331,6 +357,20 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
}
});
+ btn_autosearch.setText(MessageManager.getString("option.autosearch"));
+ btn_autosearch.setToolTipText(
+ MessageManager.getString("option.enable_disable_autosearch"));
+ btn_autosearch.setSelected(
+ jalview.bin.Cache.getDefault(getAutosearchPreference(), true));
+ btn_autosearch.addActionListener(new java.awt.event.ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ jalview.bin.Cache.setProperty(getAutosearchPreference(),
+ Boolean.toString(btn_autosearch.isSelected()));
+ }
+ });
btn_back.setFont(new java.awt.Font("Verdana", 0, 12));
btn_back.setText(MessageManager.getString("action.back"));
btn_back.addActionListener(new java.awt.event.ActionListener()
@@ -511,8 +551,14 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
if (primaryKeyName.equalsIgnoreCase(getCmbSearchTarget()
.getSelectedItem().toString()))
{
+ // TODO: nicer to show the list in the result set before
+ // viewing in Jalview perhaps ?
transferToSequenceFetcher(getTypedText());
}
+ else
+ {
+ performSearchAction();
+ }
}
}
});
@@ -522,12 +568,10 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
@Override
public void actionPerformed(ActionEvent e)
{
- String typed = getTypedText();
- if (!typed.equalsIgnoreCase(lastSearchTerm))
+ if (btn_autosearch.isSelected()
+ || txt_search.wasEnterPressed())
{
- searchAction(true);
- paginatorCart.clear();
- lastSearchTerm = typed;
+ performSearchAction();
}
}
}, false);
@@ -549,6 +593,15 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
}
});
+ txt_search.addActionListener(new ActionListener()
+ {
+
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ performSearchAction();
+ }
+ });
final String searchTabTitle = MessageManager
.getString("label.search_result");
final String configureCols = MessageManager
@@ -613,6 +666,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
pnl_results.add(tabbedPane);
pnl_inputs.add(cmb_searchTarget);
pnl_inputs.add(txt_search);
+ pnl_inputs.add(btn_autosearch);
pnl_inputs.add(lbl_loading);
pnl_inputs.add(lbl_warning);
pnl_inputs.add(lbl_blank);
@@ -624,7 +678,17 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
this.add(pnl_results, java.awt.BorderLayout.CENTER);
this.add(pnl_actions, java.awt.BorderLayout.SOUTH);
mainFrame.setVisible(true);
- mainFrame.setContentPane(this);
+ if (tabs != null)
+ {
+ tabs.setOpaque(true);
+ tabs.insertTab("Free Text Search", null, this, "", 0);
+ mainFrame.setContentPane(tabs);
+ tabs.setVisible(true);
+ }
+ else
+ {
+ mainFrame.setContentPane(this);
+ }
mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
mainFrame.addInternalFrameListener(
new javax.swing.event.InternalFrameAdapter()
@@ -635,8 +699,6 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
closeAction();
}
});
- mainFrame.setVisible(true);
- mainFrame.setContentPane(this);
mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
Integer x = getTempUserPrefs().get("FTSPanel.x");
Integer y = getTempUserPrefs().get("FTSPanel.y");
@@ -698,6 +760,18 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
}
+ void performSearchAction()
+ {
+ String typed = getTypedText();
+ if (typed != null && typed.length() > 0
+ && !typed.equalsIgnoreCase(lastSearchTerm))
+ {
+ searchAction(true);
+ paginatorCart.clear();
+ lastSearchTerm = typed;
+ }
+ }
+
public boolean wantedFieldsUpdated()
{
if (previousWantedFields == null)
@@ -774,7 +848,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
}
}
- protected void btn_back_ActionPerformed()
+ public void btn_back_ActionPerformed()
{
closeAction();
new SequenceFetcher(progressIndicator);
@@ -787,7 +861,7 @@ public abstract class GFTSPanel extends JPanel implements GFTSPanelI
btn_cancel.setEnabled(false);
}
- protected void btn_cancel_ActionPerformed()
+ public void btn_cancel_ActionPerformed()
{
closeAction();
}
diff --git a/src/jalview/fts/service/pdb/PDBFTSPanel.java b/src/jalview/fts/service/pdb/PDBFTSPanel.java
index 19f7db4..053d91b 100644
--- a/src/jalview/fts/service/pdb/PDBFTSPanel.java
+++ b/src/jalview/fts/service/pdb/PDBFTSPanel.java
@@ -43,9 +43,11 @@ public class PDBFTSPanel extends GFTSPanel
private static final String PDB_FTS_CACHE_KEY = "CACHE.PDB_FTS";
+ private static final String PDB_AUTOSEARCH = "FTS.PDB.AUTOSEARCH";
+
public PDBFTSPanel(SequenceFetcher fetcher)
{
- super();
+ super(fetcher);
pageLimit = PDBFTSRestClient.getInstance().getDefaultResponsePageSize();
this.seqFetcher = fetcher;
this.progressIndicator = (fetcher == null) ? null
@@ -281,4 +283,9 @@ public class PDBFTSPanel extends GFTSPanel
return PDB_FTS_CACHE_KEY;
}
-}
+ @Override
+ public String getAutosearchPreference()
+ {
+ return PDB_AUTOSEARCH;
+ }
+}
\ No newline at end of file
diff --git a/src/jalview/fts/service/uniprot/UniprotFTSPanel.java b/src/jalview/fts/service/uniprot/UniprotFTSPanel.java
index 020331a..df54dea 100644
--- a/src/jalview/fts/service/uniprot/UniprotFTSPanel.java
+++ b/src/jalview/fts/service/uniprot/UniprotFTSPanel.java
@@ -44,9 +44,11 @@ public class UniprotFTSPanel extends GFTSPanel
private static final String UNIPROT_FTS_CACHE_KEY = "CACHE.UNIPROT_FTS";
+ private static final String UNIPROT_AUTOSEARCH = "FTS.UNIPROT.AUTOSEARCH";
+
public UniprotFTSPanel(SequenceFetcher fetcher)
{
- super();
+ super(fetcher);
pageLimit = UniProtFTSRestClient.getInstance()
.getDefaultResponsePageSize();
this.seqFetcher = fetcher;
@@ -237,4 +239,10 @@ public class UniprotFTSPanel extends GFTSPanel
{
return UNIPROT_FTS_CACHE_KEY;
}
+
+ @Override
+ public String getAutosearchPreference()
+ {
+ return UNIPROT_AUTOSEARCH;
+ }
}
diff --git a/src/jalview/gui/AlignViewport.java b/src/jalview/gui/AlignViewport.java
index 90271c8..4d09084 100644
--- a/src/jalview/gui/AlignViewport.java
+++ b/src/jalview/gui/AlignViewport.java
@@ -583,58 +583,6 @@ public class AlignViewport extends AlignmentViewport
.getStructureSelectionManager(Desktop.instance);
}
- /**
- *
- * @param pdbEntries
- * @return an array of SequenceI arrays, one for each PDBEntry, listing which
- * sequences in the alignment hold a reference to it
- */
- public SequenceI[][] collateForPDB(PDBEntry[] pdbEntries)
- {
- List seqvectors = new ArrayList();
- for (PDBEntry pdb : pdbEntries)
- {
- List choosenSeqs = new ArrayList();
- for (SequenceI sq : alignment.getSequences())
- {
- Vector pdbRefEntries = sq.getDatasetSequence()
- .getAllPDBEntries();
- if (pdbRefEntries == null)
- {
- continue;
- }
- for (PDBEntry pdbRefEntry : pdbRefEntries)
- {
- if (pdbRefEntry.getId().equals(pdb.getId()))
- {
- if (pdbRefEntry.getChainCode() != null
- && pdb.getChainCode() != null)
- {
- if (pdbRefEntry.getChainCode().equalsIgnoreCase(
- pdb.getChainCode()) && !choosenSeqs.contains(sq))
- {
- choosenSeqs.add(sq);
- continue;
- }
- }
- else
- {
- if (!choosenSeqs.contains(sq))
- {
- choosenSeqs.add(sq);
- continue;
- }
- }
-
- }
- }
- }
- seqvectors
- .add(choosenSeqs.toArray(new SequenceI[choosenSeqs.size()]));
- }
- return seqvectors.toArray(new SequenceI[seqvectors.size()][]);
- }
-
@Override
public boolean isNormaliseSequenceLogo()
{
diff --git a/src/jalview/gui/FeatureColourChooser.java b/src/jalview/gui/FeatureColourChooser.java
index 6280a64..da3819c 100644
--- a/src/jalview/gui/FeatureColourChooser.java
+++ b/src/jalview/gui/FeatureColourChooser.java
@@ -57,8 +57,16 @@ import javax.swing.event.ChangeListener;
public class FeatureColourChooser extends JalviewDialog
{
+ private static final String COLON = ":";
+
private static final int MAX_TOOLTIP_LENGTH = 50;
+ private static int NO_COLOUR_OPTION = 0;
+
+ private static int MIN_COLOUR_OPTION = 1;
+
+ private static int MAX_COLOUR_OPTION = 2;
+
private FeatureRenderer fr;
private FeatureColourI cs;
@@ -157,9 +165,8 @@ public class FeatureColourChooser extends JalviewDialog
this.fr = frender;
this.type = theType;
ap = fr.ap;
- String title = MessageManager
- .formatMessage("label.graduated_color_for_params", new String[]
- { theType });
+ String title = MessageManager.formatMessage("label.variable_color_for",
+ new String[] { theType });
initDialogFrame(this, true, blocking, title, 470, 300);
slider.addChangeListener(new ChangeListener()
@@ -190,6 +197,7 @@ public class FeatureColourChooser extends JalviewDialog
}
});
+ // todo move all threshold setup inside a method
float mm[] = fr.getMinMax().get(theType)[0];
min = mm[0];
max = mm[1];
@@ -231,6 +239,8 @@ public class FeatureColourChooser extends JalviewDialog
}
minColour.setBackground(oldminColour = cs.getMinColour());
maxColour.setBackground(oldmaxColour = cs.getMaxColour());
+ noColour = cs.getNoColour();
+
adjusting = true;
try
@@ -245,15 +255,15 @@ public class FeatureColourChooser extends JalviewDialog
/*
* set the initial state of options on screen
*/
- thresholdIsMin.setSelected(!cs.isAutoScaled());
-
if (cs.isColourByLabel())
{
if (cs.isColourByAttribute())
{
byAttributeText.setSelected(true);
textAttributeCombo.setEnabled(true);
- textAttributeCombo.setSelectedItem(cs.getAttributeName());
+ String[] attributeName = cs.getAttributeName();
+ textAttributeCombo
+ .setSelectedItem(String.join(COLON, attributeName));
}
else
{
@@ -266,8 +276,9 @@ public class FeatureColourChooser extends JalviewDialog
if (cs.isColourByAttribute())
{
byAttributeValue.setSelected(true);
- String attributeName = cs.getAttributeName();
- valueAttributeCombo.setSelectedItem(attributeName);
+ String[] attributeName = cs.getAttributeName();
+ valueAttributeCombo
+ .setSelectedItem(String.join(COLON, attributeName));
valueAttributeCombo.setEnabled(true);
updateMinMax();
}
@@ -278,6 +289,19 @@ public class FeatureColourChooser extends JalviewDialog
}
}
+ if (noColour == null)
+ {
+ noValueCombo.setSelectedIndex(NO_COLOUR_OPTION);
+ }
+ else if (noColour.equals(oldminColour))
+ {
+ noValueCombo.setSelectedIndex(MIN_COLOUR_OPTION);
+ }
+ else if (noColour.equals(oldmaxColour))
+ {
+ noValueCombo.setSelectedIndex(MAX_COLOUR_OPTION);
+ }
+
threshline = new GraphLine((max - min) / 2f, "Threshold", Color.black);
threshline.value = cs.getThreshold();
@@ -369,7 +393,8 @@ public class FeatureColourChooser extends JalviewDialog
else if (byAttributeValue.isSelected())
{
String attName = (String) valueAttributeCombo.getSelectedItem();
- minMax = FeatureAttributes.getInstance().getMinMax(type, attName);
+ String[] attNames = attName.split(COLON);
+ minMax = FeatureAttributes.getInstance().getMinMax(type, attNames);
}
if (minMax != null)
{
@@ -408,8 +433,8 @@ public class FeatureColourChooser extends JalviewDialog
byAttributeValue.addActionListener(changeMinMaxAction);
byWhatPanel.add(byAttributeValue);
- List attNames = FeatureAttributes.getInstance().getAttributes(
- type);
+ List attNames = FeatureAttributes.getInstance()
+ .getAttributes(type);
valueAttributeCombo = populateAttributesDropdown(type, attNames, true);
/*
@@ -555,21 +580,21 @@ public class FeatureColourChooser extends JalviewDialog
}
/**
- * Action on user choice of no / min / max colour when there is no value to
- * colour by
+ * Action on user choice of no / min / max colour to use when there is no
+ * value to colour by
*/
protected void setNoValueColour()
{
int i = noValueCombo.getSelectedIndex();
- if (i == 0)
+ if (i == NO_COLOUR_OPTION)
{
noColour = null;
}
- else if (i == 1)
+ else if (i == MIN_COLOUR_OPTION)
{
noColour = minColour.getBackground();
}
- else if (i == 2)
+ else if (i == MAX_COLOUR_OPTION)
{
noColour = maxColour.getBackground();
}
@@ -612,8 +637,8 @@ public class FeatureColourChooser extends JalviewDialog
byAttributeText.addActionListener(changeColourAction);
byTextPanel.add(byAttributeText);
- List attNames = FeatureAttributes.getInstance().getAttributes(
- type);
+ List attNames = FeatureAttributes.getInstance()
+ .getAttributes(type);
textAttributeCombo = populateAttributesDropdown(type, attNames, false);
byTextPanel.add(textAttributeCombo);
@@ -715,13 +740,18 @@ public class FeatureColourChooser extends JalviewDialog
{
attribute = (String) textAttributeCombo.getSelectedItem();
textAttributeCombo.setEnabled(true);
+ acg.setAttributeName(attribute.split(COLON));
}
else if (byAttributeValue.isSelected())
{
attribute = (String) valueAttributeCombo.getSelectedItem();
valueAttributeCombo.setEnabled(true);
+ acg.setAttributeName(attribute.split(COLON));
+ }
+ else
+ {
+ acg.setAttributeName((String) null);
}
- acg.setAttributeName(attribute);
if (!hasThreshold)
{
@@ -798,6 +828,7 @@ public class FeatureColourChooser extends JalviewDialog
maxColour.setForeground(oldmaxColour);
minColour.setBackground(oldminColour);
minColour.setForeground(oldminColour);
+ noColour = oldNoColour;
}
/*
@@ -912,23 +943,26 @@ public class FeatureColourChooser extends JalviewDialog
/**
* A helper method to build the drop-down choice of attributes for a feature.
* Where metadata is available with a description for an attribute, that is
- * added as a tooltip. The list may be restricted to attributes for which we
- * hold a range of numerical values (so suitable candidates for a graduated
- * colour scheme).
+ * added as a tooltip. The list may optionally be restricted to attributes for
+ * which we hold a range of numerical values (so suitable candidates for a
+ * graduated colour scheme).
+ *
+ * Attribute names may be 'simple' e.g. "AC" or 'compound' e.g. {"CSQ",
+ * "Allele"}. Compound names are rendered for display as (e.g.) CSQ:Allele.
*
* @param featureType
* @param attNames
* @param withNumericRange
*/
protected JComboBox populateAttributesDropdown(
- String featureType, List attNames,
+ String featureType, List attNames,
boolean withNumericRange)
{
List validAtts = new ArrayList<>();
List tooltips = new ArrayList<>();
FeatureAttributes fa = FeatureAttributes.getInstance();
- for (String attName : attNames)
+ for (String[] attName : attNames)
{
if (withNumericRange)
{
@@ -938,7 +972,7 @@ public class FeatureColourChooser extends JalviewDialog
continue;
}
}
- validAtts.add(attName);
+ validAtts.add(String.join(COLON, attName));
String desc = fa.getDescription(featureType, attName);
if (desc != null && desc.length() > MAX_TOOLTIP_LENGTH)
{
diff --git a/src/jalview/gui/FeatureSettings.java b/src/jalview/gui/FeatureSettings.java
index 4e4d2cb..ed98830 100644
--- a/src/jalview/gui/FeatureSettings.java
+++ b/src/jalview/gui/FeatureSettings.java
@@ -53,6 +53,7 @@ import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridLayout;
+import java.awt.LayoutManager;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
@@ -119,6 +120,8 @@ import javax.swing.table.TableCellRenderer;
public class FeatureSettings extends JPanel
implements FeatureSettingsControllerI
{
+ private static final String COLON = ":";
+
private static final int MIN_WIDTH = 400;
private static final int MIN_HEIGHT = 400;
@@ -199,6 +202,9 @@ public class FeatureSettings extends JPanel
private JTextArea filtersAsText;
+ // set white normally, black to debug layout
+ private Color debugBorderColour = Color.white;
+
/**
* Constructor
*
@@ -1371,6 +1377,7 @@ public class FeatureSettings extends JPanel
*/
JPanel andOrPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
andOrPanel.setBackground(Color.white);
+ andOrPanel.setBorder(BorderFactory.createLineBorder(debugBorderColour));
andFilters = new JRadioButton("And");
orFilters = new JRadioButton("Or");
ActionListener actionListener = new ActionListener()
@@ -1397,8 +1404,9 @@ public class FeatureSettings extends JPanel
* panel with filters - populated by refreshFiltersDisplay
*/
chooseFiltersPanel = new JPanel();
- chooseFiltersPanel.setLayout(new BoxLayout(chooseFiltersPanel,
- BoxLayout.Y_AXIS));
+ LayoutManager box = new BoxLayout(chooseFiltersPanel,
+ BoxLayout.Y_AXIS);
+ chooseFiltersPanel.setLayout(box);
filtersPanel.add(chooseFiltersPanel);
/*
@@ -1454,12 +1462,12 @@ public class FeatureSettings extends JPanel
}
if (!found)
{
- filteredFeatureChoice // todo i18n
- .addItem("No filterable feature attributes known");
+ filteredFeatureChoice.addItem(MessageManager
+ .getString("label.no_feature_attributes"));
+ filteredFeatureChoice.setEnabled(false);
}
filteredFeatureChoice.addItemListener(listener);
-
}
/**
@@ -1480,8 +1488,8 @@ public class FeatureSettings extends JPanel
* look up attributes known for feature type
*/
String selectedType = (String) filteredFeatureChoice.getSelectedItem();
- List attNames = FeatureAttributes.getInstance().getAttributes(
- selectedType);
+ List attNames = FeatureAttributes.getInstance()
+ .getAttributes(selectedType);
/*
* if this feature type has filters set, load them first
@@ -1501,7 +1509,8 @@ public class FeatureSettings extends JPanel
/*
* and an empty filter for the user to populate (add)
*/
- KeyedMatcherI noFilter = new KeyedMatcher("", Condition.values()[0], "");
+ KeyedMatcherI noFilter = new KeyedMatcher(Condition.values()[0], "",
+ (String) null);
filters.add(noFilter);
/*
@@ -1510,14 +1519,16 @@ public class FeatureSettings extends JPanel
int filterIndex = 0;
for (KeyedMatcherI filter : filters)
{
- String key = filter.getKey();
+ String[] attName = filter.getKey();
Condition condition = filter.getMatcher()
.getCondition();
String pattern = filter.getMatcher().getPattern();
- JPanel row = addFilter(key, attNames, condition, pattern, filterIndex);
+ JPanel row = addFilter(attName, attNames, condition, pattern, filterIndex);
+ row.setBorder(BorderFactory.createLineBorder(debugBorderColour));
chooseFiltersPanel.add(row);
filterIndex++;
}
+ // chooseFiltersPanel.add(Box.createVerticalGlue());
filtersPane.validate();
filtersPane.repaint();
@@ -1531,27 +1542,24 @@ public class FeatureSettings extends JPanel
* a text field for input of a match pattern
* optionally, a 'remove' button
*
- * If attribute, condition or pattern are not null, they are set as defaults
- * for the input fields. The 'remove' button is added unless the pattern is
- * null or empty (incomplete filter condition).
+ * If attribute, condition or pattern are not null, they are set as defaults for
+ * the input fields. The 'remove' button is added unless the pattern is null or
+ * empty (incomplete filter condition).
*
- * @param attribute
+ * @param attName
* @param attNames
* @param cond
* @param pattern
* @param filterIndex
* @return
*/
- protected JPanel addFilter(String attribute, List attNames,
+ protected JPanel addFilter(String[] attName, List attNames,
Condition cond, String pattern, int filterIndex)
{
JPanel filterRow = new JPanel(new FlowLayout(FlowLayout.LEFT));
filterRow.setBackground(Color.white);
/*
- * inputs for attribute, condition, pattern
- */
- /*
* drop-down choice of attribute, with description as a tooltip
* if we can obtain it
*/
@@ -1588,13 +1596,13 @@ public class FeatureSettings extends JPanel
}
};
- if ("".equals(attribute))
+ if (attName == null) // the 'add a condition' row
{
attCombo.setSelectedItem(null);
}
else
{
- attCombo.setSelectedItem(attribute);
+ attCombo.setSelectedItem(String.join(COLON, attName));
}
attCombo.addItemListener(itemListener);
@@ -1634,7 +1642,7 @@ public class FeatureSettings extends JPanel
*/
if (pattern != null && pattern.trim().length() > 0)
{
- // todo: gif for - button
+ // todo: gif for button drawing '-' or 'x'
JButton removeCondition = new BasicArrowButton(SwingConstants.WEST);
removeCondition.setToolTipText(MessageManager
.getString("label.delete_row"));
@@ -1662,22 +1670,24 @@ public class FeatureSettings extends JPanel
* @param attNames
*/
protected JComboBox populateAttributesDropdown(
- String featureType, List attNames)
+ String featureType, List attNames)
{
+ List displayNames = new ArrayList<>();
List tooltips = new ArrayList<>();
FeatureAttributes fa = FeatureAttributes.getInstance();
- for (String attName : attNames)
+ for (String[] attName : attNames)
{
String desc = fa.getDescription(featureType, attName);
if (desc != null && desc.length() > MAX_TOOLTIP_LENGTH)
{
desc = desc.substring(0, MAX_TOOLTIP_LENGTH) + "...";
}
+ displayNames.add(String.join(COLON, attName));
tooltips.add(desc == null ? "" : desc);
}
JComboBox attCombo = JvSwingUtils.buildComboWithTooltips(
- attNames, tooltips);
+ displayNames, tooltips);
if (attNames.isEmpty())
{
attCombo.setToolTipText(MessageManager
@@ -1755,7 +1765,8 @@ public class FeatureSettings extends JPanel
String attName = (String) attCombo.getSelectedItem();
Condition cond = (Condition) condCombo.getSelectedItem();
String pattern = valueField.getText();
- KeyedMatcherI km = new KeyedMatcher(attName, cond, pattern);
+ KeyedMatcherI km = new KeyedMatcher(cond, pattern,
+ attName.split(COLON));
filters.set(filterIndex, km);
}
@@ -2129,7 +2140,7 @@ public class FeatureSettings extends JPanel
if (gcol.isColourByAttribute())
{
- tx.append(gcol.getAttributeName());
+ tx.append(String.join(":", gcol.getAttributeName()));
}
else if (!gcol.isColourByLabel())
{
diff --git a/src/jalview/gui/OverviewCanvas.java b/src/jalview/gui/OverviewCanvas.java
index 7371eb5..2991889 100644
--- a/src/jalview/gui/OverviewCanvas.java
+++ b/src/jalview/gui/OverviewCanvas.java
@@ -183,6 +183,8 @@ public class OverviewCanvas extends JComponent
@Override
public void paintComponent(Graphics g)
{
+ // super.paintComponent(g);
+
if (restart)
{
if (lastMiniMe == null)
@@ -204,7 +206,8 @@ public class OverviewCanvas extends JComponent
&& ((getWidth() != od.getWidth())
|| (getHeight() != od.getHeight())))
{
- // if there is annotation, scale the alignment and annotation separately
+ // if there is annotation, scale the alignment and annotation
+ // separately
if (od.getGraphHeight() > 0)
{
BufferedImage topImage = lastMiniMe.getSubimage(0, 0,
@@ -235,25 +238,24 @@ public class OverviewCanvas extends JComponent
od.setHeight(getHeight());
}
- // scale lastMiniMe to the new size
- g.drawImage(lastMiniMe, 0, 0, getWidth(), getHeight(), this);
-
// make sure the box is in the right place
od.setBoxPosition(av.getAlignment().getHiddenSequences(),
av.getAlignment().getHiddenColumns());
}
- else // not a resize
- {
- // fall back to normal behaviour
- g.drawImage(lastMiniMe, 0, 0, getWidth(), getHeight(), this);
- }
+ // fall back to normal behaviour
+ g.drawImage(lastMiniMe, 0, 0, getWidth(), getHeight(), this);
}
-
+ else
+ {
+ g.drawImage(lastMiniMe, 0, 0, getWidth(), getHeight(), this);
+ }
+
// draw the box
g.setColor(Color.red);
od.drawBox(g);
}
+
public void dispose()
{
dispose = true;
diff --git a/src/jalview/gui/OverviewPanel.java b/src/jalview/gui/OverviewPanel.java
index 9ddb751..43b4310 100755
--- a/src/jalview/gui/OverviewPanel.java
+++ b/src/jalview/gui/OverviewPanel.java
@@ -329,6 +329,22 @@ public class OverviewPanel extends JPanel
* changed
*
*/
+ private void setBoxPositionOnly()
+ {
+ if (od != null)
+ {
+ int oldX = od.getBoxX();
+ int oldY = od.getBoxY();
+ int oldWidth = od.getBoxWidth();
+ int oldHeight = od.getBoxHeight();
+ od.setBoxPosition(av.getAlignment().getHiddenSequences(),
+ av.getAlignment().getHiddenColumns());
+ repaint(oldX - 1, oldY - 1, oldWidth + 2, oldHeight + 2);
+ repaint(od.getBoxX(), od.getBoxY(), od.getBoxWidth(),
+ od.getBoxHeight());
+ }
+ }
+
private void setBoxPosition()
{
if (od != null)
@@ -342,7 +358,7 @@ public class OverviewPanel extends JPanel
@Override
public void propertyChange(PropertyChangeEvent evt)
{
- setBoxPosition();
+ setBoxPositionOnly();
}
/**
diff --git a/src/jalview/gui/SequenceFetcher.java b/src/jalview/gui/SequenceFetcher.java
index e05230b..8d46792 100755
--- a/src/jalview/gui/SequenceFetcher.java
+++ b/src/jalview/gui/SequenceFetcher.java
@@ -26,6 +26,7 @@ import jalview.datamodel.AlignmentI;
import jalview.datamodel.DBRefEntry;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
+import jalview.fts.core.GFTSPanel;
import jalview.fts.service.pdb.PDBFTSPanel;
import jalview.fts.service.uniprot.UniprotFTSPanel;
import jalview.io.FileFormatI;
@@ -78,6 +79,8 @@ public class SequenceFetcher extends JPanel implements Runnable
JButton close = new JButton();
+ JButton back = new JButton();
+
JPanel jPanel1 = new JPanel();
JTextArea textArea = new JTextArea();
@@ -383,6 +386,15 @@ public class SequenceFetcher extends JPanel implements Runnable
.getString("label.additional_sequence_fetcher"));
}
+ GFTSPanel parentFTSframe = null;
+ /**
+ * change the buttons so they fit with the FTS panel.
+ */
+ public void embedWithFTSPanel(GFTSPanel toClose)
+ {
+ back.setVisible(true);
+ parentFTSframe = toClose;
+ }
private void jbInit() throws Exception
{
this.setLayout(borderLayout2);
@@ -427,7 +439,7 @@ public class SequenceFetcher extends JPanel implements Runnable
example_actionPerformed();
}
});
- close.setText(MessageManager.getString("action.close"));
+ close.setText(MessageManager.getString("action.cancel"));
close.addActionListener(new ActionListener()
{
@Override
@@ -436,6 +448,17 @@ public class SequenceFetcher extends JPanel implements Runnable
close_actionPerformed(e);
}
});
+ back.setText(MessageManager.getString("action.back"));
+ back.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ parentFTSframe.btn_back_ActionPerformed();
+ }
+ });
+ // back not visible unless embedded
+ back.setVisible(false);
textArea.setFont(JvSwingUtils.getLabelFont());
textArea.setLineWrap(true);
textArea.addKeyListener(new KeyAdapter()
@@ -451,9 +474,10 @@ public class SequenceFetcher extends JPanel implements Runnable
});
jPanel3.setLayout(borderLayout1);
borderLayout1.setVgap(5);
- jPanel1.add(ok);
+ jPanel1.add(back);
jPanel1.add(example);
jPanel1.add(clear);
+ jPanel1.add(ok);
jPanel1.add(close);
jPanel2.setLayout(borderLayout3);
databaseButt = /*database.getDatabaseSelectorButton();
@@ -582,6 +606,10 @@ public class SequenceFetcher extends JPanel implements Runnable
try
{
frame.setClosed(true);
+ if (parentFTSframe!=null)
+ {
+ parentFTSframe.btn_cancel_ActionPerformed();
+ }
} catch (Exception ex)
{
}
@@ -594,7 +622,7 @@ public class SequenceFetcher extends JPanel implements Runnable
textArea.setEnabled(false);
ok.setEnabled(false);
close.setEnabled(false);
-
+ back.setEnabled(false);
Thread worker = new Thread(this);
worker.start();
}
@@ -606,6 +634,7 @@ public class SequenceFetcher extends JPanel implements Runnable
textArea.setEnabled(true);
ok.setEnabled(true);
close.setEnabled(true);
+ back.setEnabled(parentFTSframe != null);
}
@Override
@@ -1087,4 +1116,9 @@ public class SequenceFetcher extends JPanel implements Runnable
{
frame.setVisible(false);
}
+
+ public void setDatabaseChooserVisible(boolean b)
+ {
+ databaseButt.setVisible(b);
+ }
}
diff --git a/src/jalview/gui/StructureChooser.java b/src/jalview/gui/StructureChooser.java
index 20f4a49..37632ef 100644
--- a/src/jalview/gui/StructureChooser.java
+++ b/src/jalview/gui/StructureChooser.java
@@ -927,16 +927,10 @@ public class StructureChooser extends GStructureChooser
}
if (pdbEntriesToView.length > 1)
{
- ArrayList seqsMap = new ArrayList<>();
- for (SequenceI seq : sequences)
- {
- seqsMap.add(new SequenceI[] { seq });
- }
- SequenceI[][] collatedSeqs = seqsMap.toArray(new SequenceI[0][0]);
-
- setProgressBar(MessageManager
- .getString("status.fetching_3d_structures_for_selected_entries"), progressId);
- sViewer.viewStructures(pdbEntriesToView, collatedSeqs, alignPanel);
+ setProgressBar(MessageManager.getString(
+ "status.fetching_3d_structures_for_selected_entries"),
+ progressId);
+ sViewer.viewStructures(pdbEntriesToView, sequences, alignPanel);
}
else
{
diff --git a/src/jalview/gui/StructureViewer.java b/src/jalview/gui/StructureViewer.java
index e58b378..b142613 100644
--- a/src/jalview/gui/StructureViewer.java
+++ b/src/jalview/gui/StructureViewer.java
@@ -29,19 +29,24 @@ import jalview.structure.StructureSelectionManager;
import java.awt.Rectangle;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
/**
- * proxy for handling structure viewers.
- *
- * this allows new views to be created with the currently configured viewer, the
- * preferred viewer to be set/read and existing views created previously with a
- * particular viewer to be recovered
+ * A proxy for handling structure viewers, that orchestrates adding selected
+ * structures, associated with sequences in Jalview, to an existing viewer, or
+ * opening a new one. Currently supports either Jmol or Chimera as the structure
+ * viewer.
*
* @author jprocter
*/
public class StructureViewer
{
+ private static final String UNKNOWN_VIEWER_TYPE = "Unknown structure viewer type ";
+
StructureSelectionManager ssm;
public enum ViewerType
@@ -49,6 +54,16 @@ public class StructureViewer
JMOL, CHIMERA
};
+ /**
+ * Constructor
+ *
+ * @param structureSelectionManager
+ */
+ public StructureViewer(StructureSelectionManager structureSelectionManager)
+ {
+ ssm = structureSelectionManager;
+ }
+
public ViewerType getViewerType()
{
String viewType = Cache.getDefault(Preferences.STRUCTURE_DISPLAY,
@@ -61,135 +76,157 @@ public class StructureViewer
Cache.setProperty(Preferences.STRUCTURE_DISPLAY, type.name());
}
- public StructureViewer(
- StructureSelectionManager structureSelectionManager)
- {
- ssm = structureSelectionManager;
- }
-
/**
* View multiple PDB entries, each with associated sequences
*
* @param pdbs
- * @param seqsForPdbs
+ * @param seqs
* @param ap
* @return
*/
public JalviewStructureDisplayI viewStructures(PDBEntry[] pdbs,
- SequenceI[][] seqsForPdbs, AlignmentPanel ap)
+ SequenceI[] seqs, AlignmentPanel ap)
{
- JalviewStructureDisplayI viewer = onlyOnePdb(pdbs, seqsForPdbs, ap);
+ JalviewStructureDisplayI viewer = onlyOnePdb(pdbs, seqs, ap);
if (viewer != null)
{
+ /*
+ * user added structure to an existing viewer - all done
+ */
return viewer;
}
- return viewStructures(getViewerType(), pdbs, seqsForPdbs, ap);
+
+ ViewerType viewerType = getViewerType();
+
+ Map seqsForPdbs = getSequencesForPdbs(pdbs,
+ seqs);
+ PDBEntry[] pdbsForFile = seqsForPdbs.keySet().toArray(
+ new PDBEntry[seqsForPdbs.size()]);
+ SequenceI[][] theSeqs = seqsForPdbs.values().toArray(
+ new SequenceI[seqsForPdbs.size()][]);
+ JalviewStructureDisplayI sview = null;
+ if (viewerType.equals(ViewerType.JMOL))
+ {
+ sview = new AppJmol(ap, pdbsForFile, theSeqs);
+ }
+ else if (viewerType.equals(ViewerType.CHIMERA))
+ {
+ sview = new ChimeraViewFrame(pdbsForFile, theSeqs, ap);
+ }
+ else
+ {
+ Cache.log.error(UNKNOWN_VIEWER_TYPE + getViewerType().toString());
+ }
+ return sview;
}
/**
- * A strictly temporary method pending JAL-1761 refactoring. Determines if all
- * the passed PDB entries are the same (this is the case if selected sequences
- * to view structure for are chains of the same structure). If so, calls the
- * single-pdb version of viewStructures and returns the viewer, else returns
- * null.
+ * Converts the list of selected PDB entries (possibly including duplicates
+ * for multiple chains), and corresponding sequences, into a map of sequences
+ * for each distinct PDB file. Returns null if either argument is null, or
+ * their lengths do not match.
*
* @param pdbs
- * @param seqsForPdbs
- * @param ap
+ * @param seqs
* @return
*/
- private JalviewStructureDisplayI onlyOnePdb(PDBEntry[] pdbs,
- SequenceI[][] seqsForPdbs, AlignmentPanel ap)
+ Map getSequencesForPdbs(PDBEntry[] pdbs,
+ SequenceI[] seqs)
{
- List seqs = new ArrayList();
- if (pdbs == null || pdbs.length == 0)
+ if (pdbs == null || seqs == null || pdbs.length != seqs.length)
{
return null;
}
- int i = 0;
- String firstFile = pdbs[0].getFile();
- for (PDBEntry pdb : pdbs)
+
+ /*
+ * we want only one 'representative' PDBEntry per distinct file name
+ * (there may be entries for distinct chains)
+ */
+ Map pdbsSeen = new HashMap<>();
+
+ /*
+ * LinkedHashMap preserves order of PDB entries (significant if they
+ * will get superimposed to the first structure)
+ */
+ Map> pdbSeqs = new LinkedHashMap<>();
+ for (int i = 0; i < pdbs.length; i++)
{
+ PDBEntry pdb = pdbs[i];
+ SequenceI seq = seqs[i];
String pdbFile = pdb.getFile();
- if (pdbFile == null || !pdbFile.equals(firstFile))
+ if (!pdbsSeen.containsKey(pdbFile))
{
- return null;
+ pdbsSeen.put(pdbFile, pdb);
+ pdbSeqs.put(pdb, new ArrayList());
+ }
+ else
+ {
+ pdb = pdbsSeen.get(pdbFile);
}
- SequenceI[] pdbseqs = seqsForPdbs[i++];
- if (pdbseqs != null)
+ List seqsForPdb = pdbSeqs.get(pdb);
+ if (!seqsForPdb.contains(seq))
{
- for (SequenceI sq : pdbseqs)
- {
- seqs.add(sq);
- }
+ seqsForPdb.add(seq);
}
}
- return viewStructures(pdbs[0], seqs.toArray(new SequenceI[seqs.size()]),
- ap);
- }
-
- public JalviewStructureDisplayI viewStructures(PDBEntry pdb,
- SequenceI[] seqsForPdb, AlignmentPanel ap)
- {
- return viewStructures(getViewerType(), pdb, seqsForPdb, ap);
- }
- protected JalviewStructureDisplayI viewStructures(ViewerType viewerType,
- PDBEntry[] pdbs, SequenceI[][] seqsForPdbs, AlignmentPanel ap)
- {
- PDBEntry[] pdbsForFile = getUniquePdbFiles(pdbs);
- JalviewStructureDisplayI sview = null;
- if (viewerType.equals(ViewerType.JMOL))
- {
- sview = new AppJmol(ap, pdbsForFile,
- ap.av.collateForPDB(pdbsForFile));
- }
- else if (viewerType.equals(ViewerType.CHIMERA))
+ /*
+ * convert to Map
+ */
+ Map result = new LinkedHashMap<>();
+ for (Entry> entry : pdbSeqs.entrySet())
{
- sview = new ChimeraViewFrame(pdbsForFile,
- ap.av.collateForPDB(pdbsForFile), ap);
+ List theSeqs = entry.getValue();
+ result.put(entry.getKey(),
+ theSeqs.toArray(new SequenceI[theSeqs.size()]));
}
- else
- {
- Cache.log.error("Unknown structure viewer type "
- + getViewerType().toString());
- }
- return sview;
+
+ return result;
}
/**
- * Convert the array of PDBEntry into an array with no filename repeated
+ * A strictly temporary method pending JAL-1761 refactoring. Determines if all
+ * the passed PDB entries are the same (this is the case if selected sequences
+ * to view structure for are chains of the same structure). If so, calls the
+ * single-pdb version of viewStructures and returns the viewer, else returns
+ * null.
*
* @param pdbs
+ * @param seqsForPdbs
+ * @param ap
* @return
*/
- static PDBEntry[] getUniquePdbFiles(PDBEntry[] pdbs)
+ private JalviewStructureDisplayI onlyOnePdb(PDBEntry[] pdbs,
+ SequenceI[] seqsForPdbs, AlignmentPanel ap)
{
- if (pdbs == null)
+ List seqs = new ArrayList();
+ if (pdbs == null || pdbs.length == 0)
{
return null;
}
- List uniques = new ArrayList();
- List filesSeen = new ArrayList();
- for (PDBEntry entry : pdbs)
+ int i = 0;
+ String firstFile = pdbs[0].getFile();
+ for (PDBEntry pdb : pdbs)
{
- String file = entry.getFile();
- if (file == null)
+ String pdbFile = pdb.getFile();
+ if (pdbFile == null || !pdbFile.equals(firstFile))
{
- uniques.add(entry);
+ return null;
}
- else if (!filesSeen.contains(file))
+ SequenceI pdbseq = seqsForPdbs[i++];
+ if (pdbseq != null)
{
- uniques.add(entry);
- filesSeen.add(file);
+ seqs.add(pdbseq);
}
}
- return uniques.toArray(new PDBEntry[uniques.size()]);
+ return viewStructures(pdbs[0], seqs.toArray(new SequenceI[seqs.size()]),
+ ap);
}
- protected JalviewStructureDisplayI viewStructures(ViewerType viewerType,
- PDBEntry pdb, SequenceI[] seqsForPdb, AlignmentPanel ap)
+ public JalviewStructureDisplayI viewStructures(PDBEntry pdb,
+ SequenceI[] seqsForPdb, AlignmentPanel ap)
{
+ ViewerType viewerType = getViewerType();
JalviewStructureDisplayI sview = null;
if (viewerType.equals(ViewerType.JMOL))
{
@@ -201,8 +238,7 @@ public class StructureViewer
}
else
{
- Cache.log.error("Unknown structure viewer type "
- + getViewerType().toString());
+ Cache.log.error(UNKNOWN_VIEWER_TYPE + getViewerType().toString());
}
return sview;
}
@@ -242,7 +278,7 @@ public class StructureViewer
"Unsupported structure viewer type " + type.toString());
break;
default:
- Cache.log.error("Unknown structure viewer type " + type.toString());
+ Cache.log.error(UNKNOWN_VIEWER_TYPE + type.toString());
}
return sview;
}
diff --git a/src/jalview/io/AlignFile.java b/src/jalview/io/AlignFile.java
index a603cca..2340283 100755
--- a/src/jalview/io/AlignFile.java
+++ b/src/jalview/io/AlignFile.java
@@ -174,11 +174,6 @@ public abstract class AlignFile extends FileParse
}
parseCalled = true;
parse();
- // sets the index of each sequence in the alignment
- for (int i = 0, c = seqs.size(); i < c; i++)
- {
- seqs.get(i).setIndex(i);
- }
}
/**
diff --git a/src/jalview/io/SequenceAnnotationReport.java b/src/jalview/io/SequenceAnnotationReport.java
index 1f92428..6b82671 100644
--- a/src/jalview/io/SequenceAnnotationReport.java
+++ b/src/jalview/io/SequenceAnnotationReport.java
@@ -210,11 +210,12 @@ public class SequenceAnnotationReport
FeatureColourI fc = fr.getFeatureColours().get(feature.getType());
if (fc != null && fc.isColourByAttribute())
{
- String attName = fc.getAttributeName();
+ String[] attName = fc.getAttributeName();
String attVal = feature.getValueAsString(attName);
if (attVal != null)
{
- sb.append("; ").append(attName).append("=").append(attVal);
+ sb.append("; ").append(String.join(":", attName)).append("=")
+ .append(attVal);
}
}
}
@@ -301,7 +302,7 @@ public class SequenceAnnotationReport
*/
Collection> createLinksFrom(SequenceI seq, String link)
{
- Map> urlSets = new LinkedHashMap>();
+ Map> urlSets = new LinkedHashMap<>();
UrlLink urlLink = new UrlLink(link);
if (!urlLink.isValid())
{
diff --git a/src/jalview/io/cache/JvCacheableInputBox.java b/src/jalview/io/cache/JvCacheableInputBox.java
index 3d0daed..a837512 100644
--- a/src/jalview/io/cache/JvCacheableInputBox.java
+++ b/src/jalview/io/cache/JvCacheableInputBox.java
@@ -28,6 +28,7 @@ import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -70,11 +71,49 @@ public class JvCacheableInputBox extends JComboBox
private JMenuItem menuItemClearCache = new JMenuItem();
+ volatile boolean enterWasPressed = false;
+
+ /**
+ * @return flag indicating if the most recent keypress was enter
+ */
+ public boolean wasEnterPressed()
+ {
+ return enterWasPressed;
+ }
+
public JvCacheableInputBox(String newCacheKey)
{
super();
this.cacheKey = newCacheKey;
setEditable(true);
+ addKeyListener(new KeyListener()
+ {
+
+ @Override
+ public void keyTyped(KeyEvent e)
+ {
+ enterWasPressed = false;
+ if (e.getKeyCode() == KeyEvent.VK_ENTER)
+ {
+ enterWasPressed = true;
+ }
+ // let event bubble up
+ }
+
+ @Override
+ public void keyReleased(KeyEvent e)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void keyPressed(KeyEvent e)
+ {
+ // TODO Auto-generated method stub
+
+ }
+ });
setPrototypeDisplayValue(
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
appCache = AppCache.getInstance();
diff --git a/src/jalview/io/vcf/VCFLoader.java b/src/jalview/io/vcf/VCFLoader.java
index 5adc55c..2847bd7 100644
--- a/src/jalview/io/vcf/VCFLoader.java
+++ b/src/jalview/io/vcf/VCFLoader.java
@@ -1,17 +1,9 @@
package jalview.io.vcf;
-import htsjdk.samtools.util.CloseableIterator;
-import htsjdk.variant.variantcontext.Allele;
-import htsjdk.variant.variantcontext.VariantContext;
-import htsjdk.variant.vcf.VCFHeader;
-import htsjdk.variant.vcf.VCFHeaderLine;
-import htsjdk.variant.vcf.VCFHeaderLineCount;
-import htsjdk.variant.vcf.VCFHeaderLineType;
-import htsjdk.variant.vcf.VCFInfoHeaderLine;
-
import jalview.analysis.AlignmentUtils;
import jalview.analysis.Dna;
import jalview.api.AlignViewControllerGuiI;
+import jalview.bin.Cache;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.DBRefEntry;
import jalview.datamodel.GeneLociI;
@@ -35,6 +27,17 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import htsjdk.samtools.util.CloseableIterator;
+import htsjdk.variant.variantcontext.Allele;
+import htsjdk.variant.variantcontext.VariantContext;
+import htsjdk.variant.vcf.VCFHeader;
+import htsjdk.variant.vcf.VCFHeaderLine;
+import htsjdk.variant.vcf.VCFHeaderLineCount;
+import htsjdk.variant.vcf.VCFHeaderLineType;
+import htsjdk.variant.vcf.VCFInfoHeaderLine;
/**
* A class to read VCF data (using the htsjdk) and add variants as sequence
@@ -45,6 +48,18 @@ import java.util.Map.Entry;
public class VCFLoader
{
/*
+ * Lookup keys, and default values, for Preference entries that describe
+ * patterns for VCF and VEP fields to capture
+ */
+ private static final String VEP_FIELDS_PREF = "VEP_FIELDS";
+
+ private static final String VCF_FIELDS_PREF = "VCF_FIELDS";
+
+ private static final String DEFAULT_VCF_FIELDS = "AF,AC*";
+
+ private static final String DEFAULT_VEP_FIELDS = ".*";// "Allele,Consequence,IMPACT,SWISSPROT,SIFT,PolyPhen,CLIN_SIG";
+
+ /*
* keys to fields of VEP CSQ consequence data
* see https://www.ensembl.org/info/docs/tools/vep/vep_formats.html
*/
@@ -54,23 +69,16 @@ public class VCFLoader
private static final String FEATURE_KEY = "Feature"; // Ensembl stable id
/*
- * what comes before column headings in CSQ Description field
- */
- private static final String FORMAT = "Format: ";
-
- /*
* default VCF INFO key for VEP consequence data
* NB this can be overridden running VEP with --vcf_info_field
- * - we don't handle this case (require CSQ identifier)
+ * - we don't handle this case (require identifier to be CSQ)
*/
- private static final String CSQ = "CSQ";
+ private static final String CSQ_FIELD = "CSQ";
/*
- * separator for fields in consequence data
+ * separator for fields in consequence data is '|'
*/
- private static final String PIPE = "|";
-
- private static final String PIPE_REGEX = "\\" + PIPE;
+ private static final String PIPE_REGEX = "\\|";
/*
* key for Allele Frequency output by VEP
@@ -126,6 +134,19 @@ public class VCFLoader
*/
private String sourceId;
+ /*
+ * The INFO IDs of data that is both present in the VCF file, and
+ * also matched by any filters for data of interest
+ */
+ List vcfFieldsOfInterest;
+
+ /*
+ * The field offsets and identifiers for VEP (CSQ) data that is both present
+ * in the VCF file, and also matched by any filters for data of interest
+ * for example 0 -> Allele, 1 -> Consequence, ..., 36 -> SIFT, ...
+ */
+ Map vepFieldsOfInterest;
+
/**
* Constructor given an alignment context
*
@@ -136,7 +157,7 @@ public class VCFLoader
al = alignment;
// map of species!chromosome!fromAssembly!toAssembly to {fromRange, toRange}
- assemblyMappings = new HashMap>();
+ assemblyMappings = new HashMap<>();
}
/**
@@ -193,7 +214,7 @@ public class VCFLoader
/*
* get offset of CSQ ALLELE_NUM and Feature if declared
*/
- locateCsqFields();
+ parseCsqHeader();
VCFHeaderLine ref = header
.getOtherHeaderLine(VCFHeader.REFERENCE_KEY);
@@ -253,11 +274,15 @@ public class VCFLoader
* Reads metadata (such as INFO field descriptions and datatypes) and saves
* them for future reference
*
- * @param sourceId
+ * @param theSourceId
*/
- void saveMetadata(String sourceId)
+ void saveMetadata(String theSourceId)
{
- FeatureSource metadata = new FeatureSource(sourceId);
+ List vcfFieldPatterns = getFieldMatchers(VCF_FIELDS_PREF,
+ DEFAULT_VCF_FIELDS);
+ vcfFieldsOfInterest = new ArrayList<>();
+
+ FeatureSource metadata = new FeatureSource(theSourceId);
for (VCFInfoHeaderLine info : header.getInfoHeaderLines())
{
@@ -285,34 +310,65 @@ public class VCFLoader
}
metadata.setAttributeName(attributeId, desc);
metadata.setAttributeType(attributeId, attType);
+
+ if (isFieldWanted(attributeId, vcfFieldPatterns))
+ {
+ vcfFieldsOfInterest.add(attributeId);
+ }
}
- FeatureSources.getInstance().addSource(sourceId, metadata);
+ FeatureSources.getInstance().addSource(theSourceId, metadata);
}
/**
- * Records the position of selected fields defined in the CSQ INFO header (if
- * there is one). CSQ fields are declared in the CSQ INFO Description e.g.
+ * Answers true if the field id is matched by any of the filter patterns, else
+ * false. Matching is against regular expression patterns, and is not
+ * case-sensitive.
+ *
+ * @param id
+ * @param filters
+ * @return
+ */
+ private boolean isFieldWanted(String id, List filters)
+ {
+ for (Pattern p : filters)
+ {
+ if (p.matcher(id.toUpperCase()).matches())
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Records 'wanted' fields defined in the CSQ INFO header (if there is one).
+ * Also records the position of selected fields (Allele, ALLELE_NUM, Feature)
+ * required for processing.
+ *
+ * CSQ fields are declared in the CSQ INFO Description e.g.
*
* Description="Consequence ...from ... VEP. Format: Allele|Consequence|...
*/
- protected void locateCsqFields()
+ protected void parseCsqHeader()
{
- VCFInfoHeaderLine csqInfo = header.getInfoHeaderLine(CSQ);
+ List vepFieldFilters = getFieldMatchers(VEP_FIELDS_PREF,
+ DEFAULT_VEP_FIELDS);
+ vepFieldsOfInterest = new HashMap<>();
+
+ VCFInfoHeaderLine csqInfo = header.getInfoHeaderLine(CSQ_FIELD);
if (csqInfo == null)
{
return;
}
+ /*
+ * parse out the pipe-separated list of CSQ fields; we assume here that
+ * these form the last part of the description, and contain no spaces
+ */
String desc = csqInfo.getDescription();
- int formatPos = desc.indexOf(FORMAT);
- if (formatPos == -1)
- {
- System.err.println("Parse error, failed to find " + FORMAT
- + " in " + desc);
- return;
- }
- desc = desc.substring(formatPos + FORMAT.length());
+ int spacePos = desc.lastIndexOf(" ");
+ desc = desc.substring(spacePos + 1);
if (desc != null)
{
@@ -332,12 +388,51 @@ public class VCFLoader
{
csqFeatureFieldIndex = index;
}
+
+ if (isFieldWanted(field, vepFieldFilters))
+ {
+ vepFieldsOfInterest.put(index, field);
+ }
+
index++;
}
}
}
/**
+ * Reads the Preference value for the given key, with default specified if no
+ * preference set. The value is interpreted as a comma-separated list of
+ * regular expressions, and converted into a list of compiled patterns ready
+ * for matching. Patterns are forced to upper-case for non-case-sensitive
+ * matching.
+ *
+ * This supports user-defined filters for fields of interest to capture while
+ * processing data. For example, VCF_FIELDS = AF,AC* would mean that VCF INFO
+ * fields with an ID of AF, or starting with AC, would be matched.
+ *
+ * @param key
+ * @param def
+ * @return
+ */
+ private List getFieldMatchers(String key, String def)
+ {
+ String pref = Cache.getDefault(key, def);
+ List patterns = new ArrayList<>();
+ String[] tokens = pref.split(",");
+ for (String token : tokens)
+ {
+ try
+ {
+ patterns.add(Pattern.compile(token.toUpperCase()));
+ } catch (PatternSyntaxException e)
+ {
+ System.err.println("Invalid pattern ignored: " + token);
+ }
+ }
+ return patterns;
+ }
+
+ /**
* Transfers VCF features to sequences to which this sequence has a mapping.
* If the mapping is 3:1, computes peptide variants from nucleotide variants.
*
@@ -702,13 +797,21 @@ public class VCFLoader
* extract Consequence data (if present) that we are able to
* associated with the allele for this variant feature
*/
- if (CSQ.equals(key))
+ if (CSQ_FIELD.equals(key))
{
addConsequences(variant, seq, sf, altAlelleIndex);
continue;
}
/*
+ * filter out fields we don't want to capture
+ */
+ if (!vcfFieldsOfInterest.contains(key))
+ {
+ continue;
+ }
+
+ /*
* we extract values for other data which are allele-specific;
* these may be per alternate allele (INFO[key].Number = 'A')
* or per allele including reference (INFO[key].Number = 'R')
@@ -775,7 +878,7 @@ public class VCFLoader
protected void addConsequences(VariantContext variant, SequenceI seq,
SequenceFeature sf, int altAlelleIndex)
{
- Object value = variant.getAttribute(CSQ);
+ Object value = variant.getAttribute(CSQ_FIELD);
if (value == null || !(value instanceof ArrayList>))
{
@@ -808,8 +911,11 @@ public class VCFLoader
}
}
- StringBuilder sb = new StringBuilder(128);
- boolean found = false;
+ /*
+ * inspect CSQ consequences; where possible restrict to the consequence
+ * associated with the current transcript (Feature)
+ */
+ Map csqValues = new HashMap<>();
for (String consequence : consequences)
{
@@ -818,18 +924,29 @@ public class VCFLoader
if (includeConsequence(csqFields, matchFeature, variant,
altAlelleIndex))
{
- if (found)
+ /*
+ * inspect individual fields of this consequence, copying non-null
+ * values which are 'fields of interest'
+ */
+ int i = 0;
+ for (String field : csqFields)
{
- sb.append(COMMA);
+ if (field != null && field.length() > 0)
+ {
+ String id = vepFieldsOfInterest.get(i);
+ if (id != null)
+ {
+ csqValues.put(id, field);
+ }
+ }
+ i++;
}
- found = true;
- sb.append(consequence);
}
}
- if (found)
+ if (!csqValues.isEmpty())
{
- sf.setValue(CSQ, sb.toString());
+ sf.setValue(CSQ_FIELD, csqValues);
}
}
diff --git a/src/jalview/schemes/FeatureColour.java b/src/jalview/schemes/FeatureColour.java
index 168ab54..71a89b0 100644
--- a/src/jalview/schemes/FeatureColour.java
+++ b/src/jalview/schemes/FeatureColour.java
@@ -78,10 +78,10 @@ public class FeatureColour implements FeatureColourI
private boolean colourByLabel;
/*
- * if not null, the value of this named attribute is used for
- * colourByLabel or graduatedColour
+ * if not null, the value of [attribute, [sub-attribute] ...]
+ * is used for colourByLabel or graduatedColour
*/
- private String byAttributeName;
+ private String[] attributeName;
private float threshold;
@@ -371,7 +371,7 @@ public class FeatureColour implements FeatureColourI
base = fc.base;
range = fc.range;
isHighToLow = fc.isHighToLow;
- byAttributeName = fc.byAttributeName;
+ attributeName = fc.attributeName;
setAboveThreshold(fc.isAboveThreshold());
setBelowThreshold(fc.isBelowThreshold());
setThreshold(fc.getThreshold());
@@ -593,8 +593,8 @@ public class FeatureColour implements FeatureColourI
{
if (isColourByLabel())
{
- String label = byAttributeName == null ? feature.getDescription()
- : feature.getValueAsString(byAttributeName);
+ String label = attributeName == null ? feature.getDescription()
+ : feature.getValueAsString(attributeName);
return label == null ? noColour : ColorUtils
.createColourFromName(label);
}
@@ -611,11 +611,11 @@ public class FeatureColour implements FeatureColourI
* no such attribute is assigned the 'no value' colour
*/
float scr = feature.getScore();
- if (byAttributeName != null)
+ if (attributeName != null)
{
try
{
- String attVal = feature.getValueAsString(byAttributeName);
+ String attVal = feature.getValueAsString(attributeName);
scr = Float.valueOf(attVal);
} catch (Throwable e)
{
@@ -746,19 +746,19 @@ public class FeatureColour implements FeatureColourI
@Override
public boolean isColourByAttribute()
{
- return byAttributeName != null;
+ return attributeName != null;
}
@Override
- public String getAttributeName()
+ public String[] getAttributeName()
{
- return byAttributeName;
+ return attributeName;
}
@Override
- public void setAttributeName(String name)
+ public void setAttributeName(String... name)
{
- byAttributeName = name;
+ attributeName = name;
}
}
diff --git a/src/jalview/util/matcher/KeyedMatcher.java b/src/jalview/util/matcher/KeyedMatcher.java
index cd952e7..ef1c702 100644
--- a/src/jalview/util/matcher/KeyedMatcher.java
+++ b/src/jalview/util/matcher/KeyedMatcher.java
@@ -19,18 +19,20 @@ import java.util.function.Function;
*/
public class KeyedMatcher implements KeyedMatcherI
{
- final private String key;
+ private static final String COLON = ":";
+
+ final private String[] key;
final private MatcherI matcher;
/**
* Constructor given a key, a test condition and a match pattern
*
- * @param theKey
* @param cond
* @param pattern
+ * @param theKey
*/
- public KeyedMatcher(String theKey, Condition cond, String pattern)
+ public KeyedMatcher(Condition cond, String pattern, String... theKey)
{
key = theKey;
matcher = new Matcher(cond, pattern);
@@ -41,25 +43,25 @@ public class KeyedMatcher implements KeyedMatcherI
* to. Note that if a non-numerical condition is specified, the float will be
* converted to a string.
*
- * @param theKey
* @param cond
* @param value
+ * @param theKey
*/
- public KeyedMatcher(String theKey, Condition cond, float value)
+ public KeyedMatcher(Condition cond, float value, String... theKey)
{
key = theKey;
matcher = new Matcher(cond, value);
}
@Override
- public boolean matches(Function valueProvider)
+ public boolean matches(Function valueProvider)
{
String value = valueProvider.apply(key);
return matcher.matches(value);
}
@Override
- public String getKey()
+ public String[] getKey()
{
return key;
}
@@ -78,8 +80,8 @@ public class KeyedMatcher implements KeyedMatcherI
public String toString()
{
StringBuilder sb = new StringBuilder();
- sb.append(key).append(" ").append(matcher.getCondition().toString())
- .append(" ");
+ sb.append(String.join(COLON, key)).append(" ")
+ .append(matcher.getCondition().toString()).append(" ");
if (matcher.getCondition().isNumeric())
{
sb.append(matcher.getPattern());
diff --git a/src/jalview/util/matcher/KeyedMatcherI.java b/src/jalview/util/matcher/KeyedMatcherI.java
index e9fe014..e8d71c1 100644
--- a/src/jalview/util/matcher/KeyedMatcherI.java
+++ b/src/jalview/util/matcher/KeyedMatcherI.java
@@ -18,14 +18,14 @@ public interface KeyedMatcherI
* @param valueProvider
* @return
*/
- boolean matches(Function valueProvider);
+ boolean matches(Function valueProvider);
/**
* Answers the value key this matcher operates on
*
* @return
*/
- String getKey();
+ String[] getKey();
/**
* Answers the match condition that is applied
diff --git a/src/jalview/util/matcher/KeyedMatcherSet.java b/src/jalview/util/matcher/KeyedMatcherSet.java
index 35a41c2..a4be48a 100644
--- a/src/jalview/util/matcher/KeyedMatcherSet.java
+++ b/src/jalview/util/matcher/KeyedMatcherSet.java
@@ -19,7 +19,7 @@ public class KeyedMatcherSet implements KeyedMatcherSetI
}
@Override
- public boolean matches(Function valueProvider)
+ public boolean matches(Function valueProvider)
{
/*
* no conditions matches anything
diff --git a/src/jalview/util/matcher/KeyedMatcherSetI.java b/src/jalview/util/matcher/KeyedMatcherSetI.java
index 25dc96e..3e9f5b6 100644
--- a/src/jalview/util/matcher/KeyedMatcherSetI.java
+++ b/src/jalview/util/matcher/KeyedMatcherSetI.java
@@ -18,7 +18,7 @@ public interface KeyedMatcherSetI
* @param valueProvider
* @return
*/
- boolean matches(Function valueProvider);
+ boolean matches(Function valueProvider);
/**
* Answers a new object that matches the logical AND of this and m
diff --git a/src/jalview/util/matcher/Matcher.java b/src/jalview/util/matcher/Matcher.java
index a213a17..715694c 100644
--- a/src/jalview/util/matcher/Matcher.java
+++ b/src/jalview/util/matcher/Matcher.java
@@ -37,8 +37,8 @@ public class Matcher implements MatcherI
* @param compareTo
* @return
* @throws NumberFormatException
- * if a numerical condition is specified with a non-numeric
- * comparision value
+ * if a numerical condition is specified with a non-numeric comparison
+ * value
* @throws NullPointerException
* if a null condition or comparison string is specified
*/
diff --git a/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java b/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java
index c2f5bb7..28fceec 100644
--- a/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java
+++ b/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java
@@ -169,7 +169,7 @@ public abstract class FeatureRendererModel
{
av.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
}
- List nft = new ArrayList();
+ List nft = new ArrayList<>();
for (String featureType : featureTypes)
{
if (!fdi.isRegistered(featureType))
@@ -205,7 +205,7 @@ public abstract class FeatureRendererModel
renderOrder = neworder;
}
- protected Map minmax = new Hashtable();
+ protected Map minmax = new Hashtable<>();
public Map getMinMax()
{
@@ -284,7 +284,7 @@ public abstract class FeatureRendererModel
* include features at the position provided their feature type is
* displayed, and feature group is null or marked for display
*/
- List result = new ArrayList();
+ List result = new ArrayList<>();
if (!av.areFeaturesDisplayed() || getFeaturesDisplayed() == null)
{
return result;
@@ -333,7 +333,7 @@ public abstract class FeatureRendererModel
}
FeaturesDisplayedI featuresDisplayed = av.getFeaturesDisplayed();
- Set oldfeatures = new HashSet();
+ Set oldfeatures = new HashSet<>();
if (renderOrder != null)
{
for (int i = 0; i < renderOrder.length; i++)
@@ -346,7 +346,7 @@ public abstract class FeatureRendererModel
}
AlignmentI alignment = av.getAlignment();
- List allfeatures = new ArrayList();
+ List allfeatures = new ArrayList<>();
for (int i = 0; i < alignment.getHeight(); i++)
{
@@ -426,7 +426,7 @@ public abstract class FeatureRendererModel
*/
if (minmax == null)
{
- minmax = new Hashtable();
+ minmax = new Hashtable<>();
}
synchronized (minmax)
{
@@ -463,7 +463,7 @@ public abstract class FeatureRendererModel
*/
private void updateRenderOrder(List allFeatures)
{
- List allfeatures = new ArrayList(allFeatures);
+ List allfeatures = new ArrayList<>(allFeatures);
String[] oldRender = renderOrder;
renderOrder = new String[allfeatures.size()];
boolean initOrders = (featureOrder == null);
@@ -624,7 +624,7 @@ public abstract class FeatureRendererModel
{
if (featureOrder == null)
{
- featureOrder = new Hashtable();
+ featureOrder = new Hashtable<>();
}
featureOrder.put(type, new Float(position));
return position;
@@ -683,7 +683,7 @@ public abstract class FeatureRendererModel
* note visible feature ordering and colours before update
*/
List visibleFeatures = getDisplayedFeatureTypes();
- Map visibleColours = new HashMap(
+ Map visibleColours = new HashMap<>(
getFeatureColours());
FeaturesDisplayedI av_featuresdisplayed = null;
@@ -843,7 +843,7 @@ public abstract class FeatureRendererModel
{
if (featureGroups != null)
{
- List gp = new ArrayList();
+ List gp = new ArrayList<>();
for (String grp : featureGroups.keySet())
{
@@ -889,7 +889,7 @@ public abstract class FeatureRendererModel
@Override
public Map getDisplayedFeatureCols()
{
- Map fcols = new Hashtable();
+ Map fcols = new Hashtable<>();
if (getViewport().getFeaturesDisplayed() == null)
{
return fcols;
@@ -917,7 +917,7 @@ public abstract class FeatureRendererModel
public List getDisplayedFeatureTypes()
{
List typ = getRenderOrder();
- List displayed = new ArrayList();
+ List displayed = new ArrayList<>();
FeaturesDisplayedI feature_disp = av.getFeaturesDisplayed();
if (feature_disp != null)
{
@@ -938,7 +938,7 @@ public abstract class FeatureRendererModel
@Override
public List getDisplayedFeatureGroups()
{
- List _gps = new ArrayList();
+ List _gps = new ArrayList<>();
for (String gp : getFeatureGroups())
{
if (checkGroupVisibility(gp, false))
@@ -973,7 +973,7 @@ public abstract class FeatureRendererModel
public List findFeaturesAtResidue(SequenceI sequence,
int resNo)
{
- List result = new ArrayList();
+ List result = new ArrayList<>();
if (!av.areFeaturesDisplayed() || getFeaturesDisplayed() == null)
{
return result;
diff --git a/test/jalview/datamodel/features/FeatureAttributesTest.java b/test/jalview/datamodel/features/FeatureAttributesTest.java
new file mode 100644
index 0000000..e464326
--- /dev/null
+++ b/test/jalview/datamodel/features/FeatureAttributesTest.java
@@ -0,0 +1,41 @@
+package jalview.datamodel.features;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Comparator;
+
+import junit.extensions.PA;
+
+import org.testng.annotations.Test;
+
+public class FeatureAttributesTest
+{
+
+ /**
+ * Test the method that keeps attribute names in non-case-sensitive order,
+ * including handling of 'compound' names
+ */
+ @Test(groups="Functional")
+ public void testAttributeNameComparator()
+ {
+ FeatureAttributes fa = FeatureAttributes.getInstance();
+ Comparator comp = (Comparator) PA.getValue(fa,
+ "comparator");
+
+ assertEquals(
+ comp.compare(new String[] { "CSQ" }, new String[] { "csq" }), 0);
+
+ assertTrue(comp.compare(new String[] { "CSQ", "a" },
+ new String[] { "csq" }) > 0);
+
+ assertTrue(comp.compare(new String[] { "CSQ" }, new String[] { "csq",
+ "b" }) < 0);
+
+ assertTrue(comp.compare(new String[] { "CSQ", "AF" }, new String[] {
+ "csq", "ac" }) > 0);
+
+ assertTrue(comp.compare(new String[] { "CSQ", "ac" }, new String[] {
+ "csq", "AF" }) < 0);
+ }
+}
diff --git a/test/jalview/gui/AlignViewportTest.java b/test/jalview/gui/AlignViewportTest.java
index 812fd8f..5ed0cac 100644
--- a/test/jalview/gui/AlignViewportTest.java
+++ b/test/jalview/gui/AlignViewportTest.java
@@ -96,57 +96,6 @@ public class AlignViewportTest
testee = new AlignViewport(al);
}
- @Test(groups = { "Functional" })
- public void testCollateForPdb()
- {
- // JBP: What behaviour is this supposed to test ?
- /*
- * Set up sequence pdb ids
- */
- PDBEntry pdb1 = new PDBEntry("1ABC", "B", Type.PDB, "1ABC.pdb");
- PDBEntry pdb2 = new PDBEntry("2ABC", "C", Type.PDB, "2ABC.pdb");
- PDBEntry pdb3 = new PDBEntry("3ABC", "D", Type.PDB, "3ABC.pdb");
-
- /*
- * seq1 and seq3 refer to 1abcB, seq2 to 2abcC, none to 3abcD
- */
- al.getSequenceAt(0).getDatasetSequence()
- .addPDBId(new PDBEntry("1ABC", "B", Type.PDB, "1ABC.pdb"));
- al.getSequenceAt(2).getDatasetSequence()
- .addPDBId(new PDBEntry("1ABC", "B", Type.PDB, "1ABC.pdb"));
- al.getSequenceAt(1).getDatasetSequence()
- .addPDBId(new PDBEntry("2ABC", "C", Type.PDB, "2ABC.pdb"));
- /*
- * Add a second chain PDB xref to Seq2 - should not result in a duplicate in
- * the results
- */
- al.getSequenceAt(1).getDatasetSequence()
- .addPDBId(new PDBEntry("2ABC", "D", Type.PDB, "2ABC.pdb"));
- /*
- * Seq3 refers to 3abc - this does not match 3ABC (as the code stands)
- */
- al.getSequenceAt(2).getDatasetSequence()
- .addPDBId(new PDBEntry("3abc", "D", Type.PDB, "3ABC.pdb"));
-
- /*
- * run method under test
- */
- SequenceI[][] seqs = testee.collateForPDB(new PDBEntry[] { pdb1, pdb2,
- pdb3 });
-
- // seq1 and seq3 refer to PDBEntry[0]
- assertEquals(2, seqs[0].length);
- assertSame(al.getSequenceAt(0), seqs[0][0]);
- assertSame(al.getSequenceAt(2), seqs[0][1]);
-
- // seq2 refers to PDBEntry[1]
- assertEquals(1, seqs[1].length);
- assertSame(al.getSequenceAt(1), seqs[1][0]);
-
- // no sequence refers to PDBEntry[2]
- assertEquals(0, seqs[2].length);
- }
-
/**
* Test that a mapping is not deregistered when a second view is closed but
* the first still holds a reference to the mapping
diff --git a/test/jalview/gui/StructureViewerTest.java b/test/jalview/gui/StructureViewerTest.java
index c1c1d5c..4d5b114 100644
--- a/test/jalview/gui/StructureViewerTest.java
+++ b/test/jalview/gui/StructureViewerTest.java
@@ -1,10 +1,17 @@
package jalview.gui;
import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.PDBEntry.Type;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
+
+import java.util.Map;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@@ -20,9 +27,11 @@ public class StructureViewerTest
}
@Test(groups = "Functional")
- public void testGetUniquePdbFiles()
+ public void testGetSequencesForPdbs()
{
- assertNull(StructureViewer.getUniquePdbFiles(null));
+ StructureViewer sv = new StructureViewer(null);
+
+ assertNull(sv.getSequencesForPdbs(null, null));
PDBEntry pdbe1 = new PDBEntry("1A70", "A", Type.PDB, "path1");
PDBEntry pdbe2 = new PDBEntry("3A6S", "A", Type.PDB, "path2");
@@ -30,13 +39,45 @@ public class StructureViewerTest
PDBEntry pdbe4 = new PDBEntry("1GAQ", "A", Type.PDB, null);
PDBEntry pdbe5 = new PDBEntry("3A6S", "B", Type.PDB, "path2");
PDBEntry pdbe6 = new PDBEntry("1GAQ", "B", Type.PDB, null);
+ PDBEntry[] pdbs = new PDBEntry[] { pdbe1, pdbe2, pdbe3, pdbe4, pdbe5,
+ pdbe6 };
+
+ /*
+ * seq1 ... seq6 associated with pdbe1 ... pdbe6
+ */
+ SequenceI[] seqs = new SequenceI[pdbs.length];
+ for (int i = 0; i < seqs.length; i++)
+ {
+ seqs[i] = new Sequence("Seq" + i, "abc");
+ }
/*
- * pdbe2 and pdbe5 get removed as having a duplicate file path
+ * pdbe3/5/6 should get removed as having a duplicate file path
*/
- PDBEntry[] uniques = StructureViewer.getUniquePdbFiles(new PDBEntry[] {
- pdbe1, pdbe2, pdbe3, pdbe4, pdbe5, pdbe6 });
- assertEquals(uniques,
- new PDBEntry[] { pdbe1, pdbe2, pdbe4, pdbe6 });
+ Map uniques = sv.getSequencesForPdbs(pdbs, seqs);
+ assertTrue(uniques.containsKey(pdbe1));
+ assertTrue(uniques.containsKey(pdbe2));
+ assertFalse(uniques.containsKey(pdbe3));
+ assertTrue(uniques.containsKey(pdbe4));
+ assertFalse(uniques.containsKey(pdbe5));
+ assertFalse(uniques.containsKey(pdbe6));
+
+ // 1A70 associates with seq1 and seq3
+ SequenceI[] ss = uniques.get(pdbe1);
+ assertEquals(ss.length, 2);
+ assertSame(seqs[0], ss[0]);
+ assertSame(seqs[2], ss[1]);
+
+ // 3A6S has seq2 and seq5
+ ss = uniques.get(pdbe2);
+ assertEquals(ss.length, 2);
+ assertSame(seqs[1], ss[0]);
+ assertSame(seqs[4], ss[1]);
+
+ // 1GAQ has seq4 and seq6
+ ss = uniques.get(pdbe4);
+ assertEquals(ss.length, 2);
+ assertSame(seqs[3], ss[0]);
+ assertSame(seqs[5], ss[1]);
}
}
diff --git a/test/jalview/schemes/Blosum62ColourSchemeTest.java b/test/jalview/schemes/Blosum62ColourSchemeTest.java
index 0b5b6bd..030a90f 100644
--- a/test/jalview/schemes/Blosum62ColourSchemeTest.java
+++ b/test/jalview/schemes/Blosum62ColourSchemeTest.java
@@ -20,7 +20,7 @@ public class Blosum62ColourSchemeTest
*
*
*/
- @Test
+ @Test(groups = "Functional")
public void testFindColour()
{
ColourSchemeI blosum = new Blosum62ColourScheme();
diff --git a/test/jalview/util/MapListTest.java b/test/jalview/util/MapListTest.java
index d2db258..3fc6fe0 100644
--- a/test/jalview/util/MapListTest.java
+++ b/test/jalview/util/MapListTest.java
@@ -818,7 +818,7 @@ public class MapListTest
/**
* Test the method that compounds ('traverses') two mappings
*/
- @Test
+ @Test(groups = "Functional")
public void testTraverse()
{
/*
diff --git a/test/jalview/util/MathUtilsTest.java b/test/jalview/util/MathUtilsTest.java
index fc84741..dc23472 100644
--- a/test/jalview/util/MathUtilsTest.java
+++ b/test/jalview/util/MathUtilsTest.java
@@ -6,7 +6,7 @@ import org.testng.annotations.Test;
public class MathUtilsTest
{
- @Test
+ @Test(groups = "Functional")
public void testGcd()
{
assertEquals(MathUtils.gcd(0, 0), 0);
diff --git a/test/jalview/util/matcher/ConditionTest.java b/test/jalview/util/matcher/ConditionTest.java
index 270aa2a..9d8b225 100644
--- a/test/jalview/util/matcher/ConditionTest.java
+++ b/test/jalview/util/matcher/ConditionTest.java
@@ -8,7 +8,7 @@ import org.testng.annotations.Test;
public class ConditionTest
{
- @Test
+ @Test(groups = "Functional")
public void testToString()
{
Locale.setDefault(Locale.UK);
diff --git a/test/jalview/util/matcher/KeyedMatcherSetTest.java b/test/jalview/util/matcher/KeyedMatcherSetTest.java
index 3018cb6..3d597d2 100644
--- a/test/jalview/util/matcher/KeyedMatcherSetTest.java
+++ b/test/jalview/util/matcher/KeyedMatcherSetTest.java
@@ -12,13 +12,13 @@ import org.testng.annotations.Test;
public class KeyedMatcherSetTest
{
- @Test
+ @Test(groups = "Functional")
public void testMatches()
{
/*
* a numeric matcher - MatcherTest covers more conditions
*/
- KeyedMatcherI km = new KeyedMatcher("AF", Condition.GE, -2F);
+ KeyedMatcherI km = new KeyedMatcher(Condition.GE, -2F, "AF");
KeyedMatcherSetI kms = new KeyedMatcherSet();
kms.and(km);
assertTrue(kms.matches(key -> "-2"));
@@ -31,24 +31,25 @@ public class KeyedMatcherSetTest
/*
* a string pattern matcher
*/
- km = new KeyedMatcher("AF", Condition.Contains, "Cat");
+ km = new KeyedMatcher(Condition.Contains, "Cat", "AF");
kms = new KeyedMatcherSet();
kms.and(km);
assertTrue(kms
- .matches(key -> "AF".equals(key) ? "raining cats and dogs"
+ .matches(key -> "AF".equals(key[0]) ? "raining cats and dogs"
: "showers"));
}
- @Test
+ @Test(groups = "Functional")
public void testAnd()
{
// condition1: AF value contains "dog" (matches)
- KeyedMatcherI km1 = new KeyedMatcher("AF", Condition.Contains, "dog");
+ KeyedMatcherI km1 = new KeyedMatcher(Condition.Contains, "dog", "AF");
// condition 2: CSQ value does not contain "how" (does not match)
- KeyedMatcherI km2 = new KeyedMatcher("CSQ", Condition.NotContains,
- "how");
+ KeyedMatcherI km2 = new KeyedMatcher(Condition.NotContains, "how",
+ "CSQ");
- Function vp = key -> "AF".equals(key) ? "raining cats and dogs"
+ Function vp = key -> "AF".equals(key[0])
+ ? "raining cats and dogs"
: "showers";
assertTrue(km1.matches(vp));
assertFalse(km2.matches(vp));
@@ -61,13 +62,14 @@ public class KeyedMatcherSetTest
assertFalse(kms.matches(vp));
}
- @Test
+ @Test(groups = "Functional")
public void testToString()
{
- KeyedMatcherI km1 = new KeyedMatcher("AF", Condition.LT, 1.2f);
+ KeyedMatcherI km1 = new KeyedMatcher(Condition.LT, 1.2f, "AF");
assertEquals(km1.toString(), "AF < 1.2");
- KeyedMatcher km2 = new KeyedMatcher("CLIN_SIG", Condition.NotContains, "path");
+ KeyedMatcher km2 = new KeyedMatcher(Condition.NotContains, "path",
+ "CLIN_SIG");
assertEquals(km2.toString(), "CLIN_SIG Does not contain 'PATH'");
/*
@@ -93,16 +95,17 @@ public class KeyedMatcherSetTest
"(AF < 1.2) OR (CLIN_SIG Does not contain 'PATH')");
}
- @Test
+ @Test(groups = "Functional")
public void testOr()
{
// condition1: AF value contains "dog" (matches)
- KeyedMatcherI km1 = new KeyedMatcher("AF", Condition.Contains, "dog");
+ KeyedMatcherI km1 = new KeyedMatcher(Condition.Contains, "dog", "AF");
// condition 2: CSQ value does not contain "how" (does not match)
- KeyedMatcherI km2 = new KeyedMatcher("CSQ", Condition.NotContains,
- "how");
+ KeyedMatcherI km2 = new KeyedMatcher(Condition.NotContains, "how",
+ "CSQ");
- Function vp = key -> "AF".equals(key) ? "raining cats and dogs"
+ Function vp = key -> "AF".equals(key[0])
+ ? "raining cats and dogs"
: "showers";
assertTrue(km1.matches(vp));
assertFalse(km2.matches(vp));
@@ -114,17 +117,17 @@ public class KeyedMatcherSetTest
assertTrue(kms.matches(vp));
}
- @Test
+ @Test(groups = "Functional")
public void testIsEmpty()
{
- KeyedMatcherI km = new KeyedMatcher("AF", Condition.GE, -2F);
+ KeyedMatcherI km = new KeyedMatcher(Condition.GE, -2F, "AF");
KeyedMatcherSetI kms = new KeyedMatcherSet();
assertTrue(kms.isEmpty());
kms.and(km);
assertFalse(kms.isEmpty());
}
- @Test
+ @Test(groups = "Functional")
public void testGetMatchers()
{
KeyedMatcherSetI kms = new KeyedMatcherSet();
@@ -138,7 +141,7 @@ public class KeyedMatcherSetTest
/*
* one matcher:
*/
- KeyedMatcherI km1 = new KeyedMatcher("AF", Condition.GE, -2F);
+ KeyedMatcherI km1 = new KeyedMatcher(Condition.GE, -2F, "AF");
kms.and(km1);
iterator = kms.getMatchers().iterator();
assertSame(km1, iterator.next());
@@ -147,11 +150,44 @@ public class KeyedMatcherSetTest
/*
* two matchers:
*/
- KeyedMatcherI km2 = new KeyedMatcher("AF", Condition.LT, 8F);
+ KeyedMatcherI km2 = new KeyedMatcher(Condition.LT, 8F, "AF");
kms.and(km2);
iterator = kms.getMatchers().iterator();
assertSame(km1, iterator.next());
assertSame(km2, iterator.next());
assertFalse(iterator.hasNext());
}
+
+ /**
+ * Tests for the 'compound attribute' key i.e. where first key's value is a map
+ * from which we take the value for the second key, e.g. CSQ : Consequence
+ */
+ @Test(groups = "Functional")
+ public void testMatches_compoundKey()
+ {
+ /*
+ * a numeric matcher - MatcherTest covers more conditions
+ */
+ KeyedMatcherI km = new KeyedMatcher(Condition.GE, -2F, "CSQ",
+ "Consequence");
+ KeyedMatcherSetI kms = new KeyedMatcherSet();
+ kms.and(km);
+ assertTrue(kms.matches(key -> "-2"));
+ assertTrue(kms.matches(key -> "-1"));
+ assertFalse(kms.matches(key -> "-3"));
+ assertFalse(kms.matches(key -> ""));
+ assertFalse(kms.matches(key -> "junk"));
+ assertFalse(kms.matches(key -> null));
+
+ /*
+ * a string pattern matcher
+ */
+ km = new KeyedMatcher(Condition.Contains, "Cat", "CSQ", "Consequence");
+ kms = new KeyedMatcherSet();
+ kms.and(km);
+ assertTrue(kms.matches(key -> "csq".equalsIgnoreCase(key[0])
+ && "Consequence".equalsIgnoreCase(key[1])
+ ? "raining cats and dogs"
+ : "showers"));
+ }
}
diff --git a/test/jalview/util/matcher/KeyedMatcherTest.java b/test/jalview/util/matcher/KeyedMatcherTest.java
index 164b8eb..01d0067 100644
--- a/test/jalview/util/matcher/KeyedMatcherTest.java
+++ b/test/jalview/util/matcher/KeyedMatcherTest.java
@@ -14,7 +14,7 @@ public class KeyedMatcherTest
/*
* a numeric matcher - MatcherTest covers more conditions
*/
- KeyedMatcherI km = new KeyedMatcher("AF", Condition.GE, -2F);
+ KeyedMatcherI km = new KeyedMatcher(Condition.GE, -2F, "AF");
assertTrue(km.matches(key -> "-2"));
assertTrue(km.matches(key -> "-1"));
assertFalse(km.matches(key -> "-3"));
@@ -25,9 +25,10 @@ public class KeyedMatcherTest
/*
* a string pattern matcher
*/
- km = new KeyedMatcher("AF", Condition.Contains, "Cat");
- assertTrue(km.matches(key -> "AF".equals(key) ? "raining cats and dogs"
- : "showers"));
+ km = new KeyedMatcher(Condition.Contains, "Cat", "AF");
+ assertTrue(
+ km.matches(key -> "AF".equals(key[0]) ? "raining cats and dogs"
+ : "showers"));
}
@Test
@@ -36,21 +37,27 @@ public class KeyedMatcherTest
/*
* toString uses the i18n translation of the enum conditions
*/
- KeyedMatcherI km = new KeyedMatcher("AF", Condition.LT, 1.2f);
+ KeyedMatcherI km = new KeyedMatcher(Condition.LT, 1.2f, "AF");
assertEquals(km.toString(), "AF < 1.2");
}
@Test
public void testGetKey()
{
- KeyedMatcherI km = new KeyedMatcher("AF", Condition.GE, -2F);
- assertEquals(km.getKey(), "AF");
+ KeyedMatcherI km = new KeyedMatcher(Condition.GE, -2F, "AF");
+ assertEquals(km.getKey(), new String[] { "AF" });
+
+ /*
+ * compound key (attribute / subattribute)
+ */
+ km = new KeyedMatcher(Condition.GE, -2F, "CSQ", "Consequence");
+ assertEquals(km.getKey(), new String[] { "CSQ", "Consequence" });
}
@Test
public void testGetMatcher()
{
- KeyedMatcherI km = new KeyedMatcher("AF", Condition.GE, -2F);
+ KeyedMatcherI km = new KeyedMatcher(Condition.GE, -2F, "AF");
assertEquals(km.getMatcher().getCondition(), Condition.GE);
assertEquals(km.getMatcher().getFloatValue(), -2F);
assertEquals(km.getMatcher().getPattern(), "-2.0");
diff --git a/test/jalview/util/matcher/MatcherTest.java b/test/jalview/util/matcher/MatcherTest.java
index 489cdce..ee0ff82 100644
--- a/test/jalview/util/matcher/MatcherTest.java
+++ b/test/jalview/util/matcher/MatcherTest.java
@@ -10,7 +10,7 @@ import org.testng.annotations.Test;
public class MatcherTest
{
- @Test
+ @Test(groups = "Functional")
public void testConstructor()
{
MatcherI m = new Matcher(Condition.Contains, "foo");
@@ -55,7 +55,7 @@ public class MatcherTest
/**
* Tests for float comparison conditions
*/
- @Test
+ @Test(groups = "Functional")
public void testMatches_float()
{
/*
@@ -107,7 +107,7 @@ public class MatcherTest
assertTrue(m.matches("1.9"));
}
- @Test
+ @Test(groups = "Functional")
public void testMatches_floatNullOrInvalid()
{
for (Condition cond : Condition.values())
@@ -125,7 +125,7 @@ public class MatcherTest
/**
* Tests for string comparison conditions
*/
- @Test
+ @Test(groups = "Functional")
public void testMatches_pattern()
{
/*
@@ -177,7 +177,7 @@ public class MatcherTest
/**
* If a float is passed with a string condition it gets converted to a string
*/
- @Test
+ @Test(groups = "Functional")
public void testMatches_floatWithStringCondition()
{
MatcherI m = new Matcher(Condition.Contains, 1.2e-6f);
@@ -189,7 +189,7 @@ public class MatcherTest
assertFalse(m.matches("0.0000001f"));
}
- @Test
+ @Test(groups = "Functional")
public void testToString()
{
MatcherI m = new Matcher(Condition.LT, 1.2e-6f);
@@ -202,7 +202,7 @@ public class MatcherTest
assertEquals(m.toString(), "Contains '-1.2'");
}
- @Test
+ @Test(groups = "Functional")
public void testEquals()
{
/*
@@ -235,7 +235,7 @@ public class MatcherTest
assertFalse(m.equals(new Matcher(Condition.LT, -1.1f)));
}
- @Test
+ @Test(groups = "Functional")
public void testHashCode()
{
MatcherI m1 = new Matcher(Condition.NotMatches, "ABC");
|