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

org.apache.pivot.wtk.Component 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.apache.pivot.wtk;

import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.util.Iterator;

import org.apache.pivot.beans.BeanAdapter;
import org.apache.pivot.beans.IDProperty;
import org.apache.pivot.beans.PropertyNotFoundException;
import org.apache.pivot.collections.ArrayList;
import org.apache.pivot.collections.Dictionary;
import org.apache.pivot.collections.HashMap;
import org.apache.pivot.collections.LinkedList;
import org.apache.pivot.collections.Map;
import org.apache.pivot.collections.Sequence;
import org.apache.pivot.json.JSONSerializer;
import org.apache.pivot.serialization.SerializationException;
import org.apache.pivot.util.ImmutableIterator;
import org.apache.pivot.util.ListenerList;
import org.apache.pivot.wtk.effects.Decorator;

/**
 * Top level abstract base class for all components. In MVC terminology, a
 * component represents the "controller". It has no inherent visual
 * representation and acts as an intermediary between the component's data (the
 * "model") and the skin, an implementation of {@link Skin} which serves as
 * the "view".
 */
@IDProperty("name")
public abstract class Component implements ConstrainedVisual {
    /**
     * Style dictionary implementation.
     */
    public final class StyleDictionary implements Dictionary, Iterable {
        private StyleDictionary() {
        }

        @Override
        public Object get(String key) {
            return styles.get(key);
        }

