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:16:58 UTC

svn commit: r754926 [19/38] - in /incubator/pivot/tags/v1.0: ./ 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/cha...

Added: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/Span.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/Span.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/Span.java (added)
+++ incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/Span.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,229 @@
+/*
+ * 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 pivot.collections.Dictionary;
+
+/**
+ * Class representing a range of integer values. The range includes all
+ * values in the interval <i>[start, end]</i>. Values may be negative, but the
+ * value of <tt>start</tt> must be less than or equal to the value of
+ * <tt>end</tt>.
+ *
+ * @author gbrown
+ */
+public class Span {
+    private int start = 0;
+    private int end = 0;
+
+    public static final String START_KEY = "start";
+    public static final String END_KEY = "end";
+
+    public Span() {
+    }
+
+    public Span(Dictionary<String, ?> span) {
+        if (span == null) {
+            throw new IllegalArgumentException("span is null.");
+        }
+
+        if (!span.containsKey(START_KEY)) {
+            throw new IllegalArgumentException(START_KEY + " is required.");
+        }
+
+        if (!span.containsKey(END_KEY)) {
+            throw new IllegalArgumentException(END_KEY + " is required.");
+        }
+
+        setRange((Integer)span.get(START_KEY), (Integer)span.get(END_KEY));
+    }
+
+    public Span(Span span) {
+        if (span == null) {
+            throw new IllegalArgumentException("span is null.");
+        }
+
+        setRange(span.start, span.end);
+    }
+
+    public Span(int start, int end) {
+        setRange(start, end);
+    }
+
+    /**
+     * Returns the first value in the span.
+     */
+    public int getStart() {
+        return start;
+    }
+
+    /**
+     * Sets the first value in the span.
+     *
+     * @param start
+     * The first value in the span. Must be less than or equal to
+     * the end value.
+     */
+    public void setStart(int start) {
+        setRange(start, end);
+    }
+
+    /**
+     * Returns the last value in the span.
+     */
+    public int getEnd() {
+        return end;
+    }
+
+    /**
+     * Sets the last value in the span.
+     *
+     * @param end
+     * The last value in the span. Must be greater than or equal to
+     * the start value.
+     */
+    public void setEnd(int end) {
+        setRange(start, end);
+    }
+
+    /**
+     * Returns the length of the span.
+     *
+     * @return
+     * The length of the span (<tt>end</tt> minus <tt>start</tt> + 1).
+     */
+    public long getLength() {
+        return (end - start) + 1;
+    }
+
+    /**
+     * Sets the range of the span.
+     *
+     * @param start
+     * The first value in the span. Must be less than or equal to
+     * <tt>end</tt>.
+     *
+     * @param end
+     * The last value in the span. Must be greater than or equal to
+     * <tt>start</tt>.
+     */
+    public void setRange(int start, int end) {
+        if (start > end) {
+            throw new IllegalArgumentException("start is greater than end.");
+        }
+
+        this.start = start;
+        this.end = end;
+    }
+
+    /**
+     * Determines whether this span contains another span.
+     *
+     * @param span
+     * The span to test for containment.
+     *
+     * @return
+     * <tt>true</tt> if this span contains <tt>span</tt>; <tt>false</tt>,
+     * otherwise.
+     */
+    public boolean contains(Span span) {
+        if (span == null) {
+            throw new IllegalArgumentException("span is null.");
+        }
+
+        return (start <= span.start
+            && end >= span.end);
+    }
+
+    /**
+     * Determines whether this span intersects with another span.
+     *
+     * @param span
+     * The span to test for intersection.
+     *
+     * @return
+     * <tt>true</tt> if this span intersects with <tt>span</tt>;
+     * <tt>false</tt>, otherwise.
+     */
+    public boolean intersects(Span span) {
+        if (span == null) {
+            throw new IllegalArgumentException("span is null.");
+        }
+
+        return (start >= span.end
+            || end <= span.start);
+    }
+
+    /**
+     * Determines the intersection of this span and another span.
+     *
+     * @param span
+     * The span to intersect with this span.
+     *
+     * @return
+     * A new Span instance representing the intersection of this span and
+     * <tt>span</tt>, or null if the spans do not intersect.
+     */
+    public Span createIntersection(Span span) {
+        if (span == null) {
+            throw new IllegalArgumentException("span is null.");
+        }
+
+        Span intersection = null;
+
+        if (intersects(span)) {
+            intersection = new Span(Math.max(start, span.start),
+                Math.min(end, span.end));
+        }
+
+        return intersection;
+    }
+
+    /**
+     * Determines the union of this span and another span.
+     *
+     * @param span
+     * The span to union with this span.
+     *
+     * @return
+     * A new Span instance representing the union of this span and
+     * <tt>span</tt>.
+     */
+    public Span createUnion(Span span) {
+        if (span == null) {
+            throw new IllegalArgumentException("span is null.");
+        }
+
+        return new Span(Math.min(start, span.start),
+            Math.max(end, span.end));
+    }
+
+    public boolean equals(Object o) {
+        boolean equal = false;
+
+        if (o instanceof Span) {
+            Span span = (Span)o;
+            equal = (start == span.start
+                && end == span.end);
+        }
+
+        return equal;
+    }
+
+    public String toString() {
+        return ("{start: " + start + ", end: " + end + "}");
+    }
+}

