<classpathentry kind="con" path="org.testng.TESTNG_CONTAINER"/>
<classpathentry kind="lib" path="lib/biojava-core-4.1.0.jar"/>
<classpathentry kind="lib" path="lib/biojava-ontology-4.1.0.jar"/>
- <classpathentry kind="lib" path="lib/groovy-all-2.4.6-indy.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="lib" path="lib/htsjdk-2.12.0.jar"/>
+ <classpathentry kind="lib" path="lib/groovy-all-2.4.12-indy.jar"/>
<classpathentry kind="output" path="classes"/>
</classpath>
To set up benchmarking:
-1. In the jalview directory run
+You will need to install Maven: https://maven.apache.org/install.html
+
+1. Run the makedist target of build.xml in Eclipse, or in the jalview directory run
ant makedist
This builds a jalview.jar file and puts it into dist/
-2. Make a lib directory in benchmarking/ if not already present.
+2. Make a lib directory in benchmarking/ if not already present and cd into this directory.
3. Purge any previous maven dependencies:
mvn dependency:purge-local-repository -DactTransitively=false -DreResolve=false
@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Fork(1)
public class HiddenColumnsBenchmark
-{
- /*
- * State with multiple hidden columns and a start position set
- */
- @State(Scope.Thread)
- public static class HiddenColsAndStartState
- {
- @Param({"300", "10000", "100000"})
- public int maxcols;
-
- @Param({"1", "50", "90"})
- public int startpcnt; // position as percentage of maxcols
-
- @Param({"1","15","100"})
- public int hide;
-
- HiddenColumns h = new HiddenColumns();
- Random rand = new Random();
-
- public int hiddenColumn;
- public int visibleColumn;
-
- @Setup
- public void setup()
- {
- rand.setSeed(1234);
- int lastcol = 0;
- while (lastcol < maxcols)
- {
- int count = rand.nextInt(100);
- lastcol += count;
- h.hideColumns(lastcol, lastcol+hide);
- lastcol+=hide;
- }
-
- // make sure column at start is hidden
- hiddenColumn = (int)(maxcols * startpcnt/100.0);
- h.hideColumns(hiddenColumn, hiddenColumn);
-
- // and column <hide> after start is visible
- ColumnSelection sel = new ColumnSelection();
- h.revealHiddenColumns(hiddenColumn+hide, sel);
- visibleColumn = hiddenColumn+hide;
-
- System.out.println("Maxcols: " + maxcols + " HiddenCol: " + hiddenColumn + " Hide: " + hide);
- System.out.println("Number of hidden columns: " + h.getSize());
- }
- }
-
- /* Convention: functions in alphabetical order */
-
- @Benchmark
- @BenchmarkMode({Mode.Throughput})
- public int benchAdjustForHiddenColumns(HiddenColsAndStartState tstate)
- {
- return tstate.h.adjustForHiddenColumns(tstate.visibleColumn);
- }
-
- @Benchmark
- @BenchmarkMode({Mode.Throughput})
- public int benchFindColumnPosition(HiddenColsAndStartState tstate)
- {
- return tstate.h.findColumnPosition(tstate.visibleColumn);
- }
-
- @Benchmark
- @BenchmarkMode({Mode.Throughput})
- public List<Integer> benchFindHiddenRegionPositions(HiddenColsAndStartState tstate)
- {
- return tstate.h.findHiddenRegionPositions();
- }
-
- @Benchmark
- @BenchmarkMode({Mode.Throughput})
- public ArrayList<int[]> benchGetHiddenColumnsCopy(HiddenColsAndStartState tstate)
- {
- return tstate.h.getHiddenColumnsCopy();
- }
-
-
- @Benchmark
- @BenchmarkMode({Mode.Throughput})
- public int benchGetSize(HiddenColsAndStartState tstate)
- {
- return tstate.h.getSize();
- }
+{
+ /*
+ * State with multiple hidden columns and a start position set
+ */
+ @State(Scope.Thread)
+ public static class HiddenColsAndStartState
+ {
+ @Param({ "300", "10000", "100000" })
+ public int maxcols;
- @Benchmark
- @BenchmarkMode({Mode.Throughput})
- public HiddenColumns benchHideCols(HiddenColsAndStartState tstate)
- {
- tstate.h.hideColumns(tstate.visibleColumn,
- tstate.visibleColumn+2000);
- return tstate.h;
- }
-
- @Benchmark
- @BenchmarkMode({Mode.Throughput})
- public boolean benchIsVisible(HiddenColsAndStartState tstate)
- {
- return tstate.h.isVisible(tstate.hiddenColumn);
- }
-
- @Benchmark
- @BenchmarkMode({Mode.Throughput})
- public HiddenColumns benchReveal(HiddenColsAndStartState tstate)
- {
- ColumnSelection sel = new ColumnSelection();
- tstate.h.revealHiddenColumns(tstate.hiddenColumn, sel);
- return tstate.h;
- }
-
- @Benchmark
- @BenchmarkMode({Mode.Throughput})
- public HiddenColumns benchRevealAll(HiddenColsAndStartState tstate)
+ @Param({ "1", "50", "90" })
+ public int startpcnt; // position as percentage of maxcols
+
+ @Param({ "1", "15", "100" })
+ public int hide;
+
+ HiddenColumns h = new HiddenColumns();
+
+ Random rand = new Random();
+
+ public int hiddenColumn;
+
+ public int visibleColumn;
+
+ @Setup
+ public void setup()
{
- ColumnSelection sel = new ColumnSelection();
- tstate.h.revealAllHiddenColumns(sel);
- return tstate.h;
+ rand.setSeed(1234);
+ int lastcol = 0;
+ while (lastcol < maxcols)
+ {
+ int count = rand.nextInt(100);
+ lastcol += count;
+ h.hideColumns(lastcol, lastcol + hide);
+ lastcol += hide;
+ }
+
+ // make sure column at start is hidden
+ hiddenColumn = (int) (maxcols * startpcnt / 100.0);
+ h.hideColumns(hiddenColumn, hiddenColumn);
+
+ // and column <hide> after start is visible
+ ColumnSelection sel = new ColumnSelection();
+ h.revealHiddenColumns(hiddenColumn + hide, sel);
+ visibleColumn = hiddenColumn + hide;
+
+ System.out.println("Maxcols: " + maxcols + " HiddenCol: "
+ + hiddenColumn + " Hide: " + hide);
+ System.out.println("Number of hidden columns: " + h.getSize());
}
-
-
+ }
+
+ /* Convention: functions in alphabetical order */
+
+ @Benchmark
+ @BenchmarkMode({ Mode.Throughput })
+ public int benchAdjustForHiddenColumns(HiddenColsAndStartState tstate)
+ {
+ return tstate.h.adjustForHiddenColumns(tstate.visibleColumn);
+ }
+
+ @Benchmark
+ @BenchmarkMode({ Mode.Throughput })
+ public int benchFindColumnPosition(HiddenColsAndStartState tstate)
+ {
+ return tstate.h.findColumnPosition(tstate.visibleColumn);
+ }
+
+ @Benchmark
+ @BenchmarkMode({ Mode.Throughput })
+ public List<Integer> benchFindHiddenRegionPositions(
+ HiddenColsAndStartState tstate)
+ {
+ return tstate.h.findHiddenRegionPositions();
+ }
+
+ @Benchmark
+ @BenchmarkMode({ Mode.Throughput })
+ public ArrayList<int[]> benchGetHiddenColumnsCopy(
+ HiddenColsAndStartState tstate)
+ {
+ return tstate.h.getHiddenColumnsCopy();
+ }
+
+ @Benchmark
+ @BenchmarkMode({ Mode.Throughput })
+ public int benchGetSize(HiddenColsAndStartState tstate)
+ {
+ return tstate.h.getSize();
+ }
+
+ @Benchmark
+ @BenchmarkMode({ Mode.Throughput })
+ public HiddenColumns benchHideCols(HiddenColsAndStartState tstate)
+ {
+ tstate.h.hideColumns(tstate.visibleColumn, tstate.visibleColumn + 2000);
+ return tstate.h;
+ }
+
+ @Benchmark
+ @BenchmarkMode({ Mode.Throughput })
+ public boolean benchIsVisible(HiddenColsAndStartState tstate)
+ {
+ return tstate.h.isVisible(tstate.hiddenColumn);
+ }
+
+ @Benchmark
+ @BenchmarkMode({ Mode.Throughput })
+ public HiddenColumns benchReveal(HiddenColsAndStartState tstate)
+ {
+ ColumnSelection sel = new ColumnSelection();
+ tstate.h.revealHiddenColumns(tstate.hiddenColumn, sel);
+ return tstate.h;
+ }
+
+ @Benchmark
+ @BenchmarkMode({ Mode.Throughput })
+ public HiddenColumns benchRevealAll(HiddenColsAndStartState tstate)
+ {
+ ColumnSelection sel = new ColumnSelection();
+ tstate.h.revealAllHiddenColumns(sel);
+ return tstate.h;
+ }
+
}
\ No newline at end of file
<jnlpf toFile="${jnlpFile}" />
<!-- add the add-modules j2se attribute for java 9 -->
- <replace file="${jnlpFile}" value="j2se version="1.8+" initial-heap-size="${inih}" max-heap-size="${maxh}" java-vm-args="--add-modules=java.se.ee"">
+ <replace file="${jnlpFile}" value="j2se version="1.8+" initial-heap-size="${inih}" max-heap-size="${maxh}" java-vm-args="--add-modules=java.se.ee --illegal-access=warn"">
<replacetoken>j2se version="1.8+"</replacetoken>
-
- </replace>
+ </replace>
</target>
<target name="-dofakejnlpfileassoc" depends="-generatejnlpf" if="nojnlpfileassocs">
<tocitem text="Jalview Documentation" target="home" expand="true">
<tocitem text="What's new" target="new" expand="true">
<tocitem text="Latest Release Notes" target="release"/>
- <tocitem text="Calculations Dialog" target="calcs.dialog"/>
- <tocitem text="Groovy Features Counter example" target="groovy.featurescounter"/>
- <tocitem text="Custom Colourschemes in Groovy" target="groovy.colours"/>
- <tocitem text="Omit hidden regions in Overview" target="overview"/>
- <tocitem text="Show gaps as grey in overview" target="overviewprefs"/>
- <tocitem text="identifers.org for URL Links" target="linksprefs" />
- <tocitem text="New features in Split Frame View" target="splitframe.mirrorfonts" />
+
</tocitem>
<tocitem text="Editing Alignments" target="edit" />
<p>
To open the PDB Sequence Fetcher, select PDB as the database from
any <a href="seqfetch.html">Sequence Fetcher</a> dialog (opened <em>via</em>
- <strong>"File →Fetch Sequences"</strong>).
+ <strong>"File →Fetch Sequences"</strong>).
</p>
<img src="pdbseqfetcher.png" align="left"
alt="PDB sequence fetcher (introduced in Jalview 2.9)" />
<p>
<strong>Searching the PDB Database</strong>
</p>
+ <p>To search the PDB, begin typing in the text box. If the
+ 'autosearch' checkbox is enabled, then the results of your query
+ will be automatically updated and shown in the search results tab;
+ otherwise, press return to update the results. To access previous
+ searches, press the down-arrow or click the drop down menu icon at
+ the side of the search box. If you just want to paste in a list of
+ IDs, the 'Retrieve IDs' tab provides a batch-retrieval interface.</p>
<p>
- To search the PDB, begin typing in the text box. The results of your
- query are shown in the search results tab, which updates every time
- you type in the search text box. You can sort results according to
- the displayed columns, and select entries with the mouse and
- keyboard. Once you have selected one or more entries, hit the <strong>OK</strong>
- button to retrieve and view them in Jalview.
+ You can sort results according to the displayed columns, and select
+ entries with the mouse and keyboard. Once you have selected one or
+ more entries, hit the <strong>OK</strong> button to retrieve and
+ view them in Jalview.
</p>
<p>
<ul>
1xyz:A</li>
<li><strong>Bulk PDB retrieval</strong><br>Multiple PDB
- IDs can be specified by separating them with a semi-colon.<br />
- e.g. 1xyz;2xyz;3xyz<br />Hitting Return or OK will automatically
- fetch those IDs, like the default Sequence Fetcher interface.</li>
+ IDs can be specified for retrieval via the
+ <strong>Retrieve IDs</strong> tab.</li>
<li><strong>Wild card searching</strong><br>The following
wild cards are supported by the EMBL-EBI PDBe query service:
<p>
<strong>Searching the UniProt Database</strong>
</p>
- <p>
- To search UniProt, simply begin typing in the text box. After a
- short delay (about 1.5 seconds), results will be shown in the table
- below. You can sort results by clicking on the displayed columns,
+ <p>To search UniProt, simply begin typing in the text box. If the
+ 'autosearch' check box is enabled, then after a short delay (about
+ 1.5 seconds), results will be shown in the table below. Results are
+ also updated whenever you press Enter, and you can access previous
+ searches by pressing the 'Down' arrow or clicking the drop-down menu
+ icon at the side of the search box.</p>
+ <p>You can sort results by clicking on the displayed columns,
and select entries with the mouse or keyboard. Once you have
selected one or more entries, hit the <strong>OK</strong> button to
retrieve the sequences.
<li><strong>Bulk UniProt record retrieval</strong><br> To
- retrieve several uniprot accessions at once, first select <strong>UniProt
- ID</strong> from the dropdown menu, then paste in the accession IDs as a
- semi-colon separated list. (e.g. fila_human; mnt_human;
- mnt_mouse).<br />Hitting Return or OK will automatically fetch
- those IDs, like the default Sequence Fetcher interface.</li>
+ retrieve sequences for a list of Uniprot accessions, please enter
+ them via the 'Retrieve IDs' tab.</li>
<li><strong><a name="text-search">Complex queries
with the UniProt query Syntax</a></strong> The text box also allows complex
<td width="60" nowrap>
<div align="center">
<strong><a name="Jalview.2.10.3">2.10.3</a><br />
- <em>10/10/2017</em></strong>
+ <em>14/11/2017</em></strong>
</div>
</td>
<td><div align="left">
<li><!-- JAL-2617 -->Stop codons are excluded in CDS/Protein view from Ensembl locus cross-references</li>
<li><!-- JAL-2685 -->Start/End limits are shown in Pairwise Alignment report</li>
+ <li><!-- JAL-2810 -->Sequence fetcher's Free text 'autosearch' feature can be disabled</li>
+ <li><!-- JAL-2810 -->Retrieve IDs tab added for UniProt and PDB easier retrieval of sequences for lists of IDs</li>
+
+ </ul>
+ <em>Scripting</em>
+ <ul>
+ <li>Groovy interpreter updated to 2.4.12</li>
+ <li>Example groovy script for generating a matrix of percent identity scores for current alignment.</li>
</ul>
- <ul><li>Example groovy script for generating a matrix of percent identity scores for current alignment.</li></ul>
<em>Testing and Deployment</em>
<ul><li><!-- JAL-2727 -->Test to catch memory leaks in Jalview UI</li></ul>
</div>
<li><!-- JAL-2973 -->Alignment ruler height set incorrectly after canceling the Alignment Window's Font dialog</li>
<li><!-- JAL-2036 -->Show cross-references not enabled after restoring project until a new view is created</li>
<li><!-- JAL-2756 -->Warning popup about use of SEQUENCE_ID in URL links appears when only default EMBL-EBI link is configured (since 2.10.2b2)</li>
+ <li><!-- JAL-2775 -->Overview redraws whole window when box position is adjusted</li>
+ <li><!-- JAL-2225 -->Structure viewer doesn't map all chains in a multi-chain structure when viewing alignment involving more than one chain (since 2.10)</li>
</ul>
<strong><em>Applet</em></strong><br/>
<ul>
<!-- JAL-2546 -->BioJSON export does not preserve non-positional features
</li>
</ul>
+ <strong>Known Java 9 Issues</strong>
+ <ul>
+ <li><!-- JAL-2902 -->Groovy Console very slow to open and is
+ not responsive when entering characters (Webstart, Java 9.01,
+ OSX 10.10)
+ </li>
+ </ul>
+ <strong>New Known Issues</strong>
+ <ul>
+ <li><!-- JAL- --></li>
+ </ul>
</div>
</td>
</tr>
<strong>What's new in Jalview 2.10.3 ?</strong>
</p>
<p>
- Version 2.10.3 is due for release in October 2017. The full list of
+ Version 2.10.3 was released in November 2017. The full list of
bug fixes and new features can be found in the <a
href="releases.html#Jalview.2.10.3"> 2.10.3 Release Notes</a>, but
the highlights are below.
</p>
+ <ul>
+ <li>Faster import and more responsive UI when working with wide alignments and handling hundreds and thousands of sequence features</li>
+ <li>
+ <li>Improved usability with <a href="features/pdbsequencefetcher.html">PDB</a> and
+ <a href="features/uniprotsequencefetcher.html">UniProt</a> Free Text Search
+ dialog, and new tab for retrieval of sequences for lists of IDs.</li>
+ </ul>
<p>
<strong><a name="experimental">Experimental Features</a></strong>
</p>
label.original_data_for_params = Original Data for {0}
label.points_for_params = Points for {0}
label.transformed_points_for_params = Transformed points for {0}
-label.graduated_color_for_params = Graduated Feature Colour for {0}
+label.variable_color_for = Variable Feature Colour for {0}
label.select_background_colour = Select Background Colour
label.invalid_font = Invalid Font
label.separate_multiple_accession_ids = Enter one or more accession IDs separated by a semi-colon ";"
label.colour_by_label = Colour by label
label.variable_colour = Variable colour
label.select_new_colour = Select new colour
+label.no_feature_attributes = No feature attributes found
+option.enable_disable_autosearch = When ticked, search is performed automatically.
+option.autosearch = Autosearch
+label.retrieve_ids = Retrieve IDs
label.original_data_for_params = Datos originales de {0}
label.points_for_params = Puntos de {0}
label.transformed_points_for_params = Puntos transformados de {0}
-label.graduated_color_for_params = Color graduado para la caracterÃstica de {0}
+label.variable_color_for = Color variable para la caracterÃstica de {0}
label.select_background_colour = Seleccionar color de fondo
label.invalid_font = Fuente no válida
label.separate_multiple_accession_ids = Separar los accession id con un punto y coma ";"
boolean isColourByAttribute();
/**
- * Answers the name of the attribute used for colouring if any, or null
+ * Answers the name of the attribute (and optional sub-attribute...) used for
+ * colouring if any, or null
*
* @return
*/
- String getAttributeName();
+ String[] getAttributeName();
/**
- * Sets the name of the attribute used for colouring if any, or null to remove
- * this property
+ * Sets the name of the attribute (and optional sub-attribute...) used for
+ * colouring if any, or null to remove this property
*
* @return
*/
- void setAttributeName(String name);
+ void setAttributeName(String... name);
}
List<String> getGroups(boolean visible);
/**
- * change visibility for a range of groups
+ * Set visibility for a list of groups
*
* @param toset
* @param visible
void setGroupVisibility(List<String> toset, boolean visible);
/**
- * change visibiilty of given group
+ * Set visibility of the given feature group
*
* @param group
* @param visible
void setGroupVisibility(String group, boolean visible);
/**
- * Returns features at the specified aligned column on the given sequence.
- * Non-positional features are not included. If the column has a gap, then
- * enclosing features are included (but not contact features).
+ * Returns visible features at the specified aligned column on the given
+ * sequence. Non-positional features are not included. If the column has a gap,
+ * then enclosing features are included (but not contact features).
*
* @param sequence
* @param column
slider.addAdjustmentListener(this);
slider.addMouseListener(this);
owner = (af != null) ? af : fs.frame;
- frame = new JVDialog(owner, MessageManager
- .formatMessage("label.graduated_color_for_params", new String[]
- { type }), true, 480, 248);
+ frame = new JVDialog(owner, MessageManager.formatMessage(
+ "label.variable_color_for", new String[] { type }), true, 480,
+ 248);
frame.setMainPanel(this);
validate();
frame.setVisible(true);
*/
Vector<AlignmentAnnotation> annotation;
- /**
- * The index of the sequence in a MSA
- */
- int index = -1;
-
private SequenceFeaturesI sequenceFeatureStore;
/*
}
}
- /**
- * @return The index (zero-based) on this sequence in the MSA. It returns
- * {@code -1} if this information is not available.
- */
- @Override
- public int getIndex()
- {
- return index;
- }
-
- /**
- * Defines the position of this sequence in the MSA. Use the value {@code -1}
- * if this information is undefined.
- *
- * @param The
- * position for this sequence. This value is zero-based (zero for
- * this first sequence)
- */
- @Override
- public void setIndex(int value)
- {
- index = value;
- }
-
@Override
public void setRNA(RNA r)
{
private static final String ROW_DATA = "<tr><td>%s</td><td>%s</td><td>%s</td></tr>";
/*
- * map of otherDetails special keys, and their value fields' delimiter
- */
- private static final Map<String, String> INFO_KEYS = new HashMap<>();
-
- static
- {
- INFO_KEYS.put("CSQ", ",");
- // todo capture second level metadata (CSQ FORMAT)
- // and delimiter "|" so as to report in a table within a table?
- }
-
- /*
* ATTRIBUTES is reserved for the GFF 'column 9' data, formatted as
* name1=value1;name2=value2,value3;...etc
*/
if (sf.otherDetails != null)
{
- otherDetails = new HashMap<String, Object>();
+ otherDetails = new HashMap<>();
for (Entry<String, Object> entry : sf.otherDetails.entrySet())
{
otherDetails.put(entry.getKey(), entry.getValue());
}
if (sf.links != null && sf.links.size() > 0)
{
- links = new Vector<String>();
+ links = new Vector<>();
for (int i = 0, iSize = sf.links.size(); i < iSize; i++)
{
links.addElement(sf.links.elementAt(i));
{
if (links == null)
{
- links = new Vector<String>();
+ links = new Vector<>();
}
if (!links.contains(labelLink))
/**
* Answers the value of the specified attribute as string, or null if no such
- * value
+ * value. If more than one attribute name is provided, tries to resolve as keys
+ * to nested maps. For example, if attribute "CSQ" holds a map of key-value
+ * pairs, then getValueAsString("CSQ", "Allele") returns the value of "Allele"
+ * in that map.
*
* @param key
* @return
*/
- public String getValueAsString(String key)
+ public String getValueAsString(String... key)
{
if (otherDetails == null)
{
return null;
}
- Object value = otherDetails.get(key);
+ Object value = otherDetails.get(key[0]);
+ if (key.length > 1 && value instanceof Map<?, ?>)
+ {
+ value = ((Map) value).get(key[1]);
+ }
return value == null ? null : value.toString();
}
{
if (otherDetails == null)
{
- otherDetails = new HashMap<String, Object>();
+ otherDetails = new HashMap<>();
}
otherDetails.put(key, value);
.getAttributeName(key);
}
- FeatureAttributes.getInstance().addAttribute(this.type, key, attDesc,
- value.toString());
+ FeatureAttributes.getInstance().addAttribute(this.type, attDesc, value,
+ key);
}
/*
{
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 <td title="key"> but it failed to provide a tooltip :-(
+ {
+ // tried <td title="key"> 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));
}
}
}
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
*/
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;
/**
{
private static FeatureAttributes instance = new FeatureAttributes();
- private Map<String, Map<String, AttributeData>> attributes;
+ /*
+ * map, by feature type, of a map, by attribute name, of
+ * attribute description and min-max range (if known)
+ */
+ private Map<String, Map<String[], AttributeData>> attributes;
+
+ /*
+ * a case-insensitive comparator so that attributes are ordered e.g.
+ * AC
+ * af
+ * CSQ:AFR_MAF
+ * CSQ:Allele
+ */
+ private Comparator<String[]> comparator = new Comparator<String[]>()
+ {
+ @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
{
}
/**
- * 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<String> getAttributes(String featureType)
+ public List<String[]> getAttributes(String featureType)
{
if (!attributes.containsKey(featureType))
{
- return Collections.<String> emptyList();
+ return Collections.<String[]> emptyList();
}
return new ArrayList<>(attributes.get(featureType).keySet());
* 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<String, AttributeData> 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<String[], AttributeData> atts = attributes.get(featureType);
if (atts == null)
{
- atts = new TreeMap<String, AttributeData>(
- String.CASE_INSENSITIVE_ORDER);
+ atts = new TreeMap<>(comparator);
attributes.put(featureType, atts);
}
AttributeData attData = atts.get(attName);
attData = new AttributeData();
atts.put(attName, attData);
}
- attData.addInstance(description, value);
+ attData.addInstance(description, valueAsString);
}
/**
* @param attName
* @return
*/
- public String getDescription(String featureType, String attName)
+ public String getDescription(String featureType, String... attName)
{
String desc = null;
- Map<String, AttributeData> atts = attributes.get(featureType);
+ Map<String[], AttributeData> atts = attributes.get(featureType);
if (atts != null)
{
AttributeData attData = atts.get(attName);
* @param attName
* @return
*/
- public float[] getMinMax(String featureType, String attName)
+ public float[] getMinMax(String featureType, String... attName)
{
- Map<String, AttributeData> atts = attributes.get(featureType);
+ Map<String[], AttributeData> atts = attributes.get(featureType);
if (atts != null)
{
AttributeData attData = atts.get(attName);
* @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<String, AttributeData> atts = attributes.get(featureType);
+ Map<String[], AttributeData> atts = attributes.get(featureType);
if (atts == null)
{
- atts = new TreeMap<String, AttributeData>(
- String.CASE_INSENSITIVE_ORDER);
+ atts = new TreeMap<>(comparator);
attributes.put(featureType, atts);
}
AttributeData attData = atts.get(attName);
return "EnsemblGenomes";
}
- private String Wrong[];
@Override
public String getTestQuery()
{
- return "DDB_G0283883";
+ /*
+ * Salmonella gene, Uniprot Q8Z9G6, EMBLCDS CAD01290
+ */
+ return "CAD01290";
}
@Override
* @return
*/
public String getCacheKey();
+
+ /**
+ *
+ * @return user preference name for configuring this FTS search's autosearch
+ * checkbox
+ */
+ public String getAutosearchPreference();
}
import javax.swing.ImageIcon;
import javax.swing.JButton;
+import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
protected JInternalFrame mainFrame = new JInternalFrame(
getFTSFrameTitle());
+ protected JTabbedPane tabs = new JTabbedPane();
protected IProgressIndicator progressIndicator;
protected JComboBox<FTSDataColumnI> cmb_searchTarget = new JComboBox<FTSDataColumnI>();
protected JButton btn_cancel = new JButton();
+ protected JCheckBox btn_autosearch = new JCheckBox();
+
protected JvCacheableInputBox<String> txt_search;
protected SequenceFetcher seqFetcher;
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();
}
});
+ 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()
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();
+ }
}
}
});
@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);
}
});
+ txt_search.addActionListener(new ActionListener()
+ {
+
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ performSearchAction();
+ }
+ });
final String searchTabTitle = MessageManager
.getString("label.search_result");
final String configureCols = MessageManager
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);
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()
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");
}
+ 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)
}
}
- protected void btn_back_ActionPerformed()
+ public void btn_back_ActionPerformed()
{
closeAction();
new SequenceFetcher(progressIndicator);
btn_cancel.setEnabled(false);
}
- protected void btn_cancel_ActionPerformed()
+ public void btn_cancel_ActionPerformed()
{
closeAction();
}
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
return PDB_FTS_CACHE_KEY;
}
-}
+ @Override
+ public String getAutosearchPreference()
+ {
+ return PDB_AUTOSEARCH;
+ }
+}
\ No newline at end of file
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;
{
return UNIPROT_FTS_CACHE_KEY;
}
+
+ @Override
+ public String getAutosearchPreference()
+ {
+ return UNIPROT_AUTOSEARCH;
+ }
}
.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<SequenceI[]> seqvectors = new ArrayList<SequenceI[]>();
- for (PDBEntry pdb : pdbEntries)
- {
- List<SequenceI> choosenSeqs = new ArrayList<SequenceI>();
- for (SequenceI sq : alignment.getSequences())
- {
- Vector<PDBEntry> 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()
{
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;
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()
}
});
+ // todo move all threshold setup inside a method
float mm[] = fr.getMinMax().get(theType)[0];
min = mm[0];
max = mm[1];
}
minColour.setBackground(oldminColour = cs.getMinColour());
maxColour.setBackground(oldmaxColour = cs.getMaxColour());
+ noColour = cs.getNoColour();
+
adjusting = true;
try
/*
* 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
{
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();
}
}
}
+ 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();
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)
{
byAttributeValue.addActionListener(changeMinMaxAction);
byWhatPanel.add(byAttributeValue);
- List<String> attNames = FeatureAttributes.getInstance().getAttributes(
- type);
+ List<String[]> attNames = FeatureAttributes.getInstance()
+ .getAttributes(type);
valueAttributeCombo = populateAttributesDropdown(type, attNames, true);
/*
}
/**
- * 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();
}
byAttributeText.addActionListener(changeColourAction);
byTextPanel.add(byAttributeText);
- List<String> attNames = FeatureAttributes.getInstance().getAttributes(
- type);
+ List<String[]> attNames = FeatureAttributes.getInstance()
+ .getAttributes(type);
textAttributeCombo = populateAttributesDropdown(type, attNames, false);
byTextPanel.add(textAttributeCombo);
{
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)
{
maxColour.setForeground(oldmaxColour);
minColour.setBackground(oldminColour);
minColour.setForeground(oldminColour);
+ noColour = oldNoColour;
}
/*
/**
* 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).
+ * <p>
+ * 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<String> populateAttributesDropdown(
- String featureType, List<String> attNames,
+ String featureType, List<String[]> attNames,
boolean withNumericRange)
{
List<String> validAtts = new ArrayList<>();
List<String> tooltips = new ArrayList<>();
FeatureAttributes fa = FeatureAttributes.getInstance();
- for (String attName : attNames)
+ for (String[] attName : attNames)
{
if (withNumericRange)
{
continue;
}
}
- validAtts.add(attName);
+ validAtts.add(String.join(COLON, attName));
String desc = fa.getDescription(featureType, attName);
if (desc != null && desc.length() > MAX_TOOLTIP_LENGTH)
{
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;
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;
private JTextArea filtersAsText;
+ // set white normally, black to debug layout
+ private Color debugBorderColour = Color.white;
+
/**
* Constructor
*
*/
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()
* 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);
/*
}
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);
-
}
/**
* look up attributes known for feature type
*/
String selectedType = (String) filteredFeatureChoice.getSelectedItem();
- List<String> attNames = FeatureAttributes.getInstance().getAttributes(
- selectedType);
+ List<String[]> attNames = FeatureAttributes.getInstance()
+ .getAttributes(selectedType);
/*
* if this feature type has filters set, load them first
/*
* 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);
/*
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();
* <li>a text field for input of a match pattern</li>
* <li>optionally, a 'remove' button</li>
* </ul>
- * 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<String> attNames,
+ protected JPanel addFilter(String[] attName, List<String[]> 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
*/
}
};
- 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);
*/
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"));
* @param attNames
*/
protected JComboBox<String> populateAttributesDropdown(
- String featureType, List<String> attNames)
+ String featureType, List<String[]> attNames)
{
+ List<String> displayNames = new ArrayList<>();
List<String> 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<String> attCombo = JvSwingUtils.buildComboWithTooltips(
- attNames, tooltips);
+ displayNames, tooltips);
if (attNames.isEmpty())
{
attCombo.setToolTipText(MessageManager
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);
}
if (gcol.isColourByAttribute())
{
- tx.append(gcol.getAttributeName());
+ tx.append(String.join(":", gcol.getAttributeName()));
}
else if (!gcol.isColourByLabel())
{
@Override
public void paintComponent(Graphics g)
{
+ // super.paintComponent(g);
+
if (restart)
{
if (lastMiniMe == null)
&& ((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,
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;
* 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)
@Override
public void propertyChange(PropertyChangeEvent evt)
{
- setBoxPosition();
+ setBoxPositionOnly();
}
/**
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;
JButton close = new JButton();
+ JButton back = new JButton();
+
JPanel jPanel1 = new JPanel();
JTextArea textArea = new JTextArea();
.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);
example_actionPerformed();
}
});
- close.setText(MessageManager.getString("action.close"));
+ close.setText(MessageManager.getString("action.cancel"));
close.addActionListener(new ActionListener()
{
@Override
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()
});
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();
try
{
frame.setClosed(true);
+ if (parentFTSframe!=null)
+ {
+ parentFTSframe.btn_cancel_ActionPerformed();
+ }
} catch (Exception ex)
{
}
textArea.setEnabled(false);
ok.setEnabled(false);
close.setEnabled(false);
-
+ back.setEnabled(false);
Thread worker = new Thread(this);
worker.start();
}
textArea.setEnabled(true);
ok.setEnabled(true);
close.setEnabled(true);
+ back.setEnabled(parentFTSframe != null);
}
@Override
{
frame.setVisible(false);
}
+
+ public void setDatabaseChooserVisible(boolean b)
+ {
+ databaseButt.setVisible(b);
+ }
}
}
if (pdbEntriesToView.length > 1)
{
- ArrayList<SequenceI[]> 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
{
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
JMOL, CHIMERA
};
+ /**
+ * Constructor
+ *
+ * @param structureSelectionManager
+ */
+ public StructureViewer(StructureSelectionManager structureSelectionManager)
+ {
+ ssm = structureSelectionManager;
+ }
+
public ViewerType getViewerType()
{
String viewType = Cache.getDefault(Preferences.STRUCTURE_DISPLAY,
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<PDBEntry, SequenceI[]> 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<PDBEntry, SequenceI[]> getSequencesForPdbs(PDBEntry[] pdbs,
+ SequenceI[] seqs)
{
- List<SequenceI> seqs = new ArrayList<SequenceI>();
- 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<String, PDBEntry> pdbsSeen = new HashMap<>();
+
+ /*
+ * LinkedHashMap preserves order of PDB entries (significant if they
+ * will get superimposed to the first structure)
+ */
+ Map<PDBEntry, List<SequenceI>> 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<SequenceI>());
+ }
+ else
+ {
+ pdb = pdbsSeen.get(pdbFile);
}
- SequenceI[] pdbseqs = seqsForPdbs[i++];
- if (pdbseqs != null)
+ List<SequenceI> 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<PDBEntry, SequenceI[]>
+ */
+ Map<PDBEntry, SequenceI[]> result = new LinkedHashMap<>();
+ for (Entry<PDBEntry, List<SequenceI>> entry : pdbSeqs.entrySet())
{
- sview = new ChimeraViewFrame(pdbsForFile,
- ap.av.collateForPDB(pdbsForFile), ap);
+ List<SequenceI> 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<SequenceI> seqs = new ArrayList<SequenceI>();
+ if (pdbs == null || pdbs.length == 0)
{
return null;
}
- List<PDBEntry> uniques = new ArrayList<PDBEntry>();
- List<String> filesSeen = new ArrayList<String>();
- 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))
{
}
else
{
- Cache.log.error("Unknown structure viewer type "
- + getViewerType().toString());
+ Cache.log.error(UNKNOWN_VIEWER_TYPE + getViewerType().toString());
}
return sview;
}
"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;
}
}
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);
- }
}
/**
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);
}
}
}
*/
Collection<List<String>> createLinksFrom(SequenceI seq, String link)
{
- Map<String, List<String>> urlSets = new LinkedHashMap<String, List<String>>();
+ Map<String, List<String>> urlSets = new LinkedHashMap<>();
UrlLink urlLink = new UrlLink(link);
if (!urlLink.isValid())
{
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;
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();
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;
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
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
*/
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
*/
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<String> 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<Integer, String> vepFieldsOfInterest;
+
/**
* Constructor given an alignment context
*
al = alignment;
// map of species!chromosome!fromAssembly!toAssembly to {fromRange, toRange}
- assemblyMappings = new HashMap<String, Map<int[], int[]>>();
+ assemblyMappings = new HashMap<>();
}
/**
/*
* get offset of CSQ ALLELE_NUM and Feature if declared
*/
- locateCsqFields();
+ parseCsqHeader();
VCFHeaderLine ref = header
.getOtherHeaderLine(VCFHeader.REFERENCE_KEY);
* 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<Pattern> vcfFieldPatterns = getFieldMatchers(VCF_FIELDS_PREF,
+ DEFAULT_VCF_FIELDS);
+ vcfFieldsOfInterest = new ArrayList<>();
+
+ FeatureSource metadata = new FeatureSource(theSourceId);
for (VCFInfoHeaderLine info : header.getInfoHeaderLines())
{
}
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<Pattern> 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.
+ * <p>
+ * CSQ fields are declared in the CSQ INFO Description e.g.
* <p>
* Description="Consequence ...from ... VEP. Format: Allele|Consequence|...
*/
- protected void locateCsqFields()
+ protected void parseCsqHeader()
{
- VCFInfoHeaderLine csqInfo = header.getInfoHeaderLine(CSQ);
+ List<Pattern> 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)
{
{
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.
+ * <p>
+ * 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<Pattern> getFieldMatchers(String key, String def)
+ {
+ String pref = Cache.getDefault(key, def);
+ List<Pattern> 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.
*
* 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')
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<?>))
{
}
}
- StringBuilder sb = new StringBuilder(128);
- boolean found = false;
+ /*
+ * inspect CSQ consequences; where possible restrict to the consequence
+ * associated with the current transcript (Feature)
+ */
+ Map<String, String> csqValues = new HashMap<>();
for (String consequence : consequences)
{
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);
}
}
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;
base = fc.base;
range = fc.range;
isHighToLow = fc.isHighToLow;
- byAttributeName = fc.byAttributeName;
+ attributeName = fc.attributeName;
setAboveThreshold(fc.isAboveThreshold());
setBelowThreshold(fc.isBelowThreshold());
setThreshold(fc.getThreshold());
{
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);
}
* 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)
{
@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;
}
}
*/
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);
* 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<String, String> valueProvider)
+ public boolean matches(Function<String[], String> valueProvider)
{
String value = valueProvider.apply(key);
return matcher.matches(value);
}
@Override
- public String getKey()
+ public String[] getKey()
{
return key;
}
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());
* @param valueProvider
* @return
*/
- boolean matches(Function<String, String> valueProvider);
+ boolean matches(Function<String[], String> valueProvider);
/**
* Answers the value key this matcher operates on
*
* @return
*/
- String getKey();
+ String[] getKey();
/**
* Answers the match condition that is applied
}
@Override
- public boolean matches(Function<String, String> valueProvider)
+ public boolean matches(Function<String[], String> valueProvider)
{
/*
* no conditions matches anything
* @param valueProvider
* @return
*/
- boolean matches(Function<String, String> valueProvider);
+ boolean matches(Function<String[], String> valueProvider);
/**
* Answers a new object that matches the logical AND of this and m
* @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
*/
{
av.setFeaturesDisplayed(fdi = new FeaturesDisplayed());
}
- List<String> nft = new ArrayList<String>();
+ List<String> nft = new ArrayList<>();
for (String featureType : featureTypes)
{
if (!fdi.isRegistered(featureType))
renderOrder = neworder;
}
- protected Map<String, float[][]> minmax = new Hashtable<String, float[][]>();
+ protected Map<String, float[][]> minmax = new Hashtable<>();
public Map<String, float[][]> getMinMax()
{
* include features at the position provided their feature type is
* displayed, and feature group is null or marked for display
*/
- List<SequenceFeature> result = new ArrayList<SequenceFeature>();
+ List<SequenceFeature> result = new ArrayList<>();
if (!av.areFeaturesDisplayed() || getFeaturesDisplayed() == null)
{
return result;
}
FeaturesDisplayedI featuresDisplayed = av.getFeaturesDisplayed();
- Set<String> oldfeatures = new HashSet<String>();
+ Set<String> oldfeatures = new HashSet<>();
if (renderOrder != null)
{
for (int i = 0; i < renderOrder.length; i++)
}
AlignmentI alignment = av.getAlignment();
- List<String> allfeatures = new ArrayList<String>();
+ List<String> allfeatures = new ArrayList<>();
for (int i = 0; i < alignment.getHeight(); i++)
{
*/
if (minmax == null)
{
- minmax = new Hashtable<String, float[][]>();
+ minmax = new Hashtable<>();
}
synchronized (minmax)
{
*/
private void updateRenderOrder(List<String> allFeatures)
{
- List<String> allfeatures = new ArrayList<String>(allFeatures);
+ List<String> allfeatures = new ArrayList<>(allFeatures);
String[] oldRender = renderOrder;
renderOrder = new String[allfeatures.size()];
boolean initOrders = (featureOrder == null);
{
if (featureOrder == null)
{
- featureOrder = new Hashtable<String, Float>();
+ featureOrder = new Hashtable<>();
}
featureOrder.put(type, new Float(position));
return position;
* note visible feature ordering and colours before update
*/
List<String> visibleFeatures = getDisplayedFeatureTypes();
- Map<String, FeatureColourI> visibleColours = new HashMap<String, FeatureColourI>(
+ Map<String, FeatureColourI> visibleColours = new HashMap<>(
getFeatureColours());
FeaturesDisplayedI av_featuresdisplayed = null;
{
if (featureGroups != null)
{
- List<String> gp = new ArrayList<String>();
+ List<String> gp = new ArrayList<>();
for (String grp : featureGroups.keySet())
{
@Override
public Map<String, FeatureColourI> getDisplayedFeatureCols()
{
- Map<String, FeatureColourI> fcols = new Hashtable<String, FeatureColourI>();
+ Map<String, FeatureColourI> fcols = new Hashtable<>();
if (getViewport().getFeaturesDisplayed() == null)
{
return fcols;
public List<String> getDisplayedFeatureTypes()
{
List<String> typ = getRenderOrder();
- List<String> displayed = new ArrayList<String>();
+ List<String> displayed = new ArrayList<>();
FeaturesDisplayedI feature_disp = av.getFeaturesDisplayed();
if (feature_disp != null)
{
@Override
public List<String> getDisplayedFeatureGroups()
{
- List<String> _gps = new ArrayList<String>();
+ List<String> _gps = new ArrayList<>();
for (String gp : getFeatureGroups())
{
if (checkGroupVisibility(gp, false))
public List<SequenceFeature> findFeaturesAtResidue(SequenceI sequence,
int resNo)
{
- List<SequenceFeature> result = new ArrayList<SequenceFeature>();
+ List<SequenceFeature> result = new ArrayList<>();
if (!av.areFeaturesDisplayed() || getFeaturesDisplayed() == null)
{
return result;
--- /dev/null
+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<String[]> comp = (Comparator<String[]>) 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);
+ }
+}
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
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;
}
@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");
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<PDBEntry, SequenceI[]> 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]);
}
}
* </ul>
* <ul>
*/
- @Test
+ @Test(groups = "Functional")
public void testFindColour()
{
ColourSchemeI blosum = new Blosum62ColourScheme();
/**
* Test the method that compounds ('traverses') two mappings
*/
- @Test
+ @Test(groups = "Functional")
public void testTraverse()
{
/*
public class MathUtilsTest
{
- @Test
+ @Test(groups = "Functional")
public void testGcd()
{
assertEquals(MathUtils.gcd(0, 0), 0);
public class ConditionTest
{
- @Test
+ @Test(groups = "Functional")
public void testToString()
{
Locale.setDefault(Locale.UK);
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"));
/*
* 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<String, String> vp = key -> "AF".equals(key) ? "raining cats and dogs"
+ Function<String[], String> vp = key -> "AF".equals(key[0])
+ ? "raining cats and dogs"
: "showers";
assertTrue(km1.matches(vp));
assertFalse(km2.matches(vp));
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'");
/*
"(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<String, String> vp = key -> "AF".equals(key) ? "raining cats and dogs"
+ Function<String[], String> vp = key -> "AF".equals(key[0])
+ ? "raining cats and dogs"
: "showers";
assertTrue(km1.matches(vp));
assertFalse(km2.matches(vp));
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();
/*
* 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());
/*
* 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"));
+ }
}
/*
* 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"));
/*
* 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
/*
* 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");
public class MatcherTest
{
- @Test
+ @Test(groups = "Functional")
public void testConstructor()
{
MatcherI m = new Matcher(Condition.Contains, "foo");
/**
* Tests for float comparison conditions
*/
- @Test
+ @Test(groups = "Functional")
public void testMatches_float()
{
/*
assertTrue(m.matches("1.9"));
}
- @Test
+ @Test(groups = "Functional")
public void testMatches_floatNullOrInvalid()
{
for (Condition cond : Condition.values())
/**
* Tests for string comparison conditions
*/
- @Test
+ @Test(groups = "Functional")
public void testMatches_pattern()
{
/*
/**
* 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);
assertFalse(m.matches("0.0000001f"));
}
- @Test
+ @Test(groups = "Functional")
public void testToString()
{
MatcherI m = new Matcher(Condition.LT, 1.2e-6f);
assertEquals(m.toString(), "Contains '-1.2'");
}
- @Test
+ @Test(groups = "Functional")
public void testEquals()
{
/*
assertFalse(m.equals(new Matcher(Condition.LT, -1.1f)));
}
- @Test
+ @Test(groups = "Functional")
public void testHashCode()
{
MatcherI m1 = new Matcher(Condition.NotMatches, "ABC");