001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.visualweb.gravy.actions;
043:
044: import java.awt.Container;
045: import java.awt.EventQueue;
046: import java.awt.event.ActionEvent;
047: import javax.swing.tree.TreePath; // mdk import org.netbeans.modules.visualweb.gravy.MainWindowOperator;
048: import org.netbeans.modules.visualweb.gravy.Util;
049: import org.netbeans.modules.visualweb.gravy.nodes.Node;
050: import org.netbeans.jemmy.EventTool;
051: import org.netbeans.jemmy.JemmyException;
052: import org.netbeans.jemmy.JemmyProperties;
053: import org.netbeans.jemmy.drivers.input.KeyRobotDriver;
054: import org.netbeans.jemmy.operators.ComponentOperator;
055: import org.netbeans.jemmy.operators.JPopupMenuOperator;
056: import org.netbeans.jemmy.operators.Operator;
057: import org.netbeans.jemmy.util.EmptyVisualizer;
058: import org.openide.util.actions.SystemAction;
059:
060: /** Ancestor class for all non-blocking actions.<p>
061: * This class re-implements all blocking calls from parent Action class to
062: * non-blocking call.<p>
063: * @author <a href="mailto:adam.sotona@sun.com">Adam Sotona</a>
064: * @see Action */
065: public class ActionNoBlock extends Action {
066:
067: /** creates new non-blocking Action instance without API_MODE support
068: * @param menuPath action path in main menu (use null value if menu mode is not supported)
069: * @param popupPath action path in popup menu (use null value if popup mode shell is not supported) */
070: public ActionNoBlock(String menuPath, String popupPath) {
071: super (menuPath, popupPath);
072: }
073:
074: /** creates new non-blocking Action instance
075: * @param menuPath action path in main menu (use null value if menu mode is not supported)
076: * @param popupPath action path in popup menu (use null value if popup mode is not supported)
077: * @param systemActionClass String class name of SystemAction (use null value if API mode is not supported) */
078: public ActionNoBlock(String menuPath, String popupPath,
079: String systemActionClass) {
080: super (menuPath, popupPath, systemActionClass);
081: }
082:
083: /** creates new Action instance without API_MODE support
084: * @param shortcuts array of Shortcut instances (use null value if shortcut mode is not supported)
085: * @param menuPath action path in main menu (use null value if menu mode is not supported)
086: * @param popupPath action path in popup menu (use null value if popup mode shell is not supported) */
087: public ActionNoBlock(String menuPath, String popupPath,
088: Shortcut[] shortcuts) {
089: super (menuPath, popupPath, shortcuts);
090: }
091:
092: /** creates new Action instance without API_MODE support
093: * @param shortcut Shortcut (use null value if shortcut mode is not supported)
094: * @param menuPath action path in main menu (use null value if menu mode is not supported)
095: * @param popupPath action path in popup menu (use null value if popup mode shell is not supported) */
096: public ActionNoBlock(String menuPath, String popupPath,
097: Shortcut shortcut) {
098: super (menuPath, popupPath, shortcut);
099: }
100:
101: /** creates new Action instance
102: * @param shortcuts array of Shortcut instances (use null value if shortcut mode is not supported)
103: * @param menuPath action path in main menu (use null value if menu mode is not supported)
104: * @param popupPath action path in popup menu (use null value if popup mode is not supported)
105: * @param systemActionClass String class name of SystemAction (use null value if API mode is not supported) */
106: public ActionNoBlock(String menuPath, String popupPath,
107: String systemActionClass, Shortcut[] shortcuts) {
108: super (menuPath, popupPath, systemActionClass, shortcuts);
109: }
110:
111: /** creates new Action instance
112: * @param shortcut Shortcut String (use null value if menu mode is not supported)
113: * @param menuPath action path in main menu (use null value if menu mode is not supported)
114: * @param popupPath action path in popup menu (use null value if popup mode is not supported)
115: * @param systemActionClass String class name of SystemAction (use null value if API mode is not supported) */
116: public ActionNoBlock(String menuPath, String popupPath,
117: String systemActionClass, Shortcut shortcut) {
118: super (menuPath, popupPath, systemActionClass, shortcut);
119: }
120:
121: /** performs action through main menu
122: * @throws UnsupportedOperationException when action does not support menu mode */
123: public void performMenu() {
124: if (menuPath == null) {
125: throw new UnsupportedOperationException(getClass()
126: .toString()
127: + " does not define menu path");
128: }
129: // Need to wait here to be more reliable.
130: // TBD - It can be removed after issue 23663 is solved.
131: new EventTool().waitNoEvent(500);
132: // mdk MainWindowOperator.getDefault().menuBar().pushMenuNoBlock(menuPath, "|");
133: Util.getMainMenu().pushMenuNoBlock(menuPath, "|");
134: try {
135: Thread.sleep(AFTER_ACTION_WAIT_TIME);
136: } catch (Exception e) {
137: throw new JemmyException("Sleeping interrupted", e);
138: }
139: }
140:
141: /** performs action through popup menu
142: * @param nodes nodes to be action performed on
143: * @throws UnsupportedOperationException when action does not support popup mode */
144: public void performPopup(Node[] nodes) {
145: if (popupPath == null)
146: throw new UnsupportedOperationException(getClass()
147: .toString()
148: + " does not define popup path");
149: testNodes(nodes);
150: TreePath paths[] = new TreePath[nodes.length];
151: for (int i = 0; i < nodes.length; i++) {
152: paths[i] = nodes[i].getTreePath();
153: }
154: Operator.ComponentVisualizer treeVisualizer = nodes[0].tree()
155: .getVisualizer();
156: Operator.ComponentVisualizer oldVisualizer = null;
157: // If visualizer of JTreeOperator is EmptyVisualizer, we need
158: // to avoid making tree component visible in callPopup method.
159: // So far only known case is tree from TreeTableOperator.
160: if (treeVisualizer instanceof EmptyVisualizer) {
161: oldVisualizer = Operator.getDefaultComponentVisualizer();
162: Operator.setDefaultComponentVisualizer(treeVisualizer);
163: }
164: // Need to wait here to be more reliable.
165: // TBD - It can be removed after issue 23663 is solved.
166: new EventTool().waitNoEvent(500);
167: JPopupMenuOperator popup = new JPopupMenuOperator(nodes[0]
168: .tree().callPopupOnPaths(paths));
169: // restore previously used default visualizer
170: if (oldVisualizer != null) {
171: Operator.setDefaultComponentVisualizer(oldVisualizer);
172: }
173: popup.setComparator(getComparator());
174: popup.pushMenuNoBlock(popupPath, "|");
175: try {
176: Thread.sleep(AFTER_ACTION_WAIT_TIME);
177: } catch (Exception e) {
178: throw new JemmyException("Sleeping interrupted", e);
179: }
180: }
181:
182: /** performs action through popup menu
183: * @param component component to be action performed on
184: * @throws UnsupportedOperationException when action does not support popup mode */
185: public void performPopup(ComponentOperator component) {
186: if (popupPath == null)
187: throw new UnsupportedOperationException(getClass()
188: .toString()
189: + " does not define popup path");
190: // Need to wait here to be more reliable.
191: // TBD - It can be removed after issue 23663 is solved.
192: new EventTool().waitNoEvent(500);
193: component.clickForPopup();
194: JPopupMenuOperator popup = new JPopupMenuOperator(component);
195: popup.setComparator(getComparator());
196: popup.pushMenuNoBlock(popupPath, "|");
197: try {
198: Thread.sleep(AFTER_ACTION_WAIT_TIME);
199: } catch (Exception e) {
200: throw new JemmyException("Sleeping interrupted", e);
201: }
202: }
203:
204: /** performs action through API
205: * @throws UnsupportedOperationException when action does not support API mode */
206: public void performAPI() {
207: if (systemActionClass == null) {
208: throw new UnsupportedOperationException(getClass()
209: .toString()
210: + " does not define SystemAction");
211: }
212: new Thread(new Runnable() {
213: public void run() {
214: try {
215: // Actions have to be invoked in dispatch thread
216: // (see http://www.netbeans.org/issues/show_bug.cgi?id=35755)
217: EventQueue.invokeAndWait(new Runnable() {
218: public void run() {
219: SystemAction.get(systemActionClass)
220: .actionPerformed(
221: new ActionEvent(
222: new Container(), 0,
223: null));
224: }
225: });
226: } catch (Exception e) {
227: throw new JemmyException(
228: "Exception while performing action in dispatch thread",
229: e);
230: }
231: }
232: }, "thread performing action through API").start();
233: try {
234: Thread.sleep(AFTER_ACTION_WAIT_TIME);
235: } catch (Exception e) {
236: throw new JemmyException("Interrupted", e);
237: }
238: }
239:
240: /** performs action through shortcut
241: * @throws UnsupportedOperationException when action does not support shortcut mode */
242: public void performShortcut() {
243: if (shortcuts == null) {
244: throw new UnsupportedOperationException(getClass()
245: .toString()
246: + " does not define shortcut");
247: }
248: new Thread(new Runnable() {
249: public void run() {
250: for (int i = 0; i < shortcuts.length; i++) {
251: new KeyRobotDriver(null).pushKey(null, shortcuts[i]
252: .getKeyCode(), shortcuts[i]
253: .getKeyModifiers(), JemmyProperties
254: .getCurrentTimeouts().create(
255: "Timeouts.DeltaTimeout"));
256: JemmyProperties.getProperties().getTimeouts()
257: .sleep("Action.WaitAfterShortcutTimeout");
258: }
259: }
260: }, "thread performing action through shortcut").start();
261: try {
262: Thread.sleep(AFTER_ACTION_WAIT_TIME);
263: } catch (Exception e) {
264: throw new JemmyException("Sleeping interrupted", e);
265: }
266: }
267: }
|