From: Ben Soares Date: Sat, 16 Sep 2023 11:24:31 +0000 (+0100) Subject: JAL-4269 Now using --width, --height, --scale for both --image and --structureimage... X-Git-Tag: Release_2_11_3_0~8^2~5^2~19 X-Git-Url: http://source.jalview.org/gitweb/?p=jalview.git;a=commitdiff_plain;h=85240f268c71a9d0dc91dc196a93cb10d29794d3 JAL-4269 Now using --width, --height, --scale for both --image and --structureimage. Multiple --image and --structureimage can be specified with --imagecolour allowing changes of colour. --width etc only apply to that particular image. --- diff --git a/src/jalview/bin/Commands.java b/src/jalview/bin/Commands.java index ba72831..3173b35 100644 --- a/src/jalview/bin/Commands.java +++ b/src/jalview/bin/Commands.java @@ -17,7 +17,6 @@ import jalview.api.structures.JalviewStructureDisplayI; import jalview.bin.Jalview.ExitCode; import jalview.bin.argparser.Arg; import jalview.bin.argparser.ArgParser; -import jalview.bin.argparser.ArgParser.Position; import jalview.bin.argparser.ArgValue; import jalview.bin.argparser.ArgValuesMap; import jalview.bin.argparser.SubVals; @@ -55,6 +54,7 @@ import jalview.util.ImageMaker; import jalview.util.ImageMaker.TYPE; import jalview.util.MessageManager; import jalview.util.Platform; +import jalview.util.StringUtils; import jalview.util.imagemaker.BitmapImageSizing; public class Commands @@ -290,29 +290,14 @@ public class Commands } } - // colour alignment? - String colour = ArgParser.getFromSubValArgOrPref(avm, av, - Arg.COLOUR, sv, null, "DEFAULT_COLOUR_PROT", ""); - if ("" != colour) - { - ColourSchemeI cs = ColourSchemeProperty.getColourScheme( - af.getViewport(), af.getViewport().getAlignment(), - colour); - - if (cs == null && !"None".equals(colour)) - { - addWarn("Couldn't parse '" + colour + "' as a colourscheme."); - } - else - { - af.changeColour(cs); - } - Jalview.testoutput(argParser, Arg.COLOUR, "zappo", colour); - } + // colour alignment + String colour = avm.getFromSubValArgOrPref(av, Arg.COLOUR, sv, + null, "DEFAULT_COLOUR_PROT", ""); + this.colourAlignFrame(af, colour); // Change alignment frame title - String title = ArgParser.getFromSubValArgOrPref(avm, av, - Arg.TITLE, sv, null, null, null); + String title = avm.getFromSubValArgOrPref(av, Arg.TITLE, sv, null, + null, null); if (title != null) { af.setTitle(title); @@ -320,7 +305,7 @@ public class Commands } // Add features - String featuresfile = ArgParser.getValueFromSubValOrArg(avm, av, + String featuresfile = avm.getValueFromSubValOrArg(av, Arg.FEATURES, sv); if (featuresfile != null) { @@ -331,8 +316,8 @@ public class Commands } // Add annotations from file - String annotationsfile = ArgParser.getValueFromSubValOrArg(avm, - av, Arg.ANNOTATIONS, sv); + String annotationsfile = avm.getValueFromSubValOrArg(av, + Arg.ANNOTATIONS, sv); if (annotationsfile != null) { af.loadJalviewDataFile(annotationsfile, null, null, null); @@ -342,8 +327,8 @@ public class Commands } // Set or clear the sortbytree flag - boolean sortbytree = ArgParser.getBoolFromSubValOrArg(avm, - Arg.SORTBYTREE, sv); + boolean sortbytree = avm.getBoolFromSubValOrArg(Arg.SORTBYTREE, + sv); if (sortbytree) { af.getViewport().setSortByTree(true); @@ -351,8 +336,7 @@ public class Commands } // Load tree from file - String treefile = ArgParser.getValueFromSubValOrArg(avm, av, - Arg.TREE, sv); + String treefile = avm.getValueFromSubValOrArg(av, Arg.TREE, sv); if (treefile != null) { try @@ -371,13 +355,13 @@ public class Commands } // Show secondary structure annotations? - boolean showSSAnnotations = ArgParser.getFromSubValArgOrPref(avm, + boolean showSSAnnotations = avm.getFromSubValArgOrPref( Arg.SHOWSSANNOTATIONS, av.getSubVals(), null, "STRUCT_FROM_PDB", true); af.setAnnotationsVisibility(showSSAnnotations, true, false); // Show sequence annotations? - boolean showAnnotations = ArgParser.getFromSubValArgOrPref(avm, + boolean showAnnotations = avm.getFromSubValArgOrPref( Arg.SHOWANNOTATIONS, av.getSubVals(), null, "SHOW_ANNOTATIONS", true); af.setAnnotationsVisibility(showAnnotations, false, true); @@ -395,7 +379,7 @@ public class Commands } // wrap alignment? do this last for formatting reasons - wrap = ArgParser.getFromSubValArgOrPref(avm, Arg.WRAP, sv, null, + wrap = avm.getFromSubValArgOrPref(Arg.WRAP, sv, null, "WRAP_ALIGNMENT", false); // af.setWrapFormat(wrap) is applied after structures are opened for // annotation reasons @@ -456,6 +440,7 @@ public class Commands { String val = av.getValue(); SubVals subVals = av.getSubVals(); + int argIndex = av.getArgIndex(); SequenceI seq = getSpecifiedSequence(af, avm, av); if (seq == null) { @@ -526,10 +511,9 @@ public class Commands String structureFilepath = structureFile.getAbsolutePath(); // get PAEMATRIX file and label from subvals or Arg.PAEMATRIX - String paeFilepath = ArgParser - .getFromSubValArgOrPrefWithSubstitutions(argParser, avm, - Arg.PAEMATRIX, Position.AFTER, av, subVals, null, - null, null); + String paeFilepath = avm.getFromSubValArgOrPrefWithSubstitutions( + argParser, Arg.PAEMATRIX, ArgValuesMap.Position.AFTER, av, + subVals, null, null, null); if (paeFilepath != null) { File paeFile = new File(paeFilepath); @@ -546,19 +530,17 @@ public class Commands } // showing annotations from structure file or not - boolean ssFromStructure = ArgParser.getFromSubValArgOrPref(avm, + boolean ssFromStructure = avm.getFromSubValArgOrPref( Arg.SHOWSSANNOTATIONS, subVals, null, "STRUCT_FROM_PDB", true); // get TEMPFAC type from subvals or Arg.TEMPFAC in case user Adds // reference annotations - String tftString = ArgParser - .getFromSubValArgOrPrefWithSubstitutions(argParser, avm, - Arg.TEMPFAC, Position.AFTER, av, subVals, null, - null, null); - boolean notempfac = ArgParser.getFromSubValArgOrPref(avm, - Arg.NOTEMPFAC, subVals, null, "ADD_TEMPFACT_ANN", false, - true); + String tftString = avm.getFromSubValArgOrPrefWithSubstitutions( + argParser, Arg.TEMPFAC, ArgValuesMap.Position.AFTER, av, + subVals, null, null, null); + boolean notempfac = avm.getFromSubValArgOrPref(Arg.NOTEMPFAC, + subVals, null, "ADD_TEMPFACT_ANN", false, true); TFType tft = notempfac ? null : TFType.DEFAULT; if (tftString != null && !notempfac) { @@ -587,18 +569,18 @@ public class Commands } } - String sViewer = ArgParser.getFromSubValArgOrPref(avm, - Arg.STRUCTUREVIEWER, Position.AFTER, av, subVals, null, - null, "jmol"); - ViewerType viewerType = ViewerType.getFromString(sViewer); + String sViewerName = avm.getFromSubValArgOrPref( + Arg.STRUCTUREVIEWER, ArgValuesMap.Position.AFTER, av, + subVals, null, null, "jmol"); + ViewerType viewerType = ViewerType.getFromString(sViewerName); // TODO use ssFromStructure - StructureViewer sv = StructureChooser + StructureViewer structureViewer = StructureChooser .openStructureFileForSequence(null, null, ap, seq, false, structureFilepath, tft, paeFilepath, false, ssFromStructure, false, viewerType); - if (sv == null) + if (structureViewer == null) { addError("Failed to import and open structure view for file '" + structureFile + "'."); @@ -607,17 +589,17 @@ public class Commands try { long tries = 1000; - while (sv.isBusy() && tries > 0) + while (structureViewer.isBusy() && tries > 0) { Thread.sleep(25); - if (sv.isBusy()) + if (structureViewer.isBusy()) { tries--; Console.debug( "Waiting for viewer for " + structureFilepath); } } - if (tries == 0 && sv.isBusy()) + if (tries == 0 && structureViewer.isBusy()) { addWarn("Gave up waiting for structure viewer to load file '" + structureFile @@ -639,88 +621,106 @@ public class Commands { svMap.put(id, new ArrayList<>()); } - svMap.get(id).add(sv); + svMap.get(id).add(structureViewer); Console.debug( "Successfully opened viewer for " + structureFilepath); - String structureImageFilename = ArgParser.getValueFromSubValOrArg( - avm, av, Arg.STRUCTUREIMAGE, subVals); - if (sv != null && structureImageFilename != null) + + if (avm.containsArg(Arg.STRUCTUREIMAGE)) { - ArgValue siAv = avm.getClosestNextArgValueOfArg(av, - Arg.STRUCTUREIMAGE); - SubVals sisv = null; - if (structureImageFilename.equals(siAv.getValue())) - { - sisv = siAv.getSubVals(); - } - File structureImageFile = new File(structureImageFilename); - String width = ArgParser.getValueFromSubValOrArg(avm, av, - Arg.STRUCTUREIMAGEWIDTH, sisv); - String height = ArgParser.getValueFromSubValOrArg(avm, av, - Arg.STRUCTUREIMAGEHEIGHT, sisv); - String scale = ArgParser.getValueFromSubValOrArg(avm, av, - Arg.STRUCTUREIMAGESCALE, sisv); - String renderer = ArgParser.getValueFromSubValOrArg(avm, av, - Arg.STRUCTUREIMAGETEXTRENDERER, sisv); - String typeS = ArgParser.getValueFromSubValOrArg(avm, av, - Arg.STRUCTUREIMAGETYPE, sisv); - if (typeS == null || typeS.length() == 0) - { - typeS = FileUtils.getExtension(structureImageFile); - } - TYPE imageType; - try - { - imageType = Enum.valueOf(TYPE.class, - typeS.toUpperCase(Locale.ROOT)); - } catch (IllegalArgumentException e) - { - addWarn("Do not know image format '" + typeS - + "', using PNG"); - imageType = TYPE.PNG; - } - BitmapImageSizing userBis = ImageMaker - .parseScaleWidthHeightStrings(scale, width, height); - // TODO MAKE THIS VIEWER INDEPENDENT!! - switch (StructureViewer.getViewerType()) + for (ArgValue structureImageArgValue : avm + .getArgValueList(Arg.STRUCTUREIMAGE)) { - case JMOL: - JalviewStructureDisplayI sview = sv - .getJalviewStructureDisplay(); - if (sview instanceof AppJmol) + String structureImageFilename = structureImageArgValue + .getValue(); + if (structureViewer != null && structureImageFilename != null) { - AppJmol jmol = (AppJmol) sview; + SubVals structureImageSubVals = null; + structureImageSubVals = structureImageArgValue.getSubVals(); + File structureImageFile = new File(structureImageFilename); + String width = avm.getValueFromSubValOrArg( + structureImageArgValue, Arg.WIDTH, + structureImageSubVals); + String height = avm.getValueFromSubValOrArg( + structureImageArgValue, Arg.HEIGHT, + structureImageSubVals); + String scale = avm.getValueFromSubValOrArg( + structureImageArgValue, Arg.SCALE, + structureImageSubVals); + String renderer = avm.getValueFromSubValOrArg( + structureImageArgValue, Arg.TEXTRENDERER, + structureImageSubVals); + String typeS = avm.getValueFromSubValOrArg( + structureImageArgValue, Arg.TYPE, + structureImageSubVals); + if (typeS == null || typeS.length() == 0) + { + typeS = FileUtils.getExtension(structureImageFile); + } + TYPE imageType; try { - boolean success = this.checksBeforeWritingToFile(avm, - subVals, false, structureImageFilename, - "structure image", isError); - if (!success) + imageType = Enum.valueOf(TYPE.class, + typeS.toUpperCase(Locale.ROOT)); + } catch (IllegalArgumentException e) + { + addWarn("Do not know image format '" + typeS + + "', using PNG"); + imageType = TYPE.PNG; + } + BitmapImageSizing userBis = ImageMaker + .parseScaleWidthHeightStrings(scale, width, height); + + String imageColour = avm.getValueFromSubValOrArg( + structureImageArgValue, Arg.IMAGECOLOUR, + structureImageSubVals); + ColourSchemeI originalColourScheme = this + .getColourScheme(af); + this.colourAlignFrame(af, imageColour); + + // TODO MAKE THIS VIEWER INDEPENDENT!! + switch (StructureViewer.getViewerType()) + { + case JMOL: + JalviewStructureDisplayI sview = structureViewer + .getJalviewStructureDisplay(); + if (sview instanceof AppJmol) { - continue; - } + AppJmol jmol = (AppJmol) sview; + try + { + boolean success = this.checksBeforeWritingToFile(avm, + subVals, false, structureImageFilename, + "structure image", isError); + if (!success) + { + continue; + } + + Console.debug( + "Rendering image to " + structureImageFile); + jmol.makePDBImage(structureImageFile, imageType, + renderer, userBis); + Console.debug("Finished Rendering image to " + + structureImageFile); + + } catch (ImageOutputException ioexc) + { + addError("Unexpected error whilst exporting image to " + + structureImageFile, ioexc); + isError = true; + continue; + } - Console.debug("Rendering image to " + structureImageFile); - jmol.makePDBImage(structureImageFile, imageType, renderer, - userBis); - Console.debug("Finished Rendering image to " - + structureImageFile); - - } catch (ImageOutputException ioexc) - { - addError("Unexpected error whilst exporting image to " - + structureImageFile, ioexc); - isError = true; + } + break; + default: + addWarn("Cannot export image for structure viewer " + + structureViewer.getViewerType() + " yet"); continue; } - + this.colourAlignFrame(af, originalColourScheme); } - break; - default: - addWarn("Cannot export image for structure viewer " - + sv.getViewerType() + " yet"); - continue; } } } @@ -794,29 +794,29 @@ public class Commands Boolean isError = Boolean.valueOf(false); if (avm.containsArg(Arg.IMAGE)) { - for (ArgValue av : avm.getArgValueList(Arg.IMAGE)) + for (ArgValue imageAv : avm.getArgValueList(Arg.IMAGE)) { - String val = av.getValue(); - SubVals subVal = av.getSubVals(); - String fileName = subVal.getContent(); + String val = imageAv.getValue(); + SubVals imageSubVals = imageAv.getSubVals(); + String fileName = imageSubVals.getContent(); File file = new File(fileName); String name = af.getName(); - String renderer = ArgParser.getValueFromSubValOrArg(avm, av, - Arg.TEXTRENDERER, subVal); + String renderer = avm.getValueFromSubValOrArg(imageAv, + Arg.TEXTRENDERER, imageSubVals); if (renderer == null) renderer = "text"; String type = "png"; // default - String scale = ArgParser.getValueFromSubValOrArg(avm, av, Arg.SCALE, - subVal); - String width = ArgParser.getValueFromSubValOrArg(avm, av, Arg.WIDTH, - subVal); - String height = ArgParser.getValueFromSubValOrArg(avm, av, - Arg.HEIGHT, subVal); + String scale = avm.getValueFromSubValOrArg(imageAv, Arg.SCALE, + imageSubVals); + String width = avm.getValueFromSubValOrArg(imageAv, Arg.WIDTH, + imageSubVals); + String height = avm.getValueFromSubValOrArg(imageAv, Arg.HEIGHT, + imageSubVals); BitmapImageSizing userBis = ImageMaker .parseScaleWidthHeightStrings(scale, width, height); - type = ArgParser.getValueFromSubValOrArg(avm, av, Arg.TYPE, subVal); + type = avm.getValueFromSubValOrArg(imageAv, Arg.TYPE, imageSubVals); if (type == null && fileName != null) { for (String ext : new String[] { "svg", "png", "html", "eps" }) @@ -831,10 +831,15 @@ public class Commands Cache.setPropsAreReadOnly(true); Cache.setProperty("EXPORT_EMBBED_BIOJSON", "false"); + String imageColour = avm.getValueFromSubValOrArg(imageAv, + Arg.IMAGECOLOUR, imageSubVals); + ColourSchemeI originalColourScheme = this.getColourScheme(af); + this.colourAlignFrame(af, imageColour); + Console.info("Writing " + file); - boolean success = checksBeforeWritingToFile(avm, subVal, false, - fileName, "image", isError); + boolean success = checksBeforeWritingToFile(avm, imageSubVals, + false, fileName, "image", isError); if (!success) { continue; @@ -897,6 +902,8 @@ public class Commands ioex); isError = true; } + + this.colourAlignFrame(af, originalColourScheme); } } return !isError; @@ -926,8 +933,8 @@ public class Commands File file = new File(fileName); String name = af.getName(); - String format = ArgParser.getValueFromSubValOrArg(avm, av, - Arg.FORMAT, subVals); + String format = avm.getValueFromSubValOrArg(av, Arg.FORMAT, + subVals); FileFormats ffs = FileFormats.getInstance(); List validFormats = ffs.getWritableFormats(false); @@ -987,9 +994,8 @@ public class Commands continue; } - boolean backups = ArgParser.getFromSubValArgOrPref(avm, Arg.BACKUPS, - subVals, null, - Platform.isHeadless() ? null : BackupFiles.ENABLED, + boolean backups = avm.getFromSubValArgOrPref(Arg.BACKUPS, subVals, + null, Platform.isHeadless() ? null : BackupFiles.ENABLED, !Platform.isHeadless()); Console.info("Writing " + fileName); @@ -1017,7 +1023,7 @@ public class Commands ArgValue av) { SubVals subVals = av.getSubVals(); - ArgValue idAv = avm.getClosestNextArgValueOfArg(av, Arg.SEQID); + ArgValue idAv = avm.getClosestNextArgValueOfArg(av, Arg.SEQID, true); SequenceI seq = null; if (subVals == null && idAv == null) return null; @@ -1077,6 +1083,36 @@ public class Commands return svs; } + private void colourAlignFrame(AlignFrame af, String colour) + { + // use string "none" to remove colour scheme + if (colour != null && "" != colour) + { + ColourSchemeI cs = ColourSchemeProperty.getColourScheme( + af.getViewport(), af.getViewport().getAlignment(), colour); + if (cs == null && !StringUtils.equalsIgnoreCase(colour, "none")) + { + addWarn("Couldn't parse '" + colour + "' as a colourscheme."); + } + else + { + Jalview.testoutput(argParser, Arg.COLOUR, "zappo", colour); + colourAlignFrame(af, cs); + } + } + } + + private void colourAlignFrame(AlignFrame af, ColourSchemeI cs) + { + // Note that cs == null removes colour scheme from af + af.changeColour(cs); + } + + private ColourSchemeI getColourScheme(AlignFrame af) + { + return af.getViewport().getGlobalColourScheme(); + } + private void addInfo(String errorMessage) { Console.info(errorMessage); @@ -1106,8 +1142,8 @@ public class Commands { File file = new File(filename); - boolean overwrite = ArgParser.getFromSubValArgOrPref(avm, Arg.OVERWRITE, - subVal, null, "OVERWRITE_OUTPUT", false); + boolean overwrite = avm.getFromSubValArgOrPref(Arg.OVERWRITE, subVal, + null, "OVERWRITE_OUTPUT", false); boolean stdout = false; boolean backups = false; if (includeBackups) @@ -1116,8 +1152,8 @@ public class Commands // backups. Use the Arg.BACKUPS or subval "backups" setting first, // otherwise if headless assume false, if not headless use the user // preference with default true. - backups = ArgParser.getFromSubValArgOrPref(avm, Arg.BACKUPS, subVal, - null, Platform.isHeadless() ? null : BackupFiles.ENABLED, + backups = avm.getFromSubValArgOrPref(Arg.BACKUPS, subVal, null, + Platform.isHeadless() ? null : BackupFiles.ENABLED, !Platform.isHeadless()); } @@ -1130,8 +1166,8 @@ public class Commands return false; } - boolean mkdirs = ArgParser.getFromSubValArgOrPref(avm, Arg.MKDIRS, - subVal, null, "MKDIRS_OUTPUT", false); + boolean mkdirs = avm.getFromSubValArgOrPref(Arg.MKDIRS, subVal, null, + "MKDIRS_OUTPUT", false); if (!FileUtils.checkParentDir(file, mkdirs)) { diff --git a/src/jalview/bin/argparser/Arg.java b/src/jalview/bin/argparser/Arg.java index 9dd5c93..51a2d16 100644 --- a/src/jalview/bin/argparser/Arg.java +++ b/src/jalview/bin/argparser/Arg.java @@ -157,45 +157,56 @@ public enum Arg IMAGE(Type.IMAGE, "Output an image of the open alignment window. Format is specified by the subval modifier, a following --type argument or guessed from the file extension. Valid formats/extensions are:\n" + "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.", - Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS, Opt.ALLOWMULTIID, - Opt.REQUIREINPUT, Opt.OUTPUTFILE, Opt.PRIMARY), + Opt.STRING, Opt.LINKED, Opt.ALLOWSUBSTITUTIONS, Opt.MULTIVALUE, + Opt.ALLOWMULTIID, Opt.REQUIREINPUT, Opt.OUTPUTFILE, Opt.PRIMARY), + STRUCTUREIMAGE(Type.IMAGE, + "Export an image of a 3D structure opened in JMOL", Opt.STRING, + Opt.LINKED, Opt.MULTIVALUE, Opt.OUTPUTFILE, Opt.ALLOWMULTIID, + Opt.PRIMARY), TYPE(Type.IMAGE, - "Set the image format for the preceding --image. Valid values are:\n" - + "svg,\n" + "png,\n" + "eps,\n" + "html,\n" + "biojs.", - Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID), + "Set the image format for the preceding " + Arg.IMAGE.argString() + + " or " + Arg.STRUCTUREIMAGE.argString() + + ". Valid values are:\n" + "svg,\n" + "png,\n" + "eps,\n" + + "html,\n" + "biojs.", + Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID), TEXTRENDERER(Type.IMAGE, "Sets whether text in a vector image format (SVG, HTML, EPS) should be rendered as text or vector line-art. Possible values are:\n" + "text,\n" + "lineart.", - Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID), + Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID), SCALE(Type.IMAGE, "Sets a scaling for bitmap image format (PNG). Should be given as a floating point number. If used in conjunction with --width and --height then the smallest scaling will be used (scale, width and height provide bounds for the image).", - Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID), + Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID), WIDTH(Type.IMAGE, "Sets a width for bitmap image format (PNG) with the height maintaining the aspect ratio. Should be given as a positive integer. If used in conjunction with --scale and --height then the smallest scaling will be used (scale, width and height provide bounds for the image).", - Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID), + Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID), HEIGHT(Type.IMAGE, "Sets a height for bitmap image format (PNG) with the width maintaining the aspect ratio. Should be given as a positive integer. If used in conjunction with --scale and --width then the smallest scaling will be used (scale, width and height provide bounds for the image).", - Opt.STRING, Opt.LINKED, Opt.ALLOWMULTIID), - STRUCTUREIMAGE(Type.STRUCTUREIMAGE, - "Export an image of a 3D structure opened in JMOL", Opt.STRING, - Opt.LINKED, Opt.MULTIVALUE, Opt.OUTPUTFILE, Opt.ALLOWMULTIID), - STRUCTUREIMAGETYPE(Type.STRUCTUREIMAGE, + Opt.STRING, Opt.LINKED, Opt.MULTIVALUE, Opt.ALLOWMULTIID), + IMAGECOLOUR(Type.IMAGE, "imagecolor", // being a bit soft on the Americans! + "Applies the colour scheme to the open alignment window for this image, otherwise the value of " + + Arg.COLOUR.argString() + + " (or none) will apply. Valid values are the same as " + + Arg.COLOUR.argString() + ".", + 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.STRUCTUREIMAGE, + 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.STRUCTUREIMAGE, + 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.STRUCTUREIMAGE, + 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.STRUCTUREIMAGE, + 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" @@ -463,8 +474,9 @@ 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"), - STRUCTUREIMAGE("arguments used to export an image of an structure"), + 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"), 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 diff --git a/src/jalview/bin/argparser/ArgParser.java b/src/jalview/bin/argparser/ArgParser.java index 7581dde..fd42bb2 100644 --- a/src/jalview/bin/argparser/ArgParser.java +++ b/src/jalview/bin/argparser/ArgParser.java @@ -31,10 +31,8 @@ import java.util.EnumSet; import java.util.Enumeration; import java.util.HashMap; import java.util.List; -import java.util.Locale; import java.util.Map; -import jalview.bin.Cache; import jalview.bin.Console; import jalview.bin.Jalview; import jalview.bin.Jalview.ExitCode; @@ -619,10 +617,9 @@ 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 - || a.getType() == Type.STRUCTUREIMAGE) - && !a.hasOption(Opt.PRIMARY)) + if (allStructures && (a.getType() == Type.STRUCTURE + // || a.getType() == Type.STRUCTUREIMAGE) + ) && !a.hasOption(Opt.PRIMARY)) { if (!subvals.has(Arg.ALLSTRUCTURES.getName())) // && !subvals.has("structureid")) @@ -971,161 +968,6 @@ public class ArgParser return args; } - public static enum Position - { - FIRST, BEFORE, AFTER - } - - /** - * get from following Arg of type a or subval of same name (lowercase) - */ - public static String getValueFromSubValOrArg(ArgValuesMap avm, - ArgValue av, Arg a, SubVals sv) - { - return getFromSubValArgOrPref(avm, av, a, sv, null, null, null); - } - - /** - * get from following Arg of type a or subval key or preference pref or - * default def - */ - public static String getFromSubValArgOrPref(ArgValuesMap avm, ArgValue av, - Arg a, SubVals sv, String key, String pref, String def) - { - return getFromSubValArgOrPref(avm, 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 static String getFromSubValArgOrPref(ArgValuesMap avm, Arg a, - Position pos, ArgValue av, SubVals sv, String key, String pref, - String def) - { - return getFromSubValArgOrPrefWithSubstitutions(null, avm, a, pos, av, - sv, key, pref, def); - } - - public static String getFromSubValArgOrPrefWithSubstitutions(ArgParser ap, - ArgValuesMap avm, Arg a, Position pos, ArgValue av, SubVals sv, - String key, String pref, String def) - { - if (key == null) - key = a.getName(); - String value = null; - if (sv != null && sv.has(key) && sv.get(key) != null) - { - value = ap == null ? sv.get(key) - : sv.getWithSubstitutions(ap, avm.getLinkedId(), key); - } - else if (avm != null && avm.containsArg(a)) - { - if (pos == Position.FIRST && avm.getValue(a) != null) - value = avm.getValue(a); - else if (pos == Position.BEFORE - && avm.getClosestPreviousArgValueOfArg(av, a) != null) - value = avm.getClosestPreviousArgValueOfArg(av, a).getValue(); - else if (pos == Position.AFTER - && avm.getClosestNextArgValueOfArg(av, a) != null) - value = avm.getClosestNextArgValueOfArg(av, a).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 - || a.getType() == Type.STRUCTUREIMAGE)) - { - ArgValue av2 = avm.getArgValueOfArgWithSubValKey(a, - Arg.ALLSTRUCTURES.getName()); - if (av2 != null) - { - value = av2.getValue(); - } - } - } - if (value == null) - { - value = pref != null ? Cache.getDefault(pref, def) : def; - } - return value; - } - - public static boolean getBoolFromSubValOrArg(ArgValuesMap avm, Arg a, - SubVals sv) - { - return getFromSubValArgOrPref(avm, a, sv, null, null, false); - } - - public static boolean getFromSubValArgOrPref(ArgValuesMap avm, Arg a, - SubVals sv, String key, String pref, boolean def) - { - return getFromSubValArgOrPref(avm, a, sv, key, pref, def, false); - } - - public static boolean getFromSubValArgOrPref(ArgValuesMap avm, Arg a, - SubVals sv, String key, String pref, boolean def, - boolean invertPref) - { - if ((key == null && a == null) || (sv == null && a == null)) - return false; - - boolean usingArgKey = false; - if (key == null) - { - key = a.getName(); - usingArgKey = true; - } - - String nokey = ArgParser.NEGATESTRING + key; - - // look for key or nokey in subvals first (if using Arg check options) - if (sv != null) - { - // check for true boolean - if (sv.has(key) && sv.get(key) != null) - { - if (usingArgKey) - { - if (!(a.hasOption(Opt.BOOLEAN) || a.hasOption(Opt.UNARY))) - { - Console.debug( - "Looking for boolean in subval from non-boolean/non-unary Arg " - + a.getName()); - return false; - } - } - return sv.get(key).toLowerCase(Locale.ROOT).equals("true"); - } - - // check for negative boolean (subval "no..." will be "true") - if (sv.has(nokey) && sv.get(nokey) != null) - { - if (usingArgKey) - { - if (!(a.hasOption(Opt.BOOLEAN))) - { - Console.debug( - "Looking for negative boolean in subval from non-boolean Arg " - + a.getName()); - return false; - } - } - return !sv.get(nokey).toLowerCase(Locale.ROOT).equals("true"); - } - } - - // check argvalues - if (avm != null && avm.containsArg(a)) - return avm.getBoolean(a); - - // return preference or default - boolean prefVal = pref != null ? Cache.getDefault(pref, def) : false; - return pref != null ? (invertPref ? !prefVal : prefVal) : def; - } - // the following methods look for the "*" linkedId and add the argvalue to all // linkedId ArgValues if it does. /** @@ -1138,13 +980,6 @@ public class ArgParser argIndex, doSubs); } - private void addValue(String linkedId, Type type, ArgValues avs, String v, - int argIndex, boolean doSubs) - { - this.argValueOperation(Op.ADDVALUE, linkedId, type, avs, null, v, false, - argIndex, doSubs); - } - private void setBoolean(String linkedId, Type type, ArgValues avs, boolean b, int argIndex) { @@ -1367,4 +1202,5 @@ public class ArgParser { return mixedExamples; } + } \ No newline at end of file diff --git a/src/jalview/bin/argparser/ArgValuesMap.java b/src/jalview/bin/argparser/ArgValuesMap.java index 4aa8570..99a4836 100644 --- a/src/jalview/bin/argparser/ArgValuesMap.java +++ b/src/jalview/bin/argparser/ArgValuesMap.java @@ -2,12 +2,17 @@ package jalview.bin.argparser; import java.io.File; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; +import jalview.bin.Cache; +import jalview.bin.Console; import jalview.bin.argparser.Arg.Opt; +import jalview.bin.argparser.Arg.Type; import jalview.util.FileUtils; /** @@ -16,6 +21,8 @@ import jalview.util.FileUtils; */ public class ArgValuesMap { + private List argInfoList = new ArrayList<>(); + protected Map m; private String linkedId; @@ -165,7 +172,8 @@ public class ArgValuesMap return closestAv; } - public ArgValue getClosestNextArgValueOfArg(ArgValue thisAv, Arg a) + public ArgValue getClosestNextArgValueOfArg(ArgValue thisAv, Arg a, + boolean withinType) { // 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 @@ -185,6 +193,35 @@ public class ArgValuesMap closestAv = av; } } + + // check if withinType this closestAv doesn't belong to the next primary arg + // of this type + if (withinType && 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)) + { + for (ArgValue tmpAv : getArgValueList(tmpA)) + { + int tmpArgIndex = tmpAv.getArgIndex(); + if (tmpArgIndex > thisArgIndex + && tmpArgIndex < nextPrimaryArgOfSameTypeIndex) + { + nextPrimaryArgOfSameTypeIndex = tmpArgIndex; + } + } + } + } + if (nextPrimaryArgOfSameTypeIndex < closestAv.getArgIndex()) + { + // looks licke closestAv actually belongs to a different primary Arg + return null; + } + } + return closestAv; } @@ -281,4 +318,226 @@ public class ArgValuesMap } return false; } + + /* + * ArgInfo is a more straightforward list of arguments and their info + */ + + public void addArgInfo(Arg arg, String value, SubVals subVals, + int argIndex) + { + argInfoList.add(new ArgInfo(arg, value, subVals, argIndex)); + } + + public List getArgInfoList() + { + Collections.sort(argInfoList); + return argInfoList; + } + + /** + * get from following Arg of type a or subval of same name (lowercase) + */ + public String getValueFromSubValOrArg(ArgValue av, Arg a, SubVals sv) + { + return getFromSubValArgOrPref(av, a, sv, null, null, null); + } + + /** + * get from following Arg of type a or subval key or preference pref or + * default def + */ + 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); + } + + /** + * 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) + { + 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) + { + return getFromSubValArgOrPrefWithSubstitutionsWithinType(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) + { + if (key == null) + key = a.getName(); + String value = null; + if (sv != null && sv.has(key) && sv.get(key) != null) + { + value = ap == null ? sv.get(key) + : sv.getWithSubstitutions(ap, getLinkedId(), key); + } + else if (containsArg(a)) + { + if (pos == ArgValuesMap.Position.FIRST && getValue(a) != null) + value = getValue(a); + else if (pos == ArgValuesMap.Position.BEFORE + && 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(); + + // 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 + // || a.getType() == Type.STRUCTUREIMAGE)) + )) + { + ArgValue av2 = getArgValueOfArgWithSubValKey(a, + Arg.ALLSTRUCTURES.getName()); + if (av2 != null) + { + value = av2.getValue(); + } + } + } + if (value == null) + { + value = pref != null ? Cache.getDefault(pref, def) : def; + } + return value; + } + + public boolean getBoolFromSubValOrArg(Arg a, SubVals sv) + { + return getFromSubValArgOrPref(a, sv, null, null, false); + } + + public boolean getFromSubValArgOrPref(Arg a, SubVals sv, String key, + String pref, boolean def) + { + return getFromSubValArgOrPref(a, sv, key, pref, def, false); + } + + public boolean getFromSubValArgOrPref(Arg a, SubVals sv, String key, + String pref, boolean def, boolean invertPref) + { + if ((key == null && a == null) || (sv == null && a == null)) + return false; + + boolean usingArgKey = false; + if (key == null) + { + key = a.getName(); + usingArgKey = true; + } + + String nokey = ArgParser.NEGATESTRING + key; + + // look for key or nokey in subvals first (if using Arg check options) + if (sv != null) + { + // check for true boolean + if (sv.has(key) && sv.get(key) != null) + { + if (usingArgKey) + { + if (!(a.hasOption(Opt.BOOLEAN) || a.hasOption(Opt.UNARY))) + { + Console.debug( + "Looking for boolean in subval from non-boolean/non-unary Arg " + + a.getName()); + return false; + } + } + return sv.get(key).toLowerCase(Locale.ROOT).equals("true"); + } + + // check for negative boolean (subval "no..." will be "true") + if (sv.has(nokey) && sv.get(nokey) != null) + { + if (usingArgKey) + { + if (!(a.hasOption(Opt.BOOLEAN))) + { + Console.debug( + "Looking for negative boolean in subval from non-boolean Arg " + + a.getName()); + return false; + } + } + return !sv.get(nokey).toLowerCase(Locale.ROOT).equals("true"); + } + } + + // check argvalues + if (containsArg(a)) + return getBoolean(a); + + // return preference or default + boolean prefVal = pref != null ? Cache.getDefault(pref, def) : false; + return pref != null ? (invertPref ? !prefVal : prefVal) : def; + } + + public class ArgInfo implements Comparable + { + private Arg arg; + + private String value; + + private SubVals subVals; + + private int argIndex; + + public ArgInfo(Arg arg, String value, SubVals subVals, int argIndex) + { + this.arg = arg; + this.value = value; + this.subVals = subVals; + this.argIndex = argIndex; + } + + public Arg arg() + { + return arg; + } + + public String value() + { + return value; + } + + public SubVals subVals() + { + return subVals; + } + + public int argIndex() + { + return argIndex; + } + + @Override + public int compareTo(ArgInfo ai2) + { + return Integer.compare(this.argIndex(), ai2.argIndex()); + } + } + + public static enum Position + { + FIRST, BEFORE, AFTER + } } diff --git a/test/jalview/bin/CommandsTest.java b/test/jalview/bin/CommandsTest.java index 66250d8..4d10c31 100644 --- a/test/jalview/bin/CommandsTest.java +++ b/test/jalview/bin/CommandsTest.java @@ -214,11 +214,11 @@ public class CommandsTest + "--open=./examples/test_fab41.result/sample.a2m " + "--structure=./examples/test_fab41.result/test_fab41_unrelaxed_rank_1_model_3.pdb " + "--structureimage=" + testfiles - + "/structureimage2.png --structureimagescale=1.5" + + "/structureimage2.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 --structureimagescale=2.0", + + "/structureimage3.png --scale=2.0 ", new String[] { testfiles + "/structureimage1.png", testfiles + "/structureimage2.png", @@ -229,11 +229,11 @@ public class CommandsTest + "--open=./examples/test_fab41.result/sample.a2m " + "--structure=./examples/test_fab41.result/test_fab41_unrelaxed_rank_1_model_3.pdb " + "--structureimage=" + testfiles - + "/structureimage2.png --structureimagescale=1.5" + + "/structureimage2.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 --structureimagescale=2.0", + + "/structureimage3.png --scale=2.0 ", new String[] { testfiles + "/structureimage1.png", testfiles + "/structureimage2.png",