Added: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SpanSequence.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SpanSequence.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SpanSequence.java (added)
+++ incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SpanSequence.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,375 @@
+/*
+ * 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.util.Comparator;
+
+import pivot.collections.ArrayList;
+import pivot.collections.Sequence;
+
+/**
+ * Class representing a sequence of sorted, consolidated spans.
+ *
+ * @author gbrown
+ */
+public class SpanSequence implements Sequence<Span> {
+    /**
+     * Determines the relative order of two spans.
+     *
+     * @author gbrown
+     */
+    public static class SpanComparator implements Comparator<Span> {
+        /**
+         * Compares two span values. A span is considered less than or greater
+         * than another span if and only if it is absolutely less than or
+         * greater than the other span; if the spans intersect in any way, they
+         * are considered equal.
+         *
+         * @return A positive value if <tt>span1</tt> is greater than
+         * <tt>span2</tt>; a negative value if <tt>span1</tt> is less than
+         * <tt>span2</tt>; a value of zero if <tt>span1</tt> intersects
+         * with <tt>span2</tt>.
+         */
+        public int compare(Span span1, Span span2) {
+            int result = (span1.getStart() > span2.getEnd()) ? 1
+                : (span2.getStart() > span1.getEnd()) ? -1 : 0;
+
+            return result;
+        }
+    }
+
+    /**
+     * The list of sorted, consolidated spans.
+     */
+    private ArrayList<Span> spans = new ArrayList<Span>();
+
+    /**
+     * Comparator used to locate and sort spans.
+     */
+    private static SpanComparator spanComparator = new SpanComparator();
+
+    /**
+     * Adds a span to the sequence, merging and removing intersecting spans
+     * as needed.
+     *
+     * @param span
+     * The span to add to the sequence.
+     *
+     * @return
+     * The index at which the span was added.
+     */
+    public int add(Span span) {
+        if (span == null) {
+            throw new IllegalArgumentException("span is null.");
+        }
+
+        // Get the insertion point
+        int i = indexOf(span);
+
+        if (i < 0) {
+            // The span did not intersect or connect with any currently
+            // selected span; insert it into the sequence
+            if (span.getLength() > 0) {
+                i = -(i + 1);
+                spans.insert(new Span(span), i);
+            }
+        } else {
+            // The new span intersects or connects with one or more currently
+            // selected spans; walk the selection list backward and forward from
+            // the insertion point to determine the consolidation range
+            int j = i;
+            int k = i;
+
+            int n = spans.getLength();
+
+            // Walk the list backward from the insertion point
+            while (j >= 0) {
+                Span existingSpan = spans.get(j);
+
+                if (existingSpan.getEnd() < span.getStart() - 1) {
+                    // The selected span falls outside the intersection
+                    // and connection range; exit the loop
+                    break;
+                }
+
+                // Get the previous selected span
+                existingSpan = (--j >= 0) ? spans.get(j) : null;
+            }
+
+            // Increment the lower bound index, since it points to one less than
+            // the index of the first intersecting span
+            j++;
+
+            // Walk the list forward from the insertion point
+            while (k < n) {
+                Span existingSpan = spans.get(k);
+
+                if (existingSpan.getStart() > span.getEnd() + 1) {
+                    // The selected span falls outside the intersection
+                    // and connection range; exit the loop
+                    break;
+                }
+
+                // Get the next selected span
+                existingSpan = (++k < n) ? spans.get(k) : null;
+            }
+
+            // Update the upper bound index, since it points to one more than
+            // the index of the last intersecting span
+            k--;
+
+            // Consolidate the selection and remove any redundant spans
+            Span lowerSpan = spans.get(j);
+            Span upperSpan = spans.get(k);
+
+            int start = Math.min(span.getStart(), lowerSpan.getStart());
+            int end = Math.max(span.getEnd(), upperSpan.getEnd());
+
+            lowerSpan.setRange(start, end);
+            spans.remove(j + 1, k - j);
+        }
+
+        return i;
+    }
+
+    /**
+     * Not supported.
+     */
+    public final void insert(Span span, int index) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Not supported.
+     */
+    public final Span update(int index, Span span) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Removes a span from the sequence, truncating and removing intersecting
+     * spans as needed.
+     *
+     * @param span
+     * The span to remove from the sequence.
+     *
+     * @return
+     * The index from which the span was removed.
+     */
+    public int remove(Span span) {
+        if (span == null) {
+            throw new IllegalArgumentException("span is null.");
+        }
+
+        // Get the intersection index
+        int i = indexOf(span);
+
+        if (i >= 0) {
+            Span existingSpan = spans.get(i);
+
+            if (existingSpan.getStart() < span.getStart()
+                && existingSpan.getEnd() > span.getEnd()) {
+                // Removing the span will split the intersecting selection
+                // into two spans
+                spans.insert(new Span(span.getEnd() + 1, existingSpan.getEnd()), i + 1);
+                existingSpan.setEnd(span.getStart() - 1);
+            } else {
+                // Determine the indexes of the upper and lower bounds of the
+                // intersection
+                int n = spans.getLength();
+
+                int j = i;
+                while (j >= 0
+                    && spans.get(j).getEnd() >= span.getStart()) {
+                    j--;
+                }
+                j++;
+
+                int k = i;
+                while (k < n
+                    && spans.get(k).getStart() <= span.getEnd()) {
+                    k++;
+                }
+                k--;
+
+                Span lowerSpan = spans.get(j);
+                Span upperSpan = spans.get(k);
+
+                if (lowerSpan.getStart() < span.getStart()) {
+                    // The lower bounding span will be partially cleared
+                    lowerSpan.setEnd(span.getStart() - 1);
+
+                    // Increment the lower bound index so this span isn't
+                    // removed from the selection
+                    j++;
+                }
+
+                if (upperSpan.getEnd() > span.getEnd()) {
+                    // The upper bounding span will be partially cleared
+                    upperSpan.setStart(span.getEnd() + 1);
+
+                    // Decrement the upper bound index so this span isn't
+                    // removed from the selection
+                    k--;
+                }
+
+                // Remove all completely cleared spans from the selection
+                if (k >= j) {
+                    spans.remove(j, (k - j) + 1);
+                }
+            }
+        }
+
+        return i;
+    }
+
+    /**
+     * Removes one or more spans from the sequence.
+     *
+     * @param index
+     * The starting index to remove.
+     *
+     * @param count
+     * The number of items to remove, beginning with <tt>index</tt>.
+     *
+     * @return
+     * A sequence containing the spans that were removed.
+     */
+    public Sequence<Span> remove(int index, int count) {
+        return spans.remove(index, count);
+    }
+
+    /**
+     * Removes all spans from the sequence.
+     */
+    public void clear() {
+        spans.clear();
+    }
+
+    /**
+     * Retrieves the span at the given index.
+     *
+     * @param index
+     * The index of the span to retrieve.
+     */
+    public Span get(int index) {
+        return spans.get(index);
+    }
+
+    /**
+     * Returns the index of the first identified span that intersects with
+     * the given span, or a negative value representing the insertion point
+     * of the span as defined by the binary search algorithm.
+     */
+    public int indexOf(Span span) {
+        return Search.binarySearch(spans, span, spanComparator);
+    }
+
+    /**
+     * Returns the length of the sequence.
+     *
+     * @return
+     * The number of spans in the sequence.
+     */
+    public int getLength() {
+        return spans.getLength();
+    }
+
+    /**
+     * Inserts an index into the span sequence.
+     *
+     * @param index
+     * The index to insert.
+     *
+     * @return
+     * The number of spans that were modified as a result of the insertion.
+     */
+    public int insertIndex(int index) {
+        // Keep track of the number of modified spans
+        int m = 0;
+
+        // Get the insertion point for the span corresponding to the given index
+        Span indexSpan = new Span(index, index);
+        int i = indexOf(indexSpan);
+
+        if (i < 0) {
+            // The inserted item does not intersect with a selected span
+            i = -(i + 1);
+        } else {
+            // The inserted item intersects with a currently selected span
+            Span span = get(i);
+
+            // If the spans' start values are equal, shift the selection;
+            // otherwise, insert the index into the selection
+            if (span.getStart() > indexSpan.getStart()) {
+                span.setEnd(span.getEnd() + 1);
+                m++;
+
+                // Start incrementing span bounds beginning at the next span index
+                i++;
+            }
+        }
+
+        // Increment any subsequent selection indexes
+        int n = getLength();
+        m += (n - i);
+
+        while (i < n) {
+            Span span = get(i);
+            span.setRange(span.getStart() + 1, span.getEnd() + 1);
+            i++;
+        }
+
+        return m;
+    }
+
+    /**
+     * Removes a range of indexes from the span sequence.
+     *
+     * @param index
+     * The first index to remove.
+     *
+     * @param count
+     * The number of indexes to remove.
+     *
+     * @return
+     * The number of spans that were modified as a result of the removal.
+     */
+    public int removeIndexes(int index, int count) {
+        // Clear any selections in the given range
+        Span rangeSpan = new Span(index, (index + count) - 1);
+        remove(rangeSpan);
+
+        // Decrement any subsequent selection indexes
+        Span indexSpan = new Span(index, index);
+        int i = indexOf(indexSpan);
+        assert (i < 0) : "i should be negative, since index should no longer be selected";
+
+        i = -(i + 1);
+
+        // Determine the number of spans to modify
+        int n = getLength();
+        int m = (n - i);
+
+        while (i < n) {
+            Span span = get(i);
+            span.setRange(span.getStart() - count, span.getEnd() - count);
+            i++;
+        }
+
+        return m;
+    }
+}

