ReadonlyStatusHandler refactored

This commit is contained in:
Dmitry Avdeev
2009-09-10 10:59:09 +04:00
parent 5765e4a300
commit 82cf52864a
6 changed files with 71 additions and 118 deletions
@@ -6,7 +6,6 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.project.Project;
@@ -70,29 +69,24 @@ public class CodeInsightUtilBase {
language);
}
public static boolean prepareFileForWrite(final PsiFile file) {
if (file == null) return false;
public static boolean prepareFileForWrite(final PsiFile psiFile) {
if (psiFile == null) return false;
final VirtualFile file = psiFile.getVirtualFile();
final Project project = psiFile.getProject();
final Project project = file.getProject();
final Document document = PsiDocumentManager.getInstance(project).getDocument(file);
if (!ReadonlyStatusHandler.getInstance(project).isWriteAccessAllowed(file.getVirtualFile())) {
final Editor editor =
FileEditorManager.getInstance(project).openTextEditor(new OpenFileDescriptor(project, file.getVirtualFile()), true);
if (!FileDocumentManager.getInstance().requestWriting(document, project)) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
if (editor != null && editor.getComponent().isDisplayable()) {
HintManager.getInstance()
.showErrorHint(editor, CodeInsightBundle.message("error.hint.file.is.readonly", file.getVirtualFile().getPresentableUrl()));
}
final Editor editor =
psiFile.isWritable() ? null : FileEditorManager.getInstance(project).openTextEditor(new OpenFileDescriptor(project, file), true);
if (!ReadonlyStatusHandler.ensureFilesWritable(project, file)) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
if (editor != null && editor.getComponent().isDisplayable()) {
HintManager.getInstance()
.showErrorHint(editor, CodeInsightBundle.message("error.hint.file.is.readonly", file.getPresentableUrl()));
}
});
}
});
return false;
}
return false;
}
return true;
@@ -60,12 +60,6 @@ public abstract class FileDocumentManager {
@NotNull
public abstract String getLineSeparator(@Nullable VirtualFile file, @Nullable Project project);
/**
* @return true if writing access allowed
* @see #requestWriting(com.intellij.openapi.editor.Document, com.intellij.openapi.project.Project)
*/
public abstract boolean isWritingAllowed(@NotNull Document document, Project project);
/**
* Requests writing access on given document, possibly involving interaction with user.
*
@@ -15,67 +15,27 @@
*/
package com.intellij.openapi.vfs;
import com.intellij.CommonBundle;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
public abstract class ReadonlyStatusHandler {
public static boolean ensureFilesWritable(Project project, @NotNull VirtualFile... files) {
public static boolean ensureFilesWritable(Project project, VirtualFile... files) {
return getInstance(project).ensureFilesWritable(files).hasReadonlyFiles();
}
public static class OperationStatus {
private final VirtualFile[] myReadonlyFiles;
private final VirtualFile[] myUpdatedFiles;
public interface OperationStatus {
VirtualFile[] getReadonlyFiles();
public OperationStatus(final VirtualFile[] readonlyFiles, final VirtualFile[] updatedFiles) {
myReadonlyFiles = readonlyFiles;
myUpdatedFiles = updatedFiles;
}
boolean hasReadonlyFiles();
public VirtualFile[] getReadonlyFiles() {
return myReadonlyFiles;
}
public VirtualFile[] getUpdatedFiles() {
return myUpdatedFiles;
}
public boolean hasUpdatedFiles() {
return myUpdatedFiles.length > 0;
}
public boolean hasReadonlyFiles() {
return myReadonlyFiles.length > 0;
}
public String getReadonlyFilesMessage() {
if (hasReadonlyFiles()) {
StringBuffer buf = new StringBuffer();
if (myReadonlyFiles.length > 1) {
for (VirtualFile file : myReadonlyFiles) {
buf.append('\n');
buf.append(file.getPresentableUrl());
}
return CommonBundle.message("failed.to.make.the.following.files.writable.error.message", buf.toString());
}
else {
return CommonBundle.message("failed.to.make.file.writeable.error.message", myReadonlyFiles[0].getPresentableUrl());
}
}
return null;
}
String getReadonlyFilesMessage();
}
public abstract OperationStatus ensureFilesWritable(VirtualFile... files);
public abstract boolean isWriteAccessAllowed(VirtualFile... files);
public OperationStatus ensureFilesWritable(final Collection<VirtualFile> files) {
return ensureFilesWritable(files.toArray(new VirtualFile[files.size()]));
}
@@ -83,4 +43,5 @@ public abstract class ReadonlyStatusHandler {
public static ReadonlyStatusHandler getInstance(Project project) {
return ServiceManager.getService(project, ReadonlyStatusHandler.class);
}
}
@@ -638,10 +638,7 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
}
}
if (readonlyFiles.isEmpty()) return new ReadonlyStatusHandler.OperationStatus(VirtualFile.EMPTY_ARRAY, VirtualFile.EMPTY_ARRAY);
return ReadonlyStatusHandler.getInstance(myProject)
.ensureFilesWritable(readonlyFiles.toArray(new VirtualFile[readonlyFiles.size()]));
return ReadonlyStatusHandler.getInstance(myProject).ensureFilesWritable(readonlyFiles);
}
});
}
@@ -300,21 +300,14 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Appl
}
}
@Override
public boolean isWritingAllowed(@NotNull Document document, Project project) {
return document.isWritable();
}
@Override
public boolean requestWriting(@NotNull Document document, Project project) {
if (isWritingAllowed(document, project)) {
return true;
final VirtualFile file = getInstance().getFile(document);
if (file != null && file.isValid()) {
return ReadonlyStatusHandler.ensureFilesWritable(project, file);
}
if (project != null) {
final VirtualFile file = getInstance().getFile(document);
if (file != null && file.isValid()) {
return ReadonlyStatusHandler.ensureFilesWritable(project, file);
}
if (document.isWritable()) {
return true;
}
document.fireReadOnlyModificationAttempt();
return false;
@@ -41,6 +41,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.MultiValuesMap;
import com.intellij.openapi.vfs.ReadonlyStatusHandler;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.CommonBundle;
import gnu.trove.THashSet;
import java.util.ArrayList;
@@ -79,7 +80,7 @@ public class ReadonlyStatusHandlerImpl extends ReadonlyStatusHandler implements
public OperationStatus ensureFilesWritable(VirtualFile... files) {
if (files.length == 0) {
return new OperationStatus(VirtualFile.EMPTY_ARRAY, VirtualFile.EMPTY_ARRAY);
return new OperationStatusImpl(VirtualFile.EMPTY_ARRAY);
}
ApplicationManager.getApplication().assertIsDispatchThread();
@@ -92,18 +93,13 @@ public class ReadonlyStatusHandlerImpl extends ReadonlyStatusHandler implements
}
files = realFiles.toArray(new VirtualFile[realFiles.size()]);
final long[] modificationStamps = new long[files.length];
for (int i = 0; i < files.length; i++) {
modificationStamps[i] = files[i].getModificationStamp();
}
final FileInfo[] fileInfos = createFileInfos(files);
if (fileInfos.length == 0) { // if all files are already writable
return createResultStatus(files, modificationStamps);
return createResultStatus(files);
}
if (ApplicationManager.getApplication().isUnitTestMode()) {
return createResultStatus(files, modificationStamps);
return createResultStatus(files);
}
// This event count hack is necessary to allow actions that called this stuff could still get data from their data contexts.
@@ -117,38 +113,21 @@ public class ReadonlyStatusHandlerImpl extends ReadonlyStatusHandler implements
processFiles(new ArrayList<FileInfo>(Arrays.asList(fileInfos))); // the collection passed is modified
}
IdeEventQueue.getInstance().setEventCount(savedEventCount);
return createResultStatus(files, modificationStamps);
return createResultStatus(files);
}
@Override
public boolean isWriteAccessAllowed(VirtualFile... files) {
for (VirtualFile file : files) {
if (!file.isWritable()) {
return false;
}
}
return true;
}
private static OperationStatus createResultStatus(final VirtualFile[] files, final long[] modificationStamps) {
private static OperationStatus createResultStatus(final VirtualFile[] files) {
List<VirtualFile> readOnlyFiles = new ArrayList<VirtualFile>();
List<VirtualFile> updatedFiles = new ArrayList<VirtualFile>();
for (int i = 0; i < files.length; i++) {
VirtualFile file = files[i];
for (VirtualFile file : files) {
if (file.exists()) {
if (!file.isWritable()) {
readOnlyFiles.add(file);
}
if (modificationStamps[i] != file.getModificationStamp()) {
updatedFiles.add(file);
}
}
}
return new OperationStatus(
readOnlyFiles.isEmpty() ? VirtualFile.EMPTY_ARRAY : readOnlyFiles.toArray(new VirtualFile[readOnlyFiles.size()]),
updatedFiles.isEmpty() ? VirtualFile.EMPTY_ARRAY : updatedFiles.toArray(new VirtualFile[updatedFiles.size()])
);
return new OperationStatusImpl(
readOnlyFiles.isEmpty() ? VirtualFile.EMPTY_ARRAY : readOnlyFiles.toArray(new VirtualFile[readOnlyFiles.size()]));
}
private FileInfo[] createFileInfos(VirtualFile[] files) {
@@ -178,4 +157,39 @@ public class ReadonlyStatusHandlerImpl extends ReadonlyStatusHandler implements
}
}
}
private static class OperationStatusImpl implements OperationStatus {
private final VirtualFile[] myReadonlyFiles;
OperationStatusImpl(final VirtualFile[] readonlyFiles) {
myReadonlyFiles = readonlyFiles;
}
public VirtualFile[] getReadonlyFiles() {
return myReadonlyFiles;
}
public boolean hasReadonlyFiles() {
return myReadonlyFiles.length > 0;
}
public String getReadonlyFilesMessage() {
if (hasReadonlyFiles()) {
StringBuffer buf = new StringBuffer();
if (myReadonlyFiles.length > 1) {
for (VirtualFile file : myReadonlyFiles) {
buf.append('\n');
buf.append(file.getPresentableUrl());
}
return CommonBundle.message("failed.to.make.the.following.files.writable.error.message", buf.toString());
}
else {
return CommonBundle.message("failed.to.make.file.writeable.error.message", myReadonlyFiles[0].getPresentableUrl());
}
}
throw new RuntimeException("No readonly files");
}
}
}