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

org.netbeans.jellytools.TopComponentOperator Maven / Gradle / Ivy

The newest version!
/*
 * 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;

import java.awt.Component;
import java.awt.Container;
import java.awt.Point;
import java.awt.Rectangle;
import java.io.IOException;
import javax.swing.JComponent;
import org.netbeans.api.actions.Savable;
import org.netbeans.jemmy.QueueTool;
import org.netbeans.jemmy.TestOut;
import org.netbeans.jellytools.actions.AttachWindowAction;
import org.netbeans.jellytools.actions.CloneViewAction;
import org.netbeans.jellytools.actions.CloseAllDocumentsAction;
import org.netbeans.jellytools.actions.CloseViewAction;
import org.netbeans.jellytools.actions.MaximizeWindowAction;
import org.netbeans.jellytools.actions.RestoreWindowAction;
import org.netbeans.jemmy.ComponentChooser;
import org.netbeans.jemmy.JemmyException;
import org.netbeans.jemmy.JemmyProperties;
import org.netbeans.jemmy.Timeouts;
import org.netbeans.jemmy.Waitable;
import org.netbeans.jemmy.Waiter;
import org.netbeans.jemmy.drivers.DriverManager;
import org.netbeans.jemmy.drivers.input.MouseRobotDriver;
import org.netbeans.jemmy.operators.ContainerOperator;
import org.netbeans.jemmy.operators.JComponentOperator;
import org.netbeans.jemmy.operators.JPopupMenuOperator;
import org.netbeans.jemmy.operators.Operator;
import org.openide.loaders.DataObject;
import org.openide.windows.TopComponent;
import org.netbeans.swing.tabcontrol.TabbedContainer;

/**
 * Represents org.openide.windows.TopComponent. It is IDE wrapper for a lot of
 * panels in IDE. TopComponent is for example Projects panel, every editor
 * panel or output panel. TopComponent can be located by TopComponentOperator
 * anywhere inside IDE, if it is opened. It is by default activated which means
 * it is put to foreground if there exist more top components in a split area.
 * TopComponent can also be located explicitly inside some Container.
 *
 * 

Usage:
*

 *      TopComponentOperator tco = new TopComponentOperator("Projects");
 *      tco.pushMenuOnTab("Maximize");
 *      tco.restore();
 *      tco.attachTo("Files", AttachWindowAction.AS_LAST_TAB);
 *      tco.attachTo("Output", AttachWindowAction.RIGHT);
 *      tco.close();
 * 
* * @author Adam Sotona * @author Jiri Skrivanek * * @see org.netbeans.jellytools.actions.AttachWindowAction * @see org.netbeans.jellytools.actions.CloneViewAction * @see org.netbeans.jellytools.actions.CloseAllDocumentsAction * @see org.netbeans.jellytools.actions.CloseViewAction * @see org.netbeans.jellytools.actions.MaximizeWindowAction * @see org.netbeans.jellytools.actions.RestoreWindowAction */ public class TopComponentOperator extends JComponentOperator { /** * "Close Window" popup menu item. */ private static final String closeWindowItem = Bundle.getStringTrimmed("org.netbeans.core.windows.actions.Bundle", "CTL_CloseWindowAction"); /** * "Close All Documents" popup menu item. */ private static final String closeAllDocumentsItem = Bundle.getStringTrimmed("org.netbeans.core.windows.actions.Bundle", "LBL_CloseAllDocumentsAction"); static { // Checks if you run on correct jemmy version. Writes message to jemmy log if not. JellyVersion.checkJemmyVersion(); // need to set timeout for the case it was not set previously Timeouts.initDefault("EventDispatcher.RobotAutoDelay", 0); DriverManager.setDriver(DriverManager.MOUSE_DRIVER_ID, new MouseRobotDriver(JemmyProperties.getCurrentTimeouts().create("EventDispatcher.RobotAutoDelay"), new String[]{TopComponentOperator.class.getName()})); } /** Waits for index-th TopComponent with given name in specified container. * It is activated by default. * @param contOper container where to search * @param topComponentName name of TopComponent (it used to be label of tab) * @param index index of TopComponent to be find */ public TopComponentOperator(ContainerOperator contOper, String topComponentName, int index) { super(waitTopComponent(contOper, topComponentName, index, null)); copyEnvironment(contOper); makeComponentVisible(); } /** Waits for TopComponent with given name in specified container. * It is activated by default. * @param contOper container where to search * @param topComponentName name of TopComponent (it used to be label of tab) */ public TopComponentOperator(ContainerOperator contOper, String topComponentName) { this(contOper, topComponentName, 0); } /** Waits for index-th TopComponent in specified container. * It is activated by default. * @param contOper container where to search * @param index index of TopComponent to be find */ public TopComponentOperator(ContainerOperator contOper, int index) { this(contOper, null, index); } /** Waits for first TopComponent in specified container. * It is activated by default. * @param contOper container where to search */ public TopComponentOperator(ContainerOperator contOper) { this(contOper, null, 0); } /** Waits for index-th TopComponent with given name in whole IDE. * It is activated by default. * @param topComponentName name of TopComponent (it used to be label of tab) * @param index index of TopComponent to be find */ public TopComponentOperator(String topComponentName, int index) { this(waitTopComponent(topComponentName, index)); } /** Waits for first TopComponent with given name in whole IDE. * It is activated by default. * @param topComponentName name of TopComponent (it used to be label of tab) */ public TopComponentOperator(String topComponentName) { this(topComponentName, 0); } /** Creates new instance from given TopComponent. * It is activated by default. * This constructor is used in properties.PropertySheetOperator. * @param jComponent instance of JComponent */ public TopComponentOperator(JComponent jComponent) { super(jComponent); makeComponentVisible(); } /** Makes active window in which this top component resides (main window * in joined mode) and then activates this top component to be in the * foreground. */ @Override public void makeComponentVisible() { // Make active window in which this TopComponent resides. // It is necessary e.g. for keyboard focus super.makeComponentVisible(); // Check if it is really TopComponent. It doesn't have to be // for example for PropertySheetOperator in Options window. // In that case do nothing. if (getSource() instanceof TopComponent) { // activate TopComponent, i.e. switch tab control to be active. // run in dispatch thread runMapping(new MapVoidAction("requestActive") { @Override public void map() { ((TopComponent) getSource()).requestActive(); } }); } } /** Attaches this top component to a new position defined by target top * component and side. * @param targetTopComponentName name of top component defining a position * where to attach top component * @param side side where to attach top component ({@link AttachWindowAction#LEFT}, * {@link AttachWindowAction#RIGHT}, {@link AttachWindowAction#TOP}, * {@link AttachWindowAction#BOTTOM}, {@link AttachWindowAction#AS_LAST_TAB}) */ public void attachTo(String targetTopComponentName, String side) { new AttachWindowAction(targetTopComponentName, side).perform(this); } /** Attaches this top component to a new position defined by target top * component and side. * @param targetTopComponentOperator operator of top component defining a position * where to attach top component * @param side side where to attach top component ({@link AttachWindowAction#LEFT}, * {@link AttachWindowAction#RIGHT}, {@link AttachWindowAction#TOP}, * {@link AttachWindowAction#BOTTOM}, {@link AttachWindowAction#AS_LAST_TAB}) */ public void attachTo(TopComponentOperator targetTopComponentOperator, String side) { new AttachWindowAction(targetTopComponentOperator, side).perform(this); } /** Maximizes this top component. */ public void maximize() { new MaximizeWindowAction().perform(this); } /** Restores maximized window. */ public void restore() { new RestoreWindowAction().perform(this); } /** Clones this TopComponent. TopComponent is activated before * action is performed. */ public void cloneDocument() { new CloneViewAction().perform(this); } /** Closes this TopComponent and wait until it is closed. * TopComponent is activated before action is performed. */ public void closeWindow() { if (isModified()) { new Thread(new Runnable() { @Override public void run() { pushMenuOnTab(closeWindowItem); } ; }, "thread to close TopComponent").start(); } else { new CloseViewAction().perform(this); waitComponentShowing(false); } } /** Closes this TopComponent instance by IDE API call and wait until * it is not closed. If this TopComponent is modified (e.g. editor top * component), it discards possible changes. * @see #close */ public void closeDiscard() { setUnmodified(); close(); } /** Finds DataObject for the content of this TopComponent and set it * unmodified. Used in closeDiscard method. */ public void setUnmodified() { DataObject dob = ((TopComponent) getSource()).getLookup().lookup(DataObject.class); if (dob == null) { // try to find possible enclosing MultiviewTopComponent TopComponentOperator parentTco = findParentTopComponent(); if (parentTco != null) { parentTco.setUnmodified(); } } else { dob.setModified(false); } } /** Returns true if this top component is modified (e.g. source in editor) * @return boolean true if this object is modified; false otherwise */ public boolean isModified() { Savable savable = ((TopComponent) getSource()).getLookup().lookup(Savable.class); if (savable == null) { // try to find possible enclosing MultiviewTopComponent TopComponentOperator parentTco = findParentTopComponent(); if (parentTco != null) { return parentTco.isModified(); } else { return false; } } else { return true; } } /** Saves content of this TopComponent. If it is not applicable or content * of TopComponent is not modified, it does nothing. */ public void save() { Savable savable = ((TopComponent) getSource()).getLookup().lookup(Savable.class); if (savable == null) { // try to find possible enclosing MultiviewTopComponent TopComponentOperator parentTco = findParentTopComponent(); if (parentTco != null) { parentTco.save(); } } else { try { savable.save(); } catch (IOException e) { throw new JemmyException("Saving of TopComponent " + ((TopComponent) getSource()).getDisplayName() + " failed (Savable=" + savable + ").", e); //NOI18N } } } /** Closes this TopComponent instance by IDE API call and wait until * it is not closed. If this TopComponent is modified (e.g. editor top * component), question dialog is shown and you have to close it. To close * this TopComponent and discard possible changes use {@link #closeDiscard} * method. */ public void close() { if (isModified()) { // need to call it by popup because it is impossible to call // TopComponent.close in AWT thread and handle question dialog in a different thread closeWindow(); } else { if (isOpened()) { // run in dispatch thread runMapping(new MapVoidAction("close") { @Override public void map() { ((TopComponent) getSource()).close(); } }); } else { // try to find enclosing MultiviewTopComponent TopComponentOperator parent = findParentTopComponent(); if (parent != null) { parent.close(); } } waitComponentShowing(false); } } /** Closes all opened documents and waits until this top component is closed. */ public void closeAllDocuments() { DataObject[] modifs = DataObject.getRegistry().getModified(); if (modifs.length != 0) { // some object modified => need to call in new thread because modal question dialog appears new Thread(new Runnable() { @Override public void run() { pushMenuOnTab(closeAllDocumentsItem); } ; }, "thread to closeAllDocuments").start(); } else { // no object modified new CloseAllDocumentsAction().perform(this); waitComponentShowing(false); } } /** Finds index-th TopComponent with given name in whole IDE. * @param name name of TopComponent * @param index index of TopComponent * @return TopComponent instance or null if noone matching criteria was found */ public static JComponent findTopComponent(String name, int index) { return findTopComponent(null, name, index, null); } /** Finds index-th TopComponent with given name in IDE registry. * @param cont container where to search * @param name name of TopComponent * @param index index of TopComponent * @param subchooser ComponentChooser to determine exact TopComponent * @return TopComponent instance or null if noone matching criteria was found */ protected static JComponent findTopComponent(final ContainerOperator cont, final String name, final int index, final ComponentChooser subchooser) { // run in dispatch thread return (JComponent) new QueueTool().invokeSmoothly(new QueueTool.QueueAction("findTopComponent") { // NOI18N @Override public Object launch() { int counter = index; Object tc[] = TopComponent.getRegistry().getOpened().toArray(); StringComparator comparator = cont == null ? Operator.getDefaultStringComparator() : cont.getComparator(); TopComponent c; // loop through showing TopComponents for (int i = 0; i < tc.length; i++) { c = (TopComponent) tc[i]; if (c.isShowing() && (comparator.equals(c.getName(), name) || comparator.equals(c.getDisplayName(), name)) && isUnder(cont, c)) { JComponent result = checkSubchooser(c, subchooser); if (result != null) { if (--counter < 0) { return result; } } } } // loop through NOT showing TopComponents but parent has to be showing for (int i = 0; i < tc.length; i++) { c = (TopComponent) tc[i]; if ((!c.isShowing()) && isParentShowing(c) && (comparator.equals(c.getName(), name) || comparator.equals(c.getDisplayName(), name)) && isUnder(cont, c)) { JComponent result = checkSubchooser(c, subchooser); if (result != null) { if (--counter < 0) { return result; } } } } return null; } }); } /** If subchooser is null, return TopComponent. * Else if c is instance of MultiViewCloneableTopComponent try to find * and return sub component in MVCTC corresponding to sub chooser. Else * check TC in sub chooser and return it if matches. MVCTC can host * several views, e.g. source and design view in form editor or xml, servlets, * overview views in web.xml editor. Then EditorOperator is able to find * appropriate CloneableEditor in MVCTC. * @param c TopComponent to check * @param subchooser ComponentChooser to check if matches * @return given TopComponent or appropriate sub component */ private static JComponent checkSubchooser(TopComponent c, ComponentChooser subchooser) { if (subchooser == null) { return c; } else { boolean isMultiView = false; try { //isMultiView = c instanceof MultiViewCloneableTopComponent; isMultiView = isMultyView(c); } catch (Throwable t) { // ignore possible NoClassDefFoundError because org.netbeans.core.multiview module is not enabled in IDE } if (isMultiView) { TopComponentOperator tco = new TopComponentOperator((JComponent) c); // suppress output when finding sub component tco.setOutput(TestOut.getNullOutput()); return (JComponent) tco.findSubComponent(subchooser); } else { if (subchooser.checkComponent(c)) { return c; } } } return null; } private static boolean isMultyView(TopComponent c) { Class clz = c.getClass(); do { if (clz.getName().equals("org.netbeans.core.multiview.MultiViewCloneableTopComponent")) { return true; } } while ((clz = clz.getSuperclass()) != null); return false; } private static boolean isParentShowing(Component c) { while (c != null) { if (c.isShowing()) { return true; } c = c.getParent(); } return false; } private static boolean isUnder(ContainerOperator cont, Component c) { if (cont == null) { return true; } Component comp = cont.getSource(); while (comp != c && c != null) { c = c.getParent(); } return (comp == c); } /** Waits for index-th TopComponent with given name in IDE registry. * It throws JemmyException when TopComponent is not find until timeout * expires. * @param name name of TopComponent * @param index index of TopComponent * @return TopComponent instance or throws JemmyException if not found * @see #findTopComponent */ protected static JComponent waitTopComponent(final String name, final int index) { return waitTopComponent(null, name, index, null); } /** Waits for index-th TopComponent with given name in IDE registry. * It throws JemmyException when TopComponent is not find until timeout * expires. * @param cont container where to search * @param name name of TopComponent * @param index index of TopComponent * @param subchooser ComponentChooser to determine exact TopComponent * @return TopComponent instance or throws JemmyException if not found * @see #findTopComponent */ protected static JComponent waitTopComponent(final ContainerOperator cont, final String name, final int index, final ComponentChooser subchooser) { try { Waiter waiter = new Waiter(new Waitable() { @Override public Object actionProduced(Object obj) { return findTopComponent(cont, name, index, subchooser); } @Override public String getDescription() { return ("Wait TopComponent with name=" + name + " index=" + String.valueOf(index) + (subchooser == null ? "" : " subchooser=" + subchooser.getDescription()) + " loaded"); } }); Timeouts times = JemmyProperties.getCurrentTimeouts().cloneThis(); times.setTimeout("Waiter.WaitingTime", times.getTimeout("ComponentOperator.WaitComponentTimeout")); waiter.setTimeouts(times); waiter.setOutput(JemmyProperties.getCurrentOutput()); return ((JComponent) waiter.waitAction(null)); } catch (InterruptedException e) { return (null); } } /** Makes top component active and pushes given menu on its tab. * @param popupPath menu path separated by '|' (e.g. "CVS|Refresh") */ public void pushMenuOnTab(String popupPath) { if (isOpened()) { this.makeComponentVisible(); TabbedContainer ta = findTabbedAdapter(); int index = ta.indexOf((TopComponent) getSource()); Rectangle r = new Rectangle(); ta.getTabRect(index, r); Point p = new Point(r.x + (r.width / 2), r.y + (r.height / 2)); Component tabsComp = ta.getComponentAt(p); new JPopupMenuOperator(JPopupMenuOperator.callPopup(tabsComp, p.x, p.y)).pushMenu(popupPath); } else { // try to find enclosing MultiviewTopComponent TopComponentOperator parent = findParentTopComponent(); if (parent != null) { parent.pushMenuOnTab(popupPath); } } } /** Returns TabbedAdapter component from parents hierarchy. * Used also in EditorWindowOperator. */ public TabbedContainer findTabbedAdapter() { Container parent = getSource().getParent(); while (parent != null) { if (parent instanceof TabbedContainer) { // NOI18N return (TabbedContainer) parent; } else { parent = parent.getParent(); } } return null; } public Container findTabDisplayer() { return ContainerOperator.findContainer(findTabbedAdapter(), new ComponentChooser() { @Override public boolean checkComponent(Component comp) { return comp.getClass().getName().endsWith("TabDisplayer"); } @Override public String getDescription() { return "org.netbeans.swing.tabcontrol.TabDisplayer"; } }); } /** * Waits the topcomponent to be closed. */ public void waitClosed() { getOutput().printLine("Wait topcomponent to be closed \n : " + getSource().toString()); getOutput().printGolden("Wait topcomponent to be closed"); waitState(new ComponentChooser() { @Override public boolean checkComponent(Component comp) { return (!comp.isVisible()); } @Override public String getDescription() { return ("Closed topcomponent"); } }); } /** Returns true if this TopComponent is opened. If it is not opened, it * usually means it is contained within MultiviewTopComponent. * @return true if open, false otherwise */ protected boolean isOpened() { // run in dispatch thread return runMapping(new MapBooleanAction("isOpened") { // NOI18N @Override public boolean map() { return ((TopComponent) getSource()).isOpened(); } }); } /** Returns TopComponentOperator from parents hierarchy. It should be * MultiviewTopComponent. */ protected TopComponentOperator findParentTopComponent() { Component parent = getSource().getParent(); while (parent != null) { if (parent instanceof TopComponent) { return new TopComponentOperator((JComponent) parent); } else { parent = parent.getParent(); } } return null; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy