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

org.netbeans.jellytools.actions.Action Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.netbeans.jellytools.actions;

import java.awt.Component;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.KeyStroke;
import javax.swing.tree.TreePath;

import org.netbeans.jellytools.JellyVersion;
import org.netbeans.jellytools.MainWindowOperator;
import org.netbeans.jellytools.nodes.Node;
import org.netbeans.jellytools.nodes.OutlineNode;
import org.netbeans.jemmy.EventTool;
import org.netbeans.jemmy.JemmyException;
import org.netbeans.jemmy.JemmyProperties;
import org.netbeans.jemmy.Timeouts;
import org.netbeans.jemmy.drivers.input.KeyRobotDriver;
import org.netbeans.jemmy.operators.ComponentOperator;
import org.netbeans.jemmy.operators.JPopupMenuOperator;
import org.netbeans.jemmy.operators.JTreeOperator.NoSuchPathException;
import org.netbeans.jemmy.operators.Operator;
import org.netbeans.jemmy.operators.Operator.ComponentVisualizer;
import org.netbeans.jemmy.operators.Operator.DefaultStringComparator;
import org.netbeans.jemmy.operators.Operator.StringComparator;
import org.netbeans.jemmy.util.EmptyVisualizer;
import org.openide.awt.Actions;
import org.openide.cookies.InstanceCookie;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.loaders.DataObject;
import org.openide.util.actions.SystemAction;