Added: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/Spinner.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/Spinner.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/Spinner.java (added)
+++ incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/Spinner.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,471 @@
+/*
+ * 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.util.Comparator;
+
+import pivot.collections.ArrayList;
+import pivot.collections.Dictionary;
+import pivot.collections.List;
+import pivot.collections.ListListener;
+import pivot.collections.Sequence;
+import pivot.serialization.JSONSerializer;
+import pivot.util.ListenerList;
+import pivot.wtk.content.SpinnerItemRenderer;
+
+/**
+ * Component that presents a means of cycling through a list of items.
+ *
+ * @author tvolkert
+ */
+@ComponentInfo(icon="Spinner.png")
+public class Spinner extends Container {
+    /**
+     * Spinner renderer interface.
+     *
+     * @author tvolkert
+     */
+    public interface ItemRenderer extends Renderer {
+        /**
+         * Prepares the renderer for layout or paint.
+         *
+         * @param item
+         * The item to render.
+         *
+         * @param spinner
+         * The host component.
+         */
+        public void render(Object item, Spinner spinner);
+    }
+
+    /**
+     * Spinner skin interface. Spinner skins must implement this interface to
+     * facilitate additional communication between the component and the skin.
+     *
+     * @author tvolkert
+     */
+    public interface Skin {
+        public Bounds getContentBounds();
+    }
+
+    /**
+     * List event handler.
+     *
+     * @author tvolkert
+     */
+    private class ListHandler implements ListListener<Object> {
+        public void itemInserted(List<Object> list, int index) {
+            int previousSelectedIndex = selectedIndex;
+
+            if (index <= selectedIndex) {
+                selectedIndex++;
+            }
+
+            // Notify listeners that items were inserted
+            spinnerItemListeners.itemInserted(Spinner.this, index);
+
+            // If the selection was modified, notify listeners of selection
+            // change
+            if (previousSelectedIndex != selectedIndex) {
+                spinnerSelectionListeners.selectedIndexChanged(Spinner.this,
+                    previousSelectedIndex);
+            }
+        }
+
+        public void itemsRemoved(List<Object> list, int index, Sequence<Object> items) {
+            int previousSelectedIndex = selectedIndex;
+
+            if (items == null) {
+                // All items were removed; clear the selection and notify
+                // listeners
+                selectedIndex = -1;
+                spinnerItemListeners.itemsRemoved(Spinner.this, index, -1);
+            } else {
+                int count = items.getLength();
+
+                if (index + count <= selectedIndex) {
+                    selectedIndex--;
+                } else if (index <= selectedIndex) {
+                    selectedIndex = -1;
+                }
+
+                // Notify listeners that items were removed
+                spinnerItemListeners.itemsRemoved(Spinner.this, index, count);
+            }
+
+            // Notify listeners of selection change if necessary
+            if (previousSelectedIndex != selectedIndex) {
+                spinnerSelectionListeners.selectedIndexChanged(Spinner.this,
+                    previousSelectedIndex);
+            }
+        }
+
+        public void itemUpdated(List<Object> list, int index, Object previousItem) {
+            spinnerItemListeners.itemUpdated(Spinner.this, index);
+        }
+
+        public void comparatorChanged(List<Object> list,
+            Comparator<Object> previousComparator) {
+            if (list.getComparator() != null) {
+                int previousSelectedIndex = selectedIndex;
+
+                selectedIndex = -1;
+                spinnerItemListeners.itemsSorted(Spinner.this);
+
+                if (previousSelectedIndex != selectedIndex) {
+                    spinnerSelectionListeners.selectedIndexChanged(Spinner.this,
+                        previousSelectedIndex);
+                }
+            }
+        }
+    }
+
+    /**
+     * Spinner listener list.
+     *
+     * @author tvolkert
+     */
+    private static class SpinnerListenerList extends ListenerList<SpinnerListener>
+        implements SpinnerListener {
+        public void spinnerDataChanged(Spinner spinner, List<?> previousSpinnerData) {
+            for (SpinnerListener listener : this) {
+                listener.spinnerDataChanged(spinner, previousSpinnerData);
+            }
+        }
+
+        public void itemRendererChanged(Spinner spinner,
+            Spinner.ItemRenderer previousItemRenderer) {
+            for (SpinnerListener listener : this) {
+                listener.itemRendererChanged(spinner, previousItemRenderer);
+            }
+        }
+
+        public void circularChanged(Spinner spinner) {
+            for (SpinnerListener listener : this) {
+                listener.circularChanged(spinner);
+            }
+        }
+
+        public void selectedValueKeyChanged(Spinner spinner,
+            String previousSelectedValueKey) {
+            for (SpinnerListener listener : this) {
+                listener.selectedValueKeyChanged(spinner, previousSelectedValueKey);
+            }
+        }
+    }
+
+    /**
+     * Spinner item listener list.
+     *
+     * @author tvolkert
+     */
+    private static class SpinnerItemListenerList extends ListenerList<SpinnerItemListener>
+        implements SpinnerItemListener {
+        public void itemInserted(Spinner spinner, int index) {
+            for (SpinnerItemListener listener : this) {
+                listener.itemInserted(spinner, index);
+            }
+        }
+
+        public void itemsRemoved(Spinner spinner, int index, int count) {
+            for (SpinnerItemListener listener : this) {
+                listener.itemsRemoved(spinner, index, count);
+            }
+        }
+
+        public void itemUpdated(Spinner spinner, int index) {
+            for (SpinnerItemListener listener : this) {
+                listener.itemUpdated(spinner, index);
+            }
+        }
+
+        public void itemsSorted(Spinner spinner) {
+            for (SpinnerItemListener listener : this) {
+                listener.itemsSorted(spinner);
+            }
+        }
+    }
+
+    /**
+     * Spinner selection listener list.
+     *
+     * @author tvolkert
+     */
+    private static class SpinnerSelectionListenerList
+        extends ListenerList<SpinnerSelectionListener>
+        implements SpinnerSelectionListener {
+        public void selectedIndexChanged(Spinner spinner, int previousSelectedIndex) {
+            for (SpinnerSelectionListener listener : this) {
+                listener.selectedIndexChanged(spinner, previousSelectedIndex);
+            }
+        }
+    }
+
+    private List<?> spinnerData = null;
+    private ListHandler spinnerDataHandler = new ListHandler();
+
+    private ItemRenderer itemRenderer = null;
+
+    private boolean circular = false;
+    private int selectedIndex = -1;
+
+    private String selectedValueKey = null;
+
+    private SpinnerListenerList spinnerListeners = new SpinnerListenerList();
+    private SpinnerItemListenerList spinnerItemListeners = new SpinnerItemListenerList();
+    private SpinnerSelectionListenerList spinnerSelectionListeners =
+        new SpinnerSelectionListenerList();
+
+    /**
+     * Creates a spinner populated with an empty array list.
+     */
+    public Spinner() {
+        this(new ArrayList<Object>());
+    }
+
+    /**
+     * Creates a spinner populated with the given spinner data.
+     *
+     * @param spinnerData
+     */
+    public Spinner(List<?> spinnerData) {
+        setItemRenderer(new SpinnerItemRenderer());
+        setSpinnerData(spinnerData);
+
+        installSkin(Spinner.class);
+    }
+
+    /**
+     * Returns the spinner data.
+     *
+     * @return
+     * The data currently presented by the spinner.
+     */
+    public List<?> getSpinnerData() {
+        return spinnerData;
+    }
+
+    /**
+     * Sets the spinner data. Clears any existing selection state.
+     *
+     * @param spinnerData
+     * The data to be presented by the spinner.
+     */
+    @SuppressWarnings("unchecked")
+    public void setSpinnerData(List<?> spinnerData) {
+        if (spinnerData == null) {
+            throw new IllegalArgumentException("spinnerData is null.");
+        }
+
+        List<?> previousSpinnerData = this.spinnerData;
+
+        if (previousSpinnerData != spinnerData) {
+            if (previousSpinnerData != null) {
+                // Clear any existing selection
+                setSelectedIndex(-1);
+
+                ((List<Object>)previousSpinnerData).getListListeners().remove(spinnerDataHandler);
+            }
+
+            ((List<Object>)spinnerData).getListListeners().add(spinnerDataHandler);
+
+            // Update the spinner data and fire change event
+            this.spinnerData = spinnerData;
+            spinnerListeners.spinnerDataChanged(this, previousSpinnerData);
+        }
+    }
+
+    public void setSpinnerData(String spinnerData) {
+        if (spinnerData == null) {
+            throw new IllegalArgumentException("spinnerData is null.");
+        }
+
+        setSpinnerData(JSONSerializer.parseList(spinnerData));
+    }
+
+    @Override
+    protected void setSkin(pivot.wtk.Skin skin) {
+        if (!(skin instanceof Spinner.Skin)) {
+            throw new IllegalArgumentException("Skin class must implement "
+                + Spinner.Skin.class.getName());
+        }
+
+        super.setSkin(skin);
+    }
+
+    /**
+     * Returns the item renderer used for items in this list.
+     */
+    public ItemRenderer getItemRenderer() {
+        return itemRenderer;
+    }
+
+    /**
+     * Sets the item renderer to be used for items in this list.
+     *
+     * @param itemRenderer
+     * The item renderer for the list.
+     */
+    public void setItemRenderer(ItemRenderer itemRenderer) {
+        if (itemRenderer == null) {
+            throw new IllegalArgumentException("itemRenderer is null.");
+        }
+
+        ItemRenderer previousItemRenderer = this.itemRenderer;
+
+        if (previousItemRenderer != itemRenderer) {
+            this.itemRenderer = itemRenderer;
+            spinnerListeners.itemRendererChanged(this, previousItemRenderer);
+        }
+    }
+
+    /**
+     *
+     */
+    public boolean isCircular() {
+        return circular;
+    }
+
+    /**
+     *
+     */
+    public void setCircular(boolean circular) {
+        if (circular != this.circular) {
+            this.circular = circular;
+            spinnerListeners.circularChanged(this);
+        }
+    }
+
+    /**
+     * Returns the currently selected index.
+     *
+     * @return
+     * The currently selected index.
+     */
+    public int getSelectedIndex() {
+        return selectedIndex;
+    }
+
+    /**
+     * Sets the selection to the specified index.
+     *
+     * @param selectedIndex
+     * The index to select, or <tt>-1</tt> to clear the selection.
+     */
+    public void setSelectedIndex(int selectedIndex) {
+        int previousSelectedIndex = this.selectedIndex;
+
+        if (previousSelectedIndex != selectedIndex) {
+            this.selectedIndex = selectedIndex;
+            spinnerSelectionListeners.selectedIndexChanged(this, previousSelectedIndex);
+        }
+    }
+
+    public Object getSelectedValue() {
+        int index = getSelectedIndex();
+        Object value = null;
+
+        if (index >= 0) {
+            value = spinnerData.get(index);
+        }
+
+        return value;
+    }
+
+    @SuppressWarnings("unchecked")
+    public void setSelectedValue(Object value) {
+        if (value == null) {
+            throw new IllegalArgumentException("value is null");
+        }
+
+        int index = ((List<Object>)spinnerData).indexOf(value);
+        if (index == -1) {
+            throw new IllegalArgumentException("\"" + value + "\" is not a valid selection.");
+        }
+
+        setSelectedIndex(index);
+    }
+
+    /**
+     * Gets the data binding key that is set on this spinner.
+     */
+    public String getSelectedValueKey() {
+        return selectedValueKey;
+    }
+
+    /**
+     * Sets this spinner's data binding key.
+     */
+    public void setSelectedValueKey(String selectedValueKey) {
+        String previousSelectedValueKey = this.selectedValueKey;
+
+        if ((selectedValueKey == null ^ previousSelectedValueKey == null)
+            || (selectedValueKey != null && !selectedValueKey.equals(previousSelectedValueKey))) {
+            this.selectedValueKey = selectedValueKey;
+            spinnerListeners.selectedValueKeyChanged(this, previousSelectedValueKey);
+        }
+    }
+
+    @Override
+    public void load(Dictionary<String, Object> context) {
+        if (selectedValueKey != null
+            && context.containsKey(selectedValueKey)) {
+            Object value = context.get(selectedValueKey);
+            setSelectedValue(value);
+        }
+    }
+
+    @Override
+    public void store(Dictionary<String, Object> context) {
+        if (selectedValueKey != null) {
+            Object value = getSelectedValue();
+            context.put(selectedValueKey, value);
+        }
+    }
+
+    /**
+     * Gets the bounding area of the spinner content (the area in which the
+     * item renderer will render the content).
+     *
+     * @return
+     * The bounding area of the spinner content.
+     */
+    public Bounds getContentBounds() {
+        Spinner.Skin spinnerSkin = (Spinner.Skin)getSkin();
+        return spinnerSkin.getContentBounds();
+    }
+
+    /**
+     * Returns the spinner listener list.
+     */
+    public ListenerList<SpinnerListener> getSpinnerListeners() {
+        return spinnerListeners;
+    }
+
+    /**
+     * Returns the spinner item listener list.
+     */
+    public ListenerList<SpinnerItemListener> getSpinnerItemListeners() {
+        return spinnerItemListeners;
+    }
+
+    /**
+     * Returns the spinner selection listener list.
+     */
+    public ListenerList<SpinnerSelectionListener> getSpinnerSelectionListeners() {
+        return spinnerSelectionListeners;
+    }
+}

