| /*=============================================================================# |
| # Copyright (c) 2010, 2020 IBM Corporation and others. |
| # |
| # This program and the accompanying materials are made available under the |
| # terms of the Eclipse Public License 2.0 which is available at |
| # https://www.eclipse.org/legal/epl-2.0. |
| # |
| # SPDX-License-Identifier: EPL-2.0 |
| # |
| # Contributors: |
| # IBM Corporation - org.eclipse.jdt: initial API and implementation |
| # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation |
| #=============================================================================*/ |
| |
| package org.eclipse.statet.ltk.buildpaths.ui; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.IWorkspaceRoot; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Status; |
| |
| import org.eclipse.statet.jcommons.collections.ImCollection; |
| import org.eclipse.statet.jcommons.collections.ImCollections; |
| import org.eclipse.statet.jcommons.collections.ImList; |
| |
| import org.eclipse.statet.ltk.buildpaths.core.BuildpathElement; |
| import org.eclipse.statet.ltk.buildpaths.core.BuildpathElementType; |
| import org.eclipse.statet.ltk.buildpaths.core.BuildpathInitializer; |
| import org.eclipse.statet.ltk.buildpaths.core.IBuildpathAttribute; |
| import org.eclipse.statet.ltk.buildpaths.core.IBuildpathElement; |
| |
| |
| public class BuildpathListElement { |
| |
| |
| private final BuildpathElementType type; |
| |
| private final IProject project; |
| |
| private IPath path; |
| private final IPath orginalPath; |
| private final IResource resource; |
| |
| private boolean isMissing; |
| |
| private Object parent; |
| private final ArrayList<Object> children; |
| |
| private IPath linkTarget; |
| private final IPath orginalLinkTarget; |
| |
| private IBuildpathElement cachedElement; |
| |
| |
| public BuildpathListElement(final Object parent, final IProject project, final BuildpathElementType type, |
| final IPath path, final IResource resource, final IPath linkTarget, final boolean newElement) { |
| this.type= type; |
| |
| this.parent= parent; |
| this.children= new ArrayList<>(); |
| |
| this.project= project; |
| |
| this.isMissing= false; |
| |
| this.path= path; |
| this.orginalPath= (newElement) ? null : path; |
| this.linkTarget= linkTarget; |
| this.orginalLinkTarget= linkTarget; |
| this.resource= resource; |
| |
| initBuiltinAttributes(); |
| } |
| |
| public BuildpathListElement(final IProject project, final Object parent, |
| final IBuildpathElement element, final boolean newElement) { |
| this.type= element.getType(); |
| |
| this.parent= parent; |
| this.children= new ArrayList<>(); |
| |
| this.project= project; |
| |
| this.isMissing= false; |
| |
| { IPath path= element.getPath(); |
| final IWorkspaceRoot root= ResourcesPlugin.getWorkspace().getRoot(); |
| |
| // get the resource |
| IResource resource= null; |
| IPath linkTarget= null; |
| |
| |
| switch (element.getType().getName()) { |
| case IBuildpathElement.SOURCE: |
| path= path.removeTrailingSeparator(); |
| resource= root.findMember(path); |
| if (resource == null) { |
| if (root.getWorkspace().validatePath(path.toString(), IResource.FOLDER).isOK()) { |
| resource= root.getFolder(path); |
| } |
| this.isMissing= true; |
| } |
| else if (resource.isLinked()) { |
| linkTarget= resource.getLocation(); |
| } |
| break; |
| case IBuildpathElement.PROJECT: |
| resource= root.findMember(path); |
| this.isMissing= (resource == null); |
| break; |
| default: |
| throw new UnsupportedOperationException(element.getType().getName()); |
| } |
| |
| this.path= path; |
| this.orginalPath= (newElement) ? null : path; |
| this.resource= resource; |
| |
| this.linkTarget= linkTarget; |
| this.orginalLinkTarget= linkTarget; |
| } |
| |
| initBuiltinAttributes(); |
| setAttribute(IBuildpathAttribute.FILTER_INCLUSIONS, element.getInclusionPatterns()); |
| setAttribute(IBuildpathAttribute.FILTER_EXCLUSIONS, element.getExclusionPatterns()); |
| setAttribute(IBuildpathAttribute.SOURCE_ATTACHMENT, element.getSourceAttachmentPath()); |
| setAttribute(IBuildpathAttribute.OUTPUT, element.getOutputPath()); |
| |
| final ImList<IBuildpathAttribute> extraAttributes= element.getExtraAttributes(); |
| for (final IBuildpathAttribute attribute : extraAttributes) { |
| if (setAttribute(attribute.getName(), attribute.getValue()) == null) { |
| addExtraAttribute(attribute.getName(), attribute.getValue()); |
| } |
| } |
| } |
| |
| |
| /** |
| * Gets the class path entry kind. |
| * @return the entry kind |
| * @see IBuildpathElement#getType() |
| */ |
| public BuildpathElementType getType() { |
| return this.type; |
| } |
| |
| /** |
| * Entries without resource are either non existing or a variable entry |
| * External jars do not have a resource |
| * @return returns the resource |
| */ |
| public IResource getResource() { |
| return this.resource; |
| } |
| |
| /** |
| * Gets the project. |
| * @return Returns a IProject |
| */ |
| public IProject getProject() { |
| return this.project; |
| } |
| |
| /** |
| * Gets the class path entry path. |
| * @return returns the path |
| * @see IBuildpathElement#getPath() |
| */ |
| public IPath getPath() { |
| return this.path; |
| } |
| |
| public IPath getOrginalPath() { |
| return this.orginalPath; |
| } |
| |
| public void setPath(final IPath path) { |
| this.cachedElement= null; |
| this.path= path; |
| } |
| |
| |
| public IPath getLinkTarget() { |
| return this.linkTarget; |
| } |
| |
| public IPath getOrginalLinkTarget() { |
| return this.orginalLinkTarget; |
| } |
| |
| public void setLinkTarget(final IPath linkTarget) { |
| this.cachedElement= null; |
| this.linkTarget= linkTarget; |
| } |
| |
| |
| public IBuildpathElement getCoreElement() { |
| if (this.cachedElement == null) { |
| this.cachedElement= newCoreElement(); |
| } |
| return this.cachedElement; |
| } |
| |
| private IBuildpathElement newCoreElement() { |
| return new BuildpathElement(this.type, this.path, |
| (this.type.isAttributeBuiltin(IBuildpathAttribute.FILTER_INCLUSIONS)) ? |
| (ImList<IPath>) getAttributeValue(IBuildpathAttribute.FILTER_INCLUSIONS) : null, |
| (this.type.isAttributeBuiltin(IBuildpathAttribute.FILTER_EXCLUSIONS)) ? |
| (ImList<IPath>) getAttributeValue(IBuildpathAttribute.FILTER_EXCLUSIONS) : null, |
| (this.type.isAttributeBuiltin(IBuildpathAttribute.SOURCE_ATTACHMENT)) ? |
| (IPath) getAttributeValue(IBuildpathAttribute.SOURCE_ATTACHMENT) : null, |
| null, |
| (this.type.isAttributeBuiltin(IBuildpathAttribute.OUTPUT)) ? |
| (IPath) getAttributeValue(IBuildpathAttribute.OUTPUT) : null, |
| null, |
| false, |
| ImCollections.toList(getExtraAttributes()) ); |
| } |
| |
| |
| public List<Object> getChildren() { |
| return getFilteredChildren(ImCollections.<String>emptySet()); |
| } |
| |
| private void initBuiltinAttributes() { |
| for (final String attributeKey : this.type.getAttributeBuiltinKeys()) { |
| switch (attributeKey) { |
| case IBuildpathAttribute.FILTER_INCLUSIONS: |
| case IBuildpathAttribute.FILTER_EXCLUSIONS: |
| createAttribute(attributeKey, ImCollections.emptyList(), true); |
| continue; |
| case IBuildpathAttribute.OUTPUT: |
| createAttribute(attributeKey, null, true); |
| continue; |
| default: |
| throw new IllegalStateException(attributeKey); |
| } |
| } |
| } |
| |
| private List<IBuildpathAttribute> getExtraAttributes() { |
| final ArrayList<IBuildpathAttribute> list= new ArrayList<>(Math.min(this.children.size(), 8)); |
| for (final Object child : this.children) { |
| if (child instanceof BuildpathListElementAttribute) { |
| final BuildpathListElementAttribute attribute= (BuildpathListElementAttribute) child; |
| if (!attribute.isBuiltin() && attribute.getValue() != null) { |
| list.add(attribute.getCoreAttribute()); |
| } |
| } |
| } |
| return list; |
| } |
| |
| private boolean isFiltered(final Object child, final ImCollection<String> filteredAttributeKeys) { |
| if (child instanceof BuildpathListElementAttribute) { |
| final BuildpathListElementAttribute attribute= (BuildpathListElementAttribute) child; |
| if (filteredAttributeKeys.contains(attribute.getName())) { |
| return true; |
| } |
| if (attribute.getStatus().getCode() == BuildpathInitializer.NOT_SUPPORTED) { |
| return true; |
| } |
| if (!attribute.isBuiltin()) { |
| // return !BuildpathsUtils.getDefault().getClasspathAttributeConfigurationDescriptors().containsKey(key); |
| } |
| } |
| return false; |
| } |
| |
| public List<Object> getFilteredChildren(final ImCollection<String> filteredAttributeKeys) { |
| final int nChildren= this.children.size(); |
| final ArrayList<Object> filtered= new ArrayList<>(nChildren); |
| |
| for (int i= 0; i < nChildren; i++) { |
| final Object child= this.children.get(i); |
| if (!isFiltered(child, filteredAttributeKeys)) { |
| filtered.add(child); |
| } |
| } |
| return filtered; |
| } |
| |
| public BuildpathListElementAttribute findAttribute(final String name) { |
| for (final Object child : this.children) { |
| if (child instanceof BuildpathListElementAttribute) { |
| final BuildpathListElementAttribute attribute= (BuildpathListElementAttribute) child; |
| if (name.equals(attribute.getName())) { |
| return attribute; |
| } |
| } |
| } |
| return null; |
| } |
| |
| public Object getAttributeValue(final String name) { |
| final BuildpathListElementAttribute attribute= findAttribute(name); |
| if (attribute != null) { |
| return attribute.getValue(); |
| } |
| return null; |
| } |
| |
| public List<BuildpathListElementAttribute> getAllAttributes() { |
| final ArrayList<BuildpathListElementAttribute> attributes= new ArrayList<>(); |
| for (final Object child : this.children) { |
| if (child instanceof BuildpathListElementAttribute) { |
| attributes.add((BuildpathListElementAttribute) child); |
| } |
| } |
| return attributes; |
| } |
| |
| /** |
| * Notifies that an attribute has changed |
| * |
| * @param name name of changed attribute |
| */ |
| protected void attributeChanged(final String name) { |
| this.cachedElement= null; |
| } |
| |
| public BuildpathListElementAttribute setAttribute(final String name, final Object value) { |
| final BuildpathListElementAttribute attribute= findAttribute(name); |
| if (attribute == null) { |
| return null; |
| } |
| |
| switch(name) { |
| case IBuildpathAttribute.FILTER_INCLUSIONS: |
| case IBuildpathAttribute.FILTER_EXCLUSIONS: |
| if (!(value instanceof ImList<?>)) { |
| throw new IllegalArgumentException(); |
| } |
| break; |
| default: |
| break; |
| } |
| |
| attribute.setValue(value); |
| return attribute; |
| } |
| |
| private BuildpathListElementAttribute createAttribute(final String name, |
| final Object value, final boolean builtin) { |
| final BuildpathListElementAttribute attribute= new BuildpathListElementAttribute(this, |
| name, value, builtin ); |
| this.children.add(attribute); |
| return attribute; |
| } |
| |
| public void setAttributesFromExisting(final BuildpathListElement existing) { |
| Assert.isTrue(existing.getType() == getType()); |
| final List<BuildpathListElementAttribute> attributes= existing.getAllAttributes(); |
| for (final BuildpathListElementAttribute attribute : attributes) { |
| final BuildpathListElementAttribute elem= findAttribute(attribute.getName()); |
| if (elem == null) { |
| createAttribute(attribute.getName(), attribute.getValue(), false); |
| } |
| else { |
| elem.setValue(attribute.getValue()); |
| } |
| } |
| } |
| |
| public BuildpathListElementAttribute addExtraAttribute(final String name, final Object value) { |
| return createAttribute(name, value, false); |
| } |
| |
| |
| public Object getParent() { |
| return this.parent; |
| } |
| |
| /** |
| * Sets the parent container. |
| * |
| * @param parent the parent container |
| * @since 3.7 |
| */ |
| void setParentContainer(final Object parent) { |
| this.parent= parent; |
| } |
| |
| |
| private IStatus evaluateContainerChildStatus(final BuildpathListElementAttribute attrib) { |
| return null; |
| } |
| |
| public IStatus getContainerChildStatus(final BuildpathListElementAttribute attrib) { |
| if (this.parent instanceof BuildpathListElement) { |
| final BuildpathListElement parentElement= (BuildpathListElement) this.parent; |
| return parentElement.getContainerChildStatus(attrib); |
| } |
| return Status.OK_STATUS; |
| } |
| |
| public boolean isInContainer(final String containerName) { |
| if (this.parent instanceof BuildpathListElement) { |
| final BuildpathListElement elem= (BuildpathListElement) this.parent; |
| return new Path(containerName).isPrefixOf(elem.getPath()); |
| } |
| return false; |
| } |
| |
| |
| /** |
| * Returns if a entry is missing. |
| * @return Returns a boolean |
| */ |
| public boolean isMissing() { |
| return this.isMissing; |
| } |
| |
| /** |
| * Returns if a entry has children that are missing |
| * @return Returns a boolean |
| */ |
| public boolean hasMissingChildren() { |
| for (final Object child : this.children) { |
| if (child instanceof BuildpathListElement |
| && ((BuildpathListElement) child).isMissing()) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Sets the 'missing' state of the entry. |
| * @param isMissing the new state |
| */ |
| public void setIsMissing(final boolean isMissing) { |
| this.isMissing= isMissing; |
| } |
| |
| |
| public boolean isDeprecated() { |
| return false; |
| } |
| |
| public String getDeprecationMessage() { |
| return null; |
| } |
| |
| |
| @Override |
| public int hashCode() { |
| return this.type.hashCode() + this.path.hashCode(); |
| } |
| |
| @Override |
| public boolean equals(final Object obj) { |
| if (this == obj) { |
| return true; |
| } |
| if (obj != null && obj.getClass().equals(getClass())) { |
| final BuildpathListElement other= (BuildpathListElement) obj; |
| return getCoreElement().equals(other.getCoreElement()); |
| } |
| return false; |
| } |
| |
| @Override |
| public String toString() { |
| return getCoreElement().toString(); |
| } |
| |
| } |