/******************************************************************************* * Copyright © 2008, 2013 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 * * Contributors: * IBM Corporation - initial API and implementation * *******************************************************************************/ package org.eclipse.edt.ide.ui.internal.refactoring.changes; import org.eclipse.core.filebuffers.FileBuffers; import org.eclipse.core.filebuffers.ITextFileBuffer; import org.eclipse.core.filebuffers.ITextFileBufferManager; 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.ResourceAttributes; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.edt.ide.core.model.IEGLElement; import org.eclipse.edt.ide.core.model.IEGLFile; import org.eclipse.edt.ide.ui.internal.UINlsStrings; import org.eclipse.edt.ide.ui.internal.refactoring.reorg.INewNameQuery; import org.eclipse.edt.ide.ui.internal.refactoring.reorg.ReorgUtils; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentExtension4; import org.eclipse.ltk.core.refactoring.Change; import org.eclipse.ltk.core.refactoring.RefactoringStatus; import org.eclipse.ltk.core.refactoring.participants.ReorgExecutionLog; import com.ibm.icu.text.MessageFormat; abstract class ResourceReorgChange extends Change { protected static final int NONE= 0; protected static final int READ_ONLY= 1 << 0; protected static final int DIRTY= 1 << 1; private static final int SAVE= 1 << 2; protected static final int SAVE_IF_DIRTY= SAVE | DIRTY; private long fModificationStamp; private boolean fReadOnly; private final IPath fResourcePath; private final boolean fIsFile; private final IPath fDestinationPath; private final boolean fIsDestinationProject; private final INewNameQuery fNewNameQuery; ResourceReorgChange(IResource res, IContainer dest, INewNameQuery nameQuery){ Assert.isTrue(res instanceof IFile || res instanceof IFolder); fIsFile= (res instanceof IFile); fResourcePath= getResourcePath(res); Assert.isTrue(dest instanceof IProject || dest instanceof IFolder); fIsDestinationProject= (dest instanceof IProject); fDestinationPath= getResourcePath(dest); fNewNameQuery= nameQuery; } protected abstract Change doPerformReorg(IPath path, IProgressMonitor pm) throws CoreException; /* non java-doc * @see IChange#perform(ChangeContext, IProgressMonitor) */ public final Change perform(IProgressMonitor pm) throws CoreException { try{ pm.beginTask(getName(), 2); String newName= getNewResourceName(); IResource resource= getResource(); boolean performReorg= deleteIfAlreadyExists(new SubProgressMonitor(pm, 1), newName); if (!performReorg) return null; final Change result= doPerformReorg(getDestinationPath(newName), new SubProgressMonitor(pm, 1)); markAsExecuted(resource); return result; } finally { pm.done(); } } protected IPath getDestinationPath(String newName) { return getDestination().getFullPath().append(newName); } /** * returns false if source and destination are the same (in workspace or on disk) * in such case, no action should be performed */ private boolean deleteIfAlreadyExists(IProgressMonitor pm, String newName) throws CoreException { pm.beginTask("", 1); //$NON-NLS-1$ IResource current= getDestination().findMember(newName); if (current == null) return true; if (! current.exists()) return true; IResource resource= getResource(); Assert.isNotNull(resource); if (ReorgUtils.areEqualInWorkspaceOrOnDisk(resource, current)) return false; if (current instanceof IFile) ((IFile)current).delete(false, true, new SubProgressMonitor(pm, 1)); else if (current instanceof IFolder) ((IFolder)current).delete(false, true, new SubProgressMonitor(pm, 1)); else Assert.isTrue(false); return true; } private String getNewResourceName(){ if (fNewNameQuery == null) return getResource().getName(); String name= fNewNameQuery.getNewName(); if (name == null) return getResource().getName(); return name; } /* non java-doc * @see IChange#getModifiedLanguageElement() */ public Object getModifiedElement() { return getResource(); } private IFile getFile(){ return getFile(fResourcePath); } private IFolder getFolder(){ return getFolder(fResourcePath); } protected IResource getResource(){ if (fIsFile) return getFile(); else return getFolder(); } IContainer getDestination(){ if (fIsDestinationProject) return getProject(fDestinationPath); else return getFolder(fDestinationPath); } protected int getReorgFlags() { return IResource.KEEP_HISTORY | IResource.SHALLOW; } private void markAsExecuted(IResource resource) { ReorgExecutionLog log= (ReorgExecutionLog)getAdapter(ReorgExecutionLog.class); if (log != null) { log.markAsProcessed(resource); } } static IPath getResourcePath(IResource resource){ return resource.getFullPath().removeFirstSegments(ResourcesPlugin.getWorkspace().getRoot().getFullPath().segmentCount()); } static IFile getFile(IPath path){ return ResourcesPlugin.getWorkspace().getRoot().getFile(path); } static IFolder getFolder(IPath path){ return ResourcesPlugin.getWorkspace().getRoot().getFolder(path); } static IProject getProject(IPath path){ return (IProject)ResourcesPlugin.getWorkspace().getRoot().findMember(path); } public abstract String getName(); public abstract Object getAdapter(Class clazz); private static class ValidationState { private IResource fResource; private int fKind; private boolean fDirty; private boolean fReadOnly; private long fModificationStamp; private ITextFileBuffer fTextFileBuffer; public static final int RESOURCE= 1; public static final int DOCUMENT= 2; public ValidationState(IResource resource) { fResource= resource; if (resource instanceof IFile) { initializeFile((IFile)resource); } else { initializeResource(resource); } } public void checkDirty(RefactoringStatus status, long stampToMatch, IProgressMonitor pm) throws CoreException { if (fDirty) { if (fKind == DOCUMENT && fTextFileBuffer != null && stampToMatch == fModificationStamp) { fTextFileBuffer.commit(pm, false); } else { status.addFatalError(MessageFormat.format( UINlsStrings.Change_is_unsaved, new String[] {fResource.getFullPath().toString()})); } } } public void checkDirty(RefactoringStatus status) { if (fDirty) { status.addFatalError(MessageFormat.format( UINlsStrings.Change_is_unsaved, new String[] {fResource.getFullPath().toString()})); } } public void checkReadOnly(RefactoringStatus status) { if (fReadOnly) { status.addFatalError(MessageFormat.format( UINlsStrings.Change_is_read_only, new String[] {fResource.getFullPath().toString()})); } } public void checkSameReadOnly(RefactoringStatus status, boolean valueToMatch) { if (fReadOnly != valueToMatch) { status.addFatalError(MessageFormat.format( UINlsStrings.Change_same_read_only, new String[] {fResource.getFullPath().toString()})); } } public void checkModificationStamp(RefactoringStatus status, long stampToMatch) { if (fKind == DOCUMENT) { if (stampToMatch != IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP && fModificationStamp != stampToMatch) { status.addFatalError(MessageFormat.format( UINlsStrings.Change_has_modifications, new String[] {fResource.getFullPath().toString()})); } } else { if (stampToMatch != IResource.NULL_STAMP && fModificationStamp != stampToMatch) { status.addFatalError(MessageFormat.format( UINlsStrings.Change_has_modifications, new String[] {fResource.getFullPath().toString()})); } } } private void initializeFile(IFile file) { fTextFileBuffer= getBuffer(file); if (fTextFileBuffer == null) { initializeResource(file); } else { IDocument document= fTextFileBuffer.getDocument(); fDirty= fTextFileBuffer.isDirty(); fReadOnly= isReadOnly(file); if (document instanceof IDocumentExtension4) { fKind= DOCUMENT; fModificationStamp= ((IDocumentExtension4)document).getModificationStamp(); } else { fKind= RESOURCE; fModificationStamp= file.getModificationStamp(); } } } private void initializeResource(IResource resource) { fKind= RESOURCE; fDirty= false; fReadOnly= isReadOnly(resource); fModificationStamp= resource.getModificationStamp(); } } protected final RefactoringStatus isValid(IProgressMonitor pm, int flags) throws CoreException { pm.beginTask("", 2); //$NON-NLS-1$ try { RefactoringStatus result= new RefactoringStatus(); Object modifiedElement= getModifiedElement(); checkExistence(result, modifiedElement); if (result.hasFatalError()) return result; if (flags == NONE) return result; IResource resource= getResource(modifiedElement); if (resource != null) { ValidationState state= new ValidationState(resource); state.checkModificationStamp(result, fModificationStamp); if (result.hasFatalError()) return result; state.checkSameReadOnly(result, fReadOnly); if (result.hasFatalError()) return result; if ((flags & READ_ONLY) != 0) { state.checkReadOnly(result); if (result.hasFatalError()) return result; } if ((flags & DIRTY) != 0) { if ((flags & SAVE) != 0) { state.checkDirty(result, fModificationStamp, new SubProgressMonitor(pm, 1)); } else { state.checkDirty(result); } } } return result; } finally { pm.done(); } } protected static void checkExistence(RefactoringStatus status, Object element) { if (element == null) { status.addFatalError(UINlsStrings.DynamicValidationStateChange_workspace_changed); } else if (element instanceof IResource && !((IResource)element).exists()) { status.addFatalError(MessageFormat.format( UINlsStrings.Change_does_not_exist, new String[] {((IResource)element).getFullPath().toString()})); } else if (element instanceof IEGLElement && !((IEGLElement)element).exists()) { status.addFatalError(MessageFormat.format( UINlsStrings.Change_does_not_exist, new String[] {((IEGLElement)element).getElementName()})); } } protected final RefactoringStatus isValid(int flags) throws CoreException { return isValid(new NullProgressMonitor(), flags); } private static ITextFileBuffer getBuffer(IFile file) { ITextFileBufferManager manager= FileBuffers.getTextFileBufferManager(); return manager.getTextFileBuffer(file.getFullPath()); } private static IResource getResource(Object element) { if (element instanceof IResource) { return (IResource)element; } if (element instanceof IEGLFile) { return ((IEGLFile)element).getResource(); } if (element instanceof IEGLElement) { return ((IEGLElement)element).getResource(); } if (element instanceof IAdaptable) { return (IResource)((IAdaptable)element).getAdapter(IResource.class); } return null; } public static boolean isReadOnly(IResource resource) { ResourceAttributes resourceAttributes = resource.getResourceAttributes(); if (resourceAttributes == null) // not supported on this platform for this resource return false; return resourceAttributes.isReadOnly(); } public long getModificationStamp(IResource resource) { if (!(resource instanceof IFile)) return resource.getModificationStamp(); IFile file= (IFile)resource; ITextFileBuffer buffer= getBuffer(file); if (buffer == null) { return file.getModificationStamp(); } else { IDocument document= buffer.getDocument(); if (document instanceof IDocumentExtension4) { return ((IDocumentExtension4)document).getModificationStamp(); } else { return file.getModificationStamp(); } } } public void initializeValidationData(IProgressMonitor pm) { IResource resource= getResource(getModifiedElement()); if (resource != null) { fModificationStamp= getModificationStamp(resource); fReadOnly= isReadOnly(resource); } } }