        /**
         * Stores the supplied value for the specified style.

* * NOTE The current implementation always returns * null due to the use of BeanAdapter to set the the new * value. (BeanAdapter does not look up the previous value for * performance reasons)

* * This also means that the logic determining whether to fire the the * event differs from other Pivot event firing code. The event will be * fired each time this method is executed, regardless of whether the * new value differs from the old value or not.

* * This behaviour may change in the future so should not be relied upon. * * @param key Style whose value will be overwritten * @param value Value to be stored * @return The previous value of the specified style (See note above) * @see BeanAdapter#put(String, Object) */ @Override public Object put(String key, Object value) { Object previousValue = null; try { previousValue = styles.put(key, value); componentStyleListeners.styleUpdated(Component.this, key, previousValue); } catch(PropertyNotFoundException exception) { System.err.println("\"" + key + "\" is not a valid style for " + Component.this); } return previousValue; } @Override public Object remove(String key) { throw new UnsupportedOperationException(); } @Override public boolean containsKey(String key) { return styles.containsKey(key); } public boolean isReadOnly(String key) { return styles.isReadOnly(key); } public Class getType(String key) { return styles.getType(key); } @Override public Iterator iterator() { return new ImmutableIterator(styles.iterator()); } } /** * User data dictionary implementation. */ public final class UserDataDictionary implements Dictionary, Iterable { private UserDataDictionary() { } @Override public Object get(String key) { return userData.get(key); } @Override public Object put(String key, Object value) { boolean update = userData.containsKey(key); Object previousValue = userData.put(key, value); if (update) { componentDataListeners.valueUpdated(Component.this, key, previousValue); } else { componentDataListeners.valueAdded(Component.this, key); } return previousValue; } @Override public Object remove(String key) { Object previousValue; if (userData.containsKey(key)) { previousValue = userData.remove(key); componentDataListeners.valueRemoved(Component.this, key, previousValue); } else { previousValue = null; } return previousValue; } @Override public boolean containsKey(String key) { return userData.containsKey(key); } @Override public Iterator iterator() { return new ImmutableIterator(userData.iterator()); } } /** * Decorator sequence implementation. */ public final class DecoratorSequence implements Sequence, Iterable { @Override public int add(Decorator decorator) { int index = getLength(); insert(decorator, index); return index; } @Override public void insert(Decorator decorator, int index) { if (decorator == null) { throw new IllegalArgumentException("decorator is null"); } // Repaint the the component's previous decorated region if (parent != null) { parent.repaint(getDecoratedBounds()); } decorators.insert(decorator, index); // Repaint the the component's current decorated region if (parent != null) { parent.repaint(getDecoratedBounds()); } componentDecoratorListeners.decoratorInserted(Component.this, index); } @Override public Decorator update(int index, Decorator decorator) { if (decorator == null) { throw new IllegalArgumentException("decorator is null."); } // Repaint the the component's previous decorated region if (parent != null) { parent.repaint(getDecoratedBounds()); } Decorator previousDecorator = decorators.update(index, decorator); // Repaint the the component's current decorated region if (parent != null) { parent.repaint(getDecoratedBounds()); } componentDecoratorListeners.decoratorUpdated(Component.this, index, previousDecorator); return previousDecorator; } @Override public int remove(Decorator decorator) { int index = indexOf(decorator); if (index != -1) { remove(index, 1); } return index; } @Override public Sequence remove(int index, int count) { if (count > 0) { // Repaint the the component's previous decorated region if (parent != null) { parent.repaint(getDecoratedBounds()); } } Sequence removed = decorators.remove(index, count); if (count > 0) { if (parent != null) { // Repaint the the component's current decorated region parent.repaint(getDecoratedBounds()); } componentDecoratorListeners.decoratorsRemoved(Component.this, index, removed); } return removed; } public Sequence removeAll() { return remove(0, getLength()); } @Override public Decorator get(int index) { return decorators.get(index); } @Override public int indexOf(Decorator decorator) { return decorators.indexOf(decorator); } @Override public int getLength() { return decorators.getLength(); } @Override public Iterator iterator() { return new ImmutableIterator(decorators.iterator()); } } private static class ComponentListenerList extends WTKListenerList implements ComponentListener { @Override public void parentChanged(Component component, Container previousParent) { for (ComponentListener listener : this) { listener.parentChanged(component, previousParent); } } @Override public void sizeChanged(Component component, int previousWidth, int previousHeight) { for (ComponentListener listener : this) { listener.sizeChanged(component, previousWidth, previousHeight); } } @Override public void preferredSizeChanged(Component component, int previousPreferredWidth, int previousPreferredHeight) { for (ComponentListener listener : this) { listener.preferredSizeChanged(component, previousPreferredWidth, previousPreferredHeight); } } @Override public void widthLimitsChanged(Component component, int previousMinimumWidth, int previousMaximumWidth) { for (ComponentListener listener : this) { listener.widthLimitsChanged(component, previousMinimumWidth, previousMaximumWidth); } } @Override public void heightLimitsChanged(Component component, int previousMinimumHeight, int previousMaximumHeight) { for (ComponentListener listener : this) { listener.heightLimitsChanged(component, previousMinimumHeight, previousMaximumHeight); } } @Override public void locationChanged(Component component, int previousX, int previousY) { for (ComponentListener listener : this) { listener.locationChanged(component, previousX, previousY); } } @Override public void visibleChanged(Component component) { for (ComponentListener listener : this) { listener.visibleChanged(component); } } @Override public void cursorChanged(Component component, Cursor previousCursor) { for (ComponentListener listener : this) { listener.cursorChanged(component, previousCursor); } } @Override public void tooltipTextChanged(Component component, String previousTooltipText) { for (ComponentListener listener : this) { listener.tooltipTextChanged(component, previousTooltipText); } } @Override public void tooltipDelayChanged(Component component, int previousTooltipDelay) { for (ComponentListener listener : this) { listener.tooltipDelayChanged(component, previousTooltipDelay); } } @Override public void dragSourceChanged(Component component, DragSource previousDragSource) { for (ComponentListener listener : this) { listener.dragSourceChanged(component, previousDragSource); } } @Override public void dropTargetChanged(Component component, DropTarget previousDropTarget) { for (ComponentListener listener : this) { listener.dropTargetChanged(component, previousDropTarget); } } @Override public void menuHandlerChanged(Component component, MenuHandler previousMenuHandler) { for (ComponentListener listener : this) { listener.menuHandlerChanged(component, previousMenuHandler); } } @Override public void nameChanged(Component component, String previousName) { for (ComponentListener listener : this) { listener.nameChanged(component, previousName); } } } private static class ComponentStateListenerList extends WTKListenerList implements ComponentStateListener { @Override public void enabledChanged(Component component) { for (ComponentStateListener listener : this) { listener.enabledChanged(component); } } @Override public void focusedChanged(Component component, Component obverseComponent) { for (ComponentStateListener listener : this) { listener.focusedChanged(component, obverseComponent); } } } private static class ComponentDecoratorListenerList extends WTKListenerList implements ComponentDecoratorListener { @Override public void decoratorInserted(Component component, int index) { for (ComponentDecoratorListener listener : this) { listener.decoratorInserted(component, index); } } @Override public void decoratorUpdated(Component component, int index, Decorator previousDecorator) { for (ComponentDecoratorListener listener : this) { listener.decoratorUpdated(component, index, previousDecorator); } } @Override public void decoratorsRemoved(Component component, int index, Sequence decorators) { for (ComponentDecoratorListener listener : this) { listener.decoratorsRemoved(component, index, decorators); } } } private static class ComponentStyleListenerList extends WTKListenerList implements ComponentStyleListener { @Override public void styleUpdated(Component component, String styleKey, Object previousValue) { for (ComponentStyleListener listener : this) { listener.styleUpdated(component, styleKey, previousValue); } } } private static class ComponentMouseListenerList extends WTKListenerList implements ComponentMouseListener { @Override public boolean mouseMove(Component component, int x, int y) { boolean consumed = false; for (ComponentMouseListener listener : this) { consumed |= listener.mouseMove(component, x, y); } return consumed; } @Override public void mouseOver(Component component) { for (ComponentMouseListener listener : this) { listener.mouseOver(component); } } @Override public void mouseOut(Component component) { for (ComponentMouseListener listener : this) { listener.mouseOut(component); } } } private static class ComponentMouseButtonListenerList extends WTKListenerList implements ComponentMouseButtonListener { @Override public boolean mouseDown(Component component, Mouse.Button button, int x, int y) { boolean consumed = false; for (ComponentMouseButtonListener listener : this) { consumed |= listener.mouseDown(component, button, x, y); } return consumed; } @Override public boolean mouseUp(Component component, Mouse.Button button, int x, int y) { boolean consumed = false; for (ComponentMouseButtonListener listener : this) { consumed |= listener.mouseUp(component, button, x, y); } return consumed; } @Override public boolean mouseClick(Component component, Mouse.Button button, int x, int y, int count) { boolean consumed = false; for (ComponentMouseButtonListener listener : this) { consumed |= listener.mouseClick(component, button, x, y, count); } return consumed; } } private static class ComponentMouseWheelListenerList extends WTKListenerList implements ComponentMouseWheelListener { @Override public boolean mouseWheel(Component component, Mouse.ScrollType scrollType, int scrollAmount, int wheelRotation, int x, int y) { boolean consumed = false; for (ComponentMouseWheelListener listener : this) { consumed |= listener.mouseWheel(component, scrollType, scrollAmount, wheelRotation, x, y); } return consumed; } } private static class ComponentKeyListenerList extends WTKListenerList implements ComponentKeyListener { @Override public boolean keyTyped(Component component, char character) { boolean consumed = false; for (ComponentKeyListener listener : this) { consumed |= listener.keyTyped(component, character); } return consumed; } @Override public boolean keyPressed(Component component, int keyCode, Keyboard.KeyLocation keyLocation) { boolean consumed = false; for (ComponentKeyListener listener : this) { consumed |= listener.keyPressed(component, keyCode, keyLocation); } return consumed; } @Override public boolean keyReleased(Component component, int keyCode, Keyboard.KeyLocation keyLocation) { boolean consumed = false; for (ComponentKeyListener listener : this) { consumed |= listener.keyReleased(component, keyCode, keyLocation); } return consumed; } } private static class ComponentTooltipListenerList extends WTKListenerList implements ComponentTooltipListener { @Override public void tooltipTriggered(Component component, int x, int y) { for (ComponentTooltipListener listener : this) { listener.tooltipTriggered(component, x, y); } } } private static class ComponentDataListenerList extends WTKListenerList implements ComponentDataListener { @Override public void valueAdded(Component component, String key) { for (ComponentDataListener listener : this) { listener.valueAdded(component, key); } } @Override public void valueUpdated(Component component, String key, Object previousValue) { for (ComponentDataListener listener : this) { listener.valueUpdated(component, key, previousValue); } } @Override public void valueRemoved(Component component, String key, Object value) { for (ComponentDataListener listener : this) { listener.valueRemoved(component, key, value); } } } private static class ComponentClassListenerList extends WTKListenerList implements ComponentClassListener { @Override public void focusedComponentChanged(Component previousFocusedComponent) { for (ComponentClassListener listener : this) { listener.focusedComponentChanged(previousFocusedComponent); } } } // The currently installed skin, or null if no skin is installed private Skin skin = null; // Preferred width and height values explicitly set by the user private int preferredWidth = -1; private int preferredHeight = -1; // Bounds on preferred size private int minimumWidth = 0; private int maximumWidth = Integer.MAX_VALUE; private int minimumHeight = 0; private int maximumHeight = Integer.MAX_VALUE; // Calculated preferred size value private Dimensions preferredSize = null; // Calculated baseline for current size private int baseline = -1; // The component's parent container, or null if the component does not have // a parent private Container parent = null; // The component's layout-valid state private boolean valid = false; // The component's location, relative to the parent's origin private int x = 0; private int y = 0; // The component's visible flag private boolean visible = true; // The component's decorators private ArrayList decorators = new ArrayList(); private DecoratorSequence decoratorSequence = new DecoratorSequence(); // The component's enabled flag private boolean enabled = true; // The current mouse location private Point mouseLocation = null; // The cursor that is displayed over the component private Cursor cursor = null; // The tooltip text, delay, trigger callback, flag for wrapping its text private String tooltipText = null; private int tooltipDelay = 1000; private ApplicationContext.ScheduledCallback triggerTooltipCallback = null; private boolean tooltipWrapText = true; // The component's drag source private DragSource dragSource = null; // The component's drop target private DropTarget dropTarget = null; // The component's menu handler private MenuHandler menuHandler = null; // The component's name private String name = null; // The component's styles private BeanAdapter styles = null; private StyleDictionary styleDictionary = new StyleDictionary(); // User data private HashMap userData = new HashMap(); private UserDataDictionary userDataDictionary = new UserDataDictionary(); // Container attributes private HashMap, Object> attributes = null; // The component's automation ID private String automationID; // Event listener lists private ComponentListenerList componentListeners = new ComponentListenerList(); private ComponentStateListenerList componentStateListeners = new ComponentStateListenerList(); private ComponentDecoratorListenerList componentDecoratorListeners = new ComponentDecoratorListenerList(); private ComponentStyleListenerList componentStyleListeners = new ComponentStyleListenerList(); private ComponentMouseListenerList componentMouseListeners = new ComponentMouseListenerList(); private ComponentMouseButtonListenerList componentMouseButtonListeners = new ComponentMouseButtonListenerList(); private ComponentMouseWheelListenerList componentMouseWheelListeners = new ComponentMouseWheelListenerList(); private ComponentKeyListenerList componentKeyListeners = new ComponentKeyListenerList(); private ComponentTooltipListenerList componentTooltipListeners = new ComponentTooltipListenerList(); private ComponentDataListenerList componentDataListeners = new ComponentDataListenerList(); // The component that currently has the focus private static Component focusedComponent = null; // Typed and named styles private static HashMap, Map> typedStyles = new HashMap, Map>(); private static HashMap> namedStyles = new HashMap>(); // Class event listeners private static ComponentClassListenerList componentClassListeners = new ComponentClassListenerList(); /** * Returns the component's automation ID. * * @return * The component's automation ID, or null if the component does not * have an automation ID. */ public String getAutomationID() { return automationID; } /** * Sets the component's automation ID. This value can be used to obtain a * reference to the component via {@link Automation#get(String)} when the * component is attached to a component hierarchy. * * @param automationID * The automation ID to use for the component, or null to clear the * automation ID. */ public void setAutomationID(String automationID) { String previousAutomationID = this.automationID; this.automationID = automationID; if (getDisplay() != null) { if (previousAutomationID != null) { Automation.remove(previousAutomationID); } if (automationID != null) { Automation.add(automationID, this); } } } /** * Returns the currently installed skin. * * @return * The currently installed skin. */ protected Skin getSkin() { return skin; } /** * Sets the skin, replacing any previous skin. * * @param skin * The new skin. */ @SuppressWarnings("unchecked") protected void setSkin(Skin skin) { if (skin == null) { throw new IllegalArgumentException("skin is null."); } if (this.skin != null) { throw new IllegalStateException("Skin is already installed."); } this.skin = skin; styles = new BeanAdapter(skin); skin.install(this); // Apply any defined type styles LinkedList> styleTypes = new LinkedList>(); Class type = getClass(); while (type != Object.class) { styleTypes.insert(type, 0); type = type.getSuperclass(); } for (Class styleType : styleTypes) { Map stylesLocal = typedStyles.get((Class)styleType); if (stylesLocal != null) { setStyles(stylesLocal); } } invalidate(); repaint(); } /** * Installs the skin for the given component class, as defined by the current * theme. * * @param componentClass */ @SuppressWarnings("unchecked") protected void installSkin(Class componentClass) { // Walk up component hierarchy from this type; if we find a match // and the super class equals the given component class, install // the skin. Otherwise, ignore - it will be installed later by a // subclass of the component class. Class type = getClass(); Theme theme = Theme.getTheme(); Class skinClass = theme.getSkinClass((Class)type); while (skinClass == null && type != componentClass && type != Component.class) { type = type.getSuperclass(); if (type != Component.class) { skinClass = theme.getSkinClass((Class)type); } } if (type == Component.class) { throw new IllegalArgumentException(componentClass.getName() + " is not an ancestor of " + getClass().getName()); } if (skinClass == null) { throw new IllegalArgumentException("No skin mapping for " + componentClass.getName() + " found."); } if (type == componentClass) { try { setSkin(skinClass.newInstance()); } catch(InstantiationException exception) { throw new IllegalArgumentException(exception); } catch(IllegalAccessException exception) { throw new IllegalArgumentException(exception); } } } public Container getParent() { return parent; } protected void setParent(Container parent) { // If this component is being removed from the component hierarchy // and is currently focused, clear the focus if (parent == null && isFocused()) { clearFocus(); } Container previousParent = this.parent; this.parent = parent; if (previousParent != null) { previousParent.descendantRemoved(this); } if (parent != null) { parent.descendantAdded(this); } componentListeners.parentChanged(this, previousParent); } public Window getWindow() { return (Window)getAncestor(Window.class); } public Display getDisplay() { return (Display)getAncestor(Display.class); } public Container getAncestor(Class ancestorType) { Component component = this; while (component != null && !(ancestorType.isInstance(component))) { component = component.getParent(); } return (Container)component; } @SuppressWarnings("unchecked") public Container getAncestor(String ancestorTypeName) throws ClassNotFoundException { if (ancestorTypeName == null) { throw new IllegalArgumentException(); } return getAncestor((Class)Class.forName(ancestorTypeName)); } @Override public int getWidth() { return skin.getWidth(); } public void setWidth(int width) { setSize(width, getHeight()); } @Override public int getHeight() { return skin.getHeight(); } public void setHeight(int height) { setSize(getWidth(), height); } public Dimensions getSize() { return new Dimensions(this.getWidth(), this.getHeight()); } public final void setSize(Dimensions size) { if (size == null) { throw new IllegalArgumentException("size is null."); } setSize(size.width, size.height); } /** * NOTE This method should only be called during layout. Callers should * use {@link #setPreferredSize(int, int)}. * * @param width * @param height */ @Override public void setSize(int width, int height) { if (width < 0) { throw new IllegalArgumentException("width is negative."); } if (height < 0) { throw new IllegalArgumentException("height is negative."); } int previousWidth = getWidth(); int previousHeight = getHeight(); if (width != previousWidth || height != previousHeight) { // This component's size changed, most likely as a result // of being laid out; it must be flagged as invalid to ensure // that layout is propagated downward when validate() is // called on it invalidate(); // Redraw the region formerly occupied by this component if (parent != null) { parent.repaint(getDecoratedBounds()); } // Set the size of the skin skin.setSize(width, height); // Redraw the region currently occupied by this component if (parent != null) { parent.repaint(getDecoratedBounds()); } componentListeners.sizeChanged(this, previousWidth, previousHeight); } } /** * Returns the component's unconstrained preferred width. */ public int getPreferredWidth() { return getPreferredWidth(-1); } /** * Returns the component's constrained preferred width. * * @param height * The height value by which the preferred width should be constrained, or * -1 for no constraint. * * @return * The constrained preferred width. */ @Override public int getPreferredWidth(int height) { int preferredWidthLocal; if (this.preferredWidth == -1) { if (height == -1) { preferredWidthLocal = getPreferredSize().width; } else { if (preferredSize != null && preferredSize.height == height) { preferredWidthLocal = preferredSize.width; } else { Limits widthLimits = getWidthLimits(); preferredWidthLocal = widthLimits.constrain(skin.getPreferredWidth(height)); } } } else { preferredWidthLocal = this.preferredWidth; } return preferredWidthLocal; } /** * Sets the component's preferred width. * * @param preferredWidth * The preferred width value, or -1 to use the default * value determined by the skin. */ public void setPreferredWidth(int preferredWidth) { setPreferredSize(preferredWidth, preferredHeight); } /** * Returns a flag indicating whether the preferred width was explicitly * set by the caller or is the default value determined by the skin. * * @return * true if the preferred width was explicitly set; false, * otherwise. */ public boolean isPreferredWidthSet() { return (preferredWidth != -1); } /** * Returns the component's unconstrained preferred height. */ public int getPreferredHeight() { return getPreferredHeight(-1); } /** * Returns the component's constrained preferred height. * * @param width * The width value by which the preferred height should be constrained, or * -1 for no constraint. * * @return * The constrained preferred height. */ @Override public int getPreferredHeight(int width) { int preferredHeightLocal; if (this.preferredHeight == -1) { if (width == -1) { preferredHeightLocal = getPreferredSize().height; } else { if (preferredSize != null && preferredSize.width == width) { preferredHeightLocal = preferredSize.height; } else { Limits heightLimits = getHeightLimits(); preferredHeightLocal = heightLimits.constrain(skin.getPreferredHeight(width)); } } } else { preferredHeightLocal = this.preferredHeight; } return preferredHeightLocal; } /** * Sets the component's preferred height. * * @param preferredHeight * The preferred height value, or -1 to use the default * value determined by the skin. */ public void setPreferredHeight(int preferredHeight) { setPreferredSize(preferredWidth, preferredHeight); } /** * Returns a flag indicating whether the preferred height was explicitly * set by the caller or is the default value determined by the skin. * * @return * true if the preferred height was explicitly set; false, * otherwise. */ public boolean isPreferredHeightSet() { return (preferredHeight != -1); } /** * Gets the component's unconstrained preferred size. */ @Override public Dimensions getPreferredSize() { if (preferredSize == null) { Dimensions preferredSizeLocal; if (preferredWidth == -1 && preferredHeight == -1) { preferredSizeLocal = skin.getPreferredSize(); } else if (preferredWidth == -1) { preferredSizeLocal = new Dimensions(skin.getPreferredWidth(preferredHeight), preferredHeight); } else if (preferredHeight == -1) { preferredSizeLocal = new Dimensions(preferredWidth, skin.getPreferredHeight(preferredWidth)); } else { preferredSizeLocal = new Dimensions(preferredWidth, preferredHeight); } Limits widthLimits = getWidthLimits(); Limits heightLimits = getHeightLimits(); int preferredWidthLocal = widthLimits.constrain(preferredSizeLocal.width); int preferredHeightLocal = heightLimits.constrain(preferredSizeLocal.height); if (preferredSizeLocal.width > preferredWidthLocal) { preferredHeightLocal = heightLimits.constrain(skin.getPreferredHeight(preferredWidthLocal)); } if (preferredSizeLocal.height > preferredHeightLocal) { preferredWidthLocal = widthLimits.constrain(skin.getPreferredWidth(preferredHeightLocal)); } this.preferredSize = new Dimensions(preferredWidthLocal, preferredHeightLocal); } return preferredSize; } public final void setPreferredSize(Dimensions preferredSize) { if (preferredSize == null) { throw new IllegalArgumentException("preferredSize is null."); } setPreferredSize(preferredSize.width, preferredSize.height); } /** * Sets the component's preferred size. * * @param preferredWidth * The preferred width value, or -1 to use the default * value determined by the skin. * * @param preferredHeight * The preferred height value, or -1 to use the default * value determined by the skin. */ public void setPreferredSize(int preferredWidth, int preferredHeight) { if (preferredWidth < -1) { throw new IllegalArgumentException(preferredWidth + " is not a valid value for preferredWidth."); } if (preferredHeight < -1) { throw new IllegalArgumentException(preferredHeight + " is not a valid value for preferredHeight."); } int previousPreferredWidth = this.preferredWidth; int previousPreferredHeight = this.preferredHeight; if (previousPreferredWidth != preferredWidth || previousPreferredHeight != preferredHeight) { this.preferredWidth = preferredWidth; this.preferredHeight = preferredHeight; invalidate(); componentListeners.preferredSizeChanged(this, previousPreferredWidth, previousPreferredHeight); } } /** * Returns a flag indicating whether the preferred size was explicitly * set by the caller or is the default value determined by the skin. * * @return * true if the preferred size was explicitly set; false, * otherwise. */ public boolean isPreferredSizeSet() { return isPreferredWidthSet() && isPreferredHeightSet(); } /** * Returns the minimum width of this component. */ public int getMinimumWidth() { return minimumWidth; } /** * Sets the minimum width of this component. * * @param minimumWidth */ public void setMinimumWidth(int minimumWidth) { setWidthLimits(minimumWidth, getMaximumWidth()); } /** * Returns the maximum width of this component. */ public int getMaximumWidth() { return maximumWidth; } /** * Sets the maximum width of this component. * * @param maximumWidth */ public void setMaximumWidth(int maximumWidth) { setWidthLimits(getMinimumWidth(), maximumWidth); } /** * Returns the width limits for this component. */ public Limits getWidthLimits() { return new Limits(minimumWidth, maximumWidth); } /** * Sets the width limits for this component. * * @param minimumWidth * @param maximumWidth */ public void setWidthLimits(int minimumWidth, int maximumWidth) { int previousMinimumWidth = this.minimumWidth; int previousMaximumWidth = this.maximumWidth; if (previousMinimumWidth != minimumWidth || previousMaximumWidth != maximumWidth) { if (minimumWidth < 0) { throw new IllegalArgumentException("minimumWidth is negative."); } if (minimumWidth > maximumWidth) { throw new IllegalArgumentException("minimumWidth is greater than maximumWidth."); } this.minimumWidth = minimumWidth; this.maximumWidth = maximumWidth; invalidate(); componentListeners.widthLimitsChanged(this, previousMinimumWidth, previousMaximumWidth); } } /** * Sets the width limits for this component. * * @param widthLimits */ public final void setWidthLimits(Limits widthLimits) { if (widthLimits == null) { throw new IllegalArgumentException("widthLimits is null."); } setWidthLimits(widthLimits.minimum, widthLimits.maximum); } /** * Returns the minimum height of this component. */ public int getMinimumHeight() { return minimumHeight; } /** * Sets the minimum height of this component. * * @param minimumHeight */ public void setMinimumHeight(int minimumHeight) { setHeightLimits(minimumHeight, getMaximumHeight()); } /** * Returns the maximum height of this component. */ public int getMaximumHeight() { return maximumHeight; } /** * Sets the maximum height of this component. * * @param maximumHeight */ public void setMaximumHeight(int maximumHeight) { setHeightLimits(getMinimumHeight(), maximumHeight); } /** * Returns the height limits for this component. */ public Limits getHeightLimits() { return new Limits(minimumHeight, maximumHeight); } /** * Sets the height limits for this component. * * @param minimumHeight * @param maximumHeight */ public void setHeightLimits(int minimumHeight, int maximumHeight) { int previousMinimumHeight = this.minimumHeight; int previousMaximumHeight = this.maximumHeight; if (previousMinimumHeight != minimumHeight || previousMaximumHeight != maximumHeight) { if (minimumHeight < 0) { throw new IllegalArgumentException("minimumHeight is negative."); } if (minimumHeight > maximumHeight) { throw new IllegalArgumentException("minimumHeight is greater than maximumHeight."); } this.minimumHeight = minimumHeight; this.maximumHeight = maximumHeight; invalidate(); componentListeners.heightLimitsChanged(this, previousMinimumHeight, previousMaximumHeight); } } /** * Sets the height limits for this component. * * @param heightLimits */ public final void setHeightLimits(Limits heightLimits) { if (heightLimits == null) { throw new IllegalArgumentException("heightLimits is null."); } setHeightLimits(heightLimits.minimum, heightLimits.maximum); } /** * Returns the component's x-coordinate. * * @return * The component's horizontal position relative to the origin of the * parent container. */ public int getX() { return x; } /** * Sets the component's x-coordinate. * * @param x * The component's horizontal position relative to the origin of the * parent container. */ public void setX(int x) { setLocation(x, getY()); } /** * Returns the component's y-coordinate. * * @return * The component's vertical position relative to the origin of the * parent container. */ public int getY() { return y; } /** * Sets the component's y-coordinate. * * @param y * The component's vertical position relative to the origin of the * parent container. */ public void setY(int y) { setLocation(getX(), y); } /** * Returns the component's location. * * @return * A point value containing the component's horizontal and vertical * position relative to the origin of the parent container. */ public Point getLocation() { return new Point(getX(), getY()); } /** * Sets the component's location. * * NOTE This method should only be called when performing layout. * However, since some containers do not reposition components during * layout, it is valid for callers to invoke this method directly when * such containers. * * @param x * The component's horizontal position relative to the origin of the * parent container. * * @param y * The component's vertical position relative to the origin of the * parent container. */ public void setLocation(int x, int y) { int previousX = this.x; int previousY = this.y; if (previousX != x || previousY != y) { // Redraw the region formerly occupied by this component if (parent != null) { parent.repaint(getDecoratedBounds()); } // Set the new coordinates this.x = x; this.y = y; // Redraw the region currently occupied by this component if (parent != null) { parent.repaint(getDecoratedBounds()); } componentListeners.locationChanged(this, previousX, previousY); } } /** * Sets the component's location. * * @param location * A point value containing the component's horizontal and vertical * position relative to the origin of the parent container. * * @see #setLocation(int, int) */ public final void setLocation(Point location) { if (location == null) { throw new IllegalArgumentException("location cannot be null."); } setLocation(location.x, location.y); } /** * Returns the component's baseline. * * @return * The baseline relative to the origin of this component, or -1 if * this component does not have a baseline. */ @Override public int getBaseline() { if (baseline == -1) { baseline = skin.getBaseline(); } return baseline; } /** * Returns the component's baseline for a given width and height. * * @return * The baseline relative to the origin of this component, or -1 if * this component does not have a baseline. */ @Override public int getBaseline(int width, int height) { return skin.getBaseline(width, height); } /** * Returns the component's bounding area. * * @return * The component's bounding area. The x and y values are * relative to the parent container. */ public Bounds getBounds() { return new Bounds(x, y, getWidth(), getHeight()); } /** * Returns the component's bounding area including decorators. * * @return * The decorated bounding area. The x and y values are * relative to the parent container. */ public Bounds getDecoratedBounds() { Bounds decoratedBounds = new Bounds(0, 0, getWidth(), getHeight()); for (Decorator decorator : decorators) { decoratedBounds = decoratedBounds.union(decorator.getBounds(this)); } return new Bounds(decoratedBounds.x + x, decoratedBounds.y + y, decoratedBounds.width, decoratedBounds.height); } /** * Determines if the component contains a given location. This method facilitates * mouse interaction with non-rectangular components. * * @param xArgument * @param yArgument * * @return * true if the component's shape contains the given location; false, * otherwise. * * @throws UnsupportedOperationException * This method is not currently implemented. */ public boolean contains(int xArgument, int yArgument) { // TODO throw new UnsupportedOperationException(); } /** * Returns the component's visibility. * * @return * true if the component will be painted; false, * otherwise. */ public boolean isVisible() { return visible; } /** * Sets the component's visibility. * * @param visible * true if the component should be painted; false, * otherwise. */ public void setVisible(boolean visible) { if (this.visible != visible) { // If this component is being hidden and has the focus, clear // the focus if (!visible) { if (isFocused()) { clearFocus(); } // Ensure that the mouse out event is processed if (isMouseOver()) { mouseOut(); } } // Redraw the region formerly occupied by this component if (parent != null) { parent.repaint(getDecoratedBounds()); } this.visible = visible; // Redraw the region currently occupied by this component if (parent != null) { parent.repaint(getDecoratedBounds()); } // Ensure the layout is valid if (visible && !valid) { validate(); } // Invalidate the parent if (parent != null) { parent.invalidate(); } componentListeners.visibleChanged(this); } } /** * Returns the component's decorator sequence. * * @return * The component's decorator sequence */ public DecoratorSequence getDecorators() { return decoratorSequence; } /** * Maps a point in this component's coordinate system to the specified * ancestor's coordinate space. * * @param xArgument * The x-coordinate in this component's coordinate space * * @param yArgument * The y-coordinate in this component's coordinate space * * @return * A point containing the translated coordinates, or null if the * component is not a descendant of the specified ancestor. */ public Point mapPointToAncestor(final Container ancestor, int xArgument, int yArgument) { if (ancestor == null) { throw new IllegalArgumentException("ancestor is null"); } int xArgumentMutable = xArgument; int yArgumentMutable = yArgument; Point coordinates = null; Component component = this; while (component != null && coordinates == null) { if (component == ancestor) { coordinates = new Point(xArgumentMutable, yArgumentMutable); } else { xArgumentMutable += component.x; yArgumentMutable += component.y; component = component.getParent(); } } return coordinates; } /** * Maps a point in this component's coordinate system to the specified * ancestor's coordinate space. * * @param location The coordinates in this component's coordinate space * * @return * A point containing the translated coordinates, or null if the * component is not a descendant of the specified ancestor. */ public Point mapPointToAncestor(Container ancestor, Point location) { if (location == null) { throw new IllegalArgumentException(); } return mapPointToAncestor(ancestor, location.x, location.y); } /** * Maps a point in the specified ancestor's coordinate space to this * component's coordinate system. * * @param xArgument * The x-coordinate in the ancestors's coordinate space. * * @param yArgument * The y-coordinate in the ancestor's coordinate space. * * @return * A point containing the translated coordinates, or null if the * component is not a descendant of the specified ancestor. */ public Point mapPointFromAncestor(final Container ancestor, int xArgument, int yArgument) { if (ancestor == null) { throw new IllegalArgumentException("ancestor is null"); } int xArgumentMutable = xArgument; int yArgumentMutable = yArgument; Point coordinates = null; Component component = this; while (component != null && coordinates == null) { if (component == ancestor) { coordinates = new Point(xArgumentMutable, yArgumentMutable); } else { xArgumentMutable -= component.x; yArgumentMutable -= component.y; component = component.getParent(); } } return coordinates; } public Point mapPointFromAncestor(Container ancestor, Point location) { if (location == null) { throw new IllegalArgumentException(); } return mapPointFromAncestor(ancestor, location.x, location.y); } /** * Determines if this component is showing. To be showing, the component * and all of its ancestors must be visible and attached to a display. * * @return * true if this component is showing; false otherwise. */ public boolean isShowing() { Component component = this; while (component != null && component.isVisible() && !(component instanceof Display)) { component = component.getParent(); } return (component != null && component.isVisible()); } /** * Determines the visible area of a component. The visible area is defined * as the intersection of the component's area with the visible area of its * ancestors, or, in the case of a Viewport, the viewport bounds. * * @return * The visible area of the component in the component's coordinate space, or * null if the component is either not showing or not part of the * component hierarchy. */ public Bounds getVisibleArea() { return getVisibleArea(0, 0, getWidth(), getHeight()); } /** * Determines the visible area of a component. The visible area is defined * as the intersection of the component's area with the visible area of its * ancestors, or, in the case of a Viewport, the viewport bounds. * * @param area * * @return * The visible area of the component in the component's coordinate space, or * null if the component is either not showing or not part of the * component hierarchy. */ public Bounds getVisibleArea(Bounds area) { if (area == null) { throw new IllegalArgumentException("area is null."); } return getVisibleArea(area.x, area.y, area.width, area.height); } /** * Determines the visible area of a component. The visible area is defined * as the intersection of the component's area with the visible area of its * ancestors, or, in the case of a Viewport, the viewport bounds. * * @param xArgument * @param yArgument * @param width * @param height * * @return * The visible area of the component in the component's coordinate space, or * null if the component is either not showing or not part of the * component hierarchy. */ public Bounds getVisibleArea(int xArgument, int yArgument, int width, int height) { Bounds visibleArea = null; Component component = this; int top = yArgument; int left = xArgument; int bottom = yArgument + height - 1; int right = xArgument + width - 1; int xOffset = 0; int yOffset = 0; while (component != null && component.isVisible()) { int minTop = 0; int minLeft = 0; int maxBottom = component.getHeight() - 1; int maxRight = component.getWidth() - 1; if (component instanceof Viewport) { Viewport viewport = (Viewport)component; Bounds bounds = viewport.getViewportBounds(); minTop = bounds.y; minLeft = bounds.x; maxBottom = bounds.y + bounds.height - 1; maxRight = bounds.x + bounds.width - 1; } top = component.y + Math.max(top, minTop); left = component.x + Math.max(left, minLeft); bottom = component.y + Math.max(Math.min(bottom, maxBottom), -1); right = component.x + Math.max(Math.min(right, maxRight), -1); xOffset += component.x; yOffset += component.y; if (component instanceof Display) { visibleArea = new Bounds(left - xOffset, top - yOffset, right - left + 1, bottom - top + 1); } component = component.getParent(); } return visibleArea; } /** * Ensures that the given area of a component is visible within the * viewports of all applicable ancestors. * * @param area */ public void scrollAreaToVisible(Bounds area) { if (area == null) { throw new IllegalArgumentException("area is null."); } scrollAreaToVisible(area.x, area.y, area.width, area.height); } /** * Ensures that the given area of a component is visible within the * viewports of all applicable ancestors. * * @param xArgument * @param yArgument * @param width * @param height */ public void scrollAreaToVisible(int xArgument, int yArgument, int width, int height) { int xArgumentMutable = xArgument; int yArgumentMutable = yArgument; int widthMutable = width; int heightMutable = height; Component component = this; while (component != null) { if (component instanceof Viewport) { Viewport viewport = (Viewport)component; Component view = viewport.getView(); try { Bounds viewportBounds = viewport.getViewportBounds(); int deltaX = 0; int leftDisplacement = xArgumentMutable - viewportBounds.x; int rightDisplacement = (xArgumentMutable + widthMutable) - (viewportBounds.x + viewportBounds.width); if ((leftDisplacement & rightDisplacement) < 0) { // Both leftDisplacement and rightDisplacement are // negative; the area lies to the left of our viewport // bounds deltaX = Math.max(leftDisplacement, rightDisplacement); } else if ((leftDisplacement | rightDisplacement) > 0) { // Both leftDisplacement and rightDisplacement are // positive; the area lies to the right of our viewport // bounds deltaX = Math.min(leftDisplacement, rightDisplacement); } if (deltaX != 0) { int viewWidth = (view == null) ? 0 : view.getWidth(); int scrollLeft = viewport.getScrollLeft(); scrollLeft = Math.min(Math.max(scrollLeft + deltaX, 0), Math.max(viewWidth - viewportBounds.width, 0)); viewport.setScrollLeft(scrollLeft); xArgumentMutable -= deltaX; } xArgumentMutable = Math.max(xArgumentMutable, viewportBounds.x); widthMutable = Math.min(widthMutable, Math.max(viewportBounds.width - (xArgumentMutable - viewportBounds.x), 0)); int deltaY = 0; int topDisplacement = yArgumentMutable - viewportBounds.y; int bottomDisplacement = (yArgumentMutable + heightMutable) - (viewportBounds.y + viewportBounds.height); if ((topDisplacement & bottomDisplacement) < 0) { // Both topDisplacement and bottomDisplacement are // negative; the area lies above our viewport bounds deltaY = Math.max(topDisplacement, bottomDisplacement); } else if ((topDisplacement | bottomDisplacement) > 0) { // Both topDisplacement and bottomDisplacement are // positive; the area lies below our viewport bounds deltaY = Math.min(topDisplacement, bottomDisplacement); } if (deltaY != 0) { int viewHeight = (view == null) ? 0 : view.getHeight(); int scrollTop = viewport.getScrollTop(); scrollTop = Math.min(Math.max(scrollTop + deltaY, 0), Math.max(viewHeight - viewportBounds.height, 0)); viewport.setScrollTop(scrollTop); yArgumentMutable -= deltaY; } yArgumentMutable = Math.max(yArgumentMutable, viewportBounds.y); heightMutable = Math.min(heightMutable, Math.max(viewportBounds.height - (yArgumentMutable - viewportBounds.y), 0)); } catch (UnsupportedOperationException ex) { // If the viewport doesn't support getting the viewport // bounds, we simply act as we would have had the viewport // been any other type of component; namely, we do nothing // and proceed to its parent } } xArgumentMutable += component.x; yArgumentMutable += component.y; component = component.getParent(); } } /** * Returns the component's valid state. */ public boolean isValid() { return valid; } /** * Flags the component's hierarchy as invalid, and clears any cached * preferred size. */ public void invalidate() { Container.assertEventDispatchThread(this); valid = false; // Clear the preferred size and baseline preferredSize = null; baseline = -1; if (parent != null) { parent.invalidate(); } } /** * Lays out the component by calling {@link Skin#layout()}. */ public void validate() { if (!valid && visible) { layout(); valid = true; } } /** * Called to lay out the component. */ protected void layout() { skin.layout(); } /** * Flags the entire component as needing to be repainted. */ public final void repaint() { repaint(false); } /** * Flags the entire component as needing to be repainted. * * @param immediate */ public final void repaint(boolean immediate) { repaint(0, 0, getWidth(), getHeight(), immediate); } /** * Flags an area as needing to be repainted. * * @param area */ public final void repaint(Bounds area) { repaint(area, false); } /** * Flags an area as needing to be repainted or repaints the rectangle * immediately. * * @param area * @param immediate */ public final void repaint(Bounds area, boolean immediate) { if (area == null) { throw new IllegalArgumentException("area is null."); } repaint(area.x, area.y, area.width, area.height, immediate); } /** * Flags an area as needing to be repainted. * * @param xArgument * @param yArgument * @param width * @param height */ public final void repaint(int xArgument, int yArgument, int width, int height) { repaint(xArgument, yArgument, width, height, false); } /** * Flags an area as needing to be repainted. * * @param xArgument * @param yArgument * @param width * @param height * @param immediate */ public void repaint(int xArgument, int yArgument, int width, int height, boolean immediate) { Container.assertEventDispatchThread(this); if (parent != null) { int xArgumentMutable = xArgument; int yArgumentMutable = yArgument; int widthMutable = width; int heightMutable = height; // Constrain the repaint area to this component's bounds int top = yArgumentMutable; int left = xArgumentMutable; int bottom = top + heightMutable - 1; int right = left + widthMutable - 1; xArgumentMutable = Math.max(left, 0); yArgumentMutable = Math.max(top, 0); widthMutable = Math.min(right, getWidth() - 1) - xArgumentMutable + 1; heightMutable = Math.min(bottom, getHeight() - 1) - yArgumentMutable + 1; if (widthMutable > 0 && heightMutable > 0) { // Notify the parent that the region needs updating parent.repaint(xArgumentMutable + this.x, yArgumentMutable + this.y, widthMutable, heightMutable, immediate); // Repaint any affected decorators for (Decorator decorator : decorators) { AffineTransform transform = decorator.getTransform(this); if (!transform.isIdentity()) { // Apply the decorator's transform to the repaint area Rectangle area = new Rectangle(xArgumentMutable, yArgumentMutable, widthMutable, heightMutable); Shape transformedShape = transform.createTransformedShape(area); Bounds tranformedBounds = new Bounds(transformedShape.getBounds()); // Limit the transformed area to the decorator's bounds tranformedBounds = tranformedBounds.intersect(decorator.getBounds(this)); // Add the bounded area to the repaint region parent.repaint(tranformedBounds.x + this.x, tranformedBounds.y + this.y, tranformedBounds.width, tranformedBounds.height, immediate); } } } } } /** * Paints the component. Delegates to the skin. */ @Override public void paint(Graphics2D graphics) { skin.paint(graphics); } /** * Creates a graphics context for this component. This graphics context * will not be double buffered. In other words, drawing operations on it * will operate directly on the video RAM. * * @return * A graphics context for this component, or null if this * component is not showing. * * @see #isShowing() */ public Graphics2D getGraphics() { Graphics2D graphics = null; int xLocal = 0; int yLocal = 0; Component component = this; while (component != null && component.isVisible() && !(component instanceof Display)) { xLocal += component.x; yLocal += component.y; component = component.getParent(); } if (component != null && component.isVisible()) { Display display = (Display)component; graphics = (Graphics2D)display.getDisplayHost().getGraphics(); double scale = display.getDisplayHost().getScale(); if (scale != 1) { graphics.scale(scale, scale); } graphics.translate(xLocal, yLocal); graphics.clipRect(0, 0, getWidth(), getHeight()); } return graphics; } /** * Returns the component's enabled state. * * @return * true if the component is enabled; false, otherwise. */ public boolean isEnabled() { return enabled; } /** * Sets the component's enabled state. Enabled components respond to user * input events; disabled components do not. * * @param enabled * true if the component is enabled; false, otherwise. */ public void setEnabled(boolean enabled) { if (this.enabled != enabled) { if (!enabled) { // If this component has the focus, clear it if (isFocused()) { clearFocus(); } // Ensure that the mouse out event is processed if (isMouseOver()) { mouseOut(); } } this.enabled = enabled; componentStateListeners.enabledChanged(this); } } /** * Determines if this component is blocked. A component is blocked if the * component or any of its ancestors is disabled. * * @return * true if the component is blocked; false, otherwise. */ public boolean isBlocked() { boolean blocked = false; Component component = this; while (component != null && !blocked) { blocked = !component.isEnabled(); component = component.getParent(); } return blocked; } /** * Determines if the mouse is positioned over this component. * * @return * true if the mouse is currently located over this component; * false, otherwise. */ public boolean isMouseOver() { return (mouseLocation != null); } /** * Returns the current mouse location in the component's coordinate space. * * @return * The current mouse location, or null if the mouse is not * currently positioned over this component. */ public Point getMouseLocation() { return mouseLocation; } /** * Returns the cursor that is displayed when the mouse pointer is over * this component. * * @return * The cursor that is displayed over the component. */ public Cursor getCursor() { return cursor; } /** * Sets the cursor that is displayed when the mouse pointer is over * this component. * * @param cursor * The cursor to display over the component, or null to inherit * the cursor of the parent container. */ public void setCursor(Cursor cursor) { Cursor previousCursor = this.cursor; if (previousCursor != cursor) { this.cursor = cursor; if (isMouseOver()) { Mouse.setCursor(this); } componentListeners.cursorChanged(this, previousCursor); } } /** * Returns the component's tooltip text. * * @return * The component's tooltip text, or null if no tooltip is * specified. */ public String getTooltipText() { return tooltipText; } /** * Sets the component's tooltip text. * * @param tooltipText * The component's tooltip text, or null for no tooltip. */ public void setTooltipText(String tooltipText) { String previousTooltipText = this.tooltipText; if (previousTooltipText != tooltipText) { this.tooltipText = tooltipText; componentListeners.tooltipTextChanged(this, previousTooltipText); } } /** * Returns the component's tooltip delay. * * @return * The tooltip delay, in milliseconds. */ public int getTooltipDelay() { return tooltipDelay; } /** * Sets the component's tooltip delay. * * @param tooltipDelay * The tooltip delay, in milliseconds. */ public void setTooltipDelay(int tooltipDelay) { int previousTooltipDelay = this.tooltipDelay; if (previousTooltipDelay != tooltipDelay) { this.tooltipDelay = tooltipDelay; componentListeners.tooltipDelayChanged(this, previousTooltipDelay); } } /** * Returns the tooltip's mode for wrapping its text. * * @return * true if the tooltip text wrap mode is enabled; false if not. */ public boolean getTooltipWrapText() { return tooltipWrapText; } /** * Sets the tooltip's text wrapping mode. * * @param tooltipWrapText * The component's tooltip text wrap mode. */ public void setTooltipWrapText(boolean tooltipWrapText) { boolean previousTooltipWrapText = this.tooltipWrapText; if (previousTooltipWrapText != tooltipWrapText) { this.tooltipWrapText = tooltipWrapText; // componentListeners.tooltipTextWrapChanged(this, previousTooltipWrapText); // verify if/when to implement it ... } } /** * Tells whether or not this component is fully opaque when painted. * * @return * true if this component is opaque; false if any part * of it is transparent or translucent. */ public boolean isOpaque() { return skin.isOpaque(); } /** * Returns this component's focusability. A focusable component is capable * of receiving the focus only when it is showing, unblocked, and its window * is not closing. * * @return * true if the component is capable of receiving the focus; * false, otherwise. */ public boolean isFocusable() { boolean focusable = skin.isFocusable(); if (focusable) { Component component = this; while (focusable && component != null && !(component instanceof Window)) { focusable = component.isVisible() && isEnabled(); component = component.getParent(); focusable &= component != null; } if (focusable) { Window window = (Window)component; if (window != null) { focusable = window.isVisible() && window.isEnabled() && window.isOpen() && !window.isClosing(); } else { focusable = false; } } } return focusable; } /** * Returns the component's focused state. * * @return * true if the component has the input focus; false * otherwise. */ public boolean isFocused() { return (focusedComponent == this); } /** * Called to notify a component that its focus state has changed. * * @param focused * true if the component has received the input focus; * false if the component has lost the focus. * * @param obverseComponent * If focused is true, the component that has lost the focus; * otherwise, the component that has gained the focus. */ protected void setFocused(boolean focused, Component obverseComponent) { if (focused) { parent.descendantGainedFocus(this, obverseComponent); } else { parent.descendantLostFocus(this); } componentStateListeners.focusedChanged(this, obverseComponent); } /** * Requests that focus be given to this component. * * @return * true if the component gained the focus; false * otherwise. */ public boolean requestFocus() { if (isFocusable()) { setFocusedComponent(this); ApplicationContext.DisplayHost displayHost = getDisplay().getDisplayHost(); if (!displayHost.isFocusOwner()) { displayHost.requestFocusInWindow(); } } return isFocused(); } /** * Transfers focus to the next focusable component. * * @param direction * The direction in which to transfer focus. */ public Component transferFocus(FocusTraversalDirection direction) { Component component = null; Container parentLocal = getParent(); if (parentLocal != null) { component = parentLocal.transferFocus(this, direction); } return component; } /** * Returns the currently focused component. * * @return * The component that currently has the focus, or null if no * component is focused. */ public static Component getFocusedComponent() { return focusedComponent; } /** * Sets the focused component. * * @param focusedComponent * The component to focus, or null to clear the focus. */ private static void setFocusedComponent(Component focusedComponent) { Component previousFocusedComponent = Component.focusedComponent; if (previousFocusedComponent != focusedComponent) { Component.focusedComponent = focusedComponent; if (previousFocusedComponent != null) { previousFocusedComponent.setFocused(false, focusedComponent); } if (focusedComponent != null) { focusedComponent.setFocused(true, previousFocusedComponent); } componentClassListeners.focusedComponentChanged(previousFocusedComponent); } } /** * Clears the focus. */ public static void clearFocus() { setFocusedComponent(null); } /** * Copies bound values from the bind context to the component. This * functionality must be provided by the subclass; the base implementation * is a no-op. * * @param context */ public void load(Object context) { // empty block } /** * Copies bound values from the component to the bind context. This * functionality must be provided by the subclass; the base implementation * is a no-op. * * @param context */ public void store(Object context) { // empty block } /** * Clears any bound values in the component. */ public void clear() { // empty block } public DragSource getDragSource() { return dragSource; } public void setDragSource(DragSource dragSource) { DragSource previousDragSource = this.dragSource; if (previousDragSource != dragSource) { this.dragSource = dragSource; componentListeners.dragSourceChanged(this, previousDragSource); } } public DropTarget getDropTarget() { return dropTarget; } public void setDropTarget(DropTarget dropTarget) { DropTarget previousDropTarget = this.dropTarget; if (previousDropTarget != dropTarget) { this.dropTarget = dropTarget; componentListeners.dropTargetChanged(this, previousDropTarget); } } public MenuHandler getMenuHandler() { return menuHandler; } public void setMenuHandler(MenuHandler menuHandler) { MenuHandler previousMenuHandler = this.menuHandler; if (previousMenuHandler != menuHandler) { this.menuHandler = menuHandler; componentListeners.menuHandlerChanged(this, previousMenuHandler); } } /** * Returns the component's name. */ public String getName() { return name; } /** * Sets the component's name. * * @param name */ public void setName(String name) { String previousName = this.name; if (previousName != name) { this.name = name; componentListeners.nameChanged(this, previousName); } } /** * Returns the component's style dictionary. */ public final StyleDictionary getStyles() { return styleDictionary; } /** * Applies a set of styles. * * @param styles * A map containing the styles to apply. */ public void setStyles(Map styles) { if (styles == null) { throw new IllegalArgumentException("styles is null."); } for (String key : styles) { getStyles().put(key, styles.get(key)); } } /** * Applies a set of styles. * * @param styles * The styles encoded as a JSON map. */ public void setStyles(String styles) throws SerializationException { if (styles == null) { throw new IllegalArgumentException("styles is null."); } setStyles(JSONSerializer.parseMap(styles)); } /** * Returns the typed style dictionary. */ public static Map, Map> getTypedStyles() { return typedStyles; } /** * Returns the named style dictionary. */ public static Map> getNamedStyles() { return namedStyles; } /** * Applies a set of named styles. * * @param styleName */ public void setStyleName(String styleName) { if (styleName == null) { throw new IllegalArgumentException(); } Map stylesLocal = namedStyles.get(styleName); if (stylesLocal == null) { System.err.println("Named style \"" + styleName + "\" does not exist."); } else { setStyles(stylesLocal); } } /** * Applies a set of named styles. * * @param styleNames */ public void setStyleNames(Sequence styleNames) { if (styleNames == null) { throw new IllegalArgumentException(); } for (int i = 0, n = styleNames.getLength(); i < n; i++) { setStyleName(styleNames.get(i)); } } /** * Applies a set of named styles. * * @param styleNames */ public void setStyleNames(String styleNames) { if (styleNames == null) { throw new IllegalArgumentException(); } String[] styleNameArray = styleNames.split(","); for (int i = 0; i < styleNameArray.length; i++) { String styleName = styleNameArray[i]; setStyleName(styleName.trim()); } } /** * Returns the user data dictionary. */ public UserDataDictionary getUserData() { return userDataDictionary; } /** * Gets the specified component attribute. While attributes can be used to * store arbitrary data, they are intended to be used by containers to store * layout-related metadata in their child components. * * @param key * The attribute key * * @return * The attribute value, or null if no such attribute exists */ @SuppressWarnings("unchecked") public > Object getAttribute(T key) { Object attribute = null; if (attributes != null) { attribute = ((HashMap)attributes).get(key); } return attribute; } /** * Sets the specified component attribute. While attributes can be used to * store arbitrary data, they are intended to be used by containers to store * layout-related metadata in their child components. * * @param key * The attribute key * * @param value * The attribute value, or null to clear the attribute * * @return * The previous value of the attribute, or null if the attribute * was unset */ @SuppressWarnings("unchecked") public > Object setAttribute(T key, Object value) { if (attributes == null) { attributes = new HashMap(); } Object previousValue; if (value != null) { previousValue = ((HashMap)attributes).put(key, value); } else { previousValue = ((HashMap)attributes).remove(key); } return previousValue; } /** * If the mouse is currently over the component, causes the component to * fire mouseOut() and a mouseMove() at the current mouse * location. *

* This method is primarily useful when consuming container mouse motion * events, since it allows a caller to reset the mouse state based on the * event consumption logic. */ public void reenterMouse() { if (isMouseOver()) { mouseOut(); Display display = getDisplay(); Point location = display.getMouseLocation(); location = mapPointFromAncestor(display, x, y); mouseMove(location.x, location.y); } } protected boolean mouseMove(int xArgument, int yArgument) { boolean consumed = false; if (isEnabled()) { mouseLocation = new Point(xArgument, yArgument); if (triggerTooltipCallback != null) { triggerTooltipCallback.cancel(); triggerTooltipCallback = null; } triggerTooltipCallback = ApplicationContext.scheduleCallback(new Runnable() { @Override public void run() { Point mouseLocationLocal = getMouseLocation(); if (mouseLocationLocal != null) { componentTooltipListeners.tooltipTriggered(Component.this, mouseLocationLocal.x, mouseLocationLocal.y); } } }, tooltipDelay); consumed = componentMouseListeners.mouseMove(this, xArgument, yArgument); } return consumed; } protected void mouseOver() { if (isEnabled()) { mouseLocation = new Point(-1, -1); componentMouseListeners.mouseOver(this); } } protected void mouseOut() { if (isEnabled()) { mouseLocation = null; if (triggerTooltipCallback != null) { triggerTooltipCallback.cancel(); triggerTooltipCallback = null; } componentMouseListeners.mouseOut(this); } } protected boolean mouseDown(Mouse.Button button, int xArgument, int yArgument) { boolean consumed = false; if (isEnabled()) { if (triggerTooltipCallback != null) { triggerTooltipCallback.cancel(); triggerTooltipCallback = null; } consumed = componentMouseButtonListeners.mouseDown(this, button, xArgument, yArgument); } return consumed; } protected boolean mouseUp(Mouse.Button button, int xArgument, int yArgument) { boolean consumed = false; if (isEnabled()) { consumed = componentMouseButtonListeners.mouseUp(this, button, xArgument, yArgument); } return consumed; } protected boolean mouseClick(Mouse.Button button, int xArgument, int yArgument, int count) { boolean consumed = false; if (isEnabled()) { consumed = componentMouseButtonListeners.mouseClick(this, button, xArgument, yArgument, count); } return consumed; } protected boolean mouseWheel(Mouse.ScrollType scrollType, int scrollAmount, int wheelRotation, int xArgument, int yArgument) { boolean consumed = false; if (isEnabled()) { consumed = componentMouseWheelListeners.mouseWheel(this, scrollType, scrollAmount, wheelRotation, xArgument, yArgument); } return consumed; } protected boolean keyTyped(char character) { boolean consumed = false; if (isEnabled()) { consumed = componentKeyListeners.keyTyped(this, character); if (!consumed && parent != null) { consumed = parent.keyTyped(character); } } return consumed; } protected boolean keyPressed(int keyCode, Keyboard.KeyLocation keyLocation) { boolean consumed = false; if (isEnabled()) { consumed = componentKeyListeners.keyPressed(this, keyCode, keyLocation); if (!consumed && parent != null) { consumed = parent.keyPressed(keyCode, keyLocation); } } return consumed; } protected boolean keyReleased(int keyCode, Keyboard.KeyLocation keyLocation) { boolean consumed = false; if (isEnabled()) { consumed = componentKeyListeners.keyReleased(this, keyCode, keyLocation); if (!consumed && parent != null) { consumed = parent.keyReleased(keyCode, keyLocation); } } return consumed; } @Override public String toString() { String s = this.getClass().getName(); if (automationID != null) { s += "#" + automationID; } return s; } public ListenerList getComponentListeners() { return componentListeners; } public ListenerList getComponentStateListeners() { return componentStateListeners; } public ListenerList getComponentDecoratorListeners() { return componentDecoratorListeners; } public ListenerList getComponentStyleListeners() { return componentStyleListeners; } public ListenerList getComponentMouseListeners() { return componentMouseListeners; } public ListenerList getComponentMouseButtonListeners() { return componentMouseButtonListeners; } public ListenerList getComponentMouseWheelListeners() { return componentMouseWheelListeners; } public ListenerList getComponentKeyListeners() { return componentKeyListeners; } public ListenerList getComponentTooltipListeners() { return componentTooltipListeners; } public ListenerList getComponentDataListeners() { return componentDataListeners; } public static ListenerList getComponentClassListeners() { return componentClassListeners; } /** * Provide a nice exception message for out of range values. * * @throws IndexOutOfBoundsException if index is out of range. */ protected static final void indexBoundsCheck(String indexName, int index, int min, int max) throws IndexOutOfBoundsException { if (max < min) { throw new IllegalArgumentException("max (" + max + ") < " + "min (" + min + ")"); } if (index < min) { throw new IndexOutOfBoundsException(indexName + ": index (" + index + ") < min (" + min + ")"); } if (index > max) { throw new IndexOutOfBoundsException(indexName + ": index (" + index + ") > max (" + max + ")"); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy