mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
get rid of recursion on undo (fix EA-119527 - SOE: UndoManagerImpl.undo)
This commit is contained in:
@@ -210,6 +210,13 @@ public class CommandMerger {
|
||||
|
||||
boolean isInsideStartFinishGroup = false;
|
||||
while ((undoRedo = createUndoOrRedo(editor, isUndo)) != null) {
|
||||
if (editor != null && undoRedo.isBlockedByOtherChanges()) {
|
||||
UndoRedo blockingChange = createUndoOrRedo(null, isUndo);
|
||||
if (blockingChange != null && blockingChange.myUndoableGroup != undoRedo.myUndoableGroup) {
|
||||
if (undoRedo.confirmSwitchTo(blockingChange)) blockingChange.execute(false, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!undoRedo.execute(false, isInsideStartFinishGroup)) return;
|
||||
isInsideStartFinishGroup = undoRedo.myUndoableGroup.isInsideStartFinishGroup(isUndo, isInsideStartFinishGroup);
|
||||
if (isInsideStartFinishGroup) continue;
|
||||
|
||||
@@ -16,6 +16,7 @@ import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.ReadonlyStatusHandler;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -79,7 +80,7 @@ abstract class UndoRedo {
|
||||
|
||||
protected abstract void setBeforeState(EditorAndState state);
|
||||
|
||||
public boolean execute(boolean drop, boolean isInsideStartFinishGroup) {
|
||||
public boolean execute(boolean drop, boolean disableConfirmation) {
|
||||
if (!myUndoableGroup.isUndoable()) {
|
||||
reportCannotUndo(CommonBundle.message("cannot.undo.error.contains.nonundoable.changes.message"),
|
||||
myUndoableGroup.getAffectedDocuments());
|
||||
@@ -88,14 +89,12 @@ abstract class UndoRedo {
|
||||
|
||||
Set<DocumentReference> clashing = getStackHolder().collectClashingActions(myUndoableGroup);
|
||||
if (!clashing.isEmpty()) {
|
||||
if (!tryFallbackToGlobalUndo())
|
||||
reportCannotUndo(CommonBundle.message("cannot.undo.error.other.affected.files.changed.message"), clashing);
|
||||
|
||||
reportCannotUndo(CommonBundle.message("cannot.undo.error.other.affected.files.changed.message"), clashing);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (!isInsideStartFinishGroup && myUndoableGroup.shouldAskConfirmation(isRedo()) && !UndoManagerImpl.ourNeverAskUser) {
|
||||
if (!disableConfirmation && myUndoableGroup.shouldAskConfirmation(isRedo()) && !UndoManagerImpl.ourNeverAskUser) {
|
||||
if (!askUser()) return false;
|
||||
}
|
||||
else {
|
||||
@@ -140,22 +139,6 @@ abstract class UndoRedo {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean tryFallbackToGlobalUndo() {
|
||||
UndoableGroup globalUndoableGroup = getStackHolder().findGlobalUndoableGroup(myUndoableGroup);
|
||||
if (globalUndoableGroup != null) {
|
||||
if (isRedo()) {
|
||||
myManager.redo(null);
|
||||
}
|
||||
else {
|
||||
myManager.undo(null);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected abstract boolean isRedo();
|
||||
|
||||
private Collection<Document> collectReadOnlyDocuments() {
|
||||
@@ -212,6 +195,17 @@ abstract class UndoRedo {
|
||||
return isOk[0];
|
||||
}
|
||||
|
||||
boolean confirmSwitchTo(@NotNull UndoRedo other) {
|
||||
final boolean[] isOk = new boolean[1];
|
||||
TransactionGuard.getInstance().submitTransactionAndWait(() -> {
|
||||
String message = CommonBundle.message("undo.conflicting.change.confirmation.message") + "\n" +
|
||||
getActionName(other.myUndoableGroup.getCommandName()) + "?";
|
||||
isOk[0] = Messages.showOkCancelDialog(myManager.getProject(), message, getActionName(),
|
||||
Messages.getQuestionIcon()) == Messages.OK;
|
||||
});
|
||||
return isOk[0];
|
||||
}
|
||||
|
||||
private boolean restore(EditorAndState pair, boolean onlyIfDiffers) {
|
||||
// editor can be invalid if underlying file is deleted during undo (e.g. after undoing scratch file creation)
|
||||
if (pair == null || myEditor == null || !myEditor.isValid() || !pair.canBeAppliedTo(myEditor)) return false;
|
||||
@@ -228,4 +222,9 @@ abstract class UndoRedo {
|
||||
myEditor.setState(pair.getState());
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isBlockedByOtherChanges() {
|
||||
return myUndoableGroup.isGlobal() && myUndoableGroup.isUndoable() &&
|
||||
!getStackHolder().collectClashingActions(myUndoableGroup).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
-11
@@ -12,7 +12,6 @@ import com.intellij.util.containers.WeakList;
|
||||
import gnu.trove.THashMap;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
|
||||
import java.util.*;
|
||||
@@ -286,14 +285,4 @@ class UndoRedoStacksHolder {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public UndoableGroup findGlobalUndoableGroup(UndoableGroup undoableGroup) {
|
||||
for (UndoableGroup group : myGlobalStack) {
|
||||
if (group == undoableGroup) {
|
||||
return group;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,6 +133,7 @@ profiling.capture.snapshot.error=Failed to capture snapshot: {0}
|
||||
cannot.undo.dialog.title=Cannot Undo
|
||||
cannot.undo.error.other.affected.files.changed.message=Following files affected by this action have been already changed:
|
||||
cannot.undo.error.contains.nonundoable.changes.message=Following files have changes that cannot be undone:
|
||||
undo.conflicting.change.confirmation.message=Other files affected by this action have been already changed.
|
||||
undo.dialog.title=Undo
|
||||
redo.command.confirmation.text=Redo {0}
|
||||
redo.confirmation.title=Redo
|
||||
|
||||
Reference in New Issue
Block a user