blob: b4e9f161d1ec6ee0e95956a0b06b296bef8b5637 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2017 IBM Corporation and others.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
*******************************************************************************/
package org.eclipse.dltk.internal.ui.workingsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.core.ElementChangedEvent;
import org.eclipse.dltk.core.IElementChangedListener;
import org.eclipse.dltk.core.IModelElement;
import org.eclipse.dltk.core.IModelElementDelta;
import org.eclipse.dltk.core.IScriptProject;
import org.eclipse.ui.IWorkingSet;
import org.eclipse.ui.IWorkingSetUpdater;
public class ScriptWorkingSetUpdater
implements IWorkingSetUpdater, IElementChangedListener {
private List<IWorkingSet> fWorkingSets;
private static class WorkingSetDelta {
private IWorkingSet fWorkingSet;
private List<IAdaptable> fElements;
private boolean fChanged;
public WorkingSetDelta(IWorkingSet workingSet) {
fWorkingSet = workingSet;
fElements = new ArrayList<>(
Arrays.asList(workingSet.getElements()));
}
public int indexOf(Object element) {
return fElements.indexOf(element);
}
public void set(int index, IAdaptable element) {
fElements.set(index, element);
fChanged = true;
}
public void remove(int index) {
if (fElements.remove(index) != null) {
fChanged = true;
}
}
public void process() {
if (fChanged) {
fWorkingSet.setElements(
fElements.toArray(new IAdaptable[fElements.size()]));
}
}
}
public ScriptWorkingSetUpdater() {
fWorkingSets = new ArrayList<>();
DLTKCore.addElementChangedListener(this);
}
@Override
public void add(IWorkingSet workingSet) {
checkElementExistence(workingSet);
synchronized (fWorkingSets) {
fWorkingSets.add(workingSet);
}
}
@Override
public boolean remove(IWorkingSet workingSet) {
boolean result;
synchronized (fWorkingSets) {
result = fWorkingSets.remove(workingSet);
}
return result;
}
@Override
public boolean contains(IWorkingSet workingSet) {
synchronized (fWorkingSets) {
return fWorkingSets.contains(workingSet);
}
}
@Override
public void dispose() {
synchronized (fWorkingSets) {
fWorkingSets.clear();
}
DLTKCore.removeElementChangedListener(this);
}
@Override
public void elementChanged(ElementChangedEvent event) {
IWorkingSet[] workingSets;
synchronized (fWorkingSets) {
workingSets = fWorkingSets
.toArray(new IWorkingSet[fWorkingSets.size()]);
}
for (int w = 0; w < workingSets.length; w++) {
WorkingSetDelta workingSetDelta = new WorkingSetDelta(
workingSets[w]);
processScriptDelta(workingSetDelta, event.getDelta());
IResourceDelta[] resourceDeltas = event.getDelta()
.getResourceDeltas();
if (resourceDeltas != null) {
for (int r = 0; r < resourceDeltas.length; r++) {
processResourceDelta(workingSetDelta, resourceDeltas[r]);
}
}
workingSetDelta.process();
}
}
private void processScriptDelta(WorkingSetDelta result,
IModelElementDelta delta) {
IModelElement jElement = delta.getElement();
int index = result.indexOf(jElement);
int type = jElement.getElementType();
int kind = delta.getKind();
int flags = delta.getFlags();
if (type == IModelElement.SCRIPT_PROJECT
&& kind == IModelElementDelta.CHANGED) {
if (index != -1 && (flags & IModelElementDelta.F_CLOSED) != 0) {
result.set(index, ((IScriptProject) jElement).getProject());
} else if ((flags & IModelElementDelta.F_OPENED) != 0) {
index = result
.indexOf(((IScriptProject) jElement).getProject());
if (index != -1)
result.set(index, jElement);
}
}
if (index != -1) {
if (kind == IModelElementDelta.REMOVED) {
if ((flags & IModelElementDelta.F_MOVED_TO) != 0) {
result.set(index, delta.getMovedToElement());
} else {
result.remove(index);
}
}
}
IResourceDelta[] resourceDeltas = delta.getResourceDeltas();
if (resourceDeltas != null) {
for (int i = 0; i < resourceDeltas.length; i++) {
processResourceDelta(result, resourceDeltas[i]);
}
}
IModelElementDelta[] children = delta.getAffectedChildren();
for (int i = 0; i < children.length; i++) {
processScriptDelta(result, children[i]);
}
}
private void processResourceDelta(WorkingSetDelta result,
IResourceDelta delta) {
IResource resource = delta.getResource();
int type = resource.getType();
int index = result.indexOf(resource);
int kind = delta.getKind();
int flags = delta.getFlags();
if (kind == IResourceDelta.CHANGED && type == IResource.PROJECT
&& index != -1) {
if ((flags & IResourceDelta.OPEN) != 0) {
result.set(index, resource);
}
}
if (index != -1 && kind == IResourceDelta.REMOVED) {
if ((flags & IResourceDelta.MOVED_TO) != 0) {
result.set(index, ResourcesPlugin.getWorkspace().getRoot()
.findMember(delta.getMovedToPath()));
} else {
result.remove(index);
}
}
// Don't dive into closed or opened projects
if (projectGotClosedOrOpened(resource, kind, flags))
return;
IResourceDelta[] children = delta.getAffectedChildren();
for (int i = 0; i < children.length; i++) {
processResourceDelta(result, children[i]);
}
}
private boolean projectGotClosedOrOpened(IResource resource, int kind,
int flags) {
return resource.getType() == IResource.PROJECT
&& kind == IResourceDelta.CHANGED
&& (flags & IResourceDelta.OPEN) != 0;
}
private void checkElementExistence(IWorkingSet workingSet) {
List<IAdaptable> elements = new ArrayList<>(
Arrays.asList(workingSet.getElements()));
boolean changed = false;
for (Iterator<IAdaptable> iter = elements.iterator(); iter.hasNext();) {
IAdaptable element = iter.next();
boolean remove = false;
if (element instanceof IModelElement) {
IModelElement jElement = (IModelElement) element;
// If we have directly a project then remove it when it
// doesn't exist anymore. However if we have a sub element
// under a project only remove the element if the parent
// project is open. Otherwise we would remove all elements
// in closed projects.
if (jElement instanceof IScriptProject) {
remove = !jElement.exists();
} else {
IProject project = jElement.getScriptProject().getProject();
remove = project.isOpen() && !jElement.exists();
}
} else if (element instanceof IResource) {
IResource resource = (IResource) element;
// See comments above
if (resource instanceof IProject) {
remove = !resource.exists();
} else {
IProject project = resource.getProject();
remove = (project != null ? project.isOpen() : true)
&& !resource.exists();
}
}
if (remove) {
iter.remove();
changed = true;
}
}
if (changed) {
workingSet.setElements(
elements.toArray(new IAdaptable[elements.size()]));
}
}
}