diff --git a/java/compiler/impl/src/com/intellij/compiler/progress/CompilerTask.java b/java/compiler/impl/src/com/intellij/compiler/progress/CompilerTask.java index 006f4740858b..4a5afe186608 100644 --- a/java/compiler/impl/src/com/intellij/compiler/progress/CompilerTask.java +++ b/java/compiler/impl/src/com/intellij/compiler/progress/CompilerTask.java @@ -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) { diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java index 41887a8f41cd..aa5972b14060 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java @@ -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 diff --git a/platform/lang-impl/src/com/intellij/execution/ui/RunContentManagerImpl.java b/platform/lang-impl/src/com/intellij/execution/ui/RunContentManagerImpl.java index 4666b4099b9b..ad7aabd48f9f 100644 --- a/platform/lang-impl/src/com/intellij/execution/ui/RunContentManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/ui/RunContentManagerImpl.java @@ -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; diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java index 38484ff20e08..d9cfc409b488 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileDocumentManagerImpl.java @@ -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 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 { diff --git a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java index 0d0192a8d3a4..5ff052769090 100644 --- a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java @@ -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); diff --git a/platform/projectModel-api/src/com/intellij/openapi/project/ProjectManager.java b/platform/projectModel-api/src/com/intellij/openapi/project/ProjectManager.java index dbfebe78020d..56a4db06e71f 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/project/ProjectManager.java +++ b/platform/projectModel-api/src/com/intellij/openapi/project/ProjectManager.java @@ -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} */ diff --git a/platform/projectModel-api/src/com/intellij/openapi/project/ProjectManagerListener.java b/platform/projectModel-api/src/com/intellij/openapi/project/ProjectManagerListener.java index 62f31844aceb..3f048b03c9fa 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/project/ProjectManagerListener.java +++ b/platform/projectModel-api/src/com/intellij/openapi/project/ProjectManagerListener.java @@ -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 index 000000000000..29162bc39dc8 --- /dev/null +++ b/platform/projectModel-api/src/com/intellij/openapi/project/VetoableProjectManagerListener.java @@ -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); +} diff --git a/plugins/ant/src/com/intellij/lang/ant/config/execution/AntBuildMessageView.java b/plugins/ant/src/com/intellij/lang/ant/config/execution/AntBuildMessageView.java index 4339ad41cf87..37b7b91445b8 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/execution/AntBuildMessageView.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/execution/AntBuildMessageView.java @@ -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(); }