| /******************************************************************************* |
| * 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.scriptview; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| 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.ResourcesPlugin; |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.dltk.core.DLTKCore; |
| import org.eclipse.dltk.core.IModelElement; |
| import org.eclipse.dltk.core.IScriptModel; |
| import org.eclipse.dltk.core.IScriptProject; |
| import org.eclipse.dltk.internal.ui.navigator.ScriptExplorerContentProvider; |
| import org.eclipse.dltk.internal.ui.workingsets.WorkingSetIDs; |
| import org.eclipse.dltk.internal.ui.workingsets.WorkingSetModel; |
| import org.eclipse.jface.util.IPropertyChangeListener; |
| import org.eclipse.jface.util.PropertyChangeEvent; |
| import org.eclipse.jface.viewers.TreePath; |
| import org.eclipse.ui.IWorkingSet; |
| import org.eclipse.ui.IWorkingSetManager; |
| |
| public abstract class WorkingSetAwareContentProvider |
| extends ScriptExplorerContentProvider |
| implements IMultiElementTreeContentProvider { |
| |
| private WorkingSetModel fWorkingSetModel; |
| private IPropertyChangeListener fListener; |
| |
| public WorkingSetAwareContentProvider(boolean provideMembers, |
| WorkingSetModel model) { |
| super(provideMembers); |
| fWorkingSetModel = model; |
| fListener = event -> workingSetModelChanged(event); |
| fWorkingSetModel.addPropertyChangeListener(fListener); |
| } |
| |
| @Override |
| public void dispose() { |
| fWorkingSetModel.removePropertyChangeListener(fListener); |
| super.dispose(); |
| } |
| |
| @Override |
| public boolean hasChildren(Object element) { |
| if (element instanceof IWorkingSet) |
| return true; |
| return super.hasChildren(element); |
| } |
| |
| @Override |
| public Object[] getChildren(Object element) { |
| Object[] children; |
| if (element instanceof WorkingSetModel) { |
| Assert.isTrue(fWorkingSetModel == element); |
| return fWorkingSetModel.getActiveWorkingSets(); |
| } else if (element instanceof IWorkingSet) { |
| children = getWorkingSetChildren((IWorkingSet) element); |
| } else { |
| children = super.getChildren(element); |
| } |
| return children; |
| } |
| |
| private Object[] getWorkingSetChildren(IWorkingSet set) { |
| IAdaptable[] elements = fWorkingSetModel.getChildren(set); |
| boolean isKnownWorkingSet = isKnownWorkingSet(set); |
| List result = new ArrayList(elements.length); |
| for (int i = 0; i < elements.length; i++) { |
| IAdaptable element = elements[i]; |
| boolean add = false; |
| if (element instanceof IProject) { |
| add = true; |
| } else if (element instanceof IResource) { |
| IProject project = ((IResource) element).getProject(); |
| add = project == null || project.isOpen(); |
| } else if (element instanceof IScriptProject) { |
| add = true; |
| } else if (element instanceof IModelElement) { |
| IProject project = getProject((IModelElement) element); |
| add = project == null || project.isOpen(); |
| } |
| if (add) { |
| if (isKnownWorkingSet) { |
| result.add(element); |
| } else { |
| IProject project = element.getAdapter(IProject.class); |
| if (project != null && project.exists()) { |
| IScriptProject jp = DLTKCore.create(project); |
| if (jp != null && jp.exists()) { |
| result.add(jp); |
| } else { |
| result.add(project); |
| } |
| } |
| } |
| } |
| } |
| return result.toArray(); |
| } |
| |
| private boolean isKnownWorkingSet(IWorkingSet set) { |
| String id = set.getId(); |
| return WorkingSetIDs.OTHERS.equals(id) |
| || WorkingSetIDs.SCRIPT.equals(id) |
| || WorkingSetIDs.RESOURCE.equals(id); |
| } |
| |
| private IProject getProject(IModelElement element) { |
| if (element == null) |
| return null; |
| IScriptProject project = element.getScriptProject(); |
| if (project == null) |
| return null; |
| return project.getProject(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public TreePath[] getTreePaths(Object element) { |
| if (element instanceof IWorkingSet) { |
| TreePath path = new TreePath(new Object[] { element }); |
| return new TreePath[] { path }; |
| } |
| List modelParents = getModelPath(element); |
| List<TreePath> result = new ArrayList<>(); |
| for (int i = 0; i < modelParents.size(); i++) { |
| result.addAll(getTreePaths(modelParents, i)); |
| } |
| return result.toArray(new TreePath[result.size()]); |
| } |
| |
| private List getModelPath(Object element) { |
| List result = new ArrayList(); |
| result.add(element); |
| Object parent = super.getParent(element); |
| Object input = getViewerInput(); |
| // stop at input or on ScriptModel. We never visualize it anyway. |
| while (parent != null && !parent.equals(input) |
| && !(parent instanceof IScriptModel)) { |
| result.add(parent); |
| parent = super.getParent(parent); |
| } |
| Collections.reverse(result); |
| return result; |
| } |
| |
| private List<TreePath> getTreePaths(List modelParents, int index) { |
| List<TreePath> result = new ArrayList<>(); |
| Object input = getViewerInput(); |
| Object element = modelParents.get(index); |
| Object[] parents = fWorkingSetModel.getAllParents(element); |
| for (int i = 0; i < parents.length; i++) { |
| List chain = new ArrayList(); |
| if (!parents[i].equals(input)) |
| chain.add(parents[i]); |
| for (int m = index; m < modelParents.size(); m++) { |
| chain.add(modelParents.get(m)); |
| } |
| result.add(new TreePath(chain.toArray())); |
| } |
| return result; |
| } |
| |
| @Override |
| public Object getParent(Object child) { |
| Object parent = getExtendedParent(child); |
| if (parent != null) { |
| return parent; |
| } |
| Object[] parents = fWorkingSetModel.getAllParents(child); |
| if (parents.length == 0) |
| return super.getParent(child); |
| Object first = parents[0]; |
| return first; |
| } |
| |
| @Override |
| protected void augmentElementToRefresh(List toRefresh, int relation, |
| Object affectedElement) { |
| // we are refreshing the ScriptModel and are in working set mode. |
| if (DLTKCore.create(ResourcesPlugin.getWorkspace().getRoot()) |
| .equals(affectedElement)) { |
| toRefresh.remove(affectedElement); |
| toRefresh.add(fWorkingSetModel); |
| } else if (relation == GRANT_PARENT) { |
| Object parent = internalGetParent(affectedElement); |
| if (parent != null) { |
| toRefresh.addAll( |
| Arrays.asList(fWorkingSetModel.getAllParents(parent))); |
| } |
| } |
| List nonProjetTopLevelElemens = fWorkingSetModel |
| .getNonProjectTopLevelElements(); |
| if (nonProjetTopLevelElemens.isEmpty()) |
| return; |
| List toAdd = new ArrayList(); |
| for (Iterator iter = nonProjetTopLevelElemens.iterator(); iter |
| .hasNext();) { |
| Object element = iter.next(); |
| if (isChildOf(element, toRefresh)) |
| toAdd.add(element); |
| } |
| toRefresh.addAll(toAdd); |
| } |
| |
| private void workingSetModelChanged(PropertyChangeEvent event) { |
| String property = event.getProperty(); |
| Object newValue = event.getNewValue(); |
| List toRefresh = new ArrayList(1); |
| if (WorkingSetModel.CHANGE_WORKING_SET_MODEL_CONTENT.equals(property)) { |
| toRefresh.add(fWorkingSetModel); |
| } else if (IWorkingSetManager.CHANGE_WORKING_SET_CONTENT_CHANGE |
| .equals(property)) { |
| toRefresh.add(newValue); |
| } else if (IWorkingSetManager.CHANGE_WORKING_SET_NAME_CHANGE |
| .equals(property)) { |
| toRefresh.add(newValue); |
| } |
| ArrayList runnables = new ArrayList(); |
| postRefresh(toRefresh, true, runnables); |
| executeRunnables(runnables); |
| } |
| |
| private boolean isChildOf(Object element, List potentialParents) { |
| // Calling super get parent to bypass working set mapping |
| Object parent = super.getParent(element); |
| if (parent == null) |
| return false; |
| for (Iterator iter = potentialParents.iterator(); iter.hasNext();) { |
| Object potentialParent = iter.next(); |
| while (parent != null) { |
| if (parent.equals(potentialParent)) |
| return true; |
| parent = super.getParent(parent); |
| } |
| |
| } |
| return false; |
| } |
| } |