blob: c3b15340bd30d7432d6209cebaf236a094fd1912 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2018 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.corext.refactoring.changes;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import org.eclipse.core.filebuffers.FileBuffers;
import org.eclipse.core.filebuffers.ITextFileBufferManager;
import org.eclipse.core.filebuffers.LocationKind;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
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.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.core.IProjectFragment;
import org.eclipse.dltk.core.IScriptProject;
import org.eclipse.dltk.core.ModelException;
import org.eclipse.dltk.internal.core.ScriptProject;
import org.eclipse.dltk.internal.corext.refactoring.RefactoringCoreMessages;
import org.eclipse.dltk.internal.corext.refactoring.reorg.IProjectFragmentManipulationQuery;
import org.eclipse.dltk.internal.corext.refactoring.util.ModelElementUtil;
import org.eclipse.dltk.internal.corext.util.Messages;
import org.eclipse.dltk.ui.DLTKUIPlugin;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.CompositeChange;
import org.eclipse.ltk.core.refactoring.NullChange;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.TextFileChange;
import org.eclipse.text.edits.ReplaceEdit;
import org.eclipse.ui.ide.undo.ResourceDescription;
public class DeleteProjectFragmentChange extends AbstractDeleteChange {
private final String fHandle;
private final boolean fIsExecuteChange;
private final IProjectFragmentManipulationQuery fUpdateClasspathQuery;
public DeleteProjectFragmentChange(IProjectFragment root,
boolean isExecuteChange,
IProjectFragmentManipulationQuery updateClasspathQuery) {
Assert.isNotNull(root);
Assert.isTrue(!root.isExternal());
fHandle = root.getHandleIdentifier();
fIsExecuteChange = isExecuteChange;
fUpdateClasspathQuery = updateClasspathQuery;
}
@Override
public String getName() {
return Messages.format(
RefactoringCoreMessages.DeleteProjectFragmentChange_delete,
getRoot().getElementName());
}
@Override
public Object getModifiedElement() {
return getRoot();
}
private IProjectFragment getRoot() {
return (IProjectFragment) DLTKCore.create(fHandle);
}
@Override
public RefactoringStatus isValid(IProgressMonitor pm) throws CoreException {
if (fIsExecuteChange) {
// don't check for read-only resources since we already
// prompt the user via a dialog to confirm deletion of
// read only resource. The change is currently not used
// as
return super.isValid(pm, DIRTY);
}
return super.isValid(pm, READ_ONLY | DIRTY);
}
@Override
protected Change doDelete(IProgressMonitor pm) throws CoreException {
if (!confirmDeleteIfReferenced())
return new NullChange();
int resourceUpdateFlags = IResource.KEEP_HISTORY;
int jCoreUpdateFlags = IProjectFragment.ORIGINATING_PROJECT_BUILDPATH
| IProjectFragment.OTHER_REFERRING_PROJECTS_BUILDPATH;
pm.beginTask("", 2); //$NON-NLS-1$
IProjectFragment root = getRoot();
IResource rootResource = root.getResource();
CompositeChange result = new CompositeChange(getName());
ResourceDescription rootDescription = ResourceDescription
.fromResource(rootResource);
IScriptProject[] referencingProjects = ModelElementUtil
.getReferencingProjects(root);
HashMap<IFile, String> classpathFilesContents = new HashMap<>();
for (int i = 0; i < referencingProjects.length; i++) {
IScriptProject javaProject = referencingProjects[i];
IFile classpathFile = javaProject.getProject()
.getFile(ScriptProject.BUILDPATH_FILENAME);
if (classpathFile.exists()) {
classpathFilesContents.put(classpathFile,
getFileContents(classpathFile));
}
}
root.delete(resourceUpdateFlags, jCoreUpdateFlags,
new SubProgressMonitor(pm, 1));
rootDescription.recordStateFromHistory(rootResource,
new SubProgressMonitor(pm, 1));
for (Iterator<Entry<IFile, String>> iterator = classpathFilesContents
.entrySet().iterator(); iterator.hasNext();) {
Entry<IFile, String> entry = iterator.next();
IFile file = entry.getKey();
String contents = entry.getValue();
// Restore time stamps? This should probably be some sort of
// UndoTextFileChange.
TextFileChange classpathUndo = new TextFileChange(Messages.format(
RefactoringCoreMessages.DeleteProjectFragmentChange_restore_file,
file.getFullPath().toOSString()), file);
classpathUndo
.setEdit(new ReplaceEdit(0, getFileLength(file), contents));
result.add(classpathUndo);
}
result.add(new UndoDeleteResourceChange(rootDescription));
pm.done();
return result;
}
private boolean confirmDeleteIfReferenced() throws ModelException {
if (!getRoot().isArchive()) // for source folders, you don't ask, just
// do it
return true;
if (fUpdateClasspathQuery == null)
return true;
IScriptProject[] referencingProjects = ModelElementUtil
.getReferencingProjects(getRoot());
if (referencingProjects.length == 0)
return true;
return fUpdateClasspathQuery.confirmManipulation(getRoot(),
referencingProjects);
}
private static int getFileLength(IFile file) throws CoreException {
// Cannot use file buffers here, since they are not yet in sync at this
// point.
InputStream contents = file.getContents();
InputStreamReader reader;
try {
reader = new InputStreamReader(contents, file.getCharset());
} catch (UnsupportedEncodingException e) {
DLTKUIPlugin.log(e);
reader = new InputStreamReader(contents);
}
try {
return (int) reader.skip(Integer.MAX_VALUE);
} catch (IOException e) {
throw new CoreException(new Status(IStatus.ERROR,
DLTKUIPlugin.getPluginId(), e.getMessage(), e));
}
}
private static String getFileContents(IFile file) throws CoreException {
ITextFileBufferManager manager = FileBuffers.getTextFileBufferManager();
IPath path = file.getFullPath();
manager.connect(path, LocationKind.IFILE, new NullProgressMonitor());
try {
return manager.getTextFileBuffer(path, LocationKind.IFILE)
.getDocument().get();
} finally {
manager.disconnect(path, LocationKind.IFILE,
new NullProgressMonitor());
}
}
}