From 27c8ac0ac33a07dbda0b1bf66cd2082c9d40f403 Mon Sep 17 00:00:00 2001 From: Alain Magloire Date: Thu, 3 Mar 2005 21:59:59 +0000 Subject: [PATCH] 2005-03-03 Alain Magloire Part of plan item 79518: for PathEntry variable manager. * model/org/eclipse/cdt/internal/core/model/PathEntryManager.java * src/org/eclipse/cdt/core/CCorePlugin.java * src/org/eclipse/cdt/core/resources/IPathEntryVariableChangeListener.java * src/org/eclipse/cdt/core/resources/IPathEntryVariableManager.java * src/org/eclipse/cdt/core/resources/PathEntryVariableManager.java * src/org/eclipse/cdt/internal/core/PathEntryVariableManager.java --- core/org.eclipse.cdt.core/ChangeLog | 9 + .../internal/core/model/PathEntryManager.java | 5 +- .../src/org/eclipse/cdt/core/CCorePlugin.java | 25 +- .../IPathEntryVariableChangeListener.java | 42 +++ .../resources/IPathEntryVariableManager.java | 136 +++++++++ .../PathEntryVariableChangeEvent.java | 88 ++++++ .../core/PathEntryVariableManager.java | 257 ++++++++++++++++++ 7 files changed, 553 insertions(+), 9 deletions(-) create mode 100644 core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/resources/IPathEntryVariableChangeListener.java create mode 100644 core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/resources/IPathEntryVariableManager.java create mode 100644 core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/resources/PathEntryVariableChangeEvent.java create mode 100644 core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/PathEntryVariableManager.java diff --git a/core/org.eclipse.cdt.core/ChangeLog b/core/org.eclipse.cdt.core/ChangeLog index 4b2ef90c62c..123021d0414 100644 --- a/core/org.eclipse.cdt.core/ChangeLog +++ b/core/org.eclipse.cdt.core/ChangeLog @@ -1,3 +1,12 @@ +2005-03-03 Alain Magloire + Part of plan item 79518: for PathEntry variable manager. + * model/org/eclipse/cdt/internal/core/model/PathEntryManager.java + * src/org/eclipse/cdt/core/CCorePlugin.java + * src/org/eclipse/cdt/core/resources/IPathEntryVariableChangeListener.java + * src/org/eclipse/cdt/core/resources/IPathEntryVariableManager.java + * src/org/eclipse/cdt/core/resources/PathEntryVariableManager.java + * src/org/eclipse/cdt/internal/core/PathEntryVariableManager.java + 2005-03-03 Vladimir Hirsl Small change for enabling generation of path entry container change events. * model/org/eclipse/cdt/core/model/PathEntryContainerChanged.java diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/PathEntryManager.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/PathEntryManager.java index 6257daab466..a71d1c33973 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/PathEntryManager.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/PathEntryManager.java @@ -459,7 +459,6 @@ public class PathEntryManager implements IPathEntryStoreListener, IElementChange if (hasPathEntryProblemMarkersChange(project, problems)) { generateMarkers(project, problems); } - } // Check for duplication in the sources @@ -1805,11 +1804,9 @@ public class PathEntryManager implements IPathEntryStoreListener, IElementChange * Record a new marker denoting a pathentry problem */ void createPathEntryProblemMarker(IProject project, ICModelStatus status) { - - IMarker marker = null; int severity = code2Severity(status); try { - marker = project.createMarker(ICModelMarker.PATHENTRY_PROBLEM_MARKER); + IMarker marker = project.createMarker(ICModelMarker.PATHENTRY_PROBLEM_MARKER); marker.setAttributes(new String[]{IMarker.MESSAGE, IMarker.SEVERITY, IMarker.LOCATION, ICModelMarker.PATHENTRY_FILE_FORMAT,}, new Object[]{status.getMessage(), new Integer(severity), "pathentry",//$NON-NLS-1$ "false",//$NON-NLS-1$ diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java index 1b13e0b9853..76ee1d7a10b 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java @@ -25,10 +25,12 @@ import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.IWorkingCopy; import org.eclipse.cdt.core.parser.IScannerInfoProvider; import org.eclipse.cdt.core.resources.IConsole; +import org.eclipse.cdt.core.resources.IPathEntryVariableManager; import org.eclipse.cdt.core.resources.ScannerProvider; import org.eclipse.cdt.core.search.SearchEngine; import org.eclipse.cdt.internal.core.CDTLogWriter; import org.eclipse.cdt.internal.core.CDescriptorManager; +import org.eclipse.cdt.internal.core.PathEntryVariableManager; import org.eclipse.cdt.internal.core.model.BufferManager; import org.eclipse.cdt.internal.core.model.CModelManager; import org.eclipse.cdt.internal.core.model.DeltaProcessor; @@ -116,7 +118,9 @@ public class CCorePlugin extends Plugin { private CDescriptorManager fDescriptorManager = new CDescriptorManager(); private CoreModel fCoreModel; - + + private PathEntryVariableManager fPathEntryVariableManager; + // -------- static methods -------- static { @@ -215,6 +219,11 @@ public class CCorePlugin extends Plugin { if (cdtLog != null) { cdtLog.shutdown(); } + + if (fPathEntryVariableManager != null) { + fPathEntryVariableManager.shutdown(); + } + savePluginPreferences(); } finally { super.stop(context); @@ -245,6 +254,9 @@ public class CCorePlugin extends Plugin { getPluginPreferences().setDefault(PREF_USE_STRUCTURAL_PARSE_MODE, false); // Start file type manager + fPathEntryVariableManager = new PathEntryVariableManager(); + fPathEntryVariableManager.startup(); + } @@ -598,6 +610,10 @@ public class CCorePlugin extends Plugin { return fCoreModel; } + public IPathEntryVariableManager getPathEntryVariableManager() { + return fPathEntryVariableManager; + } + /** * @param project * @return @@ -853,9 +869,9 @@ public class CCorePlugin extends Plugin { /** * Configure the plugin with respect to option settings defined in ".options" file */ - public void configurePluginDebugOptions(){ + public void configurePluginDebugOptions() { - if(CCorePlugin.getDefault().isDebugging()){ + if(CCorePlugin.getDefault().isDebugging()) { String option = Platform.getDebugOption(PARSER); if(option != null) Util.VERBOSE_PARSER = option.equalsIgnoreCase("true") ; //$NON-NLS-1$ @@ -903,8 +919,7 @@ public class CCorePlugin extends Plugin { return getPluginPreferences().getBoolean(PREF_USE_STRUCTURAL_PARSE_MODE); } - public CDOM getDOM() - { + public CDOM getDOM() { return CDOM.getInstance(); } diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/resources/IPathEntryVariableChangeListener.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/resources/IPathEntryVariableChangeListener.java new file mode 100644 index 00000000000..e4ffddec3a9 --- /dev/null +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/resources/IPathEntryVariableChangeListener.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * 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.EventListener; + + +/** + * An interface to be implemented by objects interested in path variable + * creation, removal and value change events. + * + *

