public boolean execute(boolean drop, boolean isInsideStartFinishGroup) { if (!myUndoableGroup.isUndoable()) { reportCannotUndo( CommonBundle.message("cannot.undo.error.contains.nonundoable.changes.message"), myUndoableGroup.getAffectedDocuments()); return false; } Set<DocumentReference> clashing = getStackHolder().collectClashingActions(myUndoableGroup); if (!clashing.isEmpty()) { reportCannotUndo( CommonBundle.message("cannot.undo.error.other.affected.files.changed.message"), clashing); return false; } if (!isInsideStartFinishGroup && myUndoableGroup.shouldAskConfirmation(isRedo())) { if (!askUser()) return false; } else { if (restore(getBeforeState())) { setBeforeState(new EditorAndState(myEditor, myEditor.getState(FileEditorStateLevel.UNDO))); return true; } } Collection<VirtualFile> readOnlyFiles = collectReadOnlyAffectedFiles(); if (!readOnlyFiles.isEmpty()) { final Project project = myManager.getProject(); final VirtualFile[] files = VfsUtil.toVirtualFileArray(readOnlyFiles); if (project == null) { return false; } final ReadonlyStatusHandler.OperationStatus operationStatus = ReadonlyStatusHandler.getInstance(project).ensureFilesWritable(files); if (operationStatus.hasReadonlyFiles()) { return false; } } Collection<Document> readOnlyDocuments = collectReadOnlyDocuments(); if (!readOnlyDocuments.isEmpty()) { for (Document document : readOnlyDocuments) { document.fireReadOnlyModificationAttempt(); } return false; } getStackHolder().removeFromStacks(myUndoableGroup); if (!drop) { getReverseStackHolder().addToStacks(myUndoableGroup); } performAction(); restore(getAfterState()); return true; }
public void removeFromStacks(UndoableGroup group) { if (group.getAffectedDocuments().isEmpty()) return; if (group.isGlobal()) { assert myGlobalStack.getLast() == group; myGlobalStack.removeLast(); } for (DocumentReference each : group.getAffectedDocuments()) { LinkedList<UndoableGroup> stack = getStack(each); assert stack.getLast() == group; stack.removeLast(); } }
private void doAddToStack(LinkedList<UndoableGroup> stack, UndoableGroup group, int limit) { if (!group.isUndoable() && stack.isEmpty()) return; stack.addLast(group); while (stack.size() > limit) { stack.removeFirst(); } }
private boolean askUser() { String actionText = getActionName(myUndoableGroup.getCommandName()); if (actionText.length() > 80) { actionText = actionText.substring(0, 80) + "... "; } return Messages.showOkCancelDialog( myManager.getProject(), actionText + "?", getActionName(), Messages.getQuestionIcon()) == Messages.OK; }
private Collection<VirtualFile> collectReadOnlyAffectedFiles() { Collection<DocumentReference> affectedDocument = myUndoableGroup.getAffectedDocuments(); Collection<VirtualFile> readOnlyFiles = new ArrayList<VirtualFile>(); for (DocumentReference documentReference : affectedDocument) { VirtualFile file = documentReference.getFile(); if ((file != null) && file.isValid() && !file.isWritable()) { readOnlyFiles.add(file); } } return readOnlyFiles; }
private Collection<Document> collectReadOnlyDocuments() { Collection<DocumentReference> affectedDocument = myUndoableGroup.getAffectedDocuments(); Collection<Document> readOnlyDocs = new ArrayList<Document>(); for (DocumentReference ref : affectedDocument) { if (ref instanceof DocumentReferenceByDocument) { Document doc = ref.getDocument(); if (doc != null && !doc.isWritable()) readOnlyDocs.add(doc); } } return readOnlyDocs; }
@NotNull public UndoableGroup getLastAction(Collection<DocumentReference> refs) { if (refs.isEmpty()) return myGlobalStack.getLast(); UndoableGroup mostRecentAction = null; int mostRecentDocTimestamp = myUndo ? -1 : Integer.MAX_VALUE; for (DocumentReference each : refs) { LinkedList<UndoableGroup> stack = getStack(each); // the stack for a document can be empty in case of compound editors with several documents if (stack.isEmpty()) continue; UndoableGroup lastAction = stack.getLast(); int timestamp = lastAction.getCommandTimestamp(); if (myUndo ? timestamp > mostRecentDocTimestamp : timestamp < mostRecentDocTimestamp) { mostRecentAction = lastAction; mostRecentDocTimestamp = timestamp; } } // result must not be null return mostRecentAction; }
public Set<DocumentReference> collectClashingActions(UndoableGroup group) { Set<DocumentReference> result = new THashSet<DocumentReference>(); for (DocumentReference each : group.getAffectedDocuments()) { UndoableGroup last = getStack(each).getLast(); if (last != group) { result.addAll(last.getAffectedDocuments()); } } if (group.isGlobal()) { UndoableGroup last = myGlobalStack.getLast(); if (last != group) { result.addAll(last.getAffectedDocuments()); } } return result; }
public void collectAllAffectedDocuments(Collection<DocumentReference> result) { for (UndoableGroup each : myGlobalStack) { result.addAll(each.getAffectedDocuments()); } collectLocalAffectedDocuments(result); }
private void doInvalidateAllGlobalActions(LinkedList<UndoableGroup> stack) { for (UndoableGroup g : stack) { g.invalidateIfGlobal(); } }
public void addToStacks(UndoableGroup group) { if (group.isGlobal()) doAddToStack(myGlobalStack, group, UndoManagerImpl.GLOBAL_UNDO_LIMIT); for (DocumentReference each : group.getAffectedDocuments()) { doAddToStack(getStack(each), group, UndoManagerImpl.LOCAL_UNDO_LIMIT); } }
boolean isTransparent() { return myUndoableGroup.isTransparent(); }