package com.redhat.ceylon.eclipse.code.style; import java.util.ArrayList; 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 ceylon.formatter.options.FormattingOptions; import ceylon.formatter.options.SparseFormattingOptions; /** * The model for the set of available ceylon.formatter profiles. */ public class FormatterProfileManager extends Observable { /** * Represents a profile with a unique name and the SparseFormatterOptions */ public static class Profile implements Comparable<Profile> { private String name; private FormattingOptions settings; private int order; private final int currentVersion; private int type; public boolean hasEqualSettings(SparseFormattingOptions otherSettings) { if (this.getSettings() != null) { return this.getSettings().equals(otherSettings); } else { return false; } } public Profile(String name, FormattingOptions options, int type, int order, int currentVersion) { this.name = name; this.settings = options; this.type = type; this.order = order; this.currentVersion = currentVersion; } public String getName() { return name; } public Profile rename(String name, FormatterProfileManager manager) { final String trimmed = name.trim(); if (this.type == 0) { Profile newProfile = new Profile(trimmed, this.settings, 1, this.order, this.currentVersion); manager.addProfile(newProfile); return newProfile; } else { // custom if (trimmed.equals(getName())) return this; String oldName = this.getName(); this.name = trimmed; manager.profileRenamed(this, oldName); return this; } } public FormattingOptions getSettings() { return settings; } public final int compareTo(Profile o) { if (this.type == 0) { if (o.type == 0) { return this.order - (o.getOrder()); } else { return -1; } } else { if (o.type == 1) { return getName().compareToIgnoreCase(o.getName()); } else { return 1; } } } private int getOrder() { return this.order; } public void setSettings(FormattingOptions options, FormatterProfileManager manager) { if (options == null) throw new IllegalArgumentException(); this.settings = options; if (manager != null) { manager.profileChanged(this); } } public boolean isBuiltInProfile() { return type == 0; } } /** * 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; private final Map<String, Profile> profiles; private final List<Profile> profilesByName; /** * The currently selected profile. */ private Profile selected; // different semantics from the default profile name in CeylonFormatterConstants public final static String CEYLON_PROFILE = "default"; public final static String DEFAULT_PROFILE = CEYLON_PROFILE; public static final int CEYLON_FORMATTER_VERSION = 1; public FormatterProfileManager(List<Profile> profiles, String activeProfile) { addBuiltinProfiles(profiles); this.profiles = new HashMap<String, Profile>(); this.profilesByName = new ArrayList<Profile>(); for (final Iterator<Profile> iter = profiles.iterator(); iter.hasNext();) { final Profile profile = iter.next(); this.profiles.put(profile.getName(), profile); this.profilesByName.add(profile); } Collections.sort(profilesByName); if (activeProfile != null) { selected = this.profiles.get(activeProfile); } else { selected = getDefaultProfile(); } } /** * 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)); } /** * 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(profilesByName); } /** * 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[profilesByName.size()]; int i = 0; for (final Iterator<Profile> iter = profilesByName.iterator(); iter .hasNext();) { Profile curr = iter.next(); sortedNames[i++] = curr.getName(); } return sortedNames; } public Profile getProfile(String name) { return profiles.get(name); } public Profile getSelected() { return this.selected; } public void setSelected(Profile profile) { final Profile newSelected = profiles.get(profile.getName()); if (newSelected != null && !newSelected.equals(this.selected)) { this.selected = newSelected; notifyObservers(SELECTION_CHANGED_EVENT); } } public boolean containsName(String name) { for (final Iterator<Profile> iter = profilesByName.iterator(); iter .hasNext();) { Profile curr = iter.next(); if (name.equals(curr.getName())) { return true; } } return false; } public void addProfile(Profile profile) { final Profile oldProfile = profiles.get(profile.getName()); if (oldProfile != null) { profiles.remove(oldProfile.getName()); profilesByName.remove(oldProfile); } profiles.put(profile.getName(), profile); profilesByName.add(profile); Collections.sort(profilesByName); this.selected = profile; notifyObservers(PROFILE_CREATED_EVENT); } public boolean deleteSelected() { if (this.selected == null) return false; return deleteProfile(this.selected); } public boolean deleteProfile(Profile profile) { int index = profilesByName.indexOf(profile); profiles.remove(profile.getName()); profilesByName.remove(profile); if (index >= profilesByName.size()) index--; selected = profilesByName.get(index); notifyObservers(PROFILE_DELETED_EVENT); return true; } public void profileRenamed(Profile profile, String oldName) { profiles.remove(oldName); profiles.put(profile.getName(), profile); Collections.sort(profilesByName); notifyObservers(PROFILE_RENAMED_EVENT); } public void profileReplaced(Profile oldProfile, Profile newProfile) { profiles.remove(oldProfile.getName()); profiles.put(newProfile.getName(), newProfile); profilesByName.remove(oldProfile); profilesByName.add(newProfile); Collections.sort(profilesByName); setSelected(newProfile); notifyObservers(PROFILE_CREATED_EVENT); notifyObservers(SELECTION_CHANGED_EVENT); } public void profileChanged(Profile profile) { notifyObservers(SETTINGS_CHANGED_EVENT); } private static List<Profile> addBuiltinProfiles(List<Profile> profiles) { final Profile ceylonProfile = new Profile(CEYLON_PROFILE, new FormattingOptions(), 0, 1, CEYLON_FORMATTER_VERSION); profiles.add(ceylonProfile); return profiles; } public Profile getDefaultProfile() { return getProfile(DEFAULT_PROFILE); } }