/** * This file Copyright (c) 2005-2008 Aptana, Inc. This program is * dual-licensed under both the Aptana Public License and the GNU General * Public license. You may elect to use one or the other of these licenses. * * This program is distributed in the hope that it will be useful, but * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or * NONINFRINGEMENT. Redistribution, except as permitted by whichever of * the GPL or APL you select, is prohibited. * * 1. For the GPL license (GPL), you can redistribute and/or modify this * program under the terms of the GNU General Public License, * Version 3, as published by the Free Software Foundation. You should * have received a copy of the GNU General Public License, Version 3 along * with this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Aptana provides a special exception to allow redistribution of this file * with certain other free and open source software ("FOSS") code and certain additional terms * pursuant to Section 7 of the GPL. You may view the exception and these * terms on the web at http://www.aptana.com/legal/gpl/. * * 2. For the Aptana Public License (APL), this program and the * accompanying materials are made available under the terms of the APL * v1.0 which accompanies this distribution, and is available at * http://www.aptana.com/legal/apl/. * * You may view the GPL, Aptana's exception and additional terms, and the * APL in the file titled license.html at the root of the corresponding * plugin containing this source file. * * Any modifications to this file must keep this entire header intact. */ package com.aptana.ide.core.ui.preferences; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.ListenerList; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import com.aptana.ide.core.StringUtils; import com.aptana.ide.core.URLEncoder; /** * * * @author Kevin Lindsey * @notes Please be cautious about adding aptana dependencies to this file as the Python plugin now uses this class. * A logging should be completed using the standard Eclipse Logging mechanism. */ public final class ApplicationPreferences { private static final String aptanaSettings = ".aptana-settings"; //$NON-NLS-1$ private static ApplicationPreferences instance; private Map<String,String> _keyValuePairs; private boolean _hasLoaded; private ListenerList listenerList; /** * ApplicationPreferences */ private ApplicationPreferences() { this._keyValuePairs = new HashMap<String,String>(); this.listenerList = new ListenerList(); } /** * getInstance * * @return preference singleton */ public static ApplicationPreferences getInstance() { if (instance == null) { instance = new ApplicationPreferences(); instance.loadPreferences(); } return instance; } /** * Returns the settings file on disk * * @return settings file */ private File getSettingsFile() { /* Removing dependency on CoreUIUtils */ // File config = CoreUIUtils.getConfigurationDirectory(); File config = ApplicationPreferences.getConfigurationDirectory(); return new File(config, aptanaSettings); } /** * Returns a file handle to the folder links to osgi.configuration.area. * * @return A reference to the configuration directory on disk */ public static File getConfigurationDirectory() { String homeDir = System.getProperty("osgi.configuration.area"); //$NON-NLS-1$ URL fileURL = ApplicationPreferences.uriToURL(homeDir); File f = ApplicationPreferences.urlToFile(fileURL); f.mkdirs(); return f; } /** * LoadPreferences */ public void loadPreferences() { File settings = getSettingsFile(); if (this._hasLoaded || settings.exists() == false) { return; } FileReader fr = null; StringBuilder errors = new StringBuilder(); try { fr = new FileReader(settings); BufferedReader br = new BufferedReader(fr); String line = br.readLine(); int lineNumber = 1; while (line != null) { int colonIndex = line.indexOf(":"); //$NON-NLS-1$ if (colonIndex != -1) { // split key/value pair String key = line.substring(0, colonIndex); String value = line.substring(colonIndex + 1, line.length()); // store key/value pair this._keyValuePairs.put(key, value); } else { errors.append("\t[line ");//$NON-NLS-1$ errors.append(lineNumber); errors.append("] - Expected key-value pair, but found '");//$NON-NLS-1$ errors.append(line); errors.append("'\n");//$NON-NLS-1$ } // read next line line = br.readLine(); lineNumber++; } } catch (Exception e) { logError(Messages.ApplicationPreferences_ERR_UnableToReadAptanaSettings, e); } finally { if (fr != null) { try { fr.close(); } catch (IOException e) { logError(Messages.ApplicationPreferences_ERR_UnableToCloseAptanaSettings, e); } } if (errors.length() > 0) { // Log any errors found while reading the Aptana settings file logError("Errors found when reading the Aptana settings file:\n" + errors.toString(), null);//$NON-NLS-1$ } this._hasLoaded = true; } } /** * Returns a the location of .aptanaSettings file from earlier * releases * * @return file */ private File getPreviousDefaultSettingsFile() { File previousReleaseSettingsFile = null; if (Platform.OS_MACOSX.equals(Platform.getOS())) { previousReleaseSettingsFile = new File( System.getProperty("user.home") + "/Library/Application Support/Aptana/Aptana Studio/configuration", //$NON-NLS-1$ //$NON-NLS-2$ aptanaSettings); } else if (Platform.OS_WIN32.equals(Platform.getOS())) { previousReleaseSettingsFile = new File( System.getProperty("user.home") + "\\Application Data\\Aptana\\Aptana Studio\\configuration", //$NON-NLS-1$ //$NON-NLS-2$ aptanaSettings); } else if (Platform.OS_LINUX.equals(Platform.getOS())) { previousReleaseSettingsFile = new File( System.getProperty("user.home") + "/.Aptana/Aptana Studio/configuration", //$NON-NLS-1$ //$NON-NLS-2$ aptanaSettings); } if (previousReleaseSettingsFile != null && previousReleaseSettingsFile.exists()) { return previousReleaseSettingsFile; } return null; } /** * load preferences from .aptanaSettings file from earlier * releases if found */ public Map<String,String> loadPreviousPreferences() { Map<String,String> previousPreferences = new HashMap<String, String>(); File previousDefaultSettingsFile = getPreviousDefaultSettingsFile(); if (previousDefaultSettingsFile != null) { FileReader fr = null; try { fr = new FileReader(previousDefaultSettingsFile); BufferedReader br = new BufferedReader(fr); String line = br.readLine(); while (line != null) { int colonIndex = line.indexOf(":"); //$NON-NLS-1$ if (colonIndex != -1) { // split key/value pair String key = line.substring(0, colonIndex); String value = line.substring(colonIndex + 1, line.length()); previousPreferences.put(key, value); // read next line line = br.readLine(); } } } catch (Exception e) { logError("Unable to read previous Aptana settings", e); //$NON-NLS-1$ } finally { if (fr != null) { try { fr.close(); } catch (IOException e) { logError("Unable to close previous Aptana settings", e); //$NON-NLS-1$ } } } } return previousPreferences; } /** * Add property change listener * * @param listener */ public void addPropertyChangeListener(IPropertyChangeListener listener) { listenerList.add(listener); } /** * Remove property change listener * * @param listener */ public void removePropertyChangeListener(IPropertyChangeListener listener) { listenerList.remove(listener); } /** * Fire a property change event * * @param name * @param oldValue * @param newValue */ public void firePropertyChangeEvent(String name, Object oldValue, Object newValue) { firePropertyChangeEvent(new PropertyChangeEvent(this, name, oldValue, newValue)); } private void firePropertyChangeEvent(PropertyChangeEvent event) { Object[] listeners = listenerList.getListeners(); for (int i = 0; i < listeners.length; i++) { ((IPropertyChangeListener) listeners[i]).propertyChange(event); } } /** * SavePreferences */ public void savePreferences() { BufferedWriter bw = null; try { File settings = getSettingsFile(); FileWriter fw = new FileWriter(settings); bw = new BufferedWriter(fw); Set<Map.Entry<String,String>> entries = this._keyValuePairs.entrySet(); Iterator<Map.Entry<String,String>> iter = entries.iterator(); while (iter.hasNext()) { Map.Entry<String,String> entry = iter.next(); bw.write(entry.getKey()); bw.write(":"); //$NON-NLS-1$ bw.write(entry.getValue()); bw.newLine(); } } catch (Exception e) { logError(Messages.ApplicationPreferences_ERR_UnableToWriteAptanaSettings, e); } finally { if (bw != null) { try { bw.close(); } catch (IOException e) { logError(Messages.ApplicationPreferences_ERR_UnableToCloseAptanaSettings, e); } } } } /** * getBoolean * * @param preferenceName * @return boolean */ public boolean getBoolean(String preferenceName) { return "true".equals(this.getString(preferenceName)); //$NON-NLS-1$ } /** * getString * * @param preferenceName * @return preference string value */ public String getString(String preferenceName) { if (preferenceName == null) { throw new IllegalArgumentException("preference name must be defined"); //$NON-NLS-1$ } String result = null; if (this._keyValuePairs.containsKey(preferenceName)) { result = this._keyValuePairs.get(preferenceName); } return result; } /** * setBoolean * * @param preferenceName * @param preferenceValue */ public void setBoolean(String preferenceName, boolean preferenceValue) { this.setString(preferenceName, preferenceValue ? "true" : "false"); //$NON-NLS-1$ //$NON-NLS-2$ } /** * setString * * @param preferenceName * @param preferenceValue */ public void setString(String preferenceName, String preferenceValue) { if (preferenceName == null) { throw new IllegalArgumentException("preference name must be defined"); //$NON-NLS-1$ } this._keyValuePairs.put(preferenceName, preferenceValue); firePropertyChangeEvent(preferenceName, StringUtils.EMPTY, preferenceValue); //$NON-NLS-1$ } /** * uriToURL and urlToFile are both pulled from FileUtils * The have been moved locally to remove a dependency so that * Python does not need to depend on FileUtils as well. */ public static URL uriToURL(String uri) { URI uri2; String encodedUri; try { encodedUri = URLEncoder.encode(uri, null, null); uri2 = new URI(encodedUri); // NOTE: normalizing causes paths with ".." to lose their drive specification // uri2.normalize(); return uri2.toURL(); } catch (MalformedURLException e) { logError(StringUtils.format(Messages.ApplicationPreferences_ERR_UnableToConvertURIToURL, uri), e); return null; } catch (URISyntaxException e) { logError(StringUtils.format(Messages.ApplicationPreferences_ERR_UnableToConvertURIToURLSyntaxIsIncorrect, uri), e); return null; } } /** * Converts a file://-based url into a file * * @param url * The url * @return the File, or null if not a file URL */ public static File urlToFile(URL url) { try { //Done for Pydev: Instead of using // //url.toURI() // //use: // //new URI(url.toString()) // //Which is the same thing with a difference: it can be retroweaved to be compatible //with Java 1.4 (which is a requisite for Pydev) URI uri = new URI(url.toString()); if ("file".equals(uri.getScheme())) //$NON-NLS-1$ { return new File(uri.getSchemeSpecificPart()); } } catch (Exception e) { logError(Messages.ApplicationPreferences_ERR_FailedToConvertURLToFile, e); } return null; } private static void logError(String errorMessage, Throwable e ){ IStatus status = new Status( IStatus.ERROR, ResourcesPlugin.getPlugin().getBundle().getSymbolicName(), IStatus.OK, errorMessage, e); ResourcesPlugin.getPlugin().getLog().log(status); } }