introduce VetoableProjectManagerListener to avoid inappropriate using of message bus

This commit is contained in:
Vladimir Krivosheev
2017-05-09 18:31:16 +02:00
parent 9354592142
commit 4ae9edbe94
9 changed files with 102 additions and 21 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -566,11 +566,10 @@ public class CompilerTask extends Task.Backgroundable {
private boolean myUserAcceptedCancel = false;
@Override
public boolean canCloseProject(final Project project) {
if (project != null && project.equals(myProject)) {
public void projectClosingBeforeSave(@NotNull Project project) {
if (myProject == project) {
cancel();
}
return true;
}
public void setContent(Content content, ContentManager contentManager) {
@@ -1693,9 +1693,8 @@ public class BuildManager implements Disposable {
}
@Override
public boolean canCloseProject(Project project) {
public void projectClosingBeforeSave(@NotNull Project project) {
cancelAutoMakeTasks(project);
return true;
}
@Override
@@ -38,7 +38,7 @@ import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.project.ProjectManagerListener;
import com.intellij.openapi.project.VetoableProjectManagerListener;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.IconLoader;
@@ -603,14 +603,14 @@ public class RunContentManagerImpl implements RunContentManager, Disposable {
return null;
}
private class CloseListener extends ContentManagerAdapter implements ProjectManagerListener, Disposable {
private class CloseListener extends ContentManagerAdapter implements VetoableProjectManagerListener, Disposable {
private Content myContent;
private final Executor myExecutor;
private CloseListener(@NotNull final Content content, @NotNull Executor executor) {
myContent = content;
content.getManager().addContentManagerListener(this);
ApplicationManager.getApplication().getMessageBus().connect(this).subscribe(ProjectManager.TOPIC, this);
ProjectManager.getInstance().addProjectManagerListener(myProject, this);
myExecutor = executor;
}
@@ -636,6 +636,7 @@ public class RunContentManagerImpl implements RunContentManager, Disposable {
}
finally {
content.getManager().removeContentManagerListener(this);
ProjectManager.getInstance().removeProjectManagerListener(myProject, this);
content.release(); // don't invoke myContent.release() because myContent becomes null after destroyProcess()
myContent = null;
}
@@ -660,7 +661,7 @@ public class RunContentManagerImpl implements RunContentManager, Disposable {
}
@Override
public boolean canCloseProject(final Project project) {
public boolean canClose(@NotNull Project project) {
if (project != myProject) return true;
if (myContent == null) return true;
@@ -75,7 +75,7 @@ import java.nio.charset.Charset;
import java.util.*;
import java.util.List;
public class FileDocumentManagerImpl extends FileDocumentManager implements VirtualFileListener, ProjectManagerListener, SafeWriteRequestor {
public class FileDocumentManagerImpl extends FileDocumentManager implements VirtualFileListener, VetoableProjectManagerListener, SafeWriteRequestor {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl");
public static final Key<Document> HARD_REF_TO_DOCUMENT_KEY = Key.create("HARD_REF_TO_DOCUMENT_KEY");
@@ -125,8 +125,9 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Virt
}
};
public FileDocumentManagerImpl(@NotNull VirtualFileManager virtualFileManager) {
public FileDocumentManagerImpl(@NotNull VirtualFileManager virtualFileManager, @NotNull ProjectManager projectManager) {
virtualFileManager.addVirtualFileListener(this);
projectManager.addProjectManagerListener(this);
myBus = ApplicationManager.getApplication().getMessageBus();
myBus.connect().subscribe(ProjectManager.TOPIC, this);
@@ -708,7 +709,7 @@ public class FileDocumentManagerImpl extends FileDocumentManager implements Virt
}
@Override
public boolean canCloseProject(Project project) {
public boolean canClose(@NotNull Project project) {
if (!myUnsavedDocuments.isEmpty()) {
myOnClose = true;
try {
@@ -134,6 +134,18 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable {
}
}
}
@Override
public void projectClosingBeforeSave(@NotNull Project project) {
for (ProjectManagerListener listener : ContainerUtil.concat(getListeners(project), myListeners)) {
try {
listener.projectClosingBeforeSave(project);
}
catch (Exception e) {
handleListenerError(e, listener);
}
}
}
});
}
@@ -614,6 +626,8 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable {
final ShutDownTracker shutDownTracker = ShutDownTracker.getInstance();
shutDownTracker.registerStopperThread(Thread.currentThread());
try {
myBusPublisher.projectClosingBeforeSave(project);
if (save) {
FileDocumentManager.getInstance().saveAllDocuments();
project.save();
@@ -665,6 +679,11 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable {
myListeners.add(listener);
}
@Override
public void addProjectManagerListener(@NotNull VetoableProjectManagerListener listener) {
myListeners.add(listener);
}
@Override
public void addProjectManagerListener(@NotNull final ProjectManagerListener listener, @NotNull Disposable parentDisposable) {
addProjectManagerListener(listener);
@@ -46,6 +46,8 @@ public abstract class ProjectManager {
@Deprecated
public abstract void addProjectManagerListener(@NotNull ProjectManagerListener listener);
public abstract void addProjectManagerListener(@NotNull VetoableProjectManagerListener listener);
/**
* @deprecated Use {@link Topic}
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 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.
@@ -15,6 +15,8 @@
*/
package com.intellij.openapi.project;
import org.jetbrains.annotations.NotNull;
import java.util.EventListener;
/**
@@ -32,10 +34,7 @@ public interface ProjectManagerListener extends EventListener {
}
/**
* Checks whether the project can be closed.
*
* @param project project to check
* @return true or false
* @deprecated Please use {@link VetoableProjectManagerListener}
*/
default boolean canCloseProject(Project project) {
return true;
@@ -54,4 +53,7 @@ public interface ProjectManagerListener extends EventListener {
*/
default void projectClosing(Project project) {
}
default void projectClosingBeforeSave(@NotNull Project project) {
}
}
@@ -0,0 +1,31 @@
/*
* Copyright 2000-2017 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.project;
import org.jetbrains.annotations.NotNull;
/**
* Must be added only using {@link ProjectManager#addProjectManagerListener(VetoableProjectManagerListener)}, not message bus.
*/
public interface VetoableProjectManagerListener extends ProjectManagerListener {
/**
* Checks whether the project can be closed.
*
* @param project project to check
* @return true or false
*/
boolean canClose(@NotNull Project project);
}
@@ -41,7 +41,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.project.ProjectManagerListener;
import com.intellij.openapi.project.VetoableProjectManagerListener;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Clock;
import com.intellij.openapi.util.Disposer;
@@ -125,18 +125,22 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O
private ActionToolbar myLeftToolbar;
private ActionToolbar myRightToolbar;
private final TreeExpander myTreeExpander = new TreeExpander() {
@Override
public boolean canCollapse() {
return isTreeView();
}
@Override
public boolean canExpand() {
return isTreeView();
}
@Override
public void collapseAll() {
AntBuildMessageView.this.collapseAll();
}
@Override
public void expandAll() {
AntBuildMessageView.this.expandAll();
}
@@ -199,6 +203,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O
myTreeView.setActionsEnabled(false);
new OutputFlusher() {
@Override
public void doFlush() {
final int processedCount = myCommandsProcessedCount;
for (int i = 0; i < processedCount; i++) {
@@ -370,6 +375,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O
}
public final class CloseAction extends CloseTabToolbarAction {
@Override
public void actionPerformed(AnActionEvent e) {
close();
}
@@ -457,6 +463,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O
addCommand(new FinishTaskCommand());
}
@Override
public Object getData(String dataId) {
Object data = myCurrentView.getData(dataId);
if (data != null) {
@@ -536,7 +543,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O
myTreeView.expandAll();
}
private static final class CloseListener extends ContentManagerAdapter implements ProjectManagerListener {
private static final class CloseListener extends ContentManagerAdapter implements VetoableProjectManagerListener {
private Content myContent;
private boolean myCloseAllowed = false;
private final ContentManager myContentManager;
@@ -550,6 +557,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O
ProjectManager.getInstance().addProjectManagerListener(myProject, this);
}
@Override
public void contentRemoved(ContentManagerEvent event) {
if (event.getContent() == myContent) {
myContentManager.removeContentManagerListener(this);
@@ -565,6 +573,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O
}
}
@Override
public void contentRemoveQuery(ContentManagerEvent event) {
if (event.getContent() == myContent) {
boolean canClose = closeQuery();
@@ -574,13 +583,15 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O
}
}
@Override
public void projectClosed(Project project) {
if (myContent != null) {
myContentManager.removeContent(myContent, true);
}
}
public boolean canCloseProject(Project project) {
@Override
public boolean canClose(@NotNull Project project) {
return closeQuery();
}
@@ -657,6 +668,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O
super(new AntMessage(MessageType.BUILD, 0, buildName, null, 0, 0));
}
@Override
void execute(AntOutputView outputView) {
outputView.startBuild(getMessage());
}
@@ -667,6 +679,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O
super(new AntMessage(MessageType.ERROR, 0, AntBundle.message("cannot.start.build.name.error.message", buildName), null, 0, 0));
}
@Override
void execute(AntOutputView outputView) {
outputView.buildFailed(getMessage());
}
@@ -680,6 +693,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O
myFinishStatusText = finishStatusText;
}
@Override
void execute(AntOutputView outputView) {
outputView.finishBuild(myFinishStatusText);
}
@@ -690,6 +704,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O
super(new AntMessage(MessageType.TARGET, 0, targetName, null, 0, 0));
}
@Override
void execute(AntOutputView outputView) {
outputView.startTarget(getMessage());
}
@@ -700,6 +715,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O
super(0);
}
@Override
void execute(AntOutputView outputView) {
outputView.finishTarget();
}
@@ -710,6 +726,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O
super(new AntMessage(MessageType.TASK, 0, taskName, null, 0, 0));
}
@Override
void execute(AntOutputView outputView) {
outputView.startTask(getMessage());
}
@@ -720,6 +737,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O
super(0);
}
@Override
public void execute(AntOutputView outputView) {
outputView.finishTask();
}
@@ -730,6 +748,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O
super(antMessage);
}
@Override
void execute(AntOutputView outputView) {
outputView.addMessage(getMessage());
}
@@ -740,6 +759,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O
super(antMessage);
}
@Override
void execute(AntOutputView outputView) {
outputView.addException(getMessage(), isVerboseMode());
}
@@ -753,6 +773,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O
myUrl = url;
}
@Override
void execute(AntOutputView outputView) {
outputView.addJavacMessage(getMessage(), myUrl);
}
@@ -934,26 +955,32 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O
}
}
@Override
public String getNextOccurenceActionName() {
return myTreeView.getNextOccurenceActionName();
}
@Override
public String getPreviousOccurenceActionName() {
return myTreeView.getPreviousOccurenceActionName();
}
@Override
public OccurenceInfo goNextOccurence() {
return isTreeView() ? myTreeView.goNextOccurence() : null;
}
@Override
public OccurenceInfo goPreviousOccurence() {
return isTreeView() ? myTreeView.goPreviousOccurence() : null;
}
@Override
public boolean hasNextOccurence() {
return isTreeView() && myTreeView.hasNextOccurence();
}
@Override
public boolean hasPreviousOccurence() {
return isTreeView() && myTreeView.hasPreviousOccurence();
}