Clover icon

Coverage Report

  1. Project Clover database Thu Dec 11 2025 10:57:44 GMT
  2. Package jalview.util

File Platform.java

 

Coverage histogram

../../img/srcFileCovDistChart5.png
43% of files have more coverage

Code metrics

138
247
64
2
1,227
703
170
0.69
3.86
32
2.66

Classes

Class Line # Actions
Platform 71 219 153
0.4603960546%
Platform.PlatformDependentValue 274 28 17
0.4222222342.2%
 

Contributing tests

This file is covered by 814 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
7    * Jalview is free software: you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation, either version 3
10    * of the License, or (at your option) any later version.
11    *
12    * Jalview is distributed in the hope that it will be useful, but
13    * WITHOUT ANY WARRANTY; without even the implied warranty
14    * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15    * PURPOSE. See the GNU General Public License for more details.
16    *
17    * You should have received a copy of the GNU General Public License
18    * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19    * The Jalview Authors are detailed in the 'AUTHORS' file.
20    */
21    package jalview.util;
22   
23    import java.awt.Component;
24    import java.awt.Dimension;
25    import java.awt.GraphicsEnvironment;
26    import java.awt.Toolkit;
27    import java.awt.event.KeyEvent;
28    import java.awt.event.MouseEvent;
29    import java.io.BufferedReader;
30    import java.io.File;
31    import java.io.FileOutputStream;
32    import java.io.FileReader;
33    import java.io.IOException;
34    import java.io.InputStream;
35    import java.io.InputStreamReader;
36    import java.io.Reader;
37    import java.lang.reflect.Method;
38    import java.net.URL;
39    import java.nio.channels.Channels;
40    import java.nio.channels.ReadableByteChannel;
41    import java.nio.file.Files;
42    import java.nio.file.Path;
43    import java.nio.file.Paths;
44    import java.nio.file.StandardCopyOption;
45    import java.nio.file.attribute.BasicFileAttributes;
46    import java.util.Date;
47    import java.util.Locale;
48    import java.util.Map;
49    import java.util.Objects;
50    import java.util.Properties;
51    import java.util.logging.ConsoleHandler;
52    import java.util.logging.Level;
53    import java.util.logging.Logger;
54   
55    import javax.swing.SwingUtilities;
56   
57    import org.json.simple.parser.JSONParser;
58    import org.json.simple.parser.ParseException;
59   
60    import com.stevesoft.pat.Regex;
61   
62    import jalview.bin.Jalview;
63    import jalview.javascript.json.JSON;
64    import swingjs.api.JSUtilI;
65   
66    /**
67    * System platform information used by Applet and Application
68    *
69    * @author Jim Procter
70    */
 
