diff options
author | Shashank | 2017-05-29 12:40:26 +0530 |
---|---|---|
committer | Shashank | 2017-05-29 12:40:26 +0530 |
commit | 0345245e860375a32c9a437c4a9d9cae807134e9 (patch) | |
tree | ad51ecbfa7bcd3cc5f09834f1bb8c08feaa526a4 /modules/commons/src/java | |
download | scilab_for_xcos_on_cloud-0345245e860375a32c9a437c4a9d9cae807134e9.tar.gz scilab_for_xcos_on_cloud-0345245e860375a32c9a437c4a9d9cae807134e9.tar.bz2 scilab_for_xcos_on_cloud-0345245e860375a32c9a437c4a9d9cae807134e9.zip |
CMSCOPE changed
Diffstat (limited to 'modules/commons/src/java')
22 files changed, 3191 insertions, 0 deletions
diff --git a/modules/commons/src/java/org/scilab/modules/commons/CommonFileUtils.java b/modules/commons/src/java/org/scilab/modules/commons/CommonFileUtils.java new file mode 100755 index 000000000..6fd850641 --- /dev/null +++ b/modules/commons/src/java/org/scilab/modules/commons/CommonFileUtils.java @@ -0,0 +1,38 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 2.0.7 + * + * Do not make changes to this file unless you know what you are doing--modify + * the SWIG interface file instead. + * ----------------------------------------------------------------------------- */ + +package org.scilab.modules.commons; + + +/** + * Some file utils + * @author Calixte DENIZET + * @copyright DIGITEO 2011 + */ +public class CommonFileUtils { + + /** + * Constructor + */ + protected CommonFileUtils() { + throw new UnsupportedOperationException(); + } + public static int isEmptyDirectory(String dirName) { + return CommonFileUtilsJNI.isEmptyDirectory(dirName); + } + + + /** + * Get the current working directory + * @return the Scilab CWD + */ + public static String getCWD() { + return CommonFileUtilsJNI.getCWD(); + } + +} diff --git a/modules/commons/src/java/org/scilab/modules/commons/CommonFileUtilsJNI.java b/modules/commons/src/java/org/scilab/modules/commons/CommonFileUtilsJNI.java new file mode 100755 index 000000000..bebe7c277 --- /dev/null +++ b/modules/commons/src/java/org/scilab/modules/commons/CommonFileUtilsJNI.java @@ -0,0 +1,49 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 2.0.7 + * + * Do not make changes to this file unless you know what you are doing--modify + * the SWIG interface file instead. + * ----------------------------------------------------------------------------- */ + +package org.scilab.modules.commons; + + +/* It is generated code. Disable checkstyle */ +//CHECKSTYLE:OFF +/** + * Some file utils + * @author Calixte DENIZET + * @copyright DIGITEO 2011 + */ +public class CommonFileUtilsJNI { + + /** + * Constructor + */ + protected CommonFileUtilsJNI() { + throw new UnsupportedOperationException(); + } + + static { + try { + System.loadLibrary("scicommons"); + } catch (SecurityException e) { + System.err.println("A security manager exists and does not allow the loading of the specified dynamic library."); + System.err.println(e.getLocalizedMessage()); + System.exit(-1); + } catch (UnsatisfiedLinkError e) { + System.err.println("The native library scicommons does not exist or cannot be found."); + if (System.getenv("CONTINUE_ON_JNI_ERROR") == null) { + System.err.println(e.getLocalizedMessage()); + System.err.println("Current java.library.path is : " + System.getProperty("java.library.path")); + System.exit(-1); + } else { + System.err.println("Continuing anyway because of CONTINUE_ON_JNI_ERROR"); + } + } + } + + public final static native int isEmptyDirectory(String jarg1); + public final static native String getCWD(); +} diff --git a/modules/commons/src/java/org/scilab/modules/commons/OS.java b/modules/commons/src/java/org/scilab/modules/commons/OS.java new file mode 100755 index 000000000..1b584b82d --- /dev/null +++ b/modules/commons/src/java/org/scilab/modules/commons/OS.java @@ -0,0 +1,79 @@ +/* + * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab + * Copyright (C) 2010 - DIGITEO - Allan CORNET + * Copyright (C) 2011 - DIGITEO - Clement DAVID + * + * This file must be used under the terms of the CeCILL. + * This source file is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at + * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt + * + */ + +package org.scilab.modules.commons; + +/** + * Operating Systems utility class + */ +public enum OS { + WINDOWS { + /** + * {@inheritDoc} + */ + @Override + public Object getVersion() { + return Double.valueOf(System.getProperty("os.version")); + } + }, + MAC { + /** + * {@inheritDoc} + */ + @Override + public Object getVersion() { + final String[] numbers = System.getProperty("os.version").split( + "\\."); + + int[] ret = new int[numbers.length]; + for (int i = 0; i < numbers.length; i++) { + ret[i] = Integer.parseInt(numbers[i]); + } + return ret; + } + }, + UNIX; + + /** + * @return the OS type + */ + public static OS get() { + final String name = System.getProperty("os.name").toLowerCase(); + + if (name.contains("windows")) { + return OS.WINDOWS; + } else if (name.contains("mac")) { + return MAC; + } else { + return UNIX; + } + } + + /** + * @return the OS version + */ + public Object getVersion() { + return null; + } + + public static String getVersionName() { + switch (get()) { + case WINDOWS: + return "Windows"; + case MAC: + return "Mac"; + default: + return "Linux"; + } + } +} diff --git a/modules/commons/src/java/org/scilab/modules/commons/ScilabCommons.java b/modules/commons/src/java/org/scilab/modules/commons/ScilabCommons.java new file mode 100755 index 000000000..44b8d810a --- /dev/null +++ b/modules/commons/src/java/org/scilab/modules/commons/ScilabCommons.java @@ -0,0 +1,125 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 2.0.7 + * + * Do not make changes to this file unless you know what you are doing--modify + * the SWIG interface file instead. + * ----------------------------------------------------------------------------- */ + +package org.scilab.modules.commons; + + +/** + * Some commons values from Scilab engine to Java + * @author Sylvestre LEDRU + * @copyright DIGITEO 2010 + */ +public class ScilabCommons { + + /** + * Constructor + */ + protected ScilabCommons() { + throw new UnsupportedOperationException(); + } + + /** + * Get SCIHOME variable from Scilab + * @return SCIHOME value + */ + public static String getSCIHOME() { + return ScilabCommonsJNI.getSCIHOME(); + } + + public static String getTMPDIR() { + return ScilabCommonsJNI.getTMPDIR(); + } + + public static String getlanguage() { + return ScilabCommonsJNI.getlanguage(); + } + + public static String createtempfilename(String prefix, int bShortFormat) { + return ScilabCommonsJNI.createtempfilename(prefix, bShortFormat); + } + + public static int getieee() { + return ScilabCommonsJNI.getieee(); + } + + public static void setieee(int arg0) { + ScilabCommonsJNI.setieee(arg0); + } + + + /** + * Set the Scilab ieee mode + */ + public static void setformat(String format, int width) { + ScilabCommonsJNI.setformat(format, width); + } + + + /** + * returns the Scilab format ("v" or "e") + * @return format + */ + public static String getformat() { + return ScilabCommonsJNI.getformat(); + } + + + /** + * returns the Scilab format width + * @return format + */ + public static int getformatwidth() { + return ScilabCommonsJNI.getformatwidth(); + } + + + /** + * returns the Scilab version major number + * @return version major + */ + public static int getScilabVersionMajor() { + return ScilabCommonsJNI.getScilabVersionMajor(); + } + + + /** + * returns the Scilab version minor number + * @return version minor + */ + public static int getScilabVersionMinor() { + return ScilabCommonsJNI.getScilabVersionMinor(); + } + + + /** + * returns the Scilab version maintenance number + * @return version maintenance + */ + public static int getScilabVersionMaintenance() { + return ScilabCommonsJNI.getScilabVersionMaintenance(); + } + + + /** + * returns the Scilab version timestamp number + * @return version timestamp + */ + public static int getScilabVersionTimestamp() { + return ScilabCommonsJNI.getScilabVersionTimestamp(); + } + + + /** + * returns the Scilab version as string + * @return version Scilab version as a string + */ + public static String getScilabVersionAsString() { + return ScilabCommonsJNI.getScilabVersionAsString(); + } + +} diff --git a/modules/commons/src/java/org/scilab/modules/commons/ScilabCommonsJNI.java b/modules/commons/src/java/org/scilab/modules/commons/ScilabCommonsJNI.java new file mode 100755 index 000000000..5e49a18ba --- /dev/null +++ b/modules/commons/src/java/org/scilab/modules/commons/ScilabCommonsJNI.java @@ -0,0 +1,61 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 2.0.7 + * + * Do not make changes to this file unless you know what you are doing--modify + * the SWIG interface file instead. + * ----------------------------------------------------------------------------- */ + +package org.scilab.modules.commons; + + +/* It is generated code. Disable checkstyle */ +//CHECKSTYLE:OFF +/** + * Some commons values from Scilab engine to Java + * @author Sylvestre LEDRU + * @copyright DIGITEO 2010 + */ +public class ScilabCommonsJNI { + + /** + * Constructor + */ + protected ScilabCommonsJNI() { + throw new UnsupportedOperationException(); + } + + static { + try { + System.loadLibrary("scicommons"); + } catch (SecurityException e) { + System.err.println("A security manager exists and does not allow the loading of the specified dynamic library."); + System.err.println(e.getLocalizedMessage()); + System.exit(-1); + } catch (UnsatisfiedLinkError e) { + System.err.println("The native library scicommons does not exist or cannot be found."); + if (System.getenv("CONTINUE_ON_JNI_ERROR") == null) { + System.err.println(e.getLocalizedMessage()); + System.err.println("Current java.library.path is : " + System.getProperty("java.library.path")); + System.exit(-1); + } else { + System.err.println("Continuing anyway because of CONTINUE_ON_JNI_ERROR"); + } + } + } + + public final static native String getSCIHOME(); + public final static native String getTMPDIR(); + public final static native String getlanguage(); + public final static native String createtempfilename(String jarg1, int jarg2); + public final static native int getieee(); + public final static native void setieee(int jarg1); + public final static native void setformat(String jarg1, int jarg2); + public final static native String getformat(); + public final static native int getformatwidth(); + public final static native int getScilabVersionMajor(); + public final static native int getScilabVersionMinor(); + public final static native int getScilabVersionMaintenance(); + public final static native int getScilabVersionTimestamp(); + public final static native String getScilabVersionAsString(); +} diff --git a/modules/commons/src/java/org/scilab/modules/commons/ScilabCommonsUtils.java b/modules/commons/src/java/org/scilab/modules/commons/ScilabCommonsUtils.java new file mode 100755 index 000000000..917df11e9 --- /dev/null +++ b/modules/commons/src/java/org/scilab/modules/commons/ScilabCommonsUtils.java @@ -0,0 +1,187 @@ +/* + * Scilab (http://www.scilab.org/) - This file is part of Scilab + * Copyright (C) 2011 - Calixte DENIZET + * + * This file must be used under the terms of the CeCILL. + * This source file is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at + * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt + * + */ + +package org.scilab.modules.commons; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.reflect.Method; +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * Basic utils + * @author Calixte DENIZET + */ +public final class ScilabCommonsUtils { + + private static final int BUFFERSIZE = 8192; + private static Thread scilabThread; + + private static MessageDigest MD5; + static { + try { + MD5 = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException e) { + System.err.println(e); + MD5 = null; + } + } + + public static int[] getScilabVersions() { + return new int[] {ScilabCommons.getScilabVersionMajor(), ScilabCommons.getScilabVersionMinor(), ScilabCommons.getScilabVersionMaintenance(), ScilabCommons.getScilabVersionTimestamp()}; + } + + public static String getScilabVersion() { + return ScilabCommons.getScilabVersionMajor() + "." + ScilabCommons.getScilabVersionMinor() + "." + ScilabCommons.getScilabVersionMaintenance(); + } + + public static String getScilabVersionAsString() { + return ScilabCommons.getScilabVersionAsString().replaceFirst("scilab-", ""); + } + + + + /** + * Get a MD5 string of the input string + * @param str the string to convert + * @return the MD5 representation of str + */ + public static String getMD5(String str) { + if (MD5 == null) { + return null; + } + + try { + byte[] bytes = MD5.digest(str.getBytes("UTF-8")); + return new BigInteger(1, bytes).toString(16); + } catch (Exception e) { + return null; + } + } + + /** + * Copy a file + * @param inFile src file + * @param outFile dest file + * @return true if the operation succeeded + */ + public static boolean copyFile(File inFile, File outFile) { + FileInputStream in = null; + FileOutputStream out = null; + boolean success = false; + + try { + in = new FileInputStream(inFile); + out = new FileOutputStream(outFile); + byte[] buffer = new byte[BUFFERSIZE]; + int n; + + while ((n = in.read(buffer)) != -1) { + out.write(buffer, 0, n); + } + out.flush(); + success = true; + } catch (IOException e) { + System.err.println("Error in copying file " + inFile.getAbsolutePath() + " to " + outFile.getAbsolutePath()); + System.err.println(e); + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException e) { + System.err.println(e); + } + } + if (out != null) { + try { + out.close(); + } catch (IOException e) { + System.err.println(e); + } + } + } + + return success; + } + + /** + * Replace ~ by user home, SCI by Scilab main directory, ... + * @param baseDir the base directory + * @return correct base directory + */ + public static String getCorrectedPath(String path) { + String sciUnixStyle = ""; + path = path.trim(); + String pathLinux = path.replace("\\", "/"); + if (path != null && !path.isEmpty()) { + if (path.startsWith("~" + "/") || path.equals("~")) { + sciUnixStyle = ScilabConstants.USERHOME.replace("\\", "/"); + return path.replaceFirst("~", sciUnixStyle); + } else if (path.startsWith("SCI/") || path.equals("SCI")) { + try { + sciUnixStyle = ScilabConstants.SCI.getCanonicalPath().replace("\\", "/"); + } catch (IOException e) { + sciUnixStyle = ScilabConstants.SCI.getAbsolutePath().replace("\\", "/"); + } + return pathLinux.replaceFirst("SCI", sciUnixStyle).replace("/", File.separator); + } else if (path.startsWith("SCIHOME/") || path.equals("SCIHOME")) { + sciUnixStyle = ScilabConstants.SCIHOME.toString().replace("\\", "/"); + return path.replaceFirst("SCIHOME", sciUnixStyle).replace("/", File.separator); + } else if (path.startsWith("TMPDIR/") || path.equals("TMPDIR")) { + sciUnixStyle = ScilabCommons.getTMPDIR().replace("\\", "/"); + return path.replaceFirst("TMPDIR", sciUnixStyle).replace("/", File.separator); + } + } + + return path; + } + + /** + * Load on use + * @param str the action + */ + public static void loadOnUse(String str) { + try { + Class jvmLoadClassPathClass = Class.forName("org.scilab.modules.jvm.LoadClassPath"); + Method loadOnUseMethod = jvmLoadClassPathClass.getDeclaredMethod("loadOnUse", new Class[] { String.class }); + loadOnUseMethod.invoke(null, str); + } catch (java.lang.ClassNotFoundException ex) { + System.err.println("Could not find the Scilab class to load dependency: " + ex); + } catch (java.lang.NoSuchMethodException ex) { + System.err.println("Could not find the Scilab method to load dependency: " + ex); + } catch (java.lang.IllegalAccessException ex) { + System.err.println("Could not access to the Scilab method to load dependency: " + ex); + } catch (java.lang.reflect.InvocationTargetException ex) { + System.err.println("Could not invoke the Scilab method to load dependency: " + ex); + } + } + + /** + * Set the scilab thread as the current thread + * Called from org.scilab.modules.core.Scilab::executeInitialHooks called itself + * in GetCommandLine.c just after the first display of the prompt. + */ + public static void registerScilabThread() { + scilabThread = Thread.currentThread(); + } + + /** + * @return true if Thread.currentThread() is the main Scilab thread + */ + public static boolean isScilabThread() { + return scilabThread != null && scilabThread == Thread.currentThread(); + } +} diff --git a/modules/commons/src/java/org/scilab/modules/commons/ScilabConstants.java b/modules/commons/src/java/org/scilab/modules/commons/ScilabConstants.java new file mode 100755 index 000000000..aeac7e097 --- /dev/null +++ b/modules/commons/src/java/org/scilab/modules/commons/ScilabConstants.java @@ -0,0 +1,93 @@ +/* + * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab + * Copyright (C) 2010 - DIGITEO - Clement DAVID + * Copyright (C) 2010 - DIGITEO - Sylvestre LEDRU + * + * This file must be used under the terms of the CeCILL. + * This source file is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at + * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt + * + */ + +package org.scilab.modules.commons; + +import java.io.File; + +/** + * Define all the constants used on a Scilab + */ +public class ScilabConstants { + + /* Scilab */ + + /** + * The tmp directory + * This code used to be System.getenv("TMPDIR"). + * However, this was failing with Javasci to due architecture constraints + * Javasci (Java) => Call_scilab (C) => Scilab engine (C) + * => Java VM (graphics, xcos, etc). + * In this case, the Java VM is started by Javasci. + * Since, the TMPDIR env variable is set by Call_Scilab (the second step), + * the environnement in the Java world has not TMPDIR + */ + public static final File TMPDIR; + + /** + * The SCI directory (Scilab root directory) + */ + public static final File SCI; + + /** + * The SCI configuration directory (Scilab home directory) + */ + public static final File SCIHOME; + + /** + * The user home directory + */ + public static final String USERHOME = System.getProperty("user.home"); + + /** Escape double quote symbol */ + public static final char QUOTE = '\"'; + + /** 2 is for GUI **/ + public static int mode; + + /* + * Static constructor + */ + static { + String value; + + value = ScilabCommons.getTMPDIR(); + if (value == null || value.isEmpty()) { + value = System.getProperty("java.io.tmpdir"); + } + TMPDIR = new File(value); + + value = System.getenv("SCI"); + SCI = new File(value).getAbsoluteFile(); + + value = ScilabCommons.getSCIHOME(); + if (value == null || "".equals(value) || "empty_SCIHOME".equals(value)) { + // Empty java value is TMPDIR + SCIHOME = TMPDIR; + } else { + SCIHOME = new File(value); + } + } + + /** This class is a static singleton, thus it must not be instantiated */ + protected ScilabConstants() { } + + public static void setMode(int mode) { + ScilabConstants.mode = mode; + } + + public static boolean isGUI() { + return ScilabConstants.mode == 2; + } + +} diff --git a/modules/commons/src/java/org/scilab/modules/commons/ScilabGeneralPrefs.java b/modules/commons/src/java/org/scilab/modules/commons/ScilabGeneralPrefs.java new file mode 100755 index 000000000..2da76cab8 --- /dev/null +++ b/modules/commons/src/java/org/scilab/modules/commons/ScilabGeneralPrefs.java @@ -0,0 +1,137 @@ +/* + * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab + * Copyright (C) 2012 - Scilab Enterprises - Calixte DENIZET + * + * This file must be used under the terms of the CeCILL. + * This source file is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at + * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt + * + */ + +package org.scilab.modules.commons; + +import java.awt.Font; +import java.lang.reflect.Method; + +import org.w3c.dom.Document; + +import org.scilab.modules.commons.xml.XConfiguration; +import org.scilab.modules.commons.xml.XConfigurationEvent; +import org.scilab.modules.commons.xml.XConfigurationListener; +import static org.scilab.modules.commons.xml.XConfiguration.XConfAttribute; +import org.scilab.modules.localization.WindowsDefaultLanguage; + +public class ScilabGeneralPrefs implements XConfigurationListener { + + private static final String ENV_PATH = "//general/body/environment"; + private static final String FONT_PATH = "//fonts/body/fonts"; + private static final String LANG_PATH = "//general/body/languages"; + private static final ScilabGeneralPrefs instance = new ScilabGeneralPrefs(); + private static Font desktopFont; + + private ScilabGeneralPrefs() { } + + public static ScilabGeneralPrefs getInstance() { + return instance; + } + + public static void openPreferences(String path) { + try { + Class prefs = ClassLoader.getSystemClassLoader().loadClass("org.scilab.modules.preferences.ScilabPreferences"); + Method open = prefs.getDeclaredMethod("openPreferences", String.class); + open.invoke(null, path); + } catch (ClassNotFoundException e) { + // Nothing displayed (always occurs in MN mode) + } catch (Exception e) { + System.err.println(e); + } + } + + public void configurationChanged(XConfigurationEvent e) { + boolean all = e.getModifiedPaths().contains("ALL"); + if (all || e.getModifiedPaths().contains(ENV_PATH)) { + Document doc = XConfiguration.getXConfigurationDocument(); + GeneralEnvironment ge = XConfiguration.get(GeneralEnvironment.class, doc, ENV_PATH)[0]; + ScilabCommons.setieee(ge.code); + ScilabCommons.setformat(ge.format, ge.width); + } + + if (e.getModifiedPaths().contains(LANG_PATH)) { + Document doc = XConfiguration.getXConfigurationDocument(); + Language language = XConfiguration.get(Language.class, doc, LANG_PATH)[0]; + WindowsDefaultLanguage.setdefaultlanguage(language.lang); + } + + if (all || e.getModifiedPaths().contains(FONT_PATH)) { + desktopFont = null; + } + } + + public static Font getDesktopFont() { + if (desktopFont == null) { + Document doc = XConfiguration.getXConfigurationDocument(); + DesktopFont df = XConfiguration.get(DesktopFont.class, doc, FONT_PATH)[0]; + desktopFont = df.font; + } + + return desktopFont; + } + + @XConfAttribute + private static class DesktopFont { + + public Font font; + + private DesktopFont() { } + + @XConfAttribute(tag = "fonts", attributes = {"font-face", "font-name", "font-size", "system"}) + private void set(String fontFace, String fontName, int fontSize, boolean useSystemFont) { + if (useSystemFont) { + this.font = new Font("monospaced", Font.PLAIN, 13); + } else { + this.font = new Font(fontName, Font.PLAIN, fontSize); + int style = Font.PLAIN; + if (fontFace.contains("bold")) { + style = style | Font.BOLD; + } else if (fontFace.contains("italic")) { + style = style | Font.ITALIC; + } + if (style != Font.PLAIN) { + this.font = this.font.deriveFont(style); + } + } + } + } + + @XConfAttribute + private static class GeneralEnvironment { + + public int code; + public String format; + public int width; + + private GeneralEnvironment() { } + + @XConfAttribute(attributes = {"fpe", "printing-format", "width"}) + private void set(int fpe, String format, int width) { + this.code = fpe; + this.format = format; + this.width = Math.min(Math.max(0, width), 25); + } + } + + @XConfAttribute + private static class Language { + + public String lang; + + private Language() { } + + @XConfAttribute(attributes = {"lang"}) + private void set(String lang) { + this.lang = lang; + } + } +} diff --git a/modules/commons/src/java/org/scilab/modules/commons/gui/FindIconHelper.java b/modules/commons/src/java/org/scilab/modules/commons/gui/FindIconHelper.java new file mode 100755 index 000000000..cb0ed05d2 --- /dev/null +++ b/modules/commons/src/java/org/scilab/modules/commons/gui/FindIconHelper.java @@ -0,0 +1,320 @@ +package org.scilab.modules.commons.gui; + +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.TreeSet; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.imageio.ImageIO; +import javax.swing.Icon; +import javax.swing.ImageIcon; + +import org.scilab.modules.commons.OS; +import org.scilab.modules.commons.ScilabCommonsUtils; + +public final class FindIconHelper { + /** + * Look for the icon associated with the name. + * + * @param icon + * the name to look for + * @return the image icon path + */ + public static String findIcon(final String icon) { + return findIcon(icon, "16x16", true); + } + + public static String findIcon(final String icon, boolean defaultValue) { + return findIcon(icon, "16x16", defaultValue); + } + + /** + * Look for the icon associated with the name for a specific module. + * + * @param name + * the name to look for + * @param size + * the size to look for + * @return the loaded image icon + */ + public static String findIcon(final String icon, final String size) { + return findIcon(icon, size, true); + } + + public static String findIcon(final String icon, final String size, boolean defaultValue) { + if (icon == null || icon.isEmpty()) { + return null; + } + + final String filename = findIconHelper(icon, size, "Tango"); + if (filename != null) { + if (LOG.isLoggable(Level.FINER)) { + LOG.finer(icon + '[' + size + ']' + " i " + filename); + } + return filename; + } + + final String fallback = lookupFallbackIcon(icon); + if (defaultValue && fallback == null) { + LOG.warning("Unable to found icon: " + icon + '[' + size + ']'); + return System.getenv("SCI") + "/modules/gui/images/icons/16x16/status/error.png"; + } + + if (LOG.isLoggable(Level.FINER)) { + LOG.finer(icon + '[' + size + ']' + " f " + fallback); + } + return fallback; + } + + private static String findIconHelper(final String icon, final String size, final String theme) { + try { + final String filename = lookupIcon(icon, size, theme); + if (filename != null) { + return filename; + } + } catch (IOException e) { + } + + /* + * always look for hicolor and then empty theme in case of invalid + * theme. + */ + if (!theme.isEmpty() && theme != HICOLOR) { + return findIconHelper(icon, size, HICOLOR); + } else if (!theme.isEmpty()) { + return findIconHelper(icon, size, ""); + } else { + return null; + } + } + + private static final Logger LOG = Logger.getLogger(FindIconHelper.class.getName()); + + private static final String SCI = System.getenv("SCI"); + private static final String SEP = System.getProperty("file.separator"); + private static final String DOT = "."; + private static final String HICOLOR = "hicolor"; + private static final List<String> ICONS_EXTENSIONS = Arrays.asList("png", "svg", "xpm"); + private static final HashMap<File, TreeSet<String>> THEME_SUBDIR_CACHE = new HashMap<File, TreeSet<String>>(); + + private static final FileFilter DIR_FILTER; + private static final List<String> THEME_BASENAME; + static { + DIR_FILTER = new FileFilter() { + @Override + public boolean accept(File pathname) { + return pathname.isDirectory(); + } + }; + THEME_BASENAME = new ArrayList<String>(); + + /* + * Linux specific path + */ + switch (OS.get()) { + case UNIX: + THEME_BASENAME.add("~/.icons"); + THEME_BASENAME.add("/usr/share/icons"); + THEME_BASENAME.add("/usr/share/pixmaps"); + + THEME_BASENAME.add(SCI + "/../icons"); + break; + + case MAC: + THEME_BASENAME.add(SCI + "/../icons"); + break; + + default: + break; + } + + /* + * Scilab embedded icons + */ + + final ArrayList<File> dirs = new ArrayList<File>(); + + // Append SCI/desktop and SCI/modules/xxx to the dirs + dirs.add(new File(SCI + SEP + "desktop")); + dirs.addAll(Arrays.asList(new File(SCI + SEP + "modules").listFiles(DIR_FILTER))); + for (File m : dirs) { + final File icons = new File(m, "images" + SEP + "icons"); + final boolean iconsIsDir = icons.isDirectory(); + + // add dirs/images/icons/ to the base name + if (iconsIsDir) { + THEME_BASENAME.add(icons.getAbsolutePath()); + } + + // add dirs/images/icons/*/* to the base name + if (iconsIsDir) { + for (File s : icons.listFiles(DIR_FILTER)) { + for (File category : s.listFiles(DIR_FILTER)) { + THEME_BASENAME.add(category.getAbsolutePath()); + } + } + } + } + } + + private static String lookupIcon(final String iconname, final String size, final String theme) throws IOException { + if(iconname.contains("<html>")) { + return null; + } + + for (String directory : THEME_BASENAME) { + final File themeDir = new File(directory + SEP + theme); + if (!themeDir.exists() || !themeDir.isDirectory()) { + continue; + } + + /* + * FIXME: implement an index.theme reader, for now we are parsing + * the file path to get the information + */ + for (String extension : ICONS_EXTENSIONS) { + final File f = new File(themeDir, iconname + DOT + extension); + + if (f.exists()) { + return f.getCanonicalPath(); + } + } + /* + * Create the theme subdirs + */ + final int themeDirLen = themeDir.getCanonicalPath().length(); + final TreeSet<String> themeSubdirs = findThemeSubdir(themeDir, themeDirLen); + + /* + * Create a theme subdirs for a specific size + */ + final TreeSet<String> sizedSubDirs = findSizedSubdirs(size, themeSubdirs); + + /* + * Look for the icon + */ + for (final String s : sizedSubDirs) { + for (String extension : ICONS_EXTENSIONS) { + final File f = new File(themeDir, s + SEP + iconname + DOT + extension); + + if (f.exists()) { + return f.getCanonicalPath(); + } + } + } + } + + return null; + } + + private static TreeSet<String> findSizedSubdirs(final String size, final TreeSet<String> themeSubdirs) { + final TreeSet<String> sizedSubDirs = new TreeSet<String>(); + for (String subdir : themeSubdirs) { + if (subdir.startsWith(size)) { + sizedSubDirs.add(subdir); + } + } + return sizedSubDirs; + } + + private static TreeSet<String> findThemeSubdir(final File themeDir, final int themeDirLen) throws IOException { + final TreeSet<String> cache = THEME_SUBDIR_CACHE.get(themeDir); + if (cache != null) { + return cache; + } + + final TreeSet<String> themeSubdirs = new TreeSet<String>(); + + final LinkedList<File> dirs = new LinkedList<File>(Arrays.asList(themeDir.listFiles(DIR_FILTER))); + while (!dirs.isEmpty()) { + final File d = dirs.poll(); + + File[] allDirs = d.listFiles(DIR_FILTER); + if (allDirs == null) { + continue; + } + + final List<File> sub = Arrays.asList(allDirs); + if (sub.isEmpty()) { + final String s = d.getCanonicalPath(); + + themeSubdirs.add(s.substring(themeDirLen + 1)); + } else { + dirs.addAll(sub); + } + } + + THEME_SUBDIR_CACHE.put(themeDir, themeSubdirs); + return themeSubdirs; + } + + public static String findImage(final String image) { + return findImage(image, true); + } + + public static String findImage(final String image, boolean defaulValue) { + + File file = new File(ScilabCommonsUtils.getCorrectedPath(image)); + if (file.exists()) { + return file.getAbsolutePath(); + } + + for (String directory : THEME_BASENAME) { + final File f = new File(directory + SEP + image); + if (f.exists()) { + return f.getAbsolutePath(); + } + } + + return findIcon(image, defaulValue); + } + + private static String lookupFallbackIcon(final String icon) { + for (String directory : THEME_BASENAME) { + for (String extension : ICONS_EXTENSIONS) { + final File f = new File(directory + SEP + icon + DOT + extension); + if (f.exists()) { + return f.getAbsolutePath(); + } + } + } + + return null; + } + + public static void addThemePath(String path) { + if (THEME_BASENAME.contains(path)) { + return; + } + + THEME_BASENAME.add(path); + } + + + public static Icon loadIcon(String icon) throws IOException { + String iconFile = findIcon(icon, false); + if (iconFile == null) { + iconFile = ""; + } + + //add item in listbox + File file = new File(iconFile); + if (file.exists() == false) { + String filename = findImage(iconFile, false); + if (filename == null) { + filename = ""; + } + + file = new File(filename); + } + + return new ImageIcon(ImageIO.read(file)); + } +} diff --git a/modules/commons/src/java/org/scilab/modules/commons/gui/ScilabCaret.java b/modules/commons/src/java/org/scilab/modules/commons/gui/ScilabCaret.java new file mode 100755 index 000000000..d31f2f219 --- /dev/null +++ b/modules/commons/src/java/org/scilab/modules/commons/gui/ScilabCaret.java @@ -0,0 +1,183 @@ +/* + * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab + * Copyright (C) 2010 - Calixte DENIZET + * + * This file must be used under the terms of the CeCILL. + * This source file is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at + * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt + * + */ + +package org.scilab.modules.commons.gui; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.event.FocusEvent; +import java.awt.event.MouseEvent; + +import javax.swing.UIManager; +import javax.swing.text.BadLocationException; +import javax.swing.text.DefaultCaret; +import javax.swing.text.JTextComponent; + +/** + * This class handles the tabulation + * @author Calixte DENIZET + */ +public class ScilabCaret extends DefaultCaret { + + private static final long serialVersionUID = 8230195712653828841L; + + private static Color selectionColor; + private static Color inactiveSelectionColor; + + private JTextComponent editor; + + private boolean overwriteMode; + private boolean mustAdjustVisibility = true; + + /** + * Constructor + * @param editor the editor where the caret lives + */ + public ScilabCaret(JTextComponent editor) { + super(); + this.editor = editor; + setSelectionColor(editor.getSelectionColor(), UIManager.getColor("TextComponent.selectionBackgroundInactive")); + } + + /** + * {@inheritDoc} + */ + protected void adjustVisibility(Rectangle nloc) { + if (mustAdjustVisibility) { + super.adjustVisibility(nloc); + } + } + + public void setMustAdjustVisibility(boolean mustAdjustVisibility) { + this.mustAdjustVisibility = mustAdjustVisibility; + } + + public boolean getMustAdjustVisibility() { + return this.mustAdjustVisibility; + } + + /** + * @param active the color of the selection when it is active + * @param inactive the color of the selection when it is inactive + */ + public void setSelectionColor(Color active, Color inactive) { + selectionColor = active; + inactiveSelectionColor = inactive; + if (inactiveSelectionColor == null) { + float r = 0.6f * selectionColor.getRed() / 255f + 0.4f * Color.LIGHT_GRAY.getRed() / 255f; + float g = 0.6f * selectionColor.getGreen() / 255f + 0.4f * Color.LIGHT_GRAY.getGreen() / 255f; + float b = 0.6f * selectionColor.getBlue() / 255f + 0.4f * Color.LIGHT_GRAY.getBlue() / 255f; + inactiveSelectionColor = new Color(r, g, b); + } + } + + /** + * @return the color of the selection + */ + public Color getSelectionColor() { + return selectionColor; + } + + /** + * @return the color of the inactive selection + */ + public Color getInactiveSelectionColor() { + return inactiveSelectionColor; + } + + /** + * {@inheritDoc} + */ + public void setSelectionVisible(boolean vis) { + super.setSelectionVisible(true); + } + + /** + * {@inheritDoc} + */ + public void focusGained(FocusEvent e) { + editor.setSelectionColor(selectionColor); + editor.repaint(); + super.focusGained(e); + } + + /** + * {@inheritDoc} + */ + public void focusLost(FocusEvent e) { + editor.setSelectionColor(inactiveSelectionColor); + editor.repaint(); + super.focusLost(e); + } + + /** + * {@inheritDoc} + */ + public void mouseDragged(MouseEvent e) { + editor.setSelectionColor(selectionColor); + super.mouseDragged(e); + } + + /** + * @param overwriteMode if true, the caret will be drawn as solid rectangle + */ + public void setOverwriteMode(boolean overwriteMode) { + this.overwriteMode = overwriteMode; + } + + /** + * {@inheritDoc} + */ + public void paint(Graphics g) { + if (isVisible() && overwriteMode) { + Rectangle r = null; + int pos = editor.getCaretPosition(); + try { + r = editor.modelToView(pos); + } catch (BadLocationException e) { } + if (r != null && (r.width != 0 || r.height != 0)) { + if ( (x != r.x) || (y != r.y) ) { + repaint(); + x = r.x; + y = r.y; + height = r.height; + width = editor.getFontMetrics(editor.getFont()).charWidth('W') + 1; + } else { + g.setColor(editor.getCaretColor()); + g.setXORMode(editor.getBackground()); + g.fillRect(x, y, width, height); + } + } + } else { + super.paint(g); + } + } + + /** + * {@inheritDoc} + */ + protected synchronized void damage(Rectangle r) { + if (overwriteMode) { + if (r == null) { + return; + } + + x = r.x; + y = r.y; + height = r.height; + repaint(); + } else { + super.damage(r); + } + } +} diff --git a/modules/commons/src/java/org/scilab/modules/commons/gui/ScilabGUIUtilities.java b/modules/commons/src/java/org/scilab/modules/commons/gui/ScilabGUIUtilities.java new file mode 100755 index 000000000..4de02d283 --- /dev/null +++ b/modules/commons/src/java/org/scilab/modules/commons/gui/ScilabGUIUtilities.java @@ -0,0 +1,51 @@ +/* + * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab + * Copyright (C) 2011 - Calixte DENIZET + * + * This file must be used under the terms of the CeCILL. + * This source file is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at + * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt + * + */ + +package org.scilab.modules.commons.gui; + +import java.awt.event.WindowEvent; +import java.awt.event.WindowFocusListener; + +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +/** + * GUI utilities + * @author Calixte DENIZET + */ +public class ScilabGUIUtilities { + + /** + * Bring a window to the front + * @param window the window to bring to the front + */ + public static void toFront(final JFrame window) { + WindowFocusListener listener = new WindowFocusListener() { + + public void windowGainedFocus(WindowEvent e) { + window.setAlwaysOnTop(true); + } + + public void windowLostFocus(WindowEvent e) { + window.setAlwaysOnTop(false); + window.removeWindowFocusListener(this); + } + }; + window.addWindowFocusListener(listener); + window.toFront(); + SwingUtilities.invokeLater(new Runnable() { + public void run() { + window.requestFocus(); + } + }); + } +} diff --git a/modules/commons/src/java/org/scilab/modules/commons/gui/ScilabKeyStroke.java b/modules/commons/src/java/org/scilab/modules/commons/gui/ScilabKeyStroke.java new file mode 100755 index 000000000..cd94e66be --- /dev/null +++ b/modules/commons/src/java/org/scilab/modules/commons/gui/ScilabKeyStroke.java @@ -0,0 +1,87 @@ +/* + * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab + * Copyright (C) 2010 - Calixte DENIZET + * + * This file must be used under the terms of the CeCILL. + * This source file is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at + * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt + * + */ + +package org.scilab.modules.commons.gui; + +import java.awt.GraphicsEnvironment; +import java.awt.Toolkit; +import java.awt.event.KeyEvent; + +import javax.swing.KeyStroke; + +import org.scilab.modules.commons.OS; + +/** + * Class to handle the keystroke and the default menu shortcut key. + */ +public final class ScilabKeyStroke { + + private static final String oSKey; + + static { + String key = ""; + int mask; + if (!GraphicsEnvironment.isHeadless()) { + mask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); + } else { + switch (OS.get()) { + case MAC: + mask = KeyEvent.META_MASK; + break; + default: + mask = KeyEvent.CTRL_MASK; + } + } + + if ((mask & KeyEvent.CTRL_MASK) != 0) { + key += " Ctrl"; + } + if ((mask & KeyEvent.META_MASK) != 0) { + key += " Meta"; + } + if ((mask & KeyEvent.SHIFT_MASK) != 0) { + key += " Shift"; + } + if ((mask & KeyEvent.ALT_MASK) != 0) { + key += " Alt"; + } + if ((mask & KeyEvent.ALT_GRAPH_MASK) != 0) { + key += " AltGraph"; + } + + if (key.length() > 0 && key.startsWith(" ")) { + key = key.substring(1); + } + + oSKey = key; + } + + /** + * Get the OS meta key: usually Ctrl for Linux or Windows OS, and Meta (Apple) for Mac OS + * @return the OS special meta key + */ + public static final String getOSMetaKey() { + return oSKey; + } + + /** + * @param key String representation of the key "control A" or + * "OSSCKEY A" where OSSCKEY is replaced by the default meta key of + * the OS. + * @return the corresponding key + */ + public static KeyStroke getKeyStroke(String key) { + String str = key.replaceAll("OSSCKEY", oSKey.toLowerCase()); + + return KeyStroke.getKeyStroke(str); + } +} diff --git a/modules/commons/src/java/org/scilab/modules/commons/gui/ScilabLAF.java b/modules/commons/src/java/org/scilab/modules/commons/gui/ScilabLAF.java new file mode 100755 index 000000000..c6127fc21 --- /dev/null +++ b/modules/commons/src/java/org/scilab/modules/commons/gui/ScilabLAF.java @@ -0,0 +1,26 @@ +/* + * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab + * Copyright (C) 2014 - Scialb Enterprises - Calixte DENIZET + * + * This file must be used under the terms of the CeCILL. + * This source file is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at + * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt + * + */ + +package org.scilab.modules.commons.gui; + +import javax.swing.AbstractButton; + +public final class ScilabLAF { + + public static void setDefaultProperties(AbstractButton button) { + if (button != null) { + button.setFocusable(false); + button.setContentAreaFilled(true); + button.setOpaque(false); + } + } +} diff --git a/modules/commons/src/java/org/scilab/modules/commons/jarsci/Handler.java b/modules/commons/src/java/org/scilab/modules/commons/jarsci/Handler.java new file mode 100755 index 000000000..1154b7c5c --- /dev/null +++ b/modules/commons/src/java/org/scilab/modules/commons/jarsci/Handler.java @@ -0,0 +1,46 @@ +/* + * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab + * Copyright (C) 2012 - Scilab Enterprises - Calixte DENIZET + * + * This file must be used under the terms of the CeCILL. + * This source file is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at + * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt + * + */ + +package org.scilab.modules.commons.jarsci; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; + +import org.scilab.modules.commons.ScilabConstants; + +/** + * A {@link URLStreamHandler} that handles images resource. + */ +public class Handler extends URLStreamHandler { + + private static String JARPATH = new File(ScilabConstants.SCI, "/modules/helptools/jar/scilab_images.jar").getAbsoluteFile().toURI().toString(); + + public Handler() { + + } + + @Override + protected URLConnection openConnection(URL u) throws IOException { + String path = u.getPath(); + if (path.startsWith("./")) { + path = path.substring(1); + } else { + path = "/" + path; + } + + URL jar = new URL("jar:" + JARPATH + "!" + path); + return jar.openConnection(); + } +} diff --git a/modules/commons/src/java/org/scilab/modules/commons/utils/BlockingResult.java b/modules/commons/src/java/org/scilab/modules/commons/utils/BlockingResult.java new file mode 100755 index 000000000..73e2e4b7c --- /dev/null +++ b/modules/commons/src/java/org/scilab/modules/commons/utils/BlockingResult.java @@ -0,0 +1,55 @@ +/* + * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab + * Copyright (C) 2008 - INRIA - Bruno JOFRET + * Copyright (C) 2012 - Scilab Enterprises - Bruno JOFRET + * + * This file must be used under the terms of the CeCILL. + * This source file is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at + * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt + * + */ + +package org.scilab.modules.commons.utils; + +/** + * Class use for dialogs that wait for a user input + * + * @author Bruno JOFRET + */ +public class BlockingResult<BlockingResultType> { + + private BlockingResultType theResult = null; + private final Object lock = new Object(); + + /** + * Get the user input (wait until it) + * + * @return the user input + */ + public BlockingResultType getResult() { + synchronized (lock) { + try { + lock.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + return theResult; + } + + /** + * Set the result for this BlockingResult and notify + * + * @param theResult + * the user input to set + */ + public void setResult(BlockingResultType theResult) { + this.theResult = theResult; + synchronized (lock) { + lock.notify(); + } + } + +} diff --git a/modules/commons/src/java/org/scilab/modules/commons/utils/StringBlockingResult.java b/modules/commons/src/java/org/scilab/modules/commons/utils/StringBlockingResult.java new file mode 100755 index 000000000..8322fd53f --- /dev/null +++ b/modules/commons/src/java/org/scilab/modules/commons/utils/StringBlockingResult.java @@ -0,0 +1,35 @@ +/* + * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab + * Copyright (C) 2008 - INRIA - Bruno JOFRET + * Copyright (C) 2012 - Scilab Enterprises - Bruno JOFRET + * + * This file must be used under the terms of the CeCILL. + * This source file is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at + * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt + * + */ + +package org.scilab.modules.commons.utils; + +/** + * Class use for dialogs that wait for a user input + * + * @author Bruno JOFRET + */ +public final class StringBlockingResult extends BlockingResult<String> { + + private static StringBlockingResult me; + + /** + * Get the current instance of BlockingResult + * @return this instance + */ + public static StringBlockingResult getInstance() { + if (me == null) { + me = new StringBlockingResult(); + } + return me; + } +} diff --git a/modules/commons/src/java/org/scilab/modules/commons/xml/ScilabDocumentBuilderFactory.java b/modules/commons/src/java/org/scilab/modules/commons/xml/ScilabDocumentBuilderFactory.java new file mode 100755 index 000000000..1ab26de11 --- /dev/null +++ b/modules/commons/src/java/org/scilab/modules/commons/xml/ScilabDocumentBuilderFactory.java @@ -0,0 +1,59 @@ +/* + * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab + * Copyright (C) 2011 - Calixte DENIZET + * + * This file must be used under the terms of the CeCILL. + * This source file is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at + * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt + * + */ + +package org.scilab.modules.commons.xml; + +import javax.xml.parsers.DocumentBuilderFactory; + +/** + * Class to provide a way to be sure that the default DocumentBuilderFactory provided by Java framework will be used. + * @author Calixte DENIZET + */ +public class ScilabDocumentBuilderFactory { + + private static final String DOCUMENTBUILDERFACTORYPROPERTY = "javax.xml.parsers.DocumentBuilderFactory"; + private static final String DOCUMENTBUILDERFACTORYIMPL = "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl"; + + /** + * Use default internal DocumentBuilderFactoryImpl + * @return the key corresponding to the currently used implementation + */ + public static String useDefaultDocumentBuilderFactoryImpl() { + String factory = System.getProperty(DOCUMENTBUILDERFACTORYPROPERTY); + System.setProperty(DOCUMENTBUILDERFACTORYPROPERTY, DOCUMENTBUILDERFACTORYIMPL); + + return factory; + } + + /** + * Restore the previous factory + * @param factory the key as returned by useDefaultDocumentBuilderFactoryImpl + */ + public static void restoreDocumentBuilderFactoryImpl(String factory) { + if (factory == null) { + System.clearProperty(DOCUMENTBUILDERFACTORYPROPERTY); + } else { + System.setProperty(DOCUMENTBUILDERFACTORYPROPERTY, factory); + } + } + + /** + * @return a new instance using the default DocumentBuilderFactory implementation + */ + public static DocumentBuilderFactory newInstance() { + String factory = useDefaultDocumentBuilderFactoryImpl(); + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + restoreDocumentBuilderFactoryImpl(factory); + + return dbf; + } +} diff --git a/modules/commons/src/java/org/scilab/modules/commons/xml/ScilabTransformerFactory.java b/modules/commons/src/java/org/scilab/modules/commons/xml/ScilabTransformerFactory.java new file mode 100755 index 000000000..a0ac6c0f9 --- /dev/null +++ b/modules/commons/src/java/org/scilab/modules/commons/xml/ScilabTransformerFactory.java @@ -0,0 +1,59 @@ +/* + * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab + * Copyright (C) 2010 - Calixte DENIZET + * + * This file must be used under the terms of the CeCILL. + * This source file is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at + * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt + * + */ + +package org.scilab.modules.commons.xml; + +import javax.xml.transform.TransformerFactory; + +/** + * Class to provide a way to be sure that the default TransformerFactory provided by Java framework will be used. + * @author Calixte DENIZET + */ +public class ScilabTransformerFactory { + + private static final String TRANSFORMERFACTORYPROPERTY = "javax.xml.transform.TransformerFactory"; + private static final String TRANSFORMERFACTORYIMPL = "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl"; + + /** + * Use default internal TransformerFactoryImpl + * @return the key corresponding to the currently used implementation + */ + public static String useDefaultTransformerFactoryImpl() { + String factory = System.getProperty(TRANSFORMERFACTORYPROPERTY); + System.setProperty(TRANSFORMERFACTORYPROPERTY, TRANSFORMERFACTORYIMPL); + + return factory; + } + + /** + * Restore the previous factory + * @param factory the key as returned by useDefaultTransformerFactoryImpl + */ + public static void restoreTransformerFactoryImpl(String factory) { + if (factory == null) { + System.clearProperty(TRANSFORMERFACTORYPROPERTY); + } else { + System.setProperty(TRANSFORMERFACTORYPROPERTY, factory); + } + } + + /** + * @return a new instance using the default TransforferFactory implementation + */ + public static TransformerFactory newInstance() { + String factory = useDefaultTransformerFactoryImpl(); + TransformerFactory tf = TransformerFactory.newInstance(); + restoreTransformerFactoryImpl(factory); + + return tf; + } +} diff --git a/modules/commons/src/java/org/scilab/modules/commons/xml/ScilabXMLUtilities.java b/modules/commons/src/java/org/scilab/modules/commons/xml/ScilabXMLUtilities.java new file mode 100755 index 000000000..a6d07603a --- /dev/null +++ b/modules/commons/src/java/org/scilab/modules/commons/xml/ScilabXMLUtilities.java @@ -0,0 +1,537 @@ +/* + * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab + * Copyright (C) 2010 - Calixte DENIZET + * + * This file must be used under the terms of the CeCILL. + * This source file is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at + * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt + * + */ + +package org.scilab.modules.commons.xml; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.TransformerFactoryConfigurationError; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import org.xml.sax.SAXException; + +import org.scilab.modules.localization.Messages; + +/** + * Class to provide different tools to manage xml. + * + * @author Calixte DENIZET + */ +public class ScilabXMLUtilities { + + private static final String ENCODING = "UTF-8"; + private static final String ERROR_WRITE = Messages.gettext("Could not save file: "); + private static final String ERROR_READ = Messages.gettext("Could not load file: "); + private static final Integer INDENTATION = new Integer(4); + + private static Transformer transformer; + + /** + * Read a xml file and parse it + * @param fileToRead the file to read + * @return the corresponding document + */ + public static Document readDocument(String fileToRead) { + Document doc = null; + try { + DocumentBuilderFactory factory = ScilabDocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder = factory.newDocumentBuilder(); + doc = docBuilder.parse(new File(fileToRead)); + } catch (ParserConfigurationException e) { + System.err.println(ERROR_READ + fileToRead); + } catch (SAXException e) { + System.err.println(ERROR_READ + fileToRead); + } catch (IOException e) { + System.err.println(ERROR_READ + fileToRead); + } + + return doc; + } + + /** + * Write a Document in a file. The empty lines are removed and the xml code is indented + * @param doc the document to write + * @param fileName the file name + */ + public static void writeDocument(Document doc, String fileName) { + if (doc != null && fileName != null) { + if (transformer == null) { + initTransformer(); + } + + if (transformer != null) { + removeEmptyLines(doc.getDocumentElement()); + + FileOutputStream fos = null; + OutputStreamWriter osw = null; + + try { + /* FileOutputStream & OutputStreamWriter are needed to be sure that + the indentation will be correct (known Java bug) */ + + fos = new FileOutputStream(fileName, false); + osw = new OutputStreamWriter(fos, ENCODING); + transformer.transform(new DOMSource(doc), new StreamResult(osw)); + } catch (FileNotFoundException e) { + System.err.println(ERROR_WRITE + fileName); + System.err.println(e); + } catch (UnsupportedEncodingException e) { + System.err.println(ERROR_WRITE + fileName); + System.err.println(e); + } catch (TransformerException e) { + System.err.println(ERROR_WRITE + fileName); + System.err.println(e); + } finally { + if (osw != null) { + try { + osw.close(); + } catch (IOException ex) { + System.err.println(ex); + } + } + } + } + } + } + + /** + * Remove empty lines which are a descendant of node + * @param node the initial node + */ + public static void removeEmptyLines(Node node) { + Set<Node> nodesToRemove = new HashSet<Node>(); + collectEmptyLines(node, nodesToRemove); + for (Node n : nodesToRemove) { + n.getParentNode().removeChild(n); + } + } + + /** + * Collect the empty lines to remove + * @param node the parent node + * @param nodesToRemove the set containing the nodes to remove + */ + private static void collectEmptyLines(Node node, Set<Node> nodesToRemove) { + if (node != null) { + NodeList list = node.getChildNodes(); + int length = getNodeListLength(list); + for (int i = 0; i < length; i++) { + Node n = list.item(i); + if (n != null) { + if (n.getNodeType() == Node.TEXT_NODE) { + nodesToRemove.add(n); + } else { + collectEmptyLines(n, nodesToRemove); + } + } + } + } + } + + /** + * Replace or create a named node with parent element + * @param doc the document + * @param parent the parent element + * @param nodeName the node name + * @param attr an array containing attribute name followed by its value: "attr1", 1, "attr2", true, ... + * @return the created element + */ + public static Element replaceNamedNode(Document doc, Element parent, String nodeName, Object[] attr) { + NodeList children = parent.getElementsByTagName(nodeName); + Element elem; + if (getNodeListLength(children) > 0) { + elem = (Element) children.item(0); + } else { + elem = doc.createElement(nodeName); + parent.appendChild(elem); + } + + for (int i = 0; i < attr.length; i += 2) { + elem.setAttribute(attr[i].toString(), attr[i + 1].toString()); + } + + return elem; + } + + /** + * Replace or create a named node with parent element + * @param doc the document + * @param parent the name of the parent element + * @param nodeName the node name + * @param attr an array containing attribute name followed by its value: "attr1", 1, "attr2", true, ... + * @return the created element + */ + public static Element replaceNamedNode(Document doc, String parent, String nodeName, Object[] attr) { + NodeList parents = doc.getDocumentElement().getElementsByTagName(parent); + if (getNodeListLength(parents) > 0) { + return replaceNamedNode(doc, (Element) parents.item(0), nodeName, attr); + } + + return null; + } + + /** + * Replace or create a named node with parent element + * @param doc the document + * @param parent the parent element + * @param nodeName the node name + * @param map a map containing {attributes -> value}, the method value.toString() will be used. + * @return the created element + */ + public static Element replaceNamedNode(Document doc, Element parent, String nodeName, Map<String, Object> map) { + NodeList children = parent.getElementsByTagName(nodeName); + Element elem; + if (getNodeListLength(children) > 0) { + elem = (Element) children.item(0); + } else { + elem = doc.createElement(nodeName); + parent.appendChild(elem); + } + + for (String name : map.keySet()) { + elem.setAttribute(name, map.get(name).toString()); + } + + return elem; + } + + /** + * Replace or create a named node with parent element + * @param doc the document + * @param parent the name of the parent element + * @param nodeName the node name + * @param map a map containing {attributes -> value}, the method value.toString() will be used. + * @return the created element + */ + public static Element replaceNamedNode(Document doc, String parent, String nodeName, Map<String, Object> map) { + NodeList parents = doc.getDocumentElement().getElementsByTagName(parent); + if (getNodeListLength(parents) > 0) { + return replaceNamedNode(doc, (Element) parents.item(0), nodeName, map); + } + + return null; + } + + /** + * Create a new node with parent element + * @param doc the document + * @param parent the parent element + * @param nodeName the node name + * @param attr an array containing attribute name followed by its value: "attr1", 1, "attr2", true, ... + * @return the created element + */ + public static Element createNode(Document doc, Element parent, String nodeName, Object[] attr) { + Element elem = doc.createElement(nodeName); + for (int i = 0; i < attr.length; i += 2) { + elem.setAttribute(attr[i].toString(), attr[i + 1].toString()); + } + parent.appendChild(elem); + + return elem; + } + + /** + * Create a new node with parent element + * @param doc the document + * @param parent the parent element + * @param nodeName the node name + * @param map a map containing {attributes -> value}, the method value.toString() will be used. + * @return the created element + */ + public static Element createNode(Document doc, Element parent, String nodeName, Map<String, Object> map) { + Element elem = doc.createElement(nodeName); + for (String name : map.keySet()) { + elem.setAttribute(name, map.get(name).toString()); + } + parent.appendChild(elem); + + return elem; + } + + /** + * Read the attributes of elem. + * Map must be like this: "attr1" -> integer.class, "attr2" -> boolean.class, ... + * Map will be filled with the value (as Object) of the different attributes + * @param elem the element to analyze + * @param map the map containing the attributes type. + */ + public static void readNodeAttributes(Element elem, Map<String, Object> map) { + NamedNodeMap attrMap = elem.getAttributes(); + for (int i = 0; i < attrMap.getLength(); i++) { + Attr attr = (Attr) attrMap.item(i); + String key = attr.getName(); + if (map.containsKey(key)) { + map.put(key, convert(attr.getValue(), (Class) map.get(key))); + } + } + } + + /** + * Read the attributes of elem. + * Map must be like this: Object[]{"attr1", integer.class, "attr2", boolean.class, ...} + * Map will be filled with the value (as Object) of the different attributes + * @param elem the element to analyze + * @param map the map containing the attributes type. + */ + public static void readNodeAttributes(Element elem, Object[] map) { + NamedNodeMap attrMap = elem.getAttributes(); + for (int i = 0; i < attrMap.getLength(); i++) { + Attr attr = (Attr) attrMap.item(i); + String key = attr.getName(); + for (int j = 0; j < map.length; j += 2) { + if (map[j].equals(key)) { + map[j + 1] = convert(attr.getValue(), (Class) map[j + 1]); + } + } + } + } + + /** + * Read the attributes of first element named nodeName in the document. + * Map must be like this: "attr1" -> integer.class, "attr2" -> boolean.class, ... + * Map will be filled with the value (as Object) of the different attributes + * @param doc the document + * @param nodeName the node name + * @param map the map containing the attributes type. + * @return the corresponding element or null if it doesn't exist + */ + public static Element readNodeAttributes(Document doc, String nodeName, Map<String, Object> map) { + NodeList list = doc.getDocumentElement().getElementsByTagName(nodeName); + if (getNodeListLength(list) > 0) { + Node n = list.item(0); + if (n instanceof Element) { + readNodeAttributes((Element) n, map); + return (Element) n; + } + } + + return null; + } + + /** + * Read the attributes of first element named nodeName in the document. + * Map must be like this: Object[]{"attr1", integer.class, "attr2", boolean.class, ...} + * Map will be filled with the value (as Object) of the different attributes + * @param doc the document + * @param nodeName the node name + * @param map the map containing the attributes type. + * @return the corresponding element or null if it doesn't exist + */ + public static Element readNodeAttributes(Document doc, String nodeName, Object[] map) { + NodeList list = doc.getDocumentElement().getElementsByTagName(nodeName); + if (getNodeListLength(list) > 0) { + Node n = list.item(0); + if (n instanceof Element) { + readNodeAttributes((Element) n, map); + return (Element) n; + } + } + + return null; + } + + /** + * Retrieve the list of the elements which have an attribute equal to the given value. + * @param root the root element + * @param attribute the attribute name + * @param value the value + * @return the list + */ + public static List<Element> getElementsWithAttributeEquals(Element root, String attribute, String value) { + List<Element> list = new ArrayList<Element>(); + getElementsWithAttributeEquals(root, attribute, value, list); + + return list; + } + + /** + * Retrieve the list of the elements which have an attribute equal to the given value (recursive function). + * @param root the root element + * @param attribute the attribute name + * @param value the value + * @param list the list to fill + */ + private static final void getElementsWithAttributeEquals(Element root, String attribute, String value, List<Element> list) { + if (root.getAttribute(attribute).equals(value)) { + list.add(root); + } + if (root.hasChildNodes()) { + NodeList nodes = root.getChildNodes(); + int length = nodes.getLength(); + for (int i = 0; i < length; i++) { + Node node = nodes.item(i); + if (node instanceof Element) { + Element elem = (Element) nodes.item(i); + getElementsWithAttributeEquals(elem, attribute, value, list); + } + } + } + } + + /** + * Convert a value (as String) into an object according to its class type giving in clazz + * @param value the value to convert + * @param clazz the class type of the value + * @return the converted object + */ + private static final Object convert(String value, Class clazz) { + if (clazz == int.class) { + return Integer.parseInt(value); + } else if (clazz == float.class) { + return Float.parseFloat(value); + } else if (clazz == boolean.class) { + return Boolean.parseBoolean(value); + } else if (clazz == double.class) { + return Double.parseDouble(value); + } else if (clazz == short.class) { + return Short.parseShort(value); + } else if (clazz == long.class) { + return Long.parseLong(value); + } else if (clazz == byte.class) { + return Byte.parseByte(value); + } else if (clazz == char.class) { + return value.length() == 0 ? '\0' : value.charAt(0); + } else if (clazz == String[].class) { + return getArray(value, ";"); + } + + return value; + } + + /** + * Get an array from a string containing strings separated with a delimitor + * @param value the string to parse + * @param delimitor the delimitor + * @return an array of String + */ + private static final String[] getArray(String value, String delimitor) { + StringTokenizer tokens = new StringTokenizer(value, delimitor); + String[] arr = new String[tokens.countTokens()]; + for (int i = 0; i < arr.length; i++) { + arr[i] = tokens.nextToken(); + } + + return arr; + } + + /** + * Init the transformer + */ + private static final void initTransformer() { + try { + TransformerFactory factory = ScilabTransformerFactory.newInstance(); + factory.setAttribute("indent-number", INDENTATION); + transformer = factory.newTransformer(); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); + transformer.setOutputProperty(OutputKeys.ENCODING, ENCODING); + } catch (TransformerConfigurationException e) { + System.err.println("Problem to init the Transformer to write xml files"); + System.err.println(e); + } catch (TransformerFactoryConfigurationError e) { + System.err.println("Problem to init the Transformer to write xml files"); + System.err.println(e); + } + } + + /** + * @param list a node list + * @return the length + */ + private static int getNodeListLength(NodeList list) { + int length = 0; + try { + length = list.getLength(); + } catch (NullPointerException e) { + /* Avoid Java bug */ + } + return length; + } + + /** + * Replace classical XML reserved chars by their XML equivalent entities + * @param str the String to parse and transform + * @return a String with the XML entities. + */ + public static String getXMLString(String str) { + if (str != null && !str.isEmpty()) { + StringBuilder buf = new StringBuilder(); + char[] chars = str.toCharArray(); + int last = 0; + for (int i = 0; i < chars.length; i++) { + switch (chars[i]) { + case '\'' : + buf.append(chars, last, i - last).append("'"); + last = i + 1; + break; + case '\"' : + buf.append(chars, last, i - last).append("""); + last = i + 1; + break; + case '<' : + buf.append(chars, last, i - last).append("<"); + last = i + 1; + break; + case '>' : + buf.append(chars, last, i - last).append(">"); + last = i + 1; + break; + case '&' : + buf.append(chars, last, i - last).append("&"); + last = i + 1; + break; + default : + break; + } + } + + if (last == 0) { + return str; + } + + if (last < chars.length) { + buf.append(chars, last, chars.length - last); + } + + return buf.toString(); + } + + return str; + } +} diff --git a/modules/commons/src/java/org/scilab/modules/commons/xml/XConfiguration.java b/modules/commons/src/java/org/scilab/modules/commons/xml/XConfiguration.java new file mode 100755 index 000000000..1c6c8f01d --- /dev/null +++ b/modules/commons/src/java/org/scilab/modules/commons/xml/XConfiguration.java @@ -0,0 +1,902 @@ +/* + * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab + * Copyright (C) 2012 - Scilab Enterprises - Calixte DENIZET + * + * This file must be used under the terms of the CeCILL. + * This source file is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at + * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt + * + */ + +package org.scilab.modules.commons.xml; + +import java.awt.Color; +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FilenameFilter; +import java.io.FileFilter; +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.HashSet; +import java.util.Set; + +import javax.swing.KeyStroke; +import javax.swing.event.EventListenerList; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactoryConfigurationError; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; + +import org.xml.sax.SAXException; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import org.scilab.modules.commons.ScilabConstants; +import org.scilab.modules.commons.ScilabGeneralPrefs; +import org.scilab.modules.commons.gui.ScilabKeyStroke; +import org.scilab.modules.localization.Messages; + +/** + * Class to retrieve object from the xml configuration file + * + * @author Calixte DENIZET + * + */ +public class XConfiguration { + + // User configuration file + private static final String SCI = System.getenv("SCI"); + private static final String SCILAB_CONFIG_FILE = SCI + "/modules/preferences/etc/XConfiguration.xml"; + + private static final String ERROR_READ = Messages.gettext("Could not load file: "); + private static final String ERROR_WRITE = Messages.gettext("Could not write the file: "); + private static final String SEVERE_ERROR = Messages.gettext("A severe error occurred: cannot load the preferences file."); + private static final String PARSING_ERROR = Messages.gettext("An error occurred when loading the preferences file, try to reload the default one."); + + private static final XPathFactory xpathFactory = XPathFactory.newInstance(); + private static final Map < Class<?>, StringParser > conv = new HashMap < Class<?>, StringParser > (); + + private static final EventListenerList listenerList = new EventListenerList(); + private static final Set<String> modifiedPaths = new HashSet<String>(); + + private static Document doc; + private static boolean hasBeenRead; + private static boolean mustSave = true;; + private static String USER_CONFIG_FILE = ScilabConstants.SCIHOME.toString() + "/XConfiguration.xml"; + + static { + if (ScilabConstants.SCIHOME != null && ScilabConstants.SCIHOME.canRead() && ScilabConstants.SCIHOME.canWrite()) { + USER_CONFIG_FILE = ScilabConstants.SCIHOME.toString() + "/XConfiguration.xml"; + } else { + USER_CONFIG_FILE = SCILAB_CONFIG_FILE; + mustSave = false; + } + + addXConfigurationListener(ScilabGeneralPrefs.getInstance()); + + try { + Class histoprefs = ClassLoader.getSystemClassLoader().loadClass("org.scilab.modules.history_manager.HistoryPrefs"); + Method getinstance = histoprefs.getDeclaredMethod("getInstance"); + addXConfigurationListener((XConfigurationListener)getinstance.invoke(null)); + } catch (ClassNotFoundException e) { + // Nothing displayed (always occurs in MN mode) + } catch (Exception e) { + System.err.println(e); + } + } + + /** + * Get the document in SCIHOME corresponding to the configuration file. + * @return the configuration document. + */ + public static Document getXConfigurationDocument() { + if (doc == null) { + boolean error = false; + File xml = new File(USER_CONFIG_FILE); + if (!xml.exists() && mustSave) { + ScilabXMLUtilities.writeDocument(createDocument(), USER_CONFIG_FILE); + } + + DocumentBuilder docBuilder = null; + + if (mustSave) { + try { + DocumentBuilderFactory factory = ScilabDocumentBuilderFactory.newInstance(); + docBuilder = factory.newDocumentBuilder(); + doc = docBuilder.parse(xml); + float version = getDocumentVersion(doc); + float defaultVersion = getDocumentVersion(getDefaultDocument()); + if (defaultVersion != version) { + xml.delete(); + doc = null; + return getXConfigurationDocument(); + } else { + return doc; + } + } catch (ParserConfigurationException pce) { + error = true; + } catch (SAXException se) { + error = true; + } catch (IOException ioe) { + error = true; + } + + if (error) { + if (hasBeenRead) { + System.err.println(SEVERE_ERROR); + doc = null; + xml.delete(); + return docBuilder.newDocument(); + } + + hasBeenRead = true; + doc = null; + xml.delete(); + System.err.println(PARSING_ERROR); + return getXConfigurationDocument(); + } + + return docBuilder.newDocument(); + } else { + doc = createDocument(); + } + } + + return doc; + } + + /** + * Save the modifications + */ + public static void writeDocument(String filename, Node written) { + if (mustSave) { + Transformer transformer = null; + try { + transformer = ScilabTransformerFactory.newInstance().newTransformer(); + } catch (TransformerConfigurationException e1) { + System.err.println(ERROR_WRITE + filename); + return; + } catch (TransformerFactoryConfigurationError e1) { + System.err.println(ERROR_WRITE + filename); + return; + } + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + + StreamResult result = new StreamResult(new File(filename)); + DOMSource source = new DOMSource(written); + try { + transformer.transform(source, result); + } catch (TransformerException e) { + System.err.println(ERROR_WRITE + filename); + return; + } + + // Invalidate the current document + if (filename.equals(USER_CONFIG_FILE)) { + doc = null; + } + } + } + + /** + * Save the modifications + */ + public static String dumpNode(Node written) { + Transformer transformer = null; + try { + transformer = ScilabTransformerFactory.newInstance().newTransformer(); + } catch (TransformerConfigurationException e1) { + System.err.println("Cannot dump xml"); + return ""; + } catch (TransformerFactoryConfigurationError e1) { + System.err.println("Cannot dump xml"); + return ""; + } + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + StreamResult result = new StreamResult(new BufferedOutputStream(stream)); + DOMSource source = new DOMSource(written); + String str = ""; + try { + transformer.transform(source, result); + str = stream.toString(); + } catch (TransformerException e) { + System.err.println("Cannot dump xml"); + return str; + } finally { + try { + stream.close(); + } catch (Exception e) { } + } + + return str; + } + + /** + * Get the document version + * @param doc the document + * @return the version + */ + private static float getDocumentVersion(Document doc) { + if (doc != null) { + Element root = doc.getDocumentElement(); + String version = root.getAttribute("version"); + + try { + return Float.parseFloat(version); + } catch (NumberFormatException e) { } + } + + return 0.0f; + } + + /** + * Get the default document + * @return the document + */ + private static Document getDefaultDocument() { + DocumentBuilder docBuilder; + DocumentBuilderFactory factory; + Document mainDoc = null; + + try { + factory = ScilabDocumentBuilderFactory.newInstance(); + docBuilder = factory.newDocumentBuilder(); + mainDoc = docBuilder.parse(SCILAB_CONFIG_FILE); + } catch (ParserConfigurationException pce) { + System.err.println("Cannot create a XML DocumentBuilder:\n" + pce); + return null; + } catch (SAXException se) { + System.err.println("Weird... Cannot parse basic file:\n" + se); + return null; + } catch (IOException ioe) { + System.err.println("Weird... Cannot parse basic file:\n" + ioe); + return null; + } + + return mainDoc; + } + + /** + * Create a document in using the XConfiguration-*.xml found in SCI/modules/MODULE_NAME/etc/ + * @return the built document + */ + public static Document createDocument() { + DocumentBuilder docBuilder; + DocumentBuilderFactory factory; + Document mainDoc = getDefaultDocument(); + if (mainDoc == null) { + return null; + } + + Element root = mainDoc.getDocumentElement(); + + factory = ScilabDocumentBuilderFactory.newInstance(); + + try { + docBuilder = factory.newDocumentBuilder(); + } catch (ParserConfigurationException pce) { + System.err.println("Cannot create a XML DocumentBuilder:\n" + pce); + return null; + } + + List<File> etcs = getEtcDir(); + for (File etc : etcs) { + File[] xmls = etc.listFiles(new FilenameFilter() { + public boolean accept(File dir, String name) { + return name.endsWith(".xml") && name.startsWith("XConfiguration-"); + } + }); + for (File xml : xmls) { + try { + Document doc = docBuilder.parse(xml); + if (xml.getName().equals("XConfiguration-general.xml")) { + try { + XPath xp = xpathFactory.newXPath(); + NodeList nodes = (NodeList) xp.compile("//shortcuts/body/actions/action-folder/action[contains(@key, 'OSSCKEY')]").evaluate(doc, XPathConstants.NODESET); + for (int i = 0; i < nodes.getLength(); i++) { + Element e = (Element) nodes.item(i); + e.setAttribute("key", e.getAttribute("key").replace("OSSCKEY", ScilabKeyStroke.getOSMetaKey())); + } + } catch (XPathExpressionException e) { + System.err.println(e); + } + } + Node node = mainDoc.importNode(doc.getDocumentElement(), true); + NodeList list = root.getElementsByTagName(node.getNodeName()); + if (list.getLength() != 0) { + root.replaceChild(node, list.item(0)); + } + } catch (SAXException se) { + System.err.println(ERROR_READ + xml.getName()); + } catch (IOException ioe) { + System.err.println(ERROR_READ + xml.getName()); + } + } + } + + return mainDoc; + } + + /** + * Get the list of the etc dirs in modules dirs + * @return the lit of etc dirs + */ + public static List<File> getEtcDir() { + List<File> list = new ArrayList<File>(); + File modulesDir = new File(SCI + "/modules/"); + File[] modules = modulesDir.listFiles(new FileFilter() { + public boolean accept(File f) { + return f.isDirectory(); + } + }); + + for (File module : modules) { + File etc = new File(module, "/etc/"); + if (etc.exists() && etc.isDirectory()) { + list.add(etc); + } + } + + return list; + } + + public static void addModifiedPath(String path) { + if (path != null && !path.isEmpty()) { + modifiedPaths.add(path); + } + } + + public static void invalidate() { + modifiedPaths.clear(); + doc = null; + } + + public static void addXConfigurationListener(XConfigurationListener listener) { + listenerList.add(XConfigurationListener.class, listener); + } + + public static void removeXConfigurationListener(XConfigurationListener listener) { + listenerList.remove(XConfigurationListener.class, listener); + } + + public static XConfigurationListener[] getXConfigurationListeners() { + return listenerList.getListeners(XConfigurationListener.class); + } + + public static void fireXConfigurationEvent() { + if (!modifiedPaths.isEmpty()) { + XConfigurationEvent event = null; + Object[] listeners = listenerList.getListenerList(); + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == XConfigurationListener.class) { + if (event == null) { + event = new XConfigurationEvent(modifiedPaths); + } + ((XConfigurationListener) listeners[i + 1]).configurationChanged(event); + } + } + + modifiedPaths.clear(); + } + } + + /** + * Register a StringParser for a given Class + * @param type the class type + * @param parser the StringParser + */ + public static void registerStringParser(Class<?> type, StringParser parser) { + conv.put(type, parser); + } + + /** + * Get a StringParser for a given Class + * @param type the class type + * @return the corresponding parser + */ + public static StringParser getStringParser(Class<?> type) { + return conv.get(type); + } + + public static void set(final Document doc, final String path, String value) { + XPath xp = xpathFactory.newXPath(); + NodeList nodes; + try { + nodes = (NodeList) xp.compile(path).evaluate(doc, XPathConstants.NODESET); + } catch (XPathExpressionException e) { + System.err.println(e); + return; + } + + for (int i = 0; i < nodes.getLength() ; i++) { + Node n = nodes.item(i); + if (n != null && n.getNodeType() == Node.ATTRIBUTE_NODE) { + n.setNodeValue(value); + } + } + + writeDocument(USER_CONFIG_FILE, doc); + } + + /** + * Save the current file + */ + public static void save() { + if (doc != null) { + writeDocument(USER_CONFIG_FILE, doc); + } + } + + /** + * Get all the nodes with the given path. + * All the get nodes are serialized into an object (generic paramater) which must have + * a constructor without argument and with methods named set<Attribute Name> with + * one argument and no returned value. + * For example a node <foo aaa="1" bbb="true" ccc-ddd="#001122"/> could be retrieved with something like + * XConfiguration.get(MyObject.class, doc, "//path/to/node") where MyObject should be something like + * <code> + * public class MyObject { + * + * public MyObject() { + * // ... + * } + * + * public void setAaa(int a) { + * // ... + * } + * + * public void setBbb(boolean b) { + * // ... + * } + * + * public void setCccDdd(Color c) { + * // ... + * } + * } + * </code> + * If an attribute must not be retrieved, just remove the setter. + * + * It is possible to use the annotation @XConfAttribute to make easier the retrievement. + * For example + * <code> + * @XConfAttribute + * public class MyObject { + * + * public MyObject() { + * // ... + * } + * + * @XConfAttribute(attributes={"aaa", "bbb", "ccc-ddd"}) + * // the contents of aaa will be converted into int and passed as first argument + * // the contents of bbb will be converted into boolean and passed as second argument + * // the contents of ccc-ddd will be converted into Color and passed as third argument + * public void set(int n, boolean b, Color c) { + * // ... + * } + * } + * </code> + * + * @param type the Class type to retrieve + * @param doc the document to explore + * @param path the xpath query to retrieve the corresponding nodeset. + * @return an array of instance of class type. + */ + public static final <T> T[] get(final Class<T> type, final Document doc, final String path) { + XPath xp = xpathFactory.newXPath(); + NodeList nodes; + try { + nodes = (NodeList) xp.compile(path).evaluate(doc, XPathConstants.NODESET); + } catch (XPathExpressionException e) { + System.err.println(e); + return (T[]) Array.newInstance(type, 0); + } + + if (type.getAnnotation(XConfAttribute.class) != null) { + T[] arr = get(type, nodes); + if (arr != null) { + return arr; + } + } + + Method[] meths = type.getDeclaredMethods(); + Map<String, Method> mapMethods = new HashMap<String, Method>(); + for (Method m : meths) { + String name = m.getName(); + if (name.startsWith("set") && m.getParameterTypes().length == 1 && m.getReturnType().equals(Void.TYPE)) { + mapMethods.put(m.getName(), m); + m.setAccessible(true); + } + } + + Map<String, String> names = new HashMap<String, String>(); + + T[] values = (T[]) Array.newInstance(type, nodes.getLength()); + for (int i = 0; i < values.length; i++) { + NamedNodeMap map = nodes.item(i).getAttributes(); + try { + Constructor<T> constructor = type.getDeclaredConstructor(new Class[] {}); + constructor.setAccessible(true); + values[i] = constructor.newInstance(); + } catch (InstantiationException e) { + System.err.println(e); + break; + } catch (IllegalAccessException e) { + System.err.println(e); + break; + } catch (NoSuchMethodException e) { + System.err.println(e); + break; + } catch (InvocationTargetException e) { + System.err.println(e.getTargetException()); + } + + for (int j = 0; j < map.getLength(); j++) { + Node n = map.item(j); + String name = n.getNodeName(); + String methName = names.get(name); + if (methName == null) { + StringBuilder buffer = new StringBuilder("set"); + String[] parts = name.split("-"); + for (String part : parts) { + if (part != null && part.length() > 0) { + buffer.append(part.substring(0, 1).toUpperCase()); + buffer.append(part.substring(1).toLowerCase()); + } + } + methName = buffer.toString(); + names.put(name, methName); + } + String value = n.getNodeValue(); + Method method = mapMethods.get(methName); + if (method != null) { + Class[] paramsClass = method.getParameterTypes(); + StringParser parser = conv.get(paramsClass[0]); + if (parser != null) { + Object[] params = new Object[] {parser.parse(value)}; + try { + method.invoke(values[i], params); + } catch (IllegalAccessException e) { + System.err.println(e); + } catch (IllegalArgumentException e) { + System.err.println(e); + } catch (InvocationTargetException e) { + System.err.println(e.getTargetException()); + } + } + } + } + } + + return values; + } + + /** + * Get a Map with where the key is the converted value (according to keyType) of the attribute named key + * and the value is given in the same way. + * @param doc the document to read + * @param key the attribute name where its value will be converted and used as a key in the map + * @param keyType the Class of the key + * @param value the attribute name where its value will be converted and used as a value in the map + * @param valueType the Class of the value + * @return the corresponding map. + */ + public static final <T, U> Map<T, U> get(final Document doc, final String key, final Class<T> keyType, final String value, final Class<U> valueType, final String path) { + XPath xp = xpathFactory.newXPath(); + Map<T, U> map = new HashMap<T, U>(); + NodeList nodes; + try { + nodes = (NodeList) xp.compile(path).evaluate(doc, XPathConstants.NODESET); + } catch (XPathExpressionException e) { + System.err.println(e); + return map; + } + + int len = nodes.getLength(); + for (int i = 0; i < len; i++) { + NamedNodeMap nmap = nodes.item(i).getAttributes(); + Node k = nmap.getNamedItem(key); + Node v = nmap.getNamedItem(value); + if (k == null || v == null) { + return map; + } + + String kk = k.getNodeValue(); + String vv = v.getNodeValue(); + + StringParser convK = conv.get(keyType); + StringParser convV = conv.get(valueType); + if (convK == null || convV == null) { + return map; + } + + map.put((T) convK.parse(kk), (U) convV.parse(vv)); + } + + return map; + } + + /** + * Getter for annoted class (with @XConfAttribute) + * @param type the class type + * @param nodes the nodes to read + * @return an array of instances of type, if the class is annoted with @XConfAttribute(isStatic=true), + * the returned array is empty. + */ + private static final <T> T[] get(final Class<T> type, NodeList nodes) { + Method[] meths = type.getDeclaredMethods(); + List<String[]> attrs = new ArrayList<String[]>(); + List<Method> methods = new ArrayList<Method>(); + Map<String[], Method> mapMethods = new HashMap<String[], Method>(); + for (Method m : meths) { + String name = m.getName(); + Annotation ann = m.getAnnotation(XConfAttribute.class); + if (ann != null) { + String[] attributes = ((XConfAttribute) ann).attributes(); + if (attributes.length == m.getParameterTypes().length) { + m.setAccessible(true); + attrs.add(attributes); + methods.add(m); + } else { + return null; + } + } + } + + Annotation ann = type.getAnnotation(XConfAttribute.class); + boolean mustInstantiate = !((XConfAttribute) ann).isStatic(); + + T[] values = null; + int len = nodes.getLength(); + if (mustInstantiate) { + values = (T[]) Array.newInstance(type, len); + } + + for (int i = 0; i < len; i++) { + NamedNodeMap map = nodes.item(i).getAttributes(); + String nodeName = nodes.item(i).getNodeName(); + + if (mustInstantiate) { + try { + Constructor<T> constructor = type.getDeclaredConstructor(new Class[] {}); + constructor.setAccessible(true); + values[i] = constructor.newInstance(); + } catch (InstantiationException e) { + System.err.println(e); + break; + } catch (IllegalAccessException e) { + System.err.println(e); + break; + } catch (NoSuchMethodException e) { + System.err.println(e); + break; + } catch (InvocationTargetException e) { + System.err.println(e.getTargetException()); + } + } + + for (int j = 0; j < methods.size(); j++) { + Method method = methods.get(j); + ann = method.getAnnotation(XConfAttribute.class); + String tag = ((XConfAttribute) ann).tag(); + if (tag.isEmpty() || tag.equals(nodeName)) { + String[] attributes = attrs.get(j); + Object[] params = new Object[attributes.length]; + Class[] paramsClass = method.getParameterTypes(); + for (int k = 0; k < attributes.length; k++) { + String p = ""; + Node node = null; + if (map != null) { + node = map.getNamedItem(attributes[k]); + } + if (node != null) { + p = node.getNodeValue(); + } + + StringParser parser = conv.get(paramsClass[k]); + if (parser != null) { + params[k] = parser.parse(p); + } + } + + try { + if (mustInstantiate) { + method.invoke(values[i], params); + } else { + method.invoke(null, params); + } + } catch (IllegalAccessException e) { + System.err.println(e); + } catch (IllegalArgumentException e) { + System.err.println(e); + } catch (InvocationTargetException e) { + System.err.println(e.getTargetException()); + } + } + } + } + + if (mustInstantiate) { + return values; + } else { + return (T[]) Array.newInstance(type, 0); + } + } + + /** + * Interface to implement to parse an attribute String into a Java object + */ + public static interface StringParser { + + /** + * Parse a string + * @param str the string to parse + * @return the corresponding Object + */ + public Object parse(String str); + } + + static { + conv.put(int.class, new StringParser() { + public Integer parse(String str) { + try { + return Integer.parseInt(str); + } catch (NumberFormatException e) { + try { + return (int) Double.parseDouble(str); + } catch (NumberFormatException ee) { + return new Integer(0); + } + } + } + }); + conv.put(char.class, new StringParser() { + public Object parse(String str) { + if (str.length() > 0) { + return str.charAt(0); + } else { + return new Character((char) 0); + } + } + }); + conv.put(byte.class, new StringParser() { + public Object parse(String str) { + try { + return Byte.parseByte(str); + } catch (NumberFormatException e) { + try { + return (byte) Double.parseDouble(str); + } catch (NumberFormatException ee) { + return new Byte((byte) 0); + } + } + } + }); + conv.put(short.class, new StringParser() { + public Object parse(String str) { + try { + return Short.parseShort(str); + } catch (NumberFormatException e) { + try { + return (short) Double.parseDouble(str); + } catch (NumberFormatException ee) { + return new Short((short) 0); + } + } + } + }); + conv.put(double.class, new StringParser() { + public Object parse(String str) { + try { + return Double.parseDouble(str); + } catch (NumberFormatException ee) { + return new Double((double) 0); + } + } + }); + conv.put(float.class, new StringParser() { + public Object parse(String str) { + try { + return Float.parseFloat(str); + } catch (NumberFormatException ee) { + return new Float((float) 0); + } + } + }); + conv.put(boolean.class, new StringParser() { + public Object parse(String str) { + return Boolean.parseBoolean(str); + } + }); + conv.put(long.class, new StringParser() { + public Object parse(String str) { + try { + return Long.parseLong(str); + } catch (NumberFormatException e) { + try { + return (long) Double.parseDouble(str); + } catch (NumberFormatException ee) { + return new Long((long) 0); + } + } + } + }); + conv.put(String.class, new StringParser() { + public Object parse(String str) { + return str; + } + }); + conv.put(Color.class, new StringParser() { + public Object parse(String str) { + try { + return Color.decode(str); + } catch (NumberFormatException e) { + return Color.BLACK; + } + } + }); + conv.put(KeyStroke.class, new StringParser() { + public Object parse(String str) { + String[] toks = str.split(" +"); + StringBuilder buffer = new StringBuilder(); + for (int i = 0; i < toks.length - 1; i++) { + buffer.append(toks[i].toLowerCase()); + buffer.append(" "); + } + buffer.append(toks[toks.length - 1].toUpperCase()); + return KeyStroke.getKeyStroke(buffer.toString()); + } + }); + } + + @Retention(RetentionPolicy.RUNTIME) + public @interface XConfAttribute { + + /** + * Map method arguments with attributes name + * For example, + * <code> + * @XConfAttribute(tag="mytag", attributes={"a", "b"}) + * void foo(String one, int tow) { ... } + * </code> + * The value of attribute "a" is converted into a String and passed as "one" argument,... + */ + public String[] attributes() default { + "" + }; + + public String tag() default ""; + + /** + * Used to avoid object instanciation so the differents annotated methods must be static. + */ + public boolean isStatic() default false; + } +} diff --git a/modules/commons/src/java/org/scilab/modules/commons/xml/XConfigurationEvent.java b/modules/commons/src/java/org/scilab/modules/commons/xml/XConfigurationEvent.java new file mode 100755 index 000000000..68aa8808b --- /dev/null +++ b/modules/commons/src/java/org/scilab/modules/commons/xml/XConfigurationEvent.java @@ -0,0 +1,36 @@ +/* + * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab + * Copyright (C) 2012 - Scilab Enterprises - Calixte DENIZET + * + * This file must be used under the terms of the CeCILL. + * This source file is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at + * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt + * + */ + +package org.scilab.modules.commons.xml; + +import java.util.Set; + +public class XConfigurationEvent { + + private Set<String> changedPaths; + + /** + * Default constructor + * @param changedPaths a set containing all the paths which have been modified + */ + public XConfigurationEvent(Set<String> changedPaths) { + this.changedPaths = changedPaths; + } + + /** + * Get the modified paths + * @return the modified paths as a set + */ + public Set<String> getModifiedPaths() { + return changedPaths; + } +}
\ No newline at end of file diff --git a/modules/commons/src/java/org/scilab/modules/commons/xml/XConfigurationListener.java b/modules/commons/src/java/org/scilab/modules/commons/xml/XConfigurationListener.java new file mode 100755 index 000000000..06c41e219 --- /dev/null +++ b/modules/commons/src/java/org/scilab/modules/commons/xml/XConfigurationListener.java @@ -0,0 +1,26 @@ +/* + * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab + * Copyright (C) 2012 - Scilab Enterprises - Calixte DENIZET + * + * This file must be used under the terms of the CeCILL. + * This source file is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at + * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt + * + */ + +package org.scilab.modules.commons.xml; + +import java.util.EventListener; + +public interface XConfigurationListener extends EventListener { + + /** + * Prevent the listener that configuration has changed + * + * @param e the event + */ + public void configurationChanged(XConfigurationEvent e); + +} |