/******************************************************************************* * Copyright (c) 2000, 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.jdt.internal.core; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import org.eclipse.core.resources.*; import org.eclipse.core.runtime.*; import org.eclipse.core.runtime.jobs.ISchedulingRule; import org.eclipse.jdt.core.*; import org.eclipse.jdt.internal.core.util.Messages; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.text.edits.TextEdit; /** * Defines behavior common to all Java Model operations */ @SuppressWarnings({"rawtypes", "unchecked"}) public abstract class JavaModelOperation implements IWorkspaceRunnable, IProgressMonitor { protected interface IPostAction { /* * Returns the id of this action. * @see JavaModelOperation#postAction */ String getID(); /* * Run this action. */ void run() throws JavaModelException; } /* * Constants controlling the insertion mode of an action. * @see JavaModelOperation#postAction */ protected static final int APPEND = 1; // insert at the end protected static final int REMOVEALL_APPEND = 2; // remove all existing ones with same ID, and add new one at the end protected static final int KEEP_EXISTING = 3; // do not insert if already existing with same ID /* * Whether tracing post actions is enabled. */ protected static boolean POST_ACTION_VERBOSE; /* * A list of IPostActions. */ protected IPostAction[] actions; protected int actionsStart = 0; protected int actionsEnd = -1; /* * A HashMap of attributes that can be used by operations */ protected HashMap attributes; public static final String HAS_MODIFIED_RESOURCE_ATTR = "hasModifiedResource"; //$NON-NLS-1$ public static final String TRUE = JavaModelManager.TRUE; //public static final String FALSE = "false"; /** * The elements this operation operates on, * or <code>null</code> if this operation * does not operate on specific elements. */ protected IJavaElement[] elementsToProcess; /** * The parent elements this operation operates with * or <code>null</code> if this operation * does not operate with specific parent elements. */ protected IJavaElement[] parentElements; /** * An empty collection of <code>IJavaElement</code>s - the common * empty result if no elements are created, or if this * operation is not actually executed. */ protected static final IJavaElement[] NO_ELEMENTS= new IJavaElement[] {}; /** * The elements created by this operation - empty * until the operation actually creates elements. */ protected IJavaElement[] resultElements= NO_ELEMENTS; /** * The progress monitor passed into this operation */ public IProgressMonitor progressMonitor= null; /** * A flag indicating whether this operation is nested. */ protected boolean isNested = false; /** * Conflict resolution policy - by default do not force (fail on a conflict). */ protected boolean force = false; /* * A per thread stack of java model operations (PerThreadObject of ArrayList). */ protected static final ThreadLocal OPERATION_STACKS = new ThreadLocal(); protected JavaModelOperation() { // default constructor used in subclasses } /** * A common constructor for all Java Model operations. */ protected JavaModelOperation(IJavaElement[] elements) { this.elementsToProcess = elements; } /** * Common constructor for all Java Model operations. */ protected JavaModelOperation(IJavaElement[] elementsToProcess, IJavaElement[] parentElements) { this.elementsToProcess = elementsToProcess; this.parentElements= parentElements; } /** * A common constructor for all Java Model operations. */ protected JavaModelOperation(IJavaElement[] elementsToProcess, IJavaElement[] parentElements, boolean force) { this.elementsToProcess = elementsToProcess; this.parentElements= parentElements; this.force= force; } /** * A common constructor for all Java Model operations. */ protected JavaModelOperation(IJavaElement[] elements, boolean force) { this.elementsToProcess = elements; this.force= force; } /** * Common constructor for all Java Model operations. */ protected JavaModelOperation(IJavaElement element) { this.elementsToProcess = new IJavaElement[]{element}; } /* * Registers the given action at the end of the list of actions to run. */ protected void addAction(IPostAction action) { int length = this.actions.length; if (length == ++this.actionsEnd) { System.arraycopy(this.actions, 0, this.actions = new IPostAction[length*2], 0, length); } this.actions[this.actionsEnd] = action; } /* * Registers the given delta with the Java Model Manager. */ protected void addDelta(IJavaElementDelta delta) { JavaModelManager.getJavaModelManager().getDeltaProcessor().registerJavaModelDelta(delta); } /* * Registers the given reconcile delta with the Java Model Manager. */ protected void addReconcileDelta(ICompilationUnit workingCopy, IJavaElementDelta delta) { HashMap reconcileDeltas = JavaModelManager.getJavaModelManager().getDeltaProcessor().reconcileDeltas; JavaElementDelta previousDelta = (JavaElementDelta)reconcileDeltas.get(workingCopy); if (previousDelta != null) { IJavaElementDelta[] children = delta.getAffectedChildren(); for (int i = 0, length = children.length; i < length; i++) { JavaElementDelta child = (JavaElementDelta)children[i]; previousDelta.insertDeltaTree(child.getElement(), child); } // note that the last delta's AST always takes precedence over the existing delta's AST // since it is the result of the last reconcile operation if ((delta.getFlags() & IJavaElementDelta.F_AST_AFFECTED) != 0) { previousDelta.changedAST(delta.getCompilationUnitAST()); } } else { reconcileDeltas.put(workingCopy, delta); } } /* * Deregister the reconcile delta for the given working copy */ protected void removeReconcileDelta(ICompilationUnit workingCopy) { JavaModelManager.getJavaModelManager().getDeltaProcessor().reconcileDeltas.remove(workingCopy); } protected void applyTextEdit(ICompilationUnit cu, TextEdit edits) throws JavaModelException { try { edits.apply(getDocument(cu)); } catch (BadLocationException e) { // content changed under us throw new JavaModelException(e, IJavaModelStatusConstants.INVALID_CONTENTS); } } /** * @see IProgressMonitor */ public void beginTask(String name, int totalWork) { if (this.progressMonitor != null) { this.progressMonitor.beginTask(name, totalWork); } } /* * Returns whether this operation can modify the package fragment roots. */ protected boolean canModifyRoots() { return false; } /** * Checks with the progress monitor to see whether this operation * should be canceled. An operation should regularly call this method * during its operation so that the user can cancel it. * * @exception OperationCanceledException if cancelling the operation has been requested * @see IProgressMonitor#isCanceled */ protected void checkCanceled() { if (isCanceled()) { throw new OperationCanceledException(Messages.operation_cancelled); } } /** * Common code used to verify the elements this operation is processing. * @see JavaModelOperation#verify() */ protected IJavaModelStatus commonVerify() { if (this.elementsToProcess == null || this.elementsToProcess.length == 0) { return new JavaModelStatus(IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS); } for (int i = 0; i < this.elementsToProcess.length; i++) { if (this.elementsToProcess[i] == null) { return new JavaModelStatus(IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS); } } return JavaModelStatus.VERIFIED_OK; } /** * Convenience method to copy resources */ protected void copyResources(IResource[] resources, IPath container) throws JavaModelException { IProgressMonitor subProgressMonitor = getSubProgressMonitor(resources.length); IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); try { for (int i = 0, length = resources.length; i < length; i++) { IResource resource = resources[i]; IPath destination = container.append(resource.getName()); if (root.findMember(destination) == null) { resource.copy(destination, false, subProgressMonitor); } } setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); } catch (CoreException e) { throw new JavaModelException(e); } } /** * Convenience method to create a file */ protected void createFile(IContainer folder, String name, InputStream contents, boolean forceFlag) throws JavaModelException { IFile file= folder.getFile(new Path(name)); try { file.create( contents, forceFlag ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY, getSubProgressMonitor(1)); setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); } catch (CoreException e) { throw new JavaModelException(e); } } /** * Convenience method to create a folder */ protected void createFolder(IContainer parentFolder, String name, boolean forceFlag) throws JavaModelException { IFolder folder= parentFolder.getFolder(new Path(name)); try { // we should use true to create the file locally. Only VCM should use tru/false folder.create( forceFlag ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY, true, // local getSubProgressMonitor(1)); setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); } catch (CoreException e) { throw new JavaModelException(e); } } /** * Convenience method to delete an empty package fragment */ protected void deleteEmptyPackageFragment( IPackageFragment fragment, boolean forceFlag, IResource rootResource) throws JavaModelException { IContainer resource = (IContainer) ((JavaElement)fragment).resource(); try { resource.delete( forceFlag ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY, getSubProgressMonitor(1)); setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); while (resource instanceof IFolder) { // deleting a package: delete the parent if it is empty (e.g. deleting x.y where folder x doesn't have resources but y) // without deleting the package fragment root resource = resource.getParent(); if (!resource.equals(rootResource) && resource.members().length == 0) { resource.delete( forceFlag ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY, getSubProgressMonitor(1)); setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); } } } catch (CoreException e) { throw new JavaModelException(e); } } /** * Convenience method to delete a resource */ protected void deleteResource(IResource resource,int flags) throws JavaModelException { try { resource.delete(flags, getSubProgressMonitor(1)); setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); } catch (CoreException e) { throw new JavaModelException(e); } } /** * Convenience method to delete resources */ protected void deleteResources(IResource[] resources, boolean forceFlag) throws JavaModelException { if (resources == null || resources.length == 0) return; IProgressMonitor subProgressMonitor = getSubProgressMonitor(resources.length); IWorkspace workspace = resources[0].getWorkspace(); try { workspace.delete( resources, forceFlag ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY, subProgressMonitor); setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); } catch (CoreException e) { throw new JavaModelException(e); } } /** * @see IProgressMonitor */ public void done() { if (this.progressMonitor != null) { this.progressMonitor.done(); } } /* * Returns whether the given path is equals to one of the given other paths. */ protected boolean equalsOneOf(IPath path, IPath[] otherPaths) { for (int i = 0, length = otherPaths.length; i < length; i++) { if (path.equals(otherPaths[i])) { return true; } } return false; } /** * Convenience method to run an operation within this operation */ public void executeNestedOperation(JavaModelOperation operation, int subWorkAmount) throws JavaModelException { IJavaModelStatus status= operation.verify(); if (!status.isOK()) { throw new JavaModelException(status); } IProgressMonitor subProgressMonitor = getSubProgressMonitor(subWorkAmount); // fix for 1FW7IKC, part (1) try { operation.setNested(true); operation.run(subProgressMonitor); } catch (CoreException ce) { if (ce instanceof JavaModelException) { throw (JavaModelException)ce; } else { // translate the core exception to a java model exception if (ce.getStatus().getCode() == IResourceStatus.OPERATION_FAILED) { Throwable e = ce.getStatus().getException(); if (e instanceof JavaModelException) { throw (JavaModelException) e; } } throw new JavaModelException(ce); } } } /** * Performs the operation specific behavior. Subclasses must override. */ protected abstract void executeOperation() throws JavaModelException; /* * Returns the attribute registered at the given key with the top level operation. * Returns null if no such attribute is found. */ protected static Object getAttribute(Object key) { ArrayList stack = getCurrentOperationStack(); if (stack.size() == 0) return null; JavaModelOperation topLevelOp = (JavaModelOperation)stack.get(0); if (topLevelOp.attributes == null) { return null; } else { return topLevelOp.attributes.get(key); } } /** * Returns the compilation unit the given element is contained in, * or the element itself (if it is a compilation unit), * otherwise <code>null</code>. */ protected ICompilationUnit getCompilationUnitFor(IJavaElement element) { return ((JavaElement)element).getCompilationUnit(); } /* * Returns the stack of operations running in the current thread. * Returns an empty stack if no operations are currently running in this thread. */ protected static ArrayList getCurrentOperationStack() { ArrayList stack = (ArrayList)OPERATION_STACKS.get(); if (stack == null) { stack = new ArrayList(); OPERATION_STACKS.set(stack); } return stack; } /* * Returns the existing document for the given cu, or a DocumentAdapter if none. */ protected IDocument getDocument(ICompilationUnit cu) throws JavaModelException { IBuffer buffer = cu.getBuffer(); if (buffer instanceof IDocument) return (IDocument) buffer; return new DocumentAdapter(buffer); } /** * Returns the element to which this operation applies, * or <code>null</code> if not applicable. */ protected IJavaElement getElementToProcess() { if (this.elementsToProcess == null || this.elementsToProcess.length == 0) { return null; } return this.elementsToProcess[0]; } /** * Returns the Java Model this operation is operating in. */ public IJavaModel getJavaModel() { return JavaModelManager.getJavaModelManager().getJavaModel(); } protected IPath[] getNestedFolders(IPackageFragmentRoot root) throws JavaModelException { IPath rootPath = root.getPath(); IClasspathEntry[] classpath = root.getJavaProject().getRawClasspath(); int length = classpath.length; IPath[] result = new IPath[length]; int index = 0; for (int i = 0; i < length; i++) { IPath path = classpath[i].getPath(); if (rootPath.isPrefixOf(path) && !rootPath.equals(path)) { result[index++] = path; } } if (index < length) { System.arraycopy(result, 0, result = new IPath[index], 0, index); } return result; } /** * Returns the parent element to which this operation applies, * or <code>null</code> if not applicable. */ protected IJavaElement getParentElement() { if (this.parentElements == null || this.parentElements.length == 0) { return null; } return this.parentElements[0]; } /** * Returns the parent elements to which this operation applies, * or <code>null</code> if not applicable. */ protected IJavaElement[] getParentElements() { return this.parentElements; } /** * Returns the elements created by this operation. */ public IJavaElement[] getResultElements() { return this.resultElements; } /* * Returns the scheduling rule for this operation (i.e. the resource that needs to be locked * while this operation is running. * Subclasses can override. */ protected ISchedulingRule getSchedulingRule() { return ResourcesPlugin.getWorkspace().getRoot(); } /** * Creates and returns a subprogress monitor if appropriate. */ protected IProgressMonitor getSubProgressMonitor(int workAmount) { IProgressMonitor sub = null; if (this.progressMonitor != null) { sub = new SubProgressMonitor(this.progressMonitor, workAmount, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK); } return sub; } /** * Returns whether this operation has performed any resource modifications. * Returns false if this operation has not been executed yet. */ public boolean hasModifiedResource() { return !isReadOnly() && getAttribute(HAS_MODIFIED_RESOURCE_ATTR) == TRUE; } public void internalWorked(double work) { if (this.progressMonitor != null) { this.progressMonitor.internalWorked(work); } } /** * @see IProgressMonitor */ public boolean isCanceled() { if (this.progressMonitor != null) { return this.progressMonitor.isCanceled(); } return false; } /** * Returns <code>true</code> if this operation performs no resource modifications, * otherwise <code>false</code>. Subclasses must override. */ public boolean isReadOnly() { return false; } /* * Returns whether this operation is the first operation to run in the current thread. */ protected boolean isTopLevelOperation() { ArrayList stack; return (stack = getCurrentOperationStack()).size() > 0 && stack.get(0) == this; } /* * Returns the index of the first registered action with the given id, starting from a given position. * Returns -1 if not found. */ protected int firstActionWithID(String id, int start) { for (int i = start; i <= this.actionsEnd; i++) { if (this.actions[i].getID().equals(id)) { return i; } } return -1; } /** * Convenience method to move resources */ protected void moveResources(IResource[] resources, IPath container) throws JavaModelException { IProgressMonitor subProgressMonitor = null; if (this.progressMonitor != null) { subProgressMonitor = new SubProgressMonitor(this.progressMonitor, resources.length, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK); } IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); try { for (int i = 0, length = resources.length; i < length; i++) { IResource resource = resources[i]; IPath destination = container.append(resource.getName()); if (root.findMember(destination) == null) { resource.move(destination, false, subProgressMonitor); } } setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE); } catch (CoreException e) { throw new JavaModelException(e); } } /** * Creates and returns a new <code>IJavaElementDelta</code> * on the Java Model. */ public JavaElementDelta newJavaElementDelta() { return new JavaElementDelta(getJavaModel()); } /* * Removes the last pushed operation from the stack of running operations. * Returns the poped operation or null if the stack was empty. */ protected JavaModelOperation popOperation() { ArrayList stack = getCurrentOperationStack(); int size = stack.size(); if (size > 0) { if (size == 1) { // top level operation OPERATION_STACKS.set(null); // release reference (see http://bugs.eclipse.org/bugs/show_bug.cgi?id=33927) } return (JavaModelOperation)stack.remove(size-1); } else { return null; } } /* * Registers the given action to be run when the outer most java model operation has finished. * The insertion mode controls whether: * - the action should discard all existing actions with the same id, and be queued at the end (REMOVEALL_APPEND), * - the action should be ignored if there is already an action with the same id (KEEP_EXISTING), * - the action should be queued at the end without looking at existing actions (APPEND) */ protected void postAction(IPostAction action, int insertionMode) { if (POST_ACTION_VERBOSE) { System.out.print("(" + Thread.currentThread() + ") [JavaModelOperation.postAction(IPostAction, int)] Posting action " + action.getID()); //$NON-NLS-1$ //$NON-NLS-2$ switch(insertionMode) { case REMOVEALL_APPEND: System.out.println(" (REMOVEALL_APPEND)"); //$NON-NLS-1$ break; case KEEP_EXISTING: System.out.println(" (KEEP_EXISTING)"); //$NON-NLS-1$ break; case APPEND: System.out.println(" (APPEND)"); //$NON-NLS-1$ break; } } JavaModelOperation topLevelOp = (JavaModelOperation)getCurrentOperationStack().get(0); IPostAction[] postActions = topLevelOp.actions; if (postActions == null) { topLevelOp.actions = postActions = new IPostAction[1]; postActions[0] = action; topLevelOp.actionsEnd = 0; } else { String id = action.getID(); switch (insertionMode) { case REMOVEALL_APPEND : int index = this.actionsStart-1; while ((index = topLevelOp.firstActionWithID(id, index+1)) >= 0) { // remove action[index] System.arraycopy(postActions, index+1, postActions, index, topLevelOp.actionsEnd - index); postActions[topLevelOp.actionsEnd--] = null; } topLevelOp.addAction(action); break; case KEEP_EXISTING: if (topLevelOp.firstActionWithID(id, 0) < 0) { topLevelOp.addAction(action); } break; case APPEND: topLevelOp.addAction(action); break; } } } /* * Returns whether the given path is the prefix of one of the given other paths. */ protected boolean prefixesOneOf(IPath path, IPath[] otherPaths) { for (int i = 0, length = otherPaths.length; i < length; i++) { if (path.isPrefixOf(otherPaths[i])) { return true; } } return false; } /* * Pushes the given operation on the stack of operations currently running in this thread. */ protected void pushOperation(JavaModelOperation operation) { getCurrentOperationStack().add(operation); } /* * Removes all actions with the given id from the queue of post actions. * Does nothing if no such action is in the queue. */ protected void removeAllPostAction(String actionID) { if (POST_ACTION_VERBOSE) { System.out.println("(" + Thread.currentThread() + ") [JavaModelOperation.removeAllPostAction(String)] Removing actions " + actionID); //$NON-NLS-1$ //$NON-NLS-2$ } JavaModelOperation topLevelOp = (JavaModelOperation)getCurrentOperationStack().get(0); IPostAction[] postActions = topLevelOp.actions; if (postActions == null) return; int index = this.actionsStart-1; while ((index = topLevelOp.firstActionWithID(actionID, index+1)) >= 0) { // remove action[index] System.arraycopy(postActions, index+1, postActions, index, topLevelOp.actionsEnd - index); postActions[topLevelOp.actionsEnd--] = null; } } /** * Runs this operation and registers any deltas created. * * @see IWorkspaceRunnable * @exception CoreException if the operation fails */ public void run(IProgressMonitor monitor) throws CoreException { JavaModelManager manager = JavaModelManager.getJavaModelManager(); DeltaProcessor deltaProcessor = manager.getDeltaProcessor(); int previousDeltaCount = deltaProcessor.javaModelDeltas.size(); try { this.progressMonitor = monitor; pushOperation(this); try { if (canModifyRoots()) { // computes the root infos before executing the operation // noop if aready initialized JavaModelManager.getDeltaState().initializeRoots(false/*not initiAfterLoad*/); } executeOperation(); } finally { if (isTopLevelOperation()) { runPostActions(); } } } finally { try { // reacquire delta processor as it can have been reset during executeOperation() deltaProcessor = manager.getDeltaProcessor(); // update JavaModel using deltas that were recorded during this operation for (int i = previousDeltaCount, size = deltaProcessor.javaModelDeltas.size(); i < size; i++) { deltaProcessor.updateJavaModel((IJavaElementDelta)deltaProcessor.javaModelDeltas.get(i)); } // close the parents of the created elements and reset their project's cache (in case we are in an // IWorkspaceRunnable and the clients wants to use the created element's parent) // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=83646 for (int i = 0, length = this.resultElements.length; i < length; i++) { IJavaElement element = this.resultElements[i]; Openable openable = (Openable) element.getOpenable(); if (!(openable instanceof CompilationUnit) || !((CompilationUnit) openable).isWorkingCopy()) { // a working copy must remain a child of its parent even after a move ((JavaElement) openable.getParent()).close(); } switch (element.getElementType()) { case IJavaElement.PACKAGE_FRAGMENT_ROOT: case IJavaElement.PACKAGE_FRAGMENT: deltaProcessor.projectCachesToReset.add(element.getJavaProject()); break; } } deltaProcessor.resetProjectCaches(); // fire only iff: // - the operation is a top level operation // - the operation did produce some delta(s) // - but the operation has not modified any resource if (isTopLevelOperation()) { if ((deltaProcessor.javaModelDeltas.size() > previousDeltaCount || !deltaProcessor.reconcileDeltas.isEmpty()) && !hasModifiedResource()) { deltaProcessor.fire(null, DeltaProcessor.DEFAULT_CHANGE_EVENT); } // else deltas are fired while processing the resource delta } } finally { popOperation(); } } } /** * Main entry point for Java Model operations. Runs a Java Model Operation as an IWorkspaceRunnable * if not read-only. */ public void runOperation(IProgressMonitor monitor) throws JavaModelException { IJavaModelStatus status= verify(); if (!status.isOK()) { throw new JavaModelException(status); } try { if (isReadOnly()) { run(monitor); } else { // Use IWorkspace.run(...) to ensure that resource changes are batched // Note that if the tree is locked, this will throw a CoreException, but this is ok // as this operation is modifying the tree (not read-only) and a CoreException will be thrown anyway. ResourcesPlugin.getWorkspace().run(this, getSchedulingRule(), IWorkspace.AVOID_UPDATE, monitor); } } catch (CoreException ce) { if (ce instanceof JavaModelException) { throw (JavaModelException)ce; } else { if (ce.getStatus().getCode() == IResourceStatus.OPERATION_FAILED) { Throwable e= ce.getStatus().getException(); if (e instanceof JavaModelException) { throw (JavaModelException) e; } } throw new JavaModelException(ce); } } } protected void runPostActions() throws JavaModelException { while (this.actionsStart <= this.actionsEnd) { IPostAction postAction = this.actions[this.actionsStart++]; if (POST_ACTION_VERBOSE) { System.out.println("(" + Thread.currentThread() + ") [JavaModelOperation.runPostActions()] Running action " + postAction.getID()); //$NON-NLS-1$ //$NON-NLS-2$ } postAction.run(); } } /* * Registers the given attribute at the given key with the top level operation. */ protected static void setAttribute(Object key, Object attribute) { ArrayList operationStack = getCurrentOperationStack(); if (operationStack.size() == 0) return; JavaModelOperation topLevelOp = (JavaModelOperation) operationStack.get(0); if (topLevelOp.attributes == null) { topLevelOp.attributes = new HashMap(); } topLevelOp.attributes.put(key, attribute); } /** * @see IProgressMonitor */ public void setCanceled(boolean b) { if (this.progressMonitor != null) { this.progressMonitor.setCanceled(b); } } /** * Sets whether this operation is nested or not. * @see CreateElementInCUOperation#checkCanceled */ protected void setNested(boolean nested) { this.isNested = nested; } /** * @see IProgressMonitor */ public void setTaskName(String name) { if (this.progressMonitor != null) { this.progressMonitor.setTaskName(name); } } /** * @see IProgressMonitor */ public void subTask(String name) { if (this.progressMonitor != null) { this.progressMonitor.subTask(name); } } /** * Returns a status indicating if there is any known reason * this operation will fail. Operations are verified before they * are run. * * Subclasses must override if they have any conditions to verify * before this operation executes. * * @see IJavaModelStatus */ protected IJavaModelStatus verify() { return commonVerify(); } /** * @see IProgressMonitor */ public void worked(int work) { if (this.progressMonitor != null) { this.progressMonitor.worked(work); checkCanceled(); } } }