/******************************************************************************* * Breakout Cave Survey Visualizer * * Copyright (C) 2014 James Edwards * * jedwards8 at fastmail dot fm * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *******************************************************************************/ package org.andork.ui.test; import java.awt.AWTEvent; import java.awt.Toolkit; import java.awt.event.AWTEventListener; import javax.swing.SwingUtilities; import javax.swing.plaf.basic.ComboPopup; /** * "Nabs" something (generally a component) found from an AWT event. This is a * brute force process using an {@link AWTEventListener}, hence the term "nab". * II invented it to find {@link ComboPopup}s for automated testing, since I * wasn't aware of any other way. * * @author andy.edwards * * @param <C> * the type of object to be nabbed */ public abstract class AWTNabber<C> { private class Listener implements AWTEventListener { @Override public void eventDispatched(AWTEvent event) { final C nabbed = nab(event); if (nabbed != null) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { setNabbed(nabbed); Toolkit.getDefaultToolkit().removeAWTEventListener(Listener.this); } }); } } } private final Object lock = new Object(); private final Listener listener = new Listener(); private boolean listening = false; private C nabbed; private long eventMask = AWTEvent.FOCUS_EVENT_MASK | AWTEvent.PAINT_EVENT_MASK | AWTEvent.COMPONENT_EVENT_MASK; /** * Gets the nabbed object, blocking if necessary until something is nabbed. * * @return the nabbed object. * @throws InterruptedException * if the calling thread was interrupted while waiting for * something to be nabbed. */ public C getNabbed() throws InterruptedException { C result; synchronized (lock) { if (!listening) { throw new IllegalStateException("Not currently listening"); } while (this.nabbed == null) { lock.wait(); } result = this.nabbed; listening = false; } return result; } /** * Nabs something found via an {@link AWTEvent}, for example the list of a * {@code ComboPopup}. * * @param event * the event to nab from. * @return the nabbed object, or {@code null} if nothing was nabbed from the * given event. */ protected abstract C nab(AWTEvent event); private void setNabbed(C result) { synchronized (lock) { this.nabbed = result; lock.notifyAll(); } } /** * Starts listening to {@link AWTEvent}s and looking for a result with * {@link #nab(AWTEvent)}. Once {@code nab()} returns a non-null value, it * will be saved and the {@link AWTEventListener} will be removed. */ public void startNabbing() { synchronized (lock) { if (listening) { throw new IllegalStateException("Already listening"); } listening = true; nabbed = null; } Toolkit.getDefaultToolkit().addAWTEventListener(listener, eventMask); } }