/******************************************************************************* * Copyright (c) MOBAC developers * * 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, see <http://www.gnu.org/licenses/>. ******************************************************************************/ package mobac.program; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.Properties; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.JOptionPane; import mobac.utilities.Utilities; /** * Provides the common directories used within Mobile Atlas Creator: * <ul> * <li>current directory</li> * <li>program directory</li> * <li>user home directory</li> * <li>user settings directory</li> * <li>temporary directory</li> * </ul> * */ public class DirectoryManager { public static final File currentDir; public static final File programDir; public static final File userHomeDir; public static final File tempDir; public static final File userAppDataDir; public static final File userSettingsDir; public static final File mapSourcesDir; public static final File toolsDir; public static final File atlasProfilesDir; public static final File tileStoreDir; private static Properties dirConfig = null; static { currentDir = new File(System.getProperty("user.dir")); userHomeDir = new File(System.getProperty("user.home")); programDir = getProgramDir(); loadDirectoriesIni(); userAppDataDir = getUserAppDataDir(); tempDir = applyDirConfig("mobac.tmpdir", new File(System.getProperty("java.io.tmpdir"))); mapSourcesDir = applyDirConfig("mobac.mapsourcesdir", new File(programDir, "mapsources")); toolsDir = applyDirConfig("mobac.toolsdir", new File(programDir, "tools")); userSettingsDir = applyDirConfig("mobac.usersettingsdir", programDir); atlasProfilesDir = applyDirConfig("mobac.atlasprofilesdir", currentDir); tileStoreDir = applyDirConfig("mobac.tilestoredir", new File(programDir, "tilestore")); } private static File applyDirConfig(String propertyName, File defaultDir) { if (dirConfig == null) return defaultDir; try { final String dirCfg = dirConfig.getProperty(propertyName); if (dirCfg == null) { return defaultDir; } else { return expandCommandLine(dirCfg); } } catch (Exception e) { Logging.LOG.error("Error reading directory configuration: " + e.getMessage(), e); JOptionPane.showMessageDialog(null, "<html><p>Failed to load directory.ini - entry \"" + propertyName + "\":<p><p>" + e.getMessage() + "</p></html>", "Faile do load directory.ini", JOptionPane.ERROR_MESSAGE); return defaultDir; } } /** * Modified version of * http://stackoverflow.com/questions/2090647/evaluation-of-environment-variables-in-command-run- * by-javas-runtime-exec * * @param cmd * @return */ private static File expandCommandLine(final String cmd) { final Pattern vars = Pattern.compile("[$]\\{(\\S+)\\}"); final Matcher m = vars.matcher(cmd.trim()); final StringBuffer sb = new StringBuffer(cmd.length()); int lastMatchEnd = 0; while (m.find()) { sb.append(cmd.substring(lastMatchEnd, m.start())); final String envVar = m.group(1); String envVal = System.getenv(envVar); if (envVal == null) { File defPath = null; if ("mobac-prog".equalsIgnoreCase(envVar)) defPath = programDir; else if ("home".equalsIgnoreCase(envVar)) defPath = userHomeDir; else if ("XDG_CONFIG_HOME".equalsIgnoreCase(envVar)) defPath = new File(userHomeDir, ".config"); else if ("XDG_CACHE_HOME".equalsIgnoreCase(envVar)) defPath = new File(userHomeDir, ".cache"); else if ("XDG_DATA_HOME".equalsIgnoreCase(envVar)) { File localDataDir = new File(userHomeDir, ".local"); defPath = new File(localDataDir, "share"); } if (defPath != null) envVal = defPath.getAbsolutePath(); } if (envVal == null) sb.append(cmd.substring(m.start(), m.end())); else sb.append(envVal); lastMatchEnd = m.end(); } sb.append(cmd.substring(lastMatchEnd)); return new File(sb.toString()); } public static void initialize() { if (currentDir == null || userAppDataDir == null || tempDir == null || programDir == null) throw new RuntimeException("DirectoryManager failed"); } private static void loadDirectoriesIni() { File dirIniFile = new File(programDir, "directories.ini"); if (!dirIniFile.isFile()) return; dirConfig = new Properties(); FileInputStream in = null; try { in = new FileInputStream(dirIniFile); dirConfig.load(in); } catch (IOException e) { System.err.println("Failed to load " + dirIniFile.getName()); e.printStackTrace(); } finally { Utilities.closeStream(in); } } /** * Returns the directory from which this java program is executed * * @return */ private static File getProgramDir() { File f = null; try { f = Utilities.getClassLocation(DirectoryManager.class); } catch (Exception e) { System.err.println(e.getMessage()); return currentDir; } if ("bin".equals(f.getName())) // remove the bin dir -> this usually // happens only in a development environment return f.getParentFile(); else return f; } /** * Returns the directory where Mobile Atlas Creator saves it's application settings. * * Examples: * <ul> * <li>English Windows XP:<br> * <tt>C:\Document and Settings\%username%\Application Data\Mobile Atlas Creator</tt> * <li>Vista:<br> * <tt>C:\Users\%username%\Application Data\Mobile Atlas Creator</tt> * <li>Linux:<br> * <tt>/home/$username$/.mobac</tt></li> * </ul> * * @return */ private static File getUserAppDataDir() { String appData = System.getenv("APPDATA"); if (appData != null) { File appDataDir = new File(appData); if (appDataDir.isDirectory()) { File mobacDataDir = new File(appData, "Mobile Atlas Creator"); if (mobacDataDir.isDirectory() || mobacDataDir.mkdir()) return mobacDataDir; else throw new RuntimeException("Unable to create directory \"" + mobacDataDir.getAbsolutePath() + "\""); } } File userDir = new File(System.getProperty("user.home")); File mobacUserDir = new File(userDir, ".mobac"); if (!mobacUserDir.exists() && !mobacUserDir.mkdir()) throw new RuntimeException("Unable to create directory \"" + mobacUserDir.getAbsolutePath() + "\""); return mobacUserDir; } }