blob: 8e9cff83d77e1790e3a9e8e5bf2a1e0fd6a09762 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2008 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* Contributors:
* IBM Corporation - initial API and implementation
* Obeo - code cleanup and tweaking for use within ATL
*******************************************************************************/
package org.eclipse.m2m.atl.adt.ui.preferences;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ProjectScope;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.preferences.DefaultScope;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.IScopeContext;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.m2m.atl.adt.ui.AtlUIPlugin;
/**
* The model for the set of profiles which are available in the workbench.
*
*/
public abstract class ProfileManager extends Observable {
public static final class KeySet {
private final List<String> fKeys;
private final String fNodeName;
public KeySet(String nodeName, List<String> keys) {
fNodeName = nodeName;
fKeys = keys;
}
public String getNodeName() {
return fNodeName;
}
public List<String> getKeys() {
return fKeys;
}
}
/**
* A prefix which is prepended to every ID of a user-defined profile, in order
* to differentiate it from a built-in profile.
*/
public final static String ID_PREFIX= "_"; //$NON-NLS-1$
/**
* Represents a profile with a unique ID, a name and a map
* containing the code formatter settings.
*/
public static abstract class Profile implements Comparable<Profile> {
public abstract String getName();
public abstract Profile rename(String name, ProfileManager manager);
public abstract Map<String, String> getSettings();
public abstract void setSettings(Map<String, String> settings);
public boolean hasEqualSettings(Map<String, String> otherMap, Collection<String> allKeys) {
Map<String, String> settings = getSettings();
for (Iterator<String> iter = allKeys.iterator(); iter.hasNext(); ){
String key = (String) iter.next();
Object other = otherMap.get(key);
Object curr = settings.get(key);
if (other == null) {
if (curr != null) {
return false;
}
} else if (!other.equals(curr)) {
return false;
}
}
return true;
}
public abstract boolean isProfileToSave();
public abstract String getID();
public boolean isSharedProfile() {
return false;
}
public boolean isBuiltInProfile() {
return false;
}
}
/**
* Represents a built-in profile. The state of a built-in profile
* cannot be changed after instantiation.
*/
public static final class BuiltInProfile extends Profile {
private final String fName;
private final String fID;
private final Map<String, String> fSettings;
private final int fOrder;
public BuiltInProfile(String ID, String name, Map<String, String> settings, int order) {
fName = name;
fID = ID;
fSettings = settings;
fOrder = order;
}
public String getName() {
return fName;
}
public Profile rename(String name, ProfileManager manager) {
final String trimmed = name.trim();
CustomProfile newProfile = new CustomProfile(trimmed, fSettings);
manager.addProfile(newProfile);
return newProfile;
}
public Map<String, String> getSettings() {
return fSettings;
}
public String getID() {
return fID;
}
public boolean isProfileToSave() {
return false;
}
public boolean isBuiltInProfile() {
return true;
}
public int compareTo(Profile o) {
if (o instanceof BuiltInProfile) {
return fOrder - ((BuiltInProfile)o).fOrder;
}
return -1;
}
@Override
public void setSettings(Map<String, String> settings) {
}
}
/**
* Represents a user-defined profile. A custom profile can be modified after instantiation.
*/
public static class CustomProfile extends Profile {
private String fName;
private Map<String, String> fSettings;
protected ProfileManager fManager;
public CustomProfile(String name, Map<String, String> settings) {
fName = name;
fSettings = settings;
}
public String getName() {
return fName;
}
public Profile rename(String name, ProfileManager manager) {
final String trimmed = name.trim();
if (trimmed.equals(getName()))
return this;
String oldID = getID(); // remember old id before changing name
fName = trimmed;
manager.profileRenamed(this, oldID);
return this;
}
public Map<String, String> getSettings() {
return fSettings;
}
public void setSettings(Map<String, String> settings) {
if (settings == null)
throw new IllegalArgumentException();
fSettings = settings;
if (fManager != null) {
fManager.profileChanged(this);
}
}
public String getID() {
return ID_PREFIX + fName;
}
public void setManager(ProfileManager profileManager) {
fManager = profileManager;
}
public ProfileManager getManager() {
return fManager;
}
public boolean isProfileToSave() {
return true;
}
public int compareTo(Profile o) {
if (o instanceof SharedProfile) {
return -1;
}
if (o instanceof CustomProfile) {
return getName().compareToIgnoreCase(((Profile)o).getName());
}
return 1;
}
}
public final class SharedProfile extends CustomProfile {
public SharedProfile(String oldName, Map<String, String> options) {
super(oldName, options);
}
public Profile rename(String name, ProfileManager manager) {
CustomProfile profile = new CustomProfile(name.trim(), getSettings());
manager.profileReplaced(this, profile);
return profile;
}
public String getID() {
return SHARED_PROFILE;
}
public final int compareTo(Profile o) {
return 1;
}
public boolean isProfileToSave() {
return false;
}
public boolean isSharedProfile() {
return true;
}
}
/**
* The possible events for observers listening to this class.
*/
public final static int SELECTION_CHANGED_EVENT = 1;
public final static int PROFILE_DELETED_EVENT = 2;
public final static int PROFILE_RENAMED_EVENT = 3;
public final static int PROFILE_CREATED_EVENT = 4;
public final static int SETTINGS_CHANGED_EVENT = 5;
/**
* The key of the preference where the selected profile is stored.
*/
private final String fProfileKey;
private final static String SHARED_PROFILE= "org.eclipse.jdt.ui.default.shared"; //$NON-NLS-1$
/**
* A map containing the available profiles, using the IDs as keys.
*/
private final Map<String, Profile> fProfiles;
/**
* The available profiles, sorted by name.
*/
private final List<Profile> fProfilesByName;
/**
* The currently selected profile.
*/
private Profile fSelected;
/**
* The keys of the options to be saved with each profile
*/
private final KeySet[] fKeySets;
private final PreferencesAccess fPreferencesAccess;
/**
* Create and initialize a new profile manager.
* @param profiles Initial custom profiles (List of type <code>CustomProfile</code>)
*/
public ProfileManager(
List<Profile> profiles,
IScopeContext context,
PreferencesAccess preferencesAccess,
KeySet[] keySets,
String profileKey) {
fPreferencesAccess = preferencesAccess;
fKeySets = keySets;
fProfileKey = profileKey;
fProfiles = new HashMap<String, Profile>();
fProfilesByName = new ArrayList<Profile>();
for (final Iterator<Profile> iter = profiles.iterator(); iter.hasNext();) {
final Profile profile = iter.next();
if (profile instanceof CustomProfile) {
((CustomProfile)profile).setManager(this);
}
fProfiles.put(profile.getID(), profile);
fProfilesByName.add(profile);
}
Collections.sort(fProfilesByName);
String profileId = getSelectedProfileId(fPreferencesAccess.getInstanceScope());
Profile profile = fProfiles.get(profileId);
if (profile == null) {
profile = getDefaultProfile();
}
fSelected = profile;
if (context.getName() == ProjectScope.SCOPE) {
String projProfileId = context.getNode(AtlUIPlugin.getPluginId()).get(AtlCodeFormatterPropertyPage.CURRENT_PROFILE_KEY, null);
if(projProfileId != null) {
Profile curr = fProfiles.get(projProfileId);
if(curr != null)
fSelected = curr;
}
}
}
protected String getSelectedProfileId(IScopeContext instanceScope) {
String profileId = instanceScope.getNode(AtlUIPlugin.getPluginId()).get(fProfileKey, null);
if (profileId == null) {
// request from bug 129427
profileId = new DefaultScope().getNode(AtlUIPlugin.getPluginId()).get(fProfileKey, null);
}
return profileId;
}
/**
* Notify observers with a message. The message must be one of the following:
* @param message Message to send out
*
* @see #SELECTION_CHANGED_EVENT
* @see #PROFILE_DELETED_EVENT
* @see #PROFILE_RENAMED_EVENT
* @see #PROFILE_CREATED_EVENT
* @see #SETTINGS_CHANGED_EVENT
*/
protected void notifyObservers(int message) {
setChanged();
notifyObservers(new Integer(message));
}
public static boolean hasProjectSpecificSettings(IScopeContext context, KeySet[] keySets) {
for (int i= 0; i < keySets.length; i++) {
KeySet keySet = keySets[i];
IEclipsePreferences preferences = context.getNode(keySet.getNodeName());
for (final Iterator<String> keyIter = keySet.getKeys().iterator(); keyIter.hasNext();) {
final String key = keyIter.next();
Object val = preferences.get(key, null);
if (val != null) {
return true;
}
}
}
return false;
}
public boolean hasProjectSpecificSettings(IScopeContext context) {
return hasProjectSpecificSettings(context, fKeySets);
}
private boolean updatePreferences(IEclipsePreferences prefs, List<String> keys, Map<String, String> profileOptions) {
boolean hasChanges= false;
for (final Iterator<String> keyIter = keys.iterator(); keyIter.hasNext(); ) {
final String key = keyIter.next();
final String oldVal = prefs.get(key, null);
final String val = profileOptions.get(key);
if (val == null) {
if (oldVal != null) {
prefs.remove(key);
hasChanges = true;
}
} else if (!val.equals(oldVal)) {
prefs.put(key, val);
hasChanges = true;
}
}
return hasChanges;
}
/**
* Update all formatter settings with the settings of the specified profile.
* @param profile The profile to write to the preference store
*/
private void writeToPreferenceStore(Profile profile, IScopeContext context) {
final Map<String, String> profileOptions= profile.getSettings();
for (int i= 0; i < fKeySets.length; i++) {
updatePreferences(context.getNode(fKeySets[i].getNodeName()), fKeySets[i].getKeys(), profileOptions);
}
final IEclipsePreferences uiPrefs= context.getNode(AtlUIPlugin.getPluginId());
if (context.getName() == InstanceScope.SCOPE) {
uiPrefs.put(fProfileKey, profile.getID());
} else if (context.getName() == ProjectScope.SCOPE && !profile.isSharedProfile()) {
uiPrefs.put(fProfileKey, profile.getID());
}
}
/**
* Get an immutable list as view on all profiles, sorted alphabetically. Unless the set
* of profiles has been modified between the two calls, the sequence is guaranteed to
* correspond to the one returned by <code>getSortedNames</code>.
* @return a list of elements of type <code>Profile</code>
*
* @see #getSortedDisplayNames()
*/
public List<Profile> getSortedProfiles() {
return Collections.unmodifiableList(fProfilesByName);
}
/**
* Get the names of all profiles stored in this profile manager, sorted alphabetically. Unless the set of
* profiles has been modified between the two calls, the sequence is guaranteed to correspond to the one
* returned by <code>getSortedProfiles</code>.
* @return All names, sorted alphabetically
* @see #getSortedProfiles()
*/
public String[] getSortedDisplayNames() {
final String[] sortedNames = new String[fProfilesByName.size()];
int i = 0;
for (final Iterator<Profile> iter = fProfilesByName.iterator(); iter.hasNext();) {
Profile curr = iter.next();
sortedNames[i++] = curr.getName();
}
return sortedNames;
}
/**
* Get the profile for this profile id.
* @param ID The profile ID
* @return The profile with the given ID or <code>null</code>
*/
public Profile getProfile(String ID) {
return fProfiles.get(ID);
}
/**
* Activate the selected profile, update all necessary options in
* preferences and save profiles to disk.
*/
public void commitChanges(IScopeContext scopeContext) {
if (fSelected != null) {
writeToPreferenceStore(fSelected, scopeContext);
}
}
public void clearAllSettings(IScopeContext context) {
for (int i = 0; i < fKeySets.length; i++) {
updatePreferences(context.getNode(fKeySets[i].getNodeName()), fKeySets[i].getKeys(), new HashMap<String, String>());
}
final IEclipsePreferences uiPrefs = context.getNode(AtlUIPlugin.getPluginId());
uiPrefs.remove(fProfileKey);
}
/**
* Get the currently selected profile.
* @return The currently selected profile.
*/
public Profile getSelected() {
return fSelected;
}
/**
* Set the selected profile. The profile must already be contained in this profile manager.
* @param profile The profile to select
*/
public void setSelected(Profile profile) {
final Profile newSelected = fProfiles.get(profile.getID());
if (newSelected != null && !newSelected.equals(fSelected)) {
fSelected = newSelected;
notifyObservers(SELECTION_CHANGED_EVENT);
}
}
/**
* Check whether a user-defined profile in this profile manager
* already has this name.
* @param name The name to test for
* @return Returns <code>true</code> if a profile with the given name exists
*/
public boolean containsName(String name) {
for (Profile curr : fProfilesByName) {
if (name.equals(curr.getName())) {
return true;
}
}
return false;
}
/**
* Add a new custom profile to this profile manager.
* @param profile The profile to add
*/
public void addProfile(CustomProfile profile) {
profile.setManager(this);
final CustomProfile oldProfile = (CustomProfile)fProfiles.get(profile.getID());
if (oldProfile != null) {
fProfiles.remove(oldProfile.getID());
fProfilesByName.remove(oldProfile);
oldProfile.setManager(null);
}
fProfiles.put(profile.getID(), profile);
fProfilesByName.add(profile);
Collections.sort(fProfilesByName);
fSelected = profile;
notifyObservers(PROFILE_CREATED_EVENT);
}
/**
* Delete the currently selected profile from this profile manager. The next profile
* in the list is selected.
* @return true if the profile has been successfully removed, false otherwise.
*/
public boolean deleteSelected() {
if (!(fSelected instanceof CustomProfile))
return false;
return deleteProfile((CustomProfile)fSelected);
}
public boolean deleteProfile(CustomProfile profile) {
int index = fProfilesByName.indexOf(profile);
fProfiles.remove(profile.getID());
fProfilesByName.remove(profile);
profile.setManager(null);
if (index >= fProfilesByName.size())
index--;
fSelected = fProfilesByName.get(index);
if (!profile.isSharedProfile()) {
updateProfilesWithName(profile.getID(), null, false);
}
notifyObservers(PROFILE_DELETED_EVENT);
return true;
}
public void profileRenamed(CustomProfile profile, String oldID) {
fProfiles.remove(oldID);
fProfiles.put(profile.getID(), profile);
if (!profile.isSharedProfile()) {
updateProfilesWithName(oldID, profile, false);
}
Collections.sort(fProfilesByName);
notifyObservers(PROFILE_RENAMED_EVENT);
}
public void profileReplaced(CustomProfile oldProfile, CustomProfile newProfile) {
fProfiles.remove(oldProfile.getID());
fProfiles.put(newProfile.getID(), newProfile);
fProfilesByName.remove(oldProfile);
fProfilesByName.add(newProfile);
Collections.sort(fProfilesByName);
if (!oldProfile.isSharedProfile()) {
updateProfilesWithName(oldProfile.getID(), null, false);
}
setSelected(newProfile);
notifyObservers(PROFILE_CREATED_EVENT);
notifyObservers(SELECTION_CHANGED_EVENT);
}
public void profileChanged(CustomProfile profile) {
if (!profile.isSharedProfile()) {
updateProfilesWithName(profile.getID(), profile, true);
}
notifyObservers(SETTINGS_CHANGED_EVENT);
}
protected void updateProfilesWithName(String oldName, Profile newProfile, boolean applySettings) {
IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
for (int i = 0; i < projects.length; i++) {
IScopeContext projectScope = fPreferencesAccess.getProjectScope(projects[i]);
IEclipsePreferences node = projectScope.getNode(AtlUIPlugin.getPluginId());
String profileId = node.get(fProfileKey, null);
if (oldName.equals(profileId)) {
if (newProfile == null) {
node.remove(fProfileKey);
} else {
if (applySettings) {
writeToPreferenceStore(newProfile, projectScope);
} else {
node.put(fProfileKey, newProfile.getID());
}
}
}
}
IScopeContext instanceScope = fPreferencesAccess.getInstanceScope();
final IEclipsePreferences uiPrefs = instanceScope.getNode(AtlUIPlugin.getPluginId());
if (newProfile != null && oldName.equals(uiPrefs.get(fProfileKey, null))) {
writeToPreferenceStore(newProfile, instanceScope);
}
}
public abstract Profile getDefaultProfile();
}