blob: 30deab4dd9629868f1cc76a9d63bfa25641c9589 [file] [log] [blame]
/*
* 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.apache.pivot.wtk;
import java.net.URL;
import java.util.Iterator;
import org.apache.pivot.beans.DefaultProperty;
import org.apache.pivot.collections.ArrayList;
import org.apache.pivot.collections.HashMap;
import org.apache.pivot.collections.Sequence;
import org.apache.pivot.util.ImmutableIterator;
import org.apache.pivot.util.ListenerList;
import org.apache.pivot.util.Utils;
import org.apache.pivot.util.Vote;
import org.apache.pivot.wtk.media.Image;
/**
* Top-level container representing the entry point into a user interface.
* Windows are direct descendants of the display.
*/
@DefaultProperty("content")
public class Window extends Container {
/**
* Window skin interface.
*/
public interface Skin extends org.apache.pivot.wtk.Skin {
public Bounds getClientArea();
}
/**
* Class representing a mapping from keystrokes to actions.
*/
public static class ActionMapping {
private Window window = null;
private Keyboard.KeyStroke keyStroke = null;
private Action action = null;
public ActionMapping() {
}
public ActionMapping(Keyboard.KeyStroke keyStroke, Action action) {
setKeyStroke(keyStroke);
setAction(action);
}
public ActionMapping(Keyboard.KeyStroke keyStroke, String actionID) {
setKeyStroke(keyStroke);
setAction(actionID);
}
public Window getWindow() {
return window;
}
public Keyboard.KeyStroke getKeyStroke() {
return keyStroke;
}
public void setKeyStroke(Keyboard.KeyStroke keyStroke) {
Keyboard.KeyStroke previousKeyStroke = this.keyStroke;
if (keyStroke != previousKeyStroke) {
if (window != null) {
Utils.checkNull(keyStroke, "keyStroke");
if (window.actionMap.containsKey(keyStroke)) {
throw new IllegalArgumentException("A mapping for " + keyStroke
+ " already exists.");
}
if (previousKeyStroke != null) {
window.actionMap.remove(previousKeyStroke);
}
window.actionMap.put(keyStroke, action);
window.windowActionMappingListeners.keyStrokeChanged(this, previousKeyStroke);
}
this.keyStroke = keyStroke;
}
}
public void setKeyStroke(String keyStroke) {
Utils.checkNull(keyStroke, "keyStroke");
setKeyStroke(Keyboard.KeyStroke.decode(keyStroke));
}
public Action getAction() {
return action;
}
public void setAction(Action action) {
Action previousAction = this.action;
if (action != previousAction) {
if (window != null) {
Utils.checkNull(action, "action");
window.actionMap.put(keyStroke, action);
window.windowActionMappingListeners.actionChanged(this, previousAction);
}
this.action = action;
}
}
public void setAction(String actionID) {
Utils.checkNull(actionID, "actionID");
Action actionLocal = Action.getNamedActions().get(actionID);
if (actionLocal == null) {
throw new IllegalArgumentException("An action with ID " + actionID
+ " does not exist.");
}
setAction(actionLocal);
}
}
public class ActionMappingSequence implements Sequence<ActionMapping> {
@Override
public int add(ActionMapping actionMapping) {
if (actionMapping.window != null) {
throw new IllegalArgumentException("Action mapping already has a window.");
}
if (actionMapping.keyStroke == null) {
throw new IllegalArgumentException("Keystroke is undefined.");
}
if (actionMapping.action == null) {
throw new IllegalArgumentException("Action is undefined.");
}
if (actionMap.containsKey(actionMapping.keyStroke)) {
throw new IllegalArgumentException("A mapping for " + actionMapping.keyStroke
+ " already exists.");
}
actionMapping.window = Window.this;
int index = actionMappings.add(actionMapping);
actionMap.put(actionMapping.keyStroke, actionMapping.action);
windowActionMappingListeners.actionMappingAdded(Window.this);
return index;
}
@Override
public void insert(ActionMapping actionMapping, int index) {
throw new UnsupportedOperationException();
}
@Override
public ActionMapping update(int index, ActionMapping actionMapping) {
throw new UnsupportedOperationException();
}
@Override
public int remove(ActionMapping actionMapping) {
int index = indexOf(actionMapping);
if (index >= 0) {
remove(index, 1);
}
return index;
}
@Override
public Sequence<ActionMapping> remove(int index, int count) {
Sequence<ActionMapping> removed = actionMappings.remove(index, count);
for (int i = 0, n = removed.getLength(); i < n; i++) {
ActionMapping actionMapping = removed.get(i);
actionMapping.window = null;
actionMap.remove(actionMapping.keyStroke);
}
windowActionMappingListeners.actionMappingsRemoved(Window.this, index, removed);
return removed;
}
@Override
public ActionMapping get(int index) {
return actionMappings.get(index);
}
@Override
public int indexOf(ActionMapping actionMapping) {
return actionMappings.indexOf(actionMapping);
}
@Override
public int getLength() {
return actionMappings.getLength();
}
}
public class IconImageSequence implements Sequence<Image>, Iterable<Image> {
@Override
public int add(Image image) {
int index = iconImageList.add(image);
windowListeners.iconAdded(Window.this, image);
return index;
}
@Override
public void insert(Image image, int index) {
iconImageList.insert(image, index);
windowListeners.iconInserted(Window.this, image, index);
}
@Override
public Image update(int index, Image image) {
throw new UnsupportedOperationException();
}
@Override
public int remove(Image image) {
int index = indexOf(image);
if (index >= 0) {
remove(index, 1);
}
return index;
}
@Override
public Sequence<Image> remove(int index, int count) {
Sequence<Image> removed = iconImageList.remove(index, count);
windowListeners.iconsRemoved(Window.this, index, removed);
return removed;
}
@Override
public Image get(int index) {
return iconImageList.get(index);
}
@Override
public int indexOf(Image image) {
return iconImageList.indexOf(image);
}
@Override
public int getLength() {
return iconImageList.getLength();
}
@Override
public Iterator<Image> iterator() {
return new ImmutableIterator<>(iconImageList.iterator());
}
}
private static class WindowListenerList extends WTKListenerList<WindowListener> implements
WindowListener {
@Override
public void titleChanged(Window window, String previousTitle) {
for (WindowListener listener : this) {
listener.titleChanged(window, previousTitle);
}
}
@Override
public void iconAdded(Window window, Image addedIcon) {
for (WindowListener listener : this) {
listener.iconAdded(window, addedIcon);
}
}
@Override
public void iconInserted(Window window, Image addedIcon, int index) {
for (WindowListener listener : this) {
listener.iconInserted(window, addedIcon, index);
}
}
@Override
public void iconsRemoved(Window window, int index, Sequence<Image> removed) {
for (WindowListener listener : this) {
listener.iconsRemoved(window, index, removed);
}
}
@Override
public void contentChanged(Window window, Component previousContent) {
for (WindowListener listener : this) {
listener.contentChanged(window, previousContent);
}
}
@Override
public void activeChanged(Window window, Window obverseWindow) {
for (WindowListener listener : this) {
listener.activeChanged(window, obverseWindow);
}
}
@Override
public void maximizedChanged(Window window) {
for (WindowListener listener : this) {
listener.maximizedChanged(window);
}
}
}
private static class WindowStateListenerList extends WTKListenerList<WindowStateListener>
implements WindowStateListener {
@Override
public void windowOpened(Window window) {
for (WindowStateListener listener : this) {
listener.windowOpened(window);
}
}
@Override
public Vote previewWindowClose(Window window) {
Vote vote = Vote.APPROVE;
for (WindowStateListener listener : this) {
vote = vote.tally(listener.previewWindowClose(window));
}
return vote;
}
@Override
public void windowCloseVetoed(Window window, Vote reason) {
for (WindowStateListener listener : this) {
listener.windowCloseVetoed(window, reason);
}
}
@Override
public Vote previewWindowOpen(Window window) {
Vote vote = Vote.APPROVE;
for (WindowStateListener listener : this) {
vote = vote.tally(listener.previewWindowOpen(window));
}
return vote;
}
@Override
public void windowOpenVetoed(Window window, Vote reason) {
for (WindowStateListener listener : this) {
listener.windowOpenVetoed(window, reason);
}
}
@Override
public void windowClosed(Window window, Display display, Window owner) {
for (WindowStateListener listener : this) {
listener.windowClosed(window, display, owner);
}
}
}
private static class WindowActionMappingListenerList extends
WTKListenerList<WindowActionMappingListener> implements WindowActionMappingListener {
@Override
public void actionMappingAdded(Window window) {
for (WindowActionMappingListener listener : this) {
listener.actionMappingAdded(window);
}
}
@Override
public void actionMappingsRemoved(Window window, int index,
Sequence<Window.ActionMapping> removed) {
for (WindowActionMappingListener listener : this) {
listener.actionMappingsRemoved(window, index, removed);
}
}
@Override
public void keyStrokeChanged(Window.ActionMapping actionMapping,
Keyboard.KeyStroke previousKeyStroke) {
for (WindowActionMappingListener listener : this) {
listener.keyStrokeChanged(actionMapping, previousKeyStroke);
}
}
@Override
public void actionChanged(Window.ActionMapping actionMapping, Action previousAction) {
for (WindowActionMappingListener listener : this) {
listener.actionChanged(actionMapping, previousAction);
}
}
}
private static class WindowClassListenerList extends WTKListenerList<WindowClassListener>
implements WindowClassListener {
@Override
public void activeWindowChanged(Window previousActiveWindow) {
for (WindowClassListener listener : this) {
listener.activeWindowChanged(previousActiveWindow);
}
}
}
private Window owner = null;
private ArrayList<Window> ownedWindows = new ArrayList<>();
private ArrayList<ActionMapping> actionMappings = new ArrayList<>();
private ActionMappingSequence actionMappingSequence = new ActionMappingSequence();
private HashMap<Keyboard.KeyStroke, Action> actionMap = new HashMap<>();
private String title = null;
private ArrayList<Image> iconImageList = new ArrayList<>();
private IconImageSequence iconImageSequence = new IconImageSequence();
private Component content = null;
private Component focusDescendant = null;
private boolean opening = false;
private boolean closing = false;
private Point restoreLocation = null;
private WindowListenerList windowListeners = new WindowListenerList();
private WindowStateListenerList windowStateListeners = new WindowStateListenerList();
private WindowActionMappingListenerList windowActionMappingListeners = new WindowActionMappingListenerList();
private static WindowClassListenerList windowClassListeners = new WindowClassListenerList();
private static Window activeWindow = null;
public Window() {
this(null);
}
public Window(Component content) {
setContent(content);
installSkin(Window.class);
}
@Override
protected void setParent(Container parent) {
if (parent != null && (!(parent instanceof Display))) {
throw new IllegalArgumentException("Window parent must be null or display, cannot be "
+ parent);
}
if (parent == null && isActive()) {
clearActive();
}
super.setParent(parent);
}
@Override
public Sequence<Component> remove(int index, int count) {
for (int i = index, n = index + count; i < n; i++) {
Component component = get(i);
if (component == content) {
throw new UnsupportedOperationException();
}
}
// Call the base method to remove the components
return super.remove(index, count);
}
@Override
public void setVisible(boolean visible) {
if (visible && owner != null && !owner.isVisible()) {
throw new IllegalStateException("Owner is not visible.");
}
super.setVisible(visible);
if (visible && isActive()) {
clearActive();
}
for (Window ownedWindow : ownedWindows) {
ownedWindow.setVisible(visible);
}
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
if (!enabled && isActive()) {
clearActive();
}
}
public Window getOwner() {
return owner;
}
public Window getRootOwner() {
return (owner == null) ? this : owner.getRootOwner();
}
public Window getOwnedWindow(int index) {
return ownedWindows.get(index);
}
public int getOwnedWindowCount() {
return ownedWindows.getLength();
}
/**
* Tests whether this window is an owning ancestor of a given window. A
* window is not considered an owner of itself.
*
* @param window The window which could be an owned descendant of this window.
* @return <tt>true</tt> if this window is an owning ancestor of the given
* window; <tt>false</tt>, otherwise.
*/
public boolean isOwner(Window window) {
Utils.checkNull(window, "window");
Window ownerLocal = window.getOwner();
while (ownerLocal != null && ownerLocal != this) {
ownerLocal = ownerLocal.getOwner();
}
return (ownerLocal == this);
}
/**
* Returns this window's open state.
*
* @return <tt>true</tt> if the window is open; <tt>false</tt>, otherwise.
*/
public boolean isOpen() {
return (getParent() != null);
}
/**
* Returns this window's opening state.
*
* @return <tt>true</tt> if the window is opening; <tt>false</tt>,
* otherwise.
*/
public boolean isOpening() {
return opening;
}
/**
* Opens the window.
*
* @param display The display on which to open this window.
*/
public final void open(Display display) {
open(display, null);
}
/**
* Opens the window.
*
* @param ownerArgument The window's owner. The window is opened on the
* owner's display.
* @throws IllegalArgumentException if the owner argument is {@code null}.
*/
public final void open(Window ownerArgument) {
Utils.checkNull(ownerArgument, "owner");
open(ownerArgument.getDisplay(), ownerArgument);
}
/**
* Opens the window. <p> Note that this method is not a synchronous call, it
* schedules an event to open the window.
*
* @param display The display on which the window will be opened.
* @param ownerArgument The window's owner, or <tt>null</tt> if the window
* has no owner.
*/
public void open(Display display, Window ownerArgument) {
Utils.checkNull(display, "display");
if (ownerArgument != null) {
if (!ownerArgument.isOpen()) {
throw new IllegalArgumentException("owner is not open.");
}
if (isOwner(ownerArgument)) {
throw new IllegalArgumentException("owner is an owned descendant of this window.");
}
}
if (isOpen()) {
if (getDisplay() != display) {
throw new IllegalStateException("Window is already open on a different display.");
}
if (this.owner != ownerArgument) {
throw new IllegalStateException("Window is already open with a different owner.");
}
}
if (!isOpen()) {
opening = true;
Vote vote = windowStateListeners.previewWindowOpen(this);
if (vote == Vote.APPROVE) {
// Set the owner and add to the owner's owned window list
this.owner = ownerArgument;
if (ownerArgument != null) {
ownerArgument.ownedWindows.add(this);
}
// Add the window to the display
display.add(this);
// Notify listeners
opening = false;
windowStateListeners.windowOpened(this);
moveToFront();
} else {
if (vote == Vote.DENY) {
opening = false;
}
windowStateListeners.windowOpenVetoed(this, vote);
}
}
}
/**
* Returns this window's closed state.
*
* @return <tt>true</tt> if the window is closed; <tt>false</tt>, otherwise.
*/
public boolean isClosed() {
return !isOpen();
}
/**
* Returns this window's closing state.
*
* @return <tt>true</tt> if the window is closing; <tt>false</tt>,
* otherwise.
*/
public boolean isClosing() {
return closing;
}
/**
* Closes the window and all of its owned windows. If any owned window fails
* to close, this window will also fail to close.
*/
public void close() {
if (!isClosed()) {
closing = true;
// Close all owned windows (create a copy of the owned window
// list so owned windows can remove themselves from the list
// without interrupting the iteration)
boolean cancel = false;
for (Window ownedWindow : new ArrayList<>(this.ownedWindows)) {
ownedWindow.close();
cancel |= !(ownedWindow.isClosing() || ownedWindow.isClosed());
}
// Close this window only if all owned windows are closing or closed
// (we allow the owner to close even if an owned window is only
// reports
// that it is closing, under the assumption that it will ultimately
// close - not doing so would prevent close transitions from running
// in parallel, forcing them to run in series)
if (cancel) {
closing = false;
} else {
Vote vote = windowStateListeners.previewWindowClose(this);
if (vote == Vote.APPROVE) {
// Remove the window from the display
Display display = getDisplay();
display.remove(this);
// Clear the owner and remove from the owner's owned window
// list
Window ownerLocal = this.owner;
this.owner = null;
if (ownerLocal != null) {
ownerLocal.ownedWindows.remove(this);
}
// Notify listeners
closing = false;
windowStateListeners.windowClosed(this, display, ownerLocal);
} else {
if (vote == Vote.DENY) {
closing = false;
}
windowStateListeners.windowCloseVetoed(this, vote);
}
}
}
}
/**
* Returns the window's title.
*
* @return The pane's title, or <tt>null</tt> if no title is set.
*/
public String getTitle() {
return title;
}
/**
* Sets the window's title.
*
* @param title The new title, or <tt>null</tt> for no title.
*/
public void setTitle(String title) {
String previousTitle = this.title;
if (previousTitle != title) {
this.title = title;
windowListeners.titleChanged(this, previousTitle);
}
}
/**
* @return The icons for this window.
*/
public IconImageSequence getIcons() {
return iconImageSequence;
}
/**
* Sets the window's icon by URL. <p> If the icon already exists in the
* application context resource cache, the cached value will be used.
* Otherwise, the icon will be loaded synchronously and added to the cache.
*
* @param iconURL The location of the icon to set.
*/
public void setIcon(URL iconURL) {
Utils.checkNull(iconURL, "iconURL");
Image icon = Image.loadFromCache(iconURL);
getIcons().remove(0, getIcons().getLength());
getIcons().add(icon);
}
/**
* Sets the window's icon by {@linkplain ClassLoader#getResource(String)
* resource name}.
*
* @param iconName The resource name of the icon to set.
* @see #setIcon(URL)
*/
public void setIcon(String iconName) {
Utils.checkNull(iconName, "iconName");
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
URL url = classLoader.getResource(iconName.substring(1));
if (url == null) {
throw new IllegalArgumentException("Cannot find icon resource " + iconName);
}
setIcon(url);
}
public Component getContent() {
return content;
}
public void setContent(Component content) {
Component previousContent = this.content;
if (content != previousContent) {
this.content = null;
// Remove any previous content component
if (previousContent != null) {
remove(previousContent);
}
// Add the component
if (content != null) {
insert(content, 0);
}
this.content = content;
windowListeners.contentChanged(this, previousContent);
}
}
/**
* @return The bounds of the window's client area.
*/
public Bounds getClientArea() {
Window.Skin windowSkin = (Window.Skin) getSkin();
return windowSkin.getClientArea();
}
/**
* Returns the window's active state.
*
* @return <tt>true</tt> if the window is active; <tt>false</tt>; otherwise.
*/
public boolean isActive() {
return (activeWindow == this);
}
/**
* Requests that this window become the active window.
*
* @return <tt>true</tt> if the window became active; <tt>false</tt>,
* otherwise.
*/
public boolean requestActive() {
if (isOpen() && isVisible() && isEnabled()) {
setActiveWindow(this);
}
return isActive();
}
/**
* Called to notify a window that its active state has changed.
*
* @param active The new value of the "active" state for this window.
* @param obverseWindow The "other" window (that is now in the obverse state).
*/
protected void setActive(boolean active, Window obverseWindow) {
windowListeners.activeChanged(this, obverseWindow);
}
/**
* Returns the currently active window.
*
* @return The window that is currently active, or <tt>null</tt> if no
* window is active.
*/
public static Window getActiveWindow() {
return activeWindow;
}
/**
* Sets the active window. The window must be activatable, open, and
* enabled. If the window is not currently visible, it will be made visible.
*
* @param activeWindow The window to activate, or <tt>null</tt> to clear the
* active window.
*/
private static void setActiveWindow(Window activeWindow) {
Window previousActiveWindow = Window.activeWindow;
if (previousActiveWindow != activeWindow) {
// Set the active window
Window.activeWindow = activeWindow;
// Notify the windows of the state change
if (previousActiveWindow != null) {
previousActiveWindow.setActive(false, activeWindow);
}
// Activate the window
if (activeWindow != null) {
activeWindow.setActive(true, previousActiveWindow);
}
windowClassListeners.activeWindowChanged(previousActiveWindow);
}
}
/**
* Clears the active window.
*/
public static void clearActive() {
if (activeWindow != null) {
setActiveWindow(activeWindow.owner);
}
}
/**
* @return The window descendant to which focus will be restored when this
* window is moved to the front.
*/
public Component getFocusDescendant() {
return focusDescendant;
}
/**
* Clears the window descendant to which focus will be restored when this
* window is moved to the front, meaning that when this window is moved to
* front, focus will not be restored to the window.
*/
public void clearFocusDescendant() {
focusDescendant = null;
}
@Override
protected void descendantGainedFocus(Component descendant, Component previousFocusedComponent) {
this.focusDescendant = descendant;
super.descendantGainedFocus(descendant, previousFocusedComponent);
}
@Override
protected void descendantRemoved(Component descendant) {
super.descendantRemoved(descendant);
if (descendant == focusDescendant) {
focusDescendant = null;
}
}
/**
* @return The action mappings for this window.
*/
public ActionMappingSequence getActionMappings() {
return actionMappingSequence;
}
/**
* Determines if this is the top-most window.
*
* @return {@code true} if this window is at the top of the Z-order of its display.
*/
public boolean isTopMost() {
Display display = getDisplay();
return display.get(display.getLength() - 1) == this;
}
/**
* Determines if this is the bottom-most window.
*
* @return {@code true} if this window is at the bottom of the Z-order of its display.
*/
public boolean isBottomMost() {
Display display = getDisplay();
return display.get(0) == this;
}
/**
* Moves the window to the top of the window stack. All owned windows are
* subsequently moved to the front, ensuring that this window's owned
* windows remain on top of it. If the window does not have any owned
* windows, focus is restored to it.
*/
public void moveToFront() {
if (!isOpen()) {
throw new IllegalStateException("Window is not open.");
}
// If this window is not currently top-most, move it to the top
Display display = getDisplay();
int top = display.getLength() - 1;
int i = display.indexOf(this);
if (i < top) {
display.move(i, top);
}
int ownedWindowCount = ownedWindows.getLength();
if (ownedWindowCount == 0) {
// Restore focus
if (isShowing() && isEnabled() && focusDescendant != null) {
focusDescendant.requestFocus();
}
} else {
// Move all open owned windows to the front of this window,
// preserving the
// current z-order
ArrayList<Integer> ownedWindowIndexes = new ArrayList<>(ownedWindowCount);
for (Window ownedWindow : ownedWindows) {
if (ownedWindow.isOpen()) {
ownedWindowIndexes.add(Integer.valueOf(display.indexOf(ownedWindow)));
}
}
ArrayList.sort(ownedWindowIndexes);
ArrayList<Window> sortedOwnedWindows = new ArrayList<>(ownedWindows.getLength());
for (Integer index : ownedWindowIndexes) {
sortedOwnedWindows.add((Window) display.get(index.intValue()));
}
for (Window ownedWindow : sortedOwnedWindows) {
ownedWindow.moveToFront();
}
}
}
/**
* Moves the window to the bottom of the window stack. If the window is
* active, the active window will be cleared. If the window is the focus
* host, the focus will be cleared.
*/
public void moveToBack() {
if (!isOpen()) {
throw new IllegalStateException("Window is not open.");
}
if (isActive()) {
clearActive();
}
if (containsFocus()) {
clearFocus();
}
// Ensure that the window and all of its owning ancestors are moved
// to the back
Display display = getDisplay();
int i = display.indexOf(this);
if (i > 0) {
display.move(i, 0);
}
if (owner != null) {
owner.moveToBack();
}
}
public boolean isMaximized() {
return (restoreLocation != null);
}
public void setMaximized(boolean maximized) {
if (maximized != isMaximized()) {
if (maximized) {
restoreLocation = getLocation();
setLocation(0, 0);
} else {
setLocation(restoreLocation.x, restoreLocation.y);
restoreLocation = null;
}
invalidate();
windowListeners.maximizedChanged(this);
}
}
public void align(Bounds bounds, HorizontalAlignment horizontalAlignment,
VerticalAlignment verticalAlignment) {
align(bounds, horizontalAlignment, 0, verticalAlignment, 0);
}
public void align(Bounds bounds, HorizontalAlignment horizontalAlignment, int horizontalOffset,
VerticalAlignment verticalAlignment, int verticalOffset) {
int x = 0;
int y = 0;
Dimensions size = getSize();
if (horizontalAlignment == HorizontalAlignment.LEFT) {
x = bounds.x - size.width;
} else if (horizontalAlignment == HorizontalAlignment.RIGHT) {
x = bounds.x + bounds.width - size.width;
} else if (horizontalAlignment == HorizontalAlignment.CENTER) {
x = bounds.x + (int) Math.round((double) (bounds.width - size.width) / 2);
} else {
throw new IllegalArgumentException("Unsupported horizontal alignment.");
}
x += horizontalOffset;
if (verticalAlignment == VerticalAlignment.TOP) {
y = bounds.y - size.height;
} else if (verticalAlignment == VerticalAlignment.BOTTOM) {
y = bounds.y + bounds.height;
} else if (verticalAlignment == VerticalAlignment.CENTER) {
y = bounds.y + (int) Math.round((double) (bounds.height - size.height) / 2);
} else {
throw new IllegalArgumentException("Unsupported vertical alignment.");
}
y += verticalOffset;
setLocation(x, y);
}
@Override
public boolean keyPressed(int keyCode, Keyboard.KeyLocation keyLocation) {
/*
* Use keyPressed rather than keyReleased other this sequence: Press
* Ctrl, Press C, Release Ctrl, Release C will not trigger the Ctrl-C
* action.
*/
boolean consumed = super.keyPressed(keyCode, keyLocation);
// Perform any action defined for this keystroke
// in the active window's action dictionary
Keyboard.KeyStroke keyStroke = new Keyboard.KeyStroke(keyCode, Keyboard.getModifiers());
Action action = actionMap.get(keyStroke);
if (action != null && action.isEnabled()) {
action.perform(this);
}
return consumed;
}
public ListenerList<WindowListener> getWindowListeners() {
return windowListeners;
}
public ListenerList<WindowStateListener> getWindowStateListeners() {
return windowStateListeners;
}
public ListenerList<WindowActionMappingListener> getWindowActionMappingListeners() {
return windowActionMappingListeners;
}
public static ListenerList<WindowClassListener> getWindowClassListeners() {
return windowClassListeners;
}
}