jalview.release=releases/Release_2_11_3_Branch
-jalview.version=2.11.3.2
+jalview.version=2.11.3.3
}
+task launcherJar(type: Jar) {
+ manifest {
+ attributes (
+ "Main-Class": shadow_jar_main_class,
+ "Implementation-Version": JALVIEW_VERSION,
+ "Application-Name": applicationName
+ )
+ }
+}
+
shadowJar {
group = "distribution"
description = "Create a single jar file with all dependency libraries merged. Can be run with java -jar"
from groovyJars
from otherJars
+ manifest {
+ // shadowJar manifest must inheritFrom another Jar task. Can't set attributes here.
+ inheritFrom(project.tasks.launcherJar.manifest)
+ }
// we need to include the groovy-swing Include-Package for it to run in the shadowJar
doFirst {
def jarFileManifests = []
jarFileManifests += mf
}
}
-
manifest {
- attributes "Implementation-Version": JALVIEW_VERSION, "Application-Name": applicationName
from (jarFileManifests) {
eachEntry { details ->
if (!details.key.equals("Import-Package")) {
duplicatesStrategy "INCLUDE"
+ // this mainClassName is mandatory but gets ignored due to manifest created in doFirst{}. Set the Main-Class as an attribute in launcherJar instead
mainClassName = shadow_jar_main_class
mergeServiceFiles()
classifier = "all-"+JALVIEW_VERSION+"-j"+JAVA_VERSION
```
# download
git clone http://source.jalview.org/git/jalview.git
-# compile
+# compile - needs java 11 JDK
cd ./jalview
-gradle shadowJar
+gradle shadowJar # needs to be gradle 7.6.3 or above (but not gradle 8)
# run
java -jar build/libs/jalview-all-*-j11.jar
- <!-- JAL-4089 --> Use selected columns for superposition
- <!-- JAL-4086 --> Highlight aligned positions on all associated structures when mousing over a column
- <!-- JAL-4221 --> sequence descriptions are updated from database reference sources if not already defined
-- <!-- JAL-4273 --> Visible adjuster marks to grab and adjust annotation panel height and id width
+- <!-- JAL-4273,JAL-3497 --> Visible adjuster marks to grab and adjust annotation panel height and id width
- <!-- JAL-4260 --> Adjustable ID margin when alignment is wrapped
- <!-- JAL-4274 --> Command line options and configurable bitmap export (via preferences file) for height, width and scale factor
- <!-- JAL-4307 --> Show or hide ligands in a Jmol structure view via View Ligands submenu
---
version: 2.11.3.3
-date: 2023-12-14
+date: 2024-01-24
channel: "release"
---
## New Features
+- <!-- JAL-4192 --> Minimum versions of Jalview's build toolchain are explicitly specified in doc/building.md
+
## Issues Resolved
- <!-- JAL-840 --> Clustal colourscheme documentation not consistent with implementation
-
-
-
+- <!-- JAL-4367 --> Handles to adjust ID panel width or annotation panel height can be dragged out of the Alignment window
+- <!-- JAL-2934 --> Trackpad scrolling not proportional to gesture velocity
+- <!-- JAL-4353 --> Cannot output individual images of more than one structure view attached to one open alignment
+- <!-- JAL-4373 --> --jvmempc and --jvmemmax don't work for jalview installed via conda or jar
+- <!-- JAL-4368 --> User's default colour scheme is erroneously applied to alignments in Jalview projects opened via command line when no --colour argument supplied
+- <!-- JAL-4290 --> Headless alignment export with structure annotations doesn't include secondary structure and temperature factor
+- <!-- JAL-4369 --> Uniprot record retrieval not working in JalviewJS (affects all versions)
+- <!-- JAL-4243 --> bio.tools record version number updated
+- <!-- JAL-4217 --> Miscellaneous patches to fix hangs in 2.11.3 test suite
if (argParser.getBoolean(Arg.QUIT))
{
- Jalview.getInstance().exit(
- "Exiting due to " + Arg.QUIT.argString() + " argument.",
+ Jalview.exit("Exiting due to " + Arg.QUIT.argString() + " argument.",
ExitCode.OK);
return true;
}
Boolean isError = Boolean.valueOf(false);
- // set wrap scope here so it can be applied after structures are opened
+ // set wrap, showSSAnnotations, showAnnotations and hideTFrows scope here so
+ // it can be applied after structures are opened
boolean wrap = false;
+ boolean showSSAnnotations = false;
+ boolean showAnnotations = false;
+ boolean hideTFrows = false;
+ AlignFrame af = null;
if (avm.containsArg(Arg.APPEND) || avm.containsArg(Arg.OPEN))
{
boolean first = true;
boolean progressBarSet = false;
- AlignFrame af;
// Combine the APPEND and OPEN files into one list, along with whether it
// was APPEND or OPEN
List<ArgValue> openAvList = new ArrayList<>();
}
// colour alignment
- String colour = avm.getFromSubValArgOrPref(av, Arg.COLOUR, sv,
- null, "DEFAULT_COLOUR_PROT", "");
- this.colourAlignFrame(af, colour);
+ String colour = null;
+ if (avm.containsArg(Arg.COLOUR)
+ || !(format == FileFormat.Jalview))
+ {
+ colour = avm.getFromSubValArgOrPref(av, Arg.COLOUR, sv, null,
+ "DEFAULT_COLOUR_PROT", null);
+ }
+ if (colour != null)
+ {
+ this.colourAlignFrame(af, colour);
+ }
// Change alignment frame title
String title = avm.getFromSubValArgOrPref(av, Arg.TITLE, sv, null,
}
// Show secondary structure annotations?
- boolean showSSAnnotations = avm.getFromSubValArgOrPref(
+ showSSAnnotations = avm.getFromSubValArgOrPref(
Arg.SHOWSSANNOTATIONS, av.getSubVals(), null,
"STRUCT_FROM_PDB", true);
-
// Show sequence annotations?
- boolean showAnnotations = avm.getFromSubValArgOrPref(
- Arg.SHOWANNOTATIONS, av.getSubVals(), null,
- "SHOW_ANNOTATIONS", true);
-
- boolean hideTFrows = (avm.getBoolean(Arg.NOTEMPFAC));
- final AlignFrame _af = af;
- // many of jalview's format/layout methods are only thread safe on the
- // swingworker thread.
- // all these methods should be on the alignViewController so it can
- // coordinate such details
- try
- {
- SwingUtilities.invokeAndWait(new Runnable()
- {
-
- @Override
- public void run()
- {
- _af.setAnnotationsVisibility(showSSAnnotations, true,
- false);
-
- _af.setAnnotationsVisibility(showAnnotations, false, true);
+ showAnnotations = avm.getFromSubValArgOrPref(Arg.SHOWANNOTATIONS,
+ av.getSubVals(), null, "SHOW_ANNOTATIONS", true);
+ // hide the Temperature Factor row?
+ hideTFrows = (avm.getBoolean(Arg.NOTEMPFAC));
- // show temperature factor annotations?
- if (hideTFrows)
- {
- // do this better (annotation types?)
- List<String> hideThese = new ArrayList<>();
- hideThese.add("Temperature Factor");
- hideThese.add(AlphaFoldAnnotationRowBuilder.LABEL);
- AlignmentUtils.showOrHideSequenceAnnotations(
- _af.getCurrentView().getAlignment(), hideThese,
- null, false, false);
- }
- }
- });
- } catch (Exception x)
- {
- Console.warn(
- "Unexpected exception adjusting annotation row visibility.",
- x);
- }
+ // showSSAnnotations, showAnnotations, hideTFrows used after opening
+ // structure
// wrap alignment? do this last for formatting reasons
wrap = avm.getFromSubValArgOrPref(Arg.WRAP, sv, null,
// open the structure (from same PDB file or given PDBfile)
if (!avm.getBoolean(Arg.NOSTRUCTURE))
{
-
- AlignFrame af = afMap.get(id);
+ if (af == null)
+ {
+ af = afMap.get(id);
+ }
if (avm.containsArg(Arg.STRUCTURE))
{
commandArgsProvided = true;
- for (
-
- ArgValue av : avm.getArgValueList(Arg.STRUCTURE))
+ for (ArgValue structureAv : avm.getArgValueList(Arg.STRUCTURE))
{
argParser.setStructureFilename(null);
- String val = av.getValue();
- SubVals subVals = av.getSubVals();
- int argIndex = av.getArgIndex();
- SequenceI seq = getSpecifiedSequence(af, avm, av);
+ String val = structureAv.getValue();
+ SubVals subVals = structureAv.getSubVals();
+ int argIndex = structureAv.getArgIndex();
+ SequenceI seq = getSpecifiedSequence(af, avm, structureAv);
if (seq == null)
{
// Could not find sequence from subId, let's assume the first
// get PAEMATRIX file and label from subvals or Arg.PAEMATRIX
String paeFilepath = avm.getFromSubValArgOrPrefWithSubstitutions(
- argParser, Arg.PAEMATRIX, ArgValuesMap.Position.AFTER, av,
- subVals, null, null, null);
+ argParser, Arg.PAEMATRIX, ArgValuesMap.Position.AFTER,
+ structureAv, subVals, null, null, null);
if (paeFilepath != null)
{
File paeFile = new File(paeFilepath);
// get TEMPFAC type from subvals or Arg.TEMPFAC in case user Adds
// reference annotations
String tftString = avm.getFromSubValArgOrPrefWithSubstitutions(
- argParser, Arg.TEMPFAC, ArgValuesMap.Position.AFTER, av,
- subVals, null, null, null);
+ argParser, Arg.TEMPFAC, ArgValuesMap.Position.AFTER,
+ structureAv, subVals, null, null, null);
boolean notempfac = avm.getFromSubValArgOrPref(Arg.NOTEMPFAC,
subVals, null, "ADD_TEMPFACT_ANN", false, true);
TFType tft = notempfac ? null : TFType.DEFAULT;
}
String sViewerName = avm.getFromSubValArgOrPref(
- Arg.STRUCTUREVIEWER, ArgValuesMap.Position.AFTER, av,
- subVals, null, null, "jmol");
+ Arg.STRUCTUREVIEWER, ArgValuesMap.Position.AFTER,
+ structureAv, subVals, null, null, "jmol");
ViewerType viewerType = ViewerType.getFromString(sViewerName);
// TODO use ssFromStructure
if (avm.containsArg(Arg.STRUCTUREIMAGE))
{
for (ArgValue structureImageArgValue : avm
- .getArgValueList(Arg.STRUCTUREIMAGE))
+ .getArgValueListFromSubValOrArg(structureAv,
+ Arg.STRUCTUREIMAGE, subVals))
{
String structureImageFilename = argParser.makeSubstitutions(
structureImageArgValue.getValue(), id, true);
}
}
- if (wrap)
+ if (af == null)
+ {
+ af = afMap.get(id);
+ }
+ // many of jalview's format/layout methods are only thread safe on the
+ // swingworker thread.
+ // all these methods should be on the alignViewController so it can
+ // coordinate such details
+ if (headless)
{
+ showOrHideAnnotations(af, showSSAnnotations, showAnnotations,
+ hideTFrows);
+ }
+ else
+ {
+ try
+ {
+ AlignFrame _af = af;
+ final boolean _showSSAnnotations = showSSAnnotations;
+ final boolean _showAnnotations = showAnnotations;
+ final boolean _hideTFrows = hideTFrows;
+ SwingUtilities.invokeAndWait(() -> {
+ showOrHideAnnotations(_af, _showSSAnnotations, _showAnnotations,
+ _hideTFrows);
+ }
- AlignFrame af = afMap.get(id);
+ );
+ } catch (Exception x)
+ {
+ Console.warn(
+ "Unexpected exception adjusting annotation row visibility.",
+ x);
+ }
+ }
+
+ if (wrap)
+ {
+ if (af == null)
+ {
+ af = afMap.get(id);
+ }
if (af != null)
{
af.setWrapFormat(wrap, true);
return theseArgsWereParsed && !isError;
}
+ private static void showOrHideAnnotations(AlignFrame af,
+ boolean showSSAnnotations, boolean showAnnotations,
+ boolean hideTFrows)
+ {
+ af.setAnnotationsVisibility(showSSAnnotations, true, false);
+ af.setAnnotationsVisibility(showAnnotations, false, true);
+
+ // show temperature factor annotations?
+ if (hideTFrows)
+ {
+ // do this better (annotation types?)
+ List<String> hideThese = new ArrayList<>();
+ hideThese.add("Temperature Factor");
+ hideThese.add(AlphaFoldAnnotationRowBuilder.LABEL);
+ AlignmentUtils.showOrHideSequenceAnnotations(
+ af.getCurrentView().getAlignment(), hideThese, null, false,
+ false);
+ }
+ }
+
protected void processGroovyScript(String id)
{
ArgValuesMap avm = argParser.getLinkedArgs(id);
private void colourAlignFrame(AlignFrame af, ColourSchemeI cs)
{
- // Note that cs == null removes colour scheme from af
- af.changeColour(cs);
+ try {
+ SwingUtilities.invokeAndWait(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ // Note that cs == null removes colour scheme from af
+ af.changeColour(cs);
+ }
+ }); } catch (Exception x) {
+ Console.trace("Interrupted whilst waiting for colorAlignFrame action",x);
+
+ }
}
private ColourSchemeI getColourScheme(AlignFrame af)
import java.util.Locale;
import java.util.concurrent.TimeUnit;
+import jalview.bin.argparser.Arg;
import jalview.util.ChannelProperties;
import jalview.util.LaunchUtils;
* A Launcher class for Jalview. This class is used to launch Jalview from the
* shadowJar when Getdown is not used or available. It attempts to take all the
* command line arguments to pass on to the jalview.bin.Jalview class, but to
- * insert a -Xmx memory setting to a sensible default, using the -jvmmempc and
+ * insert a -Xmx memory setting to a sensible default, using the --jvmmempc and
* -jvmmemmax application arguments if specified. If not specified then system
* properties will be looked for by jalview.bin.MemorySetting. If the user has
- * provided the JVM with a -Xmx setting directly and not set -jvmmempc or
- * -jvmmemmax then this setting will be used and system properties ignored. If
- * -Xmx is set as well as -jvmmempc or -jvmmemmax as argument(s) then the -Xmx
+ * provided the JVM with a -Xmx setting directly and not set --jvmmempc or
+ * --jvmmemmax then this setting will be used and system properties ignored. If
+ * -Xmx is set as well as --jvmmempc or --jvmmemmax as argument(s) then the -Xmx
* argument will NOT be passed on to the main application launch.
*
* @author bsoares
/**
* main method for jalview.bin.Launcher. This restarts the same JRE's JVM with
- * the same arguments but with memory adjusted based on extracted -jvmmempc
- * and -jvmmemmax application arguments. If on a Mac then extra dock:icon and
+ * the same arguments but with memory adjusted based on extracted --jvmmempc
+ * and --jvmmemmax application arguments. If on a Mac then extra dock:icon and
* dock:name arguments are also set.
*
* @param args
}
// jvmmempc and jvmmemmax args used to set memory and are not passed on to
// startClass
- if (arg.startsWith(
- "-" + MemorySetting.MAX_HEAPSIZE_PERCENT_PROPERTY_NAME + "="))
+ final String jvmmempcArg = Arg.JVMMEMPC.getName();
+ final String jvmmemmaxArg = Arg.JVMMEMMAX.getName();
+ if (arg.startsWith("-" + jvmmempcArg + "="))
{
- jvmmempc = arg.substring(
- MemorySetting.MAX_HEAPSIZE_PERCENT_PROPERTY_NAME.length()
- + 2);
+ jvmmempc = arg.substring(jvmmempcArg.length() + 2);
}
- else if (arg.startsWith(
- "-" + MemorySetting.MAX_HEAPSIZE_PROPERTY_NAME + "="))
+ else if (arg.startsWith("-" + jvmmemmaxArg + "="))
{
- jvmmemmax = arg.substring(
- MemorySetting.MAX_HEAPSIZE_PROPERTY_NAME.length() + 2);
+ jvmmemmax = arg.substring(jvmmemmaxArg.length() + 2);
}
// --doubledash versions
- else if (arg.startsWith("--"
- + MemorySetting.MAX_HEAPSIZE_PERCENT_PROPERTY_NAME + "="))
+ else if (arg.startsWith("--" + jvmmempcArg + "="))
{
- jvmmempc = arg.substring(
- MemorySetting.MAX_HEAPSIZE_PERCENT_PROPERTY_NAME.length()
- + 3);
+ jvmmempc = arg.substring(jvmmempcArg.length() + 3);
}
- else if (arg.startsWith(
- "--" + MemorySetting.MAX_HEAPSIZE_PROPERTY_NAME + "="))
+ else if (arg.startsWith("--" + jvmmemmaxArg + "="))
{
- jvmmemmax = arg.substring(
- MemorySetting.MAX_HEAPSIZE_PROPERTY_NAME.length() + 3);
+ jvmmemmax = arg.substring(jvmmemmaxArg.length() + 3);
}
// retain arg
else
import java.util.Locale;
+import jalview.bin.argparser.Arg;
+
/**
* Methods to decide on appropriate memory setting for Jalview based on two
* optionally provided values: jvmmempc - the maximum percentage of total
*/
public class MemorySetting
{
- public static final String MAX_HEAPSIZE_PERCENT_PROPERTY_NAME = "jvmmempc";
+ public static final String MAX_HEAPSIZE_PERCENT_PROPERTY_NAME = Arg.JVMMEMPC
+ .getName();
- public static final String MAX_HEAPSIZE_PROPERTY_NAME = "jvmmemmax";
+ public static final String MAX_HEAPSIZE_PROPERTY_NAME = Arg.JVMMEMMAX
+ .getName();
private static final int MAX_HEAPSIZE_PERCENT_DEFAULT = 90; // 90%
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
+import java.util.Set;
import java.util.stream.Collectors;
import jalview.bin.argparser.Arg.Opt;
+ "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.",
Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS, Opt.MULTIVALUE,
Opt.ALLOWMULTIID, Opt.REQUIREINPUT, Opt.OUTPUTFILE, Opt.PRIMARY),
- STRUCTUREIMAGE(Type.IMAGE,
+ STRUCTUREIMAGE(new Type[]
+ { Type.IMAGE, Type.STRUCTUREIMAGE },
"Export an image of a 3D structure opened in JMOL", Opt.STRING,
Opt.LINKED, Opt.MULTIVALUE, Opt.OUTPUTFILE, Opt.ALLOWMULTIID,
Opt.PRIMARY),
BGCOLOUR(Type.IMAGE, "bgcolor", // being a bit soft on the Americans!
"Applies a background colour to the structure image. Valid values are named colours known to Java or RRGGBB 6 digit hex-string.",
Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID),
- /*
- STRUCTUREIMAGETYPE(Type.IMAGE,
- "Set the structure image format for the preceding --structureimage. Valid values are:\n"
- + "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.",
- Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
- STRUCTUREIMAGETEXTRENDERER(Type.IMAGE,
- "Sets whether text in a vector structure image format (SVG, EPS) should be rendered as text or vector line-art. Possible values are:\n"
- + "text,\n" + "lineart.",
- Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
- STRUCTUREIMAGESCALE(Type.IMAGE,
- "Sets a scaling for bitmap structure image format (PNG). Should be given as a floating point number. If used in conjunction with --structureimagewidth and --structureimageheight then the smallest scaling will be used (structureimagescale, structureimagewidth and structureimageheight provide bounds for the structure image).",
- Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
- STRUCTUREIMAGEWIDTH(Type.IMAGE,
- "Sets a width for bitmap structure image format (PNG) with the height maintaining the aspect ratio. Should be given as a positive integer. If used in conjunction with --structureimagescale and --structureimageheight then the smallest scaling will be used (structureimagescale, structureimagewidth and structureimageheight provide bounds for the structure image).",
- Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
- STRUCTUREIMAGEHEIGHT(Type.IMAGE,
- "Sets a height for bitmap structure image format (PNG) with the width maintaining the aspect ratio. Should be given as a positive integer. If used in conjunction with --structureimagescale and --structureimagewidth then the smallest scaling will be used (structureimagescale, structureimagewidth and structureimageheight provide bounds for the structure image).",
- Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID),
- */
-
OUTPUT(Type.OUTPUT,
"Export the open alignment to file filename. The format name is specified by the subval modifier format=name, a following --format name argument or guessed from the file extension. Valid format names (and file extensions) are:\n"
+ "fasta (fa, fasta, mfa, fastq),\n" + "pfam (pfam),\n"
// these last two have no purpose in the normal Jalview application but are
// used by jalview.bin.Launcher to set memory settings. They are not used by
- // argparser but are here for Usage statement reasons.
+ // argparser but are here for Usage statement and parsing reasons.
JVMMEMPC(Type.CONFIG,
"Limit maximum heap size (memory) to PERCENT% of total physical memory detected. This defaults to 90 if total physical memory can be detected.\n"
+ "The equals sign (\"=\") separator must be used with no spaces.",
STRUCTURE("arguments used to add and format 3D structure data"),
PROCESS("arguments used to process an alignment once opened"),
OUTPUT("arguments used to save data from a processed alignment"),
- IMAGE("arguments used to export an image of an alignment or structure"),
- // IMAGE("arguments used to export an image of an alignment"),
- // STRUCTUREIMAGE("arguments used to export an image of an structure"),
+ IMAGE("arguments used to export an image of an alignment"),
+ STRUCTUREIMAGE("arguments used to export an image of an structure"),
FLOW("arguments that control processing of the other arguments"), //
ALL("all arguments"), // mostly just a place-holder for --help-all
NONE, // mostly a place-holder for --help
private String description;
- private Type type;
+ private Type[] types;
private Arg(Type type, String description, Opt... options)
{
+ this(new Type[] { type }, description, options);
+ }
+
+ private Arg(Type[] type, String description, Opt... options)
+ {
this(type, null, description, false, options);
}
private Arg(Type type, String description, boolean defaultBoolean,
Opt... options)
{
+ this(new Type[] { type }, description, defaultBoolean, options);
+ }
+
+ private Arg(Type[] type, String description, boolean defaultBoolean,
+ Opt... options)
+ {
this(type, null, description, defaultBoolean, options);
}
private Arg(Type type, String alternativeName, String description,
Opt... options)
{
+ this(new Type[] { type }, alternativeName, description, options);
+ }
+
+ private Arg(Type[] type, String alternativeName, String description,
+ Opt... options)
+ {
this(type, alternativeName, description, false, options);
}
private Arg(Type type, String alternativeName, String description,
boolean defaultBoolean, Opt... options)
{
- this.type = type;
+ this(new Type[] { type }, alternativeName, description, defaultBoolean,
+ options);
+ }
+
+ private Arg(Type[] type, String alternativeName, String description,
+ boolean defaultBoolean, Opt... options)
+ {
+ this.types = type;
this.description = description;
this.defaultBoolValue = defaultBoolean;
this.setOptions(options);
if (getNames().length > 0)
sb.append('"');
sb.append(")\n");
- sb.append("\nType: " + type.name());
+ for (Type type : getTypes())
+ {
+ String typeName = type.name();
+ sb.append("\nType: " + typeName);
+ }
sb.append("\nOpt: ");
// map List<Opt> to List<String> for the String.join
List<String> optList = Arrays.asList(argOptions).stream()
return defaultBoolValue;
}
- public Type getType()
+ public Type getFirstType()
{
- return this.type;
+ return this.getTypes()[0];
+ }
+
+ public Type[] getTypes()
+ {
+ return this.types;
+ }
+
+ public boolean sharesType(Arg a)
+ {
+ return this.hasType(a.getTypes());
+ }
+
+ public boolean hasType(Type... types)
+ {
+ Set<Type> typesSet = new HashSet<>(Arrays.asList(types));
+ return this.hasType(typesSet);
+ }
+
+ public boolean hasType(Set<Type> typesSet)
+ {
+ for (Type type : getTypes())
+ {
+ if (typesSet.contains(type))
+ {
+ return true;
+ }
+ }
+ return false;
}
protected String getDescription()
public static final void appendUsageGeneral(StringBuilder sb,
int maxArgLength)
{
+ Set<Type> firstTypes = new HashSet<>();
+ for (Arg a : EnumSet.allOf(Arg.class))
+ {
+ if (!firstTypes.contains(a.getFirstType()))
+ {
+ firstTypes.add(a.getFirstType());
+ }
+ }
for (Type t : EnumSet.allOf(Type.class))
{
- if (t.description() != null)
+ if (t.description() != null && firstTypes.contains(t))
{
StringBuilder argSb = new StringBuilder();
argSb.append(Arg.HELP.argString()).append(ArgParser.SINGLEDASH)
{
List<Arg> args = argsSortedForDisplay(types);
- /*
- * just use a set maxArgLength of DESCRIPTIONINDENT
-
- int maxArgLength = 0;
- for (Arg a : args)
- {
- if (a.hasOption(Opt.PRIVATE) || a.hasOption(Opt.SECRET))
- continue;
-
- String argS = argDisplayString(a);
- if (argS.length() > maxArgLength)
- maxArgLength = argS.length();
- }
- */
int maxArgLength = DESCRIPTIONINDENT;
// always show --help
continue;
}
- if (a.getType() != typeSection)
+ if (a.getFirstType() != typeSection)
{
- typeSection = a.getType();
- String typeDescription = a.getType().description();
+ typeSection = a.getFirstType();
+ String typeDescription = a.getFirstType().description();
if (typeDescription != null && typeDescription.length() > 0)
{
// typeDescription = typeDescription.substring(0,
{
Opt[] opts = options == null ? new Opt[] {} : options;
return EnumSet.allOf(Arg.class).stream().filter(a -> {
- if (a.getType() != type)
+ if (!a.hasType(type))
return false;
for (Opt o : opts)
{
if (b == null)
return -1;
// first compare types (in enum order)
- int i = a.getType().compareTo(b.getType());
+ int i = a.getFirstType().compareTo(b.getFirstType());
if (i != 0)
return i;
// do Opt.LAST next (oddly). Reversed args important!
List<String> globVals = null; // for Opt.GLOB only
SubVals globSubVals = null; // also for use by Opt.GLOB only
String linkedId = null;
+ String givenLinkedId = null; // this is preserved to add to each
+ // "ArgValue"
Type type = null;
// look for equals e.g. --arg=value
if (idOpen > -1 && idClose == argName.length() - 1)
{
linkedId = argName.substring(idOpen + 1, idClose);
+ givenLinkedId = linkedId;
argName = argName.substring(0, idOpen);
}
{
linkedId = MATCHALLLINKEDIDS;
}
+ if (allLinkedIds)
+ {
+ // user has made conscious decision for these args to apply to
+ // all, so set givenLinkedId too
+ givenLinkedId = linkedId;
+ }
else if (a.hasOption(Opt.ALLOWMULTIID)
&& this.storedLinkedIds != null
&& this.storedLinkedIds.size() > 0)
// set allstructures to all non-primary structure options in this linked
// id if --allstructures has been set
- if (allStructures && (a.getType() == Type.STRUCTURE
+ if (allStructures && (a.hasType(Type.STRUCTURE)
// || a.getType() == Type.STRUCTUREIMAGE)
) && !a.hasOption(Opt.PRIMARY))
{
{
String v = gve.nextElement();
SubVals vsv = new SubVals(globSubVals, v);
- addValue(linkedId, type, avs, vsv, v, argIndex++, true);
+ addValue(linkedId, givenLinkedId, type, avs, vsv, v,
+ argIndex++, true);
// if we're using defaultLinkedId and the arg increments the
// counter:
if (gve.hasMoreElements() && usingDefaultLinkedId
else
{
// addValue(linkedId, type, avs, val, argIndex, true);
- addValue(linkedId, type, avs, addNewSubVals ? subvals : null,
- val, argIndex, true);
+ addValue(linkedId, givenLinkedId, type, avs,
+ addNewSubVals ? subvals : null, val, argIndex, true);
}
}
else if (a.hasOption(Opt.BOOLEAN))
{
- setBoolean(linkedId, type, avs, !negated, argIndex);
+ setBoolean(linkedId, givenLinkedId, type, avs, !negated,
+ argIndex);
setNegated(linkedId, avs, negated);
}
else if (a.hasOption(Opt.UNARY))
{
- setBoolean(linkedId, type, avs, true, argIndex);
+ setBoolean(linkedId, givenLinkedId, type, avs, true, argIndex);
}
// remove the '*' or 'open*' linkedId that should be empty if it was
/**
* This version inserts the subvals sv into all created values
*/
- private void addValue(String linkedId, Type type, ArgValues avs,
- SubVals sv, String v, int argIndex, boolean doSubs)
+ private void addValue(String linkedId, String givenLinkedId, Type type,
+ ArgValues avs, SubVals sv, String v, int argIndex, boolean doSubs)
{
- this.argValueOperation(Op.ADDVALUE, linkedId, type, avs, sv, v, false,
- argIndex, doSubs);
+ this.argValueOperation(Op.ADDVALUE, linkedId, givenLinkedId, type, avs,
+ sv, v, false, argIndex, doSubs);
}
- private void setBoolean(String linkedId, Type type, ArgValues avs,
- boolean b, int argIndex)
+ private void setBoolean(String linkedId, String givenLinkedId, Type type,
+ ArgValues avs, boolean b, int argIndex)
{
- this.argValueOperation(Op.SETBOOLEAN, linkedId, type, avs, null, null,
- b, argIndex, false);
+ this.argValueOperation(Op.SETBOOLEAN, linkedId, givenLinkedId, type,
+ avs, null, null, b, argIndex, false);
}
private void setNegated(String linkedId, ArgValues avs, boolean b)
{
- this.argValueOperation(Op.SETNEGATED, linkedId, null, avs, null, null,
- b, 0, false);
+ this.argValueOperation(Op.SETNEGATED, linkedId, null, null, avs, null,
+ null, b, 0, false);
}
private void incrementCount(String linkedId, ArgValues avs)
{
- this.argValueOperation(Op.INCREMENTCOUNT, linkedId, null, avs, null,
- null, false, 0, false);
+ this.argValueOperation(Op.INCREMENTCOUNT, linkedId, null, null, avs,
+ null, null, false, 0, false);
}
private enum Op
ADDVALUE, SETBOOLEAN, SETNEGATED, INCREMENTCOUNT
}
- private void argValueOperation(Op op, String linkedId, Type type,
- ArgValues avs, SubVals sv, String v, boolean b, int argIndex,
- boolean doSubs)
+ private void argValueOperation(Op op, String linkedId,
+ String givenLinkedId, Type type, ArgValues avs, SubVals sv,
+ String v, boolean b, int argIndex, boolean doSubs)
{
// default to merge subvals if subvals are provided
- argValueOperation(op, linkedId, type, avs, sv, true, v, b, argIndex,
- doSubs);
+ argValueOperation(op, linkedId, givenLinkedId, type, avs, sv, true, v,
+ b, argIndex, doSubs);
}
/**
* @param doSubs
* Whether to perform substitutions on the subvals and value.
*/
- private void argValueOperation(Op op, String linkedId, Type type,
- ArgValues avs, SubVals sv, boolean merge, String v, boolean b,
- int argIndex, boolean doSubs)
+ private void argValueOperation(Op op, String linkedId,
+ String givenLinkedId, Type type, ArgValues avs, SubVals sv,
+ boolean merge, String v, boolean b, int argIndex, boolean doSubs)
{
Arg a = avs.arg();
// linkedIds
if (wildcardLinkedIds != null)
{
- for (String id : wildcardLinkedIds)
+ for (String matchedLinkedId : wildcardLinkedIds)
{
// skip incorrectly stored wildcard ids!
- if (id == null || MATCHALLLINKEDIDS.equals(id)
- || MATCHOPENEDLINKEDIDS.equals(id))
+ if (matchedLinkedId == null
+ || MATCHALLLINKEDIDS.equals(matchedLinkedId)
+ || MATCHOPENEDLINKEDIDS.equals(matchedLinkedId))
{
continue;
}
- ArgValuesMap avm = linkedArgs.get(id);
+ ArgValuesMap avm = linkedArgs.get(matchedLinkedId);
// don't set an output if there isn't an input
if (a.hasOption(Opt.REQUIREINPUT)
&& !avm.hasArgWithOption(Opt.INPUT))
if (doSubs)
{
sv = new SubVals(sv, val, merge);
- val = makeSubstitutions(sv.getContent(), id);
+ val = makeSubstitutions(sv.getContent(), matchedLinkedId);
}
- tavs.addValue(sv, type, val, argIndex, true);
+ tavs.addValue(sv, type, val, argIndex, true, givenLinkedId);
}
else
{
if (doSubs)
{
- val = makeSubstitutions(v, id);
+ val = makeSubstitutions(v, matchedLinkedId);
}
- tavs.addValue(type, val, argIndex, true);
+ tavs.addValue(type, val, argIndex, true, givenLinkedId);
}
- finaliseStoringArgValue(id, tavs);
+ finaliseStoringArgValue(matchedLinkedId, tavs);
break;
case SETBOOLEAN:
- tavs.setBoolean(type, b, argIndex, true);
- finaliseStoringArgValue(id, tavs);
+ tavs.setBoolean(type, b, argIndex, true, givenLinkedId);
+ finaliseStoringArgValue(matchedLinkedId, tavs);
break;
case SETNEGATED:
val = makeSubstitutions(v, linkedId);
sv = new SubVals(sv, val);
}
- avs.addValue(sv, type, val, argIndex, false);
+ avs.addValue(sv, type, val, argIndex, false, givenLinkedId);
}
else
{
{
val = makeSubstitutions(v, linkedId);
}
- avs.addValue(type, val, argIndex, false);
+ avs.addValue(type, val, argIndex, false, givenLinkedId);
}
finaliseStoringArgValue(linkedId, avs);
break;
case SETBOOLEAN:
- avs.setBoolean(type, b, argIndex, false);
+ avs.setBoolean(type, b, argIndex, false, givenLinkedId);
finaliseStoringArgValue(linkedId, avs);
break;
private String value;
+ private String givenLinkedId = null;
+
+ private String assignedLinkedId = null;
+
+ private boolean setByWildcardLinkedId = false;
+
/*
* Type type is only really used by --help-type
*/
private SubVals subVals;
protected ArgValue(Arg a, SubVals sv, Type type, String content,
- int argIndex)
+ int argIndex, boolean setByWildcardLinkedId, String givenLinkedId,
+ String assignedLinkedId)
{
this.arg = a;
this.value = content;
this.argIndex = argIndex;
this.subVals = sv == null ? new SubVals("") : sv;
this.setType(type);
+ this.setByWildcardLinkedId = setByWildcardLinkedId;
+ this.givenLinkedId = givenLinkedId;
+ this.assignedLinkedId = assignedLinkedId;
}
- protected ArgValue(Arg a, Type type, String value, int argIndex)
+ protected ArgValue(Arg a, Type type, String value, int argIndex,
+ boolean setByWildcardLinkedId, String givenLinkedId,
+ String assignedLinkedId)
{
this.arg = a;
this.argIndex = argIndex;
this.subVals = new SubVals(value);
this.value = getSubVals().getContent();
this.setType(type);
+ this.setByWildcardLinkedId = setByWildcardLinkedId;
+ this.givenLinkedId = givenLinkedId;
+ this.assignedLinkedId = assignedLinkedId;
}
protected void setType(Type t)
{
return this.getArgIndex() - o.getArgIndex();
}
+
+ @Override
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append(this.getArg().argString());
+ sb.append("=");
+ if (!this.getSubVals().getSubValMap().isEmpty())
+ {
+ sb.append(this.getSubVals().toString());
+ }
+ sb.append("'");
+ sb.append(this.getValue());
+ sb.append("'");
+
+ return sb.toString();
+ }
+
+ public String getGivenLinkedId()
+ {
+ return this.givenLinkedId;
+ }
+
+ public String getAssignedLinkedId()
+ {
+ return this.assignedLinkedId;
+ }
+
+ public boolean setByWildcardLinkedId()
+ {
+ // looking for deliberately user set wildcard
+ return this.setByWildcardLinkedId && this.getGivenLinkedId() != null;
+ }
}
\ No newline at end of file
private boolean setByWildcard = false;
+ private String givenLinkedId = null;
+
private int boolIndex = -1;
private List<Integer> argsIndexes;
private Map<String, ArgValue> idMap = new HashMap<>();
+ private ArgValuesMap avm;
+
/*
* Type type is only really used by --help-type
*/
private Type type = null;
- protected ArgValues(Arg a)
+ protected ArgValues(Arg a, ArgValuesMap avm)
{
this.arg = a;
this.argValueList = new ArrayList<ArgValue>();
this.boolValue = arg.getDefaultBoolValue();
+ this.avm = avm;
}
protected boolean setByWildcard()
}
protected void setBoolean(Type t, boolean b, int i,
- boolean beingSetByWildcard)
+ boolean beingSetByWildcard, String givenLinkedId)
{
this.setType(t);
// don't overwrite a wildcard set boolean with a non-wildcard set boolean
this.boolValue = b;
this.boolIndex = i;
this.setSetByWildcard(beingSetByWildcard);
+ this.givenLinkedId = givenLinkedId;
}
protected boolean getBoolean()
}
protected void addValue(Type type, String val, int argIndex,
- boolean wildcard)
+ boolean wildcard, String givenLinkedId)
{
- addArgValue(new ArgValue(arg(), type, val, argIndex), wildcard);
+ addArgValue(new ArgValue(arg(), type, val, argIndex, wildcard,
+ givenLinkedId, avm.getLinkedId()), wildcard);
}
protected void addValue(SubVals sv, Type type, String content,
- int argIndex, boolean wildcard)
+ int argIndex, boolean wildcard, String givenLinkedId)
{
- addArgValue(new ArgValue(arg(), sv, type, content, argIndex), wildcard);
+ addArgValue(new ArgValue(arg(), sv, type, content, argIndex, wildcard,
+ givenLinkedId, avm.getLinkedId()), wildcard);
}
protected void addArgValue(ArgValue av, boolean beingSetByWildcard)
}
return false;
}
+
+ public boolean setByWildcardLinkedId()
+ {
+ // looking for deliberately user set wildcard
+ return this.setByWildcard && this.givenLinkedId != null;
+ }
+
}
\ No newline at end of file
import java.io.File;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
private void newArg(Arg a)
{
if (m == null)
+ {
newMap();
+ }
if (!containsArg(a))
- m.put(a, new ArgValues(a));
+ {
+ m.put(a, new ArgValues(a, this));
+ }
}
public ArgValues getArgValues(Arg a)
return avs == null ? new ArrayList<>() : avs.getArgValueList();
}
+ public List<ArgValue> getArgValueListFromSubValOrArg(ArgValue av, Arg a,
+ SubVals sv)
+ {
+ return getArgValueListFromSubValArgOrPrefWithSubstitutionsWithinTypes(
+ null, a, Position.AFTER, av, sv, null, null, null, true, null);
+ }
+
+ public List<ArgValue> getArgValueListFromSubValArgOrPrefWithSubstitutionsWithinTypes(
+ ArgParser ap, Arg a, ArgValuesMap.Position pos, ArgValue av,
+ SubVals sv, String key, String pref, String def,
+ boolean withinTypes, Type type)
+ {
+ if (key == null)
+ {
+ key = a.getName();
+ }
+ Set<Type> types = new HashSet<>();
+ if (type == null)
+ {
+ types.addAll(Arrays.asList(av.getArg().getTypes()));
+ }
+ else
+ {
+ types.add(type);
+ }
+ List<ArgValue> avList = new ArrayList<>();
+ if (sv != null && sv.has(key) && sv.get(key) != null)
+ {
+ String value = ap == null ? sv.get(key)
+ : sv.getWithSubstitutions(ap, getLinkedId(), key);
+ // protected ArgValue(Arg a, SubVals sv, Type type, String content, int
+ // argIndex)
+
+ ArgValue svav = new ArgValue(a, null, null, value, av.getArgIndex(),
+ false, null, this.getLinkedId());
+ avList.add(svav);
+ }
+ else if (containsArg(a))
+ {
+ if (pos == ArgValuesMap.Position.FIRST && getValue(a) != null)
+ avList.add(getArgValue(a));
+ else if (pos == ArgValuesMap.Position.BEFORE
+ && getClosestPreviousArgValueOfArg(av, a) != null)
+ {
+ for (ArgValue tmpAv : getArgValues(a).getArgValueList())
+ {
+ if (tmpAv.getArgIndex() >= av.getArgIndex())
+ {
+ continue;
+ }
+ avList.add(tmpAv);
+ }
+ }
+ else if (pos == ArgValuesMap.Position.AFTER
+ && getClosestNextArgValueOfArg(av, a, withinTypes) != null)
+ {
+ for (ArgValue tmpAv : getArgValues(a).getArgValueList())
+ {
+ if (tmpAv.getArgIndex() <= av.getArgIndex())
+ {
+ continue;
+ }
+ avList.add(tmpAv);
+ }
+ }
+ }
+
+ // check if withinType the avs don't belong to the next primary arg
+ // of this type. Checking for *any* shared type.
+ if (withinTypes && !avList.isEmpty())
+ {
+ int nextPrimaryArgOfSameTypeIndex = Integer.MAX_VALUE;
+ // run through every Arg used in this ArgValuesMap
+ for (Arg tmpA : this.getArgKeys())
+ {
+ // only interested in looking up to next Opt.PRIMARY args of the same
+ // type as av (or provided type)
+ if (tmpA.hasType(types) && tmpA.hasOption(Opt.PRIMARY))
+ {
+ for (ArgValue tmpAv : getArgValueList(tmpA))
+ {
+ int tmpArgIndex = tmpAv.getArgIndex();
+ if (tmpArgIndex > av.getArgIndex()
+ && tmpArgIndex < nextPrimaryArgOfSameTypeIndex)
+ {
+ nextPrimaryArgOfSameTypeIndex = tmpArgIndex;
+ }
+ }
+ }
+ }
+ List<ArgValue> tmpList = new ArrayList<>();
+ for (ArgValue tmpAv : avList)
+ {
+ int tmpAvIndex = tmpAv.getArgIndex();
+ if (av.getArgIndex() < tmpAvIndex
+ && tmpAvIndex < nextPrimaryArgOfSameTypeIndex)
+ {
+ tmpList.add(tmpAv);
+ }
+ }
+ avList = tmpList;
+ }
+
+ return avList;
+ }
+
public ArgValue getArgValue(Arg a)
{
List<ArgValue> vals = getArgValueList(a);
return av == null ? null : av.getValue();
}
+ public List<String> getValues(Arg a)
+ {
+ return toValues(getArgValueList(a));
+ }
+
+ public static List<String> toValues(List<ArgValue> avl)
+ {
+ if (avl == null)
+ {
+ return null;
+ }
+ List<String> vl = new ArrayList<>();
+ for (ArgValue av : avl)
+ {
+ vl.add(av.getValue());
+ }
+ return vl;
+ }
+
public boolean containsArg(Arg a)
{
if (m == null || !m.containsKey(a))
}
public ArgValue getClosestNextArgValueOfArg(ArgValue thisAv, Arg a,
- boolean withinType)
+ boolean withinTypes)
{
// this looks for the *next* arg that *might* be referring back to
// a thisAv. Such an arg would have no subValues (if it does it should
}
// check if withinType this closestAv doesn't belong to the next primary arg
- // of this type
- if (withinType && closestAv != null)
+ // of this type. Checking for *any* shared type.
+ if (withinTypes && closestAv != null)
{
int nextPrimaryArgOfSameTypeIndex = Integer.MAX_VALUE;
for (Arg tmpA : this.getArgKeys())
{
// interested in Opt.PRIMARY args of the same type
- if (tmpA.getType() == a.getType() && tmpA.hasOption(Opt.PRIMARY))
+ if (tmpA.sharesType(a) && tmpA.hasOption(Opt.PRIMARY))
{
for (ArgValue tmpAv : getArgValueList(tmpA))
{
}
if (nextPrimaryArgOfSameTypeIndex < closestAv.getArgIndex())
{
- // looks licke closestAv actually belongs to a different primary Arg
+ // looks like closestAv actually belongs to a different primary Arg
return null;
}
}
public String getFromSubValArgOrPref(ArgValue av, Arg a, SubVals sv,
String key, String pref, String def)
{
- return getFromSubValArgOrPref(a, ArgValuesMap.Position.AFTER, av, sv,
- key, pref, def);
+ return getFromSubValArgOrPref(a, Position.AFTER, av, sv, key, pref,
+ def);
}
/**
* get from following(AFTER), first occurence of (FIRST) or previous (BEFORE)
* Arg of type a or subval key or preference pref or default def
*/
- public String getFromSubValArgOrPref(Arg a, ArgValuesMap.Position pos,
- ArgValue av, SubVals sv, String key, String pref, String def)
+ public String getFromSubValArgOrPref(Arg a, Position pos, ArgValue av,
+ SubVals sv, String key, String pref, String def)
{
return getFromSubValArgOrPrefWithSubstitutions(null, a, pos, av, sv,
key, pref, def);
}
public String getFromSubValArgOrPrefWithSubstitutions(ArgParser ap, Arg a,
- ArgValuesMap.Position pos, ArgValue av, SubVals sv, String key,
- String pref, String def)
+ Position pos, ArgValue av, SubVals sv, String key, String pref,
+ String def)
{
- return getFromSubValArgOrPrefWithSubstitutionsWithinType(ap, a, pos, av,
- sv, key, pref, def, true);
+ return getFromSubValArgOrPrefWithSubstitutionsWithinTypes(ap, a, pos,
+ av, sv, key, pref, def, true);
}
- public String getFromSubValArgOrPrefWithSubstitutionsWithinType(
- ArgParser ap, Arg a, ArgValuesMap.Position pos, ArgValue av,
- SubVals sv, String key, String pref, String def,
- boolean withinType)
+ public String getFromSubValArgOrPrefWithSubstitutionsWithinTypes(
+ ArgParser ap, Arg a, Position pos, ArgValue av, SubVals sv,
+ String key, String pref, String def, boolean withinTypes)
{
if (key == null)
key = a.getName();
&& getClosestPreviousArgValueOfArg(av, a) != null)
value = getClosestPreviousArgValueOfArg(av, a).getValue();
else if (pos == ArgValuesMap.Position.AFTER
- && getClosestNextArgValueOfArg(av, a, withinType) != null)
- value = getClosestNextArgValueOfArg(av, a, withinType).getValue();
+ && getClosestNextArgValueOfArg(av, a, withinTypes) != null)
+ value = getClosestNextArgValueOfArg(av, a, withinTypes).getValue();
// look for allstructures subval for Type.STRUCTURE
Arg arg = av.getArg();
if (value == null && arg.hasOption(Opt.PRIMARY)
- && arg.getType() == Type.STRUCTURE
- && !a.hasOption(Opt.PRIMARY) && (a.getType() == Type.STRUCTURE
+ && arg.hasType(Type.STRUCTURE) && !a.hasOption(Opt.PRIMARY)
+ && (a.getFirstType() == Type.STRUCTURE
// || a.getType() == Type.STRUCTUREIMAGE))
))
{
value = av2.getValue();
}
}
+
+ if (value == null)
+ {
+ // look for --all --a occurrences
+ for (ArgValue tmpAv : this.getArgValueList(a))
+ {
+ if (tmpAv.setByWildcardLinkedId())
+ {
+ value = tmpAv.getValue();
+ }
+ }
+ }
}
if (value == null)
{
return pref != null ? (invertPref ? !prefVal : prefVal) : def;
}
+ @Override
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder();
+ for (Arg a : this.getArgKeys())
+ {
+ sb.append(a.argString());
+ sb.append(":\n");
+ for (ArgValue av : this.getArgValueList(a))
+ {
+ sb.append(" ");
+ sb.append(av.getValue());
+ sb.append("\n");
+ }
+ }
+ return sb.toString();
+ }
+
public class ArgInfo implements Comparable<ArgInfo>
{
private Arg arg;
argsOptions.add(opt);
}
}
- Type t = a.getType();
- if (!argsTypes.contains(t))
+ for (Type t : a.getTypes())
{
- argsTypes.add(t);
+ if (!argsTypes.contains(t))
+ {
+ argsTypes.add(t);
+ }
}
}
import java.io.PrintWriter;
import java.util.List;
+import javax.swing.BoundedRangeModel;
import javax.swing.SwingUtilities;
import jalview.analysis.AnnotationSorter;
// Also check annotation label widths
if (includeAnnotations && al.getAlignmentAnnotation() != null)
{
- fm = c.getFontMetrics(getAlabels().getFont());
+ if (legacy)
+ {
+ fm = c.getFontMetrics(getAlabels().getFont());
+ }
if (!legacy || Jalview.isHeadlessMode())
{
}
/**
+ * Answers true if the panel has no horizontal scrollbar, or the scrollbar is
+ * at its rightmost position, else false.
+ *
+ * @return
+ */
+ boolean isScrolledFullyRight()
+ {
+ if (hscroll == null)
+ {
+ return true;
+ }
+ BoundedRangeModel model = hscroll.getModel();
+ return (model.getExtent() + model.getValue() >= model.getMaximum());
+ }
+
+ /**
* Respond to adjustment event when horizontal or vertical scrollbar is
* changed
*
return idwidth.intValue() + ID_WIDTH_PADDING;
}
- int w = getIdPanel().getWidth();
- w = calculateIdWidth(-1, true, true).width;
+ // int w = getIdPanel().getWidth();
+ // w = calculateIdWidth(-1, true, true).width;
+ int w = calculateIdWidth(-1, true, true).width;
return (w > 0 ? w : calculateIdWidth().width);
}
// need to obtain default alignment width and then add in any
// additional allowance for id margin
// this duplicates the calculation in getWrappedHeight but adjusts for
- // offscreen idWith
+ // offscreen idWidth
width = alignFrame.getWidth() - vscroll.getPreferredSize().width
- alignFrame.getInsets().left - alignFrame.getInsets().right
- getVisibleIdWidth() + getVisibleIdWidth(false);
{
Dimension d = ap.annotationScroller.getPreferredSize();
int dif = evt.getY() - oldY;
+ dif -= dif % ap.av.getCharHeight();
- dif /= ap.av.getCharHeight();
- dif *= ap.av.getCharHeight();
+ // don't allow setting an annotation panel height larger than visible
+ // (otherwise you can't get back)
+ if (d.height - dif > ap.idPanelHolder.getHeight()
+ - ap.getIdSpaceFillerPanel1().getHeight())
+ {
+ return;
+ }
if ((d.height - dif) > 20)
{
if (ap != null)
{
iwa = ap.idwidthAdjuster;
- if ((Cache.getDefault(ADJUST_ANNOTATION_LABELS_WIDTH_PREF, true)
- || Jalview.isHeadlessMode()))
+ if (Cache.getDefault(ADJUST_ANNOTATION_LABELS_WIDTH_PREF, true)
+ || Jalview.isHeadlessMode())
{
Graphics2D g2d = (Graphics2D) g;
Graphics dummy = g2d.create();
renderer = new AnnotationRenderer();
}
+ /**
+ * Responds to a mouse wheel movement by scrolling the annotations up or down.
+ * Annotation labels are scrolled via method adjustmentValueChanged when the
+ * vertical scrollbar is adjusted.
+ * <p>
+ * If shift is pressed, then scrolling is left or right instead, and is
+ * delegated to AlignmentPanel, so that both sequences and annotations are
+ * scrolled together.
+ * <p>
+ * This object is a MouseWheelListener to AnnotationLabels, so mouse wheel
+ * events over the labels are delegated to this method.
+ * <p>
+ * Note that this method may also be fired by scrolling with a gesture on a
+ * trackpad.
+ */
@Override
public void mouseWheelMoved(MouseWheelEvent e)
{
if (e.isShiftDown())
{
- e.consume();
- double wheelRotation = e.getPreciseWheelRotation();
- if (wheelRotation > 0)
- {
- av.getRanges().scrollRight(true);
- }
- else if (wheelRotation < 0)
- {
- av.getRanges().scrollRight(false);
- }
+ ap.getSeqPanel().mouseWheelMoved(e);
}
else
{
}
+ public boolean isRepainting()
+ {
+ if (renderPanel!=null && renderPanel.isVisible())
+ {
+ return renderPanel.repainting;
+ }
+ return false;
+ }
/**
* Outputs the Jmol viewer image as an image file, after prompting the user to
* choose a file and (for EPS) choice of Text or Lineart character rendering
@Override
public void makePDBImage(ImageMaker.TYPE type)
{
+ while (!isRepainting())
+ {
+ try {
+ Thread.sleep(2);
+ } catch (Exception q)
+ {}
+ }
try
{
makePDBImage(null, type, null,
}
else
{
- jmb.jmolViewer.renderScreenImage(g, currentSize.width,
- currentSize.height);
+ repainting=true;
+ synchronized (jmb)
+ {
+ jmb.jmolViewer.renderScreenImage(g, currentSize.width,
+ currentSize.height);
+
+ }
+ repainting=false;
}
}
+ volatile boolean repainting=false;
}
@Override
// configure services
StructureSelectionManager ssm = StructureSelectionManager
.getStructureSelectionManager(this);
- if (Cache.getDefault(Preferences.ADD_SS_ANN, true))
- {
- ssm.setAddTempFacAnnot(
- Cache.getDefault(Preferences.ADD_TEMPFACT_ANN, true));
- ssm.setProcessSecondaryStructure(
- Cache.getDefault(Preferences.STRUCT_FROM_PDB, true));
- // JAL-3915 - RNAView is no longer an option so this has no effect
- ssm.setSecStructServices(
- Cache.getDefault(Preferences.USE_RNAVIEW, false));
- }
- else
- {
- ssm.setAddTempFacAnnot(false);
- ssm.setProcessSecondaryStructure(false);
- ssm.setSecStructServices(false);
- }
+ StructureSelectionManager.doConfigureStructurePrefs(ssm);
}
public void checkForNews()
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
-import java.awt.event.MouseWheelEvent;
-import java.awt.event.MouseWheelListener;
import java.util.List;
import javax.swing.JPanel;
/**
* This panel hosts alignment sequence ids and responds to mouse clicks on them,
* as well as highlighting ids matched by a search from the Find menu.
- *
- * @author $author$
- * @version $Revision$
*/
public class IdPanel extends JPanel
- implements MouseListener, MouseMotionListener, MouseWheelListener
+ implements MouseListener, MouseMotionListener
{
private IdCanvas idCanvas;
add(getIdCanvas(), BorderLayout.CENTER);
addMouseListener(this);
addMouseMotionListener(this);
- addMouseWheelListener(this);
+ addMouseWheelListener(alignPanel.getSeqPanel());
ToolTipManager.sharedInstance().registerComponent(this);
}
}
/**
- * Response to the mouse wheel by scrolling the alignment panel.
- */
- @Override
- public void mouseWheelMoved(MouseWheelEvent e)
- {
- e.consume();
- double wheelRotation = e.getPreciseWheelRotation();
- if (wheelRotation > 0)
- {
- if (e.isShiftDown())
- {
- av.getRanges().scrollRight(true);
- }
- else
- {
- av.getRanges().scrollUp(false);
- }
- }
- else if (wheelRotation < 0)
- {
- if (e.isShiftDown())
- {
- av.getRanges().scrollRight(false);
- }
- else
- {
- av.getRanges().scrollUp(true);
- }
- }
- }
-
- /**
* Handle a mouse click event. Currently only responds to a double-click. The
* action is to try to open a browser window at a URL that searches for the
* selected sequence id. The search URL is configured in Preferences |
/*
* don't drag below minimum width
*/
- if (newWidth < MIN_ID_WIDTH)
+ if (newWidth < MIN_ID_WIDTH || newWidth > this.ap.getWidth())
{
return;
}
}
}
+ /**
+ * Responds to a mouse wheel movement by scrolling the alignment
+ * <ul>
+ * <li>left or right, if the shift key is down, else up or down</li>
+ * <li>right (or down) if the reported mouse movement is positive</li>
+ * <li>left (or up) if the reported mouse movement is negative</li>
+ * </ul>
+ * Note that this method may also be fired by scrolling with a gesture on a
+ * trackpad.
+ */
@Override
public void mouseWheelMoved(MouseWheelEvent e)
{
e.consume();
double wheelRotation = e.getPreciseWheelRotation();
+
+ /*
+ * scroll more for large (fast) mouse movements
+ */
+ int size = 1 + (int) Math.abs(wheelRotation);
+
if (wheelRotation > 0)
{
if (e.isShiftDown())
{
- av.getRanges().scrollRight(true);
-
+ /*
+ * scroll right
+ * stop trying to scroll right when limit is reached (saves
+ * expensive calls to Alignment.getWidth())
+ */
+ while (size-- > 0 && !ap.isScrolledFullyRight())
+ {
+ if (!av.getRanges().scrollRight(true))
+ {
+ break;
+ }
+ }
}
else
{
- av.getRanges().scrollUp(false);
+ /*
+ * scroll down
+ */
+ while (size-- > 0)
+ {
+ if (!av.getRanges().scrollUp(false))
+ {
+ break;
+ }
+ }
}
}
else if (wheelRotation < 0)
{
if (e.isShiftDown())
{
- av.getRanges().scrollRight(false);
+ /*
+ * scroll left
+ */
+ while (size-- > 0)
+ {
+ if (!av.getRanges().scrollRight(false))
+ {
+ break;
+ }
+ }
}
else
{
- av.getRanges().scrollUp(true);
+ /*
+ * scroll up
+ */
+ while (size-- > 0)
+ {
+ if (!av.getRanges().scrollUp(true))
+ {
+ break;
+ }
+ }
}
}
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JTextPane;
+import javax.swing.SwingUtilities;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
}
try
{
-
- iframe.setClosed(true); // ##### implicated BLOCKED
+ final JInternalFrame frme = iframe;
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ frme.setClosed(true);
+ } catch (Exception ex)
+ {
+ }
+ }
+ });
} catch (Exception ex)
{
}
if (ssm == null)
{
ssm = ap.getStructureSelectionManager();
+ StructureSelectionManager.doConfigureStructurePrefs(ssm);
}
PDBEntry fileEntry = new AssociatePdbFileWithSeq().associatePdbWithSeq(
hscrollHolder.add(hscrollFillerPanel, BorderLayout.WEST);
this.add(sequenceHolderPanel, BorderLayout.CENTER);
}
+
+ public JPanel getIdSpaceFillerPanel1()
+ {
+ return idSpaceFillerPanel1;
+ }
}
import jalview.analysis.AlignSeq;
import jalview.api.StructureSelectionManagerProvider;
+import jalview.bin.Cache;
import jalview.bin.Console;
import jalview.commands.CommandI;
import jalview.commands.EditCommand;
import jalview.datamodel.SequenceI;
import jalview.ext.jmol.JmolParser;
import jalview.gui.IProgressIndicator;
+import jalview.gui.Preferences;
import jalview.io.AppletFormatAdapter;
import jalview.io.DataSourceType;
import jalview.io.StructureFile;
return pdbIdFileName;
}
+ public static void doConfigureStructurePrefs(
+ StructureSelectionManager ssm)
+ {
+ doConfigureStructurePrefs(ssm,
+ Cache.getDefault(Preferences.ADD_SS_ANN, true),
+ Cache.getDefault(Preferences.ADD_TEMPFACT_ANN, true),
+ Cache.getDefault(Preferences.STRUCT_FROM_PDB, true),
+ Cache.getDefault(Preferences.USE_RNAVIEW, false));
+ }
+
+ public static void doConfigureStructurePrefs(
+ StructureSelectionManager ssm, boolean add_ss_ann,
+ boolean add_tempfact_ann, boolean struct_from_pdb,
+ boolean use_rnaview)
+ {
+ if (add_ss_ann)
+ {
+ ssm.setAddTempFacAnnot(add_tempfact_ann);
+ ssm.setProcessSecondaryStructure(struct_from_pdb);
+ // JAL-3915 - RNAView is no longer an option so this has no effect
+ ssm.setSecStructServices(use_rnaview);
+ }
+ else
+ {
+ ssm.setAddTempFacAnnot(false);
+ ssm.setProcessSecondaryStructure(false);
+ ssm.setSecStructServices(false);
+ }
+ }
+
}
package jalview.util;
-import java.util.Locale;
-
import java.awt.Color;
import java.util.HashMap;
+import java.util.Locale;
import java.util.Map;
import java.util.Random;
colour = colour.trim();
Color col = null;
+
+ if ("random".equals(colour))
+ {
+ return generateRandomColor(null);
+ }
+
try
{
int value = Integer.parseInt(colour, 16);
int b = Integer.parseInt(tokens[2].trim());
col = new Color(r, g, b);
}
- } catch (Exception ex)
+ } catch (IllegalArgumentException ex) // IllegalArgumentException includes
+ // NumberFormatException
{
// non-numeric token or out of 0-255 range
}
*/
public class Uniprot extends DbSourceProxyImpl
{
- private static final String DEFAULT_UNIPROT_DOMAIN = "https://www.uniprot.org";
+ private static final String DEFAULT_UNIPROT_DOMAIN = "https://rest.uniprot.org";
private static final String BAR_DELIMITER = "|";
"(UNIPROT\\|?|UNIPROT_|UNIREF\\d+_|UNIREF\\d+\\|?)", "");
AlignmentI al = null;
- String downloadstring = getDomain() + "/uniprot/" + queries + ".xml";
+ String downloadstring = getDomain() + "/uniprotkb/" + queries + ".xml";
URL url = new URL(downloadstring);
HttpURLConnection urlconn = (HttpURLConnection) url.openConnection();
* @author jimp
*
*/
- private static class Worker extends Thread
+ public static class Worker extends Thread
{
private final Process process;
return classpath;
}
- private Worker getJalviewDesktopRunner(boolean withAwt, String cmd,
+ public static Worker getJalviewDesktopRunner(boolean withAwt, String cmd,
int timeout)
{
// Note: JAL-3065 - don't include quotes for lib/* because the arguments are
new InputStreamReader(ls2_proc.getInputStream()));
BufferedReader errorReader = new BufferedReader(
new InputStreamReader(ls2_proc.getErrorStream()));
- worker = new Worker(ls2_proc);
+ worker = new CommandLineOperations.Worker(ls2_proc);
worker.start();
try
{
*/
package jalview.bin;
+import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
import java.nio.file.Files;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
+import javax.imageio.ImageIO;
import javax.swing.SwingUtilities;
import org.testng.Assert;
public static void callJalviewMain(String[] args)
{
- if (Jalview.getInstance() != null)
+ callJalviewMain(args, false);
+ }
+
+ public static void callJalviewMain(String[] args, boolean newJalview)
+ {
+ if (Jalview.getInstance() != null && !newJalview)
{
Jalview.getInstance().doMain(args);
}
}
*/
- @Test(groups = { "Functional", "testTask3" }, dataProvider = "cmdLines")
+ @Test(
+ groups =
+ { "Functional", "testTask3" },
+ dataProvider = "cmdLines",
+ singleThreaded = true)
+
public void commandsOpenTest(String cmdLine, boolean cmdArgs,
int numFrames, String[] sequences)
{
@Test(
groups =
{ "Functional", "testTask3" },
- dataProvider = "structureImageOutputFiles")
+ dataProvider = "structureImageOutputFiles",
+ singleThreaded = true)
public void structureImageOutputTest(String cmdLine, String[] filenames)
throws IOException
{
cleanupFiles(filenames);
- String[] args = (cmdLine + " --gui").split("\\s+");
+ String[] args = (cmdLine).split("\\s+");
try
{
- callJalviewMain(args);
+ callJalviewMain(args, true);
Commands cmds = Jalview.getInstance().getCommands();
Assert.assertNotNull(cmds);
- File lastFile = null;
- for (String filename : filenames)
+ verifyIncreasingSize(cmdLine, filenames);
+ } catch (Exception x)
+ {
+ Assert.fail("Unexpected exception during structureImageOutputTest",
+ x);
+ } finally
+ {
+ cleanupFiles(filenames);
+ tearDown();
+ }
+ }
+
+ /**
+ * given two command lines, compare the output files produced - they should
+ * exist and be equal in size
+ */
+ @Test(
+ groups =
+ { "Functional", "testTask3" },
+ dataProvider = "compareHeadlessAndGUIOps",
+ singleThreaded = true)
+ public void headlessOrGuiImageOutputTest(String[] cmdLines,
+ String[] filenames) throws IOException
+ {
+ cleanupFiles(filenames);
+ try
+ {
+ for (String cmdLine : cmdLines)
{
- File file = new File(filename);
- Assert.assertTrue(file.exists(), "File '" + filename
- + "' was not created by '" + cmdLine + "'");
- Assert.assertTrue(file.isFile(), "File '" + filename
- + "' is not a file from '" + cmdLine + "'");
- Assert.assertTrue(Files.size(file.toPath()) > 0, "File '" + filename
- + "' has no content from '" + cmdLine + "'");
- // make sure the successive output files get bigger!
- if (lastFile != null)
- Assert.assertTrue(Files.size(file.toPath()) > Files
- .size(lastFile.toPath()));
+ CommandLineOperations.Worker runner = CommandLineOperations
+ .getJalviewDesktopRunner(false, cmdLine, 1000);
+ long timeOut = 10000;
+ while (runner.isAlive() && timeOut > 0)
+ {
+ Thread.sleep(25);
+ timeOut -= 25;
+ }
}
+
+ verifyOrderedFileSet(cmdLines[0] + " vs " + cmdLines[1], filenames,
+ false);
+
+ verifySimilarEnoughImages(cmdLines[0] + " vs " + cmdLines[1],
+ filenames, 0f, 0f);
} catch (Exception x)
{
Assert.fail("Unexpected exception during structureImageOutputTest",
}
}
- @Test(groups = "Functional", dataProvider = "argfileOutputFiles")
+ @DataProvider(name = "compareHeadlessAndGUIOps")
+ public Object[][] compareHeadlessAndGUIOps()
+ {
+ return new Object[][] {
+ new Object[]
+ { new String[] { "--open examples/uniref50.fa "
+ + "--structure [seqid=FER1_SPIOL,tempfac=plddt,showssannotations,structureviewer=jmol]"
+ + "examples/AlphaFold/AF-P00221-F1-model_v4.pdb "
+ + "--paematrix examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json --image="
+ + testfiles + "/"
+ + "test-al-pae-ss-gui.png --overwrite --gui --quit",
+ "--open examples/uniref50.fa "
+ + "--structure [seqid=FER1_SPIOL,tempfac=plddt,showssannotations,structureviewer=jmol]"
+ + "examples/AlphaFold/AF-P00221-F1-model_v4.pdb "
+ + "--paematrix examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json --image="
+ + testfiles + "/"
+ + "test-al-pae-ss-nogui.png --overwrite --nogui" },
+ new String[]
+ { testfiles + "/test-al-pae-ss-gui.png",
+ testfiles + "/test-al-pae-ss-nogui.png", } } };
+ }
+
+ private static void verifyIncreasingSize(String cmdLine,
+ String[] filenames) throws Exception
+ {
+ verifyOrderedFileSet(cmdLine, filenames, true);
+ }
+
+ private static void verifyOrderedFileSet(String cmdLine,
+ String[] filenames, boolean increasingSize) throws Exception
+ {
+ File lastFile = null;
+ for (String filename : filenames)
+ {
+ File file = new File(filename);
+ Assert.assertTrue(file.exists(), "File '" + filename
+ + "' was not created by '" + cmdLine + "'");
+ Assert.assertTrue(file.isFile(), "File '" + filename
+ + "' is not a file from '" + cmdLine + "'");
+ Assert.assertTrue(Files.size(file.toPath()) > 0, "File '" + filename
+ + "' has no content from '" + cmdLine + "'");
+ // make sure the successive output files get bigger!
+ if (lastFile != null)
+ {
+ waitForLastWrite(file, 25);
+
+ if (increasingSize)
+ {
+ Assert.assertTrue(
+ Files.size(file.toPath()) > Files.size(lastFile.toPath()),
+ "Expected " + file.toPath() + " to be larger than "
+ + lastFile.toPath());
+ }
+ else
+ {
+ Assert.assertEquals(Files.size(file.toPath()),
+ Files.size(lastFile.toPath()),
+ "New file " + file.toPath()
+ + " (actual size) not same as last file's size "
+ + lastFile.toString());
+ }
+ }
+ // remember it for next file
+ lastFile = file;
+ }
+
+ }
+
+ private static void verifySimilarEnoughImages(String cmdLine,
+ String[] filenames, float w_tolerance_pc, float h_tolerance_pc)
+ throws Exception
+ {
+ int min_w = -1;
+ int max_w = -1;
+ int min_h = -1;
+ int max_h = -1;
+ for (String filename : filenames)
+ {
+ File file = new File(filename);
+ Assert.assertTrue(file.exists(), "File '" + filename
+ + "' was not created by '" + cmdLine + "'");
+ Assert.assertTrue(file.isFile(), "File '" + filename
+ + "' is not a file from '" + cmdLine + "'");
+ Assert.assertTrue(Files.size(file.toPath()) > 0, "File '" + filename
+ + "' has no content from '" + cmdLine + "'");
+
+ BufferedImage img = ImageIO.read(file);
+ if (img.getWidth() < min_w || min_w == -1)
+ {
+ min_w = img.getWidth();
+ }
+ if (img.getWidth() > max_w || max_w == -1)
+ {
+ max_w = img.getWidth();
+ }
+ if (img.getHeight() < min_h || min_h == -1)
+ {
+ min_h = img.getHeight();
+ }
+ if (img.getHeight() > max_h || max_h == -1)
+ {
+ max_h = img.getHeight();
+ }
+ }
+ Assert.assertTrue(min_w > 0,
+ "Minimum width is not positive (" + min_w + ")");
+ Assert.assertTrue(max_w > 0,
+ "Maximum width is not positive (" + max_w + ")");
+ Assert.assertTrue(min_h > 0,
+ "Minimum height is not positive (" + min_h + ")");
+ Assert.assertTrue(max_h > 0,
+ "Maximum height is not positive (" + max_h + ")");
+ // tolerance
+ Assert.assertTrue(100 * (max_w - min_w) / min_w <= w_tolerance_pc,
+ "Width variation (" + (max_w - min_w)
+ + " not within tolerance (" + w_tolerance_pc
+ + "%) of minimum width (" + min_w + ")");
+ if (max_w != min_w)
+ {
+ System.out.println("Widths within tolerance (" + w_tolerance_pc
+ + "%), min_w=" + min_w + " < max_w=" + max_w);
+ }
+ Assert.assertTrue(100 * (max_h - min_h) / min_h <= h_tolerance_pc,
+ "Height variation (" + (max_h - min_h)
+ + " not within tolerance (" + h_tolerance_pc
+ + "%) of minimum height (" + min_h + ")");
+ if (max_h != min_h)
+ {
+ System.out.println("Heights within tolerance (" + h_tolerance_pc
+ + "%), min_h=" + min_h + " < max_h=" + max_h);
+ }
+ }
+
+ private static long waitForLastWrite(File file, int i) throws IOException
+ {
+ long lastSize, stableSize = Files.size(file.toPath());
+ // wait around until we are sure the file has been completely written.
+ do
+ {
+ lastSize = stableSize;
+ try
+ {
+ Thread.sleep(i);
+ } catch (Exception x)
+ {
+ }
+ stableSize = Files.size(file.toPath());
+ } while (stableSize != lastSize);
+ return stableSize;
+ }
+
+ @Test(
+ groups = "Functional",
+ dataProvider = "argfileOutputFiles",
+ singleThreaded = true)
+
public void argFilesGlobAndSubstitutionsTest(String cmdLine,
String[] filenames) throws IOException
{
+ "' has no content from '" + cmdLine + "'");
// make sure the successive output files get bigger!
if (lastFile != null)
+ {
Assert.assertTrue(Files.size(file.toPath()) > Files
.size(lastFile.toPath()));
+ System.out.println("this file: " + file + " +"
+ + Files.size(file.toPath()) + " greater than "
+ + Files.size(lastFile.toPath()));
+ }
+ // remember it for next file
+ lastFile = file;
}
} catch (Exception x)
{
{
return new Object[][] {
//
+ /*
+ */
{ "--gui --nonews --nosplash --open=./examples/test_fab41.result/sample.a2m "
+ "--structure=./examples/test_fab41.result/test_fab41_unrelaxed_rank_1_model_3.pdb "
- + "--structureimage=" + testfiles + "/structureimage1.png "
+ + "--structureimage=" + testfiles
+ + "/structureimage0-1.png "
+ "--open=./examples/test_fab41.result/sample.a2m "
+ "--structure=./examples/test_fab41.result/test_fab41_unrelaxed_rank_1_model_3.pdb "
+ "--structureimage=" + testfiles
- + "/structureimage2.png --scale=1.5 "
+ + "/structureimage0-2.png --scale=1.5 "
+ "--open=./examples/test_fab41.result/sample.a2m "
+ "--structure=./examples/test_fab41.result/test_fab41_unrelaxed_rank_1_model_3.pdb "
+ "--structureimage=" + testfiles
- + "/structureimage3.png --scale=2.0 ",
+ + "/structureimage0-3.png --scale=2.0 ",
new String[]
- { testfiles + "/structureimage1.png",
- testfiles + "/structureimage2.png",
- testfiles + "/structureimage3.png" } },
+ { testfiles + "/structureimage0-1.png",
+ testfiles + "/structureimage0-2.png",
+ testfiles + "/structureimage0-3.png" } },
{ "--headless --noquit --open=./examples/test_fab41.result/sample.a2m "
+ "--structure=./examples/test_fab41.result/test_fab41_unrelaxed_rank_1_model_3.pdb "
- + "--structureimage=" + testfiles + "/structureimage1.png "
+ + "--structureimage=" + testfiles
+ + "/structureimage1-1.png "
+ "--open=./examples/test_fab41.result/sample.a2m "
+ "--structure=./examples/test_fab41.result/test_fab41_unrelaxed_rank_1_model_3.pdb "
+ "--structureimage=" + testfiles
- + "/structureimage2.png --scale=1.5 "
+ + "/structureimage1-2.png --scale=1.5 "
+ "--open=./examples/test_fab41.result/sample.a2m "
+ "--structure=./examples/test_fab41.result/test_fab41_unrelaxed_rank_1_model_3.pdb "
+ "--structureimage=" + testfiles
- + "/structureimage3.png --scale=2.0 ",
+ + "/structureimage1-3.png --scale=2.0 ",
+ new String[]
+ { testfiles + "/structureimage1-1.png",
+ testfiles + "/structureimage1-2.png",
+ testfiles + "/structureimage1-3.png" } },
+ { "--gui --nonews --nosplash --open examples/1gaq.txt --append ./examples/3W5V.pdb "
+ + "--structure examples/1gaq.txt --seqid \"1GAQ|A\" "
+ + "--structureimage " + testfiles
+ + "/structureimage2-1gaq.png --structure examples/3W5V.pdb "
+ + "--seqid \"3W5V|A\" --structureimage " + testfiles
+ + "/structureimage2-3w5v.png --overwrite",
+
+ new String[]
+ { testfiles + "/structureimage2-3w5v.png",
+ testfiles + "/structureimage2-1gaq.png", } },
+ { "--headless --noquit --open ./examples/1gaq.txt --append ./examples/3W5V.pdb "
+ + "--structure examples/1gaq.txt --seqid \"1GAQ|A\" "
+ + "--structureimage " + testfiles
+ + "/structureimage3-1gaq.png --structure examples/3W5V.pdb "
+ + "--seqid \"3W5V|A\" --structureimage " + testfiles
+ + "/structureimage3-3w5v.png --overwrite",
+
new String[]
- { testfiles + "/structureimage1.png",
- testfiles + "/structureimage2.png",
- testfiles + "/structureimage3.png" } },
+ { testfiles + "/structureimage3-3w5v.png",
+ testfiles + "/structureimage3-1gaq.png", } }
/*
*/
//
};
}
+ @Test(
+ groups =
+ { "Functional", "testTask3" },
+ dataProvider = "structureImageAnnotationsOutputFiles",
+ singleThreaded = true)
+ public void structureImageAnnotationsOutputTest(String cmdLine,
+ String filename, int height) throws IOException
+ {
+ cleanupFiles(new String[] { filename });
+ String[] args = (cmdLine).split("\\s+");
+ callJalviewMain(args, true); // Create new instance of Jalview each time for
+ // linkedIds
+ BufferedImage img = ImageIO.read(new File(filename));
+ Assert.assertEquals(height, img.getHeight(), "Output image '" + filename
+ + "' is not in the expected height range, possibly because of the wrong number of annotations");
+
+ cleanupFiles(new String[] { filename });
+ tearDown();
+ }
+
+ @DataProvider(name = "structureImageAnnotationsOutputFiles")
+ public Object[][] structureImageAnnotationsOutputFiles()
+ {
+ String filename = "test/jalview/bin/argparser/testfiles/test_annotations.png";
+ return new Object[][] {
+ // MUST use --noquit with --headless to avoid a System.exit()
+ { "--noquit --headless --nonews --nosplash --open=./examples/uniref50.fa "
+ + "--structure=examples/AlphaFold/AF-P00221-F1-model_v4.pdb "
+ + "--seqid=FER1_SPIOL --structureviewer=jmol "
+ + "--paematrix examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json "
+ + "--image=" + filename + " " + "--tempfac=plddt "
+ + "--overwrite " //
+ + "--noshowssannotations " + "--noshowannotations", //
+ filename, //
+ 252 }, //
+ { "--noquit --headless --nonews --nosplash --open=./examples/uniref50.fa "
+ + "--structure=examples/AlphaFold/AF-P00221-F1-model_v4.pdb "
+ + "--seqid=FER1_SPIOL --structureviewer=jmol "
+ + "--paematrix examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json "
+ + "--image=" + filename + " " + "--tempfac=plddt "
+ + "--overwrite " //
+ + "--showssannotations " + "--noshowannotations", //
+ filename, //
+ 368 }, //
+ { "--noquit --headless --nonews --nosplash --open=./examples/uniref50.fa "
+ + "--structure=examples/AlphaFold/AF-P00221-F1-model_v4.pdb "
+ + "--seqid=FER1_SPIOL --structureviewer=jmol "
+ + "--paematrix examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json "
+ + "--image=" + filename + " " + "--tempfac=plddt "
+ + "--overwrite " //
+ + "--noshowssannotations " + "--showannotations", //
+ filename, //
+ 524 }, //
+ { "--noquit --headless --nonews --nosplash --open=./examples/uniref50.fa "
+ + "--structure=examples/AlphaFold/AF-P00221-F1-model_v4.pdb "
+ + "--seqid=FER1_SPIOL --structureviewer=jmol "
+ + "--paematrix examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json "
+ + "--image=" + filename + " " + "--tempfac=plddt "
+ + "--overwrite " //
+ + "--showssannotations " + "--showannotations", //
+ filename, //
+ 660 }, //
+ { "--gui --nonews --nosplash --open=./examples/uniref50.fa "
+ + "--structure=examples/AlphaFold/AF-P00221-F1-model_v4.pdb "
+ + "--seqid=FER1_SPIOL --structureviewer=jmol "
+ + "--paematrix examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json "
+ + "--image=" + filename + " " + "--tempfac=plddt "
+ + "--overwrite " //
+ + "--noshowssannotations " + "--noshowannotations", //
+ filename, //
+ 252 }, //
+ { "--gui --nonews --nosplash --open=./examples/uniref50.fa "
+ + "--structure=examples/AlphaFold/AF-P00221-F1-model_v4.pdb "
+ + "--seqid=FER1_SPIOL --structureviewer=jmol "
+ + "--paematrix examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json "
+ + "--image=" + filename + " " + "--tempfac=plddt "
+ + "--overwrite " //
+ + "--showssannotations " + "--noshowannotations", //
+ filename, //
+ 368 }, //
+ { "--gui --nonews --nosplash --open=./examples/uniref50.fa "
+ + "--structure=examples/AlphaFold/AF-P00221-F1-model_v4.pdb "
+ + "--seqid=FER1_SPIOL --structureviewer=jmol "
+ + "--paematrix examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json "
+ + "--image=" + filename + " " + "--tempfac=plddt "
+ + "--overwrite " //
+ + "--noshowssannotations " + "--showannotations", //
+ filename, //
+ 524 }, //
+ { "--gui --nonews --nosplash --open=./examples/uniref50.fa "
+ + "--structure=examples/AlphaFold/AF-P00221-F1-model_v4.pdb "
+ + "--seqid=FER1_SPIOL --structureviewer=jmol "
+ + "--paematrix examples/AlphaFold/AF-P00221-F1-predicted_aligned_error_v4.json "
+ + "--image=" + filename + " " + "--tempfac=plddt "
+ + "--overwrite " //
+ + "--showssannotations " + "--showannotations", //
+ filename, //
+ 660 }, //
+ };
+ }
+
}
import java.io.File;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
import java.util.Properties;
+import org.apache.logging.log4j.util.Strings;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.Test;
import jalview.bin.Cache;
+import jalview.bin.Console;
import jalview.gui.Desktop;
@Test(singleThreaded = true)
};
}
+ @Test(groups = "Functional", dataProvider = "argsWithinTypesData")
+ public void checkArgsWithinTypesTest(String commandLineArgs,
+ Object[] stuff)
+ {
+ String linkedId = "JALVIEW:0";
+ String[] args = commandLineArgs.split("\\s+");
+ ArgParser argparser = new ArgParser(args);
+ ArgValuesMap avm = argparser.getLinkedArgs(linkedId);
+
+ ArgAndValues avals = (ArgAndValues) stuff[0];
+
+ Object[] moreStuff = (Object[]) stuff[1];
+
+ ArgAndValues[] subAv = (ArgAndValues[]) moreStuff[0];
+
+ Object[] secondaryArgAndAuxStuff = (Object[]) stuff[2];
+
+ // Now look at the argparser
+
+ Arg primaryArg = avals.arg;
+
+ List<ArgValue> parsed_ArgValues = avm.getArgValueList(primaryArg);
+
+ Assert.assertTrue(
+ areEqualSets(avals.values,
+ ArgValuesMap.toValues(parsed_ArgValues)),
+ "Primary arg (" + primaryArg.toString()
+ + ") does not have the expected values. Expected "
+ + avals.values + " and got "
+ + ArgValuesMap.toValues(parsed_ArgValues));
+
+ for (int i = 0; i < parsed_ArgValues.size(); i++)
+ {
+ ArgValue parsed_ArgValue = parsed_ArgValues.get(i);
+ String value = avals.values.get(i);
+
+ Console.debug("- primary arg '" + primaryArg + "' = '" + value + "'");
+
+ Assert.assertEquals(parsed_ArgValue.getValue(), value,
+ "Primary arg value not as expected");
+
+ ArgAndValues[] aux_avals = (ArgAndValues[]) moreStuff[i];
+
+ for (ArgAndValues aux_aval : aux_avals)
+ {
+ Arg auxArg = aux_aval.arg;
+ List<String> auxValues = aux_aval.values;
+
+ String parsed_auxValue = avm.getFromSubValArgOrPref(auxArg,
+ ArgValuesMap.Position.AFTER, parsed_ArgValue, null, null,
+ null, null);
+
+ if (auxValues.isEmpty())
+ {
+ Assert.assertTrue(parsed_auxValue == null,
+ "Not expecting to parse a value for '" + auxArg
+ + "' but found '" + parsed_auxValue + "'");
+ }
+
+ for (String auxValue : auxValues)
+ {
+
+ Console.debug("- + primary aux arg '" + auxArg + "' = '"
+ + auxValue + "'");
+
+ Assert.assertEquals(parsed_auxValue, auxValue,
+ "Primary auxiliary arg (" + auxArg.toString()
+ + ") values do not match");
+
+ }
+ }
+
+ // Now for the secondary args
+ Object[] secondaryStuff = (Object[]) secondaryArgAndAuxStuff[i];
+ ArgAndValues secondaryArgAndValues = (ArgAndValues) secondaryStuff[0];
+ Arg secondaryArg = secondaryArgAndValues.arg;
+ List<String> secondaryValues = secondaryArgAndValues.values;
+
+ List<ArgValue> parsed_secondaryArgValues = avm
+ .getArgValueListFromSubValOrArg(parsed_ArgValue, secondaryArg,
+ null);
+
+ Assert.assertTrue(
+ areEqualSets(secondaryValues,
+ ArgValuesMap.toValues(parsed_secondaryArgValues)),
+ "Secondary arg (" + secondaryArg.toString()
+ + ") does not have the expected values");
+
+ Object[] secondaryMoreStuff = (Object[]) secondaryStuff[1];
+
+ for (int j = 0; j < parsed_secondaryArgValues.size(); j++)
+ {
+ ArgValue parsed_secondaryArgValue = parsed_secondaryArgValues
+ .get(j);
+ String secondary_value = secondaryValues.get(j);
+
+ Console.debug("-- secondary arg '" + secondaryArg + "' = '"
+ + secondary_value + "'");
+
+ Assert.assertEquals(parsed_secondaryArgValue.getValue(),
+ secondary_value, "Secondary arg value not as expected");
+
+ ArgAndValues[] secondary_aux_avals = (ArgAndValues[]) secondaryMoreStuff[j];
+
+ for (ArgAndValues secondary_aux_aval : secondary_aux_avals)
+ {
+ Arg secondary_auxArg = secondary_aux_aval.arg;
+ List<String> secondary_auxValues = secondary_aux_aval.values;
+
+ String parsed_secondary_auxValue = avm.getValueFromSubValOrArg(
+ parsed_secondaryArgValue, secondary_auxArg, null);
+
+ if (secondary_auxValues.isEmpty())
+ {
+ Assert.assertTrue(parsed_secondary_auxValue == null,
+ "Not expecting to parse a value for '"
+ + secondary_auxArg + "' but found '"
+ + parsed_secondary_auxValue + "'");
+ }
+
+ for (String secondary_auxValue : secondary_auxValues)
+ {
+ Console.debug("-- + secondary aux arg '" + secondary_auxArg
+ + "' for value '" + secondary_auxValue + "'");
+
+ Assert.assertEquals(parsed_secondary_auxValue,
+ secondary_auxValue,
+ "Secondary auxiliary arg ("
+ + secondary_auxArg.toString()
+ + ") values do not match");
+ }
+ }
+ }
+ }
+ }
+
+ @DataProvider(name = "argsWithinTypesData")
+ public Object[][] argsWithinTypesData()
+ {
+ return new Object[][] {
+ /*
+ * { cmdline args },
+ * {
+ * { Primary Arg, Secondary Args },
+ * { { Secondary Arg => { Values } } }
+ * },
+ */
+ /*
+ */
+ { //
+ // commandLineArgs
+ "--open=alignment.fa --structure=structure0.pdb"
+ // structureimage0a and structureimage args
+ + " --structureimage=image0a.png --bgcolour=bg0a --imagecolour=col0a"
+ // structureimage0b and structureimage args
+ + " --structureimage=image0b.png --bgcolour=bg0b --imagecolour=col0b"
+ // more structure args
+ + " --structureviewer=sv0 --paematrix=pae0" //
+ // structure1
+ + " --structure=structure1.pdb"
+ // structure args
+ + " --structureviewer=sv1 --paematrix=pae1"
+ // structureimage1a with NO structureimage args
+ // (see `--all --bgcolour=pineapple` later)
+ + " --structureimage=image1a.png"
+ // structureimage1b and structureimage args
+ + " --structureimage=image1b.png --bgcolour=bg1b --imagecolour=col1b"
+ // --all args, should apply to structureimage1a only
+ + " --all --bgcolour=pineapple" //
+ ,
+ // stuff
+ new Object[]
+ {
+ // avals (0) and (1)
+ av(Arg.STRUCTURE, "structure0.pdb", "structure1.pdb"),
+ // moreStuff (0) and (1)
+ new ArgAndValues[][]
+ { //
+ { av(Arg.STRUCTUREVIEWER, "sv0"),
+ av(Arg.PAEMATRIX, "pae0") },
+ { av(Arg.STRUCTUREVIEWER, "sv1"),
+ av(Arg.PAEMATRIX, "pae1") } //
+ },
+ // secondaryArgAndAuxStuff
+ // (same size as values of avals)
+ new Object[][]
+ {
+ // secondaryStuff (0)
+ {
+ // secondaryArgAndValues (a) and (b)
+ av(Arg.STRUCTUREIMAGE, "image0a.png",
+ "image0b.png"),
+ // secondaryMoreStuff
+ // (same size as values of secondaryArgAndValues)
+ new ArgAndValues[][]
+ {
+ // secondary_aux_avals (a)
+ { av(Arg.BGCOLOUR, "bg0a"),
+ av(Arg.IMAGECOLOUR, "col0a") },
+ // secondary_aux_avals (b)
+ { av(Arg.BGCOLOUR, "bg0b"),
+ av(Arg.IMAGECOLOUR, "col0b") }, //
+ }, //
+ },
+ // secondaryStuff (1)
+ {
+ // secondaryArgAndValues (a) and (b)
+ av(Arg.STRUCTUREIMAGE, "image1a.png",
+ "image1b.png"),
+ // secondaryMoreStuff
+ new ArgAndValues[][]
+ {
+ // secondary_aux_avals (a)
+ { av(Arg.BGCOLOUR, "pineapple"),
+ av(Arg.IMAGECOLOUR) },
+ // secondary_aux_avals (b)
+ { av(Arg.BGCOLOUR, "bg1b"),
+ av(Arg.IMAGECOLOUR, "col1b") }, //
+ }, //
+ }, //
+ } //
+ } //
+ }, //
+ { //
+ "--open=alignment.fa --wrap --colour=gecose-flower"
+ // structure0
+ + " --structure=structure0.pdb"
+ + " --structureimage=image0a.png --bgcolour=bg0a --scale=3"
+ + " --structureimage=image0b.png --imagecolour=col0b --scale=4"
+ + " --structureviewer=sv0 --paematrix=pae0" //
+ + " --structureimage=image0c.png"
+ // structure1
+ + " --structure=structure1.pdb"
+ + " --structureviewer=sv1 --paematrix=pae1"
+ + " --structureimage=image1a.png"
+ + " --structureimage=image1b.png --bgcolour=bg1b --imagecolour=col1b"
+ + " --structureimage=image1c.png --bgcolour=bg1c --imagecolour=col1c --scale=5"
+ + " --structureimage=image1d.png --imagecolour=col1d --scale=6"
+ + " --structureimage=image1e.png --bgcolour=bg1e"
+ // structure2
+ + " --structure=structure2.pdb"
+ + " --structureimage=image2a.png --bgcolour=bg2a --scale=23"
+ + " --all --bgcolour=pineapple --imagecolour=banana --scale=2" //
+ ,
+ // stuff
+ new Object[]
+ { av(Arg.STRUCTURE, "structure0.pdb", "structure1.pdb",
+ "structure2.pdb"),
+ new ArgAndValues[][]
+ { //
+ { av(Arg.STRUCTUREVIEWER, "sv0"),
+ av(Arg.PAEMATRIX, "pae0") },
+ { av(Arg.STRUCTUREVIEWER, "sv1"),
+ av(Arg.PAEMATRIX, "pae1") },
+ { av(Arg.STRUCTUREVIEWER), av(Arg.PAEMATRIX) } //
+ }, //
+ new Object[][]
+ { //
+ { //
+ av(Arg.STRUCTUREIMAGE, "image0a.png", "image0b.png",
+ "image0c.png"), //
+ new ArgAndValues[][]
+ { //
+ { av(Arg.BGCOLOUR, "bg0a"),
+ av(Arg.IMAGECOLOUR, "banana"),
+ av(Arg.SCALE, "3") },
+ { av(Arg.BGCOLOUR, "pineapple"),
+ av(Arg.IMAGECOLOUR, "col0b"),
+ av(Arg.SCALE, "4") },
+ { av(Arg.BGCOLOUR, "pineapple"),
+ av(Arg.IMAGECOLOUR, "banana"),
+ av(Arg.SCALE, "2") }, //
+ }, //
+ }, //
+ { //
+ av(Arg.STRUCTUREIMAGE, "image1a.png", "image1b.png",
+ "image1c.png", "image1d.png",
+ "image1e.png"),
+ new ArgAndValues[][]
+ { //
+ { av(Arg.BGCOLOUR, "pineapple"),
+ av(Arg.IMAGECOLOUR, "banana"),
+ av(Arg.SCALE, "2") },
+ { av(Arg.BGCOLOUR, "bg1b"),
+ av(Arg.IMAGECOLOUR, "col1b"),
+ av(Arg.SCALE, "2") },
+ { av(Arg.BGCOLOUR, "bg1c"),
+ av(Arg.IMAGECOLOUR, "col1c"),
+ av(Arg.SCALE, "5") },
+ { av(Arg.BGCOLOUR, "pineapple"),
+ av(Arg.IMAGECOLOUR, "col1d"),
+ av(Arg.SCALE, "6") },
+ { av(Arg.BGCOLOUR, "bg1e"),
+ av(Arg.IMAGECOLOUR, "banana"),
+ av(Arg.SCALE, "2") } //
+ }, //
+ }, //
+ { //
+ av(Arg.STRUCTUREIMAGE, "image2a.png"),
+ new ArgAndValues[][]
+ { //
+ { av(Arg.BGCOLOUR, "bg2a"),
+ av(Arg.IMAGECOLOUR, "banana"),
+ av(Arg.SCALE, "23") }, //
+ }, //
+ }, //
+ } //
+ } //
+ } //
+ };
+ }
+
+ protected ArgAndValues av(Arg a, String... vals)
+ {
+ return new ArgAndValues(a, vals);
+ }
+
+ protected class ArgAndValues
+ {
+ protected Arg arg;
+
+ protected List<String> values;
+
+ ArgAndValues(Arg a, String... vals)
+ {
+ arg = a;
+ values = vals == null ? new ArrayList<String>() : Arrays.asList(vals);
+ }
+
+ @Override
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append(arg.argString());
+ sb.append("\n");
+ sb.append(Strings.join(values, ','));
+ sb.append("\n");
+ return sb.toString();
+ }
+ }
+
+ private static boolean areEqualSets(String[] strArray,
+ List<String> strList)
+ {
+ return areEqualSets(Arrays.asList(strArray), strList);
+ }
+
+ private static boolean areEqualSets(List<String> l1, List<String> l2)
+ {
+ if (l1 == null && l2 == null)
+ {
+ Console.info(
+ "Comparing null lists, should be okay but you might want to know");
+ return true;
+ }
+ if (l1 == null || l2 == null)
+ {
+ return false;
+ }
+ return new HashSet<String>(l1).equals(new HashSet<String>(l2));
+ }
+
}
\ No newline at end of file