Clients may implement this interface.

+ * + * @since 3.0 + */ +public interface IPathEntryVariableChangeListener extends EventListener { + /** + * Notification that a path variable has changed. + *

+ * This method is called when a path variable is added, removed or has its value + * changed in the observed IPathVariableManager object. + *

+ * + * @param event the path variable change event object describing which variable + * changed and how + * @see IPathEntryVariableManager#addChangeListener(IPathVariableChangeListener) + * @see IPathEntryVariableManager#removeChangeListener(IPathVariableChangeListener) + * @see PathEntryVariableChangeEvent + */ + public void pathVariableChanged(PathEntryVariableChangeEvent event); + +} \ No newline at end of file diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/resources/IPathEntryVariableManager.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/resources/IPathEntryVariableManager.java new file mode 100644 index 00000000000..42ebee778bd --- /dev/null +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/resources/IPathEntryVariableManager.java @@ -0,0 +1,136 @@ +/******************************************************************************* + * 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 org.eclipse.core.runtime.CoreException; + +/** + * Manages a collection of variables + * @since 3.0 + */ +public interface IPathEntryVariableManager { + + /** + * Sets the variable with the given name to be the specified value. + * Depending on the value given and if the variable is currently defined + * or not, there are several possible outcomes for this operation: + *

+ *

+ *

If a variable is effectively changed, created or removed by a call to + * this method, notification will be sent to all registered listeners.

+ * + * @param name the name of the variable + * @param value the value for the variable (may be 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). + *

+ * If the given String is null then null will be + * returned. In all other cases the result will be non-null. + *

+ * + *

+ * 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/foo

+ * + * @param path the path to be resolved + * @return the resolved path or 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