JAL-4059 Allow form-created querystring style values for boolean values
authorBen Soares <b.soares@dundee.ac.uk>
Fri, 24 Nov 2023 15:40:05 +0000 (15:40 +0000)
committerBen Soares <b.soares@dundee.ac.uk>
Fri, 24 Nov 2023 15:40:05 +0000 (15:40 +0000)
src/jalview/bin/argparser/ArgParser.java
src/jalview/bin/argparser/ArgValuesMap.java
src/jalview/util/JalviewJSUtil.java

index 43082e3..48cbf9c 100644 (file)
@@ -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<String, Arg> argMap;
 
   protected Map<String, ArgValuesMap> 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
index fc1e090..de0dbe0 100644 (file)
@@ -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)
index e176ba7..15bf400 100644 (file)
@@ -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