/*FreeMind - A Program for creating and viewing Mindmaps *Copyright (C) 2000-2006 Joerg Mueller, Daniel Polansky, Christian Foltin and others. * *See COPYING for Details * *This program is free software; you can redistribute it and/or *modify it under the terms of the GNU General Public License *as published by the Free Software Foundation; either version 2 *of the License, or (at your option) any later version. * *This program is distributed in the hope that it will be useful, *but WITHOUT ANY WARRANTY; without even the implied warranty of *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *GNU General Public License for more details. * *You should have received a copy of the GNU General Public License *along with this program; if not, write to the Free Software *Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Created on 10.01.2006 */ /*$Id: FreeMindCommon.java,v 1.1.2.2.2.39 2009/05/18 19:47:57 christianfoltin Exp $*/ package freemind.main; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.net.URLDecoder; import java.util.Enumeration; import java.util.Locale; import java.util.Properties; import java.util.PropertyResourceBundle; import java.util.ResourceBundle; import java.util.logging.Logger; /** * @author foltin * */ public class FreeMindCommon { public static final String FREEMIND_FILE_EXTENSION_WITHOUT_DOT = "mm"; public static final String FREEMIND_FILE_EXTENSION = "." + FREEMIND_FILE_EXTENSION_WITHOUT_DOT; public static final String POSTFIX_TRANSLATE_ME = "[translate me]"; private class FreeMindResourceBundle extends ResourceBundle { private PropertyResourceBundle languageResources; private PropertyResourceBundle defaultResources; FreeMindResourceBundle() { try { String lang = getProperty(RESOURCE_LANGUAGE); if (lang == null || lang.equals("automatic")) { lang = Locale.getDefault().getLanguage() + "_" + Locale.getDefault().getCountry(); if (getLanguageResources(lang) == null) { lang = Locale.getDefault().getLanguage(); if (getLanguageResources(lang) == null) { // default is english. lang = DEFAULT_LANGUAGE; } } } if ("no".equals(lang)) { // Bugs item #1935818 lang = "nb"; } languageResources = getLanguageResources(lang); /* * fc, 26.4.2008. the following line is a bug, as the * defaultResources are used, even, when a single string is * missing inside a bundle and not only, when the complete * bundle is missing. */ // if(languageResources == null) defaultResources = getLanguageResources(DEFAULT_LANGUAGE); } catch (Exception ex) { freemind.main.Resources.getInstance().logException(ex); logger.severe("Error loading Resources"); } // printResourceTable(); } // /** This is useful, if you want to see all resource strings in a HTML // table. // * Just rename the log file to log.0.html, open in a browser and set // the // * coding to UTF-8 */ // private void printResourceTable() { // StringBuffer b = new StringBuffer("<html><body><table>"); // Set keySet = languageResources.keySet(); // Vector keys = new Vector(keySet); // Collections.sort(keys); // for (Iterator iterator = keys.iterator(); iterator.hasNext();) { // String key = (String) iterator.next(); // b.append("<tr><td>" + key + "</td><td>" + // languageResources.getString(key)+"</td></tr>\n"); // } // b.append("</table></body></html>"); // logger.info(b.toString()); // } /** * @throws IOException */ private PropertyResourceBundle getLanguageResources(String lang) throws IOException { URL systemResource = mFreeMindMain.getResource("Resources_" + lang + ".properties"); if (systemResource == null) { return null; } InputStream in = systemResource.openStream(); if (in == null) { return null; } PropertyResourceBundle bundle = new PropertyResourceBundle(in); in.close(); return bundle; } protected Object handleGetObject(String key) { try { return languageResources.getString(key); } catch (Exception ex) { if(key != null && key.startsWith("__")) { // private string, only translate on demand return key; } else { logger.severe("Warning - resource string not found:\n" + key); return defaultResources.getString(key) + POSTFIX_TRANSLATE_ME; } } } public Enumeration getKeys() { return defaultResources.getKeys(); } String getResourceString(String key) { try { return getString(key); } catch (Exception ex) { return key; } } String getResourceString(String key, String pDefault) { try { try { return languageResources.getString(key); } catch (Exception ex) { return defaultResources.getString(key) + POSTFIX_TRANSLATE_ME; } } catch (Exception e) { // logger.info(key+" not found."); return pDefault; } } } public static final String RESOURCE_LANGUAGE = "language"; public static final String CHECK_SPELLING = "check_spelling"; public static final String RESOURCE_ANTIALIAS = "antialias"; public static final String DEFAULT_LANGUAGE = "en"; public static final String LOCAL_PROPERTIES = "LocalProperties."; private final FreeMindMain mFreeMindMain; private String baseDir; private FreeMindResourceBundle resources; /** * Holds the last opened map. */ public static final String ON_START_IF_NOT_SPECIFIED = "onStartIfNotSpecified"; public static final String LOAD_LAST_MAP = "loadLastMap"; public static final String LOAD_LAST_MAPS_AND_LAYOUT = "load_last_maps_and_layout"; public static final String SAVE_ONLY_INTRISICALLY_NEEDED_IDS = "save_only_intrisically_needed_ids"; public static final String LOAD_NEW_MAP = "load_new_map_when_no_other_is_specified"; /** * Load event occurred during startup * <p> * If FreeMind is not started and you double-click a .mm file on Mac OS X * the .mm file is not passed to Java's main method but handleOpenFile is * called which happens during startup where it is not safe to already load * the map. Therefore the event is stored in this property and later * processed by loadMaps. * <p> * Related issues * <ul> * <li> * http://sourceforge.net/tracker/?func=detail&aid=2908045&group_id=7118& * atid=107118 * <li>http://sourceforge.net/tracker/index.php?func=detail&aid=1980423& * group_id=7118&atid=107118 * </ul> */ public static final String LOAD_EVENT_DURING_STARTUP = "loadEventDuringStartup"; public static final String MINDMAP_LAST_STATE_MAP_STORAGE = "mindmap_last_state_map_storage"; private static Logger logger = null; /** * */ public FreeMindCommon(FreeMindMain main) { super(); // TODO Auto-generated constructor stub this.mFreeMindMain = main; if (logger == null) logger = main.getLogger(this.getClass().getName()); } public String getProperty(String key) { return mFreeMindMain.getProperty(key); } private void setDefaultProperty(String key, String value) { mFreeMindMain.setDefaultProperty(key, value); } /** Returns the ResourceBundle with the current language */ public ResourceBundle getResources() { if (resources == null) { resources = new FreeMindResourceBundle(); } return resources; } public String getResourceString(String key) { return ((FreeMindResourceBundle) getResources()).getResourceString(key); } public String getResourceString(String key, String pDefault) { return ((FreeMindResourceBundle) getResources()).getResourceString(key, pDefault); } public void clearLanguageResources() { resources = null; } public ClassLoader getFreeMindClassLoader() { ClassLoader classLoader = this.getClass().getClassLoader(); try { return new URLClassLoader(new URL[] { Tools.fileToUrl(new File( getFreemindBaseDir())) }, classLoader); } catch (MalformedURLException e) { freemind.main.Resources.getInstance().logException(e); return classLoader; } } /** * Old version using String manipulation out of the classpath to find the * base dir. */ public String getFreemindBaseDirOld() { if (baseDir == null) { final String classPath = System.getProperty("java.class.path"); final String mainJarFile = "freemind.jar"; int lastpos = classPath.indexOf(mainJarFile); int firstpos = 0; // if freemind.jar is not found in the class path use user.dir as // Basedir if (lastpos == -1) { baseDir = System.getProperty("user.dir"); logger.info("Basedir is user.dir: " + baseDir); return baseDir; } /* * fc: Now, if freemind.jar is the first, firstpos == -1. This * results in bad results in the substring method, or not?? */ firstpos = classPath.lastIndexOf(File.pathSeparator, lastpos) + 1; lastpos -= 1; if (lastpos > firstpos) { logger.info("First " + firstpos + " and last " + lastpos + " and string " + classPath); baseDir = classPath.substring(firstpos, lastpos); } else baseDir = ""; final File basePath = new File(baseDir); baseDir = basePath.getAbsolutePath(); logger.info("First basedir is: " + baseDir); /* * I suppose, that here, the freemind.jar is removed together with * the last path. Example: /home/foltin/freemindapp/lib/freemind.jar * gives /home/foltin/freemindapp */ lastpos = baseDir.lastIndexOf(File.separator); if (lastpos > -1) baseDir = baseDir.substring(0, lastpos); logger.info("Basedir is: " + baseDir); } return baseDir; } /* * We define the base dir of FreeMind as the directory where accessories, * plugins and other things are to be found. We expect it to be either the * directory where the main jar file is (freemind.jar), or the root of the * class hierarchy (if no jar file is used), after any 'lib' directory is * removed. One can overwrite this definition by setting the * freemind.base.dir property. */ public String getFreemindBaseDir() { if (baseDir == null) { try { File file; String dir = System.getProperty("freemind.base.dir"); if (dir == null) { // Property isn't set, we try to find the // base directory ourselves. // System.err.println("property not set"); // We locate first the current class. String classname = this.getClass().getName(); URL url = this.getClass().getResource( classname.replaceFirst("^" + this.getClass().getPackage().getName() + ".", "") + ".class"); // then we create a file out of it, after // removing file: and jar:, removing everything // after !, as well as the class name part. // Finally we decode everything (e.g. %20) // TODO: is UTF-8 always the right value? file = new File(URLDecoder.decode( url.getPath() .replaceFirst("^(file:|jar:)+", "") .replaceFirst("!.*$", "") .replaceFirst( classname.replace('.', '/') + ".class$", ""), "UTF-8")); // if it's a file, we take its parent, a dir if (file.isFile()) file = file.getParentFile(); /* * Now, we remove the lib directory: Example: * /home/foltin/freemindapp/lib/freemind.jar gives * /home/foltin/freemindapp */ if (file.getName().equals("lib")) file = file.getParentFile(); } else { file = new File(dir); } // then we check if the directory exists and is really // a directory. if (!file.exists()) { throw new IllegalArgumentException("FreeMind base dir '" + file + "' does not exist."); } if (!file.isDirectory()) { throw new IllegalArgumentException( "FreeMind base dir (!) '" + file + "' is not a directory."); } // set the member variable baseDir = file.getCanonicalPath(); logger.info("Basedir is: " + baseDir); } catch (Exception e) { Resources.getInstance().logException(e); throw new IllegalArgumentException( "FreeMind base dir can't be determined."); } } // return the value of the cache variable return baseDir; } public String getAdjustableProperty(final String label) { String value = getProperty(label); if (value == null) { return value; } if (value.startsWith("?") && !value.equals("?")) { // try to look in the language specific properties String localValue = ((FreeMindResourceBundle) getResources()) .getResourceString(LOCAL_PROPERTIES + label, null); value = localValue == null ? value.substring(1).trim() : localValue; setDefaultProperty(label, value); } return value; } public void loadUIProperties(Properties props) { // props.put(FreeMind.RESOURCES_BACKGROUND_COLOR, // Tools.colorToXml(UIManager.getColor("text"))); // props.put(FreeMind.RESOURCES_NODE_TEXT_COLOR, // Tools.colorToXml(UIManager.getColor("textText"))); // props.put(FreeMind.RESOURCES_SELECTED_NODE_COLOR, // Tools.colorToXml(UIManager.getColor("textHighlight"))); // props.put(FreeMind.RESOURCES_SELECTED_NODE_TEXT_COLOR, // Tools.colorToXml(UIManager.getColor("textHighlightText"))); } }