Added: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/Spinner.png
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/Spinner.png?rev=754926&view=auto
==============================================================================
Binary file - no diff available.

Propchange: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/Spinner.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SpinnerItemListener.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SpinnerItemListener.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SpinnerItemListener.java (added)
+++ incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SpinnerItemListener.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,55 @@
+/*
+ * 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;
+
+/**
+ * Spinner item listener interface.
+ *
+ * @author tvolkert
+ */
+public interface SpinnerItemListener {
+    /**
+     * Called when an item is inserted into the spinner data.
+     *
+     * @param spinner
+     * @param index
+     */
+    public void itemInserted(Spinner spinner, int index);
+
+    /**
+     * Called when items are removed from the spinner data.
+     *
+     * @param spinner
+     * @param index
+     * @param count
+     */
+    public void itemsRemoved(Spinner spinner, int index, int count);
+
+    /**
+     * Called when an item is updated within the spinner data.
+     *
+     * @param spinner
+     * @param index
+     */
+    public void itemUpdated(Spinner spinner, int index);
+
+    /**
+     * Called when the spinner data is sorted
+     *
+     * @param spinner
+     */
+    public void itemsSorted(Spinner spinner);
+}

Added: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SpinnerListener.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SpinnerListener.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SpinnerListener.java (added)
+++ incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SpinnerListener.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,56 @@
+/*
+ * 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 pivot.collections.List;
+
+/**
+ * Spinner listener interface.
+ *
+ * @author tvolkert
+ */
+public interface SpinnerListener {
+    /**
+     * Called when a spinner's data has changed.
+     *
+     * @param spinner
+     * @param previousSpinnerData
+     */
+    public void spinnerDataChanged(Spinner spinner, List<?> previousSpinnerData);
+
+    /**
+     * Called when a spinner's item renderer has changed.
+     *
+     * @param spinner
+     * @param previousItemRenderer
+     */
+    public void itemRendererChanged(Spinner spinner, Spinner.ItemRenderer previousItemRenderer);
+
+    /**
+     * Called when a spinner's circular property has changed.
+     *
+     * @param spinner
+     */
+    public void circularChanged(Spinner spinner);
+
+    /**
+     * Called when a spinner's selected value key has changed.
+     *
+     * @param spinner
+     * @param previousSelectedValueKey
+     */
+    public void selectedValueKeyChanged(Spinner spinner, String previousSelectedValueKey);
+}

Added: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SpinnerSelectionListener.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SpinnerSelectionListener.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SpinnerSelectionListener.java (added)
+++ incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SpinnerSelectionListener.java Mon Mar 16 16:16:40 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;
+
+/**
+ * Spinner selection listener interface.
+ *
+ * @author tvolkert
+ */
+public interface SpinnerSelectionListener {
+    /**
+     * Called when a spinner's selected index has changed.
+     *
+     * @param spinner
+     * @param previousSelectedIndex
+     */
+    public void selectedIndexChanged(Spinner spinner, int previousSelectedIndex);
+}

