blob: a2f7552485f6489b4c3eedef94687a92e71d1516 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2017 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
*******************************************************************************/
package org.eclipse.dltk.internal.core;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.core.DLTKLanguageManager;
import org.eclipse.dltk.core.IDLTKLanguageToolkit;
import org.eclipse.dltk.core.IModelElement;
import org.eclipse.dltk.core.IScriptModel;
import org.eclipse.dltk.core.IScriptProject;
import org.eclipse.dltk.core.ModelException;
import org.eclipse.dltk.core.WorkingCopyOwner;
import org.eclipse.dltk.core.environment.EnvironmentPathUtils;
import org.eclipse.dltk.core.environment.IFileHandle;
import org.eclipse.dltk.internal.core.util.MementoTokenizer;
import org.eclipse.dltk.utils.CorePrinter;
public class Model extends Openable implements IScriptModel {
/**
* A set of java.io.Files used as a cache of external files that are known
* to be existing. Note this cache is kept for the whole session.
*/
public static HashSet<IFileHandle> existingExternalFiles = new HashSet<>();
/**
* A set of external files ({@link #existingExternalFiles}) which have been
* confirmed as file (ie. which returns true to
* {@link java.io.File#isFile()}. Note this cache is kept for the whole
* session.
*/
public static HashSet<IFileHandle> existingExternalConfirmedFiles = new HashSet<>();
protected Model() {
super(null);
}
@Override
protected boolean buildStructure(OpenableElementInfo info,
IProgressMonitor pm, Map newElements,
IResource underlyingResource) /*
* throws ModelException
*/ {
// determine my children
IProject[] projects = ResourcesPlugin.getWorkspace().getRoot()
.getProjects();
int length = projects.length;
IModelElement[] children = new IModelElement[length];
int index = 0;
for (int i = 0; i < length; i++) {
IProject project = projects[i];
if (ScriptProject.hasScriptNature(project)) {
children[index++] = getScriptProject(project);
}
}
if (index < length)
System.arraycopy(children, 0, children = new IModelElement[index],
0, index);
info.setChildren(children);
newElements.put(this, info);
return true;
}
/**
* Helper method - returns the targeted item (IResource if internal or
* IFileHandle if external), or null if unbound Internal items must be
* referred to using container relative paths.
*/
public static Object getTarget(IContainer container, IPath path,
boolean checkResourceExistence) {
if (path == null)
return null;
// lookup - inside the container
if (path.getDevice() == null) { // container relative paths should not
// contain a device
// (see http://dev.eclipse.org/bugs/show_bug.cgi?id=18684)
// (case of a workspace rooted at d:\ )
IResource resource = container.findMember(path);
if (resource != null) {
if (!checkResourceExistence || resource.exists())
return resource;
return null;
}
}
// if path is relative, it cannot be an external path
// (see http://dev.eclipse.org/bugs/show_bug.cgi?id=22517)
if (!path.isAbsolute())
return null;
// lookup - outside the container
IFileHandle externalFile = EnvironmentPathUtils.getFile(path);
if (externalFile != null) {
if (!checkResourceExistence) {
return externalFile;
} else if (existingExternalFiles.contains(externalFile)) {
return externalFile;
} else {
if (ModelManager.ZIP_ACCESS_VERBOSE) {
System.out.println("(" + Thread.currentThread() //$NON-NLS-1$
+ ") [Model.getTarget(...)] Checking existence of " //$NON-NLS-1$
+ path.toString());
}
if (externalFile.exists()) {
// cache external file
existingExternalFiles.add(externalFile);
return externalFile;
}
}
}
return null;
}
/**
* Returns the active script project associated with the specified resource,
* or <code>null</code> if no script project yet exists for the resource.
*
* @exception IllegalArgumentException
* if the given resource is not one of an IProject, IFolder,
* or IFile.
*/
public IScriptProject getScriptProject(IResource resource) {
switch (resource.getType()) {
case IResource.FOLDER:
return new ScriptProject(((IFolder) resource).getProject(), this);
case IResource.FILE:
return new ScriptProject(((IFile) resource).getProject(), this);
case IResource.PROJECT:
return new ScriptProject((IProject) resource, this);
default:
throw new IllegalArgumentException(
Messages.Model_invalidResourceForTheProject);
}
}
/**
* @see IScriptModel
*/
@Override
public IScriptProject getScriptProject(String projectName) {
return new ScriptProject(ResourcesPlugin.getWorkspace().getRoot()
.getProject(projectName), this);
}
/**
* @see IScriptModel
*/
@Override
public IScriptProject[] getScriptProjects() throws ModelException {
final List<IModelElement> list = getChildrenOfType(SCRIPT_PROJECT);
return list.toArray(new IScriptProject[list.size()]);
}
@Override
public IScriptProject[] getScriptProjects(String nature)
throws ModelException {
final List<IModelElement> list = getChildrenOfType(SCRIPT_PROJECT);
final List<IScriptProject> result = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
IScriptProject project = (IScriptProject) list.get(i);
IDLTKLanguageToolkit toolkit = DLTKLanguageManager
.getLanguageToolkit(project);
if (toolkit.getNatureId().equals(nature)) {
result.add(project);
}
}
return result.toArray(new IScriptProject[result.size()]);
}
@Override
public void copy(IModelElement[] elements, IModelElement[] containers,
IModelElement[] siblings, String[] renamings, boolean force,
IProgressMonitor monitor) throws ModelException {
if (elements != null && elements.length > 0 && elements[0] != null
&& elements[0].getElementType() < IModelElement.TYPE) {
runOperation(new CopyResourceElementsOperation(elements, containers,
force), elements, siblings, renamings, monitor);
} else {
runOperation(new CopyElementsOperation(elements, containers, force),
elements, siblings, renamings, monitor);
}
}
@Override
protected Object createElementInfo() {
return new ModelInfo();
}
@Override
public int getElementType() {
return SCRIPT_MODEL;
}
@Override
public IResource getResource() {
return ResourcesPlugin.getWorkspace().getRoot();
}
@Override
public IPath getPath() {
return Path.ROOT;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Model))
return false;
return super.equals(o);
}
/**
* Flushes the cache of external files known to be existing.
*/
public static void flushExternalFileCache() {
existingExternalFiles = new HashSet<>();
existingExternalConfirmedFiles = new HashSet<>();
}
/**
* Configures and runs the <code>MultiOperation</code>.
*/
protected void runOperation(MultiOperation op, IModelElement[] elements,
IModelElement[] siblings, String[] renamings,
IProgressMonitor monitor) throws ModelException {
op.setRenamings(renamings);
if (siblings != null) {
for (int i = 0; i < elements.length; i++) {
op.setInsertBefore(elements[i], siblings[i]);
}
}
op.runOperation(monitor);
}
/**
* @private Debugging purposes
*/
@Override
protected void toStringInfo(int tab, StringBuffer buffer, Object info,
boolean showResolvedInfo) {
buffer.append(this.tabString(tab));
buffer.append("Model"); //$NON-NLS-1$
if (info == null) {
buffer.append(" (not open)"); //$NON-NLS-1$
}
}
@Override
public void printNode(CorePrinter output) {
output.formatPrint("DLTK Model:" + getElementName()); //$NON-NLS-1$
output.indent();
try {
IModelElement modelElements[] = this.getChildren();
for (int i = 0; i < modelElements.length; ++i) {
IModelElement element = modelElements[i];
if (element instanceof ModelElement) {
((ModelElement) element).printNode(output);
} else {
output.print("Unknown element:" + element); //$NON-NLS-1$
}
}
} catch (ModelException ex) {
output.formatPrint(ex.getLocalizedMessage());
}
output.dedent();
}
@Override
public void delete(IModelElement[] elements, boolean force,
IProgressMonitor monitor) throws ModelException {
if (elements != null && elements.length > 0 && elements[0] != null
&& elements[0].getElementType() < IModelElement.TYPE) {
new DeleteResourceElementsOperation(elements, force)
.runOperation(monitor);
} else {
// new DeleteElementsOperation(elements,
// force).runOperation(monitor);
}
if (DLTKCore.DEBUG) {
System.err.println("Add Delete operations"); //$NON-NLS-1$
}
}
/**
* Helper method - returns the file item (ie. which returns true to
* {@link java.io.File#isFile()}, or null if unbound
*/
public static synchronized IFileHandle getFile(Object target) {
if (existingExternalConfirmedFiles.contains(target))
return (IFileHandle) target;
if (target instanceof IFileHandle) {
IFileHandle f = (IFileHandle) target;
if (f.isFile()) {
existingExternalConfirmedFiles.add(f);
return f;
}
}
return null;
}
/**
* Helper method - returns whether an object is afile (ie. which returns
* true to {@link java.io.File#isFile()}.
*/
public static boolean isFile(Object target) {
return getFile(target) != null;
}
/*
* @see IScriptModel
*/
@Override
public boolean contains(IResource resource) {
switch (resource.getType()) {
case IResource.ROOT:
case IResource.PROJECT:
return true;
}
// file or folder
IScriptProject[] projects;
try {
projects = this.getScriptProjects();
} catch (ModelException e) {
return false;
}
for (int i = 0, length = projects.length; i < length; i++) {
ScriptProject project = (ScriptProject) projects[i];
if (!project.contains(resource)) {
return false;
}
}
return true;
}
@Override
public IModelElement getHandleFromMemento(String token,
MementoTokenizer memento, WorkingCopyOwner owner) {
switch (token.charAt(0)) {
case JEM_SCRIPTPROJECT:
if (!memento.hasMoreTokens())
return this;
String projectName = memento.nextToken();
ModelElement project = (ModelElement) getScriptProject(projectName);
return project.getHandleFromMemento(memento, owner);
case JEM_USER_ELEMENT:
return MementoModelElementUtil.getHandleFromMemento(memento, this,
owner);
}
return null;
}
@Override
protected char getHandleMementoDelimiter() {
Assert.isTrue(false, "Should not be called"); //$NON-NLS-1$
return 0;
}
@Override
public Object[] getForeignResources() throws ModelException {
return ((ModelInfo) getElementInfo()).getForeignResources();
}
@Override
public IWorkspace getWorkspace() {
return ResourcesPlugin.getWorkspace();
}
@Override
public void move(IModelElement[] elements, IModelElement[] containers,
IModelElement[] siblings, String[] renamings, boolean force,
IProgressMonitor monitor) throws ModelException {
if (elements != null && elements.length > 0 && elements[0] != null
&& elements[0].getElementType() < IModelElement.TYPE) {
runOperation(new MoveResourceElementsOperation(elements, containers,
force), elements, siblings, renamings, monitor);
} else {
if (DLTKCore.DEBUG) {
System.err.println("TODO:Add move elements operation"); //$NON-NLS-1$
}
// runOperation(new MoveElementsOperation(elements, containers,
// force), elements, siblings, renamings, monitor);
}
}
@Override
public IResource getUnderlyingResource() {
return null;
}
@Override
public void getHandleMemento(StringBuffer buff) {
buff.append(getElementName());
}
@Override
public void rename(IModelElement[] elements, IModelElement[] destinations,
String[] renamings, boolean force, IProgressMonitor monitor)
throws ModelException {
MultiOperation op;
if (elements != null && elements.length > 0 && elements[0] != null
&& elements[0].getElementType() < IModelElement.TYPE) {
op = new RenameResourceElementsOperation(elements, destinations,
renamings, force);
} else {
op = new RenameElementsOperation(elements, destinations, renamings,
force);
}
op.runOperation(monitor);
}
}