You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pivot.apache.org by gb...@apache.org on 2009/07/31 19:44:45 UTC

svn commit: r799669 - in /incubator/pivot/trunk: demos/src/org/apache/pivot/demos/lists/ wtk/src/org/apache/pivot/wtk/ wtk/src/org/apache/pivot/wtk/content/

Author: gbrown
Date: Fri Jul 31 17:44:44 2009
New Revision: 799669

URL: http://svn.apache.org/viewvc?rev=799669&view=rev
Log:
Fix some issues with focus management:
- Component#isFocusable() now checks for showing and enabled, not showing and !blocked
- Container#requestFocus() now only checks for showing, not showing and !blocked
- Window#restoreFocus() now only asserts showing, not showing and !blocked
- ApplicationContext.DisplayHost#processKeyEvent() doesn't propagate events to the focused component if it is blocked

Partially implement multiple selection support in ListSelection class; add demo app to test selection state.

Added:
    incubator/pivot/trunk/demos/src/org/apache/pivot/demos/lists/
    incubator/pivot/trunk/demos/src/org/apache/pivot/demos/lists/MultiSelect.java
    incubator/pivot/trunk/demos/src/org/apache/pivot/demos/lists/multi_select.wtkx
Modified:
    incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/ApplicationContext.java
    incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/Component.java
    incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/Container.java
    incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/ListSelection.java
    incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/ListView.java
    incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/Sheet.java
    incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/TableView.java
    incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/Window.java
    incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/content/NumericSpinnerData.java

Added: incubator/pivot/trunk/demos/src/org/apache/pivot/demos/lists/MultiSelect.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/demos/src/org/apache/pivot/demos/lists/MultiSelect.java?rev=799669&view=auto
==============================================================================
--- incubator/pivot/trunk/demos/src/org/apache/pivot/demos/lists/MultiSelect.java (added)
+++ incubator/pivot/trunk/demos/src/org/apache/pivot/demos/lists/MultiSelect.java Fri Jul 31 17:44:44 2009
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pivot.demos.lists;
+
+import org.apache.pivot.collections.ArrayList;
+import org.apache.pivot.collections.Map;
+import org.apache.pivot.collections.Sequence;
+import org.apache.pivot.wtk.Application;
+import org.apache.pivot.wtk.DesktopApplicationContext;
+import org.apache.pivot.wtk.Display;
+import org.apache.pivot.wtk.ListView;
+import org.apache.pivot.wtk.ListViewSelectionListener;
+import org.apache.pivot.wtk.Span;
+import org.apache.pivot.wtk.Window;
+import org.apache.pivot.wtkx.WTKXSerializer;
+
+public class MultiSelect implements Application {
+    private Window window = null;
+    private ListView dataListView = null;
+    private ListView selectionListView = null;
+
+    @Override
+    public void startup(Display display, Map<String, String> properties)
+        throws Exception {
+        WTKXSerializer wtkxSerializer = new WTKXSerializer();
+        window = (Window)wtkxSerializer.readObject(this, "multi_select.wtkx");
+
+        dataListView = (ListView)wtkxSerializer.get("dataListView");
+        selectionListView = (ListView)wtkxSerializer.get("selectionListView");
+
+        dataListView.getListViewSelectionListeners().add(new ListViewSelectionListener() {
+            public void selectedRangeAdded(ListView listView, int rangeStart, int rangeEnd) {
+                refreshSelectionListData();
+            }
+
+            public void selectedRangeRemoved(ListView listView, int rangeStart, int rangeEnd) {
+                refreshSelectionListData();
+            }
+
+            public void selectedRangesChanged(ListView listView, Sequence<Span> previousSelectedRanges) {
+                refreshSelectionListData();
+            }
+
+            private void refreshSelectionListData() {
+                selectionListView.setListData(new ArrayList<Span>(dataListView.getSelectedRanges()));
+            }
+        });
+
+        window.open(display);
+        dataListView.requestFocus();
+    }
+
+    @Override
+    public boolean shutdown(boolean optional) {
+        if (window != null) {
+            window.close();
+        }
+
+        return false;
+    }
+
+    @Override
+    public void suspend() {
+    }
+
+    @Override
+    public void resume() {
+    }
+
+    public static void main(String[] args) {
+        DesktopApplicationContext.main(MultiSelect.class, args);
+    }
+}

