From 27c8ac0ac33a07dbda0b1bf66cd2082c9d40f403 Mon Sep 17 00:00:00 2001
From: Alain Magloire Clients may implement this interface.
+ * This method is called when a path variable is added, removed or has its value
+ * changed in the observed
+ * If a variable is effectively changed, created or removed by a call to
+ * this method, notification will be sent to all registered listeners.
+ * If the given String is
+ * For example, consider the following collection of path variables:
+ * The following paths would be resolved as:
+ * c:/bin => c:/bin c:${TEMP} => c:/temp /TEMP => /TEMP ${TEMP}/foo => /temp/foo ${BACKUP} => /tmp/backup ${BACKUP}/bar.txt => /tmp/backup/bar.txt SOMEPATH/foo => SOMEPATH/fooIPathVariableManager
object.
+ *
+ *
+ * null
.
+ * null
.null
.
+ * null
, or if it is
+ * defined but the given value is equal to its current value.
+ * null
)
+ * @exception CoreException if this method fails. Reasons include:
+ *
+ *
+ */
+ public void setValue(String name, String value) throws CoreException;
+
+ /**
+ * Returns the value of the variable with the given name. If there is
+ * no variable defined with the given name, returns null
.
+ *
+ * @param name the name of the variable to return the value for
+ * @return the value for the variable, or null
if there is no
+ * variable defined with the given name
+ */
+ public String getValue(String name);
+
+ /**
+ * Returns an array containing all defined variable names.
+ *
+ * @return an array containing all defined variable names
+ */
+ public String[] getVariableNames();
+
+ /**
+ * Registers the given listener to receive notification of changes to
+ * variables. The listener will be notified whenever a variable has been
+ * added, removed or had its value changed. Has no effect if an identical
+ * variable change listener is already registered.
+ *
+ * @param listener the listener
+ * @see IPathEntryVariableChangeListener
+ */
+ public void addChangeListener(IPathEntryVariableChangeListener listener);
+
+ /**
+ * Removes the given variable change listener from the listeners list.
+ * Has no effect if an identical listener is not registered.
+ *
+ * @param listener the listener
+ * @see IPathEntryVariableChangeListener
+ */
+ public void removeChangeListener(IPathEntryVariableChangeListener listener);
+
+ /**
+ * Resolves a String
potentially containing a
+ * variable reference, replacing the variable reference
+ * (if any) with the variable's value (which is a concrete absolute path).
+ * null
then null
will be
+ * returned. In all other cases the result will be non-null
.
+ *
+ *
+ *
null
+ */
+ public String resolvePath(String path);
+
+ /**
+ * Returns true
if the given variable is defined and
+ * false
otherwise. Returns false
if the given
+ * name is not a valid path variable name.
+ *
+ * @param name the variable's name
+ * @return true
if the variable exists, false
+ * otherwise
+ */
+ public boolean isDefined(String name);
+
+}
\ No newline at end of file
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/resources/PathEntryVariableChangeEvent.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/resources/PathEntryVariableChangeEvent.java
new file mode 100644
index 00000000000..df0695f348f
--- /dev/null
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/resources/PathEntryVariableChangeEvent.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.core.resources;
+
+import java.util.EventObject;
+
+/**
+ * Describes a change in path variable.
+ */
+public class PathEntryVariableChangeEvent extends EventObject {
+ private static final long serialVersionUID = 1L;
+
+ /** Event type constant (value = 1) that denotes a value change . */
+ public final static int VARIABLE_CHANGED = 1;
+
+ /** Event type constant (value = 2) that denotes a variable creation. */
+ public final static int VARIABLE_CREATED = 2;
+
+ /** Event type constant (value = 3) that denotes a variable deletion. */
+ public final static int VARIABLE_DELETED = 3;
+
+
+ /**
+ * The name of the changed variable.
+ */
+ private String variableName;
+
+ /**
+ * The value of the changed variable (may be null).
+ */
+ private String value;
+
+ /** The event type. */
+ private int type;
+
+ /**
+ * Constructor for this class.
+ */
+ public PathEntryVariableChangeEvent(IPathEntryVariableManager source, String variableName, String value, int type) {
+ super(source);
+ if (type < VARIABLE_CHANGED || type > VARIABLE_DELETED)
+ throw new IllegalArgumentException("Invalid event type: " + type); //$NON-NLS-1$
+ this.variableName = variableName;
+ this.value = value;
+ this.type = type;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public String getVariableName() {
+ return variableName;
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ /**
+ * Return a string representation of this object.
+ */
+ public String toString() {
+ String[] typeStrings = {"VARIABLE_CHANGED", "VARIABLE_CREATED", "VARIABLE_DELETED"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ StringBuffer sb = new StringBuffer(getClass().getName());
+ sb.append("[variable = "); //$NON-NLS-1$
+ sb.append(variableName);
+ sb.append(", type = "); //$NON-NLS-1$
+ sb.append(typeStrings[type - 1]);
+ if (type != VARIABLE_DELETED) {
+ sb.append(", value = "); //$NON-NLS-1$
+ sb.append(value);
+ }
+ sb.append("]"); //$NON-NLS-1$
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/PathEntryVariableManager.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/PathEntryVariableManager.java
new file mode 100644
index 00000000000..8bada30ee24
--- /dev/null
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/PathEntryVariableManager.java
@@ -0,0 +1,257 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * QNX Software Systems - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.internal.core;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.resources.IPathEntryVariableChangeListener;
+import org.eclipse.cdt.core.resources.IPathEntryVariableManager;
+import org.eclipse.cdt.core.resources.PathEntryVariableChangeEvent;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Preferences;
+
+
+
+/**
+ * Core's implementation of IPathEntryVariableManager.
+ */
+public class PathEntryVariableManager implements IPathEntryVariableManager {
+
+ private Set listeners;
+ private Preferences preferences;
+
+ static final String VARIABLE_PREFIX = "pathEntryVariable."; //$NON-NLS-1$
+
+ /**
+ * Constructor for the class.
+ */
+ public PathEntryVariableManager() {
+ this.listeners = Collections.synchronizedSet(new HashSet());
+ this.preferences = CCorePlugin.getDefault().getPluginPreferences();
+ }
+
+ /**
+ * Note that if a user changes the key in the preferences file to be invalid
+ * and then calls #getValue using that key, they will get the value back for
+ * that. But then if they try and call #setValue using the same key it will throw
+ * an exception. We may want to revisit this behaviour in the future.
+ *
+ * @see org.eclipse.core.resources.IPathEntryVariableManager#getValue(String)
+ */
+ public String getValue(String varName) {
+ String key = getKeyForName(varName);
+ String value = preferences.getString(key);
+ return value.length() == 0 ? null : value;
+ }
+
+ /**
+ * @see org.eclipse.core.resources.IPathEntryVariableManager#setValue(String, IPath)
+ */
+ public void setValue(String varName, String newValue) throws CoreException {
+ int eventType;
+ // read previous value and set new value atomically in order to generate the right event
+ synchronized (this) {
+ String currentValue = getValue(varName);
+ boolean variableExists = currentValue != null;
+ if (!variableExists && newValue == null) {
+ return;
+ }
+ if (variableExists && currentValue.equals(newValue)) {
+ return;
+ }
+ if (newValue == null) {
+ preferences.setToDefault(getKeyForName(varName));
+ eventType = PathEntryVariableChangeEvent.VARIABLE_DELETED;
+ } else {
+ preferences.setValue(getKeyForName(varName), newValue);
+ eventType = variableExists ? PathEntryVariableChangeEvent.VARIABLE_CHANGED : PathEntryVariableChangeEvent.VARIABLE_CREATED;
+ }
+ }
+ // notify listeners from outside the synchronized block to avoid deadlocks
+ fireVariableChangeEvent(varName, newValue, eventType);
+ }
+
+ /**
+ * Return a key to use in the Preferences.
+ */
+ private String getKeyForName(String varName) {
+ return VARIABLE_PREFIX + varName;
+ }
+
+ /**
+ * @see org.eclipse.core.resources.IPathEntryVariableManager#resolvePath(IPath)
+ */
+ public String resolvePath(String variable) {
+ if (variable == null || variable.length() == 0 || variable.indexOf('$') == -1) {
+ return variable;
+ }
+ String value = expandVariable(variable);
+ return value == null ? variable : value;
+ }
+
+ /**
+ * Fires a property change event corresponding to a change to the
+ * current value of the variable with the given name.
+ *
+ * @param name the name of the variable, to be used as the variable
+ * in the event object
+ * @param value the current value of the path variable or null
if
+ * the variable was deleted
+ * @param type one of IPathVariableChangeEvent.VARIABLE_CREATED
,
+ * PathEntryVariableChangeEvent.VARIABLE_CHANGED
, or
+ * PathEntryVariableChangeEvent.VARIABLE_DELETED
+ * @see PathEntryVariableChangeEvent
+ * @see PathEntryVariableChangeEvent#VARIABLE_CREATED
+ * @see PathEntryVariableChangeEvent#VARIABLE_CHANGED
+ * @see PathEntryVariableChangeEvent#VARIABLE_DELETED
+ */
+ private void fireVariableChangeEvent(String name, String value, int type) {
+ if (this.listeners.size() == 0)
+ return;
+ // use a separate collection to avoid interference of simultaneous additions/removals
+ Object[] listenerArray = this.listeners.toArray();
+ final PathEntryVariableChangeEvent pve = new PathEntryVariableChangeEvent(this, name, value, type);
+ for (int i = 0; i < listenerArray.length; ++i) {
+ final IPathEntryVariableChangeListener l = (IPathEntryVariableChangeListener) listenerArray[i];
+ ISafeRunnable job = new ISafeRunnable() {
+ public void handleException(Throwable exception) {
+ // already being logged in Platform#run()
+ }
+
+ public void run() throws Exception {
+ l.pathVariableChanged(pve);
+ }
+ };
+ Platform.run(job);
+ }
+ }
+
+ /**
+ * @see org.eclipse.core.resources.IPathVariableManager#getPathVariableNames()
+ */
+ public String[] getVariableNames() {
+ List result = new LinkedList();
+ String[] names = preferences.propertyNames();
+ for (int i = 0; i < names.length; i++) {
+ if (names[i].startsWith(VARIABLE_PREFIX)) {
+ String key = names[i].substring(VARIABLE_PREFIX.length());
+ result.add(key);
+ }
+ }
+ return (String[]) result.toArray(new String[result.size()]);
+ }
+
+ /**
+ * @see org.eclipse.core.resources.
+ * IPathEntryVariableManager#addChangeListener(IPathEntryVariableChangeListener)
+ */
+ public void addChangeListener(IPathEntryVariableChangeListener listener) {
+ listeners.add(listener);
+ }
+
+ /**
+ * @see org.eclipse.core.resources.
+ * IPathEntryVariableManager#removeChangeListener(IPathEntryVariableChangeListener)
+ */
+ public void removeChangeListener(IPathEntryVariableChangeListener listener) {
+ listeners.remove(listener);
+ }
+
+ /**
+ * @see org.eclipse.core.resources.IPathVariableManager#isDefined(String)
+ */
+ public boolean isDefined(String varName) {
+ return getValue(varName) != null;
+ }
+
+ public void startup() {
+ }
+
+ public void shutdown() {
+ }
+
+ /**
+ * Expand the variable with the format ${key}. example:
+ * with variable HOME=/foobar
+ * ${HOME}/project
+ * The the return value will be /foobar/project.
+ */
+ protected String expandVariable(String variable) {
+ StringBuffer sb = new StringBuffer();
+ StringBuffer param = new StringBuffer();
+ char prev = '\n';
+ char ch = prev;
+ boolean inMacro = false;
+ boolean inSingleQuote = false;
+
+ for (int i = 0; i < variable.length(); i++) {
+ ch = variable.charAt(i);
+ switch (ch) {
+ case '\'':
+ if (prev != '\\') {
+ inSingleQuote = !inSingleQuote;
+ }
+ break;
+
+ case '$' :
+ if (!inSingleQuote && prev != '\\') {
+ if (i < variable.length() && variable.indexOf('}', i) > 0) {
+ char c = variable.charAt(i + 1);
+ if (c == '{') {
+ param.setLength(0);
+ inMacro = true;
+ prev = ch;
+ continue;
+ }
+ }
+ }
+ break;
+
+ case '}' :
+ if (inMacro) {
+ inMacro = false;
+ String p = param.toString();
+ String v = getValue(p);
+ if (v != null) {
+ sb.append(v);
+ }
+ param.setLength(0);
+ /* Skip the trailing } */
+ prev = ch;
+ continue;
+ }
+ break;
+ } /* switch */
+
+ if (!inMacro) {
+ sb.append(ch);
+ } else {
+ /* Do not had the '{' */
+ if (!(ch == '{' && prev == '$')) {
+ param.append(ch);
+ }
+ }
+ prev = (ch == '\\' && prev == '\\') ? '\n' : ch;
+ } /* for */
+ return sb.toString();
+ }
+
+
+}
\ No newline at end of file