You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pivot.apache.org by tv...@apache.org on 2009/03/16 17:36:28 UTC
svn commit: r754936 [14/38] - in /incubator/pivot/tags/v1.0.1: ./
charts-test/ charts-test/src/ charts-test/src/pivot/
charts-test/src/pivot/charts/ charts-test/src/pivot/charts/test/ charts/
charts/lib/ charts/src/ charts/src/pivot/ charts/src/pivot/c...
Added: incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/Component.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/Component.java?rev=754936&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/Component.java (added)
+++ incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/Component.java Mon Mar 16 16:36:10 2009
@@ -0,0 +1,2454 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.wtk;
+
+import java.awt.Graphics2D;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Iterator;
+
+import pivot.beans.BeanDictionary;
+import pivot.beans.PropertyNotFoundException;
+import pivot.collections.ArrayList;
+import pivot.collections.Dictionary;
+import pivot.collections.HashMap;
+import pivot.collections.HashSet;
+import pivot.collections.Map;
+import pivot.collections.Sequence;
+import pivot.serialization.JSONSerializer;
+import pivot.serialization.SerializationException;
+import pivot.util.ImmutableIterator;
+import pivot.util.ListenerList;
+import pivot.util.Vote;
+
+/**
+ * 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".
+ * <p>
+ * TODO Add a contains() method or some equivalent that will support mouse
+ * interaction with non-rectangular components.
+ */
+public abstract class Component implements ConstrainedVisual {
+ /**
+ * Style dictionary implementation.
+ *
+ * @author gbrown
+ */
+ public final class StyleDictionary extends BeanDictionary {
+ public StyleDictionary(pivot.wtk.Skin skin) {
+ super(skin, true);
+ }
+
+ public Object put(String key, Object value) {
+ Object previousValue = null;
+
+ try {
+ previousValue = super.put(key, value);
+ customStyles.add(key);
+ componentListeners.styleUpdated(Component.this, key, previousValue);
+ } catch(PropertyNotFoundException exception) {
+ System.out.println("\"" + key + "\" is not a valid style for "
+ + Component.this);
+ }
+
+ return previousValue;
+ }
+ }
+
+ /**
+ * Decorator sequence implementation.
+ *
+ * @author tvolkert
+ * @author gbrown
+ */
+ public final class DecoratorSequence implements Sequence<Decorator>,
+ Iterable<Decorator> {
+ public int add(Decorator decorator) {
+ int i = getLength();
+ insert(decorator, i);
+
+ return i;
+ }
+
+ public void insert(Decorator decorator, int index) {
+ if (decorator == null) {
+ throw new IllegalArgumentException("decorator is null");
+ }
+
+ decorators.insert(decorator, index);
+ repaint();
+
+ componentDecoratorListeners.decoratorInserted(Component.this, index);
+ }
+
+ public Decorator update(int index, Decorator decorator) {
+ if (decorator == null) {
+ throw new IllegalArgumentException("decorator is null.");
+ }
+
+ Decorator previousDecorator = decorators.update(index, decorator);
+ repaint();
+
+ componentDecoratorListeners.decoratorUpdated(Component.this, index,
+ previousDecorator);
+
+ return previousDecorator;
+ }
+
+ public int remove(Decorator decorator) {
+ int index = indexOf(decorator);
+ if (index != -1) {
+ remove(index, 1);
+ }
+
+ return index;
+ }
+
+ public Sequence<Decorator> remove(int index, int count) {
+ Sequence<Decorator> removed = decorators.remove(index, count);
+
+ if (count > 0) {
+ repaint();
+ componentDecoratorListeners.decoratorsRemoved(Component.this, index, removed);
+ }
+
+ return removed;
+ }
+
+ public Sequence<Decorator> removeAll() {
+ return remove(0, getLength());
+ }
+
+ public Decorator get(int index) {
+ return decorators.get(index);
+ }
+
+ public int indexOf(Decorator decorator) {
+ return decorators.indexOf(decorator);
+ }
+
+ public int getLength() {
+ return decorators.getLength();
+ }
+
+ public Iterator<Decorator> iterator() {
+ return new ImmutableIterator<Decorator>(decorators.iterator());
+ }
+ }
+
+ /**
+ * Holds cached preferred size constraint/value pairs.
+ *
+ * @author tvolkert
+ */
+ private static class PreferredSizeCache {
+ public int constraint;
+ public int value;
+
+ public PreferredSizeCache(int constraint, int value) {
+ this.constraint = constraint;
+ this.value = value;
+ }
+ }
+
+ /**
+ * Abstract base class for component "attributes". Attributes are attached
+ * properties that are specific to a particular component type.
+ *
+ * @author gbrown
+ */
+ public static abstract class Attributes {
+ private Component component = null;
+
+ protected Attributes() {
+ }
+
+ public Component getComponent() {
+ return component;
+ }
+
+ private void setComponent(Component component) {
+ this.component = component;
+ }
+ }
+
+ /**
+ * Provides dictionary access to all components by handle.
+ *
+ * @author gbrown
+ */
+ public static class ComponentDictionary implements
+ Dictionary<Integer, Component>, Iterable<Integer> {
+ public Component get(Integer key) {
+ return components.get(key);
+ }
+
+ public Component put(Integer key, Component value) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Component remove(Integer key) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean containsKey(Integer key) {
+ return components.containsKey(key);
+ }
+
+ public boolean isEmpty() {
+ return components.isEmpty();
+ }
+
+ public Iterator<Integer> iterator() {
+ return new ImmutableIterator<Integer>(components.iterator());
+ }
+ }
+
+ /**
+ * Component listener list.
+ *
+ * @author gbrown
+ */
+ private static class ComponentListenerList extends ListenerList<ComponentListener>
+ implements ComponentListener {
+ public void parentChanged(Component component, Container previousParent) {
+ for (ComponentListener listener : this) {
+ listener.parentChanged(component, previousParent);
+ }
+ }
+
+ public void sizeChanged(Component component, int previousWidth, int previousHeight) {
+ for (ComponentListener listener : this) {
+ listener.sizeChanged(component, previousWidth, previousHeight);
+ }
+ }
+
+ public void locationChanged(Component component, int previousX, int previousY) {
+ for (ComponentListener listener : this) {
+ listener.locationChanged(component, previousX, previousY);
+ }
+ }
+
+ public void visibleChanged(Component component) {
+ for (ComponentListener listener : this) {
+ listener.visibleChanged(component);
+ }
+ }
+
+ public void styleUpdated(Component component, String styleKey, Object previousValue) {
+ for (ComponentListener listener : this) {
+ listener.styleUpdated(component, styleKey, previousValue);
+ }
+ }
+
+ public void cursorChanged(Component component, Cursor previousCursor) {
+ for (ComponentListener listener : this) {
+ listener.cursorChanged(component, previousCursor);
+ }
+ }
+
+ public void tooltipTextChanged(Component component, String previousTooltipText) {
+ for (ComponentListener listener : this) {
+ listener.tooltipTextChanged(component, previousTooltipText);
+ }
+ }
+ }
+
+ private static class ComponentLayoutListenerList extends
+ ListenerList<ComponentLayoutListener> implements ComponentLayoutListener {
+ public void preferredSizeChanged(Component component,
+ int previousPreferredWidth, int previousPreferredHeight) {
+ for (ComponentLayoutListener listener : this) {
+ listener.preferredSizeChanged(component,
+ previousPreferredWidth, previousPreferredHeight);
+ }
+ }
+
+ public void displayableChanged(Component component) {
+ for (ComponentLayoutListener listener : this) {
+ listener.displayableChanged(component);
+ }
+ }
+ }
+
+ private static class ComponentStateListenerList extends
+ ListenerList<ComponentStateListener> implements ComponentStateListener {
+ public Vote previewEnabledChange(Component component) {
+ Vote vote = Vote.APPROVE;
+
+ for (ComponentStateListener listener : this) {
+ vote = vote.tally(listener.previewEnabledChange(component));
+ }
+
+ return vote;
+ }
+
+ public void enabledChangeVetoed(Component component, Vote reason) {
+ for (ComponentStateListener listener : this) {
+ listener.enabledChangeVetoed(component, reason);
+ }
+ }
+
+ public void enabledChanged(Component component) {
+ for (ComponentStateListener listener : this) {
+ listener.enabledChanged(component);
+ }
+ }
+
+ public Vote previewFocusedChange(Component component, boolean temporary) {
+ Vote vote = Vote.APPROVE;
+
+ for (ComponentStateListener listener : this) {
+ vote = vote.tally(listener.previewFocusedChange(component, temporary));
+ }
+
+ return vote;
+ }
+
+ public void focusedChangeVetoed(Component component, Vote reason) {
+ for (ComponentStateListener listener : this) {
+ listener.focusedChangeVetoed(component, reason);
+ }
+ }
+
+ public void focusedChanged(Component component, boolean temporary) {
+ for (ComponentStateListener listener : this) {
+ listener.focusedChanged(component, temporary);
+ }
+ }
+ }
+
+ private static class ComponentDecoratorListenerList extends
+ ListenerList<ComponentDecoratorListener> implements ComponentDecoratorListener {
+ public void decoratorInserted(Component component, int index) {
+ for (ComponentDecoratorListener listener : this) {
+ listener.decoratorInserted(component, index);
+ }
+ }
+
+ public void decoratorUpdated(Component component, int index, Decorator previousDecorator) {
+ for (ComponentDecoratorListener listener : this) {
+ listener.decoratorUpdated(component, index, previousDecorator);
+ }
+ }
+
+ public void decoratorsRemoved(Component component, int index,
+ Sequence<Decorator> decorators) {
+ for (ComponentDecoratorListener listener : this) {
+ listener.decoratorsRemoved(component, index, decorators);
+ }
+ }
+ }
+
+ private static class ComponentMouseListenerList extends ListenerList<ComponentMouseListener>
+ implements ComponentMouseListener {
+ public boolean mouseMove(Component component, int x, int y) {
+ boolean consumed = false;
+
+ for (ComponentMouseListener listener : this) {
+ consumed |= listener.mouseMove(component, x, y);
+ }
+
+ return consumed;
+ }
+
+ public void mouseOver(Component component) {
+ for (ComponentMouseListener listener : this) {
+ listener.mouseOver(component);
+ }
+ }
+
+ public void mouseOut(Component component) {
+ for (ComponentMouseListener listener : this) {
+ listener.mouseOut(component);
+ }
+ }
+ }
+
+ private static class ComponentMouseButtonListenerList extends ListenerList<ComponentMouseButtonListener>
+ implements ComponentMouseButtonListener {
+ 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;
+ }
+
+ 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;
+ }
+
+ public void mouseClick(Component component, Mouse.Button button, int x, int y, int count) {
+ for (ComponentMouseButtonListener listener : this) {
+ listener.mouseClick(component, button, x, y, count);
+ }
+ }
+ }
+
+ private static class ComponentMouseWheelListenerList extends ListenerList<ComponentMouseWheelListener>
+ implements ComponentMouseWheelListener {
+ 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 ListenerList<ComponentKeyListener>
+ implements ComponentKeyListener {
+ public void keyTyped(Component component, char character) {
+ for (ComponentKeyListener listener : this) {
+ listener.keyTyped(component, character);
+ }
+ }
+
+ 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;
+ }
+
+ 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 ComponentDataListenerList extends ListenerList<ComponentDataListener>
+ implements ComponentDataListener {
+ public void userDataChanged(Component component, Object previousValue) {
+ for (ComponentDataListener listener : this) {
+ listener.userDataChanged(component, previousValue);
+ }
+ }
+ }
+
+ private static class ComponentDragDropListenerList extends ListenerList<ComponentDragDropListener>
+ implements ComponentDragDropListener {
+ public void dragHandlerChanged(Component component, DragHandler previousDragHandler) {
+ for (ComponentDragDropListener listener : this) {
+ listener.dragHandlerChanged(component, previousDragHandler);
+ }
+ }
+
+ public void dropHandlerChanged(Component component, DropHandler previousDropHandler) {
+ for (ComponentDragDropListener listener : this) {
+ listener.dropHandlerChanged(component, previousDropHandler);
+ }
+ }
+ }
+
+ /**
+ * Component class listener list.
+ *
+ * @author tvolkert
+ */
+ private static class ComponentClassListenerList extends ListenerList<ComponentClassListener>
+ implements ComponentClassListener {
+ public void focusedComponentChanged(Component previousFocusedComponent) {
+ for (ComponentClassListener listener : this) {
+ listener.focusedComponentChanged(previousFocusedComponent);
+ }
+ }
+ }
+
+ /**
+ * The component's handle.
+ */
+ private final Integer handle;
+
+ /**
+ * The currently installed skin, or null if no skin is installed.
+ */
+ private pivot.wtk.Skin skin = null;
+
+ /**
+ * The component's preferred width, height, and cache.
+ */
+ private int preferredWidth = -1;
+ private int preferredHeight = -1;
+
+ private PreferredSizeCache preferredWidthCache = null;
+ private PreferredSizeCache preferredHeightCache = null;
+
+ /**
+ * The component's parent container, or null if the component does not have
+ * a parent.
+ */
+ private Container parent = null;
+
+ /**
+ * The component's location. These coordinates are relative to the origin of
+ * the component's parent.
+ */
+ private int x = 0;
+ private int y = 0;
+
+ /**
+ * The component's visible flag.
+ */
+ private boolean visible = true;
+
+ /**
+ * The component's displayable flag.
+ */
+ private boolean displayable = true;
+
+ /**
+ * The component's decorators.
+ */
+ private ArrayList<Decorator> decorators = new ArrayList<Decorator>();
+ private DecoratorSequence decoratorSequence = new DecoratorSequence();
+
+ /**
+ * The component's enabled flag.
+ */
+ private boolean enabled = true;
+
+ /**
+ * The component's mouse-over flag.
+ */
+ private boolean mouseOver = false;
+
+ /**
+ * The cursor that is displayed over the component.
+ */
+ private Cursor cursor = Cursor.DEFAULT;
+
+ /**
+ * The tooltip text.
+ */
+ private String tooltipText = null;
+
+ /**
+ * User data.
+ */
+ private Object userData = null;
+
+ /**
+ * Drag handler.
+ */
+ private DragHandler dragHandler = null;
+
+ /**
+ * Drop handler.
+ */
+ private DropHandler dropHandler = null;
+
+ /**
+ * Proxy class for getting/setting style properties on the skin.
+ */
+ private StyleDictionary styleDictionary = null;
+
+ /**
+ * Custom style keys.
+ */
+ private HashSet<String> customStyles = new HashSet<String>();
+
+ /**
+ * Attached properties.
+ */
+ private Attributes attributes = null;
+
+ /**
+ * Instance event listener lists.
+ */
+ private ComponentListenerList componentListeners = new ComponentListenerList();
+ private ComponentLayoutListenerList componentLayoutListeners = new ComponentLayoutListenerList();
+ private ComponentStateListenerList componentStateListeners = new ComponentStateListenerList();
+ private ComponentDecoratorListenerList componentDecoratorListeners = new ComponentDecoratorListenerList();
+ private ComponentMouseListenerList componentMouseListeners = new ComponentMouseListenerList();
+ private ComponentMouseButtonListenerList componentMouseButtonListeners = new ComponentMouseButtonListenerList();
+ private ComponentMouseWheelListenerList componentMouseWheelListeners = new ComponentMouseWheelListenerList();
+ private ComponentKeyListenerList componentKeyListeners = new ComponentKeyListenerList();
+ private ComponentDataListenerList componentDataListeners = new ComponentDataListenerList();
+ private ComponentDragDropListenerList componentDragDropListeners = new ComponentDragDropListenerList();
+
+ /**
+ * The component that currently has the focus.
+ */
+ private static Component focusedComponent = null;
+
+ /**
+ * The next available component handle.
+ */
+ private static int nextHandle = 0;
+
+ /**
+ * Static map of all components by handle.
+ */
+ private static HashMap<Integer, Component> components = new HashMap<Integer, Component>(true);
+ private static ComponentDictionary componentDictionary = new ComponentDictionary();
+
+ /**
+ * Class event listener list.
+ */
+ private static ComponentClassListenerList componentClassListeners = new ComponentClassListenerList();
+
+ /**
+ * Creates a new component.
+ */
+ public Component() {
+ handle = nextHandle++;
+ components.put(handle, this);
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ components.remove(handle);
+ } finally {
+ super.finalize();
+ }
+ }
+
+ /**
+ * Return's the component's handle.
+ */
+ public Integer getHandle() {
+ return handle;
+ }
+
+ /**
+ * Returns the currently installed skin.
+ *
+ * @return
+ * The currently installed skin.
+ */
+ protected pivot.wtk.Skin getSkin() {
+ return skin;
+ }
+
+ /**
+ * Sets the skin, replacing any previous skin.
+ *
+ * @param skin
+ * The new skin.
+ */
+ protected void setSkin(pivot.wtk.Skin skin) {
+ if (skin == null) {
+ throw new IllegalArgumentException("skin is null.");
+ }
+
+ if (this.skin != null) {
+ this.skin.uninstall();
+ }
+
+ this.skin = skin;
+ styleDictionary = new StyleDictionary(skin);
+ skin.install(this);
+
+ invalidate();
+ repaint();
+ }
+
+ /**
+ * Installs the skin for the given component class, unless a subclass has
+ * defined a more specific skin. Any component that defines a custom skin
+ * class must call this method.
+ *
+ * @param componentClass
+ */
+ @SuppressWarnings("unchecked")
+ protected void installSkin(Class<? extends Component> 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<? extends pivot.wtk.Skin> skinClass = theme.getSkinClass((Class<? extends Component>)type);
+
+ while (skinClass == null
+ && type != componentClass
+ && type != Component.class) {
+ type = type.getSuperclass();
+
+ if (type != Component.class) {
+ skinClass = theme.getSkinClass((Class<? extends Component>)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) {
+ // Cache the values of custom styles
+ HashMap<String, Object> styles = new HashMap<String, Object>();
+ for (String key : customStyles) {
+ styles.put(key, styleDictionary.get(key));
+ }
+
+ try {
+ setSkin(skinClass.newInstance());
+ } catch(InstantiationException exception) {
+ throw new IllegalArgumentException(exception);
+ } catch(IllegalAccessException exception) {
+ throw new IllegalArgumentException(exception);
+ }
+
+ // Re-apply custom styles
+ setStyles(styles);
+ }
+ }
+
+ public Container getParent() {
+ return parent;
+ }
+
+ protected void setParent(Container parent) {
+ // If the mouse is currently over this component, set the cursor
+ // to the default
+ if (mouseOver) {
+ Mouse.setCursor(Cursor.DEFAULT);
+ mouseOver = false;
+ }
+
+ // 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;
+
+ componentListeners.parentChanged(this, previousParent);
+ }
+
+ public Window getWindow() {
+ Component component = this;
+
+ while (component != null
+ && !(component instanceof Window)) {
+ component = component.getParent();
+ }
+
+ return (Window)component;
+ }
+
+ public Display getDisplay() {
+ Component component = this;
+
+ while (component != null
+ && !(component instanceof Display)) {
+ component = component.getParent();
+ }
+
+ return (Display)component;
+ }
+
+ public int getWidth() {
+ return skin.getWidth();
+ }
+
+ public int getHeight() {
+ return skin.getHeight();
+ }
+
+ 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
+ */
+ 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
+ repaint();
+
+ // Set the size of the skin
+ skin.setSize(width, height);
+
+ // Redraw the region currently occupied by this component
+ repaint();
+
+ componentListeners.sizeChanged(this, previousWidth, previousHeight);
+ }
+ }
+
+ public int getPreferredWidth() {
+ return getPreferredWidth(-1);
+ }
+
+ public int getPreferredWidth(int height) {
+ int preferredWidth = this.preferredWidth;
+
+ if (preferredWidth == -1) {
+ if (height == -1) {
+ height = preferredHeight;
+ }
+
+ if (preferredWidthCache != null
+ && preferredWidthCache.constraint == height) {
+ preferredWidth = preferredWidthCache.value;
+ } else {
+ preferredWidth = skin.getPreferredWidth(height);
+
+ if (isValid()) {
+ // Update the cache
+ if (preferredWidthCache == null) {
+ preferredWidthCache = new PreferredSizeCache(height,
+ preferredWidth);
+ } else {
+ preferredWidthCache.constraint = height;
+ preferredWidthCache.value = preferredWidth;
+ }
+ }
+ }
+ }
+
+ return preferredWidth;
+ }
+
+ /**
+ * Sets the component's preferred width.
+ *
+ * @param preferredWidth
+ * The preferred width value, or <tt>-1</tt> to use the default
+ * value determined by the skin.
+ */
+ public void setPreferredWidth(int preferredWidth) {
+ if (preferredWidth < -1) {
+ throw new IllegalArgumentException(preferredWidth
+ + " is not a valid value for preferredWidth.");
+ }
+
+ int previousPreferredWidth = this.preferredWidth;
+
+ if (previousPreferredWidth != preferredWidth) {
+ this.preferredWidth = preferredWidth;
+
+ invalidate();
+
+ componentLayoutListeners.preferredSizeChanged(this,
+ previousPreferredWidth, 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
+ * <tt>true</tt> if the preferred width was explicitly set; <tt>false</tt>,
+ * otherwise.
+ */
+ public boolean isPreferredWidthSet() {
+ return (preferredWidth != -1);
+ }
+
+ public int getPreferredHeight() {
+ return getPreferredHeight(-1);
+ }
+
+ public int getPreferredHeight(int width) {
+ int preferredHeight = this.preferredHeight;
+
+ if (preferredHeight == -1) {
+ if (width == -1) {
+ width = preferredWidth;
+ }
+
+ if (preferredHeightCache != null
+ && preferredHeightCache.constraint == width) {
+ preferredHeight = preferredHeightCache.value;
+ } else {
+ preferredHeight = skin.getPreferredHeight(width);
+
+ if (isValid()) {
+ // Update the cache
+ if (preferredHeightCache == null) {
+ preferredHeightCache = new PreferredSizeCache(width,
+ preferredHeight);
+ } else {
+ preferredHeightCache.constraint = width;
+ preferredHeightCache.value = preferredHeight;
+ }
+ }
+ }
+ }
+
+ return preferredHeight;
+ }
+
+ /**
+ * Sets the component's preferred height.
+ *
+ * @param preferredHeight
+ * The preferred height value, or <tt>-1</tt> to use the default
+ * value determined by the skin.
+ */
+ public void setPreferredHeight(int preferredHeight) {
+ if (preferredHeight < -1) {
+ throw new IllegalArgumentException(preferredHeight
+ + " is not a valid value for preferredHeight.");
+ }
+
+ int previousPreferredHeight = this.preferredHeight;
+
+ if (previousPreferredHeight != preferredHeight) {
+ this.preferredHeight = preferredHeight;
+
+ invalidate();
+
+ componentLayoutListeners.preferredSizeChanged(this,
+ preferredWidth, previousPreferredHeight);
+ }
+ }
+
+ /**
+ * Returns a flag indicating whether the preferred height was explicitly
+ * set by the caller or is the default value determined by the skin.
+ *
+ * @return
+ * <tt>true</tt> if the preferred height was explicitly set; <tt>false</tt>,
+ * otherwise.
+ */
+ public boolean isPreferredHeightSet() {
+ return (preferredHeight != -1);
+ }
+
+ /**
+ * Gets the component's unconstrained preferred size.
+ */
+ public Dimensions getPreferredSize() {
+ Dimensions preferredSize = null;
+
+ if (isPreferredWidthSet()
+ && isPreferredHeightSet()) {
+ preferredSize = new Dimensions(preferredWidth, preferredHeight);
+ } else if (isPreferredWidthSet()) {
+ int preferredHeight;
+
+ if (preferredHeightCache != null
+ && preferredHeightCache.constraint == preferredWidth) {
+ preferredHeight = preferredHeightCache.value;
+ } else {
+ preferredHeight = skin.getPreferredHeight(preferredWidth);
+
+ if (isValid()) {
+ // Update the cache
+ if (preferredHeightCache == null) {
+ preferredHeightCache = new PreferredSizeCache(preferredWidth,
+ preferredHeight);
+ } else {
+ preferredHeightCache.constraint = preferredWidth;
+ preferredHeightCache.value = preferredHeight;
+ }
+ }
+ }
+
+ preferredSize = new Dimensions(preferredWidth, preferredHeight);
+ } else if (isPreferredHeightSet()) {
+ int preferredWidth;
+
+ if (preferredWidthCache != null
+ && preferredWidthCache.constraint == preferredHeight) {
+ preferredWidth = preferredWidthCache.value;
+ } else {
+ preferredWidth = skin.getPreferredWidth(preferredHeight);
+
+ if (isValid()) {
+ // Update the cache
+ if (preferredWidthCache == null) {
+ preferredWidthCache = new PreferredSizeCache(preferredHeight,
+ preferredWidth);
+ } else {
+ preferredWidthCache.constraint = preferredHeight;
+ preferredWidthCache.value = preferredWidth;
+ }
+ }
+ }
+
+ preferredSize = new Dimensions(preferredWidth, preferredHeight);
+ } else {
+ if (preferredWidthCache != null
+ && preferredWidthCache.constraint == -1
+ && preferredHeightCache != null
+ && preferredHeightCache.constraint == -1) {
+ preferredSize = new Dimensions(preferredWidthCache.value,
+ preferredHeightCache.value);
+ } else {
+ preferredSize = skin.getPreferredSize();
+
+ if (isValid()) {
+ // Update the cache
+ if (preferredWidthCache == null) {
+ preferredWidthCache = new PreferredSizeCache(-1,
+ preferredSize.width);
+ } else {
+ preferredWidthCache.constraint = -1;
+ preferredWidthCache.value = preferredSize.width;
+ }
+
+ if (preferredHeightCache == null) {
+ preferredHeightCache = new PreferredSizeCache(-1,
+ preferredSize.height);
+ } else {
+ preferredHeightCache.constraint = -1;
+ preferredHeightCache.value = preferredSize.height;
+ }
+ }
+ }
+ }
+
+ 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 <tt>-1</tt> to use the default
+ * value determined by the skin.
+ *
+ * @param preferredHeight
+ * The preferred height value, or <tt>-1</tt> 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();
+
+ componentLayoutListeners.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
+ * <tt>true</tt> if the preferred size was explicitly set; <tt>false</tt>,
+ * otherwise.
+ */
+ public boolean isPreferredSizeSet() {
+ return isPreferredWidthSet()
+ && isPreferredHeightSet();
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * 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
+ repaint();
+
+ // Set the new coordinates
+ this.x = x;
+ this.y = y;
+
+ // Redraw the region currently occupied by this component
+ repaint();
+
+ 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 bounding area.
+ *
+ * @return
+ * The component's bounding area. The <tt>x</tt> and <tt>y</tt> values are
+ * relative to the parent container.
+ */
+ public Bounds getBounds() {
+ return new Bounds(x, y, getWidth(), getHeight());
+ }
+
+ /**
+ * Returns the component's visibility.
+ *
+ * @return
+ * <tt>true</tt> if the component will be painted; <tt>false</tt>,
+ * otherwise.
+ */
+ public boolean isVisible() {
+ return visible;
+ }
+
+ /**
+ * Sets the component's visibility.
+ * <p>
+ * NOTE This method should only be called during layout. Callers should
+ * use {@link #setDisplayable(boolean)}.
+ *
+ * @param visible
+ * <tt>true</tt> if the component should be painted; <tt>false</tt>,
+ * 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 (mouseOver) {
+ mouseOut();
+ }
+ }
+
+ // Redraw the region formerly occupied by this component
+ repaint();
+
+ this.visible = visible;
+
+ // Redraw the region currently occupied by this component
+ repaint();
+
+ if (visible) {
+ // This component is being shown; ensure that it's layout
+ // is valid
+ invalidate();
+ }
+
+ componentListeners.visibleChanged(this);
+ }
+ }
+
+ /**
+ * Returns the component's displayability.
+ *
+ * NOTE Container skins should generally try to respect this flag when
+ * laying out, as follows:
+ * <ul>
+ * <li>
+ * When a component's displayable flag is <tt>true</tt>, the
+ * container skin should include the component in layout and set its
+ * visibility to <tt>true</tt>.
+ * </li>
+ * <li>
+ * When a component's displayable flag is <tt>false</tt>, the
+ * container skin should not include the component in layout and set
+ * its visibility to <tt>false</tt>.
+ * </li>
+ * </ul>
+ * However, depending on the nature of the skin, it may ignore this flag
+ * and manage its components' visibilities internally.
+ *
+ * @return
+ * <tt>true</tt> if the component will participate in layout;
+ * <tt>false</tt>, otherwise.
+ */
+ public boolean isDisplayable() {
+ return displayable;
+ }
+
+ /**
+ * Sets the component's displayability.
+ *
+ * @param displayable
+ * <tt>true</tt> if the component will participate in layout;
+ * <tt>false</tt>, otherwise.
+ */
+ public void setDisplayable(boolean displayable) {
+ if (this.displayable != displayable) {
+ this.displayable = displayable;
+
+ invalidate();
+
+ componentLayoutListeners.displayableChanged(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 x
+ * The x-coordinate in this component's coordinate space
+ *
+ * @param y
+ * The y-coordinate in this component's coordinate space
+ *
+ * @return
+ * A point containing the translated coordinates, or <tt>null</tt> if the
+ * component is not a descendant of the specified ancestor.
+ */
+ public Point mapPointToAncestor(Container ancestor, int x, int y) {
+ if (ancestor == null) {
+ throw new IllegalArgumentException("ancestor is null");
+ }
+
+ Point coordinates = null;
+
+ Component component = this;
+
+ while (component != null
+ && coordinates == null) {
+ if (component == ancestor) {
+ coordinates = new Point(x, y);
+ } else {
+ x += component.x;
+ y += component.y;
+
+ component = component.getParent();
+ }
+ }
+
+ return coordinates;
+ }
+
+ /**
+ * Maps a point in the specified ancestor's coordinate space to this
+ * component's coordinate system.
+ *
+ * @param x
+ * The x-coordinate in the ancestors's coordinate space.
+ *
+ * @param y
+ * The y-coordinate in the ancestor's coordinate space.
+ *
+ * @return
+ * A point containing the translated coordinates, or <tt>null</tt> if the
+ * component is not a descendant of the specified ancestor.
+ */
+ public Point mapPointFromAncestor(Container ancestor, int x, int y) {
+ if (ancestor == null) {
+ throw new IllegalArgumentException("ancestor is null");
+ }
+
+ Point coordinates = null;
+
+ Component component = this;
+
+ while (component != null
+ && coordinates == null) {
+ if (component == ancestor) {
+ coordinates = new Point(x, y);
+ } else {
+ x -= component.x;
+ y -= component.y;
+
+ component = component.getParent();
+ }
+ }
+
+ return coordinates;
+ }
+
+ /**
+ * Determines if this component is showing. To be showing, the component
+ * and all of its ancestors must be visible, and the component's window
+ * must be open.
+ *
+ * @return
+ * <tt>true</tt> if this component is showing; <tt>false</tt> otherwise
+ */
+ public boolean isShowing() {
+ boolean showing = true;
+
+ Component component = this;
+ while (component != null
+ && showing) {
+ Container parent = component.getParent();
+ showing &= (component.isVisible()
+ && (parent != null || component instanceof Display));
+
+ component = parent;
+ }
+
+ return showing;
+ }
+
+ /**
+ * Determines the visible bounds of an area within a component (the
+ * intersection of the area with the visible area of the component
+ * and its ancestors).
+ *
+ * @return
+ * The visible bounds of the given area in display coordinates,
+ * or <tt>null</tt> if the component is either not showing (see
+ * {@link #isShowing()}) or not part of the container 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 bounds of an area within a component (the
+ * intersection of the area with the visible area of the component
+ * and its ancestors).
+ *
+ * @param x
+ * @param y
+ * @param width
+ * @param height
+ *
+ * @return
+ * The visible bounds of the given area in display coordinates,
+ * or <tt>null</tt> if the component is either not showing (see
+ * {@link #isShowing()}) or not part of the container hierarchy
+ */
+ public Bounds getVisibleArea(int x, int y, int width, int height) {
+ Bounds visibleArea = null;
+
+ Component component = this;
+
+ int top = y;
+ int left = x;
+ int bottom = y + height - 1;
+ int right = x + width - 1;
+
+ while (component != null
+ && component.isVisible()) {
+ int topCutoff = 0;
+ int leftCutoff = 0;
+ int bottomCutoff = component.getHeight() - 1;
+ int rightCutoff = component.getWidth() - 1;
+
+ if (component instanceof Viewport) {
+ Viewport viewport = (Viewport)component;
+ Bounds viewportBounds = viewport.getViewportBounds();
+
+ topCutoff = viewportBounds.y;
+ leftCutoff = viewportBounds.x;
+ bottomCutoff = topCutoff + viewportBounds.height - 1;
+ rightCutoff = leftCutoff + viewportBounds.width - 1;
+ }
+
+ top = component.y + Math.max(top, topCutoff);
+ left = component.x + Math.max(left, leftCutoff);
+ bottom = component.y + Math.max(Math.min(bottom, bottomCutoff), -1);
+ right = component.x + Math.max(Math.min(right, rightCutoff), -1);
+
+ if (component instanceof Display) {
+ visibleArea = new Bounds(left, top, 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 x
+ * @param y
+ * @param width
+ * @param height
+ */
+ public void scrollAreaToVisible(int x, int y, int width, int 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 = x - viewportBounds.x;
+ int rightDisplacement = (x + width) -
+ (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);
+
+ x -= deltaX;
+ }
+
+ x = Math.max(x, viewportBounds.x);
+ width = Math.min(width,
+ Math.max(viewportBounds.width - (x - viewportBounds.x), 0));
+
+ int deltaY = 0;
+
+ int topDisplacement = y - viewportBounds.y;
+ int bottomDisplacement = (y + height) -
+ (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);
+
+ y -= deltaY;
+ }
+
+ y = Math.max(y, viewportBounds.y);
+ height = Math.min(height,
+ Math.max(viewportBounds.height - (y - 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
+ }
+ }
+
+ x += component.x;
+ y += component.y;
+
+ component = component.getParent();
+ }
+ }
+
+ /**
+ * Returns the component's valid state.
+ *
+ * @return
+ * <tt>true</tt>; non-container components are always valid.
+ */
+ public boolean isValid() {
+ return true;
+ }
+
+ /**
+ * Notifies the component's parent that it needs to re-layout.
+ */
+ public void invalidate() {
+ preferredWidthCache = null;
+ preferredHeightCache = null;
+
+ if (parent != null) {
+ parent.invalidate();
+ }
+ }
+
+ /**
+ * Lays out the component by calling {@link Skin#layout()}.
+ * <p>
+ * This is an effective no-op for non-containers since the skin's
+ * implementation of layout() will be a no-op.
+ */
+ public void validate() {
+ if (getWidth() > 0
+ && getHeight() > 0) {
+ skin.layout();
+ }
+ }
+
+ /**
+ * Flags the entire component as needing to be repainted.
+ */
+ public void repaint() {
+ repaint(false);
+ }
+
+ /**
+ * Flags the entire component as needing to be repainted or repaints
+ * the entire component immediately.
+ *
+ * @param immediate
+ */
+ public 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 x
+ * @param y
+ * @param width
+ * @param height
+ */
+ public final void repaint(int x, int y, int width, int height) {
+ repaint(x, y, width, height, false);
+ }
+
+ /**
+ * Flags an area as needing to be repainted or repaints the rectangle
+ * immediately.
+ *
+ * @param x
+ * @param y
+ * @param width
+ * @param height
+ * @param immediate
+ */
+ public void repaint(int x, int y, int width, int height, boolean immediate) {
+ if (parent != null) {
+ int top = y;
+ int left = x;
+ int bottom = top + height - 1;
+ int right = left + width - 1;
+
+ x = Math.max(left, 0);
+ y = Math.max(top, 0);
+ width = Math.min(right, getWidth() - 1) - x + 1;
+ height = Math.min(bottom, getHeight() - 1) - y + 1;
+
+ if (width > 0
+ && height > 0) {
+ parent.repaint(x + this.x, y + this.y, width, height);
+
+ for (Decorator decorator : decorators) {
+ Bounds affectedArea = decorator.getAffectedArea(this, x, y, width, height);
+ parent.repaint(affectedArea.x + this.x,
+ affectedArea.y + this.y,
+ affectedArea.width,
+ affectedArea.height);
+ }
+ }
+ }
+ }
+
+ /**
+ * Paints the component. Delegates to the skin.
+ */
+ public void paint(Graphics2D graphics) {
+ skin.paint(graphics);
+ }
+
+ /**
+ * Returns the component's enabled state.
+ *
+ * @return
+ * <tt>true</tt> if the component is enabled; <tt>false</tt>, 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
+ * <tt>true</tt> if the component is enabled; <tt>false</tt>, otherwise.
+ */
+ public void setEnabled(boolean enabled) {
+ if (this.enabled != enabled) {
+ Vote vote = componentStateListeners.previewEnabledChange(this);
+
+ if (vote == Vote.APPROVE) {
+ if (!enabled) {
+ // If this component has the focus, clear it
+ if (isFocused()) {
+ clearFocus();
+ }
+
+ // Ensure that the mouse out event is processed
+ if (mouseOver) {
+ mouseOut();
+ }
+ }
+
+ this.enabled = enabled;
+
+ componentStateListeners.enabledChanged(this);
+ } else {
+ componentStateListeners.enabledChangeVetoed(this, vote);
+ }
+ }
+ }
+
+ /**
+ * Determines if this component is blocked. A component is blocked if the
+ * component or any of its ancestors is disabled.
+ *
+ * @return
+ * <tt>true</tt> if the component is blocked; <tt>false</tt>, 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
+ * <tt>true</tt> if the mouse is currently located over this component;
+ * <tt>false</tt>, otherwise.
+ */
+ public boolean isMouseOver() {
+ return mouseOver;
+ }
+
+ /**
+ * 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.
+ */
+ public void setCursor(Cursor cursor) {
+ if (cursor == null) {
+ throw new IllegalArgumentException("cursor is null.");
+ }
+
+ Cursor previousCursor = this.cursor;
+
+ if (previousCursor != cursor) {
+ this.cursor = cursor;
+ componentListeners.cursorChanged(this, previousCursor);
+ }
+ }
+
+ public final void setCursor(String cursor) {
+ if (cursor == null) {
+ throw new IllegalArgumentException("cursor is null.");
+ }
+
+ setCursor(Cursor.decode(cursor));
+ }
+
+ /**
+ * Returns the component's tooltip text.
+ *
+ * @return
+ * The component's tooltip text, or <tt>null</tt> if no tooltip is
+ * specified.
+ */
+ public String getTooltipText() {
+ return tooltipText;
+ }
+
+ /**
+ * Sets the component's tooltip text.
+ *
+ * @param tooltipText
+ * The component's tooltip text, or <tt>null</tt> 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 drag handler.
+ *
+ * @return
+ * The component's drag handler, or <tt>null</tt> if no handler is
+ * installed.
+ */
+ public DragHandler getDragHandler() {
+ return dragHandler;
+ }
+
+ /**
+ * Sets the component's drag handler.
+ *
+ * @param dragHandler
+ * The drag handler to install, or <tt>null</tt> for no handler.
+ */
+ public void setDragHandler(DragHandler dragHandler) {
+ DragHandler previousDragHandler = this.dragHandler;
+ if (previousDragHandler != dragHandler) {
+ this.dragHandler = dragHandler;
+ componentDragDropListeners.dragHandlerChanged(this, previousDragHandler);
+ }
+ }
+
+ /**
+ * Returns the component's drop handler.
+ *
+ * @return
+ * The component's drop handler, or <tt>null</tt> if no handler is
+ * installed.
+ */
+ public DropHandler getDropHandler() {
+ return dropHandler;
+ }
+
+ /**
+ * Sets the component's drop handler.
+ *
+ * @param dropHandler
+ * The drop handler to install, or <tt>null</tt> for no handler.
+ */
+ public void setDropHandler(DropHandler dropHandler) {
+ DropHandler previousDropHandler = this.dropHandler;
+ if (previousDropHandler != dropHandler) {
+ this.dropHandler = dropHandler;
+ componentDragDropListeners.dropHandlerChanged(this, previousDropHandler);
+ }
+ }
+
+ /**
+ * Returns this component's focusability. A focusable component is capable
+ * of receiving the focus.
+ *
+ * @return
+ * <tt>true</tt> if the component is enabled and visible.
+ */
+ public boolean isFocusable() {
+ return skin.isFocusable();
+ }
+
+ /**
+ * Returns the component's focused state.
+ *
+ * @return
+ * <tt>true</tt> if the component has the input focus; <tt>false</tt>;
+ * otherwise.
+ */
+ public boolean isFocused() {
+ return focusedComponent == this;
+ }
+
+ /**
+ * Called to notify a component that its focus state has changed.
+ *
+ * @param focused
+ * <tt>true</tt> if the component has received the input focus;
+ * <tt>false</tt> if the component has lost the focus.
+ *
+ * @param temporary
+ * <tt>true</tt> if this focus change is temporary; <tt>false</tt>,
+ * otherwise.
+ */
+ protected void setFocused(boolean focused, boolean temporary) {
+ componentStateListeners.focusedChanged(this, temporary);
+ }
+
+ /**
+ * Requests that focus be given to this component.
+ */
+ public void requestFocus() {
+ requestFocus(false);
+ }
+
+ /**
+ * Requests that focus be given to this component.
+ *
+ * @param temporary
+ * If <tt>true</tt>, indicates that focus is being restored from a
+ * temporary loss.
+ */
+ protected void requestFocus(boolean temporary) {
+ if (!isFocusable()) {
+ throw new IllegalArgumentException("Component is not focusable.");
+ }
+
+ if (!isShowing()) {
+ throw new IllegalArgumentException("Component is not showing.");
+ }
+
+ if (isBlocked()) {
+ throw new IllegalArgumentException("Component is blocked.");
+ }
+
+ setFocusedComponent(this, temporary);
+ }
+
+ /**
+ * Transfers focus to the next focusable component.
+ *
+ * @param direction
+ * The direction in which to transfer focus.
+ */
+ public void transferFocus(Direction direction) {
+ Component component = this;
+
+ // Loop until we either find a component that is capable of receiving
+ // the focus or we run out of components
+ do {
+ // Attempt to traverse the current component's parent
+ Container container = component.getParent();
+ FocusTraversalPolicy focusTraversalPolicy = container.getFocusTraversalPolicy();
+
+ if (focusTraversalPolicy == null) {
+ // This container has no traversal policy; move up a level
+ component = container;
+ } else {
+ // Get the next component in the traversal
+ component = focusTraversalPolicy.getNextComponent(container, component, direction);
+
+ // If the next component is a container, attempt to traverse
+ // down into it
+ while (component instanceof Container) {
+ container = (Container)component;
+ component = null;
+
+ focusTraversalPolicy = container.getFocusTraversalPolicy();
+
+ if (focusTraversalPolicy != null) {
+ component = focusTraversalPolicy.getNextComponent(container, component, direction);
+ }
+ }
+
+ if (component == null) {
+ // We are at the end of the traversal; move up a level
+ component = container;
+ }
+ }
+ } while (component != null
+ && !(component.isFocusable()
+ && !component.isBlocked()
+ && component.isShowing()));
+
+ // Focus the component (which may be null)
+ setFocusedComponent(component, false);
+ }
+
+ /**
+ * Returns the currently focused component.
+ *
+ * @return
+ * The component that currently has the focus, or <tt>null</tt> if no
+ * component is focused.
+ */
+ public static Component getFocusedComponent() {
+ return focusedComponent;
+ }
+
+ /**
+ * Sets the focused component.
+ *
+ * @param focusedComponent
+ * The component to focus, or <tt>null</tt> to clear the focus.
+ *
+ * @param temporary
+ * <tt>true</tt> if this focus change is or was temporary; <tt>false</tt>,
+ * if it is permanent.
+ */
+ private static void setFocusedComponent(Component focusedComponent, boolean temporary) {
+ Component previousFocusedComponent = Component.focusedComponent;
+
+ if (previousFocusedComponent != focusedComponent) {
+ if (previousFocusedComponent != null) {
+ ComponentStateListener listeners = previousFocusedComponent.componentStateListeners;
+ Vote vote = listeners.previewFocusedChange(previousFocusedComponent, temporary);
+
+ if (!vote.isApproved()) {
+ listeners.focusedChangeVetoed(previousFocusedComponent, vote);
+ return;
+ }
+ }
+
+ if (focusedComponent != null) {
+ ComponentStateListener listeners = focusedComponent.componentStateListeners;
+ Vote vote = listeners.previewFocusedChange(focusedComponent, temporary);
+
+ if (!vote.isApproved()) {
+ listeners.focusedChangeVetoed(focusedComponent, vote);
+ return;
+ }
+ }
+
+ // Set the focused component
+ Component.focusedComponent = focusedComponent;
+
+ // Notify the components of the state change
+ if (previousFocusedComponent != null) {
+ previousFocusedComponent.setFocused(false, temporary);
+ }
+
+ if (focusedComponent == null) {
+ if (previousFocusedComponent != null
+ && !temporary) {
+ previousFocusedComponent.getWindow().setActiveDescendant(null);
+ }
+ } else {
+ focusedComponent.setFocused(true, temporary);
+ focusedComponent.getWindow().setActiveDescendant(focusedComponent);
+ }
+
+ componentClassListeners.focusedComponentChanged(previousFocusedComponent);
+ }
+ }
+
+ /**
+ * Clears the focus.
+ */
+ public static void clearFocus() {
+ clearFocus(false);
+ }
+
+ /**
+ * Returns the component dictionary.
+ */
+ public static ComponentDictionary getComponents() {
+ return componentDictionary;
+ }
+
+ /**
+ * Clears the focus.
+ *
+ * @param temporary
+ * If <tt>true</tt>, the focus is being cleared temporarily.
+ */
+ protected static void clearFocus(boolean temporary) {
+ setFocusedComponent(null, temporary);
+ }
+
+ /**
+ * 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(Dictionary<String, Object> context) {
+ }
+
+ /**
+ * 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(Dictionary<String, Object> context) {
+ }
+
+ public Object getUserData() {
+ return userData;
+ }
+
+ public void setUserData(Object userData) {
+ Object previousUserData = this.userData;
+ this.userData = userData;
+ componentDataListeners.userDataChanged(this, previousUserData);
+ }
+
+ /**
+ * Returns a dictionary instance representing the component's style
+ * properties. This is effectively a pass-through to the skin's dictionary
+ * implementation. It allows callers to modify the properties of the skin
+ * without directly obtaining a reference to the skin.
+ */
+ public StyleDictionary getStyles() {
+ return styleDictionary;
+ }
+
+ /**
+ * Applies a set of styles.
+ *
+ * @param styles
+ */
+ public void setStyles(Map<String, ?> 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 location of the styles to apply. If the styles have been previously
+ * applied, they will be retrieved from the resource cache in the
+ * application context. Otherwise, they will be loaded from the given
+ * location and added to the cache before being applied.
+ */
+ @SuppressWarnings("unchecked")
+ public void setStyles(URL styles) throws IOException, SerializationException {
+ if (styles == null) {
+ throw new IllegalArgumentException("styles is null.");
+ }
+
+ Map<String, Object> cachedStyles =
+ (Map<String, Object>)ApplicationContext.getResourceCache().get(styles);
+
+ if (cachedStyles == null) {
+ JSONSerializer jsonSerializer = new JSONSerializer();
+ cachedStyles =
+ (Map<String, Object>)jsonSerializer.readObject(styles.openStream());
+
+ ApplicationContext.getResourceCache().put(styles, cachedStyles);
+ }
+
+ setStyles(cachedStyles);
+ }
+
+ /**
+ * Applies a set of styles encoded as a JSON string.
+ *
+ * @param styles
+ */
+ public void setStyles(String styles) {
+ if (styles == null) {
+ throw new IllegalArgumentException("styles is null.");
+ }
+
+ setStyles(JSONSerializer.parseMap(styles));
+ }
+
+ /**
+ * Returns the currently installed attributes.
+ *
+ * @return
+ * This component's attributes
+ */
+ public Attributes getAttributes() {
+ return attributes;
+ }
+
+ /**
+ * Sets the attributes.
+ *
+ * @param attributes
+ */
+ protected void setAttributes(Attributes attributes) {
+ assert (parent != null);
+
+ if (this.attributes != null) {
+ this.attributes.setComponent(null);
+ }
+
+ this.attributes = attributes;
+
+ if (this.attributes != null) {
+ this.attributes.setComponent(this);
+ }
+ }
+
+ protected boolean mouseMove(int x, int y) {
+ boolean consumed = false;
+
+ if (enabled) {
+ consumed = componentMouseListeners.mouseMove(this, x, y);
+ }
+
+ return consumed;
+ }
+
+ protected void mouseOver() {
+ if (enabled) {
+ // Only change the cursor if a drag/drop is not active
+ Display display = getDisplay();
+ if (display != null) {
+ DragDropManager dragDropManager = display.getDragDropManager();
+ if (dragDropManager != null
+ && !dragDropManager.isActive()) {
+ Mouse.setCursor(cursor);
+ }
+ }
+
+ mouseOver = true;
+ componentMouseListeners.mouseOver(this);
+ }
+ }
+
+ protected void mouseOut() {
+ if (enabled) {
+ // Only change the cursor if a drag/drop is not active
+ Display display = getDisplay();
+ if (display != null) {
+ DragDropManager dragDropManager = display.getDragDropManager();
+ if (dragDropManager != null
+ && !dragDropManager.isActive()) {
+ Mouse.setCursor((parent == null) ?
+ Cursor.DEFAULT : parent.getCursor());
+ }
+ }
+
+ mouseOver = false;
+ componentMouseListeners.mouseOut(this);
+ }
+ }
+
+ protected boolean mouseDown(Mouse.Button button, int x, int y) {
+ boolean consumed = false;
+
+ if (enabled) {
+ consumed = componentMouseButtonListeners.mouseDown(this, button, x, y);
+ }
+
+ return consumed;
+ }
+
+ protected boolean mouseUp(Mouse.Button button, int x, int y) {
+ boolean consumed = false;
+
+ if (enabled) {
+ consumed = componentMouseButtonListeners.mouseUp(this, button, x, y);
+ }
+
+ return consumed;
+ }
+
+ protected void mouseClick(Mouse.Button button, int x, int y, int count) {
+ if (enabled) {
+ componentMouseButtonListeners.mouseClick(this, button, x, y, count);
+ }
+ }
+
+ protected boolean mouseWheel(Mouse.ScrollType scrollType, int scrollAmount,
+ int wheelRotation, int x, int y) {
+ boolean consumed = false;
+
+ if (enabled) {
+ consumed = componentMouseWheelListeners.mouseWheel(this, scrollType,
+ scrollAmount, wheelRotation, x, y);
+ }
+
+ return consumed;
+ }
+
+ protected void keyTyped(char character) {
+ if (enabled) {
+ componentKeyListeners.keyTyped(this, character);
+
+ if (parent != null) {
+ parent.keyTyped(character);
+ }
+ }
+ }
+
+ protected boolean keyPressed(int keyCode, Keyboard.KeyLocation keyLocation) {
+ boolean consumed = false;
+
+ if (enabled) {
+ 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 (enabled) {
+ 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() + "#" + getHandle();
+ return s;
+ }
+
+ public ListenerList<ComponentListener> getComponentListeners() {
+ return componentListeners;
+ }
+
+ public ListenerList<ComponentLayoutListener> getComponentLayoutListeners() {
+ return componentLayoutListeners;
+ }
+
+ public ListenerList<ComponentStateListener> getComponentStateListeners() {
+ return componentStateListeners;
+ }
+
+ public ListenerList<ComponentDecoratorListener> getComponentDecoratorListeners() {
+ return componentDecoratorListeners;
+ }
+
+ public ListenerList<ComponentMouseListener> getComponentMouseListeners() {
+ return componentMouseListeners;
+ }
+
+ public ListenerList<ComponentMouseButtonListener> getComponentMouseButtonListeners() {
+ return componentMouseButtonListeners;
+ }
+
+ public ListenerList<ComponentMouseWheelListener> getComponentMouseWheelListeners() {
+ return componentMouseWheelListeners;
+ }
+
+ public ListenerList<ComponentKeyListener> getComponentKeyListeners() {
+ return componentKeyListeners;
+ }
+
+ public ListenerList<ComponentDataListener> getComponentDataListeners() {
+ return componentDataListeners;
+ }
+
+ public ListenerList<ComponentDragDropListener> getComponentDragDropListeners() {
+ return componentDragDropListeners;
+ }
+
+ public static ListenerList<ComponentClassListener> getComponentClassListeners() {
+ return componentClassListeners;
+ }
+}
Added: incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/Component.png
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/Component.png?rev=754936&view=auto
==============================================================================
Binary file - no diff available.
Propchange: incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/Component.png
------------------------------------------------------------------------------
svn:mime-type = application/octet-stream
Added: incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/ComponentClassListener.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/ComponentClassListener.java?rev=754936&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/ComponentClassListener.java (added)
+++ incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/ComponentClassListener.java Mon Mar 16 16:36:10 2009
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.wtk;
+
+/**
+ * Component class listener interface.
+ *
+ * @author gbrown
+ */
+public interface ComponentClassListener {
+ /**
+ * Called when the focused component changes.
+ *
+ * @param previousFocusedComponent
+ */
+ public void focusedComponentChanged(Component previousFocusedComponent);
+}
Added: incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/ComponentDataListener.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/ComponentDataListener.java?rev=754936&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/ComponentDataListener.java (added)
+++ incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/ComponentDataListener.java Mon Mar 16 16:36:10 2009
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.wtk;
+
+/**
+ * Component data listener interface.
+ *
+ * @author gbrown
+ */
+public interface ComponentDataListener {
+ /**
+ * Called when a component's user data has changed.
+ *
+ * @param component
+ * @param previousValue
+ */
+ public void userDataChanged(Component component, Object previousValue);
+}
Added: incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/ComponentDecoratorListener.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/ComponentDecoratorListener.java?rev=754936&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/ComponentDecoratorListener.java (added)
+++ incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/ComponentDecoratorListener.java Mon Mar 16 16:36:10 2009
@@ -0,0 +1,40 @@
+package pivot.wtk;
+
+import pivot.collections.Sequence;
+
+/**
+ * Component decorator listener interface.
+ *
+ * @author gbrown
+ */
+public interface ComponentDecoratorListener {
+ /**
+ * Called when a decorator has been inserted into a component's decorator
+ * sequence.
+ *
+ * @param component
+ * @param index
+ */
+ public void decoratorInserted(Component component, int index);
+
+ /**
+ * Called when a decorator has been updated in a component's decorator
+ * sequence.
+ *
+ * @param component
+ * @param index
+ * @param previousDecorator
+ */
+ public void decoratorUpdated(Component component, int index, Decorator previousDecorator);
+
+ /**
+ * Called when decorators have been removed from a component's decorator
+ * sequence.
+ *
+ * @param component
+ * @param index
+ * @param decorators
+ */
+ public void decoratorsRemoved(Component component, int index,
+ Sequence<Decorator> decorators);
+}
Added: incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/ComponentDragDropListener.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/ComponentDragDropListener.java?rev=754936&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/ComponentDragDropListener.java (added)
+++ incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/ComponentDragDropListener.java Mon Mar 16 16:36:10 2009
@@ -0,0 +1,24 @@
+package pivot.wtk;
+
+/**
+ * Component drag/drop listener interface.
+ *
+ * @author gbrown
+ */
+public interface ComponentDragDropListener {
+ /**
+ * Called when a component's drag handler has changed.
+ *
+ * @param component
+ * @param previousDragHandler
+ */
+ public void dragHandlerChanged(Component component, DragHandler previousDragHandler);
+
+ /**
+ * Called when a component's drop handler has changed.
+ *
+ * @param component
+ * @param previousDropHandler
+ */
+ public void dropHandlerChanged(Component component, DropHandler previousDropHandler);
+}
Added: incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/ComponentInfo.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/ComponentInfo.java?rev=754936&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/ComponentInfo.java (added)
+++ incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/ComponentInfo.java Mon Mar 16 16:36:10 2009
@@ -0,0 +1,16 @@
+package pivot.wtk;
+
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Annotation that provides additional information about a component.
+ *
+ * @author eryzhikov
+ */
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ComponentInfo {
+ String icon();
+}
Added: incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/ComponentKeyListener.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/ComponentKeyListener.java?rev=754936&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/ComponentKeyListener.java (added)
+++ incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/ComponentKeyListener.java Mon Mar 16 16:36:10 2009
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.wtk;
+
+/**
+ * Component key listener interface.
+ *
+ * @author gbrown
+ */
+public interface ComponentKeyListener {
+ /**
+ * Called when a key has been typed.
+ *
+ * @param component
+ * @param character
+ */
+ public void keyTyped(Component component, char character);
+
+ /**
+ * Called when a key has been pressed.
+ *
+ * @param component
+ * @param keyCode
+ * @param keyLocation
+ *
+ * @return
+ * <tt>true</tt> to consume the event; <tt>false</tt> to allow it to
+ * propagate.
+ */
+ public boolean keyPressed(Component component, int keyCode, Keyboard.KeyLocation keyLocation);
+
+ /**
+ * Called when a key has been released.
+ *
+ * @param component
+ * @param keyCode
+ * @param keyLocation
+ *
+ * @return
+ * <tt>true</tt> to consume the event; <tt>false</tt> to allow it to
+ * propagate.
+ */
+ public boolean keyReleased(Component component, int keyCode, Keyboard.KeyLocation keyLocation);
+}