IDEA-129512 Indicate in the user interface run and debug process appcode/140.2174 appcode/140.2183 clion/140.2173 clion/140.2176 dbe/140.2179 phpstorm/140.2178 pycharm/140.2181 rubymine/140.2177 webstorm/140.2180 webstorm/32
authorVassiliy.Kudryashov <Vassiliy.Kudryashov@jetbrains.com>
Tue, 3 Feb 2015 22:34:00 +0000 (01:34 +0300)
committerVassiliy.Kudryashov <Vassiliy.Kudryashov@jetbrains.com>
Tue, 3 Feb 2015 22:34:00 +0000 (01:34 +0300)
platform/lang-impl/src/com/intellij/execution/ui/RunContentManagerImpl.java
platform/platform-api/src/com/intellij/util/ui/IconAnimator.java [new file with mode: 0644]
platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowImpl.java

index 5062fd35143e9d472ea5f617e5cc2acb241c6d50..62b89a22035279c9752e9fa09efbbf5687cc1cbf 100644 (file)
@@ -52,6 +52,7 @@ import com.intellij.ui.docking.DockManager;
 import com.intellij.util.SmartList;
 import com.intellij.util.concurrency.Semaphore;
 import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.ui.IconAnimator;
 import gnu.trove.THashMap;
 import gnu.trove.THashSet;
 import org.jetbrains.annotations.NotNull;
