org.assertj.swing.monitor.Context Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of assertj-swing Show documentation
Show all versions of assertj-swing Show documentation
Fluent interface for functional GUI testing
/*
* Created on Oct 14, 2007
*
* Licensed 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.
*
* Copyright @2007-2013 the original author or authors.
*/
package org.assertj.swing.monitor;
import static org.assertj.core.util.Lists.newArrayList;
import static org.assertj.core.util.Sets.newLinkedHashSet;
import static org.assertj.swing.edt.GuiActionRunner.execute;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Frame;
import java.awt.Toolkit;
import java.awt.Window;
import java.util.Collection;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import org.assertj.swing.annotation.RunsInEDT;
import org.assertj.swing.edt.GuiQuery;
/**
* Monitor that maps event queues to GUI components and GUI components to event event queues.
*
* @author Alex Ruiz
*/
@ThreadSafe
class Context {
/** Maps unique event queues to the set of root windows found on each queue. */
@GuardedBy("lock")
private final WindowEventQueueMapping windowEventQueueMapping;
/** Maps components to their corresponding event queues. */
@GuardedBy("lock")
private final EventQueueMapping eventQueueMapping;
private final Object lock = new Object();
Context(@Nonnull Toolkit toolkit) {
this(toolkit, new WindowEventQueueMapping(), new EventQueueMapping());
}
Context(@Nonnull Toolkit toolkit, @Nonnull WindowEventQueueMapping windowEventQueueMapping,
@Nonnull EventQueueMapping eventQueueMapping) {
this.windowEventQueueMapping = windowEventQueueMapping;
this.eventQueueMapping = eventQueueMapping;
this.windowEventQueueMapping.addQueueFor(toolkit);
}
/**
* Return all available root {@code Window}s. A root {@code Window} is one that has a {@code null} parent. Nominally
* this means a list similar to that returned by {@code Frame.getFrames()}, but in the case of an {@code Applet} may
* return a few dialogs as well.
*
* @return all available root {@code Window}s.
*/
@Nonnull
Collection rootWindows() {
Set rootWindows = newLinkedHashSet();
synchronized (lock) {
rootWindows.addAll(windowEventQueueMapping.windows());
}
rootWindows.addAll(newArrayList(Frame.getFrames()));
rootWindows.addAll(newArrayList(Window.getOwnerlessWindows()));
return rootWindows;
}
@Nullable
EventQueue storedQueueFor(@Nonnull Component c) {
synchronized (lock) {
return eventQueueMapping.storedQueueFor(c);
}
}
void removeContextFor(@Nonnull Component component) {
synchronized (lock) {
windowEventQueueMapping.removeMappingFor(component);
}
}
void addContextFor(@Nonnull Component component) {
synchronized (lock) {
windowEventQueueMapping.addQueueFor(component);
eventQueueMapping.addQueueFor(component);
}
}
/**
* Return the event queue corresponding to the given AWT or Swing {@code Component}. In most cases, this is the same
* as {@link java.awt.Toolkit#getSystemEventQueue()}, but in the case of applets will bypass the {@code AppContext}
* and provide the real event queue.
*
* @param c the given {@code Component}.
* @return the event queue corresponding to the given {@code Component}.
*/
@RunsInEDT
@Nullable
EventQueue eventQueueFor(@Nonnull Component c) {
Component component = topParentOf(c);
if (component == null) {
return null;
}
synchronized (lock) {
return eventQueueMapping.queueFor(component);
}
}
@RunsInEDT
private static @Nullable Component topParentOf(final @Nonnull Component c) {
return execute(new GuiQuery() {
@Override
protected @Nullable Component executeInEDT() {
Component parent = c;
// Components above the applet in the hierarchy may or may not share the same context with the applet itself.
while (!(parent instanceof java.applet.Applet) && parent.getParent() != null) {
parent = parent.getParent();
}
return parent;
}
});
}
/**
* @return all known event queues.
*/
@Nonnull
Collection allEventQueues() {
Set eventQueues = newLinkedHashSet();
synchronized (lock) {
eventQueues.addAll(windowEventQueueMapping.eventQueues());
eventQueues.addAll(eventQueueMapping.eventQueues());
}
return eventQueues;
}
}