Java tutorial
/******************************************************************************* * Copyright (c) 2004, 2010 BREDEX GmbH. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * BREDEX GmbH - initial API and implementation and/or initial documentation *******************************************************************************/ package org.eclipse.jubula.rc.swing.components; import java.awt.Component; import java.awt.Container; import java.awt.Dialog; import java.awt.EventQueue; import java.awt.Window; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.awt.event.ContainerEvent; import java.awt.event.ContainerListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.Vector; import javax.swing.JDesktopPane; import javax.swing.JInternalFrame; import javax.swing.JMenu; import javax.swing.JToolBar; import javax.swing.SwingUtilities; import org.apache.commons.lang.Validate; import org.eclipse.jubula.rc.common.AUTServer; import org.eclipse.jubula.rc.common.AUTServerConfiguration; import org.eclipse.jubula.rc.common.Constants; import org.eclipse.jubula.rc.common.components.AUTHierarchy; import org.eclipse.jubula.rc.common.components.HierarchyContainer; import org.eclipse.jubula.rc.common.exception.ComponentNotManagedException; import org.eclipse.jubula.rc.common.logger.AutServerLogger; import org.eclipse.jubula.rc.swing.SwingAUTServer; import org.eclipse.jubula.rc.swing.listener.ComponentHandler; import org.eclipse.jubula.rc.swing.utils.WorkerRunnable; import org.eclipse.jubula.tools.exception.InvalidDataException; import org.eclipse.jubula.tools.messagehandling.MessageIDs; import org.eclipse.jubula.tools.objects.ComponentIdentifier; import org.eclipse.jubula.tools.objects.IComponentIdentifier; import org.eclipse.jubula.tools.objects.MappingConstants; import org.eclipse.jubula.tools.utils.EnvironmentUtils; /** * This class holds a hierarchy of the components of the AUT. <br> * * The hierarchy is composed with <code>SwingHierarchyContainer</code>s. For every * component from the AUT a hierarchy container is created. The names for the * components are stored in the appropriate hierarchy containers, instead of the * components itself. Thus the AUTServer does not affect the instances from the * AUT. <br> * * In JRE 1.3 the WINDOW_CLOSED event is not delivered properly, so a window * listener is added to any opened window listening to * <code>WindowEvent.WINDOW_CLOSED</code>.<br> * <p> * <b>Interferences with the AUT</b> * <ul> * <li>The AUTHierarchy is registered as a container listener to every * container from the AUT (but not to the hierarchy container).</li> * <li>The AUTHierarchy is registered as a window listener to every window * from the AUT.</li> * </ul> * * @author BREDEX GmbH * @created 30.08.2004 * */ public class AUTSwingHierarchy extends AUTHierarchy implements ContainerListener, ComponentListener { /** * name of environment variable / Java property that should be set to * "true" (case-insensitive) if Swing/AWT listeners should be * (de-)registered directly in the thread that handles Swing / AWT events */ private static final String ENV_VAR_SYNC_REGISTER_LISTENERS = "JB_SYNC_REG_SWING_LISTENERS"; //$NON-NLS-1$ /** the logger */ private static AutServerLogger log = new AutServerLogger(AUTSwingHierarchy.class); /**Businessprocess for getting components */ private static FindSwingComponentBP findBP = new FindSwingComponentBP(); /** * the worker responsible for handling (de-)registration of * Swing/AWT listeners */ private WorkerRunnable m_listenerRegistrationWorker = new WorkerRunnable(); /** * whether Swing/AWT listeners should be (de-)registered directly in the * thread that handles Swing / AWT events. if not, then a worker thread is * used. */ private boolean m_syncListenerRegistration = false; /** * Constructor */ public AUTSwingHierarchy() { String syncListenersRegistrationValue = EnvironmentUtils .getProcessOrSystemProperty(ENV_VAR_SYNC_REGISTER_LISTENERS); m_syncListenerRegistration = Boolean.valueOf(syncListenersRegistrationValue).booleanValue(); if (!m_syncListenerRegistration) { Thread registrationThread = new Thread(m_listenerRegistrationWorker, "Jubula Listener Registration"); registrationThread.setDaemon(true); registrationThread.start(); } } /** * Adds the complete hierarchy of the given <code>window</code> to the * hierarchy. <br> * @param window a new (and opened) window */ public void add(Window window) { // if window has no parent, its a new top level container, otherwise // the parent is already in the AutHierarchy, // NO!: creating a Window without a parent, calling show() // -> window.getParent() == SwingUtilities$1 // don't add, if in hierarchy map yet if (getRealMap().get(window) == null || getHierarchyContainer(window) == null) { if (log.isInfoEnabled()) { log.info("adding window " + window); //$NON-NLS-1$ } // create a new SwingHierarchyContainer for window SwingComponent componentID = new SwingComponent(window); SwingHierarchyContainer hierarchyWindow = new SwingHierarchyContainer(componentID); // update the hash table addToHierachyMap(hierarchyWindow); // add a window listener for window closed events registerAsWindowListener(window); // get the parent of window, if any Container parent = window.getParent(); if (parent != null) { SwingHierarchyContainer hierarchyParent = getHierarchyContainer(parent); if (hierarchyParent == null) { // a new container, see comment at top of the method hierarchyParent = new SwingHierarchyContainer(new SwingComponent(parent)); } name(hierarchyParent); // add the new container for the window to hierarchyParent hierarchyParent.add(hierarchyWindow); hierarchyWindow.setParent(hierarchyParent); name(hierarchyWindow); // update m_hierarchyMap addToHierachyMap(hierarchyParent); addToHierarchyUp(hierarchyParent, parent); } } // registering this class as a container listener happens in // addToHierarchy addToHierarchyDown(getHierarchyContainer(window), window); } /** * Removes the given window from the hierarchy. * @param window the window to remove. */ private void remove(Window window) { // remove window from the map // remove the container from hierarchyMap // deregistering the listener from the window happens in window listener itself if (getRealMap().get(window) != null) { SwingHierarchyContainer windowContainer = (SwingHierarchyContainer) getHierarchyMap() .get(getRealMap().get(window)); if (windowContainer != null) { // remove the windowContainer from its parent in the hierarchy, if any SwingHierarchyContainer parentContainer = windowContainer.getParent(); if (parentContainer != null) { parentContainer.remove(windowContainer); } // Remove recursivly all hierarchy container from the maps and // remove all listener from the container of the AUT. If the window // is displayed again, the complete hierarchy is rebuilded. removeFromHierarchy(windowContainer); } else { // window is not in the hierarchy map // -> log this as an error log.error("an unmanaged window was closed: " + window); //$NON-NLS-1$ } } } /** * Investigates the given <code>component</code> for an identifier. To * obtain this identifier the name of the component and the container * hierarchy is used. * @param component the component to create an identifier for, must not be null. * @throws ComponentNotManagedException if component is null or <br> * (one of the) component(s) in the hierarchy is not managed * @return the identifier for <code>component</code> */ public IComponentIdentifier getComponentIdentifier(Component component) throws ComponentNotManagedException { checkDispatchThread(); IComponentIdentifier result = new ComponentIdentifier(); try { // fill the componentIdentifier result.setComponentClassName(component.getClass().getName()); result.setSupportedClassName( AUTServerConfiguration.getInstance().getTestableClass(component.getClass()).getName()); List hierarchy = getPathToRoot(component); result.setHierarchyNames(hierarchy); result.setNeighbours(getComponentContext(component)); HierarchyContainer container = getHierarchyContainer(component); setAlternativeDisplayName(container, component, result); if (component.equals(findBP.findComponent(result, ComponentHandler.getAutHierarchy()))) { result.setEqualOriginalFound(true); } return result; } catch (IllegalArgumentException iae) { // from getPathToRoot() log.error(iae); throw new ComponentNotManagedException("getComponentIdentifier() called for an unmanaged component: " //$NON-NLS-1$ + component, MessageIDs.E_COMPONENT_NOT_MANAGED); // let pass the ComponentNotManagedException from getPathToRoot() } } /** * {@inheritDoc} */ protected List getComponentContext(Object component) { Component comp = (Component) component; List context = new ArrayList(); if (comp.getParent() != null) { SwingHierarchyContainer parent = getHierarchyContainer(comp.getParent()); if (parent != null) { SwingHierarchyContainer[] comps = parent.getComponents(); for (int i = 0; i < comps.length; i++) { Component child = comps[i].getComponentID().getRealComponent(); if (!child.equals(comp)) { String toAdd = child.getClass().getName() + Constants.CLASS_NUMBER_SEPERATOR + 1; while (context.contains(toAdd)) { int lastCount = Integer .valueOf(toAdd .substring(toAdd.lastIndexOf(Constants.CLASS_NUMBER_SEPERATOR) + 1)) .intValue(); toAdd = child.getClass().getName() + Constants.CLASS_NUMBER_SEPERATOR + (lastCount + 1); } context.add(toAdd); } } } } return context; } /** * {@inheritDoc} */ public IComponentIdentifier[] getAllComponentId() { checkDispatchThread(); List result = new Vector(); Set keys = getHierarchyMap().keySet(); for (Iterator iter = keys.iterator(); iter.hasNext();) { Component component = ((SwingComponent) iter.next()).getRealComponent(); try { if (AUTServerConfiguration.getInstance().isSupported(component)) { result.add(getComponentIdentifier(component)); } } catch (IllegalArgumentException iae) { // from isSupported -> log log.error("hierarchy map contains null values", iae); //$NON-NLS-1$ // and continue } catch (ComponentNotManagedException e) { // from isSupported -> log log.error("component '" + component.getName() + "' not found!", e); //$NON-NLS-1$ //$NON-NLS-2$ // and continue } } return (IComponentIdentifier[]) result.toArray(new IComponentIdentifier[result.size()]); } /** * Searchs for the component in the AUT with the given * <code>componentIdentifier</code>. * @param componentIdentifier the identifier created in object mapping mode * @throws IllegalArgumentException if the given identifer is null or <br>the hierarchy is not valid: empty or containing null elements * @throws InvalidDataException if the hierarchy in the componentIdentifier does not consist of strings * @throws ComponentNotManagedException if no component could be found for the identifier * @return the instance of the component of the AUT */ public Component findComponent(IComponentIdentifier componentIdentifier) throws IllegalArgumentException, ComponentNotManagedException, InvalidDataException { Component comp = (Component) findBP.findComponent(componentIdentifier, ComponentHandler.getAutHierarchy()); if (comp != null && comp.isShowing()) { Window window = SwingUtilities.getWindowAncestor(comp); if (window != null && window.isShowing() && !window.isActive()) { window.toFront(); } return comp; } throw new ComponentNotManagedException("unmanaged component with identifier: '" //$NON-NLS-1$ + componentIdentifier.toString() + "'.", //$NON-NLS-1$ MessageIDs.E_COMPONENT_NOT_MANAGED); } /** * Returns the path from the given component to root. The List contains * Strings (the name of the components). * @param component the component to start, it's an instance from the AUT, must not be null * @throws IllegalArgumentException if component is null * @throws ComponentNotManagedException if no hierarchy conatiner exists for the component * @return the path to root, the first elements contains the root, the last element contains the component itself. */ public List getPathToRoot(Component component) throws IllegalArgumentException, ComponentNotManagedException { if (log.isInfoEnabled()) { log.info("pathToRoot called for " + component); //$NON-NLS-1$ } Validate.notNull(component, "The component must not be null"); //$NON-NLS-1$ List hierarchy = new ArrayList(); SwingHierarchyContainer parent; SwingHierarchyContainer autContainer = getHierarchyContainer(component); if (autContainer != null) { // add the name of the container itself hierarchy.add(autContainer.getName()); final String className = component.getClass().getName(); if (MappingConstants.SWING_APPLICATION_CLASSNAME.equals(className) || MappingConstants.SWING_MENU_DEFAULT_MAPPING_CLASSNAME.equals(className) || MappingConstants.SWING_MENU_CLASSNAME.equals(className)) { return hierarchy; } parent = getHierarchyContainer(component.getParent()); autContainer.setParent(parent); // prepend the name of the container up to the root container while (parent != null) { ((ArrayList) hierarchy).add(0, parent.getName()); Component compo = parent.getComponentID().getRealComponent(); parent = parent.getParent(); if (parent == null && compo != null && compo.getParent() != null) { SwingComponent comp = new SwingComponent(compo.getParent()); SwingHierarchyContainer container = new SwingHierarchyContainer(comp); name(container); parent = container; addToHierachyMap(container); } } } else { log.error("component '" + component //$NON-NLS-1$ + "' is not managed by this hierarchy"); //$NON-NLS-1$ throw new ComponentNotManagedException("unmanaged component " + component.toString(), //$NON-NLS-1$ MessageIDs.E_COMPONENT_NOT_MANAGED); } return hierarchy; } /** * Add the new component to the hierarchy. * {@inheritDoc} */ public void componentAdded(ContainerEvent event) { checkDispatchThread(); addComponent(event.getChild()); } /** * Add the new component to the hierarchy. * * @param toAdd The component to add to the hierarchy. */ private void addComponent(Component toAdd) { ClassLoader originalCL = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader()); try { // Don't add an invisible component if (!toAdd.isShowing()) { return; } Container container = toAdd.getParent(); if (log.isDebugEnabled()) { log.debug("component '" + toAdd //$NON-NLS-1$ + "' added to '" + container + "'"); //$NON-NLS-1$ //$NON-NLS-2$ } // get the hierarchy container for container, must be there! SwingHierarchyContainer hierarchyContainer = null; if (toAdd instanceof Window) { hierarchyContainer = getHierarchyContainer(toAdd); } else { hierarchyContainer = getHierarchyContainer(container); } if (hierarchyContainer == null) { // Parent container not managed at this time. // Do not clutter up the hierarchy with orphan components. return; } // create new hierarchy container for child, name, update hashtable, put // them together, if (getHierarchyContainer(toAdd) != null) { return; } // create new hierarchy container for child, name, update hashtable, put // them together, SwingHierarchyContainer hierarchyChild = new SwingHierarchyContainer(new SwingComponent(toAdd)); hierarchyContainer.add(hierarchyChild); hierarchyChild.setParent(hierarchyContainer); name(hierarchyChild); addToHierachyMap(hierarchyChild); if (toAdd instanceof Container) { Container cont = (Container) toAdd; // call addTohierachyDown() addToHierarchyDown(hierarchyChild, cont); } } finally { Thread.currentThread().setContextClassLoader(originalCL); } } /** * Remove the removed component from the hierarchy. * {@inheritDoc} */ public void componentRemoved(ContainerEvent event) { checkDispatchThread(); removeComponent(event.getChild(), event.getContainer()); } /** * Remove the removed component from the hierarchy. * * @param toRemove The component to remove from the hierarchy. * @param parent The parent of the component to remove. */ private void removeComponent(Component toRemove, Container parent) { ClassLoader originalCL = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader()); try { if (log.isDebugEnabled()) { log.debug("component '" + toRemove //$NON-NLS-1$ + "' removed from '" + parent + "'"); //$NON-NLS-1$ //$NON-NLS-2$ } // deregister as listener if (toRemove instanceof Container) { deregisterAsContainerListener((Container) toRemove); } SwingHierarchyContainer hierarchyChild = getHierarchyContainer(toRemove); // update the hierarchy if (hierarchyChild != null) { SwingHierarchyContainer hierarchyParent = hierarchyChild.getParent(); if (hierarchyParent != null) { hierarchyParent.remove(hierarchyChild); } else { // child was not in the hierarchy // -> log this is an error log.error("hierarchy structure corrupted, " //$NON-NLS-1$ + "child has no parent: " + hierarchyChild); //$NON-NLS-1$ } // remove children recursively removeFromHierarchy(hierarchyChild); } else { // child was not in the hierarchy map // -> log this as an error log.debug("an unmanaged component was removed: " + toRemove); //$NON-NLS-1$ } } finally { Thread.currentThread().setContextClassLoader(originalCL); } } /** * Register the AutHierarchy as a container listener to <code>container</code>. * @param container the container to register to */ private void registerAsContainerListener(final Container container) { Runnable registrationRunnable = new Runnable() { public void run() { if (log.isInfoEnabled()) { log.info("registering as listener to container " + container); //$NON-NLS-1$ } ContainerListener[] listener = container.getContainerListeners(); for (int i = 0; i < listener.length; i++) { if (listener[i] instanceof AUTSwingHierarchy) { return; } } container.addContainerListener(AUTSwingHierarchy.this); } }; registerListener(registrationRunnable); } /** * (De-)Registers a Swing / AWT listener, using the given {@link Runnable}. * A worker thread may be used in order to perform the (de-)registration * asynchronously, depending on how the receiver is configured. * * @param registrationRunnable The work to perform in order to * (de-)register the listener. */ private void registerListener(Runnable registrationRunnable) { if (m_syncListenerRegistration) { registrationRunnable.run(); } else { m_listenerRegistrationWorker.addWork(registrationRunnable); } } /** * remove the AutHierarchy as a container listener from <code>container</code>. * @param container the container to deregister from */ private void deregisterAsContainerListener(final Container container) { Runnable deregistrationRunnable = new Runnable() { public void run() { if (log.isInfoEnabled()) { log.info("deregistering as listener from container " + container); //$NON-NLS-1$ } container.removeContainerListener(AUTSwingHierarchy.this); } }; registerListener(deregistrationRunnable); } /** * register a window listener to <code>window</code>.<br> deregistering happens in * <code>WindowClosingListener.windowClosed()</code>. * @param window the window to register to */ private void registerAsWindowListener(final Window window) { Runnable registrationRunnable = new Runnable() { public void run() { if (log.isInfoEnabled()) { log.info("registering window listener to window " //$NON-NLS-1$ + window); } WindowListener[] listener = window.getWindowListeners(); for (int i = 0; i < listener.length; i++) { if (listener[i] instanceof WindowClosingListener) { return; } } window.addWindowListener(new WindowClosingListener()); } }; registerListener(registrationRunnable); } /** * Adds the parent(s) of the given container to the hierarchy recursivly. <br> * Recursion stops if the top level container is reached or a parent container is already known. * @param hierarchyContainer the responding SwingHierarchyContainer of container * @param container the container from the AUT */ private void addToHierarchyUp(SwingHierarchyContainer hierarchyContainer, Container container) { checkDispatchThread(); if (log.isInfoEnabled()) { log.info("addToHierarchyUp: " //$NON-NLS-1$ + hierarchyContainer + "," + container); //$NON-NLS-1$ } registerAsContainerListener(container); Container parent = container.getParent(); if (parent != null) { // root not reached SwingHierarchyContainer hierarchyParent = getHierarchyContainer(container); if (hierarchyParent == null) { // unknown SwingHierarchyContainer for parent: // create new hierarchy container, name it, // add current SwingHierarchyContainer to parent hierarchy, // update map m_hierarchyMap // register listener // recursion hierarchyParent = new SwingHierarchyContainer(new SwingComponent(parent)); hierarchyParent.add(hierarchyContainer); hierarchyContainer.setParent(hierarchyParent); name(hierarchyParent); addToHierachyMap(hierarchyParent); addToHierarchyUp(hierarchyParent, parent); } } } /** * adds the children of the given container to the hierachy. * @param hierarchyContainer the responding container (meta data) * @param container the container from the AUT, which childrens are to be added */ private void addToHierarchyDown(SwingHierarchyContainer hierarchyContainer, Container container) { checkDispatchThread(); if (log.isInfoEnabled()) { log.info("addToHierarchyDown: " + hierarchyContainer + "," + container); //$NON-NLS-1$ //$NON-NLS-2$ } registerAsContainerListener(container); Collection collection = getComponents(container); for (Iterator iter = collection.iterator(); iter.hasNext();) { final Component comp = (Component) iter.next(); // Don't add if the component is already in our hierarchy or // if it is invisible. if (getHierarchyContainer(comp) != null || !comp.isShowing()) { continue; } if (comp instanceof Window) { add((Window) comp); } else { // add the container SwingHierarchyContainer newHierarchyContainer = new SwingHierarchyContainer( new SwingComponent(comp)); name(newHierarchyContainer); // update the hash table newHierarchyContainer.setParent(hierarchyContainer); hierarchyContainer.add(newHierarchyContainer); addToHierachyMap(newHierarchyContainer); if (comp instanceof Container) { // recursivly down addToHierarchyDown(newHierarchyContainer, (Container) comp); } } } name(hierarchyContainer); } /** * removes recusivly all containers from <code>container</code><br> * <p> deregisters this from the container from AUT. <br> updates also the internal hierarchy map. * @param container the container to start */ private void removeFromHierarchy(SwingHierarchyContainer container) { if (container == null) { return; } SwingComponent autCompID = container.getComponentID(); Component autComp = autCompID.getRealComponent(); if (autComp == null) { log.error("invalid component for removal:" //$NON-NLS-1$ + autCompID.toString()); } removeFromHierachyMap(container); if (autComp instanceof Container) { deregisterAsContainerListener((Container) autComp); } Collection childs = getComponents(autComp); for (Iterator iter = childs.iterator(); iter.hasNext();) { removeFromHierarchy(getHierarchyContainer((Component) iter.next())); } } /** * Returns the hierarchy container for <code>component</code>. * @param component the component from the AUT, must no be null * @throws IllegalArgumentException if component is null * @return the hierachy container or null if the component is not yet managed */ public SwingHierarchyContainer getHierarchyContainer(Component component) throws IllegalArgumentException { Validate.notNull(component, "The component must not be null"); //$NON-NLS-1$ SwingHierarchyContainer result = null; try { SwingComponent compID = (SwingComponent) getRealMap().get(component); if (compID != null) { result = (SwingHierarchyContainer) getHierarchyMap().get(compID); } } catch (ClassCastException cce) { log.error(cce); } catch (NullPointerException npe) { log.error(npe); } return result; } /** * Names the given hierarchy container. <br> * If the managed component has a unique name, this name is used. Otherwise * a name (unique for the hierachy level) is created. * @param hierarchyContainer the SwingHierarchyContainer to name, if SwingHierarchyContainer is null, * no action is performed and no exception is thrown. */ private void name(SwingHierarchyContainer hierarchyContainer) { checkDispatchThread(); if (hierarchyContainer != null) { final Component component = hierarchyContainer.getComponentID().getRealComponent(); String compName = component.getName(); // SPECIAL HANDLING !!! ----------------------------------- if (component instanceof Dialog && compName != null && compName.startsWith("dialog")) { //$NON-NLS-1$ compName = null; } else if (component instanceof JToolBar && compName != null && compName.startsWith("Tool Bar ")) { //$NON-NLS-1$ compName = null; } // -------------------------------------------------------- SwingHierarchyContainer hierarchyParent = null; final Container parent = component.getParent(); if (parent != null) { hierarchyParent = getHierarchyContainer(parent); } if (hierarchyContainer.getName() != null && hierarchyContainer.getName().length() != 0) { return; } // isUniqueName is null safe, see description there int count = 1; String originalName = null; String newName = null; boolean newNameGenerated = (compName == null); if (compName != null) { originalName = compName; newName = compName; } if (newName == null) { while (!isUniqueName(hierarchyParent, newName, component)) { newName = createName(component, count); count++; } } else { while (!isUniqueName(hierarchyParent, newName, component)) { count++; newName = createName(originalName, count); } } hierarchyContainer.setName(newName, newNameGenerated); } } /** * Checks for uniqueness of <code>name</code> for the components in * <code>parent</code>.<br> * If parent is null every name is unique, a null name is NEVER unique. If * both parameters are null, false is returned. <br> * @param parent the hierarchy container containing the components which are checked. * @param name the name to check * @param swingComponent The component for which the name is being checked. * @return true if the name is treated as unique, false otherwise. */ private boolean isUniqueName(SwingHierarchyContainer parent, String name, Component swingComponent) { if (name == null) { return false; } if (parent == null) { return true; } SwingHierarchyContainer[] compIDs = parent.getComponents(); final int length = compIDs.length; for (int index = 0; index < length; index++) { Component childComponent = compIDs[index].getComponentID().getRealComponent(); Object childName = childComponent.getName(); if (name.equals(childName) && childComponent != swingComponent) { return false; } } for (int index = 0; index < length; index++) { if (name.equals(compIDs[index].getName())) { return false; } } return true; } /** * Returns all descendents of the given <code>component</code> * @param c a <code>component</code> value * @return a <code>collection</code> of the component's descendents or an * empty <code>collection</code> if nothing was found or <code>c</code> is null. */ private Collection getComponents(Component c) { if (c instanceof Container) { Container cont = (Container) c; List list = new ArrayList(); list.addAll(Arrays.asList(cont.getComponents())); if (c instanceof JMenu) { list.add(((JMenu) c).getPopupMenu()); } else if (c instanceof Window) { list.addAll(Arrays.asList(((Window) c).getOwnedWindows())); } else if (c instanceof JDesktopPane) { // add iconified frames, which are otherwise unreachable // for consistency, they are still considerered children of // the desktop pane. int count = cont.getComponentCount(); for (int i = 0; i < count; i++) { Component child = cont.getComponent(i); if (child instanceof JInternalFrame.JDesktopIcon) { JInternalFrame frame = ((JInternalFrame.JDesktopIcon) child).getInternalFrame(); if (frame != null) { list.add(frame); } } } } return list; } // an empty ArrayList return new ArrayList(); } /** * A window listener listening to window closed, registerd to any opened window. <br> * @author BREDEX GmbH * @created 05.10.2004 * */ private class WindowClosingListener extends WindowAdapter { /** * {@inheritDoc} */ public void windowOpened(WindowEvent e) { windowActivated(e); } /** * {@inheritDoc} */ public void windowClosed(final WindowEvent event) { Runnable deregistrationRunnable = new Runnable() { public void run() { ClassLoader originalCL = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader( ((SwingAUTServer) AUTServer.getInstance()).getClass().getClassLoader()); try { Window window = event.getWindow(); remove(window); if (log.isInfoEnabled()) { log.info("deregistering window listener from window " + window); //$NON-NLS-1$ } window.removeWindowListener(WindowClosingListener.this); } finally { Thread.currentThread().setContextClassLoader(originalCL); } } }; registerListener(deregistrationRunnable); } /** * {@inheritDoc} */ public void windowDeactivated(WindowEvent e) { ClassLoader originalCL = Thread.currentThread().getContextClassLoader(); Thread.currentThread() .setContextClassLoader(((SwingAUTServer) AUTServer.getInstance()).getClass().getClassLoader()); try { Window window = e.getWindow(); if (!window.isVisible()) { remove(window); } } finally { Thread.currentThread().setContextClassLoader(originalCL); } } /** * {@inheritDoc} */ public void windowActivated(WindowEvent e) { ClassLoader originalCL = Thread.currentThread().getContextClassLoader(); Thread.currentThread() .setContextClassLoader(((SwingAUTServer) AUTServer.getInstance()).getClass().getClassLoader()); try { Window window = e.getWindow(); if (window.isVisible() && getHierarchyContainer(window) == null) { add(window); } } finally { Thread.currentThread().setContextClassLoader(originalCL); } } } /** * {@inheritDoc} */ public void componentHidden(ComponentEvent e) { checkDispatchThread(); if (e.getComponent() instanceof Window) { remove((Window) e.getComponent()); } else { removeComponent(e.getComponent(), e.getComponent().getParent()); } } /** * {@inheritDoc} */ public void componentMoved(ComponentEvent e) { // Do nothing } /** * {@inheritDoc} */ public void componentResized(ComponentEvent e) { // Do nothing } /** * {@inheritDoc} */ public void componentShown(ComponentEvent e) { checkDispatchThread(); if (e.getComponent() instanceof Window) { add((Window) e.getComponent()); } else { addComponent(e.getComponent()); } } /** * Checks whether the current thread is the dispatch thread, and logs an * error if it is not. */ private void checkDispatchThread() { if (!EventQueue.isDispatchThread()) { // throw and catch an exception so we can get a stack trace try { throw new Exception(); } catch (Exception e) { log.error( "Method called outside of the dispatch thread. This may indicate a potential error in the AUT.", //$NON-NLS-1$ e); } } } }