71    public class Platform
72    {
73   
74    private static boolean isJS = /** @j2sNative true || */
75    false;
76   
77    private static Boolean isNoJSMac = null, isNoJSWin = null, isMac = null,
78    isWin = null, isLinux = null;
79   
80    private static Boolean isHeadless = null;
81   
82    // If launched from CLI with launcher script then -DCOLUMNWIDTH is set
83    private static final int CONSOLEWIDTH;
84   
85    private static final String CONSOLEWIDTHPROPERTY = "CONSOLEWIDTH";
86   
87    private static swingjs.api.JSUtilI jsutil;
88   
89    /**
90    * added to group mouse events into Windows and nonWindows (mac, unix, linux)
91    *
92    * @return
93    */
 
94  853 toggle public static boolean isMac()
95    {
96  853 return (isMac == null
97    ? (isMac = (System.getProperty("os.name").indexOf("Mac") >= 0))
98    : isMac);
99    }
100   
101    public static int SHORTCUT_KEY_MASK = (Platform.isMac()
102    ? KeyEvent.META_DOWN_MASK
103    : KeyEvent.CTRL_DOWN_MASK);
104   
 
105  55 toggle static
106    {
107  55 int cw = 80;
108  55 if (System.getProperty(CONSOLEWIDTHPROPERTY) != null
109    && System.getProperty(CONSOLEWIDTHPROPERTY).length() > 0)
110    {
111  0 try
112    {
113  0 cw = Integer.parseInt(System.getProperty(CONSOLEWIDTHPROPERTY));
114    } catch (NumberFormatException e)
115    {
116    }
117    }
118  55 CONSOLEWIDTH = cw;
119  55 if (isJS)
120    {
121  0 try
122    {
123    // this is ok - it's a highly embedded method in Java; the deprecation
124    // is
125    // really a recommended best practice.
126  0 jsutil = ((JSUtilI) Class.forName("swingjs.JSUtil").newInstance());
127    } catch (InstantiationException | IllegalAccessException
128    | ClassNotFoundException e)
129    {
130  0 e.printStackTrace();
131    }
132    }
133  55 if (!GraphicsEnvironment.isHeadless())
134    {
135    // Using non-deprecated Extended key mask modifiers, but Java 8 has no
136    // getMenuShortcutKeyMaskEx method
137  19 Toolkit tk = Toolkit.getDefaultToolkit();
138  19 Method method = null;
139  19 try
140    {
141  19 method = tk.getClass().getMethod("getMenuShortcutKeyMaskEx");
142    } catch (Exception e)
143    {
144  0 System.err.println(
145    "Could not find Toolkit method getMenuShortcutKeyMaskEx. Trying getMenuShortcutKeyMask.");
146    }
147  19 if (method == null)
148    {
149  0 try
150    {
151  0 method = tk.getClass().getMethod("getMenuShortcutKeyMask");
152    } catch (Exception e)
153    {
154  0 System.err.println(
155    "Could not find Toolkit method getMenuShortcutKeyMaskEx or getMenuShortcutKeyMask.");
156  0 e.printStackTrace();
157    }
158    }
159  19 if (method != null)
160    {
161  19 try
162    {
163  19 method.setAccessible(true);
164  19 SHORTCUT_KEY_MASK = ((int) method.invoke(tk, new Object[0]));
165    } catch (Exception e)
166    {
167  0 e.printStackTrace();
168    }
169    }
170  19 if (SHORTCUT_KEY_MASK <= 0xF)
171    {
172    // shift this into the extended region (was Java 8)
173  0 SHORTCUT_KEY_MASK = SHORTCUT_KEY_MASK << 6;
174    }
175    }
176    }
177   
178    /**
179    * added to group mouse events into Windows and nonWindows (mac, unix, linux)
180    *
181    * @return
182    */
 
183  22 toggle public static boolean isWin()
184    {
185  22 return (isWin == null
186    ? (isWin = (System.getProperty("os.name").indexOf("Win") >= 0))
187    : isWin);
188    }
189   
190    /**
191    * added to check LaF for Linux
192    *
193    * @return
194    */
 
195  249 toggle public static boolean isLinux()
196    {
197  249 return (isLinux == null
198    ? (isLinux = (System.getProperty("os.name")
199    .indexOf("Linux") >= 0))
200    : isLinux);
201    }
202   
203    /**
204    *
205    * @return true if HTML5 JavaScript
206    */
 
207  2517704 toggle public static boolean isJS()
208    {
209  2517707 return isJS;
210    }
211   
212    /**
213    * sorry folks - Macs really are different
214    *
215    * BH: disabled for SwingJS -- will need to check key-press issues
216    *
217    * @return true if we do things in a special way.
218    */
 
219  4913 toggle public static boolean isAMacAndNotJS()
220    {
221  4913 return (isNoJSMac == null ? (isNoJSMac = !isJS && isMac()) : isNoJSMac);
222    }
223   
224    /**
225    * Check if we are on a Microsoft platform...
226    *
227    * @return true if we have to cope with another platform variation
228    */
 
229  11 toggle public static boolean isWindowsAndNotJS()
230    {
231  11 return (isNoJSWin == null ? (isNoJSWin = !isJS && isWin()) : isNoJSWin);
232    }
233   
234    /**
235    *
236    * @return true if we are running in non-interactive no UI mode
237    */
 
238  1007 toggle public static boolean isHeadless()
239    {
240  1007 if (isHeadless == null)
241    {
242  21 isHeadless = "true".equals(System.getProperty("java.awt.headless"));
243    }
244  1007 return isHeadless;
245    }
246   
247    /**
248    * Construct the value that depends on the system architecture. The methods
249    * setting the value for subsequent platforms are chained after this call and
250    * finalized with a {@link PlatformDependentValue#value() value()} call.
251    *
252    * Example: {@code
253    * Platform.forArch(120).forMac(114).forWin(112).forLinux(115).value();
254    * }
255    *
256    * @param <T>
257    * type of the value
258    * @param defaultValue
259    * default value used if platform not determined
260    * @return platform dependent value wrapper object
261    */
 
262  1 toggle public static <T> PlatformDependentValue<T> forArch(T defaultValue)
263    {
264  1 return new PlatformDependentValue<T>(defaultValue);
265    }
266   
267    /**
268    *
269    * @author mmwarowny
270    *
271    * @param <T>
272    * type of the value
273    */
 
274    public static class PlatformDependentValue<T>
275    {
276    private T defaultValue = null;
277   
278    private T macValue = null;
279   
280    private T winValue = null;
281   
282    private T linuxValue = null;
283   
284    private T jsValue = null;
285   
286    private T headlessValue = null;
287   
 
288  1 toggle private PlatformDependentValue(T value)
289    {
290  1 Objects.requireNonNull(value);
291  1 defaultValue = value;
292    }
293   
294    /**
295    * Set the value used on Mac platform.
296    *
297    * @param value
298    * parameter value
299    * @return
300    */
 
301  0 toggle public PlatformDependentValue<T> forMac(T value)
302    {
303  0 Objects.requireNonNull(value);
304  0 macValue = value;
305  0 return this;
306    }
307   
308    /**
309    * Set the value used on Windows platform.
310    *
311    * @param value
312    * parameter value
313    * @return
314    */
 
315  1 toggle public PlatformDependentValue<T> forWin(T value)
316    {
317  1 Objects.requireNonNull(value);
318  1 winValue = value;
319  1 return this;
320    }
321   
322    /**
323    * Set the value used on Linux platform.
324    *
325    * @param value
326    * parameter value
327    * @return
328    */
 
329  0 toggle public PlatformDependentValue<T> forLinux(T value)
330    {
331  0 Objects.requireNonNull(value);
332  0 linuxValue = value;
333  0 return this;
334    }
335   
336    /**
337    * Set the value used on JS platform.
338    *
339    * @param value
340    * parameter value
341    * @return
342    */
 
343  0 toggle public PlatformDependentValue<T> forJS(T value)
344    {
345  0 Objects.requireNonNull(value);
346  0 jsValue = value;
347  0 return this;
348    }
349   
350    /**
351    * Set the value used on headless platform. The headless value takes
352    * precedence over other platforms if set.
353    *
354    * @param value
355    * parameter value
356    * @return
357    */
 
358  0 toggle public PlatformDependentValue<T> forHeadless(T value)
359    {
360  0 Objects.requireNonNull(value);
361  0 headlessValue = value;
362  0 return this;
363    }
364   
365    /**
366    * Get the value of the parameter respecting the platform. The headless
367    * platform takes precedence over any other platform if it has the value
368    * set.
369    *
370    * @return parameter value depending on the platform
371    */
 
372  1 toggle public T value()
373    {
374  1 if (headlessValue != null && isHeadless())
375  0 return headlessValue;
376  1 if (macValue != null && isMac())
377  0 return macValue;
378  1 if (winValue != null && isWin())
379  0 return winValue;
380  1 if (linuxValue != null && isLinux())
381  0 return linuxValue;
382  1 if (jsValue != null && isJS)
383  0 return jsValue;
384  1 return defaultValue;
385    }
386    }
387   
388    /**
389    *
390    * @return nominal maximum command line length for this platform
391    */
 
392  0 toggle public static int getMaxCommandLineLength()
393    {
394    // TODO: determine nominal limits for most platforms.
395  0 return 2046; // this is the max length for a windows NT system.
396    }
397   
398    /**
399    * Answers the input with every backslash replaced with a double backslash (an
400    * 'escaped' single backslash)
401    *
402    * @param s
403    * @return
404    */
 
405  96 toggle public static String escapeBackslashes(String s)
406    {
407  96 return s == null ? null : s.replace("\\", "\\\\");
408    }
409   
410    /**
411    * Answers true if the mouse event has Meta-down (Command key on Mac) or
412    * Ctrl-down (on other o/s). Note this answers _false_ if the Ctrl key is
413    * pressed instead of the Meta/Cmd key on Mac. To test for Ctrl-pressed on
414    * Mac, you can use e.isPopupTrigger().
415    *
416    * @param e
417    * @return
418    */
 
419  3 toggle public static boolean isControlDown(MouseEvent e)
420    {
421  3 return isControlDown(e, isMac());
422    }
423   
424    /**
425    * Overloaded version of method (to allow unit testing)
426    *
427    * @param e
428    * @param aMac
429    * @return
430    */
 
431  6 toggle protected static boolean isControlDown(MouseEvent e, boolean aMac)
432    {
433    //
434    // System.out.println(e.isPopupTrigger()
435    // + " " + ((SHORTCUT_KEY_MASK & e.getModifiersEx()) != 0)
436    // + " " + e.isControlDown());
437  6 return (aMac
438    ? !e.isPopupTrigger()
439    && (SHORTCUT_KEY_MASK & e.getModifiersEx()) != 0
440    : e.isControlDown());
441    }
442   
443    // BH: I don't know about that previous method. Here is what SwingJS uses.
444    // Notice the distinction in mouse events. (BUTTON3_MASK == META)
445    //
446    // private static boolean isPopupTrigger(int id, int mods, boolean isWin) {
447    // boolean rt = ((mods & InputEvent.BUTTON3_MASK) != 0);
448    // if (isWin) {
449    // if (id != MouseEvent.MOUSE_RELEASED)
450    // return false;
451    ////
452    //// // Oddly, Windows returns InputEvent.META_DOWN_MASK on release, though
453    //// // BUTTON3_DOWN_MASK for pressed. So here we just accept both.
454    ////
455    //// actually, we can use XXX_MASK, not XXX_DOWN_MASK and avoid this issue,
456    // because
457    //// J2S adds the appropriate extended (0x3FC0) and simple (0x3F) modifiers.
458    ////
459    // return rt;
460    // } else {
461    // // mac, linux, unix
462    // if (id != MouseEvent.MOUSE_PRESSED)
463    // return false;
464    // boolean lt = ((mods & InputEvent.BUTTON1_MASK) != 0);
465    // boolean ctrl = ((mods & InputEvent.CTRL_MASK) != 0);
466    // return rt || (ctrl && lt);
467    // }
468    // }
469    //
470   
471    /**
472    * Windows (not Mac, Linux, or Unix) and right button to test for the
473    * right-mouse pressed event in Windows that would have opened a menu or a
474    * Mac.
475    *
476    * @param e
477    * @return
478    */
 
479  3 toggle public static boolean isWinRightButton(MouseEvent e)
480    {
481    // was !isAMac(), but that is true also for Linux and Unix and JS,
482   
483  3 return isWin() && SwingUtilities.isRightMouseButton(e);
484    }
485   
486    /**
487    * Windows (not Mac, Linux, or Unix) and middle button -- for mouse wheeling
488    * without pressing the button.
489    *
490    * @param e
491    * @return
492    */
 
493  0 toggle public static boolean isWinMiddleButton(MouseEvent e)
494    {
495    // was !isAMac(), but that is true also for Linux and Unix and JS
496  0 return isWin() && SwingUtilities.isMiddleMouseButton(e);
497    }
498   
 
499  498 toggle public static boolean allowMnemonics()
500    {
501  498 return !isMac();
502    }
503   
504    public final static int TIME_RESET = 0;
505   
506    public final static int TIME_MARK = 1;
507   
508    public static final int TIME_SET = 2;
509   
510    public static final int TIME_GET = 3;
511   
512    public static long time, mark, set, duration;
513   
514    /**
515    * typical usage:
516    *
517    * Platform.timeCheck(null, Platform.TIME_MARK);
518    *
519    * ...
520    *
521    * Platform.timeCheck("some message", Platform.TIME_MARK);
522    *
523    * reset...[set/mark]n...get
524    *
525    * @param msg
526    * @param mode
527    */
 
528  0 toggle public static void timeCheck(String msg, int mode)
529    {
530  0 long t = System.currentTimeMillis();
531  0 switch (mode)
532    {
533  0 case TIME_RESET:
534  0 time = mark = t;
535  0 duration = 0;
536  0 if (msg != null)
537    {
538  0 jalview.bin.Console.errPrintln("Platform: timer reset\t\t\t" + msg);
539    }
540  0 break;
541  0 case TIME_MARK:
542  0 if (set > 0)
543    {
544    // total time between set/mark points
545  0 duration += (t - set);
546    }
547    else
548    {
549  0 if (time == 0)
550    {
551  0 time = mark = t;
552    }
553  0 if (msg != null)
554    {
555  0 jalview.bin.Console.errPrintln(
556    "Platform: timer mark\t" + ((t - time) / 1000f) + "\t"
557    + ((t - mark) / 1000f) + "\t" + msg);
558    }
559  0 mark = t;
560    }
561  0 break;
562  0 case TIME_SET:
563  0 set = t;
564  0 break;
565  0 case TIME_GET:
566  0 if (msg != null)
567    {
568  0 jalview.bin.Console
569    .errPrintln("Platform: timer dur\t" + ((t - time) / 1000f)
570    + "\t" + ((duration) / 1000f) + "\t" + msg);
571    }
572  0 set = 0;
573  0 break;
574    }
575    }
576   
 
577  0 toggle public static void cacheFileData(String path, Object data)
578    {
579  0 if (isJS && data != null)
580    {
581  0 jsutil.cachePathData(path, data);
582    }
583    }
584   
 
585  0 toggle public static void cacheFileData(File file)
586    {
587  0 if (isJS)
588    {
589  0 byte[] data = Platform.getFileBytes(file);
590    {
591  0 if (data != null)
592    {
593  0 cacheFileData(file.toString(), data);
594    }
595    }
596    }
597    }
598   
 
599  1568 toggle public static byte[] getFileBytes(File f)
600    {
601  1568 return (isJS && f != null ? jsutil.getBytes(f) : null);
602    }
603   
 
604  0 toggle public static byte[] getFileAsBytes(String fileStr)
605    {
606  0 if (isJS && fileStr != null)
607    {
608  0 byte[] bytes = (byte[]) jsutil.getFile(fileStr, false);
609  0 cacheFileData(fileStr, bytes);
610  0 return bytes;
611    }
612  0 return null;
613    }
614   
 
615  0 toggle public static String getFileAsString(String url)
616    {
617  0 if (isJS && url != null)
618    {
619  0 String ret = (String) jsutil.getFile(url, true);
620  0 cacheFileData(url, ret);
621  0 return ret;
622    }
623  0 return null;
624    }
625   
 
626  3 toggle public static boolean setFileBytes(File f, String urlstring)
627    {
628  3 if (isJS && f != null && urlstring != null)
629    {
630  0 @SuppressWarnings("unused")
631    byte[] bytes = getFileAsBytes(urlstring);
632  0 jsutil.setFileBytes(f, bytes);
633  0 return true;
634    }
635  3 return false;
636    }
637   
 
638  4 toggle public static void addJ2SBinaryType(String ext)
639    {
640  4 if (isJS)
641    {
642  0 jsutil.addBinaryFileType(ext);
643    }
644    }
645   
646    /**
647    * Encode the URI using JavaScript encodeURIComponent
648    *
649    * @param value
650    * @return encoded value
651    */
 
652  0 toggle public static String encodeURI(String value)
653    {
654    /**
655    * @j2sNative value = encodeURIComponent(value);
656    */
657  0 return value;
658    }
659   
660    /**
661    * Open the URL using a simple window call if this is JavaScript
662    *
663    * @param url
664    * @return true if window has been opened
665    */
 
666  0 toggle public static boolean openURL(String url) throws IOException
667    {
668  0 if (!isJS)
669    {
670  0 return false;
671    }
672    /**
673    * @j2sNative
674    *
675    *
676    * window.open(url);
677    */
678  0 return true;
679    }
680   
 
681  0 toggle public static String getUniqueAppletID()
682    {
683  0 return (isJS ? (String) jsutil.getAppletAttribute("_uniqueId") : null);
684   
685    }
686   
687    /**
688    * Read the Info block for this applet.
689    *
690    * @param prefix
691    * "jalview_"
692    * @param p
693    * @return unique id for this applet
694    */
 
695  49 toggle public static void readInfoProperties(String prefix, Properties p)
696    {
697  49 if (!isJS)
698    {
699  49 return;
700    }
701  0 String id = getUniqueAppletID();
702  0 String key = "", value = "";
703    /**
704    * @j2sNative var info = swingjs.JSUtil.getApplet$().__Info || {}; for (var
705    * key in info) { if (key.indexOf(prefix) == 0) { value = "" +
706    * info[key];
707    */
708   
709  0 jalview.bin.Console.outPrintln(
710    "Platform id=" + id + " reading Info." + key + " = " + value);
711  0 p.put(id + "_" + key, value);
712   
713    /**
714    * @j2sNative
715    *
716    * } }
717    */
718    }
719   
 
720  0 toggle public static void setAjaxJSON(URL url)
721    {
722  0 if (isJS)
723    {
724  0 JSON.setAjax(url);
725    }
726    }
727   
 
728  89 toggle public static Object parseJSON(InputStream response)
729    throws IOException, ParseException
730    {
731  89 if (isJS)
732    {
733  0 return JSON.parse(response);
734    }
735   
736  89 BufferedReader br = null;
737  89 try
738    {
739  89 br = new BufferedReader(new InputStreamReader(response, "UTF-8"));
740  89 return new JSONParser().parse(br);
741    } finally
742    {
743  89 if (br != null)
744    {
745  89 try
746    {
747  89 br.close();
748    } catch (IOException e)
749    {
750    // ignore
751    }
752    }
753    }
754    }
755   
 
756  140 toggle public static Object parseJSON(String json) throws ParseException
757    {
758  140 return (isJS ? JSON.parse(json) : new JSONParser().parse(json));
759    }
760   
 
761  54 toggle public static Object parseJSON(Reader r)
762    throws IOException, ParseException
763    {
764  54 if (r == null)
765    {
766  0 return null;
767    }
768   
769  54 if (!isJS)
770    {
771  54 return new JSONParser().parse(r);
772    }
773    // Using a file reader is not currently supported in SwingJS JavaScript
774   
775  0 if (r instanceof FileReader)
776    {
777  0 throw new IOException(
778    "StringJS does not support FileReader parsing for JSON -- but it could...");
779    }
780  0 return JSON.parse(r);
781   
782    }
783   
784    /**
785    * Dump the input stream to an output file.
786    *
787    * @param is
788    * @param outFile
789    * @throws IOException
790    * if the file cannot be created or there is a problem reading the
791    * input stream.
792    */
 
793  0 toggle public static void streamToFile(InputStream is, File outFile)
794    throws IOException
795    {
796  0 if (isJS)
797    {
798  0 jsutil.setFileBytes(outFile, is);
799  0 return;
800    }
801  0 FileOutputStream fio = new FileOutputStream(outFile);
802  0 try
803    {
804  0 byte[] bb = new byte[32 * 1024];
805  0 int l;
806  0 while ((l = is.read(bb)) > 0)
807    {
808  0 fio.write(bb, 0, l);
809    }
810    } finally
811    {
812  0 fio.close();
813    }
814    }
815   
816    /**
817    * Add a known domain that implements access-control-allow-origin:*
818    *
819    * These should be reviewed periodically.
820    *
821    * @param domain
822    * for a service that is not allowing ajax
823    *
824    * @author hansonr@stolaf.edu
825    *
826    */
 
827  249 toggle public static void addJ2SDirectDatabaseCall(String domain)
828    {
829   
830  249 if (isJS)
831    {
832  0 jsutil.addDirectDatabaseCall(domain);
833  0 jalview.bin.Console.outPrintln(
834    "Platform adding known access-control-allow-origin * for domain "
835    + domain);
836    /**
837    * @j2sNative
838    *
839    * J2S.addDirectDatabaseCall(domain);
840    */
841    }
842   
843    }
844   
845    /**
846    * Allow for URL-line command arguments. Untested.
847    *
848    */
 
849  55 toggle public static void getURLCommandArguments()
850    {
851  55 try
852    {
853    /**
854    * Retrieve the first query field as command arguments to Jalview. Include
855    * only if prior to "?j2s" or "&j2s" or "#". Assign the applet's
856    * __Info.args element to this value.
857    *
858    * @j2sNative var a =
859    * decodeURI((document.location.href.replace("&","?").split("?j2s")[0]
860    * + "?").split("?")[1].split("#")[0]); a &&
861    * (jalview.bin.Console.outPrintln("URL arguments detected were
862    * "+a)) && (J2S.thisApplet.__Info.urlargs = a.split(" "));
863    * (!J2S.thisApplet.__Info.args || J2S.thisApplet.__Info.args
864    * == "" || J2S.thisApplet.__Info.args == "??") &&
865    * (J2S.thisApplet.__Info.args = a) &&
866    * (jalview.bin.Console.outPrintln("URL arguments were passed
867    * to J2S main."));
868    */
869    } catch (Throwable t)
870    {
871    }
872    }
873   
874    /**
875    * A (case sensitive) file path comparator that ignores the difference between
876    * / and \
877    *
878    * @param path1
879    * @param path2
880    * @return
881    */
 
882  19 toggle public static boolean pathEquals(String path1, String path2)
883    {
884  19 if (path1 == null)
885    {
886  2 return path2 == null;
887    }
888  17 if (path2 == null)
889    {
890  1 return false;
891    }
892  16 String p1 = path1.replace('\\', '/');
893  16 String p2 = path2.replace('\\', '/');
894  16 return p1.equals(p2);
895    }
896   
897    /**
898    * If started on command line using launch script, return the console width
899    */
 
900  0 toggle public static int consoleWidth()
901    {
902  0 return CONSOLEWIDTH;
903    }
904    ///////////// JAL-3253 Applet additions //////////////
905   
906    /**
907    * Retrieve the object's embedded size from a div's style on a page if
908    * embedded in SwingJS.
909    *
910    * @param frame
911    * JFrame or JInternalFrame
912    * @param defaultWidth
913    * use -1 to return null (no default size)
914    * @param defaultHeight
915    * @return the embedded dimensions or null (no default size or not embedded)
916    */
 
917  925 toggle public static Dimension getDimIfEmbedded(Component frame,
918    int defaultWidth, int defaultHeight)
919    {
920  925 Dimension d = null;
921  925 if (isJS)
922    {
923  0 d = (Dimension) getEmbeddedAttribute(frame, "dim");
924    }
925  925 return (d == null && defaultWidth >= 0
926    ? new Dimension(defaultWidth, defaultHeight)
927    : d);
928   
929    }
930   
 
931  85 toggle public static Regex newRegex(String regex)
932    {
933  85 return newRegex(regex, null);
934    }
935   
 
936  1515 toggle public static Regex newRegex(String searchString, String replaceString)
937    {
938  1515 ensureRegex();
939  1515 return (replaceString == null ? new Regex(searchString)
940    : new Regex(searchString, replaceString));
941    }
942   
 
943  318 toggle public static Regex newRegexPerl(String code)
944    {
945  318 ensureRegex();
946  318 return Regex.perlCode(code);
947    }
948   
949    /**
950    * Initialize Java debug logging. A representative sample -- adapt as desired.
951    */
 
952  0 toggle public static void startJavaLogging()
953    {
954    /**
955    * @j2sIgnore
956    */
957    {
958  0 logClass("java.awt.EventDispatchThread", "java.awt.EventQueue",
959    "java.awt.Component", "java.awt.focus.Component",
960    "java.awt.event.Component",
961    "java.awt.focus.DefaultKeyboardFocusManager");
962    }
963    }
964   
965    /**
966    * Initiate Java logging for a given class. Only for Java, not JavaScript;
967    * Allows debugging of complex event processing.
968    *
969    * @param className
970    */
 
971  0 toggle public static void logClass(String... classNames)
972    {
973    /**
974    * @j2sIgnore
975    *
976    *
977    */
978    {
979  0 Logger rootLogger = Logger.getLogger("");
980  0 rootLogger.setLevel(Level.ALL);
981  0 ConsoleHandler consoleHandler = new ConsoleHandler();
982  0 consoleHandler.setLevel(Level.ALL);
983  0 for (int i = classNames.length; --i >= 0;)
984    {
985  0 Logger logger = Logger.getLogger(classNames[i]);
986  0 logger.setLevel(Level.ALL);
987  0 logger.addHandler(consoleHandler);
988    }
989    }
990    }
991   
992    /**
993    * load a resource -- probably a core file -- if and only if a particular
994    * class has not been instantialized. We use a String here because if we used
995    * a .class object, that reference itself would simply load the class, and we
996    * want the core package to include that as well.
997    *
998    * @param resourcePath
999    * @param className
1000    */
 
1001  5 toggle public static void loadStaticResource(String resourcePath,
1002    String className)
1003    {
1004  5 if (isJS)
1005    {
1006  0 jsutil.loadResourceIfClassUnknown(resourcePath, className);
1007    }
1008    }
1009   
 
1010  1854 toggle public static void ensureRegex()
1011    {
1012  1854 if (isJS)
1013    {
1014  0 loadStaticResource("core/core_stevesoft.z.js",
1015    "com.stevesoft.pat.Regex");
1016    }
1017    }
1018   
1019    /**
1020    * Set the "app" property of the HTML5 applet object, for example,
1021    * "testApplet.app", to point to the Jalview instance. This will be the object
1022    * that page developers use that is similar to the original Java applet object
1023    * that was accessed via LiveConnect.
1024    *
1025    * @param j
1026    */
 
1027  0 toggle public static void setAppClass(Object j)
1028    {
1029  0 if (isJS)
1030    {
1031  0 jsutil.setAppClass(j);
1032    }
1033    }
1034   
1035    /**
1036    *
1037    * If this frame is embedded in a web page, return a known type.
1038    *
1039    * @param frame
1040    * a JFrame or JInternalFrame
1041    * @param type
1042    * "name", "node", "init", "dim", or any DOM attribute, such as "id"
1043    * @return null if frame is not embedded.
1044    */
 
1045  569 toggle public static Object getEmbeddedAttribute(Component frame, String type)
1046    {
1047  569 return (isJS ? jsutil.getEmbeddedAttribute(frame, type) : null);
1048    }
1049   
 
1050  0 toggle public static void stackTrace()
1051    {
1052  0 try
1053    {
1054  0 throw new NullPointerException();
1055    } catch (Exception e)
1056    {
1057  0 e.printStackTrace();
1058    }
1059   
1060    }
1061   
 
1062  0 toggle public static URL getDocumentBase()
1063    {
1064  0 return (isJS ? jsutil.getDocumentBase() : null);
1065    }
1066   
 
1067  0 toggle public static URL getCodeBase()
1068    {
1069  0 return (isJS ? jsutil.getCodeBase() : null);
1070    }
1071   
 
1072  204 toggle public static String getUserPath(String subpath)
1073    {
1074  204 char sep = File.separatorChar;
1075  204 return System.getProperty("user.home") + sep
1076    + subpath.replace('/', sep);
1077    }
1078   
1079    /**
1080    * This method enables checking if a cached file has exceeded a certain
1081    * threshold(in days)
1082    *
1083    * @param file
1084    * the cached file
1085    * @param noOfDays
1086    * the threshold in days
1087    * @return
1088    */
 
1089  0 toggle public static boolean isFileOlderThanThreshold(File file, int noOfDays)
1090    {
1091  0 if (isJS)
1092    {
1093    // not meaningful in SwingJS -- this is a session-specific temp file. It
1094    // doesn't have a timestamp.
1095  0 return false;
1096    }
1097  0 Path filePath = file.toPath();
1098  0 BasicFileAttributes attr;
1099  0 int diffInDays = 0;
1100  0 try
1101    {
1102  0 attr = Files.readAttributes(filePath, BasicFileAttributes.class);
1103  0 diffInDays = (int) ((new Date().getTime()
1104    - attr.lastModifiedTime().toMillis())
1105    / (1000 * 60 * 60 * 24));
1106    // System.out.println("Diff in days : " + diffInDays);
1107    } catch (IOException e)
1108    {
1109  0 e.printStackTrace();
1110    }
1111  0 return noOfDays <= diffInDays;
1112    }
1113   
1114    /**
1115    * Get the leading integer part of a string that begins with an integer.
1116    *
1117    * @param input
1118    * - the string input to process
1119    * @param failValue
1120    * - value returned if unsuccessful
1121    * @return
1122    */
 
1123  6 toggle public static int getLeadingIntegerValue(String input, int failValue)
1124    {
1125  6 if (input == null)
1126    {
1127  0 return failValue;
1128    }
1129  6 if (isJS)
1130    {
1131  0 int val = /** @j2sNative 1 ? parseInt(input) : */
1132    0;
1133  0 return (val == val + 0 ? val : failValue);
1134    }
1135    // JavaScript does not support Regex ? lookahead
1136  6 String[] parts = input.split("(?=\\D)(?<=\\d)");
1137  6 if (parts != null && parts.length > 0 && parts[0].matches("[0-9]+"))
1138    {
1139  2 return Integer.valueOf(parts[0]);
1140    }
1141  4 return failValue;
1142    }
1143   
 
1144  0 toggle public static Map<String, Object> getAppletInfoAsMap()
1145    {
1146  0 return (isJS ? jsutil.getAppletInfoAsMap() : null);
1147    }
1148   
1149    /**
1150    * Get the SwingJS applet ID and combine that with the frameType
1151    *
1152    * @param frameType
1153    * "alignment", "desktop", etc., or null
1154    * @return
1155    */
 
1156  613 toggle public static String getAppID(String frameType)
1157    {
1158   
1159  613 String id = Jalview.getInstance().j2sAppletID;
1160  613 if (id == null)
1161    {
1162  54 Jalview.getInstance().j2sAppletID = id = (isJS
1163    ? (String) jsutil.getAppletAttribute("_id")
1164    : "jalview");
1165    }
1166  613 return id + (frameType == null ? "" : "-" + frameType);
1167    }
1168   
1169    /**
1170    * Option to avoid unnecessary seeking of nonexistent resources in JavaScript.
1171    * Works in Java as well.
1172    *
1173    * @param loc
1174    * @return
1175    */
 
1176  54 toggle public static Locale getLocaleOrNone(Locale loc)
1177    {
1178  54 return (isJS && loc.getLanguage() == "en" ? new Locale("") : loc);
1179    }
1180   
1181    /**
1182    * From UrlDownloadClient; trivial in JavaScript; painful in Java.
1183    *
1184    * @param urlstring
1185    * @param outfile
1186    * @throws IOException
1187    */
 
1188  14 toggle public static void download(String urlstring, String outfile)
1189    throws IOException
1190    {
1191  14 Path temp = null;
1192  14 try (InputStream is = new URL(urlstring).openStream())
1193    {
1194  10 if (isJS)
1195    { // so much easier!
1196  0 streamToFile(is, new File(outfile));
1197  0 return;
1198    }
1199  10 temp = Files.createTempFile(".jalview_", ".tmp");
1200  10 try (FileOutputStream fos = new FileOutputStream(temp.toString());
1201  10 ReadableByteChannel rbc = Channels.newChannel(is))
1202    {
1203  10 fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
1204    // copy tempfile to outfile once our download completes
1205    // incase something goes wrong
1206  10 Files.copy(temp, Paths.get(outfile),
1207    StandardCopyOption.REPLACE_EXISTING);
1208    }
1209    } catch (IOException e)
1210    {
1211  4 throw e;
1212    } finally
1213    {
1214  14 try
1215    {
1216  14 if (temp != null)
1217    {
1218  10 Files.deleteIfExists(temp);
1219    }
1220    } catch (IOException e)
1221    {
1222  0 System.out.println("Exception while deleting download temp file: "
1223    + e.getMessage());
1224    }
1225    }
1226    }
1227    }