@@ -70,6 +71,7 @@ public class RunContentManagerImpl implements RunContentManager, Disposable {
 
   private final Map<RunContentListener, Disposable> myListeners = new THashMap<RunContentListener, Disposable>();
   private final LinkedList<String> myToolwindowIdZBuffer = new LinkedList<String>();
+  private final Map<String, IconAnimator> myIconAnimators = new THashMap<String, IconAnimator>();
 
   public RunContentManagerImpl(@NotNull Project project, @NotNull DockManager dockManager) {
     myProject = project;
@@ -128,7 +130,7 @@ public class RunContentManagerImpl implements RunContentManager, Disposable {
       return;
     }
 
-    ToolWindow toolWindow = toolWindowManager.registerToolWindow(toolWindowId, true, ToolWindowAnchor.BOTTOM, this, true);
+    final ToolWindow toolWindow = toolWindowManager.registerToolWindow(toolWindowId, true, ToolWindowAnchor.BOTTOM, this, true);
     final ContentManager contentManager = toolWindow.getContentManager();
     contentManager.addDataProvider(new DataProvider() {
       private int myInsideGetData = 0;
@@ -160,11 +162,21 @@ public class RunContentManagerImpl implements RunContentManager, Disposable {
       }
     });
     myToolwindowIdToContentManagerMap.put(toolWindowId, contentManager);
+    final IconAnimator iconAnimator = new IconAnimator(contentManager, executor.getToolWindowIcon(), new IconAnimator.PaintCallback() {
+      @Override
+      public void paintNow(Icon icon) {
+        if (toolWindow.isDisposed()) return;
+        toolWindow.setIcon(null);
+        toolWindow.setIcon(icon);
+      }
+    });
+    myIconAnimators.put(toolWindowId, iconAnimator);
     Disposer.register(contentManager, new Disposable() {
       @Override
       public void dispose() {
         myToolwindowIdToContentManagerMap.remove(toolWindowId).removeAllContents(true);
         myToolwindowIdZBuffer.remove(toolWindowId);
+        myIconAnimators.remove(toolWindowId);
       }
     });
     myToolwindowIdZBuffer.addLast(toolWindowId);
@@ -257,7 +269,7 @@ public class RunContentManagerImpl implements RunContentManager, Disposable {
     showRunContent(executor, descriptor, descriptor.getExecutionId());
   }
 
-  public void showRunContent(@NotNull final Executor executor, @NotNull final RunContentDescriptor descriptor, long executionId) {
+  public void showRunContent(@NotNull final Executor executor, @NotNull final RunContentDescriptor descriptor, final long executionId) {
     if (ApplicationManager.getApplication().isUnitTestMode()) {
       return;
     }
@@ -286,13 +298,10 @@ public class RunContentManagerImpl implements RunContentManager, Disposable {
       final ProcessAdapter processAdapter = new ProcessAdapter() {
         @Override
         public void startNotified(final ProcessEvent event) {
-          ApplicationManager.getApplication().invokeLater(new Runnable() {
-            @Override
-            public void run() {
-              final Icon icon = descriptor.getIcon();
-              content.setIcon(icon == null ? executor.getToolWindowIcon() : icon);
-            }
-          });
+          IconAnimator animator = myIconAnimators.get(executor.getToolWindowId());
+          if (animator != null) {
+            animator.setActive(true);
+          }
         }
 
         @Override
@@ -301,6 +310,25 @@ public class RunContentManagerImpl implements RunContentManager, Disposable {
             @Override
             public void run() {
               final Icon icon = descriptor.getIcon();
+
+              boolean alive = false;
+              String toolWindowId = executor.getToolWindowId();
+              ContentManager manager = myToolwindowIdToContentManagerMap.get(toolWindowId);
+              for (Content content : manager.getContents()) {
+                RunContentDescriptor descriptor = getRunContentDescriptorByContent(content);
+                if (descriptor != null) {
+                  ProcessHandler handler = descriptor.getProcessHandler();
+                  if (handler != null && !handler.isProcessTerminated()) {
+                    alive = true;
+                    break;
+                  }
+                }
+              }
+
+              IconAnimator animator = myIconAnimators.get(toolWindowId);
+              if (animator != null) {
+                animator.setActive(alive);
+              }
               content.setIcon(icon == null ? executor.getDisabledIcon() : IconLoader.getTransparentIcon(icon));
             }
           });
diff --git a/platform/platform-api/src/com/intellij/util/ui/IconAnimator.java b/platform/platform-api/src/com/intellij/util/ui/IconAnimator.java
new file mode 100644 (file)
index 0000000..17681a1
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2000-2015 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.util.ui;
+
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.util.Disposer;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import java.awt.*;
+
+public class IconAnimator extends Animator implements Icon {
+  private final Icon myBase;
+  @NotNull private final PaintCallback myCallback;
+  private final Color[] myAlphas;
+  private int myFrame;
+  private boolean myActive;
+
+  public IconAnimator(@NotNull Disposable parent, @NotNull Icon base, @NotNull PaintCallback callback) {
+    super("IconAnimator{" + System.currentTimeMillis()+"}", base.getIconWidth(), 2000, true);
+    Disposer.register(parent, this);
+    myBase = base;
+    myCallback = callback;
+    myAlphas = initAlphas();
+  }
+
+  private Color[] initAlphas() {
+    Color[] colors = new Color[myBase.getIconWidth()];
+    for (int i = 0; i < colors.length; i++) {
+      double a = 2 * Math.PI * i / colors.length;
+      float v = (1 - (float)Math.sin(a)) / 2;
+      //noinspection UseJBColor
+      colors[i] = new Color(v, v, v, v * v * v / 16 + .05F);
+    }
+    return colors;
+  }
+
+  public void setActive(boolean active) {
+    if (myActive == active) return;
+
+    myActive = active;
+
+    if (isRunning() ^ myActive) {
+      if (myActive) {
+        resume();
+      } else {
+        suspend();
+      }
+      myCallback.paintNow(this);
+    }
+  }
+
+  @Override
+  public void paintNow(int frame, int totalFrames, int cycle) {
+    myFrame = frame;
+    myCallback.paintNow(this);
+  }
+
+  @Override
+  public void paintIcon(Component component, Graphics graphics, int x, int y) {
+    myBase.paintIcon(component, graphics, x, y);
+    if (!myActive) return;
+
+    for (int i = 0; i < myAlphas.length; i++) {
+      Color alpha = myAlphas[(i + myFrame) % myAlphas.length];
+      graphics.setColor(alpha);
+      graphics.drawRect(x + i, y, 1, getIconHeight());
+    }
+  }
+
+  @Override
+  public int getIconWidth() {
+    return myBase.getIconWidth();
+  }
+
+  @Override
+  public int getIconHeight() {
+    return myBase.getIconHeight();
+  }
+
+  public interface PaintCallback {
+    void paintNow(Icon icon);
+  }
+}
index e3ba657ef2925e85fa78c5a340bb52b97447cd4f..c96f21f256031b47ecdb01937ee2a9c2c4dd453e 100644 (file)
@@ -392,10 +392,10 @@ public final class ToolWindowImpl implements ToolWindowEx {
   public final void setIcon(final Icon icon) {
     ApplicationManager.getApplication().assertIsDispatchThread();
     final Icon oldIcon = getIcon();
-    if (oldIcon != icon && !(icon instanceof LayeredIcon) && (icon.getIconHeight() != JBUI.scale(13) || icon.getIconWidth() != JBUI.scale(13))) {
+    if (oldIcon != icon && icon != null && !(icon instanceof LayeredIcon) && (icon.getIconHeight() != JBUI.scale(13) || icon.getIconWidth() != JBUI.scale(13))) {
       LOG.warn("ToolWindow icons should be 13x13. Please fix ToolWindow (ID:  " + getId() + ") or icon " + icon);
     }
-    getSelectedContent().setIcon(icon);
+    //getSelectedContent().setIcon(icon);
     myIcon = icon;
     myChangeSupport.firePropertyChange(PROP_ICON, oldIcon, icon);
   }