Added: incubator/pivot/trunk/demos/src/org/apache/pivot/demos/lists/multi_select.wtkx
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/demos/src/org/apache/pivot/demos/lists/multi_select.wtkx?rev=799669&view=auto
==============================================================================
--- incubator/pivot/trunk/demos/src/org/apache/pivot/demos/lists/multi_select.wtkx (added)
+++ incubator/pivot/trunk/demos/src/org/apache/pivot/demos/lists/multi_select.wtkx Fri Jul 31 17:44:44 2009
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to you under the Apache License,
+Version 2.0 (the "License"); you may not use this file except in
+compliance with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<Window title="Multiple Selection Demo" maximized="true"
+    xmlns:wtkx="http://pivot.apache.org/wtkx"
+    xmlns:collections="org.apache.pivot.collections"
+    xmlns:content="org.apache.pivot.wtk.content"
+    xmlns="org.apache.pivot.wtk">
+    <content>
+        <TablePane styles="{padding:8, horizontalSpacing:8}">
+            <columns>
+                <TablePane.Column width="1*"/>
+                <TablePane.Column width="1*"/>
+            </columns>
+            <rows>
+                <TablePane.Row height="1*">
+                    <Border styles="{padding:0, color:10}">
+                        <content>
+                            <ScrollPane horizontalScrollBarPolicy="fill">
+                                <view>
+                                    <ListView wtkx:id="dataListView" selectMode="multi"
+                                        selectedRanges="[{start:0, end:1}, {start:3, end:7}, {start:10, end:15}]">
+                                        <listData>
+                                            <content:NumericSpinnerData lowerBound="0" upperBound="31"
+                                                increment="1"/>
+                                        </listData>
+                                    </ListView>
+                                </view>
+                            </ScrollPane>
+                        </content>
+                    </Border>
+                    <Border styles="{padding:0, color:10}">
+                        <content>
+                            <ScrollPane horizontalScrollBarPolicy="fill">
+                                <view>
+                                    <ListView wtkx:id="selectionListView" selectMode="none"/>
+                                </view>
+                            </ScrollPane>
+                        </content>
+                    </Border>
+                </TablePane.Row>
+            </rows>
+        </TablePane>
+    </content>
+</Window>