Added: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SplitPane.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SplitPane.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SplitPane.java (added)
+++ incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SplitPane.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,349 @@
+/*
+ * 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 pivot.collections.Dictionary;
+import pivot.collections.Sequence;
+import pivot.serialization.JSONSerializer;
+import pivot.util.ListenerList;
+
+/**
+ * A <tt>SplitPane</tt> is a container component that splits its size up into
+ * two regions, each of which is capable of holding one component.  A split
+ * pane may be setup to support either horizontal or veritcal splits.  The area
+ * in between the two regions is known as the <i>splitter</i> and typically
+ * allows the user to adjust the partitioning between the two regions.
+ * <p>
+ * Since <tt>SplitPane</tt>s only support a single splitter, multiple
+ * <tt>SplitPane</tt>s may be nested to support more complex layouts.  In
+ * that case, one split pane will "own" the other.  The implication of this
+ * is noticed when a split pane directly contains a child split pane of the same
+ * orientation.  The parent pane's separator will be able to travel past that
+ * of it's child, but the child's separator will be unable to pass the parent's.
+ *
+ * @author tvolkert
+ */
+@ComponentInfo(icon="SplitPane.png")
+public class SplitPane extends Container {
+    /**
+     * Enumeration defining split pane regions.
+     *
+     * @author gbrown
+     */
+    public enum Region {
+        TOP_LEFT,
+        BOTTOM_RIGHT;
+
+        public static Region decode(String value) {
+            return valueOf(value.toUpperCase());
+        }
+    }
+
+    private static class SplitPaneListenerList extends ListenerList<SplitPaneListener>
+        implements SplitPaneListener {
+        public void topLeftComponentChanged(SplitPane splitPane, Component previousTopLeftComponent) {
+            for (SplitPaneListener listener : this) {
+                listener.topLeftComponentChanged(splitPane, previousTopLeftComponent);
+            }
+        }
+
+        public void bottomRightComponentChanged(SplitPane splitPane, Component previousBottomRightComponent) {
+            for (SplitPaneListener listener : this) {
+                listener.bottomRightComponentChanged(splitPane, previousBottomRightComponent);
+            }
+        }
+
+        public void orientationChanged(SplitPane splitPane) {
+            for (SplitPaneListener listener : this) {
+                listener.orientationChanged(splitPane);
+            }
+        }
+
+        public void primaryRegionChanged(SplitPane splitPane) {
+            for (SplitPaneListener listener : this) {
+                listener.primaryRegionChanged(splitPane);
+            }
+        }
+
+        public void splitLocationChanged(SplitPane splitPane, int previousSplitLocation) {
+            for (SplitPaneListener listener : this) {
+                listener.splitLocationChanged(splitPane, previousSplitLocation);
+            }
+        }
+
+        public void splitBoundsChanged(SplitPane splitPane, Span previousSplitBounds) {
+            for (SplitPaneListener listener : this) {
+                listener.splitBoundsChanged(splitPane, previousSplitBounds);
+            }
+        }
+
+        public void lockedChanged(SplitPane splitPane) {
+            for (SplitPaneListener listener : this) {
+                listener.lockedChanged(splitPane);
+            }
+        }
+    }
+
+    Component topLeftComponent = null;
+    Component bottomRightComponent = null;
+    private Orientation orientation = null;
+    private Region primaryRegion = Region.TOP_LEFT;
+    private int splitLocation = 0;
+    private Span splitBounds = null;
+    private boolean locked = false;
+
+    private SplitPaneListenerList splitPaneListeners = new SplitPaneListenerList();
+
+    // TODO Define a constructor that takes 2 components as arguments
+
+    public SplitPane() {
+        this(Orientation.HORIZONTAL);
+    }
+
+    public SplitPane(Orientation orientation) {
+        this.orientation = orientation;
+
+        installSkin(SplitPane.class);
+    }
+
+    public Component getTopLeftComponent() {
+        return topLeftComponent;
+    }
+
+    public void setTopLeftComponent(Component topLeftComponent) {
+        if (topLeftComponent != this.topLeftComponent) {
+            // Set the component as the new top/left component
+            Component previousTopLeftComponent = this.topLeftComponent;
+            this.topLeftComponent = topLeftComponent;
+
+            // Remove any previous content component
+            if (previousTopLeftComponent != null) {
+                remove(previousTopLeftComponent);
+            }
+
+            if (topLeftComponent != null) {
+                if (topLeftComponent.getParent() != null) {
+                    throw new IllegalArgumentException("Component already has a parent.");
+                }
+
+                // Add the component
+                add(topLeftComponent);
+            }
+
+            splitPaneListeners.topLeftComponentChanged(this, previousTopLeftComponent);
+        }
+    }
+
+    public Component getBottomRightComponent() {
+        return bottomRightComponent;
+    }
+
+    public void setBottomRightComponent(Component bottomRightComponent) {
+        if (bottomRightComponent != this.bottomRightComponent) {
+            // Set the component as the new bottom/right component
+            Component previousBottomRightComponent = this.bottomRightComponent;
+            this.bottomRightComponent = bottomRightComponent;
+
+            // Remove any previous content component
+            if (previousBottomRightComponent != null) {
+                remove(previousBottomRightComponent);
+            }
+
+            if (bottomRightComponent != null) {
+                if (bottomRightComponent.getParent() != null) {
+                    throw new IllegalArgumentException("Component already has a parent.");
+                }
+
+                // Add the component
+                add(bottomRightComponent);
+            }
+
+            splitPaneListeners.bottomRightComponentChanged(this, previousBottomRightComponent);
+        }
+    }
+
+    public Component getTop() {
+        return (orientation == Orientation.HORIZONTAL) ? null : getTopLeftComponent();
+    }
+
+    public void setTop(Component component) {
+        setTopLeftComponent(component);
+    }
+
+    public Component getBottom() {
+        return (orientation == Orientation.HORIZONTAL) ? null : getBottomRightComponent();
+    }
+
+    public void setBottom(Component component) {
+        setBottomRightComponent(component);
+    }
+
+    public Component getLeft() {
+        return (orientation == Orientation.VERTICAL) ? null : getTopLeftComponent();
+    }
+
+    public void setLeft(Component component) {
+        setTopLeftComponent(component);
+    }
+
+    public Component getRight() {
+        return (orientation == Orientation.VERTICAL) ? null : getBottomRightComponent();
+    }
+
+    public void setRight(Component component) {
+        setBottomRightComponent(component);
+    }
+
+    public Orientation getOrientation() {
+        return orientation;
+    }
+
+    public void setOrientation(Orientation orientation) {
+        if (orientation == null) {
+            throw new IllegalArgumentException("orientation is null.");
+        }
+
+        if (this.orientation != orientation) {
+            this.orientation = orientation;
+
+            splitPaneListeners.orientationChanged(this);
+        }
+    }
+
+    public void setOrientation(String orientation) {
+        if (orientation == null) {
+            throw new IllegalArgumentException("orientation is null.");
+        }
+
+        setOrientation(Orientation.decode(orientation));
+    }
+
+    public Region getPrimaryRegion() {
+        return primaryRegion;
+    }
+
+    public void setPrimaryRegion(Region primaryRegion) {
+        if (primaryRegion == null) {
+            throw new IllegalArgumentException("primaryRegion is null.");
+        }
+
+        if (this.primaryRegion != primaryRegion) {
+            this.primaryRegion = primaryRegion;
+
+            splitPaneListeners.primaryRegionChanged(this);
+        }
+    }
+
+    public void setPrimaryRegion(String primaryRegion) {
+        if (primaryRegion == null) {
+            throw new IllegalArgumentException("primaryRegion is null.");
+        }
+
+        setPrimaryRegion(Region.decode(primaryRegion));
+    }
+
+    public int getSplitLocation() {
+        return splitLocation;
+    }
+
+    public void setSplitLocation(int splitLocation) {
+        int previousSplitLocation = this.splitLocation;
+
+        if (previousSplitLocation != splitLocation) {
+            this.splitLocation = splitLocation;
+            splitPaneListeners.splitLocationChanged(this, previousSplitLocation);
+        }
+    }
+
+    public Span getSplitBounds() {
+        return splitBounds;
+    }
+
+    public void setSplitBounds(Span splitBounds) {
+        // Check if this is a no-op.
+        if (this.splitBounds == null) {
+           if (splitBounds == null) {
+              return;
+           }
+        } else {
+           if (this.splitBounds.equals(splitBounds)) {
+              return;
+           }
+        }
+
+        int start = splitBounds.getStart();
+        int end = splitBounds.getEnd();
+
+        Span previousSplitBounds = this.splitBounds;
+        this.splitBounds = new Span(start, end);
+
+        // Reposition the splitter if necessary.
+        if (splitBounds != null) {
+           if (splitLocation < start) {
+              setSplitLocation(start);
+           } else if (splitLocation > end) {
+              setSplitLocation(end);
+           }
+        }
+
+        splitPaneListeners.splitBoundsChanged(this, previousSplitBounds);
+    }
+
+    public final void setSplitBounds(Dictionary<String, ?> splitBounds) {
+        if (splitBounds == null) {
+            throw new IllegalArgumentException("splitBounds is null.");
+        }
+
+        setSplitBounds(new Span(splitBounds));
+    }
+
+    public final void setSplitBounds(String splitBounds) {
+        if (splitBounds == null) {
+            throw new IllegalArgumentException("splitBounds is null.");
+        }
+
+        setSplitBounds(JSONSerializer.parseMap(splitBounds));
+    }
+
+    public boolean isLocked() {
+        return locked;
+    }
+
+    public void setLocked(boolean locked) {
+        if (this.locked != locked) {
+            this.locked = locked;
+            splitPaneListeners.lockedChanged(this);
+        }
+    }
+
+    @Override
+    public Sequence<Component> remove(int index, int count) {
+        for (int i = index, n = index + count; i < n; i++) {
+            Component component = get(i);
+            if (component == topLeftComponent
+                || component == bottomRightComponent) {
+                throw new UnsupportedOperationException();
+            }
+        }
+
+        // Call the base method to remove the components
+        return super.remove(index, count);
+    }
+
+    public ListenerList<SplitPaneListener> getSplitPaneListeners() {
+        return splitPaneListeners;
+    }
+}

Added: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SplitPane.png
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SplitPane.png?rev=754926&view=auto
==============================================================================
Binary file - no diff available.

