/*******************************************************************************
* Copyright (c) 2007 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation
*******************************************************************************/
package org.eclipse.imp.preferences;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.IScopeContext;
import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
import org.eclipse.imp.runtime.RuntimePlugin;
import org.osgi.service.prefs.BackingStoreException;
import org.osgi.service.prefs.Preferences;
/**
* This interface is for use by IMP IDE clients that wish to access preference settings.
* This can be used both for global settings that affect all IMP-based IDEs (using the
* pseudo-language ID "IMP"), as well as language-specific settings that apply only to
* one particular IDE.
* <p>Miscellaneous notes:
* <ul>
* <li>Assumes that there is a "current language" that is an implicit
* qualifier for all preferences.
* <li>Assumes that there is a "current project" with respect to which
* project-level preferences are evaluated.
* <li>Does not include various features of the Eclipse PreferencesService:
* <ul>
* <li>Call site default values (deemed not useful)
* <li>Call site specifications of priority contexts (deemed not useful)
* <li>Missing "untyped" get/set operations (which work on strings)
* </ul>
* <li>Implementations may restrict the levels at which some operations
* are effective.
* </ul>
*<p>This interface is not intended to be implemented by clients.
* @see PreferencesService
* @author sutton
*/
public interface IPreferencesService {
/*
* Levels at which preferences are supported
*/
public final String PROJECT_LEVEL = "project";
public final String INSTANCE_LEVEL = "instance";
public final String CONFIGURATION_LEVEL = "configuration";
public final String DEFAULT_LEVEL = "default";
public final int PROJECT_INDEX = 0;
public final int INSTANCE_INDEX = 1;
public final int CONFIGURATION_INDEX = 2;
public final int DEFAULT_INDEX = 3;
public final static String[] levels = { PROJECT_LEVEL, INSTANCE_LEVEL, CONFIGURATION_LEVEL, DEFAULT_LEVEL };
public int indexForLevel(String levelName);
public boolean isaPreferencesLevel(String possibleLevel);
/*
* The service applies to a particular language in a
* particular project, both which can be set dynamically
*/
public void setLanguageName(String languageName);
public String getLanguageName();
public void setProjectName(String projectName);
public String getProjectName();
public void setProject(IProject project);
public IProject getProject();
/*
* Get and set preferences by batch by level
*/
public IEclipsePreferences getPreferences(String level);
public void setPreferences(String level, IEclipsePreferences preferences);
/*
* Get applicable preferences by type
*
* Requests are evaluated relative to an implicit "current project"
* and an implicit "current language."
*
* It is an error to request a preference when the current langauge is
* not defined, because all preferences are assumed to be defined relative
* to some language.
*
* It is not an error to request a preference when the current project
* is not set. That is because a preference may not be defined on the
* project level even when the project is set, and preferences are
* returned from the lowest level at which set in any case, so that a
* value can be returned from some higher level when the project is
* undefined.
*
* Preferences are returned from the lowest level at which set. If no
* preference is defined for a given key at all levels, then an apporpriate
* default value is returned. This is 0 for the numeric preferences,
* false for boolean preferences, the empty string for String preferences,
* and the empty array for byte[].
*/
public boolean getBooleanPreference(String key);
public byte[] getByteArrayPreference(String key);
public double getDoublePreference(String key);
public float getFloatPreference(String key);
public int getIntPreference(String key);
public long getLongPreference(String key);
public String getStringPreference(String key);
public String getRawStringPreference(String key);
/*
* Get applicable preferences by project and type
*
* Requests are evaluated relative to an implicit "current language."
* It is an error to request a preference when the current langauge is
* not defined, because all preferences are assumed to be defined relative
* to some language.
*
* Requests are evaluated relative to a given project, regardless of
* whether there is a "current project" defined.
*
* Preferences are returned from the lowest level at which set. If no
* preference is defined for a given key at all levels, then an apporpriate
* default value is returned. This is 0 for the numeric preferences,
* false for boolean preferences, the empty string for String preferences,
* and the empty array for byte[].
*/
// TODO Remove these - the prefs service should use the project that the client configured it to use
public boolean getBooleanPreference(IProject project, String key);
public byte[] getByteArrayPreference(IProject project, String key);
public double getDoublePreference(IProject project, String key);
public float getFloatPreference(IProject project, String key);
public int getIntPreference(IProject project, String key);
public long getLongPreference(IProject project, String key);
public String getStringPreference(IProject project, String key);
public String getRawStringPreference(IProject project, String key);
/*
* Get preferences for a given level by type
*
* Requests are evaluated relative to an implicit "current language."
* It is an error to request a preference when the current langauge is
* not defined, because all preferences are assumed to be defined relative
* to some language.
*
* Requests are evaluated relative to the given level only.
* If a preference for the given key is defined at that level, then
* the associated value is returned. If no preferences is defined
* for the given key at that level, then a suitable default value
* is returned. This is 0 for the numeric preferences, false for
* boolean preferences, the empty string for String preferences,
* and the empty array for byte[].
*
* If the given level is the project level, then requests are
* evaluated relative to an implicit "current project." It is
* an error to request a preference from the project level when
* no current project is defined.
*/
public boolean getBooleanPreference(String level, String key);
public byte[] getByteArrayPreference(String level, String key);
public double getDoublePreference(String level, String key);
public float getFloatPreference(String level, String key);
public int getIntPreference(String level, String key);
public long getLongPreference(String level, String key);
public String getStringPreference(String level, String key);
public String getRawStringPreference(String level, String key);
/*
* Get preferences for a given project by type
*
* Requests are evaluated relative to an implicit "current language."
* It is an error to request a preference when the current langauge is
* not defined, because all preferences are assumed to be defined relative
* to some language.
*
* Requests are evaluated relative to the given project only. If a
* preference for the given key is defined for that project, then the
* associated value is returned. If no preferences is defined
* for the given key in the given project, then a suitable default value
* is returned. This is 0 for the numeric preferences, false for boolean
* preferences, the empty string for String preferences, and the empty
* array for byte[].
*/
// TODO Remove these - the prefs svc should use the project the client configured it to use
public boolean getBooleanPreferenceForProject(IProject project, String key);
public byte[] getByteArrayPreferenceForProject(IProject project, String key);
public double getDoublePreferenceForProject(IProject project, String key);
public float getFloatPreferenceForProject(IProject project, String key);
public int getIntPreferenceForProject(IProject project, String key);
public long getLongPreferenceForProject(IProject project, String key);
public String getStringPreferenceForProject(IProject project, String key);
public String getRawStringPreferenceForProject(IProject project, String key);
/*
* Set preferences for a given level by type
*/
public void setBooleanPreference(String level, String key, boolean value);
public void setByteArrayPreference(String level, String key, byte[] value);
public void setDoublePreference(String level, String key, double value);
public void setFloatPreference(String level, String key, float value);
public void setIntPreference(String level, String key, int value);
public void setLongPreference(String level, String key, long value);
public void setStringPreference(String level, String key, String value);
/*
* Get preferences for a given level, language, and project by type
*/
// TODO Remove these - the prefs svc should use the language the client configured it to use
public boolean getBooleanPreference(String languageName, String projectName, String level, String key, boolean def);
public byte[] getByteArrayPreference(String languageName, String projectName, String level, String key, byte[] def);
public double getDoublePreference(String languageName, String projectName, String level, String key, double def);
public float getFloatPreference(String languageName, String projectName, String level, String key, float def);
public int getIntPreference(String languageName, String projectName, String level, String key, int def);
public long getLongPreference(String languageName, String projectName, String level, String key, long def);
public String getStringPreference(String languageName, String projectName, String level, String key, String def);
public String getRawStringPreference(String languageName, String projectName, String level, String key, String def);
/*
* Set preferences for a given level, language, and project by type
*/
// TODO Remove these - the prefs svc should use the language the client configured it to use
public void setBooleanPreference(String languageName, String projectName, String level, String key, boolean value);
public void setByteArrayPreference(String languageName, String projectName, String level, String key, byte[] value);
public void setDoublePreference(String languageName, String projectName, String level, String key, double value);
public void setFloatPreference(String languageName, String projectName, String level, String key, float value);
public void setIntPreference(String languageName, String projectName, String level, String key, int value);
public void setLongPreference(String languageName, String projectName, String level, String key, long value);
public void setStringPreference(String languageName, String projectName, String level, String key, String value);
/**
* @return the result of performing all preference substitutions on the
* given value, which can include references of the form "${prefKey}" or
* "${pluginLoc:pluginID}". The values of any preference references are
* obtained in the context of the project associated with this
* {@link IPreferencesService}, if any.
*/
public String performSubstitutions(String value);
/**
* @return the result of performing all preference substitutions on the
* given value, which can include references of the form "${prefKey}" or
* "${pluginLoc:pluginID}". Use the given project as the context for
* obtaining the values of referenced preferences.
*/
public String performSubstitutions(String value, IProject project);
/*
* Clear preferences at a given level
*
* The first two methods operate relative to an implicit "current project."
* It is an error to invoke these methods for the project level when there is
* no currently defined project.
*
* The second two meethods operate relative to a given project, regardless of
* whether a current project is set. These are intended to address the clearing
* of preferences on the project level, but it is not an error (if nevertheless
* pointless) to use them to clear preferences on another level.
*
* The "clear preferences" methods clear all preferences on the given level.
* The "clear preference" methods clear the given preference on the given
* level; if the preference is not defined on that level then these methods
* should have no effect.
*/
public IEclipsePreferences clearPreferencesAtLevel(String level);
public String clearPreferenceAtLevel(String level, String key);
public IEclipsePreferences clearPreferencesAtLevel(IProject project, String level);
public String clearPreferenceAtLevel(IProject project, String level, String key);
/*
* Regarding where and whether a preference is defined
*
* The first three methods operate relative to an implicit "current project."
* It is an error to invoke the first two of these methods for the project level
* when there is no currently defined project.
*
* The second three methods operate relative to a given project, regardless of
* whether a current project is set. For those methods that take a preferences
* level, it is not an error (if nevertheless pointless) to invoke these methods
* with a levels other than the project level.
*
* The getApplicableLevel(..) methods get the preferences level, at or above a
* given level, at which a preference is defined for a given key. They return
* null if no such level is found.
*
* The isDefault(..) methods indicate for a given key whether the value that
* applies at a given level is the default value (that is, the value associated
* with the given key on the default preference level).
*
* The isDefined(..) methods indicate for a given key whether a value is defined
* for that key at some level.
*/
public String getApplicableLevel(String key, String level);
public boolean isDefault(String key, String level);
public boolean isDefined(String key);
public String getApplicableLevel(IProject project, String key, String level);
public boolean isDefault(IProject project, String key, String level);
public boolean isDefined(IProject project, String key);
/*
* Regarding contexts and nodes
*/
/**
* Return the preferences root node (its children are
* the nodes for the various preferences levels)
*/
public IEclipsePreferences getRootNode();
/**
* Return the preferences node for a given preferences level.
*
* @param level The String name of a preferences level
* @return The preferences node for that level
* @throws IllegalArgumentException if level is null of
* is not a recognized preferences level name;
* IllegalStateException if level designates the
* project level and the current project is not
* defined
*/
public IEclipsePreferences getNodeForLevel(String level);
/**
* Return the preferences node for a given project, regardless
* of whether this is the curently defined project.
*
* @param project An IProject indicating the project for which
* preferences are sought
* @return The preferences node for the given project
* @throws IllegalArgumentException if the given project
* is null
*/
public IEclipsePreferences getNodeForProject(IProject project);
/**
* Return an array of preferences nodes, one for each of the
* four (main) preferences levels: project, (workspace) instance,
* (workspace) configuration, and default. If there is no
* current project defined, then the project preferences node
* will be null.
*
* @return An array of preferences nodes, in order
* from lowest (project) to highest (default)
*/
public IEclipsePreferences[] getNodesForLevels();
/**
* Return an array of preferences nodes, one for each of the
* four (main) preferences levels: project, (workspace) instance,
* (workspace) configuration, and default. Use a given project
*
* @param project
* @return
*/
public IEclipsePreferences[] getNodesForLevels(IProject project);
public IScopeContext getScopeForLevel(String level);
public IScopeContext getScopeForProject(IProject project);
public int getIndexForLevel(String level);
public abstract class PreferenceServiceListener implements IPreferenceChangeListener {
private final String fKey;
private final IEclipsePreferences fConfigLevel;
private final IEclipsePreferences fWSLevel;
private final IEclipsePreferences fProjLevel;
PreferenceServiceListener(IPreferencesService service, String key) {
fKey= key;
fConfigLevel= service.getPreferences(IPreferencesService.CONFIGURATION_LEVEL);
fWSLevel= service.getPreferences(IPreferencesService.INSTANCE_LEVEL);
fProjLevel= service.getPreferences(IPreferencesService.PROJECT_LEVEL);
fConfigLevel.addPreferenceChangeListener(this);
fWSLevel.addPreferenceChangeListener(this);
if (fProjLevel != null) {
fProjLevel.addPreferenceChangeListener(this);
}
}
public void preferenceChange(PreferenceChangeEvent event) {
if (!event.getKey().equals(fKey))
return;
handleChange(event.getOldValue(), event.getNewValue());
}
public void dispose() {
// RMF Fix for bug #297603: check that the pref nodes exist before attempting to unregister
try {
if (fConfigLevel.nodeExists("")) {
fConfigLevel.removePreferenceChangeListener(this);
}
if (fWSLevel.nodeExists("")) {
fWSLevel.removePreferenceChangeListener(this);
}
if (fProjLevel != null && fProjLevel.nodeExists("")) {
fProjLevel.removePreferenceChangeListener(this);
}
} catch (BackingStoreException e) {
RuntimePlugin.getInstance().logException(e.getMessage(), e);
}
}
protected abstract void handleChange(Object oldValue, Object newValue);
}
public abstract class StringPreferenceListener extends PreferenceServiceListener {
public StringPreferenceListener(IPreferencesService service, String key) {
super(service, key);
}
@Override
protected final void handleChange(Object oldValue, Object newValue) {
changed((String) oldValue, (String) newValue);
}
public abstract void changed(String oldValue, String newValue);
}
public abstract class BooleanPreferenceListener extends PreferenceServiceListener {
public BooleanPreferenceListener(IPreferencesService service, String key) {
super(service, key);
}
@Override
protected final void handleChange(Object oldValue, Object newValue) {
changed(Boolean.parseBoolean((String) oldValue), Boolean.parseBoolean((String) newValue));
}
public abstract void changed(boolean oldValue, boolean newValue);
}
public abstract class IntegerPreferenceListener extends PreferenceServiceListener {
public IntegerPreferenceListener(IPreferencesService service, String key) {
super(service, key);
}
protected final void handleChange(Object oldValue, Object newValue) {
changed(Integer.parseInt((String) oldValue), Integer.parseInt((String) newValue));
}
public abstract void changed(int oldValue, int newValue);
}
/*
* For monitoring changes in the selected project
*/
public void addProjectSelectionListener(IProjectSelectionListener listener);
public void removeProjectSelectionListener(IProjectSelectionListener listener);
public final class ProjectSelectionEvent { //extends EventObject {
/**
* All serializable objects should have a stable serialVersionUID
*/
private static final long serialVersionUID = 1L;
private Preferences previous;
private Preferences neww;
/**
* Constructor for a new node change event object.
*
* @param parent the parent node
* @param child the child node
*/
public ProjectSelectionEvent(Preferences previous, Preferences neww) {
//super(neww);
this.previous = previous;
this.neww = neww;
}
/**
* Return the preferences node for the previously selected project.
* May be null if there was no previously selected project.
*
* @return the previous node
*/
public Preferences getPrevious() {
return previous;
}
/**
* Return the preferences node for the newly selected project.
* May be null if somehow the selection is nullified.
* </p>
* @return the new node
*/
public Preferences getNew() {
return neww;
}
}
/**
* A listener to be used to receive events that signal the selection
* of a project as the focus for project preferences.
* <p>
* Clients may implement this interface.
* </p>
*
* @since 3.0
*/
public interface IProjectSelectionListener {
/**
* Notification that a project was selected
* The given event must not be <code>null</code>.
*
* @param event an event specifying the details about the new node
*/
public void selection(ProjectSelectionEvent event);
}
}