summaryrefslogtreecommitdiff
path: root/modules/commons/src/java
diff options
context:
space:
mode:
Diffstat (limited to 'modules/commons/src/java')
-rwxr-xr-xmodules/commons/src/java/org/scilab/modules/commons/CommonFileUtils.java38
-rwxr-xr-xmodules/commons/src/java/org/scilab/modules/commons/CommonFileUtilsJNI.java49
-rwxr-xr-xmodules/commons/src/java/org/scilab/modules/commons/OS.java79
-rwxr-xr-xmodules/commons/src/java/org/scilab/modules/commons/ScilabCommons.java125
-rwxr-xr-xmodules/commons/src/java/org/scilab/modules/commons/ScilabCommonsJNI.java61
-rwxr-xr-xmodules/commons/src/java/org/scilab/modules/commons/ScilabCommonsUtils.java187
-rwxr-xr-xmodules/commons/src/java/org/scilab/modules/commons/ScilabConstants.java93
-rwxr-xr-xmodules/commons/src/java/org/scilab/modules/commons/ScilabGeneralPrefs.java137
-rwxr-xr-xmodules/commons/src/java/org/scilab/modules/commons/gui/FindIconHelper.java320
-rwxr-xr-xmodules/commons/src/java/org/scilab/modules/commons/gui/ScilabCaret.java183
-rwxr-xr-xmodules/commons/src/java/org/scilab/modules/commons/gui/ScilabGUIUtilities.java51
-rwxr-xr-xmodules/commons/src/java/org/scilab/modules/commons/gui/ScilabKeyStroke.java87
-rwxr-xr-xmodules/commons/src/java/org/scilab/modules/commons/gui/ScilabLAF.java26
-rwxr-xr-xmodules/commons/src/java/org/scilab/modules/commons/jarsci/Handler.java46
-rwxr-xr-xmodules/commons/src/java/org/scilab/modules/commons/utils/BlockingResult.java55
-rwxr-xr-xmodules/commons/src/java/org/scilab/modules/commons/utils/StringBlockingResult.java35
-rwxr-xr-xmodules/commons/src/java/org/scilab/modules/commons/xml/ScilabDocumentBuilderFactory.java59
-rwxr-xr-xmodules/commons/src/java/org/scilab/modules/commons/xml/ScilabTransformerFactory.java59
-rwxr-xr-xmodules/commons/src/java/org/scilab/modules/commons/xml/ScilabXMLUtilities.java537
-rwxr-xr-xmodules/commons/src/java/org/scilab/modules/commons/xml/XConfiguration.java902
-rwxr-xr-xmodules/commons/src/java/org/scilab/modules/commons/xml/XConfigurationEvent.java36
-rwxr-xr-xmodules/commons/src/java/org/scilab/modules/commons/xml/XConfigurationListener.java26
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 -&gt; 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 -&gt; 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 -&gt; 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" -&gt; integer.class, "attr2" -&gt; 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" -&gt; integer.class, "attr2" -&gt; 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("&apos;");
+ last = i + 1;
+ break;
+ case '\"' :
+ buf.append(chars, last, i - last).append("&quot;");
+ last = i + 1;
+ break;
+ case '<' :
+ buf.append(chars, last, i - last).append("&lt;");
+ last = i + 1;
+ break;
+ case '>' :
+ buf.append(chars, last, i - last).append("&gt;");
+ last = i + 1;
+ break;
+ case '&' :
+ buf.append(chars, last, i - last).append("&amp;");
+ 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&lt;Attribute Name&gt; with
+ * one argument and no returned value.
+ * For example a node &lt;foo aaa="1" bbb="true" ccc-ddd="#001122"/&gt; 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);
+
+}