Clover icon

Coverage Report

  1. Project Clover database Thu Dec 4 2025 14:43:25 GMT
  2. Package jalview.util

File Platform.java

 

Coverage histogram

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

Code metrics

140
249
64
2
1,229
707
171
0.69
3.89
32
2.67

Classes

Class Line # Actions
Platform 72 221 154
0.4534313745.3%
Platform.PlatformDependentValue 275 28 17
0.4222222342.2%
 

Contributing tests

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