| /******************************************************************************* |
| * Copyright (c) 2005, 2006 IBM Corporation and others. |
| * 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: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.ui.internal.services; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.List; |
| |
| import org.eclipse.core.commands.Command; |
| import org.eclipse.core.commands.IParameter; |
| import org.eclipse.core.commands.Parameterization; |
| import org.eclipse.core.commands.ParameterizedCommand; |
| import org.eclipse.core.commands.common.NotDefinedException; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.jface.preference.IPreferenceStore; |
| import org.eclipse.jface.util.IPropertyChangeListener; |
| import org.eclipse.jface.util.PropertyChangeEvent; |
| import org.eclipse.ui.IMemento; |
| import org.eclipse.ui.commands.ICommandService; |
| import org.eclipse.ui.internal.WorkbenchPlugin; |
| import org.eclipse.ui.internal.util.Util; |
| |
| /** |
| * <p> |
| * A manager for items parsed from the preference store. This attaches a |
| * listener to the registry after the first read, and monitors the preference |
| * for changes from that point on. When {@link #dispose()} is called, the |
| * listener is detached. |
| * </p> |
| * <p> |
| * This class is only intended for internal use within the |
| * <code>org.eclipse.ui.workbench</code> plug-in. |
| * </p> |
| * |
| * @since 3.2 |
| */ |
| public abstract class PreferencePersistence extends RegistryPersistence { |
| |
| /** |
| * Inserts the given element into the indexed two-dimensional array in the |
| * array at the index. The array is grown as necessary. |
| * |
| * @param elementToAdd |
| * The element to add to the indexed array; may be |
| * <code>null</code> |
| * @param indexedArray |
| * The two-dimensional array that is indexed by element type; |
| * must not be <code>null</code>. |
| * @param index |
| * The index at which the element should be added; must be a |
| * valid index. |
| * @param currentCount |
| * The current number of items in the array at the index. |
| */ |
| protected static final void addElementToIndexedArray( |
| final IMemento elementToAdd, final IMemento[][] indexedArray, |
| final int index, final int currentCount) { |
| final IMemento[] elements; |
| if (currentCount == 0) { |
| elements = new IMemento[1]; |
| indexedArray[index] = elements; |
| } else { |
| if (currentCount >= indexedArray[index].length) { |
| final IMemento[] copy = new IMemento[indexedArray[index].length * 2]; |
| System.arraycopy(indexedArray[index], 0, copy, 0, currentCount); |
| elements = copy; |
| indexedArray[index] = elements; |
| } else { |
| elements = indexedArray[index]; |
| } |
| } |
| elements[currentCount] = elementToAdd; |
| } |
| |
| /** |
| * Adds a warning to be logged at some later point in time. |
| * |
| * @param warningsToLog |
| * The collection of warnings to be logged; must not be |
| * <code>null</code>. |
| * @param message |
| * The mesaage to log; must not be <code>null</code>. |
| */ |
| protected static final void addWarning(final List warningsToLog, |
| final String message) { |
| addWarning(warningsToLog, message, null, null, null); |
| } |
| |
| /** |
| * Adds a warning to be logged at some later point in time. This logs the |
| * identifier of the item. |
| * |
| * @param warningsToLog |
| * The collection of warnings to be logged; must not be |
| * <code>null</code>. |
| * @param message |
| * The mesaage to log; must not be <code>null</code>. |
| * @param id |
| * The identifier of the item for which a warning is being |
| * logged; may be <code>null</code>. |
| */ |
| protected static final void addWarning(final List warningsToLog, |
| final String message, final String id) { |
| addWarning(warningsToLog, message, id, null, null); |
| } |
| |
| /** |
| * Adds a warning to be logged at some later point in time. This logs the |
| * identifier of the item, as well as an extra attribute. |
| * |
| * @param warningsToLog |
| * The collection of warnings to be logged; must not be |
| * <code>null</code>. |
| * @param message |
| * The mesaage to log; must not be <code>null</code>. |
| * @param id |
| * The identifier of the item for which a warning is being |
| * logged; may be <code>null</code>. |
| * @param extraAttributeName |
| * The name of extra attribute to be logged; may be |
| * <code>null</code>. |
| * @param extraAttributeValue |
| * The value of the extra attribute to be logged; may be |
| * <code>null</code>. |
| */ |
| protected static final void addWarning(final List warningsToLog, |
| final String message, final String id, |
| final String extraAttributeName, final String extraAttributeValue) { |
| String statusMessage = message; |
| if (id != null) { |
| statusMessage = statusMessage + ": id='" + id + '\''; //$NON-NLS-1$ |
| } |
| if (extraAttributeName != null) { |
| if (id != null) { |
| statusMessage = statusMessage + ','; |
| } else { |
| statusMessage = statusMessage + ':'; |
| } |
| statusMessage = statusMessage + ' ' + extraAttributeName + "='" //$NON-NLS-1$ |
| + extraAttributeValue + '\''; |
| } |
| |
| final IStatus status = new Status(IStatus.WARNING, |
| WorkbenchPlugin.PI_WORKBENCH, 0, statusMessage, null); |
| warningsToLog.add(status); |
| } |
| |
| /** |
| * Reads a boolean attribute from a memnto. |
| * |
| * @param memento |
| * The memento from which to read the attribute; must not be |
| * <code>null</code>. |
| * @param attribute |
| * The attribute to read; must not be <code>null</code>. |
| * @param defaultValue |
| * The default boolean value. |
| * @return The attribute's value; may be <code>null</code> if none. |
| */ |
| protected static final boolean readBoolean(final IMemento memento, |
| final String attribute, final boolean defaultValue) { |
| final String value = memento.getString(attribute); |
| if (value == null) { |
| return defaultValue; |
| } |
| |
| if (defaultValue) { |
| return !value.equalsIgnoreCase("false"); //$NON-NLS-1$ |
| } |
| |
| return !value.equalsIgnoreCase("true"); //$NON-NLS-1$ |
| } |
| |
| /** |
| * Reads an optional attribute from a memento. This converts zero-length |
| * strings into <code>null</code>. |
| * |
| * @param memento |
| * The memento from which to read the attribute; must not be |
| * <code>null</code>. |
| * @param attribute |
| * The attribute to read; must not be <code>null</code>. |
| * @return The attribute's value; may be <code>null</code> if none. |
| */ |
| protected static final String readOptional(final IMemento memento, |
| final String attribute) { |
| String value = memento.getString(attribute); |
| if ((value != null) && (value.length() == 0)) { |
| value = null; |
| } |
| |
| return value; |
| } |
| |
| /** |
| * Reads the parameterized command from a parent memento. This is used to |
| * read the parameter sub-elements from a key element, as well as the |
| * command id. Each parameter is guaranteed to be valid. If invalid |
| * parameters are found, then a warning status will be appended to the |
| * <code>warningsToLog</code> list. The command id is required, or a |
| * warning will be logged. |
| * |
| * @param memento |
| * The memento from which the parameters should be read; must not |
| * be <code>null</code>. |
| * @param commandService |
| * The service providing commands for the workbench; must not be |
| * <code>null</code>. |
| * @param warningsToLog |
| * The list of warnings found during parsing. Warnings found will |
| * parsing the parameters will be appended to this list. This |
| * value must not be <code>null</code>. |
| * @param message |
| * The message to print if the command identifier is not present; |
| * must not be <code>null</code>. |
| * @return The array of parameters found for this configuration element; |
| * <code>null</code> if none can be found. |
| */ |
| protected static final ParameterizedCommand readParameterizedCommand( |
| final IMemento memento, final ICommandService commandService, |
| final List warningsToLog, final String message, final String id) { |
| final String commandId = readRequired(memento, ATT_COMMAND_ID, |
| warningsToLog, message, id); |
| if (commandId == null) { |
| return null; |
| } |
| |
| final Command command = commandService.getCommand(commandId); |
| final ParameterizedCommand parameterizedCommand = readParameters( |
| memento, warningsToLog, command); |
| |
| return parameterizedCommand; |
| } |
| |
| /** |
| * Reads the parameters from a parent memento. This is used to read the |
| * parameter sub-elements from a key element. Each parameter is guaranteed |
| * to be valid. If invalid parameters are found, then a warning status will |
| * be appended to the <code>warningsToLog</code> list. |
| * |
| * @param memento |
| * The memento from which the parameters should be read; must not |
| * be <code>null</code>. |
| * @param warningsToLog |
| * The list of warnings found during parsing. Warnings found will |
| * parsing the parameters will be appended to this list. This |
| * value must not be <code>null</code>. |
| * @param command |
| * The command around which the parameterization should be |
| * created; must not be <code>null</code>. |
| * @return The array of parameters found for this memento; <code>null</code> |
| * if none can be found. |
| */ |
| protected static final ParameterizedCommand readParameters( |
| final IMemento memento, final List warningsToLog, |
| final Command command) { |
| final IMemento[] parameterMementos = memento |
| .getChildren(TAG_PARAMETER); |
| if ((parameterMementos == null) || (parameterMementos.length == 0)) { |
| return new ParameterizedCommand(command, null); |
| } |
| |
| final Collection parameters = new ArrayList(); |
| for (int i = 0; i < parameterMementos.length; i++) { |
| final IMemento parameterMemento = parameterMementos[i]; |
| |
| // Read out the id. |
| final String id = parameterMemento.getString(ATT_ID); |
| if ((id == null) || (id.length() == 0)) { |
| // The name should never be null. This is invalid. |
| addWarning(warningsToLog, "Parameters need a name"); //$NON-NLS-1$ |
| continue; |
| } |
| |
| // Find the parameter on the command. |
| IParameter parameter = null; |
| try { |
| final IParameter[] commandParameters = command.getParameters(); |
| if (parameters != null) { |
| for (int j = 0; j < commandParameters.length; j++) { |
| final IParameter currentParameter = commandParameters[j]; |
| if (Util.equals(currentParameter.getId(), id)) { |
| parameter = currentParameter; |
| break; |
| } |
| } |
| |
| } |
| } catch (final NotDefinedException e) { |
| // This should not happen. |
| } |
| if (parameter == null) { |
| // The name should never be null. This is invalid. |
| addWarning(warningsToLog, |
| "Could not find a matching parameter", id); //$NON-NLS-1$ |
| continue; |
| } |
| |
| // Read out the value. |
| final String value = parameterMemento.getString(ATT_VALUE); |
| if ((value == null) || (value.length() == 0)) { |
| // The name should never be null. This is invalid. |
| addWarning(warningsToLog, "Parameters need a value", id); //$NON-NLS-1$ |
| continue; |
| } |
| |
| parameters.add(new Parameterization(parameter, value)); |
| } |
| |
| if (parameters.isEmpty()) { |
| return new ParameterizedCommand(command, null); |
| } |
| |
| return new ParameterizedCommand(command, |
| (Parameterization[]) parameters |
| .toArray(new Parameterization[parameters.size()])); |
| } |
| |
| /** |
| * Reads a required attribute from the memento. |
| * |
| * @param memento |
| * The memento from which to read; must not be <code>null</code>. |
| * @param attribute |
| * The attribute to read; must not be <code>null</code>. |
| * @param warningsToLog |
| * The list of warnings; must not be <code>null</code>. |
| * @param message |
| * The warning message to use if the attribute is missing; must |
| * not be <code>null</code>. |
| * @return The required attribute; may be <code>null</code> if missing. |
| */ |
| protected static final String readRequired(final IMemento memento, |
| final String attribute, final List warningsToLog, |
| final String message) { |
| return readRequired(memento, attribute, warningsToLog, message, null); |
| } |
| |
| /** |
| * Reads a required attribute from the memento. This logs the identifier of |
| * the item if this required element cannot be found. |
| * |
| * @param memento |
| * The memento from which to read; must not be <code>null</code>. |
| * @param attribute |
| * The attribute to read; must not be <code>null</code>. |
| * @param warningsToLog |
| * The list of warnings; must not be <code>null</code>. |
| * @param message |
| * The warning message to use if the attribute is missing; must |
| * not be <code>null</code>. |
| * @param id |
| * The identifier of the element for which this is a required |
| * attribute; may be <code>null</code>. |
| * @return The required attribute; may be <code>null</code> if missing. |
| */ |
| protected static final String readRequired(final IMemento memento, |
| final String attribute, final List warningsToLog, |
| final String message, final String id) { |
| final String value = memento.getString(attribute); |
| if ((value == null) || (value.length() == 0)) { |
| addWarning(warningsToLog, message, id); |
| return null; |
| } |
| |
| return value; |
| } |
| |
| /** |
| * Whether the preference and registry change listeners have been attached |
| * yet. |
| */ |
| protected boolean preferenceListenerAttached = false; |
| |
| /** |
| * The registry change listener for this class. |
| */ |
| private final IPropertyChangeListener preferenceChangeListener; |
| |
| /** |
| * Detaches the preference change listener from the registry. |
| */ |
| public final void dispose() { |
| super.dispose(); |
| |
| final IPreferenceStore store = WorkbenchPlugin.getDefault() |
| .getPreferenceStore(); |
| store.removePropertyChangeListener(preferenceChangeListener); |
| } |
| |
| /** |
| * Checks whether the preference change could affect this persistence class. |
| * |
| * @param event |
| * The event indicating the preference change; must not be |
| * <code>null</code>. |
| * @return <code>true</code> if the persistence instance is affected by |
| * this change; <code>false</code> otherwise. |
| */ |
| protected abstract boolean isChangeImportant(final PropertyChangeEvent event); |
| |
| /** |
| * Reads the various elements from the registry. Subclasses should extend, |
| * but must not override. |
| */ |
| protected void read() { |
| super.read(); |
| |
| if (!preferenceListenerAttached) { |
| final IPreferenceStore store = WorkbenchPlugin.getDefault() |
| .getPreferenceStore(); |
| store.addPropertyChangeListener(preferenceChangeListener); |
| } |
| } |
| |
| /** |
| * Constructs a new instance of {@link PreferencePersistence}. A preference |
| * change listener is created. |
| */ |
| protected PreferencePersistence() { |
| super(); |
| |
| preferenceChangeListener = new IPropertyChangeListener() { |
| public final void propertyChange(final PropertyChangeEvent event) { |
| if (isChangeImportant(event)) { |
| read(); |
| } |
| } |
| }; |
| } |
| } |