blob: 390a2676a8229293d857cd62ac176abbe7040337 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005 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.core.commands;
import org.eclipse.core.commands.common.HandleObject;
import org.eclipse.core.commands.common.NotDefinedException;
import org.eclipse.core.internal.commands.util.Util;
/**
* <p>
* Provides information about the type of a command parameter. Clients can use a
* parameter type to check if an object matches the type of the parameter with
* {@link #isCompatible(Object)} and can get an
* {@link AbstractParameterValueConverter} to convert between objects matching
* the parameter type and strings that encode the object's identity.
* </p>
* <p>
* A command parameter is not required to declare a type. To determine if a
* given parameter has a type, check if an {@link IParameter} implements
* {@link ITypedParameter} and if so, use
* {@link ITypedParameter#getParameterType()} like this:
* </p>
*
* <pre>
* IParameter parameter = // ... get IParameter from Command
* if (parameter instanceof ITypedParameter) {
* ParameterType type = ((ITypedParameter)parameter).getParameterType();
* if (type != null) {
* // this parameter has a ParameterType
* }
* }
* </pre>
*
* @see IParameter
* @see ITypedParameter#getParameterType()
* @since 3.2
*/
public final class ParameterType extends HandleObject implements Comparable {
/**
* TODO: this was copied from
* org.eclipse.core.internal.expressions.Expressions is there a better place
* to reference this?
*
* @param element
* The element to test; may be <code>null</code>.
* @param type
* The type against which we are testing;may be <code>null</code>.
* @return <code>true</code> if the <code>element</code> is an instance
* of <code>type</code>; <code>false</code> otherwise.
*/
private static final boolean isInstanceOf(final Object element,
final String type) {
// null isn't an instanceof of anything.
if (element == null)
return false;
return isSubtype(element.getClass(), type);
}
/**
* TODO: this was copied from
* org.eclipse.core.internal.expressions.Expressions is there a better place
* to reference this?
*
* @param clazz
* The class to match; may be <code>null</code>.
* @param type
* The type against which we are testing;may be <code>null</code>.
* @return <code>true</code> if the <code>element</code> is an instance
* of <code>type</code>; <code>false</code> otherwise.
*/
private static final boolean isSubtype(final Class clazz, final String type) {
if (clazz.getName().equals(type))
return true;
final Class superClass = clazz.getSuperclass();
if (superClass != null && isSubtype(superClass, type))
return true;
final Class[] interfaces = clazz.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
if (isSubtype(interfaces[i], type))
return true;
}
return false;
}
/**
* An {@link AbstractParameterValueConverter} for converting parameter
* values between objects and strings. This may be <code>null</code>.
*/
private transient AbstractParameterValueConverter parameterTypeConverter;
/**
* A string specifying the object type of this parameter type. This will be
* <code>null</code> when the parameter type is undefined but never null
* when it is defined.
*/
private transient String type = null;
/**
* Constructs a new instance based on the given identifier. When a parameter
* type is first constructed, it is undefined. Parameter types should only
* be constructed by the {@link CommandManager} to ensure that the
* identifier remains unique.
*
* @param id
* The identifier for this type. This value must not be
* <code>null</code>, and must be unique amongst all parameter
* types.
*/
ParameterType(final String id) {
super(id);
}
/**
* Adds a listener to this parameter type that will be notified when its
* state changes.
*
* @param listener
* The listener to be added; must not be <code>null</code>.
*/
public final void addListener(final IParameterTypeListener listener) {
addListenerObject(listener);
}
/**
* Compares this parameter type with another object by comparing each of the
* non-transient attributes.
*
* @param object
* The object with which to compare; must be an instance of
* {@link ParameterType}.
* @return A negative integer, zero or a positive integer, if the object is
* greater than, equal to or less than this parameter type.
*/
public final int compareTo(final Object object) {
final ParameterType castedObject = (ParameterType) object;
int compareTo = Util.compare(defined, castedObject.defined);
if (compareTo == 0) {
compareTo = Util.compare(id, castedObject.id);
}
return compareTo;
}
/**
* <p>
* Defines this parameter type, setting the defined property to
* <code>true</code>.
* </p>
* <p>
* Notification is sent to all listeners that something has changed.
* </p>
*
* @param type
* a string identifying the Java object type for this parameter
* type; <code>null</code> is interpreted as
* <code>"java.lang.Object"</code>
* @param parameterTypeConverter
* an {@link AbstractParameterValueConverter} to perform
* string/object conversions for parameter values; may be
* <code>null</code>
*/
public final void define(final String type,
final AbstractParameterValueConverter parameterTypeConverter) {
final boolean definedChanged = !this.defined;
this.defined = true;
this.type = (type == null) ? Object.class.getName() : type;
this.parameterTypeConverter = parameterTypeConverter;
fireParameterTypeChanged(new ParameterTypeEvent(this, definedChanged));
}
/**
* Notifies all listeners that this parameter type has changed. This sends
* the given event to all of the listeners, if any.
*
* @param event
* The event to send to the listeners; must not be
* <code>null</code>.
*/
private final void fireParameterTypeChanged(final ParameterTypeEvent event) {
if (event == null) {
throw new NullPointerException(
"Cannot send a null event to listeners."); //$NON-NLS-1$
}
if (!isListenerAttached()) {
return;
}
final Object[] listeners = getListeners();
for (int i = 0; i < listeners.length; i++) {
final IParameterTypeListener listener = (IParameterTypeListener) listeners[i];
listener.parameterTypeChanged(event);
}
}
/**
* Returns the value converter associated with this parameter, if any.
*
* @return The parameter value converter, or <code>null</code> if there is
* no value converter for this parameter.
* @throws NotDefinedException
* if the parameter type is not currently defined
*/
public final AbstractParameterValueConverter getValueConverter()
throws NotDefinedException {
if (!isDefined()) {
throw new NotDefinedException(
"Cannot use getValueConverter() with an undefined ParameterType"); //$NON-NLS-1$
}
return parameterTypeConverter;
}
/**
* Returns whether the provided value is compatible with this parameter
* type. An object is compatible with a parameter type if the object is an
* instance of the class defined as the parameter's type class.
*
* @param value
* an object to check for compatibility with this parameter type;
* may be <code>null</code>.
* @return <code>true</code> if the value is compatible with this type,
* <code>false</code> otherwise
* @throws NotDefinedException
* if the parameter type is not currently defined
*/
public boolean isCompatible(Object value) throws NotDefinedException {
if (!isDefined()) {
throw new NotDefinedException(
"Cannot use isCompatible() with an undefined ParameterType"); //$NON-NLS-1$
}
return isInstanceOf(value, type);
}
/**
* Unregisters listener for changes to properties of this parameter type.
*
* @param listener
* the instance to unregister. Must not be <code>null</code>.
* If an attempt is made to unregister an instance which is not
* already registered with this instance, no operation is
* performed.
*/
public final void removeListener(final IParameterTypeListener listener) {
removeListenerObject(listener);
}
/**
* The string representation of this parameter type. For debugging purposes
* only. This string should not be shown to an end user.
*
* @return The string representation; never <code>null</code>.
*/
public final String toString() {
if (string == null) {
final StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("ParameterType("); //$NON-NLS-1$
stringBuffer.append(id);
stringBuffer.append(',');
stringBuffer.append(defined);
stringBuffer.append(')');
string = stringBuffer.toString();
}
return string;
}
/**
* Makes this parameter type become undefined. Notification is sent to all
* listeners.
*/
public final void undefine() {
string = null;
final boolean definedChanged = defined;
defined = false;
type = null;
parameterTypeConverter = null;
fireParameterTypeChanged(new ParameterTypeEvent(this, definedChanged));
}
}