/*
* Open Source Physics software is free software as described near the bottom of this code file.
*
* For additional information and documentation on Open Source Physics please see:
* <http://www.opensourcephysics.org/>
*/
package org.opensourcephysics.display;
import java.awt.Component;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Locale;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import javax.swing.JApplet;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.LookAndFeel;
import javax.swing.UIManager;
import javax.swing.plaf.metal.MetalLookAndFeel;
import org.opensourcephysics.controls.OSPLog;
import org.opensourcephysics.controls.XML;
import org.opensourcephysics.controls.XMLControl;
import org.opensourcephysics.controls.XMLControlElement;
import org.opensourcephysics.tools.FontSizer;
import org.opensourcephysics.tools.ResourceLoader;
import org.opensourcephysics.tools.Translator;
/**
* This class defines static methods related to the runtime environment.
*
* @author Douglas Brown
* @author Wolfgang Christian
* @version 1.0
*/
public class OSPRuntime {
static String version = "2.3"; //$NON-NLS-1$
static String releaseDate = "1 Jan 2015"; //$NON-NLS-1$
/** Disables drawing for faster start-up and to avoid screen flash in Drawing Panels. */
volatile public static boolean disableAllDrawing = false;
/** Load Video Tool, if available. */
public static boolean loadVideoTool = true;
/** Load Export Tool, if available. */
public static boolean loadExportTool = true;
/** Load Data Tool, if available. */
public static boolean loadDataTool = true;
/** Load Fourier Tool, if available. */
public static boolean loadFourierTool = true;
/** Load Translator Tool, if available. */
public static boolean loadTranslatorTool = true;
/** Load OSP Log, if available. */
public static boolean loadOSPLog = true;
/** Shared Translator after loading, if available. */
private static Translator translator; // shared Translator
/** Array of default OSP Locales. */
public static Locale[] defaultLocales = new Locale[] {Locale.ENGLISH, new Locale("es"), new Locale("de"), //$NON-NLS-1$ //$NON-NLS-2$
new Locale("da"), new Locale("sk"), Locale.TAIWAN}; //$NON-NLS-1$ //$NON-NLS-2$
/** Set <I>true</I> if a program is being run within Launcher. */
protected static boolean launcherMode = false;
/** True if text components should try and anti-alias text. */
public static Boolean antiAliasText = false;
/** True if running as an applet. */
public static boolean appletMode;
/** Static reference to an applet for document/code base access. */
public static JApplet applet;
/** True if launched by WebStart. */
public static boolean webStart;
/** True if launched by WebStart. */
// public static boolean J3D;
/** True if users allowed to author internal parameters such as Locale strings. */
protected static boolean authorMode = true;
/** Path of the launch jar, if any. */
static private String launchJarPath;
/** Path of the launch jar, if any. */
static private String launchJarName;
/** The launch jar, if any. */
static private JarFile launchJar = null;
/** Build date of the launch jar, if known. */
static private String buildDate;
/** File Chooser starting directory. */
public static String chooserDir;
/** User home directory. */
public static String userhomeDir;
/** Location of OSP icon. */
public static final String OSP_ICON_FILE = "/org/opensourcephysics/resources/controls/images/osp_icon.gif"; //$NON-NLS-1$
/** True if always launching in single vm (applet mode, etc). */
public static boolean launchingInSingleVM;
// look and feel types
@SuppressWarnings("javadoc")
public final static String CROSS_PLATFORM_LF = "CROSS_PLATFORM"; //$NON-NLS-1$
@SuppressWarnings("javadoc")
public final static String NIMBUS_LF = "NIMBUS"; //$NON-NLS-1$
@SuppressWarnings("javadoc")
public final static String SYSTEM_LF = "SYSTEM"; //$NON-NLS-1$
@SuppressWarnings("javadoc")
public final static String METAL_LF = "METAL"; //$NON-NLS-1$
@SuppressWarnings("javadoc")
public final static String GTK_LF = "GTK"; //$NON-NLS-1$
@SuppressWarnings("javadoc")
public final static String MOTIF_LF = "MOTIF"; //$NON-NLS-1$
@SuppressWarnings("javadoc")
public final static String WINDOWS_LF = "WINDOWS"; //$NON-NLS-1$
@SuppressWarnings("javadoc")
public final static String DEFAULT_LF = "DEFAULT"; //$NON-NLS-1$
@SuppressWarnings("javadoc")
public final static LookAndFeel DEFAULT_LOOK_AND_FEEL = UIManager.getLookAndFeel(); // save the default before we change LnF
@SuppressWarnings("javadoc")
public final static boolean DEFAULT_LOOK_AND_FEEL_DECORATIONS = JFrame.isDefaultLookAndFeelDecorated();
@SuppressWarnings("javadoc")
public final static HashMap<String, String> LOOK_AND_FEEL_TYPES = new HashMap<String, String>();
/** Preferences XML control */
private static XMLControl prefsControl;
/** Preferences path */
private static String prefsPath;
/** Preferences filename */
private static String prefsFileName = "osp.prefs"; //$NON-NLS-1$
/**
* Sets default properties for OSP.
*/
static {
try { // set the user home and default directory for the chooser // system properties may not be readable in some contexts
OSPRuntime.chooserDir = System.getProperty("user.dir", null); //$NON-NLS-1$
String userhome = System.getProperty("user.home"); //$NON-NLS-1$
if (userhome!=null) {
userhomeDir = XML.forwardSlash(userhome);
}
} catch(Exception ex) {
OSPRuntime.chooserDir = null;
}
// fill the look and feel map
LOOK_AND_FEEL_TYPES.put(METAL_LF, "javax.swing.plaf.metal.MetalLookAndFeel"); //$NON-NLS-1$
LOOK_AND_FEEL_TYPES.put(NIMBUS_LF, "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"); //$NON-NLS-1$
LOOK_AND_FEEL_TYPES.put(GTK_LF, "com.sun.java.swing.plaf.gtk.GTKLookAndFeel"); //$NON-NLS-1$
LOOK_AND_FEEL_TYPES.put(MOTIF_LF, "com.sun.java.swing.plaf.motif.MotifLookAndFeel"); //$NON-NLS-1$
LOOK_AND_FEEL_TYPES.put(WINDOWS_LF, "com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); //$NON-NLS-1$
LOOK_AND_FEEL_TYPES.put(CROSS_PLATFORM_LF, UIManager.getCrossPlatformLookAndFeelClassName());
LOOK_AND_FEEL_TYPES.put(SYSTEM_LF, UIManager.getSystemLookAndFeelClassName());
LOOK_AND_FEEL_TYPES.put(DEFAULT_LF, DEFAULT_LOOK_AND_FEEL.getClass().getName());
// try {
// Class.forName("com.sun.j3d.utils.universe.SimpleUniverse"); //$NON-NLS-1$
// J3D= true;
// } catch (NoClassDefFoundError e) { // Do not complain
// J3D= false;
// } catch (ClassNotFoundException e) {
// J3D= false;
// }
}
/**
* Private constructor to prevent instantiation.
*/
private OSPRuntime() {
/** empty block */
}
/**
* Shows the about dialog.
* @param parent
*/
public static void showAboutDialog(Component parent) {
String date = OSPRuntime.getLaunchJarBuildDate();
if (date==null) date = releaseDate;
String aboutString = "OSP Library "+version+" released "+date+"\n" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+"Open Source Physics Project \n"+"www.opensourcephysics.org"; //$NON-NLS-1$ //$NON-NLS-2$
JOptionPane.showMessageDialog(parent, aboutString, "About Open Source Physics", JOptionPane.INFORMATION_MESSAGE); //$NON-NLS-1$
}
/**
* Sets the look and feel of the user interface. Look and feel user interfaces are:
*
* NIMBUS_LF: com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel
* METAL_LF: javax.swing.plaf.metal.MetalLookAndFeel
* GTK_LF: com.sun.java.swing.plaf.gtk.GTKLookAndFeel
* MOTIF_LF: com.sun.java.swing.plaf.motif.MotifLookAndFeel
* WINDOWS_LF: com.sun.java.swing.plaf.windows.WindowsLookAndFeel
* DEFAULT_LF: the default look and feel in effect when this class was loaded
* CROSS_PLATFORM_LF: the cross platform look and feel; usually METAL_LF
* SYSTEM_LF: the operating system look and feel
*
* @param useDefaultLnFDecorations
* @param lookAndFeel
*
* @return true if successful
*/
public static boolean setLookAndFeel(boolean useDefaultLnFDecorations, String lookAndFeel) {
boolean found = true;
LookAndFeel currentLookAndFeel = UIManager.getLookAndFeel();
try {
if((lookAndFeel==null)||lookAndFeel.equals(DEFAULT_LF)) {
UIManager.setLookAndFeel(DEFAULT_LOOK_AND_FEEL);
useDefaultLnFDecorations = DEFAULT_LOOK_AND_FEEL_DECORATIONS;
} else if(lookAndFeel.equals(CROSS_PLATFORM_LF)) {
lookAndFeel = UIManager.getCrossPlatformLookAndFeelClassName();
UIManager.setLookAndFeel(lookAndFeel);
} else if(lookAndFeel.equals(SYSTEM_LF)) {
lookAndFeel = UIManager.getSystemLookAndFeelClassName();
UIManager.setLookAndFeel(lookAndFeel);
} else if(lookAndFeel.equals(NIMBUS_LF)) {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"); //$NON-NLS-1$
} else if(lookAndFeel.equals(METAL_LF)) {
// MetalLookAndFeel.setCurrentTheme(new DefaultMetalTheme());
UIManager.setLookAndFeel(new MetalLookAndFeel());
} else if(lookAndFeel.equals(GTK_LF)) {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel"); //$NON-NLS-1$
} else if(lookAndFeel.equals(MOTIF_LF)) {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel"); //$NON-NLS-1$
} else if(lookAndFeel.equals(WINDOWS_LF)) {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); //$NON-NLS-1$
} else {
UIManager.setLookAndFeel(lookAndFeel); // LnF can be set using a fully qualified path
}
JFrame.setDefaultLookAndFeelDecorated(useDefaultLnFDecorations);
JDialog.setDefaultLookAndFeelDecorated(useDefaultLnFDecorations);
} catch(Exception ex) {
found = false;
}
if(!found) { // keep current look and feel
try {
UIManager.setLookAndFeel(currentLookAndFeel);
} catch(Exception e) {}
}
return found;
}
/**
* Returns true if newly created <code>JFrame</code>s or <code>JDialog</code>s should have their
* Window decorations provided by the current look and feel. This is only
* a hint, as certain look and feels may not support this feature.
*
* @return true if look and feel should provide Window decorations.
* @since 1.4
*/
public static boolean isDefaultLookAndFeelDecorated() {
return JFrame.isDefaultLookAndFeelDecorated();
}
/**
* Determines if OS is Windows
*
* @return true if Windows
*/
public static boolean isWindows() {
try { // system properties may not be readable in some environments
return(System.getProperty("os.name", "").toLowerCase().startsWith("windows")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
} catch(SecurityException ex) {
return false;
}
}
/**
* Determines if OS is Mac
*
* @return true if Mac
*/
public static boolean isMac() {
try { // system properties may not be readable in some environments
return(System.getProperty("os.name", "").toLowerCase().startsWith("mac")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
} catch(SecurityException ex) {
return false;
}
}
/**
* Determines if OS is Linux
*
* @return true if Linux
*/
public static boolean isLinux() {
try { // system properties may not be readable in some environments
return(System.getProperty("os.name", "").toLowerCase().startsWith("linux")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
} catch(SecurityException ex) {
return false;
}
}
/**
* Determines if OS is Vista
*
* @return true if Vista
*/
static public boolean isVista() {
if(System.getProperty("os.name", "").toLowerCase().indexOf("vista")>-1) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
return true;
}
return false;
}
static public boolean hasJava3D() {
try{
if (OSPRuntime.isMac()) { // extra testing for Mac
boolean tryIt=true;
String home = System.getProperty("java.home");//$NON-NLS-1$
String version = System.getProperty("java.version"); //$NON-NLS-1$
if (version.indexOf("1.7")<0 && version.indexOf("1.8")<0) tryIt = true; //$NON-NLS-1$ //$NON-NLS-2$
else tryIt = (new java.io.File(home+"/lib/ext/j3dcore.jar")).exists(); //$NON-NLS-1$
if (!tryIt) return false;
}
} catch (Exception exc) { return false; } // Any problem! Do not complain and quit
// look for J3D class
try {
Class.forName("com.sun.j3d.utils.universe.SimpleUniverse"); //$NON-NLS-1$
return true;
} catch (Error e) { // do not not complain
return false;
}
catch (Exception e) { // do not not complain
return false;
}
}
/**
* Determines if Quick Time for Java has been installed by looking for QTJava.zip in java extensions folder.
*
* @return true if QTJava found; false otherwise
*/
static public boolean hasQTJava() {
// look for QTJava.zip in java extensions folder
String extdir = System.getProperty("java.ext.dirs"); //$NON-NLS-1$
// look in first directory listed (before path separator, if any)
String separator = System.getProperty("path.separator"); //$NON-NLS-1$
if(extdir.indexOf(separator)>-1) {
extdir = extdir.substring(0, extdir.indexOf(separator));
}
String slash = System.getProperty("file.separator", "/"); //$NON-NLS-1$ //$NON-NLS-2$
File extfile = new File(extdir+slash+"QTJava.zip"); //$NON-NLS-1$
return extfile.exists();
}
/**
* Determines if an InputEvent is a popup trigger.
* @param e the input event
* @return true if event is a popup trigger
*/
static public boolean isPopupTrigger(InputEvent e) {
if(e instanceof MouseEvent) {
MouseEvent me = (MouseEvent) e;
if (me.isShiftDown()) return false;
return (me.isPopupTrigger())
||(me.getButton()==MouseEvent.BUTTON3)
||(me.isControlDown()&&isMac());
}
return false;
}
/**
* Determines if launched by WebStart
*
* @return true if launched by WebStart
*/
public static boolean isWebStart() {
if(!webStart) {
try {
webStart = System.getProperty("javawebstart.version")!=null; //$NON-NLS-1$
// once true, remains true
} catch(Exception ex) {
}
}
return webStart;
}
/**
* Determines if running as an applet
*
* @return true if running as an applet
*/
public static boolean isAppletMode() {
return appletMode;
}
/**
* Determines if running in author mode
*
* @return true if running in author mode
*/
public static boolean isAuthorMode() {
return authorMode;
}
/**
* Sets the authorMode property.
* AuthorMode allows users to author internal parameters such as Locale strings.
*
* @param b boolean
*/
public static void setAuthorMode(boolean b) {
authorMode = b;
}
/**
* Sets the launcherMode property to true if applications in this VM are launched by Launcher.
* LauncherMode disables access to properties, such as Locale, that affect the VM.
*
* @param b boolean
*/
public static void setLauncherMode(boolean b) {
launcherMode = b;
}
/**
* Gets the launcherMode property. Returns true if applications in this VM are launched by Launcher.
* LauncherMode disables access to properties, such as Locale, that affect the VM.
*
* @return boolean
*/
public static boolean isLauncherMode() {
return launcherMode || "true".equals(System.getProperty("org.osp.launcher")); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* Sets the launch jar path.
* @param path the path
*/
public static void setLaunchJarPath(String path) {
if((path==null)||(launchJarPath!=null)) {
return;
}
// make sure the path ends with or contains a jar file
if(!path.endsWith(".jar")&&!path.endsWith(".exe")) { //$NON-NLS-1$ //$NON-NLS-2$
int n = path.indexOf(".jar!"); //$NON-NLS-1$
if(n==-1) {
n = path.indexOf(".exe!"); //$NON-NLS-1$
}
if(n>-1) {
path = path.substring(0, n+4);
} else {
return;
}
}
launchJarPath = path;
launchJarName = path.substring(path.lastIndexOf("/")+1); //$NON-NLS-1$
}
/**
* Gets the launch jar name, if any.
* @return launch jar path, or null if not launched from a jar
*/
public static String getLaunchJarName() {
return launchJarName;
}
/**
* Gets the launch jar path, if any.
* @return launch jar path, or null if not launched from a jar
*/
public static String getLaunchJarPath() {
return launchJarPath;
}
/**
* Gets the launch jar directory, if any.
* @return path to the directory containing the launch jar. May be null.
*/
public static String getLaunchJarDirectory() {
if(applet!=null) {
return null;
}
return(launchJarPath==null) ? null : XML.getDirectoryPath(launchJarPath);
}
/**
* Gets the jar from which the progam was launched.
* @return JarFile
*/
public static JarFile getLaunchJar() {
if(launchJar!=null) {
return launchJar;
}
if(launchJarPath==null) {
return null;
}
boolean isWebFile = launchJarPath.startsWith("http:"); //$NON-NLS-1$
if (!isWebFile) {
launchJarPath = ResourceLoader.getNonURIPath(launchJarPath);
}
try {
if((OSPRuntime.applet==null)&&!isWebFile) { // application mode
launchJar = new JarFile(launchJarPath);
} else { // applet mode
URL url;
if(isWebFile) {
// create a URL that refers to a jar file on the web
url = new URL("jar:"+launchJarPath+"!/"); //$NON-NLS-1$ //$NON-NLS-2$
} else {
// create a URL that refers to a local jar file
url = new URL("jar:file:/"+launchJarPath+"!/"); //$NON-NLS-1$ //$NON-NLS-2$
}
// get the jar
JarURLConnection conn = (JarURLConnection) url.openConnection();
launchJar = conn.getJarFile();
}
} catch(Exception ex) {
//ex.printStackTrace();
OSPLog.fine(ex.getMessage());
}
return launchJar;
}
/**
* Gets the launch jar build date.
* @return the build date, or null if not launched from a jar or date not known
*/
public static String getLaunchJarBuildDate() {
if (buildDate==null) {
try {
JarFile jarfile = getLaunchJar();
java.util.jar.Attributes att = jarfile.getManifest().getMainAttributes();
buildDate = att.getValue("Build-Date"); //$NON-NLS-1$
} catch (Exception ex) {}
}
return buildDate;
}
/**
* Gets the java executable file for a given jre path. May return null.
*
* @param jrePath the path to a java jre or jdk VM
* @return the Java executable
*/
public static File getJavaFile(String jrePath) {
if (jrePath==null) return null;
File file = new File(jrePath);
jrePath = XML.forwardSlash(jrePath);
if (jrePath.endsWith("/lib/ext")) { //$NON-NLS-1$
jrePath = jrePath.substring(0, jrePath.length()-8);
file = new File(jrePath);
}
if (!jrePath.endsWith("/bin/java") && !jrePath.endsWith("/bin/java.exe")) { //$NON-NLS-1$ //$NON-NLS-2$
if (jrePath.endsWith("/bin")) { //$NON-NLS-1$
file = file.getParentFile();
}
if (OSPRuntime.isWindows()) {
// typical jdk: Program Files\Java\jdkX.X.X_XX\jre\bin\java.exe
// typical jre: Program Files\Java\jreX.X.X_XX\bin\java.exe
// or Program Files\Java\jreX\bin\java.exe
// typical 32-bit jdk in 64-bit Windows: Program Files(x86)\Java\jdkX.X.X_XX\jre\bin\java.exe
if (file.getParentFile()!=null
&& file.getParentFile().getName().indexOf("jre")>-1) { //$NON-NLS-1$
file = file.getParentFile();
}
if (file.getParentFile()!=null
&& file.getParentFile().getName().indexOf("jdk")>-1) { //$NON-NLS-1$
file = file.getParentFile();
}
if (file.getName().indexOf("jdk")>-1) //$NON-NLS-1$
file = new File(file, "jre/bin/java.exe"); //$NON-NLS-1$
else if (file.getName().indexOf("jre")>-1) { //$NON-NLS-1$
file = new File(file, "bin/java.exe"); //$NON-NLS-1$
}
else file = null;
}
else if (OSPRuntime.isMac()) {
// typical: /System/Library/Java/JavaVirtualMachines/X.X.X.jdk/Contents/Home/bin/java
// symlink at: /Library/Java/Home/bin/java
// see also /Library/Java/JavaVirtualMachines?
if (file.getName().endsWith("jdk")) //$NON-NLS-1$
file = new File(file, "Contents/Home/bin/java"); //$NON-NLS-1$
else if (file.getName().equals("Home") //$NON-NLS-1$
&& file.getPath().indexOf("/Java")>-1) { //$NON-NLS-1$
file = new File(file, "bin/java"); //$NON-NLS-1$
}
else file = null;
}
else if (OSPRuntime.isLinux()) {
// typical: /usr/lib/jvm/java-X-openjdk/jre/bin/java
// symlink at: /usr/lib/jvm/java-X.X.X-openjdk/jre/bin/java
// sun versions: java-X-sun and java-X.X.X-sun
if (file.getParentFile()!=null
&& file.getParentFile().getName().indexOf("jre")>-1) { //$NON-NLS-1$
file = file.getParentFile();
}
if (file.getParentFile()!=null
&& file.getParentFile().getName().indexOf("jdk")>-1) { //$NON-NLS-1$
file = file.getParentFile();
}
if (file.getParentFile()!=null
&& file.getParentFile().getName().indexOf("sun")>-1) { //$NON-NLS-1$
file = file.getParentFile();
}
if (file.getName().indexOf("jdk")>-1 //$NON-NLS-1$
|| file.getName().indexOf("sun")>-1) //$NON-NLS-1$
file = new File(file, "jre/bin/java"); //$NON-NLS-1$
else file = null;
}
}
// resolve symlinks to their targets
if (file!=null) {
try {
file = file.getCanonicalFile();
} catch (IOException e) {
file = null;
}
}
if (file!=null && file.exists()) return file;
return null;
}
/**
* Gets the bitness of the current Java VM. Note this identifies only
* 32- and 64-bit VMs as of Jan 2011.
*
* @return 64 if 64-bit VM, otherwise 32
*/
public static int getVMBitness() {
String s = System.getProperty("java.vm.name"); //$NON-NLS-1$
s += "-"+System.getProperty("os.arch"); //$NON-NLS-1$ //$NON-NLS-2$
s += "-"+System.getProperty("sun.arch.data.model"); //$NON-NLS-1$ //$NON-NLS-2$
return s.indexOf("64")>-1? 64: 32; //$NON-NLS-1$
}
/**
* Gets the java VM path for a given Java executable file.
*
* @param javaFile the Java executable file
* @return the VM path
*/
public static String getJREPath(File javaFile) {
if (javaFile==null) return null;
String javaPath = XML.forwardSlash(javaFile.getAbsolutePath());
// all java command files should end with /bin/java or /bin/java.exe
if (XML.stripExtension(javaPath).endsWith("/bin/java")) //$NON-NLS-1$
return javaFile.getParentFile().getParent();
return ""; //$NON-NLS-1$
}
/**
* Gets Locales for languages that have properties files in the core library.
* @return Locale[]
*/
public static Locale[] getDefaultLocales() {
return defaultLocales;
}
/**
* Gets Locales for languages that have properties files in the core library.
* Locales are returned with english first, then in alphabetical order.
* @return Locale[]
*/
public static Locale[] getInstalledLocales() {
ArrayList<Locale> list = new ArrayList<Locale>();
java.util.TreeMap<String, Locale> languages = new java.util.TreeMap<String, Locale>();
list.add(Locale.ENGLISH); // english is first in list
if(getLaunchJarPath()!=null) {
// find available locales
JarFile jar = getLaunchJar();
if(jar!=null) {
for(Enumeration<?> e = jar.entries(); e.hasMoreElements(); ) {
JarEntry entry = (JarEntry) e.nextElement();
String path = entry.toString();
int n = path.indexOf(".properties"); //$NON-NLS-1$
if(path.indexOf(".properties")>-1) { //$NON-NLS-1$
int m = path.indexOf("display_res_"); //$NON-NLS-1$
if(m>-1) {
String loc = path.substring(m+12, n);
if(loc.equals("zh_TW")) { //$NON-NLS-1$
Locale next = Locale.TAIWAN;
languages.put(getDisplayLanguage(next).toLowerCase(), next);
}
else if(loc.equals("zh_CN")) { //$NON-NLS-1$
Locale next = Locale.CHINA;
languages.put(getDisplayLanguage(next).toLowerCase(), next);
}
else if(loc.equals("en_US")) { //$NON-NLS-1$
continue;
}
else {
Locale next;
if (!loc.contains("_")) next = new Locale(loc); //$NON-NLS-1$
else {
String lang = loc.substring(0, 2);
String country = loc.substring(3);
next = new Locale(lang, country, ""); //$NON-NLS-1$
}
if (!next.equals(Locale.ENGLISH)) {
languages.put(getDisplayLanguage(next).toLowerCase(), next);
}
}
}
}
}
for(String s : languages.keySet()) {
list.add(languages.get(s));
}
} else {
defaultLocales = new Locale[] {Locale.ENGLISH};
return defaultLocales;
}
}
return list.toArray(new Locale[0]);
}
/**
* Gets the display language for a given Locale. This returns the language name
* in the locale's own language, but substitutes the equivalent of
* SIMPLIFIED_CHINESE and TRADITIONAL_CHINESE for those locales.
* @param locale the Locale
* @return the display language
*/
public static String getDisplayLanguage(Locale locale) {
if (locale.equals(Locale.CHINA))
return "\u7b80\u4f53\u4e2d\u6587"; //$NON-NLS-1$
if (locale.equals(Locale.TAIWAN))
return "\u7e41\u4f53\u4e2d\u6587"; //$NON-NLS-1$
return locale.getDisplayLanguage(locale);
}
/**
* Gets the default search paths, typically used for autoloading.
* Search paths are platform-specific "appdata", user home and code base, in that order.
*
* @return the default search paths
*/
public static ArrayList<String> getDefaultSearchPaths() {
ArrayList<String> paths = new ArrayList<String>();
if (isWindows()) {
String appdata = System.getenv("LOCALAPPDATA"); //$NON-NLS-1$
if (appdata!=null) {
File dir = new File(appdata, "OSP"); //$NON-NLS-1$
if (!dir.exists()) dir.mkdir();
if (dir.exists()) {
paths.add(XML.forwardSlash(dir.getAbsolutePath()));
}
}
}
else if (userhomeDir!=null && isMac()) {
File dir = new File(userhomeDir, "Library/Application Support"); //$NON-NLS-1$
if (dir.exists()) {
dir = new File(dir, "OSP"); //$NON-NLS-1$
if (!dir.exists()) dir.mkdir();
if (dir.exists()) {
paths.add(XML.forwardSlash(dir.getAbsolutePath()));
}
}
}
else if (userhomeDir!=null && isLinux()) {
File dir = new File(userhomeDir, ".config"); //$NON-NLS-1$
if (dir.exists()) {
dir = new File(dir, "OSP"); //$NON-NLS-1$
if (!dir.exists()) dir.mkdir();
if (dir.exists()) {
paths.add(XML.forwardSlash(dir.getAbsolutePath()));
}
}
}
if (userhomeDir!=null) {
paths.add(userhomeDir);
}
String codebase = OSPRuntime.getLaunchJarDirectory();
if (codebase!=null) {
paths.add(XML.forwardSlash(codebase));
}
return paths;
}
/**
* Gets a named preference object. The object must be cast to the correct type
* by the user.
*
* @param name the name of the preference
* @return the object (may be null)
*/
public static Object getPreference(String name) {
XMLControl control = getPrefsControl();
return control.getObject(name);
}
/**
* Sets a named preference object. The object can be anything storable
* in an XMLControl--eg, String, Collection, OSP object, Boolean, Double, Integer
*
* @param name the name of the preference
* @param pref the object (may be null)
*/
public static void setPreference(String name, Object pref) {
XMLControl control = getPrefsControl();
control.setValue(name, pref);
}
/**
* Saves the current preference XMLControl by writing to a file.
*/
public static void savePreferences() {
XMLControl control = getPrefsControl();
File file = new File(prefsPath, prefsFileName);
control.write(file.getAbsolutePath());
}
/**
* Gets the preferences XML file if it exists.
*
* @return the file, or null if none exists
*/
public static File getPreferencesFile() {
getPrefsControl(); // ensures the prefs path is defined and writes file if needed
File file = new File(prefsPath, prefsFileName);
if (file.exists()) return file;
return null;
}
/**
* Gets the preference XMLControl. This will load the control
* from the prefs file if it can be found, otherwise create a new one.
*
* @return the XMLControl
*/
private static XMLControl getPrefsControl() {
if (prefsControl==null) {
// try to load prefs control from default search paths
ArrayList<String> dirs = getDefaultSearchPaths();
for (String dir: dirs) {
File file = new File(dir, prefsFileName);
if (!file.exists()) {
// try with leading dot
file = new File(dir, "."+prefsFileName); //$NON-NLS-1$
if (file.exists()) {
prefsFileName = "."+prefsFileName; //$NON-NLS-1$
}
}
if (file.exists()) {
XMLControl test = new XMLControlElement(file.getAbsolutePath());
if (!test.failedToRead()) {
prefsControl = test;
prefsPath = XML.forwardSlash(dir);
break;
}
}
}
if (prefsControl==null) {
prefsControl = new XMLControlElement();
// by default, save prefs in first default search directory
prefsPath = XML.forwardSlash(dirs.get(0));
if (prefsPath.equals(userhomeDir)) {
// if saving in user home, add leading dot to hide
prefsFileName = "."+prefsFileName; //$NON-NLS-1$
}
File file = new File(prefsPath, prefsFileName);
prefsControl.write(file.getAbsolutePath());
}
}
return prefsControl;
}
/**
* Gets the translator, if any.
* @return translator, or null if none available
*/
public static Translator getTranslator() {
if((translator==null)&&loadTranslatorTool) {
// creates the shared Translator
try {
Class<?> translatorClass = Class.forName("org.opensourcephysics.tools.TranslatorTool"); //$NON-NLS-1$
Method m = translatorClass.getMethod("getTool", (Class[]) null); //$NON-NLS-1$
translator = (Translator) m.invoke(null, (Object[]) null);
} catch(Exception ex) {
loadTranslatorTool = false;
OSPLog.finest("Cannot instantiate translator tool class:\n"+ex.toString()); //$NON-NLS-1$
}
}
return translator;
}
private static JFileChooser chooser;
/**
* Gets a file chooser.
* The choose is static and will therefore be the same for all OSPFrames.
*
* @return the chooser
*/
public static JFileChooser getChooser() {
if(chooser!=null) {
FontSizer.setFonts(chooser, FontSizer.getLevel());
return chooser;
}
try {
chooser = (OSPRuntime.chooserDir==null) ? new JFileChooser() : new JFileChooser(new File(OSPRuntime.chooserDir));
} catch(Exception e) {
System.err.println("Exception in OSPFrame getChooser="+e); //$NON-NLS-1$
return null;
}
javax.swing.filechooser.FileFilter defaultFilter = chooser.getFileFilter();
javax.swing.filechooser.FileFilter xmlFilter = new javax.swing.filechooser.FileFilter() {
// accept all directories and *.xml files.
public boolean accept(File f) {
if(f==null) {
return false;
}
if(f.isDirectory()) {
return true;
}
String extension = null;
String name = f.getName();
int i = name.lastIndexOf('.');
if((i>0)&&(i<name.length()-1)) {
extension = name.substring(i+1).toLowerCase();
}
if((extension!=null)&&(extension.equals("xml"))) { //$NON-NLS-1$
return true;
}
return false;
}
// the description of this filter
public String getDescription() {
return DisplayRes.getString("OSPRuntime.FileFilter.Description.XML"); //$NON-NLS-1$
}
};
javax.swing.filechooser.FileFilter txtFilter = new javax.swing.filechooser.FileFilter() {
// accept all directories and *.txt files.
public boolean accept(File f) {
if(f==null) {
return false;
}
if(f.isDirectory()) {
return true;
}
String extension = null;
String name = f.getName();
int i = name.lastIndexOf('.');
if((i>0)&&(i<name.length()-1)) {
extension = name.substring(i+1).toLowerCase();
}
if((extension!=null)&&extension.equals("txt")) { //$NON-NLS-1$
return true;
}
return false;
}
// the description of this filter
public String getDescription() {
return DisplayRes.getString("OSPRuntime.FileFilter.Description.TXT"); //$NON-NLS-1$
}
};
chooser.addChoosableFileFilter(xmlFilter);
chooser.addChoosableFileFilter(txtFilter);
chooser.setFileFilter(defaultFilter);
FontSizer.setFonts(chooser, FontSizer.getLevel());
return chooser;
}
/**
* Uses a JFileChooser to ask for a name.
* @param chooser JFileChooser
* @return String The absolute pah of the filename. Null if cancelled
*/
static public String chooseFilename(JFileChooser chooser) {
return chooseFilename(chooser, null, true);
}
/**
* Uses a JFileChooser to ask for a name.
* @param chooser JFileChooser
* @param parent Parent component for messages
* @param toSave true if we will save to the chosen file, false if we will read from it
* @return String The absolute pah of the filename. Null if cancelled
*/
static public String chooseFilename(JFileChooser chooser, Component parent, boolean toSave) {
String fileName = null;
int result;
if(toSave) {
result = chooser.showSaveDialog(parent);
} else {
result = chooser.showOpenDialog(parent);
}
if(result==JFileChooser.APPROVE_OPTION) {
OSPRuntime.chooserDir = chooser.getCurrentDirectory().toString();
File file = chooser.getSelectedFile();
// check to see if file exists
if(toSave) { // saving: check if the file will be overwritten
if(file.exists()) {
int selected = JOptionPane.showConfirmDialog(parent, DisplayRes.getString("DrawingFrame.ReplaceExisting_message")+" "+file.getName() //$NON-NLS-1$ //$NON-NLS-2$
+DisplayRes.getString("DrawingFrame.QuestionMark"), DisplayRes.getString( //$NON-NLS-1$
"DrawingFrame.ReplaceFile_option_title"), //$NON-NLS-1$
JOptionPane.YES_NO_CANCEL_OPTION);
if(selected!=JOptionPane.YES_OPTION) {
return null;
}
}
} else { // Reading: check if thefile actually exists
if(!file.exists()) {
JOptionPane.showMessageDialog(parent, DisplayRes.getString("GUIUtils.FileDoesntExist")+" "+file.getName(), //$NON-NLS-1$ //$NON-NLS-2$
DisplayRes.getString("GUIUtils.FileChooserError"), //$NON-NLS-1$
JOptionPane.ERROR_MESSAGE);
return null;
}
}
fileName = file.getAbsolutePath();
if((fileName==null)||fileName.trim().equals("")) { //$NON-NLS-1$
return null;
}
}
return fileName;
}
/**
* Creates a JFileChooser with given title, description and extensions
* @param title the title
* @param description a description string
* @param extensions an array of allowed extensions
* @return the JFileChooser
*/
static public javax.swing.JFileChooser createChooser(String title, String description, String[] extensions) {
javax.swing.JFileChooser chooser = createChooser(description, extensions, null);
chooser.setDialogTitle(title);
return chooser;
}
/**
* Creates a JFileChooser with given description and extensions
* @param description String A description string
* @param extensions String[] An array of allowed extensions
* @return JFileChooser
*/
static public javax.swing.JFileChooser createChooser(String description, String[] extensions) {
return createChooser(description, extensions, null);
}
/**
* Creates a JFileChooser with given description and extensions
* @param description String A description string
* @param extensions String[] An array of allowed extensions
* @param homeDir File The target directory when the user clicks the home icon
* @return JFileChooser
*/
static public javax.swing.JFileChooser createChooser(String description, String[] extensions, final File homeDir) {
javax.swing.JFileChooser chooser = new javax.swing.JFileChooser(new File(OSPRuntime.chooserDir));
ExtensionFileFilter filter = new ExtensionFileFilter();
for(int i = 0; i<extensions.length; i++) {
filter.addExtension(extensions[i]);
}
filter.setDescription(description);
if(homeDir!=null) {
chooser.setFileSystemView(new javax.swing.filechooser.FileSystemView() {
public File createNewFolder(File arg0) throws IOException {
return javax.swing.filechooser.FileSystemView.getFileSystemView().createNewFolder(arg0);
}
public File getHomeDirectory() {
return homeDir;
}
});
}
chooser.setFileFilter(filter);
FontSizer.setFonts(chooser, FontSizer.getLevel());
return chooser;
}
/**
* This file filter matches all files with a given set of
* extensions.
*/
static private class ExtensionFileFilter extends javax.swing.filechooser.FileFilter {
private String description = ""; //$NON-NLS-1$
private java.util.ArrayList<String> extensions = new java.util.ArrayList<String>();
/**
* Adds an extension that this file filter recognizes.
* @param extension a file extension (such as ".txt" or "txt")
*/
public void addExtension(String extension) {
if(!extension.startsWith(".")) { //$NON-NLS-1$
extension = "."+extension; //$NON-NLS-1$
}
extensions.add(extension.toLowerCase());
}
public String toString() {
return description;
}
/**
* Sets a description for the file set that this file filter
* recognizes.
* @param aDescription a description for the file set
*/
public void setDescription(String aDescription) {
description = aDescription;
}
/**
* Returns a description for the file set that this file
* filter recognizes.
* @return a description for the file set
*/
public String getDescription() {
return description;
}
public boolean accept(File f) {
if (f==null) return false;
if(f.isDirectory()) {
return true;
}
String name = f.getName().toLowerCase();
// check if the file name ends with any of the extensions
for(int i = 0; i<extensions.size(); i++) {
if(name.endsWith(extensions.get(i))) {
return true;
}
}
return false;
}
}
}
/*
* Open Source Physics software is free software; you can redistribute
* it and/or modify it under the terms of the GNU General Public License (GPL) as
* published by the Free Software Foundation; either version 2 of the License,
* or(at your option) any later version.
*
* Code that uses any portion of the code in the org.opensourcephysics package
* or any subpackage (subdirectory) of this package must must also be be released
* under the GNU GPL license.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA
* or view the license online at http://www.gnu.org/copyleft/gpl.html
*
* Copyright (c) 2007 The Open Source Physics project
* http://www.opensourcephysics.org
*/