All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.intellij.openapi.ui.playback.util.WindowSystemPlaybackCall Maven / Gradle / Ivy

/*
 * Copyright 2000-2011 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.ui.playback.util;

import com.intellij.ide.UiActivityMonitor;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Queryable;
import com.intellij.openapi.ui.playback.PlaybackContext;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.AsyncResult;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.SimpleTimer;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.openapi.wm.IdeFrame;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.util.Consumer;
import com.intellij.util.ui.UIUtil;

import javax.swing.*;
import java.awt.*;
import java.awt.event.AWTEventListener;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.awt.event.WindowEvent;
import java.util.*;

public class WindowSystemPlaybackCall {

  public static AsyncResult printFocus(final PlaybackContext context) {
    final AsyncResult result = new AsyncResult();

    getUiReady(context).doWhenProcessed(new Runnable() {
      @Override
      public void run() {
        final LinkedHashMap focusInfo = getFocusInfo();
        if (focusInfo == null) {
          result.setRejected("No component focused");
          return;
        }

        StringBuffer text = new StringBuffer();
        for (Iterator iterator = focusInfo.keySet().iterator(); iterator.hasNext(); ) {
          String key = iterator.next();
          text.append(key + "=" + focusInfo.get(key));
          if (iterator.hasNext()) {
            text.append("|");
          }
        }
        result.setDone(text.toString());
      }
    });

    return result;
  }


  public static AsyncResult waitForDialog(final PlaybackContext context, final String title) {
    final AsyncResult result = new AsyncResult();

    final Ref listener = new Ref();
    listener.set(new AWTEventListener() {
      @Override
      public void eventDispatched(AWTEvent event) {
        if (event.getID() == WindowEvent.WINDOW_ACTIVATED) {
          final Window wnd = ((WindowEvent)event).getWindow();
          if (wnd instanceof JDialog) {
            if (title.equals(((JDialog)wnd).getTitle())) {
              Toolkit.getDefaultToolkit().removeAWTEventListener(listener.get());
              SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                  getUiReady(context).notify(result);
                }
              });
            }
          }
        }
      }
    });

    Toolkit.getDefaultToolkit().addAWTEventListener(listener.get(), WindowEvent.WINDOW_EVENT_MASK);

    SimpleTimer.getInstance().setUp(new Runnable() {
      @Override
      public void run() {
        Toolkit.getDefaultToolkit().removeAWTEventListener(listener.get());
        if (!result.isProcessed()) {
          result.setRejected("Timed out waiting for window: " + title);
        }
      }
    }, Registry.intValue("actionSystem.commandProcessingTimeout"));

    return result;
  }

  public static AsyncResult checkFocus(final PlaybackContext context, String expected) {
    final AsyncResult result = new AsyncResult();
    final Map expectedMap = new LinkedHashMap();

    if (expected.length() > 0) {
      final String[] keyValue = expected.split("\\|");
      for (String each : keyValue) {
        final String[] eachPair = each.split("=");
        if (eachPair.length != 2) {
          result.setRejected("Syntax error, must be |-separated pairs key=value");
          return result;
        }

        expectedMap.put(eachPair[0], eachPair[1]);
      }
    }

    getUiReady(context).doWhenDone(new Runnable() {
      @Override
      public void run() {
        try {
          doAssert(expectedMap, result, context);
        }
        catch (AssertionError error) {
          result.setRejected("Assertion failed: " + error.getMessage());
        }
      }
    });

    return result;
  }

  public static AsyncResult waitForToolWindow(final PlaybackContext context, final String id) {
    final AsyncResult result = new AsyncResult();

    findProject().doWhenDone(new Consumer() {
      @Override
      public void consume(Project project) {
        ToolWindow toolWindow = ToolWindowManager.getInstance(project).getToolWindow(id);
        if (toolWindow == null) {
          result.setRejected("Cannot find tool window with id: " + id);
          return;
        }

        toolWindow.getReady(context).doWhenDone(result.createSetDoneRunnable()).doWhenRejected(new Runnable() {
          @Override
          public void run() {
            result.setRejected("Cannot activate tool window with id:" + id);
          }
        });
      }
    }).doWhenRejected(new Runnable() {
      @Override
      public void run() {
        result.setRejected("Cannot retrieve open project");
      }
    });

    return result;
  }

  public static AsyncResult findProject() {
    final AsyncResult project = new AsyncResult();
    final IdeFocusManager fm = IdeFocusManager.getGlobalInstance();
    fm.doWhenFocusSettlesDown(new Runnable() {
      @Override
      public void run() {
        Component parent = UIUtil.findUltimateParent(fm.getFocusOwner());
        if (parent instanceof IdeFrame) {
          IdeFrame frame = (IdeFrame)parent;
          if (frame.getProject() != null) {
            project.setDone(frame.getProject());
            return;
          }
        }

        project.setRejected();
      }
    });

    return project;
  }

  public static AsyncResult contextMenu(final PlaybackContext context, final String path) {
    final AsyncResult result = new AsyncResult();

    final IdeFocusManager fm = IdeFocusManager.getGlobalInstance();
    fm.doWhenFocusSettlesDown(new Runnable() {
      @Override
      public void run() {
        Component owner = fm.getFocusOwner();
        if (owner == null) {
          result.setRejected("No component focused");
          return;
        }

        ActionManager am = ActionManager.getInstance();
        AnAction showPopupMenu = am.getAction("ShowPopupMenu");
        if (showPopupMenu == null) {
          result.setRejected("Cannot find action: ShowPopupMenu");
          return;
        }

        am.tryToExecute(showPopupMenu, new MouseEvent(owner, MouseEvent.MOUSE_PRESSED, System.currentTimeMillis(), 0, 0, 0, 1, true), null,
                        null, false).doWhenDone(
          new Runnable() {
            @Override
            public void run() {
              SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                  MenuElement[] selectedPath = MenuSelectionManager.defaultManager().getSelectedPath();
                  if (selectedPath.length == 0) {
                    result.setRejected("Failed to find active popup menu");
                    return;
                  }
                  selectNext(context, path.split("\\|"), 0, selectedPath[0].getSubElements(), result);
                }
              });
            }
          }).doWhenRejected(new Runnable() {
          @Override
          public void run() {
            result.setRejected("Cannot invoke popup menu from the ShowPopupMenu action, action call rejected");
          }
        });
      }
    });

    return result;
  }

  private static void selectNext(final PlaybackContext context, final String[] toSelect, final int toSelectIndex, MenuElement[] menuElements, final AsyncResult result) {
    if (menuElements == null || menuElements.length == 0) {
      result.setDone();
    }

    if (toSelectIndex > toSelect.length - 1) {
      result.setDone();
      return;
    }

    String target = toSelect[toSelectIndex];
    for (final MenuElement each : menuElements) {
      if (each.getComponent() instanceof AbstractButton) {
        final AbstractButton eachButton = (AbstractButton)each.getComponent();
        if (eachButton.getText() != null && eachButton.getText().startsWith(target)) {
          activateItem(context, each).doWhenDone(new Consumer() {
            @Override
            public void consume(MenuElement[] menuElements) {
              selectNext(context, toSelect, toSelectIndex + 1, menuElements, result);
            }
          }).doWhenRejected(new Runnable() {
            @Override
            public void run() {
              result.setRejected("Cannot activate menu element: " + eachButton.getText());
              return;
            }
          });
          return;
        }
      }
      else {
        result.setRejected("Unknown class for context menu item: " + each.getComponent());
        return;
      }
    }

    result.setRejected("Failed to find menu item: " + target);
  }

  private static AsyncResult activateItem(final PlaybackContext context, final MenuElement element) {
    final AsyncResult result = new AsyncResult();
    final AbstractButton c = (AbstractButton)element.getComponent();

    final Runnable pressRunnable = new Runnable() {
      @Override
      public void run() {
        Robot robot = context.getRobot();
        Point location = c.getLocationOnScreen();
        Dimension size = c.getSize();
        Point point = new Point(location.x + size.width / 2, location.y + size.height / 2);
        robot.mouseMove(point.x, point.y);
        robot.delay(90);
        robot.mousePress(InputEvent.BUTTON1_MASK);
        robot.delay(90);
        robot.mouseRelease(InputEvent.BUTTON1_MASK);
        robot.delay(90);
        context.flushAwtAndRunInEdt(new Runnable() {
          @Override
          public void run() {

            context.flushAwtAndRunInEdt(new Runnable() {
              @Override
              public void run() {
                MenuElement[] subElements = element.getSubElements();
                if (subElements == null || subElements.length == 0) {
                  result.setDone();
                }
                else {
                  MenuElement[] menuElements = subElements[0].getSubElements();
                  result.setDone(menuElements);
                }
              }
            });
          }
        });
      }
    };

    if (c.isShowing()) {
      context.runPooledThread(pressRunnable);
    } else {
      context.delayAndRunInEdt(new Runnable() {
        @Override
        public void run() {
          if (c.isShowing()) {
            context.runPooledThread(pressRunnable);
          } else {
            result.setRejected();
          }
        }
      }, 1000);
    }

    return result;
  }

  public static ActionCallback getUiReady(final PlaybackContext context) {
    final ActionCallback result = new ActionCallback();
    context.flushAwtAndRunInEdt(new Runnable() {
      @Override
      public void run() {
        UiActivityMonitor.getInstance().getBusy().getReady(context).notify(result);
      }
    });
    return result;
  }

  private static void doAssert(Map expected, AsyncResult result, PlaybackContext context) throws AssertionError {
    final LinkedHashMap actual = getFocusInfo();

    if (actual == null) {
      result.setRejected("No component focused");
      return;
    }

    Set testedKeys = new LinkedHashSet();
    for (String eachKey : expected.keySet()) {
      testedKeys.add(eachKey);

      final String actualValue = actual.get(eachKey);
      final String expectedValue = expected.get(eachKey);

      if (!expectedValue.equals(actualValue)) {
        result.setRejected(eachKey + " expected: " + expectedValue + " but was: " + actualValue);
        return;
      }
    }

    Map untested = new HashMap();
    for (String eachKey : actual.keySet()) {
      if (testedKeys.contains(eachKey)) continue;
      untested.put(eachKey, actual.get(eachKey));
    }

    StringBuffer untestedText = new StringBuffer();
    for (String each : untested.keySet()) {
      if (untestedText.length() > 0) {
        untestedText.append(",");
      }
      untestedText.append(each).append("=").append(untested.get(each));
    }

    result.setDone();

    if (untestedText.length() > 0) {
      context.message("Untested focus info: " + untestedText.toString(), context.getCurrentLine());
    }
  }

  private static LinkedHashMap getFocusInfo() {
    final Component owner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();

    if (owner == null) {
      return null;
    }

    Component eachParent = owner;
    final LinkedHashMap actual = new LinkedHashMap();
    while (eachParent != null) {
      if (eachParent instanceof Queryable) {
        ((Queryable)eachParent).putInfo(actual);
      }

      eachParent = eachParent.getParent();
    }
    return actual;
  }

  public static AsyncResult flushUi(PlaybackContext context) {
    AsyncResult result = new AsyncResult();
    getUiReady(context).notify(result);
    return result;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy