blob: df3567ee5e337548354d6a908285f6f9e9755ec1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2015 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ltk.internal.core.refactoring.resource.undostates;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URI;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFileState;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceStatus;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.ltk.internal.core.refactoring.RefactoringCoreMessages;
/**
* {@link FileUndoState} is a lightweight description that describes a file to be
* created.
*
* This class is not intended to be instantiated or used by clients.
*
* @since 3.4
*
*/
public class FileUndoState extends AbstractResourceUndoState {
protected String name;
private URI location;
private String charset;
private IFileContentDescription fileContentDescription;
/**
* Create a {@link FileUndoState} that can be used to later restore the given
* file. The file typically already exists, but this constructor will not
* fail if the file does not exist.
*
* @param file
* the file to be restored.
*/
public FileUndoState(IFile file) {
super(file);
this.name= file.getName();
try {
this.charset= file.getCharset(false);
} catch (CoreException e) {
// we don't care, a null charset is fine.
}
if (file.isLinked()) {
location= file.getLocationURI();
}
}
/**
* Create a {@link FileUndoState} from the specified file handle. The handle does
* not exist, so no information should be derived from it. If a location
* path is specified, this file should represent a link to another location.
* The content description describes any state that should be used when the
* file resource is created.
*
* @param file
* the file to be described
* @param linkLocation
* the location of the file's link, or <code>null</code> if the
* file is not linked
* @param fileContentDescription
* the file content description that can be used to get
* information about the file, such as its initial content
*/
public FileUndoState(IFile file, URI linkLocation, IFileContentDescription fileContentDescription) {
super(file);
this.name= file.getName();
this.location= linkLocation;
this.charset= null;
this.fileContentDescription= fileContentDescription;
}
@Override
public void recordStateFromHistory(IResource resource, IProgressMonitor monitor) throws CoreException {
Assert.isLegal(resource.getType() == IResource.FILE);
if (location != null) {
// file is linked, no need to record any history
return;
}
IFileState[] states= ((IFile) resource).getHistory(monitor);
if (states.length > 0) {
final IFileState state= getMatchingFileState(states);
this.fileContentDescription= new IFileContentDescription() {
@Override
public boolean exists() {
return state.exists();
}
@Override
public InputStream getContents() throws CoreException {
return state.getContents();
}
@Override
public String getCharset() throws CoreException {
return state.getCharset();
}
};
}
}
@Override
public IResource createResourceHandle() {
IWorkspaceRoot workspaceRoot= parent.getWorkspace().getRoot();
IPath fullPath= parent.getFullPath().append(name);
return workspaceRoot.getFile(fullPath);
}
@Override
public void createExistentResourceFromHandle(IResource resource, IProgressMonitor monitor) throws CoreException {
Assert.isLegal(resource instanceof IFile);
if (resource.exists()) {
return;
}
IFile fileHandle= (IFile) resource;
monitor.beginTask("", 200); //$NON-NLS-1$
monitor.setTaskName(RefactoringCoreMessages.FileDescription_NewFileProgress);
try {
if (monitor.isCanceled()) {
throw new OperationCanceledException();
}
if (location != null) {
fileHandle.createLink(location, IResource.ALLOW_MISSING_LOCAL, new SubProgressMonitor(monitor, 200));
} else {
InputStream contents;
// Retrieve the contents from the file content
// description. Other file state attributes, such as timestamps,
// have already been retrieved from the original IResource
// object and are restored in #restoreResourceAttributes
if (fileContentDescription != null && fileContentDescription.exists()) {
contents= fileContentDescription.getContents();
} else {
contents= new ByteArrayInputStream(RefactoringCoreMessages.FileDescription_ContentsCouldNotBeRestored.getBytes());
}
fileHandle.create(contents, false, new SubProgressMonitor(monitor, 100));
fileHandle.setCharset(charset, new SubProgressMonitor(monitor, 100));
}
if (monitor.isCanceled()) {
throw new OperationCanceledException();
}
} catch (CoreException e) {
if (e.getStatus().getCode() == IResourceStatus.PATH_OCCUPIED) {
fileHandle.refreshLocal(IResource.DEPTH_ZERO, null);
} else {
throw e;
}
} finally {
monitor.done();
}
}
@Override
public boolean isValid() {
if (location != null) {
return super.isValid();
}
return super.isValid() && fileContentDescription != null && fileContentDescription.exists();
}
@Override
public String getName() {
return name;
}
/**
* Get the file state that matches this file description. The local time
* stamp is used to try to find a matching file state. If none can be found,
* the most recent copy of the file state is used.
* @param states file states
* @return best guess state
*/
private IFileState getMatchingFileState(IFileState[] states) {
for (IFileState state : states) {
if (localTimeStamp == state.getModificationTime()) {
return state;
}
}
return states[0];
}
@Override
protected void restoreResourceAttributes(IResource resource) throws CoreException {
super.restoreResourceAttributes(resource);
Assert.isLegal(resource instanceof IFile);
IFile file= (IFile) resource;
if (charset != null) {
file.setCharset(charset, null);
}
}
}