Propchange: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SplitPane.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SplitPaneListener.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SplitPaneListener.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SplitPaneListener.java (added)
+++ incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SplitPaneListener.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,76 @@
+/*
+ * 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;
+
+/**
+ * Split pane listener interface.
+ *
+ * @author tvolkert
+ */
+public interface SplitPaneListener {
+    /**
+     * Called when a split pane's top left component has changed.
+     *
+     * @param splitPane
+     * @param previousTopLeftComponent
+     */
+    public void topLeftComponentChanged(SplitPane splitPane, Component previousTopLeftComponent);
+
+    /**
+     * Called when a split pane's bottom right component has changed.
+     *
+     * @param splitPane
+     * @param previousBottomRightComponent
+     */
+    public void bottomRightComponentChanged(SplitPane splitPane, Component previousBottomRightComponent);
+
+    /**
+     * Called when a split pane's orientation has changed.
+     *
+     * @param splitPane
+     */
+    public void orientationChanged(SplitPane splitPane);
+
+    /**
+     * Called when a split pane's primary region has changed.
+     *
+     * @param splitPane
+     */
+    public void primaryRegionChanged(SplitPane splitPane);
+
+    /**
+     * Called when a split pane's split location has changed.
+     *
+     * @param splitPane
+     * @param previousSplitLocation
+     */
+    public void splitLocationChanged(SplitPane splitPane, int previousSplitLocation);
+
+    /**
+     * Called when a split pane's split bounds have changed.
+     *
+     * @param splitPane
+     * @param previousSplitBounds
+     */
+    public void splitBoundsChanged(SplitPane splitPane, Span previousSplitBounds);
+
+    /**
+     * Called when a split pane's locked flag has changed.
+     *
+     * @param splitPane
+     */
+    public void lockedChanged(SplitPane splitPane);
+}

Added: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/StackPane.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/StackPane.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/StackPane.java (added)
+++ incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/StackPane.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,28 @@
+/*
+ * 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;
+
+/**
+ * Container that behaves like a stack of transparencies, all of which are
+ * visible at the same time.
+ *
+ * @author gbrown
+ */
+public class StackPane extends Container {
+    public StackPane() {
+        installSkin(StackPane.class);
+    }
+}

Added: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SwingAdapter.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SwingAdapter.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SwingAdapter.java (added)
+++ incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SwingAdapter.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,269 @@
+/*
+ * 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.BorderLayout;
+import java.awt.Graphics2D;
+import javax.swing.JComponent;
+
+import pivot.util.ListenerList;
+import pivot.wtk.skin.ComponentSkin;
+
+/**
+ * Component that wraps a Swing <tt>JComponent</tt> for use in a pivot
+ * application.
+ * <p>
+ * NOTE: Some Swing components do not play nicely with Pivot's
+ * <tt>ScrollPane</tt> class. If this behavior is seen, it is recommended that
+ * you place your Swing component into a <tt>JScrollPane</tt> instead of using
+ * a Pivot scroll pane.
+ *
+ * @author tvolkert
+ */
+public class SwingAdapter extends Component {
+    /**
+     * Swing adapter skin.
+     * <p>
+     * NOTE: This must live in <tt>pivot.wtk</tt> because it needs protected
+     * access to the display host.
+     *
+     * @author tvolkert
+     */
+    private class SwingAdapterSkin extends ComponentSkin implements SwingAdapterListener {
+        private class SwingContainer extends java.awt.Container {
+            static final long serialVersionUID = -9151344702095162523L;
+
+            public SwingContainer() {
+                setLayout(new BorderLayout());
+            }
+
+            @Override
+            public void invalidate() {
+                super.invalidate();
+                SwingAdapterSkin.this.getComponent().invalidate();
+            }
+        }
+
+        private ComponentListener componentHandler = new ComponentListener() {
+            public void parentChanged(Component component, Container previousParent) {
+                Display display = component.getDisplay();
+                Display previousDisplay = (previousParent == null) ?
+                    null : previousParent.getDisplay();
+
+                // Add our swingContainer to the correct display host
+                if (display != previousDisplay) {
+                    if (previousDisplay != null) {
+                        previousDisplay.getApplicationContext().getDisplayHost().remove(swingContainer);
+                    }
+
+                    if (display != null) {
+                        display.getApplicationContext().getDisplayHost().add(swingContainer);
+                    }
+                }
+
+                // Stop listening on the previous ancestry
+                Component previousAncestor = previousParent;
+                while (previousAncestor != null) {
+                    previousAncestor.getComponentListeners().remove(this);
+                    previousAncestor = previousAncestor.getParent();
+                }
+
+                // Start listening on the new ancestry
+                Component ancestor = component.getParent();
+                while (ancestor != null) {
+                    ancestor.getComponentListeners().add(this);
+                    ancestor = ancestor.getParent();
+                }
+            }
+
+            public void sizeChanged(Component component, int previousWidth, int previousHeight) {
+                // No-op
+            }
+
+            public void locationChanged(Component component, int previousX, int previousY) {
+                SwingAdapter swingAdapter = (SwingAdapter)getComponent();
+
+                Display display = swingAdapter.getDisplay();
+                Point displayCoordinates = swingAdapter.mapPointToAncestor(display, 0, 0);
+                swingContainer.setLocation(displayCoordinates.x, displayCoordinates.y);
+            }
+
+            public void visibleChanged(Component component) {
+                SwingAdapter swingAdapter = (SwingAdapter)getComponent();
+                swingContainer.setVisible(swingAdapter.isShowing());
+            }
+
+            public void styleUpdated(Component component, String styleKey, Object previousValue) {
+                // No-op
+            }
+
+            public void cursorChanged(Component component, Cursor previousCursor) {
+                // No-op
+            }
+
+            public void tooltipTextChanged(Component component, String previousTooltipText) {
+                // No-op
+            }
+        };
+
+        private SwingContainer swingContainer = new SwingContainer();
+
+        @Override
+        public void install(Component component) {
+            super.install(component);
+
+            SwingAdapter swingAdapter = (SwingAdapter)component;
+            swingAdapter.getSwingAdapterListeners().add(this);
+
+            swingAdapter.getComponentListeners().add(componentHandler);
+            componentHandler.parentChanged(swingAdapter, null);
+
+            swingComponentChanged(swingAdapter, null);
+        }
+
+        @Override
+        public void uninstall() {
+            SwingAdapter swingAdapter = (SwingAdapter)getComponent();
+            swingAdapter.getSwingAdapterListeners().remove(this);
+
+            Component ancestor = swingAdapter;
+            while (ancestor != null) {
+                ancestor.getComponentListeners().remove(componentHandler);
+                ancestor = ancestor.getParent();
+            }
+
+            Display display = swingAdapter.getDisplay();
+            if (display != null) {
+                display.getApplicationContext().getDisplayHost().remove(swingContainer);
+            }
+
+            JComponent swingComponent = swingAdapter.getSwingComponent();
+            if (swingComponent != null) {
+                swingContainer.remove(swingComponent);
+            }
+
+            super.uninstall();
+        }
+
+        public int getPreferredWidth(int height) {
+            return getPreferredSize().width;
+        }
+
+        public int getPreferredHeight(int width) {
+            return getPreferredSize().height;
+        }
+
+        @Override
+        public Dimensions getPreferredSize() {
+            java.awt.Dimension preferredSize = swingContainer.getPreferredSize();
+            return new Dimensions(preferredSize.width, preferredSize.height);
+        }
+
+        public void layout() {
+            SwingAdapter swingAdapter = (SwingAdapter)getComponent();
+
+            int width = getWidth();
+            int height = getHeight();
+
+            Display display = swingAdapter.getDisplay();
+            Point displayCoordinates = swingAdapter.mapPointToAncestor(display, 0, 0);
+            swingContainer.setLocation(displayCoordinates.x, displayCoordinates.y);
+
+            swingContainer.setSize(width, height);
+            swingContainer.validate();
+        }
+
+        public void paint(Graphics2D graphics) {
+            swingContainer.paint(graphics);
+        }
+
+        @Override
+        public boolean isFocusable() {
+            return false;
+        }
+
+        @Override
+        public void enabledChanged(Component component) {
+            SwingAdapter swingAdapter = (SwingAdapter)getComponent();
+            JComponent swingComponent = swingAdapter.getSwingComponent();
+
+            swingComponent.setEnabled(component.isEnabled());
+        }
+
+        // SwingAdapterListener methods
+
+        public void swingComponentChanged(SwingAdapter swingAdapter,
+                                          JComponent previousSwingComponent) {
+            if (previousSwingComponent != null) {
+                swingContainer.remove(previousSwingComponent);
+            }
+
+            JComponent swingComponent = swingAdapter.getSwingComponent();
+
+            if (swingComponent != null) {
+                swingContainer.add(swingComponent, BorderLayout.CENTER);
+            }
+
+            invalidateComponent();
+        }
+    }
+
+    /**
+     * Swing adapter listener list.
+     *
+     * @author tvolkert
+     */
+    private static class SwingAdapterListenerList extends ListenerList<SwingAdapterListener>
+        implements SwingAdapterListener {
+        public void swingComponentChanged(SwingAdapter swingAdapter,
+            JComponent previousSwingComponent) {
+            for (SwingAdapterListener listener : this) {
+                listener.swingComponentChanged(swingAdapter, previousSwingComponent);
+            }
+        }
+    }
+
+    private JComponent swingComponent;
+
+    private SwingAdapterListenerList swingAdapterListeners = new SwingAdapterListenerList();
+
+    public SwingAdapter() {
+        this(null);
+    }
+
+    public SwingAdapter(JComponent swingComponent) {
+        this.swingComponent = swingComponent;
+
+        setSkin(new SwingAdapterSkin());
+    }
+
+    public JComponent getSwingComponent() {
+        return swingComponent;
+    }
+
+    public void setSwingComponent(JComponent swingComponent) {
+        JComponent previousSwingComponent = this.swingComponent;
+
+        if (previousSwingComponent != swingComponent) {
+            this.swingComponent = swingComponent;
+            swingAdapterListeners.swingComponentChanged(this, previousSwingComponent);
+        }
+    }
+
+    public ListenerList<SwingAdapterListener> getSwingAdapterListeners() {
+        return swingAdapterListeners;
+    }
+}

