From 0664ff257cacf018e31bf1b1b15753b28800e4f0 Mon Sep 17 00:00:00 2001 From: Ben Soares Date: Fri, 24 Nov 2023 15:40:05 +0000 Subject: [PATCH] JAL-4059 Allow form-created querystring style values for boolean values --- src/jalview/bin/argparser/ArgParser.java | 103 +++++++++++++++++++-------- src/jalview/bin/argparser/ArgValuesMap.java | 17 ++++- src/jalview/util/JalviewJSUtil.java | 9 ++- 3 files changed, 97 insertions(+), 32 deletions(-) diff --git a/src/jalview/bin/argparser/ArgParser.java b/src/jalview/bin/argparser/ArgParser.java index 43082e3..48cbf9c 100644 --- a/src/jalview/bin/argparser/ArgParser.java +++ b/src/jalview/bin/argparser/ArgParser.java @@ -203,6 +203,23 @@ public class ArgParser */ private static boolean ignoreNonStringValues = false; + /** + * flag to say whether to allow the string "false" to be interpreted as a + * boolean negation, e.g., --wrap=false to mean --nowrap + * + * Requires ignoreNonStringValues to be true. Default is false, but set to + * true for JalviewJS so a radio-box could send e.g. wrap=true or wrap=false + */ + private static boolean allowFalseStringValue = false; + + /** + * flag to say whether to always prioritise a positive boolean value (e.g. + * --wrap) when both positive and negative (e.g. --wrap --nowrap) are present. + * This could be useful for JalviewJS if a form sends both a hidden nowrap=x + * and a checkbox wrap=true. + */ + private static boolean prioritisePositiveBooleanValue = false; + protected static final Map argMap; protected Map linkedArgs = new HashMap<>(); @@ -480,6 +497,13 @@ public class ArgParser { if (getIgnoreNonStringValues()) { + // if we're allowing booleanarg=false, check it's not nobooleanarg + // and the val is "false" + if (getAllowFalseStringValue() && !negated && val != null + && val.equalsIgnoreCase("false")) + { + negated = true; + } // delete equals sign and value val = null; arg = arg.substring(0, equalPos); @@ -728,7 +752,6 @@ public class ArgParser else if (a.hasOption(Opt.BOOLEAN)) { setBoolean(linkedId, type, avs, !negated, argIndex); - setNegated(linkedId, avs, negated); } else if (a.hasOption(Opt.UNARY)) { @@ -1087,12 +1110,6 @@ public class ArgParser b, argIndex, false); } - private void setNegated(String linkedId, ArgValues avs, boolean b) - { - this.argValueOperation(Op.SETNEGATED, linkedId, null, avs, null, null, - b, 0, false); - } - private void incrementCount(String linkedId, ArgValues avs) { this.argValueOperation(Op.INCREMENTCOUNT, linkedId, null, avs, null, @@ -1101,7 +1118,7 @@ public class ArgParser private enum Op { - ADDVALUE, SETBOOLEAN, SETNEGATED, INCREMENTCOUNT + ADDVALUE, SETBOOLEAN, INCREMENTCOUNT } private void argValueOperation(Op op, String linkedId, Type type, @@ -1214,21 +1231,22 @@ public class ArgParser break; case SETBOOLEAN: - tavs.setBoolean(type, b, argIndex, true); - finaliseStoringArgValue(id, tavs); - break; - - case SETNEGATED: - tavs.setNegated(b, true); - break; - - case INCREMENTCOUNT: - tavs.incrementCount(); - break; - - default: + if (getPrioritisePositiveBooleanValue() && tavs.getCount() > 0 + && tavs.getBoolean()) + { + Console.debug("Not setting due to prioritisePositiveValue and '" + + a.argString() + "' has already been set to true"); + } + else + { + tavs.setBoolean(type, b, argIndex, true); + if (a.hasOption(Opt.BOOLEAN)) + { + tavs.setNegated(!b, true); + } + finaliseStoringArgValue(id, tavs); + } break; - } } @@ -1260,12 +1278,21 @@ public class ArgParser break; case SETBOOLEAN: - avs.setBoolean(type, b, argIndex, false); - finaliseStoringArgValue(linkedId, avs); - break; - - case SETNEGATED: - avs.setNegated(b, false); + if (getPrioritisePositiveBooleanValue() && avs.getCount() > 0 + && avs.getBoolean()) + { + Console.debug("Not setting due to prioritisePositiveValue and '" + + a.argString() + "' has already been set to true"); + } + else + { + avs.setBoolean(type, b, argIndex, false); + if (a.hasOption(Opt.BOOLEAN)) + { + avs.setNegated(!b, true); + } + finaliseStoringArgValue(linkedId, avs); + } break; case INCREMENTCOUNT: @@ -1317,4 +1344,24 @@ public class ArgParser { ignoreNonStringValues = b; } + + public static boolean getAllowFalseStringValue() + { + return allowFalseStringValue; + } + + public static void setAllowFalseStringValue(boolean b) + { + allowFalseStringValue = b; + } + + public static boolean getPrioritisePositiveBooleanValue() + { + return prioritisePositiveBooleanValue; + } + + public static void setPrioritisePositiveBooleanValue(boolean b) + { + prioritisePositiveBooleanValue = b; + } } \ No newline at end of file diff --git a/src/jalview/bin/argparser/ArgValuesMap.java b/src/jalview/bin/argparser/ArgValuesMap.java index fc1e090..de0dbe0 100644 --- a/src/jalview/bin/argparser/ArgValuesMap.java +++ b/src/jalview/bin/argparser/ArgValuesMap.java @@ -77,9 +77,13 @@ public class ArgValuesMap private void newArg(Arg a) { if (m == null) + { newMap(); + } if (!containsArg(a)) + { m.put(a, new ArgValues(a)); + } } public ArgValues getArgValues(Arg a) @@ -91,7 +95,9 @@ public class ArgValuesMap { ArgValues avs = m.get(a); if (avs == null) + { newArg(a); + } return getArgValues(a); } @@ -117,7 +123,16 @@ public class ArgValuesMap { if (m == null || !m.containsKey(a)) return false; - return a.hasOption(Opt.STRING) ? getArgValue(a) != null : true; + ArgValues av = m.get(a); + if (a.hasOption(Opt.STRING)) + { + return getArgValue(a) != null; + } + if (a.hasOption(Opt.BOOLEAN)) + { + return av.getCount() > 0; + } + return true; } public boolean hasValue(Arg a, String val) diff --git a/src/jalview/util/JalviewJSUtil.java b/src/jalview/util/JalviewJSUtil.java index e176ba7..15bf400 100644 --- a/src/jalview/util/JalviewJSUtil.java +++ b/src/jalview/util/JalviewJSUtil.java @@ -196,6 +196,8 @@ public class JalviewJSUtil if (Platform.isJS()) { ArgParser.setIgnoreNonStringValues(true); + ArgParser.setAllowFalseStringValue(true); + ArgParser.setPrioritisePositiveBooleanValue(true); try { @@ -212,9 +214,10 @@ public class JalviewJSUtil * if a namespace has been given in Info={...}. Use this namespace to * find arguments and values in the querystring parameters. Arguments * that do not take a value do not need to have a value in the - * querystring. If they do they will be ignored. Note, this means you - * cannot do 'debug=false' instead of 'nodebug'. If querystringnamepsace - * is an empty string ("") then no colon (":") will be expected. + * querystring. If they do they will be ignored. With + * allowFalseStringValue set you can have 'debug=false' instead of + * 'nodebug'. If querystringnamepsace is an empty string ("") then no + * colon (":") will be expected. * * if namespace is not defined then use the old style single first * parameter for arguments -- 1.7.10.2