/*******************************************************************************
* Copyright (c) 2000, 2007 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.php.internal.ui.refactor.processors;
import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.dltk.core.*;
import org.eclipse.dltk.internal.corext.refactoring.Checks;
import org.eclipse.dltk.internal.corext.refactoring.RefactoringCoreMessages;
import org.eclipse.dltk.internal.corext.refactoring.changes.*;
import org.eclipse.dltk.internal.corext.refactoring.reorg.ReorgUtils;
import org.eclipse.dltk.internal.corext.refactoring.util.TextChangeManager;
import org.eclipse.jface.text.BadLocationException;
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.TextFileChange;
import org.eclipse.php.internal.ui.PHPUiPlugin;
import org.eclipse.text.edits.DeleteEdit;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.wst.sse.core.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
import org.eclipse.wst.sse.core.internal.provisional.exceptions.ResourceAlreadyExists;
import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
class DeleteChangeCreator {
private DeleteChangeCreator() {
// private
}
static Change createDeleteChange(TextChangeManager manager, IResource[] resources, IModelElement[] modelElements,
String changeName, List packageDeletes) throws CoreException {
// final DynamicValidationStateChange result= new
// DynamicValidationStateChange(changeName) {
// public Change perform(IProgressMonitor pm) throws CoreException {
// super.perform(pm);
// return null;
// }
// };
DynamicValidationStateChange result;
if (packageDeletes.size() > 0) {
result = new UndoablePackageDeleteChange(changeName, packageDeletes);
} else {
result = new DynamicValidationStateChange(changeName);
}
for (int i = 0; i < modelElements.length; i++) {
IModelElement element = modelElements[i];
if (!ReorgUtils.isInsideSourceModule(element))
result.add(createDeleteChange(element));
}
for (int i = 0; i < resources.length; i++) {
result.add(createDeleteChange(resources[i]));
}
Map grouped = ReorgUtils.groupBySourceModule(getElementsSmallerThanCu(modelElements));
if (grouped.size() != 0) {
Assert.isNotNull(manager);
for (Entry entry : (Set<Entry>) grouped.entrySet()) {
Change change = createDeleteChange((ISourceModule) entry.getKey(), (List) entry.getValue(), manager);
if (change != null) {
result.add(change);
}
}
}
return result;
}
private static Change createDeleteChange(IResource resource) {
Assert.isTrue(!(resource instanceof IWorkspaceRoot));// cannot be done
Assert.isTrue(!(resource instanceof IProject)); // project deletion is
// handled by the
// workbench
if (resource instanceof IFile)
return new DeleteFileChange((IFile) resource, true);
if (resource instanceof IFolder)
return new DeleteFolderChange((IFolder) resource, true);
Assert.isTrue(false);// there're no more kinds
return null;
}
/*
* List<IModelElement> modelElements
*/
private static Change createDeleteChange(ISourceModule cu, List modelElements, TextChangeManager manager)
throws CoreException {
// SourceModule cuNode= RefactoringASTParser.parseWithASTProvider(cu,
// false, null);
// SourceModuleRewrite rewriter= new SourceModuleRewrite(cu, cuNode);
Assert.isNotNull(cu);
Assert.isNotNull(modelElements);
Assert.isNotNull(manager);
TextFileChange textFileChange = null;
if (cu.getResource() instanceof IFile) {
textFileChange = new TextFileChange(cu.getElementName(), (IFile) cu.getResource());
MultiTextEdit fileChangeRootEdit = new MultiTextEdit();
textFileChange.setEdit(fileChangeRootEdit);
manager.manage(cu, textFileChange);
IModelElement[] elements = (IModelElement[]) modelElements.toArray(new IModelElement[modelElements.size()]);
for (int cnt = 0, max = elements.length; cnt < max; cnt++) {
ISourceRange sourceRange = null;
if (elements[cnt] instanceof IMember) {
IMember type = (IMember) elements[cnt];
sourceRange = type.getSourceRange();
}
if (sourceRange != null) {
IStructuredDocument document = determineDocument(cu);
int suffixLength = getSuffixLength(document, sourceRange.getOffset() + sourceRange.getLength(),
';');
int length = sourceRange.getLength() + suffixLength;
if (sourceRange.getOffset() + length > document.getLength()) {
length = document.getLength() - sourceRange.getOffset();
}
DeleteEdit edit = new DeleteEdit(sourceRange.getOffset(), length);
fileChangeRootEdit.addChild(edit);
if (cu.isWorkingCopy()) {
textFileChange.setSaveMode(TextFileChange.LEAVE_DIRTY);
}
}
}
}
// ASTNodeDeleteUtil.markAsDeleted(elements, rewriter, null);
// return addTextEditFromRewrite(manager, cu, rewriter.getASTRewrite());
return textFileChange;
}
private static int getSuffixLength(IStructuredDocument document, int offset, char endChar) {
try {
int length = document.getLength() - offset;
for (int rv = 0; rv < length; rv++) {
char c = document.getChar(rv + offset);
if (Character.isWhitespace(c)) {
continue;
} else if (endChar == c) {
return rv + 1;
}
return 0;
}
} catch (BadLocationException e) {
e.printStackTrace();
}
return 0;
}
protected static IStructuredDocument determineDocument(ISourceModule module) {
IStructuredDocument document = null;
IStructuredModel structuredModel = null;
try {
IFile file = (IFile) module.getResource();
if (file != null) {
if (file.exists()) {
structuredModel = StructuredModelManager.getModelManager().getExistingModelForRead(file);
if (structuredModel != null) {
document = structuredModel.getStructuredDocument();
} else {
document = StructuredModelManager.getModelManager().createStructuredDocumentFor(file);
}
} else {
document = StructuredModelManager.getModelManager().createNewStructuredDocumentFor(file);
document.set(module.getSource());
}
}
} catch (IOException e) {
PHPUiPlugin.log(e);
} catch (CoreException e) {
PHPUiPlugin.log(e);
} catch (ResourceAlreadyExists e) {
PHPUiPlugin.log(e);
} finally {
if (structuredModel != null) {
structuredModel.releaseFromRead();
}
}
return document;
}
// private static TextChange addTextEditFromRewrite(TextChangeManager
// manager, ISourceModule cu, ASTRewrite rewrite) throws CoreException {
// try {
// ITextFileBuffer buffer= RefactoringFileBuffers.acquire(cu);
// TextEdit resultingEdits= rewrite.rewriteAST(buffer.getDocument(),
// cu.getScriptProject().getOptions(true));
// TextChange textChange= manager.get(cu);
// if (textChange instanceof TextFileChange) {
// TextFileChange tfc= (TextFileChange) textChange;
// if (cu.isWorkingCopy())
// tfc.setSaveMode(TextFileChange.LEAVE_DIRTY);
// }
// String message= RefactoringCoreMessages.DeleteChangeCreator_1;
// TextChangeCompatibility.addTextEdit(textChange, message, resultingEdits);
// return textChange;
// } finally {
// RefactoringFileBuffers.release(cu);
// }
// }
// List<IModelElement>
private static List getElementsSmallerThanCu(IModelElement[] modelElements) {
List result = new ArrayList();
for (int i = 0; i < modelElements.length; i++) {
IModelElement element = modelElements[i];
if (ReorgUtils.isInsideSourceModule(element))
result.add(element);
}
return result;
}
private static Change createDeleteChange(IModelElement modelElement) {
Assert.isTrue(!ReorgUtils.isInsideSourceModule(modelElement));
switch (modelElement.getElementType()) {
case IModelElement.PROJECT_FRAGMENT:
return createProjectFragmentDeleteChange((IProjectFragment) modelElement);
case IModelElement.SCRIPT_FOLDER:
return createSourceManipulationDeleteChange((IScriptFolder) modelElement);
case IModelElement.SOURCE_MODULE:
return createSourceManipulationDeleteChange((ISourceModule) modelElement);
case IModelElement.SCRIPT_MODEL: // cannot be done
Assert.isTrue(false);
return null;
case IModelElement.SCRIPT_PROJECT: // handled differently
Assert.isTrue(false);
return null;
case IModelElement.TYPE:
case IModelElement.FIELD:
case IModelElement.METHOD:
// case IModelElement.INITIALIZER:
// case IModelElement.PACKAGE_DECLARATION:
// case IModelElement.IMPORT_CONTAINER:
// case IModelElement.IMPORT_DECLARATION:
// Assert.isTrue(false);//not done here
default:
Assert.isTrue(false);// there's no more kinds
return new NullChange();
}
}
private static Change createSourceManipulationDeleteChange(ISourceManipulation element) {
// XXX workaround for bug 31384, in case of linked ISourceManipulation
// delete the resource
if (element instanceof ISourceModule || element instanceof IScriptFolder) {
IResource resource;
if (element instanceof ISourceModule)
resource = ReorgUtils.getResource((ISourceModule) element);
else
resource = ((IScriptFolder) element).getResource();
if (resource != null && resource.isLinked())
return createDeleteChange(resource);
}
return new DeleteSourceManipulationChange(element, true);
}
private static Change createProjectFragmentDeleteChange(IProjectFragment root) {
IResource resource = root.getResource();
if (resource != null && resource.isLinked()) {
// XXX using this code is a workaround for jcore bug 31998
// jcore cannot handle linked stuff
// normally, we should always create DeleteProjectFragmentChange
CompositeChange composite = new DynamicValidationStateChange(
RefactoringCoreMessages.DeleteRefactoring_delete_package_fragment_root);
composite.add(new DeleteFromBuildpathChange(root));
Assert.isTrue(!Checks.isBuildpathDelete(root));// checked in
// preconditions
composite.add(createDeleteChange(resource));
return composite;
} else {
Assert.isTrue(!root.isExternal());
// TODO remove the query argument
return new DeleteProjectFragmentChange(root, true, null);
}
}
}