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 41a175cbb869..2d43ae370fc6 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 @@ -99,7 +99,7 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable { messageBus.connect().subscribe(ProjectManager.TOPIC, new ProjectManagerListener() { @Override public void projectOpened(@NotNull Project project) { - for (ProjectManagerListener listener : ContainerUtil.concat(getListeners(project), myListeners)) { + for (ProjectManagerListener listener : getAllListeners(project)) { try { listener.projectOpened(project); } @@ -111,7 +111,7 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable { @Override public void projectClosed(Project project) { - for (ProjectManagerListener listener : ContainerUtil.concat(getListeners(project), myListeners)) { + for (ProjectManagerListener listener : getAllListeners(project)) { try { listener.projectClosed(project); } @@ -125,7 +125,7 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable { @Override public void projectClosing(Project project) { - for (ProjectManagerListener listener : ContainerUtil.concat(getListeners(project), myListeners)) { + for (ProjectManagerListener listener : getAllListeners(project)) { try { listener.projectClosing(project); } @@ -137,7 +137,7 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable { @Override public void projectClosingBeforeSave(@NotNull Project project) { - for (ProjectManagerListener listener : ContainerUtil.concat(getListeners(project), myListeners)) { + for (ProjectManagerListener listener : getAllListeners(project)) { try { listener.projectClosingBeforeSave(project); } @@ -697,6 +697,12 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable { LOG.assertTrue(removed); } + @Override + public void removeProjectManagerListener(@NotNull VetoableProjectManagerListener listener) { + boolean removed = myListeners.remove(listener); + LOG.assertTrue(removed); + } + @Override public void addProjectManagerListener(@NotNull Project project, @NotNull ProjectManagerListener listener) { List listeners = project.getUserData(LISTENERS_IN_PROJECT_KEY); @@ -737,7 +743,7 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable { LOG.debug("enter: canClose()"); } - for (ProjectManagerListener listener : ContainerUtil.concat(getListeners(project), myListeners)) { + for (ProjectManagerListener listener : getAllListeners(project)) { try { //noinspection deprecation boolean canClose = listener instanceof VetoableProjectManagerListener ? ((VetoableProjectManagerListener)listener).canClose(project) : listener.canCloseProject(project); @@ -754,6 +760,25 @@ public class ProjectManagerImpl extends ProjectManagerEx implements Disposable { return true; } + // both lists are thread-safe (LockFreeCopyOnWriteArrayList), but ContainerUtil.concat cannot handle situation when list size is changed during iteration + // so, we have to create list. + @NotNull + private List getAllListeners(@NotNull Project project) { + List projectLevelListeners = getListeners(project); + if (projectLevelListeners.isEmpty()) { + return myListeners; + } + else if (myListeners.isEmpty()) { + return projectLevelListeners; + } + + List result = new ArrayList<>(projectLevelListeners.size() + myListeners.size()); + // order is critically important due to backward compatibility - project level listeners must be first + result.addAll(projectLevelListeners); + result.addAll(myListeners); + return result; + } + private static boolean ensureCouldCloseIfUnableToSave(@NotNull Project project) { UnableToSaveProjectNotification[] notifications = NotificationsManager.getNotificationsManager().getNotificationsOfType(UnableToSaveProjectNotification.class, project); 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 56a4db06e71f..ac621ec8a935 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/project/ProjectManager.java +++ b/platform/projectModel-api/src/com/intellij/openapi/project/ProjectManager.java @@ -60,6 +60,8 @@ public abstract class ProjectManager { @Deprecated public abstract void removeProjectManagerListener(@NotNull ProjectManagerListener listener); + public abstract void removeProjectManagerListener(@NotNull VetoableProjectManagerListener listener); + /** * Adds listener to the specified project. *