Modified: incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/ApplicationContext.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/ApplicationContext.java?rev=799669&r1=799668&r2=799669&view=diff
==============================================================================
--- incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/ApplicationContext.java (original)
+++ incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/ApplicationContext.java Fri Jul 31 17:44:44 2009
@@ -1179,7 +1179,9 @@
                                     unprocessedKeyHandler.keyPressed(keyCode, keyLocation);
                                 }
                             } else {
-                                consumed = focusedComponent.keyPressed(keyCode, keyLocation);
+                                if (!focusedComponent.isBlocked()) {
+                                    consumed = focusedComponent.keyPressed(keyCode, keyLocation);
+                                }
                             }
                         } catch (Exception exception) {
                             if (application instanceof Application.UncaughtExceptionHandler) {
@@ -1211,7 +1213,9 @@
                                     unprocessedKeyHandler.keyReleased(keyCode, keyLocation);
                                 }
                             } else {
-                                consumed = focusedComponent.keyReleased(keyCode, keyLocation);
+                                if (!focusedComponent.isBlocked()) {
+                                    consumed = focusedComponent.keyReleased(keyCode, keyLocation);
+                                }
                             }
                         } catch (Exception exception) {
                             if (application instanceof Application.UncaughtExceptionHandler) {
@@ -1243,7 +1247,9 @@
                                     unprocessedKeyHandler.keyTyped(keyChar);
                                 }
                             } else {
-                                consumed = focusedComponent.keyTyped(keyChar);
+                                if (!focusedComponent.isBlocked()) {
+                                    consumed = focusedComponent.keyTyped(keyChar);
+                                }
                             }
                         } catch (Exception exception) {
                             if (application instanceof Application.UncaughtExceptionHandler) {

Modified: incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/Component.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/Component.java?rev=799669&r1=799668&r2=799669&view=diff
==============================================================================
--- incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/Component.java (original)
+++ incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/Component.java Fri Jul 31 17:44:44 2009
@@ -1964,7 +1964,7 @@
     public boolean isFocusable() {
         return skin.isFocusable()
             && isShowing()
-            && !isBlocked();
+            && isEnabled();
     }
 
     /**

Modified: incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/Container.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/Container.java?rev=799669&r1=799668&r2=799669&view=diff
==============================================================================
--- incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/Container.java (original)
+++ incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/Container.java Fri Jul 31 17:44:44 2009
@@ -254,7 +254,7 @@
         // and contains the focused component, clear the focus
         if (parent == null
             && containsFocus()) {
-            clearFocus(true);
+            clearFocus(false);
         }
 
         super.setParent(parent);
@@ -303,7 +303,7 @@
     public void setVisible(boolean visible) {
         if (!visible
             && containsFocus()) {
-            clearFocus(true);
+            clearFocus(false);
         }
 
         super.setVisible(visible);
@@ -459,8 +459,7 @@
      */
     @Override
     protected boolean requestFocus(boolean temporary) {
-        if (isShowing()
-            && !isBlocked()) {
+        if (isShowing()) {
             FocusTraversalPolicy focusTraversalPolicy = getFocusTraversalPolicy();
             Component component = focusTraversalPolicy.getNextComponent(this, null, Direction.FORWARD);
             if (component != null) {

Modified: incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/ListSelection.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/ListSelection.java?rev=799669&r1=799668&r2=799669&view=diff
==============================================================================
--- incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/ListSelection.java (original)
+++ incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/ListSelection.java Fri Jul 31 17:44:44 2009
@@ -27,31 +27,36 @@
  * @author gbrown
  */
 class ListSelection {
+    private ArrayList<Span> selectedRanges = new ArrayList<Span>();
+
     /**
-     * Determines the relative order of two ranges.
-     *
-     * @author gbrown
+     * Comparator that determines the relative order of two ranges' start
+     * values.
      */
-    public static class IntersectionComparator implements Comparator<Span> {
-        /**
-         * Compares two range values. A range is considered less than or greater
-         * than another range if and only if it is absolutely less than or
-         * greater than the other range; if the ranges overlap in any way,
-         * they are considered equal.
-         *
-         * @return
-         * A positive value if <tt>range1</tt> is greater than <tt>range2</tt>;
-         * a negative value if <tt>range1</tt> is less than <tt>range2</tt>; a
-         * value of zero if <tt>range1</tt> intersects with <tt>range2</tt>.
-         */
+    public static final Comparator<Span> START_COMPARATOR = new Comparator<Span>() {
         public int compare(Span range1, Span range2) {
-            return (range1.start > range2.end) ? 1 : (range2.start > range1.end) ? -1 : 0;
+            return (range1.start - range2.start);
         }
-    }
+    };
 
-    private ArrayList<Span> selectedRanges = new ArrayList<Span>();
+    /**
+     * Comparator that determines the relative order of two ranges' end
+     * values.
+     */
+    public static final Comparator<Span> END_COMPARATOR = new Comparator<Span>() {
+        public int compare(Span range1, Span range2) {
+            return (range1.end - range2.end);
+        }
+    };
 
-    public static final IntersectionComparator INTERSECTION_COMPARATOR = new IntersectionComparator();
+    /**
+     * Comparator that determines if two ranges intersect.
+     */
+    public static final Comparator<Span> INTERSECTION_COMPARATOR = new Comparator<Span>() {
+        public int compare(Span range1, Span range2) {
+            return (range1.start > range2.end) ? 1 : (range2.start > range1.end) ? -1 : 0;
+        }
+    };
 
     /**
      * Adds a range to the selection, merging and removing intersecting ranges
@@ -72,12 +77,59 @@
             int n = selectedRanges.getLength();
 
             if (n == 0) {
-                // Nothing is currently selected
+                // The selection is currently empty; append the new range
                 selectedRanges.add(range);
                 added.add(range);
             } else {
-                // TODO Perform two binary searches to determine the endpoints
+                // Perform two binary searches to determine the endpoints
                 // of the intersection
+                int i = ArrayList.binarySearch(selectedRanges, range, START_COMPARATOR);
+                if (i <= 0) {
+                    i = -(i + 1);
+                }
+
+                int j = ArrayList.binarySearch(selectedRanges, range, END_COMPARATOR);
+                if (j <= 0) {
+                    j = -(j + 1);
+                }
+
+                // Merge the selection with the previous and next ranges, if necessary
+                if (i > 0) {
+                    Span previousRange = selectedRanges.get(i - 1);
+                    if (range.start == previousRange.end + 1) {
+                        i--;
+                    }
+                }
+
+                if (j < n) {
+                    Span nextRange = selectedRanges.get(j);
+                    if (range.end == nextRange.start - 1) {
+                        j++;
+                    }
+                }
+
+                if (i == n) {
+                    // The new range starts after the last existing selection
+                    // ends; append
+                    selectedRanges.add(range);
+                    added.add(range);
+                } else {
+                    // TODO Add any gaps to the added list
+
+                    // Remove any redundant ranges
+                    if (i < j) {
+                        selectedRanges.remove(i + 1, j - i - 1);
+                    }
+
+                    // Create a new range representing the union of the intersecting ranges
+                    Span lowerRange = selectedRanges.get(i);
+                    Span upperRange = selectedRanges.get(j);
+
+                    range = new Span(Math.min(range.start, lowerRange.start),
+                        Math.max(range.end, upperRange.end));
+
+                    selectedRanges.update(i, range);
+                }
             }
         }
 
@@ -101,7 +153,21 @@
 
         if (range.getLength() > 0
             && selectedRanges.getLength() > 0) {
-            // TODO
+            // Perform two binary searches to determine the endpoints
+            // of the intersection
+            int i = ArrayList.binarySearch(selectedRanges, range, START_COMPARATOR);
+            if (i <= 0) {
+                i = -(i + 1);
+            }
+
+            int j = ArrayList.binarySearch(selectedRanges, range, END_COMPARATOR);
+            if (j <= 0) {
+                j = -(j + 1);
+            }
+
+            if (i == j) {
+
+            }
         }
 
         return removed;
@@ -133,8 +199,8 @@
      * @param range
      *
      * @return
-     * The index of the range, if it exists in the selection in its entirety;
-     * <tt>-1</tt>, otherwise.
+     * The index of the range, if it exists in the selection; <tt>-1</tt>,
+     * otherwise.
      */
     public int indexOf(Span range) {
         assert (range != null);
@@ -158,7 +224,10 @@
      * <tt>true</tt> if the index is selected; <tt>false</tt>, otherwise.
      */
     public boolean containsIndex(int index) {
-        return (indexOf(new Span(index, index)) != -1);
+        Span range = new Span(index, index);
+        int i = ArrayList.binarySearch(selectedRanges, range, INTERSECTION_COMPARATOR);
+
+        return (i >= 0);
     }
 
     /**

Modified: incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/ListView.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/ListView.java?rev=799669&r1=799668&r2=799669&view=diff
==============================================================================
--- incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/ListView.java (original)
+++ incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/ListView.java Fri Jul 31 17:44:44 2009
@@ -538,7 +538,7 @@
      *
      * @param selectedRanges
      */
-    public void setSelectedRanges(Sequence<Span> selectedRanges) {
+    public final void setSelectedRanges(Sequence<Span> selectedRanges) {
         if (selectedRanges == null) {
             throw new IllegalArgumentException("selectedRanges is null.");
         }

Modified: incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/Sheet.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/Sheet.java?rev=799669&r1=799668&r2=799669&view=diff
==============================================================================
--- incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/Sheet.java (original)
+++ incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/Sheet.java Fri Jul 31 17:44:44 2009
@@ -117,8 +117,8 @@
 
         if (isOpen()) {
             Component content = owner.getContent();
-            if (content.isBlocked()) {
-                throw new IllegalStateException("Owner content is already blocked.");
+            if (!content.isEnabled()) {
+                throw new IllegalStateException("Owner content is already disabled.");
             }
 
             content.setEnabled(false);

Modified: incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/TableView.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/TableView.java?rev=799669&r1=799668&r2=799669&view=diff
==============================================================================
--- incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/TableView.java (original)
+++ incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/TableView.java Fri Jul 31 17:44:44 2009
@@ -1055,7 +1055,7 @@
      *
      * @see #setSelectedRanges(Sequence)
      */
-    public void setSelectedRanges(String selectedRanges) {
+    public final void setSelectedRanges(String selectedRanges) {
         if (selectedRanges == null) {
             throw new IllegalArgumentException("selectedRanges is null.");
         }

Modified: incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/Window.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/Window.java?rev=799669&r1=799668&r2=799669&view=diff
==============================================================================
--- incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/Window.java (original)
+++ incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/Window.java Fri Jul 31 17:44:44 2009
@@ -899,8 +899,7 @@
      * have a focus descendant, the focus is cleared.
      */
     protected void restoreFocus() {
-        assert(isShowing()
-            && !isBlocked());
+        assert(isShowing());
 
         if (focusDescendant != null) {
             if (isAncestor(focusDescendant)) {
@@ -911,7 +910,7 @@
         }
 
         if (focusDescendant == null) {
-            Component.clearFocus(true);
+            Component.clearFocus(false);
         }
     }
 
@@ -976,7 +975,7 @@
             } else {
                 // Activate the window
                 if (window.isShowing()
-                    && !window.isBlocked()
+                    && window.isEnabled()
                     && !window.isAuxilliary()) {
                     setActiveWindow(window);
                     window.restoreFocus();

Modified: incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/content/NumericSpinnerData.java
URL: http://svn.apache.org/viewvc/incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/content/NumericSpinnerData.java?rev=799669&r1=799668&r2=799669&view=diff
==============================================================================
--- incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/content/NumericSpinnerData.java (original)
+++ incubator/pivot/trunk/wtk/src/org/apache/pivot/wtk/content/NumericSpinnerData.java Fri Jul 31 17:44:44 2009
@@ -33,21 +33,8 @@
  * the list).
  * <p>
  * The iterator returned by this class's <tt>iterator</tt> method is
- * <i>fail-fast</i>: if the data is structurally modified at any time after
- * the iterator is created, in any way except through the iterator's own
- * remove or add methods, the iterator will throw a
- * <tt>ConcurrentModificationException</tt>. Thus, in the face of concurrent
- * modification, the iterator fails quickly and cleanly, rather than risking
- * arbitrary, non-deterministic behavior at an undetermined time in the
- * future.
- * <p>
- * Note that the fail-fast behavior of an iterator cannot be guaranteed
- * as it is, generally speaking, impossible to make any hard guarantees in the
- * presence of unsynchronized concurrent modification.  Fail-fast iterators
- * throw <tt>ConcurrentModificationException</tt> on a best-effort basis.
- * Therefore, it would be wrong to write a program that depended on this
- * exception for its correctness: <i>the fail-fast behavior of iterators
- * should be used only to detect bugs.</i>
+ * <i>fail-fast</i>: if the bounds of the enclosing spinner data change during
+ * iteration, a <tt>ConcurrentModificationException</tt> will be thrown.
  *
  * @author tvolkert
  */