From: Ben Soares Date: Tue, 5 Dec 2023 14:15:53 +0000 (+0000) Subject: JAL-4353 Add secondary Types for Args, for STRUCTUREIMAGE Type and restrict structure... X-Git-Url: http://source.jalview.org/gitweb/?p=jalview.git;a=commitdiff_plain;h=ce6d1e09276f8481e6975d0c28c60620dfb83883 JAL-4353 Add secondary Types for Args, for STRUCTUREIMAGE Type and restrict structureimages between structures on the same open alignment --- diff --git a/src/jalview/bin/Commands.java b/src/jalview/bin/Commands.java index 475eba2..e01d40a 100644 --- a/src/jalview/bin/Commands.java +++ b/src/jalview/bin/Commands.java @@ -501,15 +501,13 @@ public class Commands 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 @@ -578,8 +576,8 @@ public class Commands // 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); @@ -603,8 +601,8 @@ public class Commands // 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; @@ -636,8 +634,8 @@ public class Commands } 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 @@ -698,7 +696,8 @@ public class Commands 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); diff --git a/src/jalview/bin/argparser/Arg.java b/src/jalview/bin/argparser/Arg.java index d043d16..cdb29bf 100644 --- a/src/jalview/bin/argparser/Arg.java +++ b/src/jalview/bin/argparser/Arg.java @@ -25,9 +25,11 @@ import java.util.Arrays; 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; @@ -181,7 +183,8 @@ public enum Arg + "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), @@ -213,26 +216,6 @@ public enum Arg 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" @@ -499,9 +482,8 @@ public enum Arg 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 @@ -533,29 +515,53 @@ public enum Arg 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); @@ -596,7 +602,11 @@ public enum Arg 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 to List for the String.join List optList = Arrays.asList(argOptions).stream() @@ -661,9 +671,39 @@ public enum Arg return defaultBoolValue; } - public Type getType() + public Type getFirstType() + { + return this.getTypes()[0]; + } + + public Type[] getTypes() { - return this.type; + return this.types; + } + + public boolean hasType(Type t) + { + for (Type type : getTypes()) + { + if (type == t) + { + return true; + } + } + return false; + } + + public boolean sharesType(Arg a) + { + List aTypes = Arrays.asList(a.getTypes()); + for (Type type : getTypes()) + { + if (aTypes.contains(type)) + { + return true; + } + } + return false; } protected String getDescription() @@ -690,9 +730,17 @@ public enum Arg public static final void appendUsageGeneral(StringBuilder sb, int maxArgLength) { + Set 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) @@ -727,20 +775,6 @@ public enum Arg { List 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 @@ -764,10 +798,10 @@ public enum Arg 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, @@ -958,7 +992,7 @@ public enum Arg { 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) { @@ -1013,7 +1047,7 @@ class ArgDisplayComparator implements Comparator 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! diff --git a/src/jalview/bin/argparser/ArgParser.java b/src/jalview/bin/argparser/ArgParser.java index 155f69e..fe73053 100644 --- a/src/jalview/bin/argparser/ArgParser.java +++ b/src/jalview/bin/argparser/ArgParser.java @@ -661,7 +661,7 @@ public class ArgParser // 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)) { diff --git a/src/jalview/bin/argparser/ArgValuesMap.java b/src/jalview/bin/argparser/ArgValuesMap.java index fc1e090..5d53641 100644 --- a/src/jalview/bin/argparser/ArgValuesMap.java +++ b/src/jalview/bin/argparser/ArgValuesMap.java @@ -101,6 +101,96 @@ public class ArgValuesMap return avs == null ? new ArrayList<>() : avs.getArgValueList(); } + public List getArgValueListFromSubValOrArg(ArgValue av, Arg a, + SubVals sv) + { + return getArgValueListFromSubValArgOrPrefWithSubstitutionsWithinTypes( + null, a, Position.AFTER, av, sv, null, null, null, true); + } + + public List getArgValueListFromSubValArgOrPrefWithSubstitutionsWithinTypes( + ArgParser ap, Arg a, ArgValuesMap.Position pos, ArgValue av, + SubVals sv, String key, String pref, String def, + boolean withinTypes) + { + if (key == null) + key = a.getName(); + List 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) + + avList.add(new ArgValue(a, null, null, value, av.getArgIndex())); + } + 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 Opt.PRIMARY args of the same type + if (tmpA.sharesType(a) && tmpA.hasOption(Opt.PRIMARY)) + { + for (ArgValue tmpAv : getArgValueList(tmpA)) + { + int tmpArgIndex = tmpAv.getArgIndex(); + if (tmpArgIndex > av.getArgIndex() + && tmpArgIndex < nextPrimaryArgOfSameTypeIndex) + { + nextPrimaryArgOfSameTypeIndex = tmpArgIndex; + } + } + } + } + List tmpList = List.copyOf(avList); + for (ArgValue tmpAv : tmpList) + { + if (nextPrimaryArgOfSameTypeIndex < tmpAv.getArgIndex()) + { + // looks like this tmpAv actually belongs to a different primary Arg + avList.remove(tmpAv); + } + } + } + + return avList; + } + public ArgValue getArgValue(Arg a) { List vals = getArgValueList(a); @@ -193,7 +283,7 @@ public class ArgValuesMap } 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 @@ -215,14 +305,14 @@ public class ArgValuesMap } // 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)) { @@ -237,7 +327,7 @@ public class ArgValuesMap } 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; } } @@ -370,33 +460,32 @@ public class ArgValuesMap 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(); @@ -414,14 +503,14 @@ public class ArgValuesMap && 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)) )) { diff --git a/src/jalview/bin/argparser/BootstrapArgs.java b/src/jalview/bin/argparser/BootstrapArgs.java index 80e08c5..51f8147 100644 --- a/src/jalview/bin/argparser/BootstrapArgs.java +++ b/src/jalview/bin/argparser/BootstrapArgs.java @@ -160,10 +160,12 @@ public class BootstrapArgs 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); + } } }