introduce VetoableProjectManagerListener to avoid inappropriate using of message bus
authorVladimir Krivosheev <vladimir.krivosheev@jetbrains.com>
Tue, 9 May 2017 12:34:29 +0000 (14:34 +0200)
committerVladimir Krivosheev <vladimir.krivosheev@jetbrains.com>
Tue, 9 May 2017 16:31:16 +0000 (18:31 +0200)
java/compiler/impl/src/com/intellij/compiler/progress/CompilerTask.java
java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java
platform/lang-impl/src/com/intellij/execution/ui/RunContentManagerImpl.java
platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java
platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java
platform/projectModel-api/src/com/intellij/openapi/project/ProjectManager.java
platform/projectModel-api/src/com/intellij/openapi/project/ProjectManagerListener.java
platform/projectModel-api/src/com/intellij/openapi/project/VetoableProjectManagerListener.java [new file with mode: 0644]
plugins/ant/src/com/intellij/lang/ant/config/execution/AntBuildMessageView.java

index 006f4740858b5bed6d2af0ec252f271fa24c4d37..4a5afe1866082f3926e178b7a2dcbe7dacbb0aeb 100644 (file)
@@ -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) {
index 41887a8f41cd76e2f5905c247db48c81dfa0a7ae..aa5972b140609a8eac83e1de74c86dafe7c541b2 100644 (file)
@@ -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
index 4666b4099b9bc7638f6401bf40b5f4243303a1d9..ad7aabd48f9fca953dddc1fb6ba354d99d059df5 100644 (file)
@@ -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;
index 38484ff20e08f47a1df8b1d04750e030f70c003d..d9cfc409b4887d4835c7df3db589d554444c061d 100644 (file)
@@ -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 {
index 0d0192a8d3a40daa8cc1949622dd83bbdc94b089..5ff052769090866a40d6026f16fe7c7ca86572d0 100644 (file)
@@ -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();
@@ -666,6 +680,11 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable {
   }
 
   @Override
+  public void addProjectManagerListener(@NotNull VetoableProjectManagerListener listener) {
+    myListeners.add(listener);
+  }
+
+  @Override
   public void addProjectManagerListener(@NotNull final ProjectManagerListener listener, @NotNull Disposable parentDisposable) {
     addProjectManagerListener(listener);
     Disposer.register(parentDisposable, () -> removeProjectManagerListener(listener));
index dbfebe78020d6ae271c38e391abe6bc27ec76f0c..56a4db06e71fd4998a9c1ebc9b15b376aaa14668 100644 (file)
@@ -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}
    */
index 62f31844aceb235176f40eeae33ebb2a579fb086..3f048b03c9fa6e08f916875eee899302c8b276fa 100644 (file)
@@ -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) {
+  }
 }
diff --git a/platform/projectModel-api/src/com/intellij/openapi/project/VetoableProjectManagerListener.java b/platform/projectModel-api/src/com/intellij/openapi/project/VetoableProjectManagerListener.java
new file mode 100644 (file)
index 0000000..29162bc
--- /dev/null
@@ -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);
+}
index 4339ad41cf87265396adb7cdc67283b1a16d4783..37b7b91445b86292ef8674d25a6688aa40f38b71 100644 (file)
@@ -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();
   }