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): Alexandre Iline.
025: *
026: * The Original Software is the Jemmy library.
027: * The Initial Developer of the Original Software is Alexandre Iline.
028: * 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: *
043: * $Id: DefaultJMenuDriver.java,v 1.13 2007/10/05 11:37:35 jskrivanek Exp $ $Revision: 1.13 $ $Date: 2007/10/05 11:37:35 $
044: *
045: */
046:
047: package org.netbeans.jemmy.drivers.menus;
048:
049: import java.awt.Component;
050:
051: import javax.swing.JMenu;
052: import javax.swing.JMenuBar;
053: import javax.swing.JMenuItem;
054: import javax.swing.JPopupMenu;
055: import javax.swing.MenuElement;
056:
057: import org.netbeans.jemmy.ComponentChooser;
058: import org.netbeans.jemmy.JemmyException;
059: import org.netbeans.jemmy.Timeouts;
060: import org.netbeans.jemmy.Waitable;
061: import org.netbeans.jemmy.Waiter;
062:
063: import org.netbeans.jemmy.drivers.DriverManager;
064: import org.netbeans.jemmy.drivers.LightSupportiveDriver;
065: import org.netbeans.jemmy.drivers.MenuDriver;
066: import org.netbeans.jemmy.drivers.MouseDriver;
067: import org.netbeans.jemmy.drivers.PathChooser;
068:
069: import org.netbeans.jemmy.operators.ComponentOperator;
070: import org.netbeans.jemmy.operators.JMenuBarOperator;
071: import org.netbeans.jemmy.operators.JMenuItemOperator;
072: import org.netbeans.jemmy.operators.JMenuOperator;
073: import org.netbeans.jemmy.operators.JPopupMenuOperator;
074:
075: public class DefaultJMenuDriver extends LightSupportiveDriver implements
076: MenuDriver {
077: public DefaultJMenuDriver() {
078: super (new String[] {
079: "org.netbeans.jemmy.operators.JMenuOperator",
080: "org.netbeans.jemmy.operators.JMenuBarOperator",
081: "org.netbeans.jemmy.operators.JPopupMenuOperator" });
082: }
083:
084: public Object pushMenu(ComponentOperator oper, PathChooser chooser) {
085: checkSupported(oper);
086: if (oper instanceof JMenuBarOperator
087: || oper instanceof JPopupMenuOperator) {
088: JMenuItem item;
089: if (oper instanceof JMenuBarOperator) {
090: item = waitItem(oper, (JMenuBar) oper.getSource(),
091: chooser, 0);
092: } else {
093: item = waitItem(oper, (JPopupMenu) oper.getSource(),
094: chooser, 0);
095: }
096: JMenuItemOperator itemOper;
097: if (item instanceof JMenu) {
098: itemOper = new JMenuOperator((JMenu) item);
099: } else if (item instanceof JMenuItem) {
100: itemOper = new JMenuItemOperator(item);
101: } else {
102: return (null);
103: }
104: itemOper.copyEnvironment(oper);
105: return (push(
106: itemOper,
107: null,
108: (oper instanceof JMenuBarOperator) ? ((JMenuBar) oper
109: .getSource())
110: : null, chooser, 1, true));
111: } else {
112: return (push(oper, null, null, chooser, 0, true));
113: }
114: }
115:
116: protected Object push(ComponentOperator oper,
117: ComponentOperator lastItem, JMenuBar menuBar,
118: PathChooser chooser, int depth, boolean pressMouse) {
119: try {
120: oper.waitComponentVisible(true);
121: oper.waitComponentEnabled();
122: } catch (InterruptedException e) {
123: throw (new JemmyException("Interrupted!", e));
124: }
125: MouseDriver mDriver = DriverManager.getMouseDriver(oper);
126: //mDriver.enterMouse(oper);
127: //use enhanced algorithm instead
128: smartMove(lastItem, oper);
129: if (depth > chooser.getDepth() - 1) {
130: if (oper instanceof JMenuOperator && menuBar != null
131: && getSelectedElement(menuBar) != null) {
132: //mDriver.enterMouse(oper);
133: } else {
134: DriverManager.getButtonDriver(oper).push(oper);
135: }
136: return (oper.getSource());
137: }
138: if (pressMouse
139: && !((JMenuOperator) oper).isPopupMenuVisible()
140: && !(menuBar != null && getSelectedElement(menuBar) != null)) {
141: DriverManager.getButtonDriver(oper).push(oper);
142: }
143: oper.getTimeouts()
144: .sleep("JMenuOperator.WaitBeforePopupTimeout");
145: JMenuItem item = waitItem(oper, waitPopupMenu(oper), chooser,
146: depth);
147: mDriver.exitMouse(oper);
148: if (item instanceof JMenu) {
149: JMenuOperator mo = new JMenuOperator((JMenu) item);
150: mo.copyEnvironment(oper);
151: return (push(mo, oper, null, chooser, depth + 1, false));
152: } else {
153: JMenuItemOperator mio = new JMenuItemOperator(item);
154: mio.copyEnvironment(oper);
155: try {
156: mio.waitComponentEnabled();
157: } catch (InterruptedException e) {
158: throw (new JemmyException("Interrupted!", e));
159: }
160: //move here first
161: smartMove(oper, mio);
162: DriverManager.getButtonDriver(oper).push(mio);
163: return (item);
164: }
165: }
166:
167: private void smartMove(ComponentOperator last,
168: ComponentOperator oper) {
169: if (last == null) {
170: oper.enterMouse();
171: return;
172: }
173: //get all the coordinates first
174: //previous item
175: long lastXl, lastXr, lastYl, lastYr;
176: lastXl = (long) last.getSource().getLocationOnScreen().getX();
177: lastXr = lastXl + last.getSource().getWidth();
178: lastYl = (long) last.getSource().getLocationOnScreen().getY();
179: lastYr = lastYl + last.getSource().getHeight();
180: //this item
181: long operXl, operXr, operYl, operYr;
182: operXl = (long) oper.getSource().getLocationOnScreen().getX();
183: operXr = operXl + oper.getSource().getWidth();
184: operYl = (long) oper.getSource().getLocationOnScreen().getY();
185: operYr = operYl + oper.getSource().getHeight();
186: //get the overlap borders
187: long overXl, overXr, overYl, overYr;
188: overXl = (lastXl > operXl) ? lastXl : operXl;
189: overXr = (lastXr < operXr) ? lastXr : operXr;
190: overYl = (lastYl > operYl) ? lastYl : operYl;
191: overYr = (lastYr < operYr) ? lastYr : operYr;
192: //now, let's see ...
193: //what if it overlaps by x?
194: if (overXl < overXr) {
195: //good - move mose to the center of the overlap
196: last.moveMouse((int) ((overXr - overXl) / 2 - lastXl), last
197: .getCenterY());
198: //move mouse inside
199: oper.moveMouse((int) ((overXr - overXl) / 2 - operXl), oper
200: .getCenterY());
201: //done - now move to the center
202: oper.enterMouse();
203: return;
204: }
205: //ok, what if it overlaps by y?
206: if (overYl < overYr) {
207: //good - move mose to the center of the overlap
208: last.moveMouse(last.getCenterX(),
209: (int) ((overYr - overYl) / 2 - lastYl));
210: //move mouse inside
211: oper.moveMouse(last.getCenterX(),
212: (int) ((overYr - overYl) / 2 - operYl));
213: //done - now move to the center
214: oper.enterMouse();
215: return;
216: }
217: //well - can't help it
218: oper.enterMouse();
219: }
220:
221: protected JPopupMenu waitPopupMenu(final ComponentOperator oper) {
222: return ((JPopupMenu) JPopupMenuOperator.waitJPopupMenu(
223: new ComponentChooser() {
224: public boolean checkComponent(Component comp) {
225: return (comp == ((JMenuOperator) oper)
226: .getPopupMenu() && comp.isShowing());
227: }
228:
229: public String getDescription() {
230: return (((JMenuOperator) oper).getText() + "'s popup");
231: }
232: }).getSource());
233: }
234:
235: protected JMenuItem waitItem(ComponentOperator oper,
236: MenuElement element, PathChooser chooser, int depth) {
237: Waiter waiter = new Waiter(new JMenuItemWaiter(element,
238: chooser, depth));
239: waiter.setOutput(oper.getOutput().createErrorOutput());
240: waiter.setTimeouts(oper.getTimeouts());
241: try {
242: return ((JMenuItem) waiter.waitAction(null));
243: } catch (InterruptedException e) {
244: throw (new JemmyException("Waiting has been interrupted", e));
245: }
246: }
247:
248: public static Object getSelectedElement(JMenuBar bar) {
249: MenuElement[] subElements = bar.getSubElements();
250: for (int i = 0; i < subElements.length; i++) {
251: if (subElements[i] instanceof JMenu
252: && ((JMenu) subElements[i]).isPopupMenuVisible()) {
253: return (subElements[i]);
254: }
255: }
256: return (null);
257: }
258:
259: private class JMenuItemWaiter implements Waitable {
260: MenuElement cont;
261: PathChooser chooser;
262: int depth;
263:
264: public JMenuItemWaiter(MenuElement cont, PathChooser chooser,
265: int depth) {
266: this .cont = cont;
267: this .chooser = chooser;
268: this .depth = depth;
269: }
270:
271: public Object actionProduced(Object obj) {
272: if (!((Component) cont).isShowing()) {
273: return (null);
274: }
275: MenuElement[] subElements = cont.getSubElements();
276: for (int i = 0; i < subElements.length; i++) {
277: if (((Component) subElements[i]).isShowing()
278: && ((Component) subElements[i]).isEnabled()
279: && chooser.checkPathComponent(depth,
280: subElements[i])) {
281: return subElements[i];
282: }
283: }
284: return (null);
285: }
286:
287: public String getDescription() {
288: return ("");
289: }
290: }
291: }
|