Added: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SwingAdapterListener.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SwingAdapterListener.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SwingAdapterListener.java (added)
+++ incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/SwingAdapterListener.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,36 @@
+/*
+ * 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 javax.swing.JComponent;
+
+/**
+ * Defines event listener methods that pertain to swing adapters. Developers
+ * register for such events by adding themselves to a swing adapter's list of
+ * "swing adapter listeners" (see {@link SwingAdapter#getSwingAdapterListeners()}).
+ *
+ * @author tvolkert
+ */
+public interface SwingAdapterListener {
+    /**
+     * Called when a swing adapter's swing component has changed.
+     *
+     * @param swingAdapter
+     * @param previousSwingComponent
+     */
+    public void swingComponentChanged(SwingAdapter swingAdapter,
+        JComponent previousSwingComponent);
+}

Added: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TabPane.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TabPane.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TabPane.java (added)
+++ incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TabPane.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,407 @@
+/*
+ * 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.net.URL;
+import java.util.Iterator;
+import pivot.collections.ArrayList;
+import pivot.collections.Sequence;
+import pivot.util.ImmutableIterator;
+import pivot.util.ListenerList;
+import pivot.wtk.media.Image;
+
+/**
+ * Container that provides access to a set of components via selectable tabs.
+ *
+ * @author gbrown
+ */
+@ComponentInfo(icon="TabPane.png")
+public class TabPane extends Container {
+    /**
+     * Defines tab attributes.
+     *
+     * @author gbrown
+     */
+    protected static class TabPaneAttributes extends Attributes {
+        private String name = null;
+        private Image icon = null;
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            String previousName = this.name;
+            this.name = name;
+
+            Component component = getComponent();
+            TabPane tabPane = (TabPane)component.getParent();
+            if (tabPane != null) {
+                tabPane.tabPaneAttributeListeners.nameChanged(tabPane, component, previousName);
+            }
+        }
+
+        public Image getIcon() {
+            return icon;
+        }
+
+        public void setIcon(Image icon) {
+            Image previousIcon = this.icon;
+            this.icon = icon;
+
+            Component component = getComponent();
+            TabPane tabPane = (TabPane)component.getParent();
+            if (tabPane != null) {
+                tabPane.tabPaneAttributeListeners.iconChanged(tabPane, component, previousIcon);
+            }
+        }
+    }
+
+    /**
+     * Tab sequence implementation.
+     *
+     * @author gbrown
+     */
+    public final class TabSequence implements Sequence<Component>, Iterable<Component> {
+        private TabSequence() {
+        }
+
+        public int add(Component tab) {
+            int i = getLength();
+            insert(tab, i);
+
+            return i;
+        }
+
+        public void insert(Component tab, int index) {
+            if (tab == null) {
+                throw new IllegalArgumentException("tab is null.");
+            }
+
+            if (tab.getParent() != null) {
+                throw new IllegalArgumentException("Tab already has a parent.");
+            }
+
+            // Add the tab to the component sequence
+            TabPane.this.add(tab);
+            tabs.insert(tab, index);
+
+            // Attach the attributes
+            tab.setAttributes(new TabPaneAttributes());
+
+            tabPaneListeners.tabInserted(TabPane.this, index);
+
+            // If the selected tab's index changed as a result of
+            // this insertion, update it
+            if (selectedIndex >= index) {
+                setSelectedIndex(selectedIndex + 1);
+            }
+        }
+
+        public Component update(int index, Component tab) {
+            throw new UnsupportedOperationException();
+        }
+
+        public int remove(Component tab) {
+            int index = indexOf(tab);
+            if (index != -1) {
+                remove(index, 1);
+            }
+
+            return index;
+        }
+
+        public Sequence<Component> remove(int index, int count) {
+            // If the selected tab is being removed, clear the selection
+            if (selectedIndex >= index
+                && selectedIndex < index + count) {
+                setSelectedIndex(-1);
+            }
+
+            // Remove the tabs from the tab list
+            Sequence<Component> removed = tabs.remove(index, count);
+
+            // Detach the attributes
+            for (int i = 0, n = removed.getLength(); i < n; i++) {
+                removed.get(i).setAttributes(null);
+            }
+
+            tabPaneListeners.tabsRemoved(TabPane.this, index, removed);
+
+            // Remove the tabs from the component list
+            for (int i = 0, n = removed.getLength(); i < n; i++) {
+                Component tab = removed.get(i);
+                TabPane.this.remove(tab);
+            }
+
+            return removed;
+        }
+
+        public Component get(int index) {
+            return tabs.get(index);
+        }
+
+        public int indexOf(Component tab) {
+            return tabs.indexOf(tab);
+        }
+
+        public int getLength() {
+            return tabs.getLength();
+        }
+
+        public Iterator<Component> iterator() {
+            return new ImmutableIterator<Component>(tabs.iterator());
+        }
+    }
+
+    private static class TabPaneListenerList extends ListenerList<TabPaneListener>
+        implements TabPaneListener {
+        public void tabOrientationChanged(TabPane tabPane) {
+            for (TabPaneListener listener : this) {
+                listener.tabOrientationChanged(tabPane);
+            }
+        }
+
+        public void tabInserted(TabPane tabPane, int index) {
+            for (TabPaneListener listener : this) {
+                listener.tabInserted(tabPane, index);
+            }
+        }
+
+        public void tabsRemoved(TabPane tabPane, int index, Sequence<Component> tabs) {
+            for (TabPaneListener listener : this) {
+                listener.tabsRemoved(tabPane, index, tabs);
+            }
+        }
+
+        public void collapsibleChanged(TabPane tabPane) {
+            for (TabPaneListener listener : this) {
+                listener.collapsibleChanged(tabPane);
+            }
+        }
+
+        public void cornerChanged(TabPane tabPane, Component previousCorner) {
+            for (TabPaneListener listener : this) {
+                listener.cornerChanged(tabPane, previousCorner);
+            }
+        }
+    }
+
+    private static class TabPaneSelectionListenerList extends ListenerList<TabPaneSelectionListener>
+        implements TabPaneSelectionListener {
+        public void selectedIndexChanged(TabPane tabPane, int previousSelectedIndex) {
+            for (TabPaneSelectionListener listener : this) {
+                listener.selectedIndexChanged(tabPane, previousSelectedIndex);
+            }
+        }
+    }
+
+    private static class TabPaneAttributeListenerList extends ListenerList<TabPaneAttributeListener>
+        implements TabPaneAttributeListener {
+        public void nameChanged(TabPane tabPane, Component component, String previousName) {
+            for (TabPaneAttributeListener listener : this) {
+                listener.nameChanged(tabPane, component, previousName);
+            }
+        }
+
+        public void iconChanged(TabPane tabPane, Component component, Image previousIcon) {
+            for (TabPaneAttributeListener listener : this) {
+                listener.iconChanged(tabPane, component, previousIcon);
+            }
+        }
+    }
+
+    private Orientation tabOrientation = Orientation.HORIZONTAL;
+    private boolean collapsible = false;
+    private int selectedIndex = -1;
+
+    private ArrayList<Component> tabs = new ArrayList<Component>();
+    private TabSequence tabSequence = new TabSequence();
+
+    private Component corner = null;
+
+    private TabPaneListenerList tabPaneListeners = new TabPaneListenerList();
+    private TabPaneSelectionListenerList tabPaneSelectionListeners = new TabPaneSelectionListenerList();
+    private TabPaneAttributeListenerList tabPaneAttributeListeners = new TabPaneAttributeListenerList();
+
+    public TabPane() {
+        this(false);
+    }
+
+    public TabPane(boolean collapsible) {
+        super();
+
+        this.collapsible = collapsible;
+
+        installSkin(TabPane.class);
+    }
+
+    public Orientation getTabOrientation() {
+        return tabOrientation;
+    }
+
+    public void setTabOrientation(Orientation tabOrientation) {
+        if (tabOrientation == null) {
+            throw new IllegalArgumentException("tabOrientation is null.");
+        }
+
+        if (this.tabOrientation != tabOrientation) {
+            this.tabOrientation = tabOrientation;
+            tabPaneListeners.tabOrientationChanged(this);
+        }
+    }
+
+    public void setTabOrientation(String tabOrientation) {
+        if (tabOrientation == null) {
+            throw new IllegalArgumentException("tabOrientation is null.");
+        }
+
+        setTabOrientation(Orientation.decode(tabOrientation));
+    }
+
+    public boolean isCollapsible() {
+        return collapsible;
+    }
+
+    public void setCollapsible(boolean collapsible) {
+        if (collapsible != this.collapsible) {
+            this.collapsible = collapsible;
+            tabPaneListeners.collapsibleChanged(this);
+        }
+    }
+
+    public int getSelectedIndex() {
+        return selectedIndex;
+    }
+
+    public void setSelectedIndex(int selectedIndex) {
+        int previousSelectedIndex = this.selectedIndex;
+
+        if (previousSelectedIndex != selectedIndex) {
+            this.selectedIndex = selectedIndex;
+            tabPaneSelectionListeners.selectedIndexChanged(this, previousSelectedIndex);
+        }
+    }
+
+    public TabSequence getTabs() {
+        return tabSequence;
+    }
+
+    public Component getCorner() {
+        return corner;
+    }
+
+    public void setCorner(Component corner) {
+        Component previousCorner = this.corner;
+
+        if (previousCorner != corner) {
+            // Remove any previous corner component
+            this.corner = null;
+
+            if (previousCorner != null) {
+                remove(previousCorner);
+            }
+
+            // Set the new corner component
+            if (corner != null) {
+                insert(corner, 0);
+            }
+
+            this.corner = corner;
+
+            tabPaneListeners.cornerChanged(this, previousCorner);
+        }
+    }
+
+    @Override
+    public Sequence<Component> remove(int index, int count) {
+        for (int i = index, n = index + count; i < n; i++) {
+            Component component = get(i);
+            if (component == corner
+                || component.getAttributes() != null) {
+                throw new UnsupportedOperationException();
+            }
+        }
+
+        // Call the base method to remove the components
+        return super.remove(index, count);
+    }
+
+    public ListenerList<TabPaneListener> getTabPaneListeners() {
+        return tabPaneListeners;
+    }
+
+    public ListenerList<TabPaneSelectionListener> getTabPaneSelectionListeners() {
+        return tabPaneSelectionListeners;
+    }
+
+    public ListenerList<TabPaneAttributeListener> getTabPaneAttributeListeners() {
+        return tabPaneAttributeListeners;
+    }
+
+    public static String getName(Component component) {
+        TabPaneAttributes tabPaneAttributes = (TabPaneAttributes)component.getAttributes();
+        return (tabPaneAttributes == null) ? null : tabPaneAttributes.getName();
+    }
+
+    public static void setName(Component component, String name) {
+        TabPaneAttributes tabPaneAttributes = (TabPaneAttributes)component.getAttributes();
+        if (tabPaneAttributes == null) {
+            throw new IllegalStateException();
+        }
+
+        tabPaneAttributes.setName(name);
+    }
+
+    public static Image getIcon(Component component) {
+        TabPaneAttributes tabPaneAttributes = (TabPaneAttributes)component.getAttributes();
+        return (tabPaneAttributes == null) ? null : tabPaneAttributes.getIcon();
+    }
+
+    public static void setIcon(Component component, Image icon) {
+        TabPaneAttributes tabPaneAttributes = (TabPaneAttributes)component.getAttributes();
+        if (tabPaneAttributes == null) {
+            throw new IllegalStateException();
+        }
+
+        tabPaneAttributes.setIcon(icon);
+    }
+
+    public static final void setIcon(Component component, URL icon) {
+        if (icon == null) {
+            throw new IllegalArgumentException("icon is null.");
+        }
+
+        Image iconImage = (Image)ApplicationContext.getResourceCache().get(icon);
+
+        if (iconImage == null) {
+            iconImage = Image.load(icon);
+            ApplicationContext.getResourceCache().put(icon, iconImage);
+        }
+
+        setIcon(component, iconImage);
+    }
+
+    public static final void setIcon(Component component, String icon) {
+        if (icon == null) {
+            throw new IllegalArgumentException("icon is null.");
+        }
+
+        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+        setIcon(component, classLoader.getResource(icon));
+    }
+}
+

