Clover icon

Coverage Report

  1. Project Clover database Thu Dec 4 2025 16:11:35 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,228
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 845 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  2462054 toggle public static boolean isJS()
208    {
209  2462062 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  5048 toggle public static boolean isAMacAndNotJS()
220    {
221  5048 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  1001 toggle public static boolean isHeadless()
239    {
240  1001 if (isHeadless == null)
241    {
242  21 isHeadless = "true".equals(System.getProperty("java.awt.headless"));
243    }
244  1001 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  97 toggle public static String escapeBackslashes(String s)
406    {
407  97 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  1575 toggle public static byte[] getFileBytes(File f)
600    {
601  1575 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   
 
721  0 toggle public static void setAjaxJSON(URL url)
722    {
723  0 if (isJS())
724    {
725  0 JSON.setAjax(url);
726    }
727    }
728   
 
729  89 toggle public static Object parseJSON(InputStream response)
730    throws IOException, ParseException
731    {
732  89 if (isJS())
733    {
734  0 return JSON.parse(response);
735    }
736   
737  89 BufferedReader br = null;
738  89 try
739    {
740  89 br = new BufferedReader(new InputStreamReader(response, "UTF-8"));
741  89 return new JSONParser().parse(br);
742    } finally
743    {
744  89 if (br != null)
745    {
746  89 try
747    {
748  89 br.close();
749    } catch (IOException e)
750    {
751    // ignore
752    }
753    }
754    }
755    }
756   
 
757  140 toggle public static Object parseJSON(String json) throws ParseException
758    {
759  140 return (isJS() ? JSON.parse(json) : new JSONParser().parse(json));
760    }
761   
 
762  54 toggle public static Object parseJSON(Reader r)
763    throws IOException, ParseException
764    {
765  54 if (r == null)
766    {
767  0 return null;
768    }
769   
770  54 if (!isJS())
771    {
772  54 return new JSONParser().parse(r);
773    }
774    // Using a file reader is not currently supported in SwingJS JavaScript
775   
776  0 if (r instanceof FileReader)
777    {
778  0 throw new IOException(
779    "StringJS does not support FileReader parsing for JSON -- but it could...");
780    }
781  0 return JSON.parse(r);
782   
783    }
784   
785    /**
786    * Dump the input stream to an output file.
787    *
788    * @param is
789    * @param outFile
790    * @throws IOException
791    * if the file cannot be created or there is a problem reading the
792    * input stream.
793    */
 
794  0 toggle public static void streamToFile(InputStream is, File outFile)
795    throws IOException
796    {
797  0 if (isJS)
798    {
799  0 jsutil.setFileBytes(outFile, is);
800  0 return;
801    }
802  0 FileOutputStream fio = new FileOutputStream(outFile);
803  0 try
804    {
805  0 byte[] bb = new byte[32 * 1024];
806  0 int l;
807  0 while ((l = is.read(bb)) > 0)
808    {
809  0 fio.write(bb, 0, l);
810    }
811    } finally
812    {
813  0 fio.close();
814    }
815    }
816   
817    /**
818    * Add a known domain that implements access-control-allow-origin:*
819    *
820    * These should be reviewed periodically.
821    *
822    * @param domain
823    * for a service that is not allowing ajax
824    *
825    * @author hansonr@stolaf.edu
826    *
827    */
 
828  249 toggle public static void addJ2SDirectDatabaseCall(String domain)
829    {
830   
831  249 if (isJS)
832    {
833  0 jsutil.addDirectDatabaseCall(domain);
834  0 jalview.bin.Console.outPrintln(
835    "Platform adding known access-control-allow-origin * for domain "
836    + domain);
837    /**
838    * @j2sNative
839    *
840    * J2S.addDirectDatabaseCall(domain);
841    */
842    }
843   
844    }
845   
846    /**
847    * Allow for URL-line command arguments. Untested.
848    *
849    */
 
850  55 toggle public static void getURLCommandArguments()
851    {
852  55 try
853    {
854    /**
855    * Retrieve the first query field as command arguments to Jalview. Include
856    * only if prior to "?j2s" or "&j2s" or "#". Assign the applet's
857    * __Info.args element to this value.
858    *
859    * @j2sNative var a =
860    * decodeURI((document.location.href.replace("&","?").split("?j2s")[0]
861    * + "?").split("?")[1].split("#")[0]); a &&
862    * (jalview.bin.Console.outPrintln("URL arguments detected were
863    * "+a)) && (J2S.thisApplet.__Info.urlargs = a.split(" "));
864    * (!J2S.thisApplet.__Info.args || J2S.thisApplet.__Info.args
865    * == "" || J2S.thisApplet.__Info.args == "??") &&
866    * (J2S.thisApplet.__Info.args = a) &&
867    * (jalview.bin.Console.outPrintln("URL arguments were passed
868    * 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  932 toggle public static Dimension getDimIfEmbedded(Component frame,
919    int defaultWidth, int defaultHeight)
920    {
921  932 Dimension d = null;
922  932 if (isJS)
923    {
924  0 d = (Dimension) getEmbeddedAttribute(frame, "dim");
925    }
926  932 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  1691 toggle public static Regex newRegex(String searchString, String replaceString)
938    {
939  1691 ensureRegex();
940  1691 return (replaceString == null ? new Regex(searchString)
941    : new Regex(searchString, replaceString));
942    }
943   
 
944  378 toggle public static Regex newRegexPerl(String code)
945    {
946  378 ensureRegex();
947  378 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  2092 toggle public static void ensureRegex()
1012    {
1013  2092 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  574 toggle public static Object getEmbeddedAttribute(Component frame, String type)
1047    {
1048  574 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  613 toggle public static String getAppID(String frameType)
1158    {
1159   
1160  613 String id = Jalview.getInstance().j2sAppletID;
1161  613 if (id == null)
1162    {
1163  54 Jalview.getInstance().j2sAppletID = id = (isJS
1164    ? (String) jsutil.getAppletAttribute("_id")
1165    : "jalview");
1166    }
1167  613 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    }