diff --git a/java/java-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java b/java/java-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java index 3ad84d11db68..9d3b1d1366b5 100644 --- a/java/java-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java @@ -23,9 +23,8 @@ import com.intellij.ide.projectView.impl.nodes.PackageElement; import com.intellij.lang.ASTNode; import com.intellij.lang.Language; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.command.undo.DocumentReference; +import com.intellij.openapi.command.undo.GlobalUndoableAction; import com.intellij.openapi.command.undo.UndoManager; -import com.intellij.openapi.command.undo.UndoableAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.module.Module; @@ -169,7 +168,7 @@ public class PsiPackageImpl extends PsiElementBase implements PsiPackage, Querya final String oldQualifedName = myQualifiedName; final boolean anyChanged = changePackagePrefixes(oldQualifedName, newQualifiedName); if (anyChanged) { - UndoManager.getInstance(myManager.getProject()).undoableActionPerformed(new UndoableAction() { + UndoManager.getInstance(myManager.getProject()).undoableActionPerformed(new GlobalUndoableAction() { public void undo() { changePackagePrefixes(newQualifiedName, oldQualifedName); } @@ -177,14 +176,6 @@ public class PsiPackageImpl extends PsiElementBase implements PsiPackage, Querya public void redo() { changePackagePrefixes(oldQualifedName, newQualifiedName); } - - public DocumentReference[] getAffectedDocuments() { - return DocumentReference.EMPTY_ARRAY; - } - - public boolean isGlobal() { - return true; - } }); } } diff --git a/java/java-impl/src/com/intellij/psi/impl/source/PsiCodeFragmentImpl.java b/java/java-impl/src/com/intellij/psi/impl/source/PsiCodeFragmentImpl.java index d3e59a75f6d0..b7af9c01cd80 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/PsiCodeFragmentImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/PsiCodeFragmentImpl.java @@ -16,10 +16,8 @@ package com.intellij.psi.impl.source; import com.intellij.lang.Language; -import com.intellij.openapi.command.undo.DocumentReference; -import com.intellij.openapi.command.undo.DocumentReferenceManager; +import com.intellij.openapi.command.undo.BasicUndoableAction; import com.intellij.openapi.command.undo.UndoManager; -import com.intellij.openapi.command.undo.UndoableAction; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypeManager; @@ -237,24 +235,19 @@ public class PsiCodeFragmentImpl extends PsiFileImpl implements JavaCodeFragment //} } - private static class ImportClassUndoableAction implements UndoableAction { + private static class ImportClassUndoableAction extends BasicUndoableAction { private final String myClassName; private final String myQName; private final LinkedHashMap myPseudoImports; - private final DocumentReference[] myReferences; public ImportClassUndoableAction(final String className, final String qName, final Document document, final LinkedHashMap pseudoImportsMap) { + super(document); myClassName = className; myQName = qName; myPseudoImports = pseudoImportsMap; - myReferences = new DocumentReference[]{DocumentReferenceManager.getInstance().create(document)}; - } - - public boolean isGlobal() { - return false; } public void undo() { @@ -264,10 +257,6 @@ public class PsiCodeFragmentImpl extends PsiFileImpl implements JavaCodeFragment public void redo() { myPseudoImports.put(myClassName, myQName); } - - public DocumentReference[] getAffectedDocuments() { - return myReferences; - } } public ExceptionHandler getExceptionHandler() { diff --git a/platform/lang-api/src/com/intellij/openapi/command/WriteCommandAction.java b/platform/lang-api/src/com/intellij/openapi/command/WriteCommandAction.java index 40d5ce569b24..ecdd377f0f5b 100644 --- a/platform/lang-api/src/com/intellij/openapi/command/WriteCommandAction.java +++ b/platform/lang-api/src/com/intellij/openapi/command/WriteCommandAction.java @@ -140,8 +140,9 @@ public abstract class WriteCommandAction extends BaseActionRunnable { // is put into undo queue final RunResult[] results = {result}; - CommandProcessor.getInstance().executeCommand(getProject(), new Runnable() { + CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { public void run() { + if (isGlobalUndoAction()) CommandProcessor.getInstance().markCurrentCommandAsGlobal(myProject); results[0].run(); results[0] = null; } diff --git a/platform/lang-api/src/com/intellij/openapi/command/undo/UndoUtil.java b/platform/lang-api/src/com/intellij/openapi/command/undo/UndoUtil.java index 589b58192608..b5d149bf895c 100644 --- a/platform/lang-api/src/com/intellij/openapi/command/undo/UndoUtil.java +++ b/platform/lang-api/src/com/intellij/openapi/command/undo/UndoUtil.java @@ -19,12 +19,12 @@ */ package com.intellij.openapi.command.undo; +import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.editor.Document; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; public class UndoUtil { @@ -40,37 +40,13 @@ public class UndoUtil { Project project = file.getProject(); final Document document = PsiDocumentManager.getInstance(project).getDocument(file); if (document == null) return; - final DocumentReference ref = DocumentReferenceManager.getInstance().create(document); - markDocumentReferenceForUndo(project, ref, "markDocumentForUndo: " + file); + CommandProcessor.getInstance().addAffectedDocuments(project, document); } + /** + * @deprecated please use CommandProcessor.getInstance().addAffectedFiles instead + */ public static void markVirtualFileForUndo(@NotNull Project project, @NotNull VirtualFile file) { - final DocumentReference ref = DocumentReferenceManager.getInstance().create(file); - markDocumentReferenceForUndo(project, ref, "markVirtualFileForUndo: " + file.getPath()); - } - - private static void markDocumentReferenceForUndo(final Project project, - final DocumentReference ref, - @NonNls final String debugName) { - UndoManager.getInstance(project).undoableActionPerformed(new UndoableAction() { - public void undo() { - } - - public void redo() { - } - - public DocumentReference[] getAffectedDocuments() { - return new DocumentReference[]{ref}; - } - - public boolean isGlobal() { - return false; - } - - @NonNls - public String toString() { - return debugName; - } - }); + CommandProcessor.getInstance().addAffectedFiles(project, file); } } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java index 5fdedf03a979..67b0d6a76db1 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java @@ -29,10 +29,10 @@ import com.intellij.openapi.command.CommandAdapter; import com.intellij.openapi.command.CommandEvent; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.command.undo.BasicUndoableAction; import com.intellij.openapi.command.undo.DocumentReference; import com.intellij.openapi.command.undo.DocumentReferenceManager; import com.intellij.openapi.command.undo.UndoManager; -import com.intellij.openapi.command.undo.UndoableAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.*; import com.intellij.openapi.editor.event.DocumentAdapter; @@ -246,10 +246,9 @@ public class TemplateState implements Disposable { myProcessor = processor; - final DocumentReference[] refs = + DocumentReference[] refs = myDocument == null ? null : new DocumentReference[]{DocumentReferenceManager.getInstance().create(myDocument)}; - - UndoManager.getInstance(myProject).undoableActionPerformed(new UndoableAction() { + UndoManager.getInstance(myProject).undoableActionPerformed(new BasicUndoableAction(refs) { public void undo() { if (myDocument != null) { fireTemplateCancelled(); @@ -264,14 +263,6 @@ public class TemplateState implements Disposable { //TODO: // throw new UnexpectedUndoException("Not implemented"); } - - public DocumentReference[] getAffectedDocuments() { - return refs; - } - - public boolean isGlobal() { - return false; - } }); myTemplateIndented = false; myCurrentVariableNumber = -1; diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/Browser.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/Browser.java index ebfe2512189c..0365a58b4667 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/Browser.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/Browser.java @@ -207,7 +207,7 @@ public class Browser extends JPanel { else if (ref.startsWith("invoke:")) { int actionNumber = Integer.parseInt(ref.substring("invoke:".length())); getTool().getQuickFixes(new RefElement[]{(RefElement)myCurrentEntity})[actionNumber] - .doApplyFix(new RefElement[]{(RefElement)myCurrentEntity}, myView); + .doApplyFix(new RefElement[]{(RefElement)myCurrentEntity}, myView, null); } else if (ref.startsWith("invokelocal:")) { int actionNumber = Integer.parseInt(ref.substring("invokelocal:".length())); diff --git a/platform/lvcs-impl/src/com/intellij/openapi/command/impl/FileUndoProvider.java b/platform/lvcs-impl/src/com/intellij/openapi/command/impl/FileUndoProvider.java index 4c8bc8d2b11c..82838477c2d8 100644 --- a/platform/lvcs-impl/src/com/intellij/openapi/command/impl/FileUndoProvider.java +++ b/platform/lvcs-impl/src/com/intellij/openapi/command/impl/FileUndoProvider.java @@ -172,13 +172,12 @@ public class FileUndoProvider extends VirtualFileAdapter implements UndoProvider return (UndoManagerImpl)UndoManager.getGlobalInstance(); } - private class MyUndoableAction implements UndoableAction { - private final DocumentReference[] myReferences; + private class MyUndoableAction extends GlobalUndoableAction { private ChangeRange myActionChangeRange; private ChangeRange myUndoChangeRange; public MyUndoableAction(DocumentReference r) { - myReferences = new DocumentReference[]{r}; + super(r); myActionChangeRange = new ChangeRange(myGateway, myLocalHistory, myLastChange); } @@ -201,13 +200,5 @@ public class FileUndoProvider extends VirtualFileAdapter implements UndoProvider throw new UnexpectedUndoException(e.getMessage()); } } - - public DocumentReference[] getAffectedDocuments() { - return myReferences; - } - - public boolean isGlobal() { - return true; - } } } diff --git a/platform/platform-api/src/com/intellij/openapi/command/CommandProcessor.java b/platform/platform-api/src/com/intellij/openapi/command/CommandProcessor.java index bb691a76d300..15a9841d94f3 100644 --- a/platform/platform-api/src/com/intellij/openapi/command/CommandProcessor.java +++ b/platform/platform-api/src/com/intellij/openapi/command/CommandProcessor.java @@ -19,7 +19,8 @@ import com.intellij.openapi.Disposable; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.editor.Document; import com.intellij.openapi.project.Project; -import org.jetbrains.annotations.Nls; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public abstract class CommandProcessor { @@ -30,26 +31,37 @@ public abstract class CommandProcessor { /** * @deprecated use {@link #executeCommand(com.intellij.openapi.project.Project, java.lang.Runnable, java.lang.String, java.lang.Object)} */ - public abstract void executeCommand(Runnable runnable, @Nls String name, Object groupId); + public abstract void executeCommand(@NotNull Runnable runnable, + @Nullable String name, + @Nullable Object groupId); - public abstract void executeCommand(Project project, Runnable runnable, @Nls String name, Object groupId); + public abstract void executeCommand(@Nullable Project project, + @NotNull Runnable runnable, + @Nullable String name, + @Nullable Object groupId); - public abstract void executeCommand(Project project, - Runnable runnable, - @Nls String name, - Object groupId, - UndoConfirmationPolicy undoConfirmationPolicy); + public abstract void executeCommand(@Nullable Project project, + @NotNull Runnable runnable, + @Nullable String name, + @Nullable Object groupId, + @Nullable Document document); - public abstract void executeCommand(Project project, - Runnable command, - String name, - Object groupId, - UndoConfirmationPolicy undoConfirmationPolicy, - Document document); + public abstract void executeCommand(@Nullable Project project, + @NotNull Runnable runnable, + @Nullable String name, + @Nullable Object groupId, + @NotNull UndoConfirmationPolicy confirmationPolicy); - public abstract void setCurrentCommandName(@Nls String name); + public abstract void executeCommand(@Nullable Project project, + @NotNull Runnable command, + @Nullable String name, + @Nullable Object groupId, + @NotNull UndoConfirmationPolicy confirmationPolicy, + @Nullable Document document); - public abstract void setCurrentCommandGroupId(Object groupId); + public abstract void setCurrentCommandName(@Nullable String name); + + public abstract void setCurrentCommandGroupId(@Nullable Object groupId); @Nullable public abstract Runnable getCurrentCommand(); @@ -63,15 +75,19 @@ public abstract class CommandProcessor { @Nullable public abstract Project getCurrentCommandProject(); - public abstract void addCommandListener(CommandListener listener); - - public abstract void addCommandListener(CommandListener listener, Disposable parentDisposable); - - public abstract void removeCommandListener(CommandListener listener); - - public abstract void runUndoTransparentAction(Runnable action); + public abstract void runUndoTransparentAction(@NotNull Runnable action); public abstract boolean isUndoTransparentActionInProgress(); - public abstract void markCurrentCommandAsGlobal(Project project); + public abstract void markCurrentCommandAsGlobal(@Nullable Project project); + + public abstract void addAffectedDocuments(@Nullable Project project, @NotNull Document... docs); + + public abstract void addAffectedFiles(@Nullable Project project, @NotNull VirtualFile... files); + + public abstract void addCommandListener(@NotNull CommandListener listener); + + public abstract void addCommandListener(@NotNull CommandListener listener, @NotNull Disposable parentDisposable); + + public abstract void removeCommandListener(@NotNull CommandListener listener); } diff --git a/platform/platform-api/src/com/intellij/openapi/command/undo/BasicUndoableAction.java b/platform/platform-api/src/com/intellij/openapi/command/undo/BasicUndoableAction.java new file mode 100644 index 000000000000..34f6d60626e5 --- /dev/null +++ b/platform/platform-api/src/com/intellij/openapi/command/undo/BasicUndoableAction.java @@ -0,0 +1,56 @@ +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.intellij.openapi.command.undo; + +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public abstract class BasicUndoableAction implements UndoableAction { + private final DocumentReference[] myRefs; + + public BasicUndoableAction() { + myRefs = null; + } + + public BasicUndoableAction(@Nullable DocumentReference... refs) { + myRefs = refs; + } + + public BasicUndoableAction(@NotNull Document... docs) { + myRefs = new DocumentReference[docs.length]; + for (int i = 0; i < docs.length; i++) { + myRefs[i] = DocumentReferenceManager.getInstance().create(docs[i]); + } + } + + public BasicUndoableAction(@NotNull VirtualFile... files) { + myRefs = new DocumentReference[files.length]; + for (int i = 0; i < files.length; i++) { + myRefs[i] = DocumentReferenceManager.getInstance().create(files[i]); + } + } + + public DocumentReference[] getAffectedDocuments() { + return myRefs; + } + + public boolean isGlobal() { + return false; + } +} diff --git a/platform/platform-api/src/com/intellij/openapi/command/undo/NonDocumentUndoableAction.java b/platform/platform-api/src/com/intellij/openapi/command/undo/GlobalUndoableAction.java similarity index 56% rename from platform/platform-api/src/com/intellij/openapi/command/undo/NonDocumentUndoableAction.java rename to platform/platform-api/src/com/intellij/openapi/command/undo/GlobalUndoableAction.java index 8f83919163e7..389f36d902c6 100644 --- a/platform/platform-api/src/com/intellij/openapi/command/undo/NonDocumentUndoableAction.java +++ b/platform/platform-api/src/com/intellij/openapi/command/undo/GlobalUndoableAction.java @@ -16,15 +16,27 @@ package com.intellij.openapi.command.undo; -/** - * @author Dmitry Avdeev - */ -public abstract class NonDocumentUndoableAction implements UndoableAction { - public DocumentReference[] getAffectedDocuments() { - return null; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; + +public abstract class GlobalUndoableAction extends BasicUndoableAction { + public GlobalUndoableAction() { } - public final boolean isGlobal() { + public GlobalUndoableAction(DocumentReference... refs) { + super(refs); + } + + public GlobalUndoableAction(@NotNull Document... docs) { + super(docs); + } + + public GlobalUndoableAction(@NotNull VirtualFile... files) { + super(files); + } + + public boolean isGlobal() { return true; } } diff --git a/platform/platform-api/src/com/intellij/openapi/command/undo/UndoableAction.java b/platform/platform-api/src/com/intellij/openapi/command/undo/UndoableAction.java index 495470e9cfa8..96770b0af313 100644 --- a/platform/platform-api/src/com/intellij/openapi/command/undo/UndoableAction.java +++ b/platform/platform-api/src/com/intellij/openapi/command/undo/UndoableAction.java @@ -35,6 +35,6 @@ public interface UndoableAction { /** * Global actions are those, that can be undone not only from the document of the file, but also from the project tree view. - * */ + */ boolean isGlobal(); } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/command/impl/CommandMerger.java b/platform/platform-impl/src/com/intellij/openapi/command/impl/CommandMerger.java index dbac41645685..048bffea6a7a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/command/impl/CommandMerger.java +++ b/platform/platform-impl/src/com/intellij/openapi/command/impl/CommandMerger.java @@ -16,8 +16,10 @@ package com.intellij.openapi.command.impl; import com.intellij.openapi.command.UndoConfirmationPolicy; +import com.intellij.openapi.command.undo.BasicUndoableAction; import com.intellij.openapi.command.undo.DocumentReference; import com.intellij.openapi.command.undo.UndoableAction; +import com.intellij.openapi.command.undo.UnexpectedUndoException; import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.vfs.VirtualFile; @@ -37,7 +39,8 @@ public class CommandMerger { private String myCommandName = null; private boolean myValid = true; private List myCurrentActions = new ArrayList(); - private Set myAffectedDocuments = new THashSet(); + private Set myAllAffectedDocuments = new THashSet(); + private Set myAdditionalAffectedDocuments = new THashSet(); private EditorAndState myStateBefore; private EditorAndState myStateAfter; private UndoConfirmationPolicy myUndoConfirmationPolicy = UndoConfirmationPolicy.DEFAULT; @@ -59,7 +62,7 @@ public class CommandMerger { myCurrentActions.add(action); DocumentReference[] refs = action.getAffectedDocuments(); if (refs != null) { - Collections.addAll(myAffectedDocuments, refs); + Collections.addAll(myAllAffectedDocuments, refs); } myForcedGlobal |= action.isGlobal(); } @@ -82,7 +85,7 @@ public class CommandMerger { private boolean shouldMerge(Object groupId, CommandMerger nextCommandToMerge) { if (isTransparent() || nextCommandToMerge.isTransparent()) { - return !hasActions() || !nextCommandToMerge.hasActions() || myAffectedDocuments.equals(nextCommandToMerge.myAffectedDocuments); + return !hasActions() || !nextCommandToMerge.hasActions() || myAllAffectedDocuments.equals(nextCommandToMerge.myAllAffectedDocuments); } return !myForcedGlobal && !nextCommandToMerge.myForcedGlobal && canMergeGroup(groupId, myLastGroupId); } @@ -94,11 +97,12 @@ public class CommandMerger { private void merge(CommandMerger nextCommandToMerge) { setBeforeState(nextCommandToMerge.myStateBefore); myStateAfter = nextCommandToMerge.myStateAfter; - if(myTransparent) { // todo write test + if (myTransparent) { // todo write test if (nextCommandToMerge.hasActions()) { myTransparent &= nextCommandToMerge.myTransparent; } - } else { + } + else { if (!hasActions()) { myTransparent = nextCommandToMerge.myTransparent; } @@ -106,7 +110,8 @@ public class CommandMerger { myValid &= nextCommandToMerge.myValid; myForcedGlobal |= nextCommandToMerge.myForcedGlobal; myCurrentActions.addAll(nextCommandToMerge.myCurrentActions); - myAffectedDocuments.addAll(nextCommandToMerge.myAffectedDocuments); + myAllAffectedDocuments.addAll(nextCommandToMerge.myAllAffectedDocuments); + myAdditionalAffectedDocuments.addAll(nextCommandToMerge.myAdditionalAffectedDocuments); mergeUndoConfirmationPolicy(nextCommandToMerge.getUndoConfirmationPolicy()); } @@ -123,6 +128,19 @@ public class CommandMerger { public void flushCurrentCommand() { if (hasActions()) { + if (!myAdditionalAffectedDocuments.isEmpty()) { + DocumentReference[] refs = myAdditionalAffectedDocuments.toArray(new DocumentReference[myAdditionalAffectedDocuments.size()]); + myCurrentActions.add(new BasicUndoableAction(refs) { + @Override + public void undo() throws UnexpectedUndoException { + } + + @Override + public void redo() throws UnexpectedUndoException { + } + }); + } + myManager.getUndoStacksHolder().addToStacks(new UndoableGroup(myCommandName, isGlobal(), myManager.getProject(), @@ -140,7 +158,8 @@ public class CommandMerger { private void reset() { myCurrentActions = new ArrayList(); - myAffectedDocuments = new THashSet(); + myAllAffectedDocuments = new THashSet(); + myAdditionalAffectedDocuments = new THashSet(); myLastGroupId = null; myForcedGlobal = false; myTransparent = false; @@ -152,7 +171,7 @@ public class CommandMerger { } private void clearRedoStacks(CommandMerger nextMerger) { - myManager.getRedoStacksHolder().clearStacks(isGlobal(), nextMerger.myAffectedDocuments); + myManager.getRedoStacksHolder().clearStacks(isGlobal(), nextMerger.myAllAffectedDocuments); } boolean isGlobal() { @@ -169,7 +188,7 @@ public class CommandMerger { private boolean affectsMultiplePhysicalDocs() { int count = 0; - for (DocumentReference each : myAffectedDocuments) { + for (DocumentReference each : myAllAffectedDocuments) { VirtualFile file = each.getFile(); if (file instanceof LightVirtualFile) continue; if (++count > 1) return true; @@ -211,13 +230,10 @@ public class CommandMerger { return !myCurrentActions.isEmpty(); } - public Collection getAffectedDocuments() { - return myAffectedDocuments; - } - public boolean isUndoAvailable(Collection refs) { if (hasNonUndoableActions()) return false; if (refs.isEmpty()) return isGlobal() && hasActions(); + for (DocumentReference each : refs) { if (hasChangesOf(each)) return true; } @@ -236,7 +252,7 @@ public class CommandMerger { DocumentReference[] refs = action.getAffectedDocuments(); if (refs == null || ArrayUtil.contains(ref, refs)) return true; } - return false; + return hasActions() && myAdditionalAffectedDocuments.contains(ref); } public void setBeforeState(EditorAndState state) { @@ -249,8 +265,13 @@ public class CommandMerger { myStateAfter = state; } + public void addAdditionalAffectedDocuments(Collection refs) { + myAllAffectedDocuments.addAll(refs); + myAdditionalAffectedDocuments.addAll(refs); + } + public void invalidateActionsFor(DocumentReference ref) { - if (myAffectedDocuments.contains(ref)) { + if (myAllAffectedDocuments.contains(ref)) { myValid = false; } } diff --git a/platform/platform-impl/src/com/intellij/openapi/command/impl/CommandProcessorImpl.java b/platform/platform-impl/src/com/intellij/openapi/command/impl/CommandProcessorImpl.java index 0499719568e7..a6bff8320670 100644 --- a/platform/platform-impl/src/com/intellij/openapi/command/impl/CommandProcessorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/command/impl/CommandProcessorImpl.java @@ -26,8 +26,10 @@ import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.EmptyRunnable; import com.intellij.openapi.util.Ref; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Stack; @@ -69,27 +71,31 @@ public class CommandProcessorImpl extends CommandProcessorEx { private int myUndoTransparentCount = 0; - public void executeCommand(Runnable runnable, String name, Object groupId) { + public void executeCommand(@NotNull Runnable runnable, String name, Object groupId) { executeCommand(null, runnable, name, groupId); } - public void executeCommand(Project project, Runnable runnable, String name, Object groupId) { + public void executeCommand(Project project, @NotNull Runnable runnable, String name, Object groupId) { executeCommand(project, runnable, name, groupId, UndoConfirmationPolicy.DEFAULT); } - public void executeCommand(Project project, - final Runnable command, - final String name, - final Object groupId, - UndoConfirmationPolicy undoConfirmationPolicy) { - executeCommand(project, command, name, groupId, undoConfirmationPolicy, null); + public void executeCommand(Project project, @NotNull Runnable runnable, String name, Object groupId, Document document) { + executeCommand(project, runnable, name, groupId, UndoConfirmationPolicy.DEFAULT, document); } public void executeCommand(Project project, - final Runnable command, + @NotNull final Runnable command, final String name, final Object groupId, - UndoConfirmationPolicy undoConfirmationPolicy, + @NotNull UndoConfirmationPolicy confirmationPolicy) { + executeCommand(project, command, name, groupId, confirmationPolicy, null); + } + + public void executeCommand(Project project, + @NotNull final Runnable command, + final String name, + final Object groupId, + @NotNull UndoConfirmationPolicy confirmationPolicy, Document document) { ApplicationManager.getApplication().assertIsDispatchThread(); if (project != null && project.isDisposed()) return; @@ -104,7 +110,7 @@ public class CommandProcessorImpl extends CommandProcessorEx { } Throwable throwable = null; try { - myCurrentCommand = new CommandDescriptor(command, project, name, groupId, undoConfirmationPolicy, document); + myCurrentCommand = new CommandDescriptor(command, project, name, groupId, confirmationPolicy, document); fireCommandStarted(); command.run(); } @@ -263,11 +269,11 @@ public class CommandProcessorImpl extends CommandProcessorEx { return myCurrentCommand != null ? myCurrentCommand.myProject : null; } - public void addCommandListener(CommandListener listener) { + public void addCommandListener(@NotNull CommandListener listener) { myListeners.add(listener); } - public void addCommandListener(final CommandListener listener, Disposable parentDisposable) { + public void addCommandListener(@NotNull final CommandListener listener, @NotNull Disposable parentDisposable) { addCommandListener(listener); Disposer.register(parentDisposable, new Disposable() { public void dispose() { @@ -276,11 +282,11 @@ public class CommandProcessorImpl extends CommandProcessorEx { }); } - public void removeCommandListener(CommandListener listener) { + public void removeCommandListener(@NotNull CommandListener listener) { myListeners.remove(listener); } - public void runUndoTransparentAction(Runnable action) { + public void runUndoTransparentAction(@NotNull Runnable action) { if (myUndoTransparentCount++ == 0) fireUndoTransparentStarted(); try { action.run(); @@ -295,8 +301,21 @@ public class CommandProcessorImpl extends CommandProcessorEx { } public void markCurrentCommandAsGlobal(Project project) { - UndoManager manager = project != null ? UndoManager.getInstance(project) : UndoManager.getGlobalInstance(); - ((UndoManagerImpl)manager).markCurrentCommandAsGlobal(); + getUndoManager(project).markCurrentCommandAsGlobal(); + } + + private UndoManagerImpl getUndoManager(Project project) { + return (UndoManagerImpl)(project != null ? UndoManager.getInstance(project) : UndoManager.getGlobalInstance()); + } + + @Override + public void addAffectedDocuments(Project project, @NotNull Document... docs) { + getUndoManager(project).addAffectedDocuments(docs); + } + + @Override + public void addAffectedFiles(Project project, @NotNull VirtualFile... files) { + getUndoManager(project).addAffectedFiles(files); } private void fireCommandStarted() { diff --git a/platform/platform-impl/src/com/intellij/openapi/command/impl/EditorChangeAction.java b/platform/platform-impl/src/com/intellij/openapi/command/impl/EditorChangeAction.java index af77f67c54cd..ae10ed909023 100644 --- a/platform/platform-impl/src/com/intellij/openapi/command/impl/EditorChangeAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/command/impl/EditorChangeAction.java @@ -15,9 +15,7 @@ */ package com.intellij.openapi.command.impl; -import com.intellij.openapi.command.undo.DocumentReference; -import com.intellij.openapi.command.undo.DocumentReferenceManager; -import com.intellij.openapi.command.undo.UndoableAction; +import com.intellij.openapi.command.undo.BasicUndoableAction; import com.intellij.openapi.editor.ex.DocumentEx; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; @@ -27,8 +25,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.testFramework.LightVirtualFile; import org.jetbrains.annotations.NonNls; -class EditorChangeAction implements UndoableAction { - private final DocumentReference myReference; +class EditorChangeAction extends BasicUndoableAction { private final int myOffset; private final CharSequence myOldString; private final CharSequence myNewString; @@ -41,7 +38,7 @@ class EditorChangeAction implements UndoableAction { CharSequence oldString, CharSequence newString, long oldTimeStamp) { - myReference = DocumentReferenceManager.getInstance().create(document); + super(document); myOffset = offset; myOldString = oldString == null ? "" : oldString; @@ -83,7 +80,7 @@ class EditorChangeAction implements UndoableAction { } private void refreshFileStatus() { - VirtualFile f = myReference.getFile(); + VirtualFile f = getAffectedDocuments()[0].getFile(); if (f == null || f instanceof LightVirtualFile) return; for (Project each : ProjectManager.getInstance().getOpenProjects()) { @@ -92,16 +89,9 @@ class EditorChangeAction implements UndoableAction { } } - public DocumentReference[] getAffectedDocuments() { - return new DocumentReference[]{myReference}; - } - - public boolean isGlobal() { - return false; - } private DocumentEx getDocument() { - return (DocumentEx)myReference.getDocument(); + return (DocumentEx)getAffectedDocuments()[0].getDocument(); } @NonNls diff --git a/platform/platform-impl/src/com/intellij/openapi/command/impl/NonUndoableAction.java b/platform/platform-impl/src/com/intellij/openapi/command/impl/NonUndoableAction.java index 704f3c21964a..c315d1165cfd 100644 --- a/platform/platform-impl/src/com/intellij/openapi/command/impl/NonUndoableAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/command/impl/NonUndoableAction.java @@ -20,7 +20,7 @@ import com.intellij.openapi.command.undo.UndoableAction; import com.intellij.openapi.command.undo.UnexpectedUndoException; import com.intellij.openapi.diagnostic.Logger; -public class NonUndoableAction implements UndoableAction { +class NonUndoableAction implements UndoableAction { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.command.undo.NonUndoableAction"); private final DocumentReference[] myRefs; diff --git a/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoManagerImpl.java index 1bc2839b9d56..0fdecaadc6d9 100644 --- a/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoManagerImpl.java @@ -155,6 +155,7 @@ public class UndoManagerImpl extends UndoManager implements ProjectComponent, Ap public void commandStarted(CommandEvent event) { onCommandStarted(event.getProject(), event.getUndoConfirmationPolicy()); + if (event.getDocument() != null) addAffectedDocuments(event.getDocument()); } public void commandFinished(CommandEvent event) { @@ -257,10 +258,6 @@ public class UndoManagerImpl extends UndoManager implements ProjectComponent, Ap } } - public void markCurrentCommandAsGlobal() { - myCurrentMerger.markAsGlobal(); - } - @Override public void nonundoableActionPerformed(final DocumentReference ref, final boolean isGlobal) { ApplicationManager.getApplication().assertIsDispatchThread(); @@ -284,6 +281,34 @@ public class UndoManagerImpl extends UndoManager implements ProjectComponent, Ap myCurrentMerger.addAction(action); } + public void markCurrentCommandAsGlobal() { + myCurrentMerger.markAsGlobal(); + } + + public void addAffectedDocuments(Document... docs) { + if (!isInsideCommand()) { + LOG.error("Must be called inside command"); + return; + } + List refs = new ArrayList(docs.length); + for (Document each : docs) { + refs.add(DocumentReferenceManager.getInstance().create(each)); + } + myCurrentMerger.addAdditionalAffectedDocuments(refs); + } + + public void addAffectedFiles(VirtualFile... files) { + if (!isInsideCommand()) { + LOG.error("Must be called inside command"); + return; + } + List refs = new ArrayList(files.length); + for (VirtualFile each : files) { + refs.add(DocumentReferenceManager.getInstance().create(each)); + } + myCurrentMerger.addAdditionalAffectedDocuments(refs); + } + public void invalidateActionsFor(DocumentReference ref) { ApplicationManager.getApplication().assertIsDispatchThread(); myMerger.invalidateActionsFor(ref); diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/Configuration.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/Configuration.java index bd9017c98a88..f77d7a017559 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/Configuration.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/Configuration.java @@ -22,10 +22,13 @@ import com.intellij.ide.plugins.cl.PluginClassLoader; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.UndoConfirmationPolicy; import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.openapi.command.undo.DocumentReference; +import com.intellij.openapi.command.undo.GlobalUndoableAction; import com.intellij.openapi.command.undo.UndoManager; import com.intellij.openapi.command.undo.UndoableAction; -import com.intellij.openapi.components.*; +import com.intellij.openapi.components.PersistentStateComponent; +import com.intellij.openapi.components.State; +import com.intellij.openapi.components.Storage; +import com.intellij.openapi.components.StorageScheme; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; @@ -59,7 +62,6 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.*; -import java.util.concurrent.CopyOnWriteArrayList; /** * Configuration that holds configured xml tag, attribute and method parameter @@ -529,7 +531,7 @@ public final class Configuration implements PersistentStateComponent, M public static void replaceInjectionsWithUndo(final Project project, final T add, final T remove, final List psiElementsToRemove, final PairProcessor actualProcessor) { - final UndoableAction action = new UndoableAction() { + final UndoableAction action = new GlobalUndoableAction() { public void undo() { actualProcessor.process(remove, add); } @@ -537,14 +539,6 @@ public final class Configuration implements PersistentStateComponent, M public void redo() { actualProcessor.process(add, remove); } - - public DocumentReference[] getAffectedDocuments() { - return DocumentReference.EMPTY_ARRAY; - } - - public boolean isGlobal() { - return true; - } }; final List psiFiles = ContainerUtil.mapNotNull(psiElementsToRemove, new NullableFunction() { public PsiFile fun(final PsiElement psiAnnotation) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/dynamic/ui/DynamicDialog.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/dynamic/ui/DynamicDialog.java index 95aa07dbf932..076851ccf4d2 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/dynamic/ui/DynamicDialog.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/intentions/dynamic/ui/DynamicDialog.java @@ -17,7 +17,9 @@ package org.jetbrains.plugins.groovy.annotator.intentions.dynamic.ui; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; import com.intellij.openapi.command.CommandProcessor; -import com.intellij.openapi.command.undo.*; +import com.intellij.openapi.command.undo.GlobalUndoableAction; +import com.intellij.openapi.command.undo.UndoManager; +import com.intellij.openapi.command.undo.UnexpectedUndoException; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.event.DocumentEvent; @@ -330,12 +332,11 @@ public abstract class DynamicDialog extends DialogWrapper { } } - Document document = PsiDocumentManager.getInstance(myProject).getDocument(myContext.getContainingFile()); - final DocumentReference[] refs = new DocumentReference[]{DocumentReferenceManager.getInstance().create(document)}; + final Document document = PsiDocumentManager.getInstance(myProject).getDocument(myContext.getContainingFile()); CommandProcessor.getInstance().executeCommand(myProject, new Runnable() { public void run() { - UndoManager.getInstance(myProject).undoableActionPerformed(new UndoableAction() { + UndoManager.getInstance(myProject).undoableActionPerformed(new GlobalUndoableAction(document) { public void undo() throws UnexpectedUndoException { final DItemElement itemElement; @@ -368,14 +369,6 @@ public abstract class DynamicDialog extends DialogWrapper { public void redo() throws UnexpectedUndoException { addElement(mySettings); } - - public DocumentReference[] getAffectedDocuments() { - return refs; - } - - public boolean isGlobal() { - return true; - } }); addElement(mySettings);