Added: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TabPane.png
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TabPane.png?rev=754926&view=auto
==============================================================================
Binary file - no diff available.

Propchange: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TabPane.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TabPaneAttributeListener.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TabPaneAttributeListener.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TabPaneAttributeListener.java (added)
+++ incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TabPaneAttributeListener.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,43 @@
+/*
+ * 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 pivot.wtk.media.Image;
+
+/**
+ * Tab pane attribute listener interface.
+ *
+ * @author gbrown
+ */
+public interface TabPaneAttributeListener {
+    /**
+     * Called when a tab's name attribute has changed.
+     *
+     * @param tabPane
+     * @param component
+     * @param previousName
+     */
+    public void nameChanged(TabPane tabPane, Component component, String previousName);
+
+    /**
+     * Called when a tab's icon attribute has changed.
+     *
+     * @param tabPane
+     * @param component
+     * @param previousIcon
+     */
+    public void iconChanged(TabPane tabPane, Component component, Image previousIcon);
+}

Added: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TabPaneListener.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TabPaneListener.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TabPaneListener.java (added)
+++ incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TabPaneListener.java Mon Mar 16 16:16:40 2009
@@ -0,0 +1,65 @@
+/*
+ * 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 pivot.collections.Sequence;
+
+/**
+ * Tab pane listener interface.
+ *
+ * @author gbrown
+ */
+public interface TabPaneListener {
+    /**
+     * Called when a tab pane's orientation has changed.
+     *
+     * @param tabPane
+     */
+    public void tabOrientationChanged(TabPane tabPane);
+
+    /**
+     * Called when a tab pane's collapsible flag has changed.
+     *
+     * @param tabPane
+     */
+    public void collapsibleChanged(TabPane tabPane);
+
+    /**
+     * Called when a tab has been inserted into a tab pane's tab sequence.
+     *
+     * @param tabPane
+     * @param index
+     */
+    public void tabInserted(TabPane tabPane, int index);
+
+    /**
+     * Called when a tab has been removed from a tab pane's tab sequence.
+     *
+     * @param tabPane
+     * @param index
+     * @param tabs
+     */
+    public void tabsRemoved(TabPane tabPane, int index, Sequence<Component> tabs);
+
+    /**
+     * Called when a tab pane's corner component (the component in the free
+     * space next to the tabs) has changed.
+     *
+     * @param tabPane
+     * @param previousCorner
+     */
+    public void cornerChanged(TabPane tabPane, Component previousCorner);
+}

Added: incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TabPaneSelectionListener.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TabPaneSelectionListener.java?rev=754926&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TabPaneSelectionListener.java (added)
+++ incubator/pivot/tags/v1.0/wtk/src/pivot/wtk/TabPaneSelectionListener.java Mon Mar 16 16:16:40 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;
+
+/**
+ * Tab pane selection listener interface.
+ *
+ * @author gbrown
+ */
+public interface TabPaneSelectionListener {
+    /**
+     * Called when a tab pane's selected index has changed.
+     *
+     * @param tabPane
+     * @param previousSelectedIndex
+     */
+    public void selectedIndexChanged(TabPane tabPane, int previousSelectedIndex);
+}