/**
 * Ancestor class for all blocking actions.

* It handles performing action through main menu (MENU_MODE), popup menu * (POPUP_MODE), IDE SystemAction API call (API_MODE) or through keyboard * shortcut (SHORTCUT_MODE). *

* Action can be performed in exact mode by calling performMenu(...), * performPopup(...), performAPI(...) or performShortcut(...). *

* If exact mode is not supported by the action it throws * UnsupportedOperationException. *

* Current implementation supports MENU_MODE when menuPath is defined, * POPUP_MODE when popupPath is defined, API_MODE when systemActionClass is * defined and SHORTCUT_MODE when shortcut is defined (see Action constructors). *

* Action also can be performed using runtime default mode by calling * perform(...). *

* When default mode is not support by the action other modes are tried till * supported mode found and action is performed. * *
Timeouts used:
* Action.WaitAfterShortcutTimeout - time to sleep between shortcuts in sequence * (default 0)
* * @author Adam Sotona * @author Jiri Skrivanek */ public class Action { /** * through menu action performing mode */ public static final int MENU_MODE = 0; /** * through popup menu action performing mode */ public static final int POPUP_MODE = 1; /** * through API action performing mode */ public static final int API_MODE = 2; /** * through shortcut action performing mode */ public static final int SHORTCUT_MODE = 3; /** * sleep time between nodes selection and action execution */ protected static final long SELECTION_WAIT_TIME = 300; /** * sleep time after action execution */ protected static final long AFTER_ACTION_WAIT_TIME = 0; /** * sleep time between sequence of shortcuts */ protected static final long WAIT_AFTER_SHORTCUT_TIMEOUT = 0; private static final int sequence[][] = {{MENU_MODE, POPUP_MODE, SHORTCUT_MODE, API_MODE}, {POPUP_MODE, MENU_MODE, SHORTCUT_MODE, API_MODE}, {API_MODE, POPUP_MODE, MENU_MODE, SHORTCUT_MODE}, {SHORTCUT_MODE, POPUP_MODE, MENU_MODE, API_MODE}}; /** * menu path of current action or null when MENU_MODE is not supported */ protected String menuPath; /** * popup menu path of current action or null when POPUP_MODE is not * supported */ protected String popupPath; /** * SystemAction class of current action or null when API_MODE is not * supported */ protected Class systemActionClass; /** * Path to action instance FileObject in layer or null when API_MODE is not * supported or systemActionClass is used. */ protected String layerInstancePath; /** * Array of key strokes or null when SHORTCUT_MODE is not supported. */ protected KeyStroke[] keystrokes; /** * Comparator used as default for all Action instances. It is set in static * clause. */ private static StringComparator defaultComparator; /** * Comparator used for this action instance. */ private StringComparator comparator; /** * creates new Action instance without API_MODE and SHORTCUT_MODE support * * @param menuPath action path in main menu (use null value if menu mode is * not supported) * @param popupPath action path in popup menu (use null value if popup mode * shell is not supported) */ public Action(String menuPath, String popupPath) { this(menuPath, popupPath, null, (KeyStroke[]) null); } /** * creates new Action instance without SHORTCUT_MODE support * * @param menuPath action path in main menu (use null value if menu mode is * not supported) * @param popupPath action path in popup menu (use null value if popup mode * is not supported) * @param systemActionClass String class name of SystemAction (use null * value if API mode is not supported) */ public Action(String menuPath, String popupPath, String systemActionClass) { this(menuPath, popupPath, systemActionClass, (KeyStroke[]) null); } /** * creates new Action instance without API_MODE support * * @param shortcuts array of Shortcut instances (use null value if shorcut * mode is not supported) * @param menuPath action path in main menu (use null value if menu mode is * not supported) * @param popupPath action path in popup menu (use null value if popup mode * shell is not supported) * @deprecated Use * {@link Action#Action(String menuPath, String popupPath, KeyStroke[] keystrokes)} * instead. */ @Deprecated public Action(String menuPath, String popupPath, Shortcut[] shortcuts) { this(menuPath, popupPath, null, shortcuts); } /** * creates new Action instance without API_MODE support * * @param shortcut Shortcut (use null value if menu mode is not supported) * @param menuPath action path in main menu (use null value if menu mode is * not supported) * @param popupPath action path in popup menu (use null value if popup mode * shell is not supported) * @deprecated Use * {@link Action#Action(String menuPath, String popupPath, KeyStroke keystroke)} * instead. */ @Deprecated public Action(String menuPath, String popupPath, Shortcut shortcut) { this(menuPath, popupPath, null, new Shortcut[]{shortcut}); } /** * creates new Action instance * * @param shortcuts array of Shortcut instances (use null value if shortcut * mode is not supported) * @param menuPath action path in main menu (use null value if menu mode is * not supported) * @param popupPath action path in popup menu (use null value if popup mode * is not supported) * @param systemActionClass String class name of SystemAction (use null * value if API mode is not supported) * @deprecated Use * {@link Action#Action(String menuPath, String popupPath, String systemActionClass, KeyStroke[] keystrokes)} * instead. */ @Deprecated public Action(String menuPath, String popupPath, String systemActionClass, Shortcut[] shortcuts) { this(menuPath, popupPath, systemActionClass, convertShortcuts(shortcuts)); } private static KeyStroke[] convertShortcuts(Shortcut[] shortcuts) { KeyStroke[] keystrokes = null; if (shortcuts != null) { keystrokes = new KeyStroke[shortcuts.length]; for (int i = 0; i < shortcuts.length; i++) { keystrokes[i] = KeyStroke.getKeyStroke(shortcuts[i].getKeyCode(), shortcuts[i].getKeyModifiers()); } } return keystrokes; } /** * creates new Action instance * * @param shortcut Shortcut String (use null value if menu mode is not * supported) * @param menuPath action path in main menu (use null value if menu mode is * not supported) * @param popupPath action path in popup menu (use null value if popup mode * is not supported) * @param systemActionClass String class name of SystemAction (use null * value if API mode is not supported) * @deprecated Use * {@link Action#Action(String menuPath, String popupPath, String systemActionClass, KeyStroke keystroke)} * instead. */ @Deprecated public Action(String menuPath, String popupPath, String systemActionClass, Shortcut shortcut) { this(menuPath, popupPath, systemActionClass, new Shortcut[]{shortcut}); } /** * Creates new Action instance without API_MODE support. * * @param keystroke KeyStroke instance (use null value if shorcut mode is * not supported) * @param menuPath action path in main menu (use null value if menu mode is * not supported) * @param popupPath action path in popup menu (use null value if popup mode * shell is not supported) */ public Action(String menuPath, String popupPath, KeyStroke keystroke) { this(menuPath, popupPath, null, keystroke); } /** * Creates new Action instance without API_MODE support. * * @param keystrokes array of KeyStroke instances (use null value if shorcut * mode is not supported) * @param menuPath action path in main menu (use null value if menu mode is * not supported) * @param popupPath action path in popup menu (use null value if popup mode * shell is not supported) */ public Action(String menuPath, String popupPath, KeyStroke[] keystrokes) { this(menuPath, popupPath, null, keystrokes); } /** * Creates new Action instance. * * @param keystroke KeyStroke instance (use null value if shorcut mode is * not supported) * @param menuPath action path in main menu (use null value if menu mode is * not supported) * @param popupPath action path in popup menu (use null value if popup mode * is not supported) * @param systemActionClass String class name of SystemAction (use null * value if API mode is not supported) */ public Action(String menuPath, String popupPath, String systemActionClass, KeyStroke keystroke) { this(menuPath, popupPath, systemActionClass, new KeyStroke[]{keystroke}); } /** * Creates new Action instance. * * @param keystrokes array of KeyStroke instances (use null value if * shortcut mode is not supported) * @param menuPath action path in main menu (use null value if menu mode is * not supported) * @param popupPath action path in popup menu (use null value if popup mode * is not supported) * @param systemActionClass String class name of SystemAction (use null * value if API mode is not supported) */ public Action(String menuPath, String popupPath, String systemActionClass, KeyStroke[] keystrokes) { this.menuPath = menuPath; this.popupPath = popupPath; if (systemActionClass == null) { this.systemActionClass = null; } else if (systemActionClass.endsWith(".instance")) { // action defined declaratively in annotation (e.g. ServicesTab) this.layerInstancePath = systemActionClass; } else { try { this.systemActionClass = Class.forName(systemActionClass); } catch (ClassNotFoundException e) { try { this.systemActionClass = Class.forName(systemActionClass, true, Thread.currentThread().getContextClassLoader()); } catch (ClassNotFoundException e2) { this.systemActionClass = null; } } } if (keystrokes != null) { this.keystrokes = keystrokes.clone(); } } static { // Checks if you run on correct jemmy version. Writes message to jemmy log if not. JellyVersion.checkJemmyVersion(); if (JemmyProperties.getCurrentProperty("Action.DefaultMode") == null) { JemmyProperties.setCurrentProperty("Action.DefaultMode", Integer.valueOf(POPUP_MODE)); } Timeouts.initDefault("Action.WaitAfterShortcutTimeout", WAIT_AFTER_SHORTCUT_TIMEOUT); // Set case sensitive comparator as default because of // very often clash between Cut and Execute menu items. // Substring criterion is set according to default string comparator boolean compareExactly = !Operator.getDefaultStringComparator().equals("abc", "a"); // NOI18N defaultComparator = new DefaultStringComparator(compareExactly, true); } private void perform(int mode) { switch (mode) { case POPUP_MODE: performPopup(); break; case MENU_MODE: performMenu(); break; case API_MODE: performAPI(); break; case SHORTCUT_MODE: performShortcut(); break; default: throw new IllegalArgumentException("Wrong Action.MODE"); } } private void perform(Node node, int mode) { switch (mode) { case POPUP_MODE: performPopup(node); break; case MENU_MODE: performMenu(node); break; case API_MODE: performAPI(node); break; case SHORTCUT_MODE: performShortcut(node); break; default: throw new IllegalArgumentException("Wrong Action.MODE"); } } private void perform(Node[] nodes, int mode) { switch (mode) { case POPUP_MODE: performPopup(nodes); break; case MENU_MODE: performMenu(nodes); break; case API_MODE: performAPI(nodes); break; case SHORTCUT_MODE: performShortcut(nodes); break; default: throw new IllegalArgumentException("Wrong Action.MODE"); } } private void perform(OutlineNode node, int mode) { switch (mode) { case POPUP_MODE: performPopup(node); break; case MENU_MODE: performMenu(node); break; case API_MODE: performAPI(node); break; case SHORTCUT_MODE: performShortcut(node); break; default: throw new IllegalArgumentException("Wrong Action.MODE"); } } private void perform(ComponentOperator component, int mode) { switch (mode) { case POPUP_MODE: performPopup(component); break; case MENU_MODE: performMenu(component); break; case API_MODE: performAPI(component); break; case SHORTCUT_MODE: performShortcut(component); break; default: throw new IllegalArgumentException("Wrong Action.MODE"); } } /** * performs action depending on default mode,
* calls performPopup(), performMenu() or performAPI(),
* when default mode is not supported, others are tried */ public void perform() { int modes[] = sequence[getDefaultMode()]; for (int i = 0; i < modes.length; i++) { try { perform(modes[i]); return; } catch (UnsupportedOperationException e) { } } } /** * performs action depending on default mode,
* calls performPopup(), performMenu() or performAPI(),
* when default mode is not supported, others are tried * * @param node node to be action performed on */ public void perform(Node node) { int modes[] = sequence[getDefaultMode()]; for (int i = 0; i < modes.length; i++) { try { perform(node, modes[i]); return; } catch (UnsupportedOperationException e) { } } } /** * performs action depending on default mode,
* calls performPopup(), performMenu() or performAPI(),
* when default mode is not supported, others are tried * * @param nodes nodes to be action performed on */ public void perform(Node[] nodes) { int modes[] = sequence[getDefaultMode()]; for (int i = 0; i < modes.length; i++) { try { perform(nodes, modes[i]); return; } catch (UnsupportedOperationException e) { } } } /** * performs action depending on default mode,
* calls performPopup(), performMenu(), performShortcut or performAPI(),
* when default mode is not supported, others are tried * * @param node node to be action performed on */ public void perform(OutlineNode node) { int modes[] = sequence[getDefaultMode()]; for (int i = 0; i < modes.length; i++) { try { perform(node, modes[i]); return; } catch (UnsupportedOperationException e) { } } } /** * performs action depending on default mode,
* calls performPopup(), performMenu() or performAPI(),
* when default mode is not supported, others are tried * * @param component component to be action performed on */ public void perform(ComponentOperator component) { int modes[] = sequence[getDefaultMode()]; for (int i = 0; i < modes.length; i++) { try { perform(component, modes[i]); return; } catch (UnsupportedOperationException e) { } } } /** * performs action through main menu * * @throws UnsupportedOperationException when action does not support menu * mode */ public void performMenu() { if (menuPath == null) { throw new UnsupportedOperationException(getClass().toString() + " does not define menu path"); } // Need to wait here to be more reliable. // TBD - It can be removed after issue 23663 is solved. new EventTool().waitNoEvent(500); MainWindowOperator.getDefault().menuBar().pushMenu(menuPath, "|", getComparator()); try { Thread.sleep(AFTER_ACTION_WAIT_TIME); } catch (Exception e) { throw new JemmyException("Sleeping interrupted", e); } } /** * performs action through main menu * * @param node node to be action performed on * @throws UnsupportedOperationException when action does not support menu * mode */ public void performMenu(Node node) { performMenu(new Node[]{node}); } /** * performs action through main menu * * @param nodes nodes to be action performed on * @throws UnsupportedOperationException when action does not support menu * mode */ public void performMenu(Node[] nodes) { if (menuPath == null) { throw new UnsupportedOperationException(getClass().toString() + " does not define menu path"); } testNodes(nodes); nodes[0].select(); for (int i = 1; i < nodes.length; i++) { nodes[i].addSelectionPath(); } try { Thread.sleep(SELECTION_WAIT_TIME); } catch (Exception e) { throw new JemmyException("Sleeping interrupted", e); } performMenu(); } public void performMenu(OutlineNode node) { if (menuPath == null) { throw new UnsupportedOperationException(getClass().toString() + " does not define menu path"); } node.select(); try { Thread.sleep(SELECTION_WAIT_TIME); } catch (Exception e) { throw new JemmyException("Sleeping interrupted", e); } performMenu(); } /** * performs action through main menu * * @param component component to be action performed on * @throws UnsupportedOperationException when action does not support menu * mode */ public void performMenu(ComponentOperator component) { component.getFocus(); try { Thread.sleep(SELECTION_WAIT_TIME); } catch (Exception e) { throw new JemmyException("Sleeping interrupted", e); } performMenu(); } /** * performs action through popup menu * * @throws UnsupportedOperationException */ public void performPopup() { throw new UnsupportedOperationException(getClass().toString() + " does not implement performPopup()"); } /** * performs action through popup menu * * @param node node to be action performed on * @throws UnsupportedOperationException when action does not support popup * mode */ public void performPopup(Node node) { performPopup(new Node[]{node}); } /** * performs action through popup menu * * @param nodes nodes to be action performed on * @throws UnsupportedOperationException when action does not support popup * mode */ public void performPopup(Node[] nodes) { callPopup(nodes).pushMenu(popupPath, "|", getComparator()); try { Thread.sleep(AFTER_ACTION_WAIT_TIME); } catch (Exception e) { throw new JemmyException("Sleeping interrupted", e); } } /** * Performs action on an OutlineNode through popup menu. * * @param node node to be performed on */ public void performPopup(OutlineNode node) { if (popupPath == null) { throw new UnsupportedOperationException(getClass().toString() + " does not define popup path"); } node.callPopup().pushMenu(popupPath, "|", getComparator()); try { Thread.sleep(AFTER_ACTION_WAIT_TIME); } catch (Exception e) { throw new JemmyException("Sleeping interrupted", e); } } /** * Calls popup on given nodes and returns JPopupMenuOperator instance. * * @param nodes nodes to be action performed on * @return JPopupMenuOperator instance */ JPopupMenuOperator callPopup(Node[] nodes) { if (popupPath == null) { throw new UnsupportedOperationException(getClass().toString() + " does not define popup path"); } testNodes(nodes); ComponentVisualizer treeVisualizer = nodes[0].tree().getVisualizer(); ComponentVisualizer oldVisualizer = null; // If visualizer of JTreeOperator is EmptyVisualizer, we need // to avoid making tree component visible in callPopup method. // So far only known case is tree from TreeTableOperator. if (treeVisualizer instanceof EmptyVisualizer) { oldVisualizer = Operator.getDefaultComponentVisualizer(); Operator.setDefaultComponentVisualizer(treeVisualizer); } // Need to wait here to be more reliable. // TBD - It can be removed after issue 23663 is solved. new EventTool().waitNoEvent(500); TreePath paths[] = new TreePath[nodes.length]; for (int i = 0; i < nodes.length; i++) { paths[i] = nodes[i].getTreePath(); } JPopupMenuOperator popup; try { popup = new JPopupMenuOperator(nodes[0].tree().callPopupOnPaths(paths)); } catch (NoSuchPathException e) { // possibly node was recreated, so we can find it again (see issue #71591) for (int i = 0; i < nodes.length; i++) { paths[i] = nodes[i].getTreePath(); } popup = new JPopupMenuOperator(nodes[0].tree().callPopupOnPaths(paths)); } // restore previously used default visualizer if (oldVisualizer != null) { Operator.setDefaultComponentVisualizer(oldVisualizer); } popup.setComparator(getComparator()); return popup; } /** * performs action through popup menu * * @param component component to be action performed on * @throws UnsupportedOperationException when action does not support popup * mode */ public void performPopup(ComponentOperator component) { if (popupPath == null) { throw new UnsupportedOperationException(getClass().toString() + " does not define popup path"); } // Need to wait here to be more reliable. // TBD - It can be removed after issue 23663 is solved. new EventTool().waitNoEvent(500); component.clickForPopup(); new JPopupMenuOperator(component).pushMenu(popupPath, "|", getComparator()); try { Thread.sleep(AFTER_ACTION_WAIT_TIME); } catch (Exception e) { throw new JemmyException("Sleeping interrupted", e); } } /** * performs action through API * * @throws UnsupportedOperationException when action does not support API * mode */ @SuppressWarnings("unchecked") public void performAPI() { if (systemActionClass == null && layerInstancePath == null) { throw new UnsupportedOperationException(getClass().toString() + " does not support API call."); } try { // actions has to be invoked in dispatch thread (see http://www.netbeans.org/issues/show_bug.cgi?id=35755) EventQueue.invokeAndWait(new Runnable() { @Override public void run() { if (layerInstancePath != null) { // action defined declaratively in annotation (e.g. ServicesTab) try { FileObject fo = FileUtil.getConfigFile(layerInstancePath); DataObject dob = DataObject.find(fo); javax.swing.Action action = (javax.swing.Action) ((InstanceCookie) dob).instanceCreate(); action.actionPerformed(new ActionEvent(new Container(), 0, null)); } catch (Exception e) { throw new JemmyException("Cannot perform declaratively defined action \"" + layerInstancePath + "\".", e); } } else if (SystemAction.class.isAssignableFrom(systemActionClass)) { // SystemAction used in IDE SystemAction.get(systemActionClass).actionPerformed( new ActionEvent(new Container(), 0, null)); } else if (javax.swing.Action.class.isAssignableFrom(systemActionClass)) { // action implements javax.swing.Action try { ((javax.swing.Action) systemActionClass.getDeclaredConstructor().newInstance()).actionPerformed( new ActionEvent(new Container(), 0, null)); } catch (Exception e) { throw new JemmyException("Exception when trying to create instance of action \"" + systemActionClass.getName() + "\".", e); } } else if (ActionListener.class.isAssignableFrom(systemActionClass)) { try { ((ActionListener) systemActionClass.getDeclaredConstructor().newInstance()).actionPerformed( new ActionEvent(new Container(), 0, null)); } catch (Exception e) { throw new JemmyException("Exception when trying to create instance of action \"" + systemActionClass.getName() + "\".", e); } } else { throw new JemmyException("Cannot create instance of action \"" + systemActionClass.getName() + "\"."); } } }); Thread.sleep(AFTER_ACTION_WAIT_TIME); } catch (Exception e) { throw new JemmyException("API call failed.", e); } } /** * performs action through API * * @param node node to be action performed on * @throws UnsupportedOperationException when action does not support API * mode */ public void performAPI(Node node) { performAPI(new Node[]{node}); } /** * performs action through API * * @param nodes nodes to be action performed on * @throws UnsupportedOperationException when action does not support API * mode */ public void performAPI(Node[] nodes) { if (systemActionClass == null) { throw new UnsupportedOperationException(getClass().toString() + " does not define SystemAction"); } testNodes(nodes); nodes[0].select(); for (int i = 1; i < nodes.length; i++) { nodes[i].addSelectionPath(); } try { Thread.sleep(SELECTION_WAIT_TIME); } catch (Exception e) { throw new JemmyException("Sleeping interrupted", e); } // if selection is wrong try to select again int selectedNodes = nodes[0].tree().getSelectionCount(); if (selectedNodes != nodes.length) { nodes[0].select(); for (int i = 1; i < nodes.length; i++) { nodes[i].addSelectionPath(); } } performAPI(); } /** * performs action through API * * @param node node to be action performed on * @throws UnsupportedOperationException when action does not support API * mode */ public void performAPI(OutlineNode node) { if (systemActionClass == null) { throw new UnsupportedOperationException(getClass().toString() + " does not define SystemAction"); } node.select(); try { Thread.sleep(SELECTION_WAIT_TIME); } catch (Exception e) { throw new JemmyException("Sleeping interrupted", e); } performAPI(); } /** * performs action through API * * @param component component to be action performed on * @throws UnsupportedOperationException when action does not support API * mode */ public void performAPI(ComponentOperator component) { component.getFocus(); try { Thread.sleep(SELECTION_WAIT_TIME); } catch (Exception e) { throw new JemmyException("Sleeping interrupted", e); } performAPI(); } /** * performs action through shortcut * * @throws UnsupportedOperationException if no shortcut is defined */ public void performShortcut() { KeyStroke[] strokes = getKeyStrokes(); if (strokes == null) { throw new UnsupportedOperationException(getClass().toString() + " does not define shortcut"); } for (int i = 0; i < strokes.length; i++) { new KeyRobotDriver(null).pushKey(null, strokes[i].getKeyCode(), strokes[i].getModifiers(), JemmyProperties.getCurrentTimeouts().create("ComponentOperator.PushKeyTimeout")); JemmyProperties.getProperties().getTimeouts().sleep("Action.WaitAfterShortcutTimeout"); } try { Thread.sleep(AFTER_ACTION_WAIT_TIME); } catch (Exception e) { throw new JemmyException("Sleeping interrupted", e); } } /** * performs action through shortcut * * @param node node to be action performed on * @throws UnsupportedOperationException when action does not support * shortcut mode */ public void performShortcut(Node node) { performShortcut(new Node[]{node}); } /** * performs action through shortcut * * @param nodes nodes to be action performed on * @throws UnsupportedOperationException when action does not support * shortcut mode */ public void performShortcut(Node[] nodes) { final KeyStroke[] strokes = getKeyStrokes(); if (strokes == null) { throw new UnsupportedOperationException(getClass().toString() + " does not define shortcut"); } testNodes(nodes); nodes[0].select(); for (int i = 1; i < nodes.length; i++) { nodes[i].addSelectionPath(); } try { Thread.sleep(SELECTION_WAIT_TIME); } catch (Exception e) { throw new JemmyException("Sleeping interrupted", e); } performShortcut(); } /** * performs action through shortcut * * @param node node to be action performed on * @throws UnsupportedOperationException when action does not support * shortcut mode */ public void performShortcut(OutlineNode node) { final KeyStroke[] strokes = getKeyStrokes(); if (strokes == null) { throw new UnsupportedOperationException(getClass().toString() + " does not define shortcut"); } node.select(); try { Thread.sleep(SELECTION_WAIT_TIME); } catch (Exception e) { throw new JemmyException("Sleeping interrupted", e); } performShortcut(); } /** * performs action through shortcut * * @param component component to be action performed on * @throws UnsupportedOperationException when action does not support * shortcut mode */ public void performShortcut(ComponentOperator component) { component.getFocus(); try { Thread.sleep(SELECTION_WAIT_TIME); } catch (Exception e) { throw new JemmyException("Sleeping interrupted", e); } performShortcut(); } /** * tests if nodes are all from the same tree * * @param nodes nodes * @throws IllegalArgumentException when given nodes does not pass */ protected void testNodes(Node[] nodes) { if ((nodes == null) || (nodes.length == 0)) { throw new IllegalArgumentException("argument nodes is null or empty"); } Component nodesTree = nodes[0].tree().getSource(); for (int i = 0; i < nodes.length; i++) { if (nodes[i] == null) { throw new IllegalArgumentException("argument nodes contains null value"); } if (!nodesTree.equals(nodes[i].tree().getSource())) { throw new IllegalArgumentException(nodes[i].toString() + " is from different tree"); } } } /** * Returns default mode in which actions are performed. * * @return default mode in which actions are performed * @see #POPUP_MODE * @see #MENU_MODE * @see #API_MODE * @see #SHORTCUT_MODE */ public int getDefaultMode() { int mode = (Integer) JemmyProperties.getCurrentProperty("Action.DefaultMode"); if (mode < 0 || mode > 3) { return POPUP_MODE; } return mode; } /** * Sets default mode in which actions are performed. If given mode value is * not valid, it sets {@link #POPUP_MODE} as default. * * @param mode mode to be set * @return previous value * @see #POPUP_MODE * @see #MENU_MODE * @see #API_MODE * @see #SHORTCUT_MODE */ public int setDefaultMode(int mode) { int oldMode = (Integer) JemmyProperties.getCurrentProperty("Action.DefaultMode"); if (mode < 0 || mode > 3) { mode = POPUP_MODE; } JemmyProperties.setCurrentProperty("Action.DefaultMode", mode); return oldMode; } /** * Sets comparator fot this action. Comparator is used for all actions after * this method is called. * * @param comparator new comparator to be set (e.g. new * Operator.DefaultStringComparator(true, true); to search string item * exactly and case sensitive) */ public void setComparator(StringComparator comparator) { this.comparator = comparator; } /** * Gets comparator set for this action instance. * * @return comparator set for this action instance. */ public StringComparator getComparator() { if (comparator == null) { comparator = defaultComparator; } return comparator; } /** * getter for popup menu path * * @return String popup menu path (or null if not suported) */ public String getPopupPath() { return popupPath; } /** * getter for main menu path * * @return String main menu path (or null if not suported) */ public String getMenuPath() { return menuPath; } /** * getter for system action class * * @return Class of system action (or null if not suported) */ public Class getSystemActionClass() { return systemActionClass; } /** * Returns an array of KeyStroke objects. * * @return an array of KeyStroke objects or null if not defined. */ public KeyStroke[] getKeyStrokes() { if (keystrokes != null) { return keystrokes.clone(); } return null; } /** * Checks whether this action is enabled. If IDE system action class is * defined, it calls its isEnabled() method else if main menu path is * defined, it checks menu item is enabled. Otherwise it throws * UnsupportedOperationException. * * @return true if this action is enabled; false otherwise */ @SuppressWarnings("unchecked") public boolean isEnabled() { if (systemActionClass != null) { return SystemAction.get(systemActionClass).isEnabled(); } else if (menuPath != null) { return MainWindowOperator.getDefault().menuBar().showMenuItem( menuPath, "|", getComparator()).isEnabled(); } else { throw new UnsupportedOperationException("Cannot detect if " + getClass().getName() + " is enabled."); } } /** * Checks whether this action on given nodes is enabled. If IDE system * action class is defined, it calls its isEnabled() method. Nodes are * selected first. Else if popup menu path is defined, it checks menu item * is enabled. Otherwise it throws UnsupportedOperationException. * * @param nodes array of nodes to be selected before a check * @return true if this action is enabled; false otherwise */ @SuppressWarnings("unchecked") public boolean isEnabled(Node[] nodes) { testNodes(nodes); if (systemActionClass != null) { nodes[0].select(); for (int i = 1; i < nodes.length; i++) { nodes[i].addSelectionPath(); } try { Thread.sleep(SELECTION_WAIT_TIME); } catch (Exception e) { throw new JemmyException("Sleeping interrupted", e); } return SystemAction.get(systemActionClass).isEnabled(); } else if (popupPath != null) { TreePath paths[] = new TreePath[nodes.length]; for (int i = 0; i < nodes.length; i++) { paths[i] = nodes[i].getTreePath(); } ComponentVisualizer treeVisualizer = nodes[0].tree().getVisualizer(); ComponentVisualizer oldVisualizer = null; // If visualizer of JTreeOperator is EmptyVisualizer, we need // to avoid making tree component visible in callPopup method. // So far only known case is tree from TreeTableOperator. if (treeVisualizer instanceof EmptyVisualizer) { oldVisualizer = Operator.getDefaultComponentVisualizer(); Operator.setDefaultComponentVisualizer(treeVisualizer); } // Need to wait here to be more reliable. // TBD - It can be removed after issue 23663 is solved. new EventTool().waitNoEvent(500); JPopupMenuOperator popup = new JPopupMenuOperator(nodes[0].tree().callPopupOnPaths(paths)); // restore previously used default visualizer if (oldVisualizer != null) { Operator.setDefaultComponentVisualizer(oldVisualizer); } boolean enabled = popup.showMenuItem(popupPath, "|", getComparator()).isEnabled(); popup.setVisible(false); return enabled; } else { throw new UnsupportedOperationException("Cannot detect if " + getClass().getName() + " is enabled."); } } /** * Checks whether this action on given node is enabled. If IDE system action * class is defined, it calls its isEnabled() method. Node is selected * first. Else if popup menu path is defined, it checks menu item is * enabled. Otherwise it throws UnsupportedOperationException. * * @param node node to be selected before a check * @return true if this action is enabled; false otherwise */ public boolean isEnabled(Node node) { return isEnabled(new Node[]{node}); } /** * Checks whether this action is enabled for given ComponentOperator. First * it makes component visible and focused. If IDE system action class is * defined, it calls its isEnabled() method. Else if main menu path is * defined, it checks menu item is enabled. Otherwise it throws * UnsupportedOperationException. * * @param componentOperator instance of ComponentOperator * @return true if this action is enabled; false otherwise */ @SuppressWarnings("unchecked") public boolean isEnabled(ComponentOperator componentOperator) { componentOperator.makeComponentVisible(); componentOperator.getFocus(); if (systemActionClass != null) { return SystemAction.get(systemActionClass).isEnabled(); } else if (popupPath != null) { // Need to wait here to be more reliable. // TBD - It can be removed after issue 23663 is solved. new EventTool().waitNoEvent(500); componentOperator.clickForPopup(); return new JPopupMenuOperator(componentOperator).showMenuItem( popupPath, "|", getComparator()).isEnabled(); } else if (menuPath != null) { return MainWindowOperator.getDefault().menuBar().showMenuItem( menuPath, "|", getComparator()).isEnabled(); } else { throw new UnsupportedOperationException("Cannot detect if " + getClass().getName() + " is enabled."); } } /** * This class defines keyboard shortcut for action execution. * * @deprecated Use {@link javax.swing.KeyStroke} instead. */ @Deprecated public static class Shortcut extends Object { /** * key code of shortcut (see KeyEvent) */ protected int keyCode; /** * key modifiers of shortcut (see KeyEvent) */ protected int keyModifiers; /** * creates new shortcut * * @param keyCode int key code (see KeyEvent) */ public Shortcut(int keyCode) { this(keyCode, 0); } /** * creates new shortcut * * @param keyCode int key code (see KeyEvent) * @param keyModifiers int key modifiers (see KeyEvent) */ public Shortcut(int keyCode, int keyModifiers) { this.keyCode = keyCode; this.keyModifiers = keyModifiers; } /** * getter for key code * * @return int key code */ public int getKeyCode() { return keyCode; } /** * getter for key modifiers * * @return int key modifiers */ public int getKeyModifiers() { return keyModifiers; } /** * returns String representation of shortcut * * @return String representation of shortcut */ @Override public String toString() { return Actions.keyStrokeToString( KeyStroke.getKeyStroke(getKeyCode(), getKeyModifiers())); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy