diff --git a/max_opened_projects/src/main/java/org/intellij/sdk/maxOpenPrj/ProjectCountingService.java b/max_opened_projects/src/main/java/org/intellij/sdk/maxOpenPrj/ProjectCountingService.java
index 4af162d2a..61a83f084 100644
--- a/max_opened_projects/src/main/java/org/intellij/sdk/maxOpenPrj/ProjectCountingService.java
+++ b/max_opened_projects/src/main/java/org/intellij/sdk/maxOpenPrj/ProjectCountingService.java
@@ -2,9 +2,6 @@
package org.intellij.sdk.maxOpenPrj;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.project.ProjectManager;
-
/**
* Application service implementation to keep a running count of
* how many projects are open at a given time.
diff --git a/max_opened_projects/src/main/java/org/intellij/sdk/maxOpenPrj/ProjectOpenCloseListener.java b/max_opened_projects/src/main/java/org/intellij/sdk/maxOpenPrj/ProjectOpenCloseListener.java
index 0f37660a4..5e3dad8b5 100644
--- a/max_opened_projects/src/main/java/org/intellij/sdk/maxOpenPrj/ProjectOpenCloseListener.java
+++ b/max_opened_projects/src/main/java/org/intellij/sdk/maxOpenPrj/ProjectOpenCloseListener.java
@@ -2,25 +2,20 @@
package org.intellij.sdk.maxOpenPrj;
-import com.intellij.openapi.Disposable;
+import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.project.ProjectManagerListener;
-import com.intellij.openapi.ui.popup.Balloon;
-import com.intellij.openapi.ui.popup.JBPopupFactory;
-import com.intellij.openapi.util.Disposer;
-import com.intellij.openapi.wm.WindowManager;
-import com.intellij.util.ui.UIUtil;
+import org.intellij.sdk.utils.SdkBalloonHelper;
import org.jetbrains.annotations.NotNull;
-import javax.swing.*;
-
/**
* Listener to detect project open and close.
- * Depends on the org.intellij.sdk.maxOpenPrj.ProjectCountingService
+ * Depends on org.intellij.sdk.maxOpenPrj.ProjectCountingService
+ * Depends on org.intellij.sdk.utils.SdkBalloonHelper
*/
-public class ProjectOpenCloseListener implements ProjectManagerListener, Disposable {
+public class ProjectOpenCloseListener implements ProjectManagerListener {
+ private static final String MAX_OPEN_PROJ_DISCLAIM = "This is an IntelliJ Platform SDK demo.
";
/**
* Invoked on project open.
@@ -29,15 +24,19 @@ public class ProjectOpenCloseListener implements ProjectManagerListener, Disposa
*/
@Override
public void projectOpened(@NotNull Project project) {
+ // Ensure this isn't part of testing
+ if (ApplicationManager.getApplication().isUnitTestMode()) return;
// Get the counting service
ProjectCountingService projectCountingService = ServiceManager.getService(ProjectCountingService.class);
// Increment the project count
projectCountingService.incrProjectCount();
// See if the total # of projects violates the limit.
if (projectCountingService.projectLimitExceeded()) {
- System.out.println("\n\nOpen limit transition called for: " + project.toString());
// Transitioned to outside the limit
- showBalloon("projectOpened", project, "Opening Project \"" + project.getName() + "\"", "The number of open projects exceeds the SDK plugin max_opened_projects limit.");
+ String title = String.format("Opening Project \"%s\"", project.getName());
+ String message = MAX_OPEN_PROJ_DISCLAIM + "The number of open projects exceeds the SDK plugin max_opened_projects limit.";
+ SdkBalloonHelper balloonHelper = SdkBalloonHelper.getSdkBalloonHelper();
+ balloonHelper.showBalloon(project, title, message);
}
}
@@ -48,6 +47,8 @@ public class ProjectOpenCloseListener implements ProjectManagerListener, Disposa
*/
@Override
public void projectClosed(@NotNull Project project) {
+ // Ensure this isn't part of testing
+ if (ApplicationManager.getApplication().isUnitTestMode()) return;
// Get the counting service
ProjectCountingService projectCountingService = ServiceManager.getService(ProjectCountingService.class);
// Was the count above the limit?
@@ -56,64 +57,12 @@ public class ProjectOpenCloseListener implements ProjectManagerListener, Disposa
projectCountingService.decrProjectCount();
// See if the total # of projects no longer violates the limit.
if (!projectCountingService.projectLimitExceeded() && previouslyOverCount) {
- System.out.println("\n\nCLOSED limit transition called for: " + project.toString());
// Transitioned to within the limit.
- showBalloon("projectClosed", project, "\"" + project.getName() + "\" Has Been Closed", "The number of open projects is below the SDK plugin max_opened_projects limit.");
+ String title = String.format("\"%s\" Has Been Closed", project.getName());
+ String message = MAX_OPEN_PROJ_DISCLAIM + "The number of open projects is below the SDK plugin max_opened_projects limit.";
+ SdkBalloonHelper balloonHelper = SdkBalloonHelper.getSdkBalloonHelper();
+ balloonHelper.showBalloon(project, title, message);
}
}
- /*
- CLOSED limit transition called for: Project (name=testKotlin, containerState=DISPOSE_IN_PROGRESS, componentStore=/Users/jhake/Documents/source/scratch/testKotlin)
- From: projectClosed - allProjects[2] = Project (name=conditional_operator_test, containerState=ACTIVE, componentStore=/Users/jhake/Documents/source/scratch/conditional_operator_test) , Open = true
- From: projectClosed - allProjects[1] = Project (name=foobar, containerState=ACTIVE, componentStore=/Users/jhake/Documents/source/scratch/foobar) , Open = true
- From: projectClosed - allProjects[0] = Project (name=SimpleTest, containerState=ACTIVE, componentStore=/Users/jhake/Documents/source/scratch/SimpleTest) , Open = true
- */
- private void showBalloon(String caller, Project project, String title, String message) {
- // Ensure the project is open. If not, use the next youngest one in the project list
- ProjectManager projectManager = ProjectManager.getInstance();
- Project[] allProjects = projectManager.getOpenProjects();
- Project validProject = allProjects[allProjects.length - 1];
- if (validProject == null) {
- return;
- }
- System.out.println(String.format("From: %s - validProject = %s", caller, validProject.toString()));
-
- // Verify the place to put the balloon
- final WindowManager manager = WindowManager.getInstance();
- final JFrame frame = manager.getFrame(validProject);
- JRootPane pane = frame.getRootPane();
- if (pane == null) {
- return;
- }
-
- // Construct and show the balloon
- JLabel component = new JLabel(message);
- final Balloon balloon = JBPopupFactory.getInstance().createBalloonBuilder(component)
- .setShadow(true)
- .setAnimationCycle(200) // Was 0
- .setHideOnClickOutside(true)
- .setHideOnAction(false)
- .setFillColor(UIUtil.getControlColor())
- .setTitle(title) // Added
- .setFadeoutTime(5000) // Added
- .createBalloon();
- Disposer.register(validProject, balloon);
- balloon.showInCenterOf(pane);
-
-// final Balloon.Position position = QuickEditAction.getBalloonPosition(editor);
-// RelativePoint point = JBPopupFactory.getInstance().guessBestPopupLocation(editor);
-// if (position == Balloon.Position.above) {
-// final Point p = point.getPoint();
-// point = new RelativePoint(point.getComponent(), new Point(p.x, p.y - editor.getLineHeight()));
-// }
-
- }
-
- /**
- * Usually not invoked directly, see Disposable class javadoc.
- */
- @Override
- public void dispose() {
- // noop
- }
}
diff --git a/max_opened_projects/src/main/java/org/intellij/sdk/utils/SdkBalloonHelper.java b/max_opened_projects/src/main/java/org/intellij/sdk/utils/SdkBalloonHelper.java
new file mode 100644
index 000000000..1fdb423c0
--- /dev/null
+++ b/max_opened_projects/src/main/java/org/intellij/sdk/utils/SdkBalloonHelper.java
@@ -0,0 +1,104 @@
+// Copyright 2000-2020 JetBrains s.r.o. and other contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+
+package org.intellij.sdk.utils;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.project.ProjectManager;
+import com.intellij.openapi.ui.popup.Balloon;
+import com.intellij.openapi.ui.popup.JBPopupFactory;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.wm.WindowManager;
+import com.intellij.util.ui.UIUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+
+/**
+ * This is just a utility class to help communicate the state of this plugin using Popups
+ *
+ * @see Popup documentation
+ */
+public class SdkBalloonHelper {
+
+ public static SdkBalloonHelper getSdkBalloonHelper() {
+ return new SdkBalloonHelper();
+ }
+
+ /**
+ * This method constructs a Balloon-type popup and displays it in the middle of a Project window.
+ * Adds the Balloon to the Project's Disposer
+ *
+ * @param project The Project to host the Balloon.
+ * @param title A short description of what the Balloon conveys
+ * @param message Detailed information
+ */
+ public void showBalloon(@Nullable Project project, @NotNull String title, @NotNull String message) {
+ // Ensure the project is open. If not, use the next youngest one to show the balloon
+ Project displayProject = findValidProject(project);
+ if (displayProject == null) return;
+
+ // Verify the place to put the balloon
+ JRootPane pane = getProjectRootPane(displayProject);
+ if (pane == null) return;
+
+ // Construct the balloon
+ JLabel component = new JLabel("" + message + "");
+ final Balloon balloon = JBPopupFactory.getInstance().createBalloonBuilder(component)
+ .setShadow(true)
+ .setHideOnClickOutside(true)
+ .setHideOnAction(false)
+ .setFillColor(UIUtil.getControlColor())
+ .setTitle(title)
+ .setFadeoutTime(6000)
+ .createBalloon();
+
+ // Register it for disposal with the project that will display it
+ Disposer.register(displayProject, balloon);
+
+ // Show the balloon in the middle of the project's window - it will disappear per the animation
+ balloon.showInCenterOf(pane);
+ }
+
+ /**
+ * This function verifies that the provided Project is still open.
+ * If the Project is not open (closed, or in some state of disposal,)
+ * the function tries to find the next most-recently opened Project.
+ *
+ * @param dodgyProject The Project to be verified as open
+ * @return dodgyProject if it is verified as open,
+ * Or the last Project listed in ProjectManager's list of open Projects.
+ * Or null if no other Projects are open. (Edge case when IDE is closing.)
+ */
+ @Nullable
+ private Project findValidProject(@Nullable Project dodgyProject) {
+ Project validProject = dodgyProject;
+ if ((validProject == null) || !validProject.isOpen()) {
+ // Find the next most-recently opened Project that is still open.
+ ProjectManager projectManager = ProjectManager.getInstance();
+ Project[] allProjects = projectManager.getOpenProjects();
+ validProject = allProjects.length > 0 ? allProjects[allProjects.length - 1] : null;
+ }
+ return validProject;
+ }
+
+ /**
+ * This function gets the JRootPane for an open Project
+ *
+ * @param project The open Project
+ * @return A valid JRootPane for the Project
+ * Otherwise null
+ */
+ @Nullable
+ private JRootPane getProjectRootPane(@Nullable Project project) {
+ JRootPane projectPane = null;
+ if ((project != null) && project.isOpen()) {
+ // Get the frame for the project, then the JRootPane
+ final WindowManager manager = WindowManager.getInstance();
+ final JFrame frame = manager.getFrame(project);
+ projectPane = frame != null ? frame.getRootPane() : null;
+ }
+ return projectPane;
+ }
+
+}