changeset 275:2fc581846b26 2.1-b09

Automated merge with ssh://jfxsrc.us.oracle.com//javafx/2.1/MASTER/jfx/rt
author David Grieve<david.grieve@oracle.com>
date Tue, 17 Jan 2012 18:02:40 -0500
parents a75035c2f8cc 049118ba62b5
children 627b0b1f20b6 05002e14187b
files
diffstat 33 files changed, 3088 insertions(+), 991 deletions(-) [+]
line wrap: on
line diff
--- a/build-defs.xml	Mon Jan 16 12:42:51 2012 +0100
+++ b/build-defs.xml	Tue Jan 17 18:02:40 2012 -0500
@@ -11,15 +11,16 @@
     
     <!-- 
         Bring in environment properties (if not already done).
-        If the environment variable JFXRT_HOME is not set, we set it here to 
-        point to a sane default location. We also create a slightly nicer to
-        understand JFXRT_HOME property to use elsewhere.
     -->
-    <!--
     <property environment="env"/>
-    <property name="env.JFXRT_HOME" value="${runtime.dist.root.dir}/../artifacts/sdk/rt/lib" />
+    
+    <!-- Set JFXRT_HOME -->
+    <condition property="JFXRT_HOME" value="../../artifacts/sdk/rt/lib">
+        <not>  
+            <isset property="env.JFXRT_HOME"/>
+        </not>
+    </condition>
     <property name="JFXRT_HOME" value="${env.JFXRT_HOME}" />
-    -->
     
     <!--
         Note that .properties files are loaded relative to the basedir of
@@ -53,8 +54,10 @@
         javafx-ui-common: 
 	ant -Djavafx-ui-common.javac.debuglevel=source,lines,vars
     -->	
+    <!--
     <propertycopy name="javac.debuglevel" from="${ant.project.name}.javac.debuglevel" silent="true" override="true"/>
-
+    -->
+    
     <!--
 
         Default targets for all subprojects are defined below.  These can
@@ -186,7 +189,7 @@
             </jar>
 
             <!-- copy the jar file to the shared lib directory -->
-            <copy file="${dist.dir}/@{name}.jar" todir="${runtime.deps.dir}"/>
+            <copy file="${dist.dir}/@{name}.jar" todir="../build"/> <!--${runtime.deps.dir}-->
         </sequential>
     </macrodef>
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/build.xml	Tue Jan 17 18:02:40 2012 -0500
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+--> 
+<project name="JavaFX Runtime" default="dist" basedir=".">
+    <description>Builds, tests, and runs the project JavaFX Runtime</description>
+
+    <import file="../build-defs.xml"/>
+    <property name="build.dir" value="${basedir}/build"/>
+
+    <property name="rt.root.dir" location="${basedir}/../rt"/>
+
+    <target name="init">
+        <!-- ensure version 1.7.1 of ant -->
+        <fail message="Ant version 1.7.1 or later is required to build JavaFX.">
+            <condition><not><antversion atleast="1.7.1"/></not></condition>
+        </fail>
+    </target>
+
+    <!--
+        Build targets...
+      -->
+
+    <!--
+    <fileset dir="${rt.root.dir}" id="rt.binaries.to.be.copied">
+        <include name="javafx-beans-dt/dist/javafx-beans-dt.jar"/>
+        <include name="javafx-concurrent/dist/javafx-concurrent.jar"/>
+        <include name="javafx-designtime/dist/javafx-designtime.jar"/>
+        <include name="javafx-ui-controls/dist/javafx-ui-controls.jar"/>
+        <include name="javafx-util-converter/dist/javafx-util-converter.jar"/>
+    </fileset>
+    -->
+
+    <target name="dist" depends="init">
+        <ant antfile="${rt.root.dir}/javafx-beans-dt/build.xml" target="jar" inheritAll="false"/>
+        <ant antfile="${rt.root.dir}/javafx-concurrent/build.xml" target="jar" inheritAll="false"/>
+        <!--<ant antfile="${rt.root.dir}/javafx-designtime/build.xml" target="jar" inheritAll="false"/>-->
+        <ant antfile="${rt.root.dir}/javafx-ui-controls/build.xml" target="jar" inheritAll="false"/>
+        <ant antfile="${rt.root.dir}/javafx-util-converter/build.xml" target="jar" inheritAll="false"/>
+    </target>
+
+    <!--
+      Testing targets...
+    -->
+
+    <target name="test">
+        <ant antfile="${rt.root.dir}/javafx-beans-dt/build.xml" target="test" inheritAll="false"/>
+        <ant antfile="${rt.root.dir}/javafx-concurrent/build.xml" target="test" inheritAll="false"/>
+        <!--<ant antfile="${rt.root.dir}/javafx-designtime/build.xml" target="test" inheritAll="false"/>-->
+        <ant antfile="${rt.root.dir}/javafx-ui-controls/build.xml" target="test" inheritAll="false"/>
+        <ant antfile="${rt.root.dir}/javafx-util-converter/build.xml" target="test" inheritAll="false"/>
+    </target>
+
+    <!--
+        Clean-up targets...
+      -->
+
+    <target name="clean" depends="init">
+        <delete dir="${build.dir}"/>
+        <delete dir="dist"/>
+        <ant antfile="${rt.root.dir}/javafx-beans-dt/build.xml" target="clean" inheritAll="false"/>
+        <ant antfile="${rt.root.dir}/javafx-concurrent/build.xml" target="clean" inheritAll="false"/>
+        <!--<ant antfile="${rt.root.dir}/javafx-designtime/build.xml" target="clean" inheritAll="false"/>-->
+        <ant antfile="${rt.root.dir}/javafx-ui-controls/build.xml" target="clean" inheritAll="false"/>
+        <ant antfile="${rt.root.dir}/javafx-util-converter/build.xml" target="clean" inheritAll="false"/>
+    </target>
+ 
+    <!--
+        Create an openjfxrt.jar file...
+      -->   
+    
+    <target name="jar" depends="dist">
+        <echo>Creating merged openjfxrt.jar file</echo>
+        <mkdir dir="dist" />
+        <jar destfile="dist/openjfxrt.jar">
+            <zipgroupfileset dir="." includes="**/dist/*.jar" /> 
+        </jar>
+    </target>
+    
+    <target name="default" depends="jar" />
+
+</project>
\ No newline at end of file
--- a/javafx-beans-dt/project.properties	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-beans-dt/project.properties	Tue Jan 17 18:02:40 2012 -0500
@@ -1,10 +1,8 @@
 JFXRT_HOME=\
     ${runtime.dist.root.dir}/../artifacts/sdk/rt/lib
-javac.classpath=\
-    ${JFXRT_HOME}/jfxrt.jar
 disable-lombok=true
 javac.classpath=\
     ${runtime.dist.root.dir}/javafx-beans/dist/javafx-beans.jar:\
     ${runtime.dist.root.dir}/javafx-common/dist/javafx-common.jar:\
-    ${runtime.dist.root.dir}/javafx-ui-common/dist/javafx-ui-common.jar
-
+    ${runtime.dist.root.dir}/javafx-ui-common/dist/javafx-ui-common.jar:\
+    ${JFXRT_HOME}/jfxrt.jar
\ No newline at end of file
--- a/javafx-concurrent/build.xml	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-concurrent/build.xml	Tue Jan 17 18:02:40 2012 -0500
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<project name="javafx-beans-dt" default="jar" basedir=".">
+<project name="javafx-concurrent" default="jar" basedir=".">
   <description>Builds, tests, and runs the project javafx-beans-dt.</description>
 
   <import file="../build-defs.xml"/>
--- a/javafx-concurrent/project.properties	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-concurrent/project.properties	Tue Jan 17 18:02:40 2012 -0500
@@ -1,13 +1,12 @@
 JFXRT_HOME=\
     ${runtime.dist.root.dir}/../artifacts/sdk/rt/lib
-javac.classpath=\
-    ${JFXRT_HOME}/jfxrt.jar
 disable-lombok=true
 javac.classpath=\
     ${runtime.dist.root.dir}/javafx-beans/dist/javafx-beans.jar:\
     ${runtime.dist.root.dir}/javafx-common/dist/javafx-common.jar:\
     ${runtime.dist.root.dir}/javafx-logging/dist/javafx-logging.jar:\
-    ${runtime.dist.root.dir}/javafx-ui-common/dist/javafx-ui-common.jar
+    ${runtime.dist.root.dir}/javafx-ui-common/dist/javafx-ui-common.jar:\
+    ${JFXRT_HOME}/jfxrt.jar
 javac.test.classpath=\
     ${javac.classpath}:\
     ${build.classes.dir}:\
--- a/javafx-concurrent/test/javafx/concurrent/TaskCancelTest.java	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-concurrent/test/javafx/concurrent/TaskCancelTest.java	Tue Jan 17 18:02:40 2012 -0500
@@ -27,7 +27,7 @@
 
 import javafx.concurrent.mocks.EpicFailTask;
 import javafx.concurrent.mocks.InfiniteTask;
-//import javafx.concurrent.mocks.RunAwayTask;
+import javafx.concurrent.mocks.RunAwayTask;
 import javafx.concurrent.mocks.SimpleTask;
 import org.junit.Before;
 import org.junit.Test;
@@ -122,8 +122,12 @@
 
     /**
      *
+     */
     @Test public void aFreeRunningCancelledTaskReturnValueShouldBeIgnored() throws Exception {
-        RunAwayTask runAway = new RunAwayTask();
+        RunAwayTask runAway = new RunAwayTask() {
+                protected void loop(int count) throws Exception {
+                }
+        };
         Thread th = new Thread(runAway);
         th.start();
         runAway.runningSemaphore.acquire();
@@ -137,5 +141,4 @@
         assertNull(runAway.getValue());
         assertTrue(runAway.isDone());
     }
-     */
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-concurrent/test/javafx/concurrent/mocks/RunAwayTask.java	Tue Jan 17 18:02:40 2012 -0500
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javafx.concurrent.mocks;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+import javafx.concurrent.AbstractTask;
+
+/**
+ * A Task which will simply loop forever without end. This is used to simulate
+ * what happens when a task doesn't head the "isCancelled" flag or
+ * cancellation in any way. To make sure it finally does terminate (so the
+ * tests will work) there is a <code>stopLooping</code> atomic boolean that
+ * the test needs to set to true.
+ *
+ * <p>To make sure that a single loop has occurred before we quit, there is
+ * a <code>loopHasHappened</code> boolean. This way we always know that
+ * a single iteration has completed, at least, before the task was
+ * terminated.</p>
+ *
+ * <p>Different tests want to use a RunAwayTask differently. Some want to
+ * call updateValue in the body of the loop, while others do not. For this
+ * reason, the RunAwayTask is abstract and an abstract <code>loop</code>
+ * method is defined that a subclass implements to implement the body
+ * of the loop.</p>
+ */
+public abstract class RunAwayTask extends AbstractTask {
+    public AtomicBoolean stopLooping = new AtomicBoolean(false);
+    private boolean loopHasHappened = false;
+
+    @Override protected String call() throws Exception {
+        int count = 0;
+        while (!loopHasHappened || !stopLooping.get()) {
+            count++;
+            loop(count);
+            loopHasHappened = true;
+        }
+        return "" + count;
+    }
+
+    protected abstract void loop(int count) throws Exception;
+    
+}
--- a/javafx-designtime/project.properties	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-designtime/project.properties	Tue Jan 17 18:02:40 2012 -0500
@@ -1,12 +1,11 @@
 JFXRT_HOME=\
     ${runtime.dist.root.dir}/../artifacts/sdk/rt/lib
-javac.classpath=\
-    ${JFXRT_HOME}/jfxrt.jar
 disable-lombok=true
 javac.classpath=\
     ${runtime.dist.root.dir}/javafx-beans/dist/javafx-beans.jar:\
     ../javafx-beans-dt/dist/javafx-beans-dt.jar:\
     ${runtime.dist.root.dir}/javafx-common/dist/javafx-common.jar:\
     ${runtime.dist.root.dir}/../rt/javafx-ui-controls/dist/javafx-ui-controls.jar:\
-    ${runtime.dist.root.dir}/javafx-ui-common/dist/javafx-ui-common.jar
+    ${runtime.dist.root.dir}/javafx-ui-common/dist/javafx-ui-common.jar:\
+    ${JFXRT_HOME}/jfxrt.jar
 
--- a/javafx-ui-controls/nbproject/project.xml	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-ui-controls/nbproject/project.xml	Tue Jan 17 18:02:40 2012 -0500
@@ -139,7 +139,7 @@
         <java-data xmlns="http://www.netbeans.org/ns/freeform-project-java/3">
             <compilation-unit>
                 <package-root>${src.dir}</package-root>
-                <classpath mode="compile">${JFXRT_HOME}/jfxrt.jar</classpath>
+                <classpath mode="compile">${javac.classpath}</classpath>
                 <built-to>dist/javafx-ui-controls.jar</built-to>
                 <source-level>1.6</source-level>
             </compilation-unit>
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/ReadOnlyUnbackedObservableList.java	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/ReadOnlyUnbackedObservableList.java	Tue Jan 17 18:02:40 2012 -0500
@@ -37,7 +37,6 @@
 
 import com.sun.javafx.collections.ListInvalidationListenerWrapper;
 import com.sun.javafx.collections.ListenerList;
-import java.util.ArrayList;
 import java.util.Collections;
 
 /**
@@ -97,7 +96,6 @@
         }
     }
 
-
     @Override public int indexOf(Object o) {
         if (o == null) return -1;
 
@@ -154,13 +152,18 @@
      * NOTE: This method does not fulfill the subList contract from Collections,
      * it simply returns a list containing the values in the given range.
      */
-    @Override public List<T> subList(int fromIndex, int toIndex) {
+    @Override public List<T> subList(final int fromIndex, final int toIndex) {
         if (fromIndex >= toIndex) return Collections.emptyList();
-        List<T> sublist = new ArrayList<T>();
-        for (int i = fromIndex; i < toIndex; i++) {
-            sublist.add(get(i));
-        }
-        return sublist;
+        final List<T> outer = this;
+        return new ReadOnlyUnbackedObservableList<T>() {
+            @Override public T get(int i) {
+                return outer.get(i + fromIndex);
+            }
+
+            @Override public int size() {
+                return toIndex - fromIndex;
+            }
+        };
     }
 
     @Override
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/ChoiceBoxBehavior.java	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/ChoiceBoxBehavior.java	Tue Jan 17 18:02:40 2012 -0500
@@ -45,7 +45,7 @@
  *
  * @profile common
  */
-public class ChoiceBoxBehavior extends BehaviorBase<ChoiceBox> {
+public class ChoiceBoxBehavior<T> extends BehaviorBase<ChoiceBox<T>> {
     /**
      * The key bindings for the ChoiceBox. It seems this should really be the
      * same as with the ButtonBehavior super class, but it doesn't handle ENTER
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/ListCellBehavior.java	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/ListCellBehavior.java	Tue Jan 17 18:02:40 2012 -0500
@@ -60,7 +60,7 @@
     }
     
     static boolean hasAnchor(ListView list) {
-        return map.containsKey(list);
+        return map.containsKey(list) && map.get(list) != -1;
     }
     
     // For RT-17456: have selection occur as fast as possible with mouse input.
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/ListViewBehavior.java	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/ListViewBehavior.java	Tue Jan 17 18:02:40 2012 -0500
@@ -101,7 +101,7 @@
             LIST_VIEW_BINDINGS.add(new KeyBinding(A, "SelectAll").meta());
             LIST_VIEW_BINDINGS.add(new KeyBinding(HOME, "FocusFirstRow").meta());
             LIST_VIEW_BINDINGS.add(new KeyBinding(END, "FocusLastRow").meta());
-            LIST_VIEW_BINDINGS.add(new KeyBinding(SPACE, "toggleFocusOwnerSelection").meta());
+            LIST_VIEW_BINDINGS.add(new KeyBinding(SPACE, "toggleFocusOwnerSelection").ctrl().meta());
             LIST_VIEW_BINDINGS.add(new KeyBinding(PAGE_UP, "FocusPageUp").meta());
             LIST_VIEW_BINDINGS.add(new KeyBinding(PAGE_DOWN, "FocusPageDown").meta());
         } else {
@@ -255,9 +255,11 @@
                     }
                 }
                 
-                if (! hasAnchor() && c.getAddedSize() > 0) {
-                    for (int i = 0; i < c.getAddedSize(); i++) {
-                        int index = ((List<Integer>)c.getAddedSubList()).get(i);
+                int addedSize = c.getAddedSize();
+                if (! hasAnchor() && addedSize > 0) {
+                    List<Integer> addedSubList = (List<Integer>) c.getAddedSubList();
+                    for (int i = 0; i < addedSize; i++) {
+                        int index = addedSubList.get(i);
                         if (index >= 0) {
                             setAnchor(index);
                             break;
@@ -339,7 +341,11 @@
     }
 
     private void scrollPageUp() {
-        int newSelectedIndex = onScrollPageUp.call(null);
+        int newSelectedIndex = -1;
+        if (onScrollPageUp != null) {
+            newSelectedIndex = onScrollPageUp.call(null);
+        }
+        if (newSelectedIndex == -1) return;
         
         MultipleSelectionModel sm = getControl().getSelectionModel();
         if (sm == null) return;
@@ -347,7 +353,11 @@
     }
 
     private void scrollPageDown() {
-        int newSelectedIndex = onScrollPageDown.call(null);
+        int newSelectedIndex = -1;
+        if (onScrollPageDown != null) {
+            newSelectedIndex = onScrollPageDown.call(null);
+        }
+        if (newSelectedIndex == -1) return;
         
         MultipleSelectionModel sm = getControl().getSelectionModel();
         if (sm == null) return;
@@ -587,13 +597,16 @@
         int leadIndex = sm.getSelectedIndex();
         
         if (isShiftDown) {
-            leadIndex = getAnchor() == -1 ? sm.getSelectedIndex() : getAnchor();
-            setAnchor(leadIndex);
+            leadIndex = hasAnchor() ? sm.getSelectedIndex() : getAnchor();
         }
 
         sm.clearSelection();
         sm.selectRange(0, leadIndex + 1);
         
+        if (isShiftDown) {
+            setAnchor(leadIndex);
+        }
+        
         // RT-18413: Focus must go to first row
         getControl().getFocusModel().focus(0);
 
@@ -607,12 +620,15 @@
         int leadIndex = sm.getSelectedIndex();
         
         if (isShiftDown) {
-            leadIndex = getAnchor() == -1 ? sm.getSelectedIndex() : getAnchor();
-            setAnchor(leadIndex);
+            leadIndex = hasAnchor() ? sm.getSelectedIndex() : getAnchor();
         }
         
         sm.clearSelection();
         sm.selectRange(leadIndex, getRowCount());
+        
+        if (isShiftDown) {
+            setAnchor(leadIndex);
+        }
 
         if (onMoveToLastCell != null) onMoveToLastCell.run();
     }
@@ -637,6 +653,7 @@
         int startPos = anchor;
         int endPos = anchor > focusIndex ? focusIndex - 1 : focusIndex + 1;
         sm.selectRange(startPos, endPos);
+        setAnchor(anchor);
     }
     
     private void cancelEdit() {
@@ -662,6 +679,7 @@
         
         if (sm.isSelected(focusedIndex)) {
             sm.clearSelection(focusedIndex);
+            fm.focus(focusedIndex);
         } else {
             sm.select(focusedIndex);
         }
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TableCellBehavior.java	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TableCellBehavior.java	Tue Jan 17 18:02:40 2012 -0500
@@ -43,7 +43,7 @@
         TableViewFocusModel fm = table.getFocusModel();
         if (fm == null) return null;
         
-        return map.containsKey(table) ? map.get(table) : fm.getFocusedCell();
+        return hasAnchor(table) ? map.get(table) : fm.getFocusedCell();
     }
     
     static void setAnchor(TableView table, TablePosition anchor) {
@@ -54,6 +54,10 @@
         }
     }
     
+    static boolean hasAnchor(TableView table) {
+        return map.containsKey(table) && map.get(table) != null;
+    }
+    
     // For RT-17456: have selection occur as fast as possible with mouse input.
     // The idea is (consistently with some native applications we've tested) to 
     // do the action as soon as you can. It takes a bit more coding but provides
@@ -119,7 +123,7 @@
         // about).
         if (e.isShiftDown()) {
             if (! map.containsKey(tableView)) {
-                map.put(tableView, fm.getFocusedCell());
+                setAnchor(tableView, fm.getFocusedCell());
             }
         } else {
             map.remove(tableView);
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TableViewBehavior.java	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TableViewBehavior.java	Tue Jan 17 18:02:40 2012 -0500
@@ -60,7 +60,6 @@
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
 import javafx.collections.ListChangeListener;
-import javafx.scene.control.*;
 import javafx.util.Callback;
 
 public class TableViewBehavior<T> extends BehaviorBase<TableView<T>> {
@@ -218,23 +217,39 @@
     private ListChangeListener<TablePosition> selectedCellsListener = new ListChangeListener<TablePosition>() {
         @Override public void onChanged(ListChangeListener.Change c) {
             while (c.next()) {
-                if (selectionChanging) continue;
-                
                 TableView.TableViewSelectionModel sm = getControl().getSelectionModel();
                 if (sm == null) return;
                 
                 TablePosition anchor = getAnchor();
                 boolean cellSelectionEnabled = sm.isCellSelectionEnabled();
                 
-                // there are no selected items, so lets clear out the anchor
-                if (c.getList().isEmpty()) {
-                    setAnchor(null);
-                } else if (anchor != null && cellSelectionEnabled && ! selectionPathDeviated) {
+                if (! selectionChanging) {
+                    // there are no selected items, so lets clear out the anchor
+                    if (c.getList().isEmpty()) {
+                        setAnchor(null);
+                    } else if (! c.getList().contains(getAnchor())) {
+                        setAnchor(null);
+                    }
+                } 
+                
+                int addedSize = c.getAddedSize();
+                List<TablePosition> addedSubList = (List<TablePosition>) c.getAddedSubList();
+                
+                if (! hasAnchor() && addedSize > 0) {
+                    for (int i = 0; i < addedSize; i++) {
+                        TablePosition tp = addedSubList.get(i);
+                        if (tp.getRow() >= 0) {
+                            setAnchor(tp);
+                            break;
+                        }
+                    }
+                }
+                
+                if (!hasAnchor() && cellSelectionEnabled && ! selectionPathDeviated) {
                     // check if the selection is on the same row or column, 
                     // otherwise set selectionPathDeviated to true
-                    
-                    for (int i = 0; i < c.getAddedSize(); i++) {
-                        TablePosition tp = (TablePosition) c.getAddedSubList().get(i);
+                    for (int i = 0; i < addedSize; i++) {
+                        TablePosition tp = addedSubList.get(i);
                         if (anchor.getRow() != -1 && tp.getRow() != anchor.getRow() && tp.getColumn() != anchor.getColumn()) {
                             selectionPathDeviated = true;
                             break;
@@ -322,6 +337,10 @@
         return TableCellBehavior.getAnchor(getControl());
     }
     
+    private boolean hasAnchor() {
+        return TableCellBehavior.hasAnchor(getControl());
+    }
+    
 //    private void shiftAnchor(boolean rowDirection, int delta) {
 //        if (anchor == null) return;
 //        if (rowDirection) {
@@ -545,7 +564,7 @@
                 }
             });
         } else {
-            if (isShiftDown && getAnchor() != null) {
+            if (isShiftDown && hasAnchor()) {
                 updateRowSelection(-1);
             } else {
                 sm.selectPrevious();
@@ -568,7 +587,7 @@
                 }
             });
         } else {
-            if (isShiftDown && getAnchor() != null) {
+            if (isShiftDown && hasAnchor()) {
                 updateRowSelection(1);
             } else {
                 sm.selectNext();
@@ -601,13 +620,18 @@
         if (fm == null) return;
         
         int newRow = fm.getFocusedIndex() + delta;
+        TablePosition anchor = getAnchor();
+        
+        if (! hasAnchor()) {
+            setAnchor(fm.getFocusedCell());
+        } 
 
-        clearSelectionOutsideRange(getAnchor().getRow(), newRow);
+        clearSelectionOutsideRange(anchor.getRow(), newRow);
 
-        if (getAnchor().getRow() > newRow) {
-            sm.selectRange(getAnchor().getRow(), newRow - 1);
+        if (anchor.getRow() > newRow) {
+            sm.selectRange(anchor.getRow(), newRow - 1);
         } else {
-            sm.selectRange(getAnchor().getRow(), newRow + 1);
+            sm.selectRange(anchor.getRow(), newRow + 1);
         }
     }
     
@@ -772,22 +796,26 @@
         if (fm == null) return;
 
         TablePosition focusedCell = fm.getFocusedCell();
-        int focusIndex = focusedCell.getRow();
-        int anchor = getAnchor().getRow();
+        int focusRow = focusedCell.getRow();
+        
+        TablePosition anchor = getAnchor();
+        int anchorRow = anchor.getRow();
         
         sm.clearSelection();
         if (! sm.isCellSelectionEnabled()) {
-            int startPos = anchor;
-            int endPos = anchor > focusIndex ? focusIndex - 1 : focusIndex + 1;
+            int startPos = anchorRow;
+            int endPos = anchorRow > focusRow ? focusRow - 1 : focusRow + 1;
             sm.selectRange(startPos, endPos);
         } else {
-            int min = Math.min(anchor, focusIndex);
-            int max = Math.max(anchor, focusIndex);
+            int min = Math.min(anchorRow, focusRow);
+            int max = Math.max(anchorRow, focusRow);
             
             for (int i = min; i <= max; i++) {
                 sm.select(i, focusedCell.getTableColumn());
             }
         }
+        
+        setAnchor(anchor);
     }
     
     private void selectAll() {
@@ -817,12 +845,16 @@
             // the requirement of selectRange, so we call focus on the 0th row
             sm.selectRange(0, leadIndex + 1);
             getControl().getFocusModel().focus(0);
-            setAnchor(leadIndex, null);
+//            setAnchor(leadIndex, null);
         } else {
             // TODO
             
 //            setAnchor(leadIndex, );
         }
+        
+        if (isShiftDown) {
+            setAnchor(leadIndex, null);
+        }
 
         if (onMoveToFirstCell != null) onMoveToFirstCell.run();
     }
@@ -840,7 +872,6 @@
         
         if (isShiftDown) {
             leadIndex = getAnchor() == null ? leadIndex : getAnchor().getRow();
-            setAnchor(leadIndex, null);
         }
         
         sm.clearSelection();
@@ -849,6 +880,10 @@
         } else {
             // TODO
         }
+        
+        if (isShiftDown) {
+            setAnchor(leadIndex, null);
+        }
 
         if (onMoveToLastCell != null) onMoveToLastCell.run();
     }
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TreeCellBehavior.java	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TreeCellBehavior.java	Tue Jan 17 18:02:40 2012 -0500
@@ -45,7 +45,7 @@
         FocusModel fm = tree.getFocusModel();
         if (fm == null) return -1;
         
-        return map.containsKey(tree) ? map.get(tree) : fm.getFocusedIndex();
+        return hasAnchor(tree) ? map.get(tree) : fm.getFocusedIndex();
     }
     
     static void setAnchor(TreeView tree, int anchor) {
@@ -56,6 +56,10 @@
         }
     }
     
+    static boolean hasAnchor(TreeView tree) {
+        return map.containsKey(tree) && map.get(tree) != -1;
+    }
+    
     // For RT-17456: have selection occur as fast as possible with mouse input.
     // The idea is (consistently with some native applications we've tested) to 
     // do the action as soon as you can. It takes a bit more coding but provides
@@ -133,7 +137,7 @@
         // about).
         if (event.isShiftDown()) {
             if (! map.containsKey(treeView)) {
-                map.put(treeView, fm.getFocusedIndex());
+                setAnchor(treeView, fm.getFocusedIndex());
             }
         } else {
             map.remove(treeView);
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TreeViewBehavior.java	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TreeViewBehavior.java	Tue Jan 17 18:02:40 2012 -0500
@@ -201,8 +201,24 @@
         @Override public void onChanged(ListChangeListener.Change c) {
             while (c.next()) {
                 // there are no selected items, so lets clear out the anchor
-                if (! selectionChanging && c.getList().isEmpty()) {
-                    setAnchor(-1);
+                if (! selectionChanging) {
+                    if (c.getList().isEmpty()) {
+                        setAnchor(-1);
+                    } else if (! c.getList().contains(getAnchor())) {
+                        setAnchor(-1);
+                    }
+                }
+                
+                int addedSize = c.getAddedSize();
+                if (! hasAnchor() && addedSize > 0) {
+                    List<Integer> addedSubList = (List<Integer>) c.getAddedSubList();
+                    for (int i = 0; i < addedSize; i++) {
+                        int index = addedSubList.get(i);
+                        if (index >= 0) {
+                            setAnchor(index);
+                            break;
+                        }
+                    }
                 }
             }
         }
@@ -237,6 +253,10 @@
     private int getAnchor() {
         return TreeCellBehavior.getAnchor(getControl());
     }
+    
+    private boolean hasAnchor() {
+        return TreeCellBehavior.hasAnchor(getControl());
+    }
 
     @Override public void mousePressed(MouseEvent e) {
         super.mousePressed(e);
@@ -351,16 +371,22 @@
         MultipleSelectionModel sm = getControl().getSelectionModel();
         if (sm == null) return;
         
-        final int focusIndex = fm.getFocusedIndex();
+//        final int focusIndex = fm.getFocusedIndex();
         
         if (isShiftDown && getAnchor() != -1) {
             int newRow = fm.getFocusedIndex() - 1;
-            clearSelectionOutsideRange(getAnchor(), newRow);
+            int anchor = getAnchor();
+            
+            if (! hasAnchor()) {
+                setAnchor(fm.getFocusedIndex());
+            } 
+            
+            clearSelectionOutsideRange(anchor, newRow);
 
-            if (getAnchor() > newRow) {
-                sm.selectRange(getAnchor(), newRow - 1);
+            if (anchor > newRow) {
+                sm.selectRange(anchor, newRow - 1);
             } else {
-                sm.selectRange(getAnchor(), newRow + 1);
+                sm.selectRange(anchor, newRow + 1);
             }
         } else {
             sm.selectPrevious();
@@ -378,12 +404,18 @@
         
         if (isShiftDown && getAnchor() != -1) {
             int newRow = fm.getFocusedIndex() + 1;
-            clearSelectionOutsideRange(getAnchor(), newRow);
+            int anchor = getAnchor();
+            
+            if (! hasAnchor()) {
+                setAnchor(fm.getFocusedIndex());
+            } 
+            
+            clearSelectionOutsideRange(anchor, newRow);
 
-            if (getAnchor() > newRow) {
-                sm.selectRange(getAnchor(), newRow - 1);
+            if (anchor > newRow) {
+                sm.selectRange(anchor, newRow - 1);
             } else {
-                sm.selectRange(getAnchor(), newRow + 1);
+                sm.selectRange(anchor, newRow + 1);
             }
         } else {
             sm.selectNext();
@@ -393,18 +425,19 @@
     }
     
     private void clearSelectionOutsideRange(int start, int end) {
-        if (getControl().getSelectionModel() == null) return;
+        MultipleSelectionModel sm = getControl().getSelectionModel();
+        if (sm == null) return;
         
         int min = Math.min(start, end);
         int max = Math.max(start, end);
         
-        List<Integer> indices = new ArrayList<Integer>(getControl().getSelectionModel().getSelectedIndices());
+        List<Integer> indices = new ArrayList<Integer>(sm.getSelectedIndices());
         
         selectionChanging = true;
         for (int i = 0; i < indices.size(); i++) {
             int index = indices.get(i);
             if (index < min || index >= max) {
-                getControl().getSelectionModel().clearSelection(index);
+                sm.clearSelection(index);
             }
         }
         selectionChanging = false;
@@ -458,11 +491,14 @@
         
         if (isShiftDown) {
             leadIndex = getAnchor() == -1 ? sm.getSelectedIndex() : getAnchor();
-            setAnchor(leadIndex);
         }
         
         sm.clearSelection();
         sm.selectRange(0, leadIndex + 1);
+        
+        if (isShiftDown) {
+            setAnchor(leadIndex);
+        }
 
         if (onMoveToFirstCell != null) onMoveToFirstCell.run();
     }
@@ -475,11 +511,14 @@
         
         if (isShiftDown) {
             leadIndex = getAnchor() == -1 ? sm.getSelectedIndex() : getAnchor();
-            setAnchor(leadIndex);
         }
         
         sm.clearSelection();
         sm.selectRange(leadIndex, getControl().impl_getTreeItemCount() - 1);
+        
+        if (isShiftDown) {
+            setAnchor(leadIndex);
+        }
 
         if (onMoveToLastCell != null) onMoveToLastCell.run();
     }
@@ -544,6 +583,7 @@
         int startPos = anchor;
         int endPos = anchor > focusIndex ? focusIndex - 1 : focusIndex + 1;
         sm.selectRange(startPos, endPos);
+        setAnchor(anchor);
     }
 
     private void expandRow() {
@@ -637,6 +677,7 @@
         
         if (sm.isSelected(focusedIndex)) {
             sm.clearSelection(focusedIndex);
+            fm.focus(focusedIndex);
         } else {
             sm.select(focusedIndex);
         }
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/ChoiceBoxSkin.java	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/ChoiceBoxSkin.java	Tue Jan 17 18:02:40 2012 -0500
@@ -25,7 +25,7 @@
 
 package com.sun.javafx.scene.control.skin;
 
-import com.sun.javafx.scene.control.WeakListChangeListener;
+import javafx.util.StringConverter;
 import javafx.beans.InvalidationListener;
 import javafx.beans.Observable;
 import javafx.beans.value.ChangeListener;
@@ -51,13 +51,13 @@
 import javafx.scene.text.Text;
 
 import com.sun.javafx.scene.control.behavior.ChoiceBoxBehavior;
-
+import com.sun.javafx.scene.control.WeakListChangeListener;
 
 
 /**
  * ChoiceBoxSkin - default implementation
  */
-public class ChoiceBoxSkin extends SkinBase<ChoiceBox, ChoiceBoxBehavior> {
+    public class ChoiceBoxSkin<T> extends SkinBase<ChoiceBox<T>, ChoiceBoxBehavior<T>> {
 
     public ChoiceBoxSkin(ChoiceBox control) {
         super(control, new ChoiceBoxBehavior(control));
@@ -253,7 +253,9 @@
         } else if (o instanceof SeparatorMenuItem) {
             popupItem = (SeparatorMenuItem) o;
         } else {
-            final RadioMenuItem item = new RadioMenuItem(o == null ? "" : o.toString());
+            StringConverter c = getSkinnable().getConverter();
+            String displayString = (c == null) ? ((o == null) ? "" : o.toString()) :  c.toString(o);
+            final RadioMenuItem item = new RadioMenuItem(displayString);
             item.setId("choice-box-menu-item");
             item.setToggleGroup(toggleGroup);
             final int index = i;
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/ScrollPaneSkin.java	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/ScrollPaneSkin.java	Tue Jan 17 18:02:40 2012 -0500
@@ -720,16 +720,17 @@
         final double contentw = getSkinnable().getWidth() - getInsets().getLeft() - getInsets().getRight();
         return (getSkinnable().getHbarPolicy().equals(ScrollBarPolicy.NEVER)) ? false :
                    ((getSkinnable().getHbarPolicy().equals(ScrollBarPolicy.ALWAYS)) ? true :
-                       ((getSkinnable().isFitToWidth() && scrollNode.isResizable()) ? false :
-                           (nodeWidth > contentw)));
+                    ((getSkinnable().isFitToWidth() && scrollNode.isResizable()) ?
+                       (nodeWidth > contentw && scrollNode.minWidth(-1) > contentw) : (nodeWidth > contentw)));
     }
 
     private boolean determineVerticalSBVisible() {
         final double contenth = getSkinnable().getHeight() - getInsets().getTop() - getInsets().getBottom();
         return (getSkinnable().getVbarPolicy().equals(ScrollBarPolicy.NEVER)) ? false :
                   ((getSkinnable().getVbarPolicy().equals(ScrollBarPolicy.ALWAYS)) ? true :
-                      ((getSkinnable().isFitToHeight() && scrollNode.isResizable()) ? false :
-                          (nodeHeight > contenth)));
+                      ((getSkinnable().isFitToHeight() && scrollNode.isResizable()) ?
+                       (nodeHeight > contenth && scrollNode.minHeight(-1) > contenth) : (nodeHeight > contenth)));
+
     }
 
     private void computeScrollBarSize() {
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/SplitPaneSkin.java	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/SplitPaneSkin.java	Tue Jan 17 18:02:40 2012 -0500
@@ -44,14 +44,15 @@
 import javafx.scene.shape.Rectangle;
 
 import com.sun.javafx.scene.control.behavior.BehaviorBase;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
 
 public class SplitPaneSkin extends SkinBase<SplitPane, BehaviorBase<SplitPane>>  {
 
     private ObservableList<Content> contentRegions;
     private ObservableList<ContentDivider> contentDividers;
     private boolean horizontal;
-    private boolean updateDividerPos = false;
-    private double previousSize = -1;
 
     public SplitPaneSkin(final SplitPane splitPane) {
         super(splitPane, new BehaviorBase<SplitPane>(splitPane));
@@ -119,17 +120,15 @@
     private final ChangeListener posPropertyListener = new ChangeListener() {
         @Override
         public void changed(ObservableValue observable, Object oldValue, Object newValue) {
-            updateDividerPos = true;
             requestLayout();
         }
     };
-
+   
     private void addDivider(SplitPane.Divider d) {
         ContentDivider c = new ContentDivider(d);
         c.setInitialPos(d.getPosition());
         c.setDividerPos(d.getPosition());
         d.positionProperty().addListener(posPropertyListener);
-        // TODO Maybe call updatePosition here.
         initializeDivderEventHandlers(c);
         contentDividers.add(c);
         getChildren().add(c);
@@ -170,7 +169,6 @@
         divider.setOnMouseDragged(new EventHandler<MouseEvent>() {
             @Override public void handle(MouseEvent e) {
                 double dividerWidth = divider.prefWidth(-1);
-                double halfDividerWidth = dividerWidth/2;
                 Content left = getLeft(divider);
                 Content right = getRight(divider);
                 double minLeft = left == null ? 0 : (horizontal) ? left.minWidth(-1) : left.minHeight(-1);
@@ -204,36 +202,24 @@
                     nextDividerPos = contentDividers.get(index + 1).getDividerPos();
                 }
                 if (delta > 0) {
-                    double max = previousDividerPos == 0 ? maxLeft + halfDividerWidth : previousDividerPos + maxLeft + dividerWidth;
+                    double max = previousDividerPos == 0 ? maxLeft : previousDividerPos + dividerWidth + maxLeft;
                     double min = nextDividerPos - minRight - dividerWidth;
-                    if (nextDividerPos > w) {
-                        nextDividerPos = w;
-                        min = nextDividerPos - dividerWidth;
-                    }
+                    double stopPos = Math.min(max, min);
 
-                    if (nextDividerPos == w) {
-                        min += halfDividerWidth;
-                    }
-
-                    double stopPos = Math.min(max, min);
                     if (newPos >= stopPos) {
-                        setDividerPos(divider, stopPos);
+                        setAbsoluteDividerPos(divider, stopPos);
                     } else {
-                        setDividerPos(divider, newPos);
+                        setAbsoluteDividerPos(divider, newPos);
                     }
                 } else {
                     double max = nextDividerPos - maxRight - dividerWidth;
-                    double min = previousDividerPos == 0 ? minLeft + halfDividerWidth : previousDividerPos + minLeft + dividerWidth;
+                    double min = previousDividerPos == 0 ? minLeft : previousDividerPos + minLeft + dividerWidth;
+                    double stopPos = Math.max(max, min);
 
-                    if (nextDividerPos == w) {
-                        max += halfDividerWidth;
-                    }
-
-                    double stopPos = Math.max(max, min);
                     if (newPos <= stopPos) {
-                        setDividerPos(divider, stopPos);
+                        setAbsoluteDividerPos(divider, stopPos);
                     } else {
-                        setDividerPos(divider, newPos);
+                        setAbsoluteDividerPos(divider, newPos);
                     }
                 }
                 e.consume();
@@ -257,16 +243,7 @@
         return null;
     }
 
-    private ContentDivider getContentDivider(SplitPane.Divider d) {
-        for (ContentDivider c: contentDividers) {
-            if (c.getDivider().equals(d)) {
-                return c;
-            }
-        }
-        return null;
-    }
-
-    @Override  protected void handleControlPropertyChanged(String property) {
+    @Override protected void handleControlPropertyChanged(String property) {
         super.handleControlPropertyChanged(property);
         if (property == "ORIENTATION") {
             this.horizontal = getSkinnable().getOrientation() == Orientation.HORIZONTAL;
@@ -274,51 +251,46 @@
                 c.setGrabberStyle(horizontal);
             }
             getSkinnable().requestLayout();
-        } else if (property == "WIDTH") {
-            updateDividerPos = true;
-        } else if (property == "HEIGHT") {
-            updateDividerPos = true;
+        } else if (property == "WIDTH" || property == "HEIGHT") {
+            requestLayout();
         }
     }
 
-    private void setDividerPos(ContentDivider divider, double value) {
-        if (getWidth() > 0 && getHeight() > 0) {
+    // Value is the left edge of the divider
+     private void setAbsoluteDividerPos(ContentDivider divider, double value) {
+        if (getWidth() > 0 && getHeight() > 0 && divider != null) {
             SplitPane.Divider paneDivider = divider.getDivider();
             divider.setDividerPos(value);
             double size = getSize();
             if (size != 0) {
-                paneDivider.setPosition(divider.getDividerPos() / size);
+                // Adjust the position to the center of the
+                // divider and convert its position to a percentage.
+                double pos = value + divider.prefWidth(-1)/2;
+                paneDivider.setPosition(pos / size);
             } else {
                 paneDivider.setPosition(0);
             }
         }
-        requestLayout();
     }
 
     // Updates the divider with the SplitPane.Divider's position
-    private void updateDividerPos(ContentDivider divider) {
-        if (updateDividerPos) {
-            if (getWidth() > 0 && getHeight() > 0) {
-                double newPos = getSize() * divider.getDivider().getPosition();
+    // The value updated to SplitPane.Divider will be the center of the divider.
+    // The returned position will be the left edge of the divider
+    private double getAbsoluteDividerPos(ContentDivider divider) {
+        if (getWidth() > 0 && getHeight() > 0 && divider != null) {
+            SplitPane.Divider paneDivider = divider.getDivider();
+            double pos = paneDivider.getPosition();
+            double newPos = getSize() * pos;
+            if (pos == 1) {                
+                newPos -= divider.prefWidth(-1);
+            } else {
                 newPos -= divider.prefWidth(-1)/2;
-                divider.setDividerPos(Math.round(newPos));
             }
-            updateDividerPos = false;
+            newPos = Math.round(newPos);
+            divider.setDividerPos(newPos);
+            return newPos;
         }
-    }
-
-    private int indexOfMaxContent() {
-        double maxSize = 0;
-        Content content = null;
-        // We are only using displayWidth here because in layoutChildren()
-        // the vertical orientation uses the width as its height.
-        for (Content c: contentRegions) {
-            if (c.fitsInArea() && c.getDisplayWidth() > maxSize) {
-                maxSize = c.getDisplayWidth();
-                content = c;
-            }
-        }
-        return contentRegions.indexOf(content);
+        return 0;
     }
 
     private double totalMinSize() {
@@ -326,23 +298,14 @@
         double minSize = 0;
         for (Content c: contentRegions) {
             if (horizontal) {
-                minSize += c.minWidth(-1);                
+                minSize += c.minWidth(-1);
             } else {
                 minSize += c.minHeight(-1);
             }
-        }        
+        }
         return minSize + dividerWidth;
     }
 
-    private double totalMaxSize() {
-        double dividerWidth = !contentDividers.isEmpty() ? contentDividers.size() * contentDividers.get(0).prefWidth(-1) : 0;
-        double maxSize = 0;
-        for (Content c: contentRegions) {
-            maxSize += c.getContent() != null ? (horizontal) ? c.getContent().maxWidth(-1) : c.getContent().maxHeight(-1) : 0;
-        }
-        return maxSize + dividerWidth;
-    }
-
     private double getSize() {
         double size = totalMinSize();
         if (horizontal) {
@@ -357,573 +320,383 @@
         return size;
     }
 
-    private void layoutDividersAndContent() {
-        double w = 0;
-        double h = 0;
+    // Evenly distribute the size to the available list.
+    // size is the amount to distribute.
+    private double distributeTo(List<Content> available, double size) {
+        if (available.isEmpty()) {
+            return size;
+        }
+
+        int portion = (int)(size)/available.size();
+        int remainder;
+
+        while (size > 0 && !available.isEmpty()) {
+            Iterator<Content> i = available.iterator();
+            while (i.hasNext()) {
+                Content c = i.next();
+                double max = Math.min((horizontal ? c.maxWidth(-1) : c.maxHeight(-1)), Double.MAX_VALUE);
+                double min = horizontal ? c.minWidth(-1) : c.minHeight(-1);
+
+                // We have too much space
+                if (c.getArea() >= max) {
+                    c.setAvailable(c.getArea() - min);
+                    i.remove();
+                    continue;
+                }
+                // Not enough space
+                if (portion >= (max - c.getArea())) {
+                    size -= (max - c.getArea());
+                    c.setArea(max);
+                    c.setAvailable(max - min);
+                    i.remove();
+                } else {
+                    // Enough space
+                    c.setArea(c.getArea() + portion);
+                    c.setAvailable(c.getArea() - min);
+                    size -= portion;
+                }
+                if (size == 0) {
+                    return size;
+                }
+            }
+            if (available.isEmpty()) {
+                // We reached the max size for everything just return
+                return size;
+            }
+            portion = (int)(size)/available.size();
+            remainder = (int)(size)%available.size();
+            if (portion == 0 && remainder != 0) {
+                portion = remainder;
+                remainder = 0;
+            }
+        }
+        return size;
+    }
+
+    // Evenly distribute the size from the available list.
+    // size is the amount to distribute.
+    private double distributeFrom(double size, List<Content> available) {
+        if (available.isEmpty()) {
+            return size;
+        }
+
+        int portion = (int)(size)/available.size();
+        int remainder;
+
+        while (size > 0 && !available.isEmpty()) {
+            Iterator<Content> i = available.iterator();
+            while (i.hasNext()) {
+                Content c = i.next();
+                //not enough space taking available and setting min
+                if (portion >= c.getAvailable()) {
+                    c.setArea(c.getArea() - c.getAvailable()); // Min size
+                    size -= c.getAvailable();
+                    c.setAvailable(0);
+                    i.remove();
+                } else {
+                    //enough space
+                    c.setArea(c.getArea() - portion);
+                    c.setAvailable(c.getAvailable() - portion);
+                    size -= portion;
+                }
+                if (size == 0) {
+                    return size;
+                }
+            }
+            if (available.isEmpty()) {
+                // We reached the min size for everything just return
+                return size;
+            }
+            portion = (int)(size)/available.size();
+            remainder = (int)(size)%available.size();
+            if (portion == 0 && remainder != 0) {
+                portion = remainder;
+                remainder = 0;
+            }
+        }
+        return size;
+    }
+
+    private void setupContentAndDividerForLayout() {
+        // Set all the value to prepare for layout
+        double dividerWidth = contentDividers.isEmpty() ? 0 : contentDividers.get(0).prefWidth(-1);
+        double startX = 0;
+        double startY = 0;
+        for (Content c: contentRegions) {
+            if (resize && !c.isResizableWithParent()) {
+                c.setArea(c.getResizableWithParentArea());
+            }
+            
+            c.setX(startX);
+            c.setY(startY);
+            if (horizontal) {
+                startX += (c.getArea() + dividerWidth);
+            } else {
+                startY += (c.getArea() + dividerWidth);
+            }
+        }
+
+        startX = 0;
+        startY = 0;
+        for (int i = 0; i < contentDividers.size(); i++) {
+            ContentDivider d = contentDividers.get(i);
+            if (horizontal) {
+                startX += getLeft(d).getArea() + (i == 0 ? 0 : dividerWidth);
+            } else {
+                startY += getLeft(d).getArea() + (i == 0 ? 0 : dividerWidth);
+            }
+            d.setX(startX);
+            d.setY(startY);
+            setAbsoluteDividerPos(d, (horizontal ? d.getX() : d.getY()));
+        }
+    }
+
+    private void layoutDividersAndContent(double width, double height) {
         double paddingX = getInsets().getLeft();
         double paddingY = getInsets().getTop();
         double dividerWidth = contentDividers.isEmpty() ? 0 : contentDividers.get(0).prefWidth(-1);
-
-        if (this.horizontal) {
-            w = getWidth() - (getInsets().getLeft() + getInsets().getRight());
-            h = getHeight() - (getInsets().getTop() + getInsets().getBottom());
-        } else {
-            w = getHeight() - (getInsets().getTop() + getInsets().getBottom());
-            h = getWidth() - (getInsets().getLeft() + getInsets().getRight());
-        }
-
+       
         for (Content c: contentRegions) {
+//            System.out.println("LAYOUT " + c.getId() + " PANELS X " + c.getX() + " Y " + c.getY() + " W " + (horizontal ? c.getArea() : width) + " H " + (horizontal ? height : c.getArea()));
             if (horizontal) {
-                layoutInArea(c, c.getX() + paddingX, c.getY() + paddingY, c.getDisplayWidth(), c.getDisplayHeight(),
+                layoutInArea(c, c.getX() + paddingX, c.getY() + paddingY, c.getArea(), height,
                     0/*baseline*/,HPos.CENTER, VPos.CENTER);
             } else {
-                layoutInArea(c, c.getX() + paddingX, c.getY() + paddingY, c.getDisplayHeight(), c.getDisplayWidth(),
+                layoutInArea(c, c.getX() + paddingX, c.getY() + paddingY, width, c.getArea(),
                     0/*baseline*/,HPos.CENTER, VPos.CENTER);
             }
         }
-
         for (ContentDivider c: contentDividers) {
+//            System.out.println("LAYOUT DIVIDERS X " + c.getX() + " Y " + c.getY() + " W " + (horizontal ? dividerWidth : width) + " H " + (horizontal ? height : dividerWidth));
             if (horizontal) {
-                c.resize(dividerWidth, h);
-                positionInArea(c, c.getX() + paddingX, c.getY() + paddingY, dividerWidth, h,
+                c.resize(dividerWidth, height);
+                positionInArea(c, c.getX() + paddingX, c.getY() + paddingY, dividerWidth, height,
                     /*baseline ignored*/0, HPos.CENTER, VPos.CENTER);
             } else {
-                c.resize(h, dividerWidth);
-                positionInArea(c, c.getX() + paddingX, c.getY() + paddingY, h, dividerWidth,
+                c.resize(width, dividerWidth);                
+                positionInArea(c, c.getX() + paddingX, c.getY() + paddingY, width, dividerWidth,
                     /*baseline ignored*/0, HPos.CENTER, VPos.CENTER);
             }
         }
     }
 
-    private void resizeSplitPane(double w, double h) {
-        boolean grow = previousSize < (horizontal ? getWidth() : getHeight());
-        redistribute(grow, w, h);        
-        layoutDividersAndContent();
-    }
+    private double previousArea = -1;
+    private boolean resize = false;
 
-    private void redistribute(boolean redistribute, double w, double h) {        
-        double dividerWidth = contentDividers.isEmpty() ? 0 : contentDividers.get(0).prefWidth(-1);
-        double halfDividerWidth = dividerWidth / 2.0f;
-        double maxSize = totalMaxSize();
-        double startX = horizontal ? contentDividers.get(contentDividers.size() - 1).getDividerPos() - halfDividerWidth : 0;
-        double startY = horizontal ? 0 : contentDividers.get(contentDividers.size() - 1).getDividerPos() - halfDividerWidth;
-        double dividerPos = 0;
-        double previousDividerPos = 0;
-        double nextDividerPos = w;
-        double pos = 0;
-
-        Content left = null;
-        ContentDivider divider = null;
-        Content right = null;
-
-        for (int i = contentDividers.size() - 1; i >= 0; i--) {
-            divider = contentDividers.get(i);
-            right = getRight(divider);
-            left = getLeft(divider);
-
-            nextDividerPos = (i + 1 >= contentDividers.size()) ? w : contentDividers.get(i + 1).getDividerPos() - halfDividerWidth;
-            dividerPos = contentDividers.get(i).getDividerPos() - halfDividerWidth;
-            previousDividerPos = (i - 1 < 0) ? 0 : contentDividers.get(i - 1).getDividerPos() - halfDividerWidth;
-
-            double availableLeftWidth = dividerPos - (previousDividerPos == 0 ? 0 : (previousDividerPos + dividerWidth));
-            double availableRightWidth = nextDividerPos - (dividerPos + dividerWidth);
-
-            // do bounds checking to ensure min/max widths aren't being exceeded
-            double minLeftWidth  = left == null ? 0 : (horizontal) ? left.minWidth(-1) : left.minHeight(-1);
-            double prefLeftWidth = left == null ? 0 : (horizontal) ? left.prefWidth(-1) : left.prefHeight(-1);
-            double maxLeftWidth  = left == null ? 0 :
-                left.getContent() != null ? (horizontal) ? left.getContent().maxWidth(-1) : left.getContent().maxHeight(-1) : 0;
-
-            double minRightWidth  = right == null ? 0 : (horizontal) ? right.minWidth(-1) : right.minHeight(-1);
-            double prefRightWidth = right == null ? 0 : (horizontal) ? right.prefWidth(-1) : right.prefHeight(-1);
-            double maxRightWidth  = right == null ? 0 :
-                right.getContent() != null ? (horizontal) ? right.getContent().maxWidth(-1) : right.getContent().maxHeight(-1) : 0;
-
-            // These properties are what the actual width will be set to
-            double leftNodeWidth;
-            double rightNodeWidth;
-
-            // sort out right node
-            if (availableRightWidth <= minRightWidth) {
-                rightNodeWidth = minRightWidth;
-            } else if (availableRightWidth >= maxRightWidth) {
-                rightNodeWidth = maxRightWidth;
-            } else {
-                if (right.isManaged()) {
-                    rightNodeWidth = availableRightWidth;
-                } else {
-                    rightNodeWidth = Math.min(prefRightWidth, availableRightWidth);
-                }
-            }
-
-            // sort out left node
-            if (availableLeftWidth <= minLeftWidth) {
-                leftNodeWidth = minLeftWidth;
-            } else if (availableLeftWidth >= maxLeftWidth) {
-                leftNodeWidth = maxLeftWidth;
-            } else {
-                if (left.isManaged()) {
-                    leftNodeWidth = availableLeftWidth;
-                } else {
-                    leftNodeWidth = Math.min(prefLeftWidth, availableLeftWidth);
-                }
-            }
-
-            // Can the content fit in the area ?
-            double rightArea = availableRightWidth;
-            double leftArea = availableLeftWidth;
-
-            // Setup all the values for layout
-            if (horizontal) {
-                if (rightArea >= maxRightWidth) {
-                    right.setX(startX + dividerWidth + (rightArea - maxRightWidth)/2);
-                    right.setY(startY);
-                    right.setDisplayWidth(maxRightWidth);
-                    right.setDisplayHeight(h);
-                    if (redistribute) {
-                        pos = nextDividerPos - maxRightWidth - dividerWidth;
-                        dividerPos = pos;
-                        leftArea = pos - (previousDividerPos == 0 ? 0 : (previousDividerPos + dividerWidth));
-
-                        if (dividerPos + maxRightWidth + dividerWidth >= maxSize) {
-                            pos = maxSize - maxRightWidth - dividerWidth;
-                        }
-                        rightArea = nextDividerPos - (pos + dividerWidth);
-                        right.setX(pos + dividerWidth + (rightArea - maxRightWidth)/2);
-                    } else {
-                        pos = dividerPos;
-                    }
-                } else if (rightArea > minRightWidth) {
-                    right.setX(startX + dividerWidth);
-                    right.setY(startY);
-                    right.setDisplayWidth(rightArea);
-                    right.setDisplayHeight(h);
-                    pos = dividerPos;
-                } else {
-                    startX = nextDividerPos - minRightWidth;
-                    right.setX(startX);
-                    right.setY(startY);
-                    right.setDisplayWidth(minRightWidth);
-                    right.setDisplayHeight(h);
-                    pos = startX - dividerWidth;
-                    dividerPos = pos;
-                    leftArea = pos - (previousDividerPos == 0 ? 0 : (previousDividerPos + dividerWidth));                    
-                    if (leftArea <= minLeftWidth) {
-                        leftArea = minLeftWidth;
-                        previousDividerPos = previousDividerPos <= 0 ? 0 : dividerPos - minLeftWidth - dividerWidth;
-                    }
-                }
-                divider.setX(pos);
-                divider.setY(startY);
-
-                if (leftArea >= maxLeftWidth) {
-                    startX = previousDividerPos;
-                    left.setX(startX);
-                    left.setY(startY);
-                    left.setDisplayWidth(maxLeftWidth);
-                    left.setDisplayHeight(h);
-                } else if (leftArea > minLeftWidth) {
-                    startX = previousDividerPos;
-                    left.setX(startX);
-                    left.setY(startY);
-                    left.setDisplayWidth(leftArea);
-                    left.setDisplayHeight(h);
-                } else {
-                    startX = previousDividerPos;
-                    left.setX(startX);
-                    left.setY(startY);
-                    left.setDisplayWidth(minLeftWidth);
-                    left.setDisplayHeight(h);
-                }
-            } else {
-                // VERTICAL ORIENTATION
-                if (rightArea >= maxRightWidth) {
-                    right.setX(startX);
-                    right.setY(startY + dividerWidth + (rightArea - maxRightWidth)/2);
-                    right.setDisplayWidth(maxRightWidth);
-                    right.setDisplayHeight(h);
-                    if (redistribute) {
-                        pos = nextDividerPos - maxRightWidth - dividerWidth;
-                        dividerPos = pos;
-                        leftArea = pos - (previousDividerPos == 0 ? 0 : (previousDividerPos + dividerWidth));
-
-                        if (dividerPos + maxRightWidth + dividerWidth >= maxSize) {
-                            pos = maxSize - maxRightWidth - dividerWidth;
-                        }
-                        rightArea = nextDividerPos - (pos + dividerWidth);
-                        right.setY(pos + dividerWidth + (rightArea - maxRightWidth)/2);
-                    } else {
-                        pos = dividerPos;
-                    }
-                } else if (rightArea > minRightWidth) {
-                    right.setX(startX);
-                    right.setY(startY + dividerWidth);
-                    right.setDisplayWidth(rightArea);
-                    right.setDisplayHeight(h);
-                    pos = dividerPos;
-                } else {
-                    startY = nextDividerPos - minRightWidth;
-                    right.setX(startX);
-                    right.setY(startY);
-                    right.setDisplayWidth(minRightWidth);
-                    right.setDisplayHeight(h);
-                    pos = startY - dividerWidth;
-                    dividerPos = pos;
-                    leftArea = pos - (previousDividerPos == 0 ? 0 : (previousDividerPos + dividerWidth));
-                    if (leftArea <= minLeftWidth) {
-                        leftArea = minLeftWidth;
-                        previousDividerPos = previousDividerPos <= 0 ? 0 : dividerPos - minLeftWidth - dividerWidth;
-                    }
-                }
-                divider.setX(startX);
-                divider.setY(pos);
-
-                if (leftArea >= maxLeftWidth) {
-                    startY = previousDividerPos;
-                    left.setX(startX);
-                    left.setY(startY);
-                    left.setDisplayWidth(maxLeftWidth);
-                    left.setDisplayHeight(h);
-                } else if (leftArea > minLeftWidth) {
-                    startY = previousDividerPos;
-                    left.setX(startX);
-                    left.setY(startY);
-                    left.setDisplayWidth(leftArea);
-                    left.setDisplayHeight(h);
-                } else {
-                    startY = previousDividerPos;
-                    left.setX(startX);
-                    left.setY(startY);
-                    left.setDisplayWidth(minLeftWidth);
-                    left.setDisplayHeight(h);
-                }
-            }
-            setDividerPos(divider, pos + halfDividerWidth);
-        }
-    }
-
-    @Override protected void layoutChildren() {        
+    @Override protected void layoutChildren() {
         if (!getSkinnable().isVisible()) {
             return;
         }
 
-        double w = 0;
-        double h = 0;
+        double dividerWidth = contentDividers.isEmpty() ? 0 : contentDividers.get(0).prefWidth(-1);
+        double w = getWidth() - (getInsets().getLeft() + getInsets().getRight());
+        double h = getHeight() - (getInsets().getTop() + getInsets().getBottom());
 
-        if (this.horizontal) {
-            w = getWidth() - (getInsets().getLeft() + getInsets().getRight());
-            h = getHeight() - (getInsets().getTop() + getInsets().getBottom());
-        } else {
-            w = getHeight() - (getInsets().getTop() + getInsets().getBottom());
-            h = getWidth() - (getInsets().getLeft() + getInsets().getRight());
+        // If we are resizing the window save the current area into
+        // resizableWithParentArea.  We use this value during layout.
+        if (contentDividers.size() > 0 && previousArea != -1 && previousArea != (getWidth() * getHeight())) {
+            previousArea = getWidth() * getHeight();
+            for (Content c: contentRegions) {
+                c.setResizableWithParentArea(c.getArea());
+                c.setAvailable(0);
+            }
+            resize = true;
+        }
+        previousArea = getWidth() * getHeight();
+        
+        // If the window is less than the min size we want to resize
+        // proportionally
+        double minSize = totalMinSize();
+        if (minSize > (horizontal ? w : h)) {
+            double percentage = 0;
+            for (int i = 0; i < contentRegions.size(); i++) {
+                Content c = contentRegions.get(i);
+                double min = horizontal ? c.minWidth(-1) : c.minHeight(-1);
+                percentage = min/minSize;
+                c.setArea(snapSpace(percentage * (horizontal ? w : h)));
+                c.setAvailable(0);
+            }
+            setupContentAndDividerForLayout();
+            layoutDividersAndContent(w, h);
+            resize = false;
+            return;
         }
 
-        if (contentDividers.size() > 0 && previousSize != -1 && previousSize != (horizontal ? getWidth() : getHeight())) {
-            resizeSplitPane(w, h);
-            previousSize = horizontal ? getWidth() : getHeight();
-            return;
-        }
-        previousSize = horizontal ? getWidth() : getHeight();
-
-        double startX = 0;
-        double startY = 0;
-        double dividerPos = 0;
-        double previousDividerPos = 0;
-        double nextDividerPos = w;
-        double dividerWidth = contentDividers.isEmpty() ? 0 : contentDividers.get(0).prefWidth(-1);
-        double halfDividerWidth = dividerWidth / 2.0f;
-        double pos = 0;
-
-        Content left = null;
-        ContentDivider divider = null;
-        Content right = null;
-        ContentDivider nextDivider = null;
-
-        for (int i = 0; i < contentRegions.size(); i++) {
-            if (i == contentRegions.size() - 1) {
-                // We only have one content region in the SplitPane.
-                if (i == 0) {                    
-                    contentRegions.get(0).setX(startX);
-                    contentRegions.get(0).setY(startY);
-                    contentRegions.get(0).setDisplayWidth(w);
-                    contentRegions.get(0).setDisplayHeight(h);
+        for(int trys = 0; trys < 10; trys++) {
+            // Compute the area in between each divider.            
+            ContentDivider previousDivider = null;
+            ContentDivider divider = null;
+            for (int i = 0; i < contentRegions.size(); i++) {
+                double space = 0;                
+                if (i < contentDividers.size()) {
+                    divider = contentDividers.get(i);
+                    if (i == 0) {
+                        // First panel
+                        space = getAbsoluteDividerPos(divider);
+                    } else {
+                        // Middle panels
+                        if (getAbsoluteDividerPos(divider) <= getAbsoluteDividerPos(previousDivider)) {
+                            // The two dividers are stacked on top of each other or if the
+                            // current divider position is less than the previous position.
+                            // We will set the divider next to the previous divider.
+                            space = Double.NaN;
+                            double pos = getAbsoluteDividerPos(divider);
+                            setAbsoluteDividerPos(divider, pos + dividerWidth);
+                        } else {
+                            space = getAbsoluteDividerPos(divider) - (getAbsoluteDividerPos(previousDivider) + dividerWidth);
+                        }
+                    }
+                } else if (i == contentDividers.size()) {
+                    // Last panel
+                    space = (horizontal ? w : h) - (previousDivider != null ? getAbsoluteDividerPos(previousDivider) + dividerWidth : 0);
                 }
-                break;
+                contentRegions.get(i).setArea(space);
+                previousDivider = divider;
             }
 
-            nextDividerPos = w;
-            nextDivider = null;
+            // Compute the amount of space we have available.
+            // Available is amount of space we can take from a panel before we reach its min.
+            // If available is negative we don't have enough space and we will
+            // proportionally take the space from the other availables.  If we have extra space
+            // we will porportionally give it to the others
+            double spaceRequested = 0;
+            double extraSpace = 0;
+            for (Content c: contentRegions) {
+                double max = 0;
+                double min = 0;
+                if (c != null) {
+                    max = horizontal ? c.maxWidth(-1) : c.maxHeight(-1);
+                    min = horizontal ? c.minWidth(-1) : c.minHeight(-1);
+                }
 
-            left = contentRegions.get(i);
-
-            // TODO need to get rid the boolean updateDividerPos.
-            if (i < contentDividers.size()) {
-                updateDividerPos = true;
-                if (divider != null) {
-                    previousDividerPos = divider.getDividerPos();
+                if (c.getArea() >= max) {
+                    // Add the space that needs to be distributed to the others
+                    extraSpace += (c.getArea() - max);
+                    c.setArea(max);
+                    c.setAvailable(c.getArea() - min);
+                } else if (c.getArea() <= min) {
+                    c.setAvailable(c.getArea() - min);
+                } else if (Double.isNaN(c.getArea())) {
+                    if (min == 0) {
+                        // We have no panels and the dividers are stacked ontop of each other.
+                        c.setArea(0);
+                        c.setAvailable(0);
+                    } else {
+                        c.setArea(0);
+                        c.setAvailable(-min);
+                    }
+                } else {
+                    c.setAvailable(c.getArea() - min);
                 }
-                divider = contentDividers.get(i);
-            }
-            if (i + 1 < contentRegions.size()) {
-                right = contentRegions.get(i + 1);
-            }
-
-            updateDividerPos(divider);
-            dividerPos = divider.getDividerPos();
-
-            if (i + 1 < contentDividers.size()) {
-                nextDivider = contentDividers.get(i + 1);
-                updateDividerPos = true;
-                updateDividerPos(nextDivider);
-            }
-
-            if (nextDivider != null && nextDivider.getDividerPos() > dividerPos) {
-                nextDividerPos = nextDivider.getDividerPos();
-            }
-
-            // this is the space available to the left and right nodes.
-            // it would be ideal if both left and right nodes would happily resize
-            // to this value, but we need to check...
-            double availableLeftWidth =
-                (dividerPos + halfDividerWidth) - (previousDividerPos == 0 ? 0 : (previousDividerPos + dividerWidth - halfDividerWidth));
-            double availableRightWidth = nextDividerPos - dividerPos - halfDividerWidth;
-
-            // do bounds checking to ensure min/max widths aren't being exceeded
-            double minLeftWidth  = left == null ? 0 : (horizontal) ? left.minWidth(-1) : left.minHeight(-1);
-            double prefLeftWidth = left == null ? 0 : (horizontal) ? left.prefWidth(-1) : left.prefHeight(-1);
-            double maxLeftWidth  = left == null ? 0 :
-                left.getContent() != null ? (horizontal) ? left.getContent().maxWidth(-1) : left.getContent().maxHeight(-1) : 0;
-
-            double minRightWidth  = right == null ? 0 : (horizontal) ? right.minWidth(-1) : right.minHeight(-1);
-            double prefRightWidth = right == null ? 0 : (horizontal) ? right.prefWidth(-1) : right.prefHeight(-1);
-            double maxRightWidth  = right == null ? 0 :
-                right.getContent() != null ? (horizontal) ? right.getContent().maxWidth(-1) : right.getContent().maxHeight(-1) : 0;
-
-            // These properties are what the actual width will be set to
-            double leftNodeWidth;
-            double rightNodeWidth;
-            boolean divRecomputed = false;
-
-            // sort out left node
-            if (availableLeftWidth <= (minLeftWidth + halfDividerWidth)) {
-                dividerPos = (horizontal ? startX : startY) + minLeftWidth;
-                leftNodeWidth = minLeftWidth;
-                availableRightWidth = nextDividerPos - dividerPos - halfDividerWidth;
-                divRecomputed = true;
-            } else if (availableLeftWidth >= maxLeftWidth) {
-                leftNodeWidth = maxLeftWidth;
-                availableRightWidth = nextDividerPos - dividerPos - halfDividerWidth;
-            } else {
-                // if the node isn't managed, we shrink, but don't grow, the node
-                availableLeftWidth -= halfDividerWidth;
-                if (left.isManaged()) {
-                    leftNodeWidth = availableLeftWidth;
-                } else {
-                    leftNodeWidth = Math.min(prefLeftWidth, availableLeftWidth);
+                if (c.getAvailable() < 0) {
+                    spaceRequested += c.getAvailable();
                 }
             }
 
-            // sort out right node
-            if (availableRightWidth <= (minRightWidth + halfDividerWidth)) {
-                rightNodeWidth = minRightWidth;
+            spaceRequested = Math.abs(spaceRequested);
 
-                // Without it the right node will overflow the side of the SplitPane
-                if (!divRecomputed) {
-                    double rw = nextDividerPos - (dividerPos + dividerWidth);
-                    if (minRightWidth > rw) {
-                        dividerPos = nextDividerPos - rw - dividerWidth;
-                    } else {
-                        dividerPos = nextDividerPos - minRightWidth - dividerWidth;
-                    }
+            // Add the panels where we can take space from
+            List<Content> availableList = new ArrayList<Content>();
+            List<Content> storageList = new ArrayList<Content>();
+            List<Content> spaceRequestor = new ArrayList<Content>();
+            double available = 0;
+            for (Content c: contentRegions) {
+                if (c.getAvailable() >= 0) {
+                    available += c.getAvailable();
+                    availableList.add(c);
                 }
 
-                if (left.isManaged()) {
-                    // without this a managed node will overflow into the right
-                    // region, but we also have to be careful that if there is a max
-                    // width set on the left node that we don't grow it past that.
-                    leftNodeWidth = Math.min(dividerPos, maxLeftWidth);
+                if (resize && !c.isResizableWithParent()) {
+                    // We are making the SplitPane bigger and will need to
+                    // distribute the extra space.
+                    if (c.getArea() >= c.getResizableWithParentArea()) {                        
+                        extraSpace += (c.getArea() - c.getResizableWithParentArea());
+                    } else {
+                        // We are making the SplitPane smaller and will need to
+                        // find distribute the space requested.
+                        spaceRequested += (c.getResizableWithParentArea() - c.getArea());
+                    }
+                    c.setAvailable(0);
                 }
-            } else if (availableRightWidth >= maxRightWidth) {
-                rightNodeWidth = maxRightWidth;
-            } else {
-                availableRightWidth -= halfDividerWidth;
-                // if the node isn't managed, we shrink, but don't grow, the node
-                if (right.isManaged()) {
-                    rightNodeWidth = availableRightWidth;
+                // Add the panels where we can add space to;
+                if (resize) {
+                    if (c.isResizableWithParent()) {
+                        storageList.add(c);
+                    }
                 } else {
-                    rightNodeWidth = Math.min(prefRightWidth, availableRightWidth);
+                    storageList.add(c);
+                }
+                // List of panels that need space.
+                if (c.getAvailable() < 0) {
+                    spaceRequestor.add(c);
                 }
             }
 
-            // Can the content fit in the area ?
-            double leftArea = dividerPos - (previousDividerPos == 0 ? 0 : previousDividerPos + dividerWidth - halfDividerWidth);
-            double rightArea = nextDividerPos - (dividerPos + dividerWidth);
+            if (extraSpace > 0) {
+                double space = distributeTo(storageList, extraSpace);
+                if (space == 0) {
+                    spaceRequested -= extraSpace;
+                } else {
+                    spaceRequested -= space;
+                }
+                extraSpace = space;
+            }
 
-            // Setup all the values for layout
-            if (horizontal) {
-                if (leftArea >= maxLeftWidth) {
-                    left.setX(startX);
-                    left.setY(startY);
-                    left.setDisplayWidth(maxLeftWidth);
-                    left.setDisplayHeight(h);
-                    pos = startX + maxLeftWidth;
-                    dividerPos = pos;
-                    rightArea = nextDividerPos - (pos + dividerWidth);
-                } else if (leftArea > minLeftWidth) {
-                    left.setX(startX);
-                    left.setY(startY);
-                    left.setDisplayWidth(leftArea);
-                    left.setDisplayHeight(h);
-                    pos = dividerPos;
-                } else {
-                    left.setX(startX);
-                    left.setY(startY);
-                    left.setDisplayWidth(minLeftWidth);
-                    left.setDisplayHeight(h);
-                    pos = startX + minLeftWidth;
+            if (available >= spaceRequested) {
+                for (Content requestor: spaceRequestor) {
+                    double min = horizontal ? requestor.minWidth(-1) : requestor.minHeight(-1);
+                    requestor.setArea(min);
+                    requestor.setAvailable(0);
+                }
+                // We have some space requested but it is not from the space requestors.
+                // This is probably from resizing the SplitPane lets add this to
+                // extraSpace and try and redistribute it.
+                if (spaceRequested > 0 && !spaceRequestor.isEmpty()) {
+                    distributeFrom(spaceRequested, availableList);
                 }
 
-                divider.setX(pos);
-                divider.setY(startY);
-
-                if (rightArea >= maxRightWidth) {
-                    startX = dividerPos + dividerWidth;
-                    right.setX(startX + (rightArea - maxRightWidth)/2);
-                    right.setY(startY);
-                    right.setDisplayWidth(maxRightWidth);
-                    right.setDisplayHeight(h);
-                } else if (rightArea > minRightWidth) {
-                    startX = dividerPos + dividerWidth;
-                    right.setX(startX);
-                    right.setY(startY);
-                    right.setDisplayWidth(rightArea);
-                    right.setDisplayHeight(h);
-                } else {
-                    // If the contents minimum size is too big to fit
-                    // in the right area we want to mark it so it is not included
-                    // using when handle the overflow.
-                    right.setFitsInArea(true);
-                    if (minRightWidth > rightArea) {                        
-                        right.setFitsInArea(false);
+                // Only for resizing.  At this point we should have all the
+                // area available computed.  We can total them up and see
+                // how much space we have left or went over and redistribute.
+                if (resize) {
+                    double total = 0;
+                    for (Content c: contentRegions) {
+                        if (c.isResizableWithParent()) {
+                            total += c.getArea();
+                        } else {
+                            total += c.getResizableWithParentArea();
+                        }
                     }
-                    startX = dividerPos + dividerWidth;
-                    right.setX(startX);
-                    right.setY(startY);
-                    right.setDisplayWidth(minRightWidth);
-                    right.setDisplayHeight(h);
-                }
-            } else {
-                // VERTICAL ORIENTATION
-                if (leftArea >= maxLeftWidth) {
-                    left.setX(startX);
-                    left.setY(startY);
-                    left.setDisplayWidth(maxLeftWidth);
-                    left.setDisplayHeight(h);
-                    pos = startY + maxLeftWidth;
-                    dividerPos = pos;
-                    rightArea = nextDividerPos - (pos + dividerWidth);
-                } else if (leftArea > minLeftWidth) {
-                    left.setX(startX);
-                    left.setY(startY);
-                    left.setDisplayWidth(leftArea);
-                    left.setDisplayHeight(h);
-                    pos = dividerPos;
-                } else {
-                    left.setX(startX);
-                    left.setY(startY);
-                    left.setDisplayWidth(minLeftWidth);
-                    left.setDisplayHeight(h);
-                    pos = startY + minLeftWidth;
-                }
-
-                divider.setX(startX);
-                divider.setY(pos);
-
-                if (rightArea >= maxRightWidth) {
-                    startY = dividerPos + dividerWidth;
-                    right.setX(startX);
-                    right.setY(startY + (rightArea - maxRightWidth)/2);
-                    right.setDisplayWidth(maxRightWidth);
-                    right.setDisplayHeight(h);
-                } else if (rightArea > minRightWidth) {
-                    startY = dividerPos + dividerWidth;
-                    right.setX(startX);
-                    right.setY(startY);
-                    right.setDisplayWidth(rightArea);
-                    right.setDisplayHeight(h);
-                } else {
-                    // If the contents minimum size is too big to fit
-                    // in the right area we want to mark it so it is not included
-                    // using when handle the overflow.
-                    right.setFitsInArea(true);
-                    if (minRightWidth > rightArea) {
-                        right.setFitsInArea(false);
+                    total += (dividerWidth * contentDividers.size());
+                    if (total < (horizontal ? w : h)) {
+                        extraSpace += ((horizontal ? w : h) - total);
+                        distributeTo(storageList, extraSpace);
+                    } else {
+                        spaceRequested += (total - (horizontal ? w : h));
+                        distributeFrom(spaceRequested, storageList);
                     }
-                    startY = dividerPos + dividerWidth;
-                    right.setX(startX);
-                    right.setY(startY);
-                    right.setDisplayWidth(minRightWidth);
-                    right.setDisplayHeight(h);
-                }
-            }
-            setDividerPos(divider, pos + halfDividerWidth);
-        }
-
-        // TODO need to remove the overflow counter;
-        int overflowCounter = 0;
-
-        // If we overflowed we may need several passes to fix the overflow.
-        double overflow = contentRegions.size() > 1 ?
-            (((contentDividers.get(contentDividers.size() - 1).getDividerPos() - halfDividerWidth) +
-                dividerWidth + contentRegions.get(contentRegions.size() - 1).getDisplayWidth()) - w) : 0;
-        
-        if (overflow < 0) {
-            // RT-18805 try and redistribute the dividers if there
-            // is space left over.
-            redistribute(true, w, h);
-        }
-        
-        // TODO Maybe we should adjust for priority.
-        while (overflow > 0 && overflowCounter < 50) {
-            int index = indexOfMaxContent();
-            if (index == -1) {
-                break;
-            }
-            ListIterator<Content> contentList = contentRegions.listIterator(index);
-            Content c = contentList.next();
-            double min = horizontal ? c.minWidth(-1): c.minHeight(-1);
-
-            if (c.getDisplayWidth() - overflow > min) {
-                c.setDisplayWidth(c.getDisplayWidth() - overflow);
-            } else {
-                overflow -= (min - (c.getDisplayWidth() - overflow));
-                c.setDisplayWidth(min);
-            }
-            while (contentList.hasNext()) {
-                c = contentList.next();
-                if (horizontal) {
-                    c.setX(c.getX() - overflow);
-                } else {
-                    c.setY(c.getY() - overflow);
                 }
             }
 
-            ListIterator<ContentDivider> dividerList = contentDividers.listIterator(index);
-            while (dividerList.hasNext()) {
-                ContentDivider div = dividerList.next();
-                if (horizontal) {
-                    div.setX(div.getX() - overflow);
-                } else {
-                    div.setY(div.getY() - overflow);
+            setupContentAndDividerForLayout();
+
+            // Check the bounds of every panel
+            boolean passed = true;
+            for (Content c: contentRegions) {
+                double max = horizontal ? c.maxWidth(-1) : c.maxHeight(-1);
+                double min = horizontal ? c.minWidth(-1) : c.minHeight(-1);
+                if (c.getArea() < min || c.getArea() > max) {
+                    passed = false;
+                    break;
                 }
-                setDividerPos(div, div.getDividerPos() - overflow);
             }
+            if (passed) {
+                break;
+            }
+        }
 
-            overflow = ((contentDividers.get(contentDividers.size() - 1).getDividerPos() - halfDividerWidth) +
-                      dividerWidth + contentRegions.get(contentRegions.size() - 1).getDisplayWidth()) - w;
-            overflowCounter++;
-        }
-        layoutDividersAndContent();
+        layoutDividersAndContent(w, h);        
+        resize = false;
     }
 
     @Override protected double computeMinWidth(double height) {
@@ -994,6 +767,21 @@
         }
     }
 
+    private void printAreaAndAvailable() {
+        for (int i = 0; i < contentRegions.size(); i++) {
+            System.out.print("AREA[" + i + "] " + contentRegions.get(i).getArea() + " ");
+        }
+        System.out.println("");
+        for (int i = 0; i < contentRegions.size(); i++) {
+            System.out.print("AVAILABLE[" + i + "] " + contentRegions.get(i).getAvailable() + " ");
+        }
+        System.out.println("");
+        for (int i = 0; i < contentRegions.size(); i++) {
+            System.out.print("RESIZABLEWTIHPARENT[" + i + "] " + contentRegions.get(i).getResizableWithParentArea() + " ");
+        }
+        System.out.println("");
+    }
+
     class ContentDivider extends StackPane {
         private double initialPos;
         private double dividerPos;
@@ -1137,22 +925,20 @@
         private Rectangle clipRect;
         private double x;
         private double y;
-        private double displayWidth;
-        private double displayHeight;
-        private boolean fitsInArea;
+        private double area;
+        private double resizableWithParentArea;
+        private double available;
 
         public Content(Node n) {
             this.clipRect = new Rectangle();
             setClip(clipRect);
             this.content = n;
             if (n != null) {
+                this.setId(n.getId());
                 getChildren().add(n);
             }
             this.x = 0;
             this.y = 0;
-            this.displayWidth = 0;
-            this.displayHeight = 0;
-            fitsInArea = true;
         }
 
         public Node getContent() {
@@ -1175,28 +961,42 @@
             this.y = y;
         }
 
-        public double getDisplayHeight() {
-            return displayHeight;
+        // This is the area of the panel.  This will be used as the
+        // width/height during layout.
+        public double getArea() {
+            return area;
         }
 
-        public void setDisplayHeight(double displayHeight) {
-            this.displayHeight = displayHeight;
+        public void setArea(double area) {
+            this.area = area;
         }
 
-        public double getDisplayWidth() {
-            return displayWidth;
+        // This is the minimum available area for other panels to use
+        // if they need more space.
+        public double getAvailable() {
+            return available;
         }
 
-        public void setDisplayWidth(double displayWidth) {
-            this.displayWidth = displayWidth;
+        public void setAvailable(double available) {
+            this.available = available;
         }
 
-        public boolean fitsInArea() {
-            return fitsInArea;
+        public boolean isResizableWithParent() {
+            return true;//SplitPane.isResizableWithParent(content);
         }
 
-        public void setFitsInArea(boolean fitsInArea) {
-            this.fitsInArea = fitsInArea;
+        public double getResizableWithParentArea() {
+            return resizableWithParentArea;
+        }
+
+        // This is used to save the current area during resizing when
+        // isResizeableWithParent equals false.
+        public void setResizableWithParentArea(double resizableWithParentArea) {
+            if (!isResizableWithParent()) {
+                this.resizableWithParentArea = resizableWithParentArea;
+            } else {
+                this.resizableWithParentArea = 0;
+            }
         }
 
         @Override protected void setWidth(double value) {
@@ -1208,5 +1008,14 @@
             super.setHeight(value);
             clipRect.setHeight(value);
         }
+
+        @Override protected double computeMaxWidth(double height) {
+            return content.maxWidth(height);
+        }
+
+        @Override protected double computeMaxHeight(double width) {
+            return content.maxHeight(width);
+        }
     }
 }
+
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TextFieldSkin.java	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TextFieldSkin.java	Tue Jan 17 18:02:40 2012 -0500
@@ -90,6 +90,7 @@
      * there is any text specified on the TextInputControl
      */
     private Text textNode = new Text();
+    private Text promptNode;
     /**
      * A path, provided by the textNode, which represents the area
      * which is selected. The path elements which make up the
@@ -104,6 +105,7 @@
     private DoubleProperty textTranslateX = new SimpleDoubleProperty(this, "textTranslateX");
     private DoubleProperty textTranslateY = new SimpleDoubleProperty(this, "textTranslateY");
     private ObservableIntegerValue caretPosition;
+    private double caretWidth;
     private BooleanProperty forwardBias = new BooleanPropertyBase() {
         @Override public Object getBean() {
             return TextFieldSkin.this;
@@ -159,16 +161,6 @@
         super(textField, new TextFieldBehavior(textField));
         getBehavior().setTextFieldSkin(this);
 
-        // A simple boolean binding which defines whether or not we should
-        // use the prompt text here. This is lighter weight than having
-        // a separate node for the prompt text.
-        usePromptText = new BooleanBinding() {
-            { bind(textField.textProperty(), textField.promptTextProperty()); }
-            @Override protected boolean computeValue() {
-                String txt = textField.getText();
-                return (txt == null || "".equals(txt));
-            }
-        };
 
         caretPosition = new IntegerBinding() {
             { bind(textField.caretPositionProperty()); }
@@ -198,7 +190,7 @@
             @Override
             public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                 if (getWidth() > 0) {
-                    textTranslateX.set(0);
+                    updateTextPos();
                     updateCaretOff();
                 }
             }
@@ -252,29 +244,16 @@
         // Add text
         textNode.setManaged(false);
         textNode.fontProperty().bind(font);
-        textNode.yProperty().bind(new DoubleBinding() {
-            { bind(fontMetrics, insets()); }
-            @Override protected double computeValue() {
-                return fontMetrics.get().getMaxAscent() + getInsets().getTop();
-            }
-        });
         textNode.xProperty().bind(textLeft);
         textNode.layoutXProperty().bind(textTranslateX);
         textNode.textProperty().bind(new StringBinding() {
-            { bind(textField.textProperty(), textField.promptTextProperty(), usePromptText); }
+            { bind(textField.textProperty()); }
             @Override protected String computeValue() {
-                String txt = usePromptText.get() ?
-                    textField.getPromptText() :
-                    maskText(textField.getText());
+                String txt = maskText(textField.getText());
                 return txt == null ? "" : txt;
             }
         });
-        textNode.fillProperty().bind(new ObjectBinding<Paint>() {
-            { bind(usePromptText, promptTextFill, textFill); }
-            @Override protected Paint computeValue() {
-                return usePromptText.get() ? promptTextFill.get() : textFill.get();
-            }
-        });
+        textNode.fillProperty().bind(textFill);
         textNode.impl_selectionFillProperty().bind(new ObjectBinding<Paint>() {
             { bind(highlightTextFill, textFill, textField.focusedProperty()); }
             @Override protected Paint computeValue() {
@@ -313,6 +292,7 @@
         textNode.impl_caretShapeProperty().addListener(new InvalidationListener() {
             @Override public void invalidated(Observable observable) {
                 caretPath.getElements().setAll(textNode.impl_caretShapeProperty().get());
+                caretWidth = caretPath.getLayoutBounds().getWidth();
             }
         });
 
@@ -330,6 +310,50 @@
         
         registerChangeListener(textField.prefColumnCountProperty(), "prefColumnCount");
         if (textField.isFocused()) setCaretAnimating(true);
+
+        textField.alignmentProperty().addListener(new InvalidationListener() {
+            @Override public void invalidated(Observable observable) {
+                if (getWidth() > 0) {
+                    updateTextPos();
+                    updateCaretOff();
+                    requestLayout();
+                }
+            }
+        });
+
+        usePromptText = new BooleanBinding() {
+            { bind(textField.textProperty(), textField.promptTextProperty()); }
+            @Override protected boolean computeValue() {
+                String txt = textField.getText();
+                String promptTxt = textField.getPromptText();
+                return ((txt == null || txt.isEmpty()) &&
+                        promptTxt != null && !promptTxt.isEmpty());
+            }
+        };
+
+        if (usePromptText.get()) {
+            createPromptNode();
+        }
+
+        usePromptText.addListener(new InvalidationListener() {
+            @Override public void invalidated(Observable observable) {
+                createPromptNode();
+            }
+        });
+    }
+
+    private void createPromptNode() {
+        if (promptNode != null || !usePromptText.get()) return;
+
+        promptNode = new Text();
+        textGroup.getChildren().add(0, promptNode);
+        promptNode.setManaged(false);
+        promptNode.visibleProperty().bind(usePromptText);
+        promptNode.fontProperty().bind(font);
+        promptNode.xProperty().bind(textLeft);
+        promptNode.layoutXProperty().set(0.0);
+        promptNode.textProperty().bind(getSkinnable().promptTextProperty());
+        promptNode.fillProperty().bind(promptTextFill);
         updateSelection();
     }
 
@@ -388,6 +412,24 @@
         return getInsets().getTop() + fontMetrics.getAscent();
     }
 
+    private void updateTextPos() {
+        switch (getSkinnable().getAlignment().getHpos()) {
+          case CENTER:
+            double midPoint = (textRight.get() - textLeft.get()) / 2;
+            textTranslateX.set(midPoint - textNode.getLayoutBounds().getWidth() / 2);
+            break;
+
+          case RIGHT:
+            textTranslateX.set(textRight.get() - textNode.getLayoutBounds().getWidth() -
+                               caretWidth / 2 - 5);
+            break;
+
+          case LEFT:
+          default:
+            textTranslateX.set(caretWidth / 2);
+        }
+    }
+
     // should be called when the padding changes, or the text box width, or
     // the dot moves
     protected void updateCaretOff() {
@@ -400,14 +442,29 @@
         if (caretX < textLeft.get()) {
             // I'll end up with a negative number
             delta = caretX - textLeft.get();
-        } else if (caretX > (textRight.get() - caretPath.getLayoutBounds().getWidth())) {
+        } else if (caretX > (textRight.get() - caretWidth)) {
             // I'll end up with a positive number
-            delta = caretX - (textRight.get() - caretPath.getLayoutBounds().getWidth());
+            delta = caretX - (textRight.get() - caretWidth);
         }
 
         // If delta is negative, then translate in the negative direction
         // to cause the text to scroll to the right. Vice-versa for positive.
-        textTranslateX.set(Math.min(textTranslateX.get() - delta, 0.0));
+        switch (getSkinnable().getAlignment().getHpos()) {
+          case CENTER:
+            textTranslateX.set(textTranslateX.get() - delta);
+            break;
+
+          case RIGHT:
+            textTranslateX.set(Math.max(textTranslateX.get() - delta,
+                                        textRight.get() - textNode.getLayoutBounds().getWidth() -
+                                        caretWidth / 2 - 5));
+            break;
+
+          case LEFT:
+          default:
+            textTranslateX.set(Math.min(textTranslateX.get() - delta,
+                                        caretWidth / 2));
+        }
     }
 
     /**
@@ -446,20 +503,43 @@
         final Bounds textBounds = textNode.localToParent(textLayoutBounds);
         final Bounds clipBounds = clip.getBoundsInParent();
         final Bounds caretBounds = caretPath.getLayoutBounds();
-        if (textBounds.getMinX() >= clipBounds.getMinX()) {
-            return;
-        }
 
-        double delta = caretMaxXOld - caretBounds.getMaxX() - textTranslateX.get();
-        if (textBounds.getMaxX() + delta < clipBounds.getMaxX()) {
-            if (textMaxXOld <= clipBounds.getMaxX()) {
-                delta = textMaxXOld - textBounds.getMaxX();
+        switch (getSkinnable().getAlignment().getHpos()) {
+          case CENTER:
+            updateTextPos();
+            break;
+
+          case RIGHT:
+            if (textBounds.getMaxX() > clipBounds.getMaxX()) {
+                double delta = caretMaxXOld - caretBounds.getMaxX() - textTranslateX.get();
+                if (textBounds.getMaxX() + delta < clipBounds.getMaxX()) {
+                    if (textMaxXOld <= clipBounds.getMaxX()) {
+                        delta = textMaxXOld - textBounds.getMaxX();
+                    } else {
+                        delta = clipBounds.getMaxX() - textBounds.getMaxX();
+                    }
+                }
+                textTranslateX.set(textTranslateX.get() + delta);
             } else {
-                delta = clipBounds.getMaxX() - textBounds.getMaxX();
+                updateTextPos();
+            }
+            break;
+
+          case LEFT:
+          default:
+            if (textBounds.getMinX() < clipBounds.getMinX() + caretWidth / 2) {
+                double delta = caretMaxXOld - caretBounds.getMaxX() - textTranslateX.get();
+                if (textBounds.getMaxX() + delta < clipBounds.getMaxX()) {
+                    if (textMaxXOld <= clipBounds.getMaxX()) {
+                        delta = textMaxXOld - textBounds.getMaxX();
+                    } else {
+                        delta = clipBounds.getMaxX() - textBounds.getMaxX();
+                    }
+                }
+                textTranslateX.set(textTranslateX.get() + delta);
             }
         }
 
-        textTranslateX.set(textTranslateX.get() + delta);
         updateCaretOff();
     }
 
@@ -540,4 +620,31 @@
     @Override protected void removeHighlight(List<? extends Node> nodes) {
         textGroup.getChildren().removeAll(nodes);
     }
+
+    @Override protected void layoutChildren() {
+        super.layoutChildren();
+
+        if (textNode != null) {
+            double textY;
+            Insets insets = getInsets();
+            switch (getSkinnable().getAlignment().getVpos()) {
+              case TOP:
+                textY = insets.getTop() + fontMetrics.get().getMaxAscent();
+                break;
+
+              case CENTER:
+                textY = (getHeight() - insets.getBottom() - insets.getTop()
+                         + fontMetrics.get().getLineHeight()) / 2;
+                break;
+
+              case BOTTOM:
+              default:
+                textY = getHeight() - insets.getBottom() - fontMetrics.get().getMaxDescent();
+            }
+            textNode.setY(textY);
+            if (promptNode != null) {
+                promptNode.setY(textY);
+            }
+        }
+    }
 }
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/ToolBarSkin.java	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/ToolBarSkin.java	Tue Jan 17 18:02:40 2012 -0500
@@ -30,7 +30,6 @@
 import java.util.List;
 
 import javafx.beans.property.ObjectProperty;
-import javafx.beans.property.ObjectPropertyBase;
 import javafx.beans.property.DoubleProperty;
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
@@ -61,7 +60,9 @@
 import javafx.scene.layout.VBox;
 
 import com.sun.javafx.css.StyleableDoubleProperty;
+import com.sun.javafx.css.StyleableObjectProperty;
 import com.sun.javafx.css.StyleableProperty;
+import com.sun.javafx.css.converters.EnumConverter;
 import com.sun.javafx.css.converters.SizeConverter;
 import com.sun.javafx.scene.control.behavior.ToolBarBehavior;
 import com.sun.javafx.scene.traversal.Direction;
@@ -189,7 +190,7 @@
 
     public final ObjectProperty<Pos> boxAlignmentProperty() {
         if (boxAlignment == null) {
-            boxAlignment = new ObjectPropertyBase<Pos>(Pos.TOP_LEFT) {
+            boxAlignment = new StyleableObjectProperty<Pos>(Pos.TOP_LEFT) {
 
                 @Override
                 public void invalidated() {
@@ -210,6 +211,11 @@
                 public String getName() {
                     return "boxAlignment";
                 }
+
+                @Override
+                public StyleableProperty getStyleableProperty() {
+                    return StyleableProperties.ALIGNMENT;
+                }
             };
         }
         return boxAlignment;
@@ -625,14 +631,41 @@
                 return n.spacingProperty();
             }
         };
+         
+        private static final StyleableProperty<ToolBarSkin,Pos>ALIGNMENT =
+                new StyleableProperty<ToolBarSkin,Pos>("-fx-alignment",
+                new EnumConverter<Pos>(Pos.class), Pos.TOP_LEFT ) {
 
+            @Override
+            public boolean isSettable(ToolBarSkin n) {
+                return n.boxAlignment == null || !n.boxAlignment.isBound();
+            }
+
+            @Override
+            public WritableValue<Pos> getWritableValue(ToolBarSkin n) {
+                return n.boxAlignmentProperty();
+            }
+        };
+
+         
          private static final List<StyleableProperty> STYLEABLES;
          static {
 
             final List<StyleableProperty> styleables =
                 new ArrayList<StyleableProperty>(SkinBase.impl_CSS_STYLEABLES());
+            
+            // StackPane also has -fx-alignment. Replace it with 
+            // ToolBarSkin's. 
+            // TODO: Really should be able to reference StackPane.StyleableProperties.ALIGNMENT
+            final String alignmentProperty = ALIGNMENT.getProperty();
+            for (int n=0, nMax=styleables.size(); n<nMax; n++) {
+                final StyleableProperty prop = styleables.get(n);
+                if (alignmentProperty.equals(prop.getProperty())) styleables.remove(prop);
+            }
+            
             Collections.addAll(styleables,
-                SPACING
+                SPACING, 
+                ALIGNMENT
             );
             STYLEABLES = Collections.unmodifiableList(styleables);
 
--- a/javafx-ui-controls/src/javafx/scene/control/ChoiceBox.java	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-ui-controls/src/javafx/scene/control/ChoiceBox.java	Tue Jan 17 18:02:40 2012 -0500
@@ -34,9 +34,12 @@
 import javafx.collections.FXCollections;
 import javafx.collections.ListChangeListener;
 import javafx.collections.ObservableList;
-import com.sun.javafx.css.StyleManager;
 import javafx.beans.property.ReadOnlyBooleanProperty;
 import javafx.beans.property.ReadOnlyBooleanWrapper;
+import javafx.event.ActionEvent;
+import javafx.util.StringConverter;
+
+import com.sun.javafx.css.StyleManager;
 
 /**
  * The ChoiceBox is used for presenting the user with a relatively small set of
@@ -94,6 +97,19 @@
         getStyleClass().setAll("choice-box");
         setItems(items);
         setSelectionModel(new ChoiceBoxSelectionModel<T>(this));
+        
+        // listen to the value property, if the value is
+        // set to something that exists in the items list, update the
+        // selection model to indicate that this is the selected item
+        valueProperty().addListener(new ChangeListener<T>() {
+            @Override public void changed(ObservableValue<? extends T> ov, T t, T t1) {
+                if (getItems() == null) return;
+                int index = getItems().indexOf(t1);
+                if (index > -1) {
+                    getSelectionModel().select(index);
+                }
+            }
+        });
     }
 
     /***************************************************************************
@@ -109,7 +125,30 @@
      * in the items list should be selected, or to listen to changes in the
      * selection to know which item has been chosen.
      */
-    private ObjectProperty<SingleSelectionModel<T>> selectionModel = new SimpleObjectProperty<SingleSelectionModel<T>>(this, "selectionModel");
+    private ObjectProperty<SingleSelectionModel<T>> selectionModel = 
+            new SimpleObjectProperty<SingleSelectionModel<T>>(this, "selectionModel") {
+         private SelectionModel<T> oldSM = null;
+        @Override protected void invalidated() {
+            if (oldSM != null) {
+                oldSM.selectedItemProperty().removeListener(selectedItemListener);
+            }
+            SelectionModel sm = get();
+            oldSM = sm;
+            if (sm != null) {
+                sm.selectedItemProperty().addListener(selectedItemListener);
+            }
+        }                
+    };
+    
+    private ChangeListener<T> selectedItemListener = new ChangeListener<T>() {
+        @Override public void changed(ObservableValue<? extends T> ov, T t, T t1) {
+            if (! valueProperty().isBound()) {
+                setValue(t1);
+            }
+        }
+    };
+
+    
     public final void setSelectionModel(SingleSelectionModel<T> value) { selectionModel.set(value); }
     public final SingleSelectionModel<T> getSelectionModel() { return selectionModel.get(); }
     public final ObjectProperty<SingleSelectionModel<T>> selectionModelProperty() { return selectionModel; }
@@ -185,7 +224,16 @@
     private final ListChangeListener<T> itemsListener = new ListChangeListener<T>() {
         @Override public void onChanged(Change<? extends T> c) {
             final SingleSelectionModel<T> sm = getSelectionModel();
+            if (sm!= null) {
+                if (getItems() == null || getItems().isEmpty()) {
+                    sm.clearSelection();
+                } else {
+                    int newIndex = getItems().indexOf(sm.getSelectedItem());
+                    sm.setSelectedIndex(newIndex);
+                }
+            }
             if (sm != null) {
+                
                 // Look for the selected item as having been removed. If it has been,
                 // then we need to clear the selection in the selection model.
                 final T selectedItem = sm.getSelectedItem();
@@ -193,11 +241,46 @@
                     if (selectedItem != null && c.getRemoved().contains(selectedItem)) {
                         sm.clearSelection();
                         break;
-                    }
+                        }
                 }
             }
         }
     };
+    
+    /**
+     * Allows a way to specify how to represent objects in the items list. When
+     * a StringConverter is set, the object toString method is not called and 
+     * instead its toString(object T) is called, passing the objects in the items list. 
+     * This is useful when using domain objects in a ChoiceBox as this property 
+     * allows for customization of the representation. Also, any of the pre-built
+     * Converters available in the {@link javafx.util.converter} package can be set. 
+     */
+    public ObjectProperty<StringConverter<T>> converterProperty() { return converter; }
+    private ObjectProperty<StringConverter<T>> converter = 
+            new SimpleObjectProperty<StringConverter<T>>(this, "converter", null);
+    public final void setConverter(StringConverter<T> value) { converterProperty().set(value); }
+    public final StringConverter<T> getConverter() {return converterProperty().get(); }
+    
+    /**
+     * The value of this ChoiceBox is defined as the selected item in the ChoiceBox
+     * selection model. The valueProperty is synchronized with the selectedItem. 
+     * This property allows for bi-directional binding of external properties to the 
+     * ChoiceBox and updates the selection model accordingly. 
+     */
+    public ObjectProperty<T> valueProperty() { return value; }
+    private ObjectProperty<T> value = new SimpleObjectProperty<T>(this, "value") {
+        @Override protected void invalidated() {
+            super.invalidated();
+            fireEvent(new ActionEvent());
+            // Update selection
+            final SingleSelectionModel<T> sm = getSelectionModel();
+            if (sm != null) {
+                sm.select(getValue());
+            }
+        }
+    };
+    public final void setValue(T value) { valueProperty().set(value); }
+    public final T getValue() { return valueProperty().get(); }
 
     /***************************************************************************
      *                                                                         *
@@ -318,7 +401,7 @@
          */
         @Override public void select(int index) {
             final int rowCount = getItemCount();
-            if (rowCount == 0 || index < 0 || index >= rowCount) return;
+            // this does not sound right, we should let the superclass handle it.
             final T value = getModelItem(index);
             if (value instanceof Separator) {
                 select(++index);
--- a/javafx-ui-controls/src/javafx/scene/control/MultipleSelectionModelBase.java	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-ui-controls/src/javafx/scene/control/MultipleSelectionModelBase.java	Tue Jan 17 18:02:40 2012 -0500
@@ -162,10 +162,10 @@
     @Override public ObservableList<Integer> getSelectedIndices() {
         return selectedIndicesSeq;
     }
-    private void setSelectedIndices(BitSet rows) {
-        this.selectedIndices.clear();
-        this.selectedIndices.or(rows);
-    }
+//    private void setSelectedIndices(BitSet rows) {
+//        this.selectedIndices.clear();
+//        this.selectedIndices.or(rows);
+//    }
 
     private final ReadOnlyUnbackedObservableList selectedItemsSeq;
     @Override public ObservableList<T> getSelectedItems() {
@@ -217,17 +217,35 @@
         if (position < 0) return;
         if (shift == 0) return;
         
+        int selectedIndicesCardinality = selectedIndices.cardinality(); // number of true bits
+        if (selectedIndicesCardinality == 0) return;
+        
+        int selectedIndicesSize = selectedIndices.size();   // number of bits reserved 
+        
+        int[] perm = new int[selectedIndicesSize];
+        int idx = 0;
+        
         if (shift > 0) {
             for (int iter = 0; iter < shift; iter++) {
-                for (int i = selectedIndices.size() - 1; i >= position && i >= 0; i--) {
-                    selectedIndices.set(i+1, selectedIndices.get(i));
+                for (int i = selectedIndicesSize - 1; i >= position && i >= 0; i--) {
+                    boolean selected = selectedIndices.get(i);
+                    selectedIndices.set(i+1, selected);
+                    
+                    if (selected) {
+                        perm[idx++] = i + 1;
+                    }
                 }
                 selectedIndices.clear(position);
              }
         } else if (shift < 0) {
             for (int iter = 0; iter < Math.abs(shift); iter++) {
-                for (int i = position; i < selectedIndices.size() ; i++) {
-                    selectedIndices.set(i, selectedIndices.get(i+1));
+                for (int i = position; i < selectedIndicesSize; i++) {
+                    boolean selected = selectedIndices.get(i + 1);
+                    selectedIndices.set(i, selected);
+                    
+                    if (selected) {
+                        perm[idx++] = i;
+                    }
                 }
             }
         }
@@ -237,8 +255,12 @@
             setSelectedIndex(getFocusedIndex() + shift);
         }
          
-        // TODO this isn't correct
-        selectedIndicesSeq.callObservers(new NonIterableChange.SimplePermutationChange<Integer>(0, getItemCount() - 1, new int[] { }, selectedIndicesSeq));
+        selectedIndicesSeq.callObservers(
+                new NonIterableChange.SimplePermutationChange<Integer>(
+                        0, 
+                        selectedIndicesCardinality, 
+                        perm, 
+                        selectedIndicesSeq));
     }
 
     @Override public void clearAndSelect(int row) {
--- a/javafx-ui-controls/src/javafx/scene/control/TableCell.java	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-ui-controls/src/javafx/scene/control/TableCell.java	Tue Jan 17 18:02:40 2012 -0500
@@ -358,7 +358,7 @@
         // reset the editing index on the TableView
         if (table != null) {
             TablePosition editingCell = table.getEditingCell();
-            table.edit(-1, null);
+            if (updateEditingIndex) table.edit(-1, null);
 
             CellEditEvent editEvent = new CellEditEvent(
                 table,
@@ -451,14 +451,23 @@
         if (getIndex() == -1 || getTableView() == null) return;
 
         TablePosition editCell = getTableView().getEditingCell();
-        if (! isEditing()) {
-            if (match(editCell)) {
-                startEdit();
-            }
-        } else {
+        boolean match = match(editCell);
+        
+        if (match && ! isEditing()) {
+            startEdit();
+        } else if (! match && isEditing()) {
+            // If my index is not the one being edited then I need to cancel
+            // the edit. The tricky thing here is that as part of this call
+            // I cannot end up calling list.edit(-1) the way that the standard
+            // cancelEdit method would do. Yet, I need to call cancelEdit
+            // so that subclasses which override cancelEdit can execute. So,
+            // I have to use a kind of hacky flag workaround.
+            updateEditingIndex = false;
             cancelEdit();
+            updateEditingIndex = true;
         }
     }
+    private boolean updateEditingIndex = true;
 
     private boolean match(TablePosition pos) {
         return pos != null && pos.getRow() == getIndex() && pos.getTableColumn() == getTableColumn();
--- a/javafx-ui-controls/src/javafx/scene/control/TextField.java	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-ui-controls/src/javafx/scene/control/TextField.java	Tue Jan 17 18:02:40 2012 -0500
@@ -25,6 +25,10 @@
 
 package javafx.scene.control;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
 import javafx.beans.InvalidationListener;
 import javafx.beans.property.IntegerProperty;
 import javafx.beans.property.IntegerPropertyBase;
@@ -33,10 +37,15 @@
 import javafx.beans.property.SimpleStringProperty;
 import javafx.beans.property.StringProperty;
 import javafx.beans.value.ChangeListener;
+import javafx.beans.value.WritableValue;
 import javafx.event.ActionEvent;
 import javafx.event.EventHandler;
+import javafx.geometry.Pos;
 
 import com.sun.javafx.binding.ExpressionHelper;
+import com.sun.javafx.css.*;
+import com.sun.javafx.css.converters.*;
+
 
 /**
  * Text input component that allows a user to enter a single line of
@@ -216,4 +225,75 @@
     public final ObjectProperty<EventHandler<ActionEvent>> onActionProperty() { return onAction; }
     public final EventHandler<ActionEvent> getOnAction() { return onActionProperty().get(); }
     public final void setOnAction(EventHandler<ActionEvent> value) { onActionProperty().set(value); }
+
+    /**
+     * Specifies how the text should be aligned when there is empty
+     * space within the TextField.
+     */
+    public final ObjectProperty<Pos> alignmentProperty() {
+        if (alignment == null) {
+            alignment = new StyleableObjectProperty<Pos>(Pos.CENTER_LEFT) {
+
+                @Override public StyleableProperty getStyleableProperty() {
+                    return StyleableProperties.ALIGNMENT;
+                }
+
+                @Override public Object getBean() {
+                    return TextField.this;
+                }
+
+                @Override public String getName() {
+                    return "alignment";
+                }
+            };
+        }
+        return alignment;
+    }
+    private ObjectProperty<Pos> alignment;
+    public final void setAlignment(Pos value) { alignmentProperty().set(value); }
+    public final Pos getAlignment() { return alignment == null ? Pos.CENTER_LEFT : alignment.get(); }
+
+
+    /***************************************************************************
+     *                                                                         *
+     * Stylesheet Handling                                                     *
+     *                                                                         *
+     **************************************************************************/
+
+     /**
+      * @treatasprivate implementation detail
+      */
+    private static class StyleableProperties {
+        private static final StyleableProperty<TextField, Pos> ALIGNMENT =
+            new StyleableProperty<TextField, Pos>("-fx-alignment",
+                new EnumConverter<Pos>(Pos.class), Pos.CENTER_LEFT ) {
+
+            @Override public boolean isSettable(TextField n) {
+                return (n.alignment == null || !n.alignment.isBound());
+            }
+
+            @Override public WritableValue<Pos> getWritableValue(TextField n) {
+                return n.alignmentProperty();
+            }
+        };
+
+        private static final List<StyleableProperty> STYLEABLES;
+        static {
+            final List<StyleableProperty> styleables =
+                new ArrayList<StyleableProperty>(Control.impl_CSS_STYLEABLES());
+            Collections.addAll(styleables,
+                ALIGNMENT
+            );
+            STYLEABLES = Collections.unmodifiableList(styleables);
+        }
+    }
+
+    /**
+     * @treatasprivate implementation detail
+     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
+     */
+    @Deprecated
+    public static List<StyleableProperty> impl_CSS_STYLEABLES() {
+        return TextField.StyleableProperties.STYLEABLES;
+    }
 }
--- a/javafx-ui-controls/test/com/sun/javafx/scene/control/skin/ScrollPaneSkinTest.java	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-ui-controls/test/com/sun/javafx/scene/control/skin/ScrollPaneSkinTest.java	Tue Jan 17 18:02:40 2012 -0500
@@ -417,6 +417,134 @@
         assertTrue(scrollPane.getViewportBounds().getWidth() == Math.ceil(100.5));
     }
 
+    /*
+    ** check ScrollBars missing if fitToHeight is true but height is > minHeight
+    */
+    @Test public void checkNoScrollbarsWhenFitToAndSizeOK() {
+        scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED);
+        scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED);
+
+        StackPane sp = new StackPane();
+        sp.setPrefWidth(80);
+        sp.setPrefHeight(80);
+        sp.setMinWidth(40);
+        sp.setMinHeight(40);
+
+        scrollPane.setPrefSize(50, 50);
+        scrollPane.setContent(sp);
+        scrollPane.setPannable(true);
+        scrollPane.setFitToWidth(true);
+        scrollPane.setFitToHeight(true);
+
+        Scene scene = new Scene(new Group(), 400, 400);
+        ((Group) scene.getRoot()).getChildren().clear();
+        ((Group) scene.getRoot()).getChildren().add(scrollPane);
+        Stage stage = new Stage();
+        stage.setScene(scene);
+        stage.show();
+        
+        /*
+        ** did it work?
+        */
+        assertTrue(!skin.isHSBarVisible() & !skin.isVSBarVisible());
+    }
+
+    /*
+    ** check if ScrollBars appear if fitToHeight is true but height is < minHeight
+    */
+    @Test public void checkIfScrollbarsWhenFitToHeightAndHeightLessMin() {
+        scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED);
+        scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED);
+
+        StackPane sp = new StackPane();
+        sp.setPrefWidth(80);
+        sp.setPrefHeight(80);
+        sp.setMinWidth(40);
+        sp.setMinHeight(40);
+
+        scrollPane.setPrefSize(30, 50);
+        scrollPane.setContent(sp);
+        scrollPane.setPannable(true);
+        scrollPane.setFitToWidth(true);
+        scrollPane.setFitToHeight(true);
+
+        Scene scene = new Scene(new Group(), 400, 400);
+        ((Group) scene.getRoot()).getChildren().clear();
+        ((Group) scene.getRoot()).getChildren().add(scrollPane);
+        Stage stage = new Stage();
+        stage.setScene(scene);
+        stage.show();
+        
+        /*
+        ** did it work?
+        */
+        assertTrue(skin.isHSBarVisible() & !skin.isVSBarVisible());
+    }
+
+    /*
+    ** check if ScrollBars appear if fitToHeight is true but height is < minHeight
+    */
+    @Test public void checkIfScrollbarsWhenFitToWidthAndWidthLessMin() {
+        scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED);
+        scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED);
+
+        StackPane sp = new StackPane();
+        sp.setPrefWidth(80);
+        sp.setPrefHeight(80);
+        sp.setMinWidth(40);
+        sp.setMinHeight(40);
+
+        scrollPane.setPrefSize(50, 30);
+        scrollPane.setContent(sp);
+        scrollPane.setPannable(true);
+        scrollPane.setFitToWidth(true);
+        scrollPane.setFitToHeight(true);
+
+        Scene scene = new Scene(new Group(), 400, 400);
+        ((Group) scene.getRoot()).getChildren().clear();
+        ((Group) scene.getRoot()).getChildren().add(scrollPane);
+        Stage stage = new Stage();
+        stage.setScene(scene);
+        stage.show();
+        
+        /*
+        ** did it work?
+        */
+        assertTrue(skin.isVSBarVisible() & !skin.isHSBarVisible());
+    }
+
+    /*
+    ** check if ScrollBars appear if fitToHeight & fitToWidth are true but height is < minHeight & width is < minWidth
+    */
+    @Test public void checkIfScrollbarsWhenBothFitToAndBothLessMin() {
+        scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED);
+        scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED);
+
+        StackPane sp = new StackPane();
+        sp.setPrefWidth(80);
+        sp.setPrefHeight(80);
+        sp.setMinWidth(40);
+        sp.setMinHeight(40);
+
+        scrollPane.setPrefSize(30, 30);
+        scrollPane.setContent(sp);
+        scrollPane.setPannable(true);
+        scrollPane.setFitToWidth(true);
+        scrollPane.setFitToHeight(true);
+
+        Scene scene = new Scene(new Group(), 400, 400);
+        ((Group) scene.getRoot()).getChildren().clear();
+        ((Group) scene.getRoot()).getChildren().add(scrollPane);
+        Stage stage = new Stage();
+        stage.setScene(scene);
+        stage.show();
+        
+        /*
+        ** did it work?
+        */
+        assertTrue(skin.isVSBarVisible() & skin.isHSBarVisible());
+    }
+
     public static final class ScrollPaneSkinMock extends ScrollPaneSkin {
         boolean propertyChanged = false;
         int propertyChangeCount = 0;
@@ -429,6 +557,15 @@
             propertyChanged = true;
             propertyChangeCount++;
         }
+
+        boolean isHSBarVisible() {
+            return hsb.isVisible();
+        }
+
+        boolean isVSBarVisible() {
+            return vsb.isVisible();
+        }
+
     }
 
     private static class MouseEventGenerator {
--- a/javafx-ui-controls/test/javafx/scene/control/ChoiceBoxTest.java	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-ui-controls/test/javafx/scene/control/ChoiceBoxTest.java	Tue Jan 17 18:02:40 2012 -0500
@@ -14,8 +14,11 @@
 import static org.junit.Assert.assertTrue;
 import javafx.beans.property.ObjectProperty;
 import javafx.beans.property.SimpleObjectProperty;
+import javafx.beans.property.SimpleStringProperty;
+import javafx.beans.property.StringProperty;
 import javafx.collections.FXCollections;
 import javafx.collections.ObservableList;
+import javafx.util.StringConverter;
 
 import org.junit.Before;
 import org.junit.Ignore;
@@ -51,6 +54,9 @@
     @Test public void noArgConstructor_selectedIndexIsNegativeOne() {
         assertEquals(-1, box.getSelectionModel().getSelectedIndex());
     }
+    @Test public void noArgConstructor_converterIsNotNull() {
+        assertNull(box.getConverter());
+    }
     
     @Test public void singleArgConstructorSetsTheStyleClass() {
         final ChoiceBox<String> b2 = new ChoiceBox<String>(FXCollections.observableArrayList("Hi"));
@@ -83,6 +89,11 @@
         assertEquals(-1, b2.getSelectionModel().getSelectedIndex());
     }
     
+    @Test public void singleArgConstructor_converterIsNotNull() {
+        final ChoiceBox<String> b2 = new ChoiceBox<String>(FXCollections.observableArrayList("Hi"));
+        assertNull(b2.getConverter());
+    }
+    
     /*********************************************************************
      * Tests for selection model                                         *
      ********************************************************************/
@@ -195,6 +206,140 @@
         assertEquals(null, box.getSelectionModel().getSelectedItem());
     }
     
+    @Test public void ensureSelectionModelUpdatesValueProperty_withSelectIndex() {
+        box.getItems().addAll("Apple", "Orange", "Banana");
+        assertNull(box.getValue());
+        box.getSelectionModel().select(0);
+        assertEquals("Apple", box.getValue());
+    }
+    
+    @Test public void ensureSelectionModelUpdatesValueProperty_withSelectItem() {
+        box.getItems().addAll("Apple", "Orange", "Banana");
+        assertNull(box.getValue());
+        box.getSelectionModel().select("Apple");
+        assertEquals("Apple", box.getValue());
+    }
+    
+    @Test public void ensureSelectionModelUpdatesValueProperty_withSelectPrevious() {
+        box.getItems().addAll("Apple", "Orange", "Banana");
+        assertNull(box.getValue());
+        box.getSelectionModel().select(2);
+        box.getSelectionModel().selectPrevious();
+        assertEquals("Orange", box.getValue());
+    }
+    
+    @Test public void ensureSelectionModelUpdatesValueProperty_withSelectNext() {
+        box.getItems().addAll("Apple", "Orange", "Banana");
+        assertNull(box.getValue());
+        box.getSelectionModel().select("Orange");
+        box.getSelectionModel().selectNext();
+        assertEquals("Banana", box.getValue());
+    }
+    
+    @Test public void ensureSelectionModelUpdatesValueProperty_withSelectFirst() {
+        box.getItems().addAll("Apple", "Orange", "Banana");
+        assertNull(box.getValue());
+        box.getSelectionModel().selectFirst();
+        assertEquals("Apple", box.getValue());
+    }
+    
+    @Test public void ensureSelectionModelUpdatesValueProperty_withSelectLast() {
+        box.getItems().addAll("Apple", "Orange", "Banana");
+        assertNull(box.getValue());
+        box.getSelectionModel().selectLast();
+        assertEquals("Banana", box.getValue());
+    }
+    
+    @Test public void ensureSelectionModelClearsValueProperty() {
+        box.getItems().addAll("Apple", "Orange", "Banana");
+        assertNull(box.getValue());
+        box.getSelectionModel().select(0);
+        assertEquals("Apple", box.getValue());
+        
+        box.getSelectionModel().clearSelection();
+        assertNull(box.getValue());
+    }
+    
+    @Test public void ensureSelectionModelClearsValuePropertyWhenNegativeOneSelected() {
+        box.getItems().addAll("Apple", "Orange", "Banana");
+        assertNull(box.getValue());
+        box.getSelectionModel().select(0);
+        assertEquals("Apple", box.getValue());
+        
+        box.getSelectionModel().select(-1);
+        assertEquals(null, box.getValue());
+    }
+    
+    @Test public void ensureValueIsCorrectWhenItemsIsAddedToWithExistingSelection() {
+        box.getItems().addAll("Apple", "Orange", "Banana");
+        box.getSelectionModel().select(1);
+        box.getItems().add(0, "pineapple");
+        assertEquals(2, box.getSelectionModel().getSelectedIndex());
+        assertEquals("Orange", box.getSelectionModel().getSelectedItem());
+        assertEquals("Orange", box.getValue());
+    }
+    
+    @Test public void ensureValueIsCorrectWhenItemsAreRemovedWithExistingSelection() {
+        box.getItems().addAll("Apple", "Orange", "Banana");
+        box.getSelectionModel().select(1);
+        
+        box.getItems().remove("Apple");
+        
+        assertEquals(0, box.getSelectionModel().getSelectedIndex());
+        assertEquals("Orange", box.getSelectionModel().getSelectedItem());
+        assertEquals("Orange", box.getValue());
+    }
+    
+    @Test public void ensureValueIsUpdatedByCorrectSelectionModelWhenSelectionModelIsChanged() {
+        box.getItems().addAll("Apple", "Orange", "Banana");
+        SelectionModel sm1 = box.getSelectionModel();
+        sm1.select(1);
+        assertEquals("Orange", box.getValue());
+        SingleSelectionModel sm2 = new ChoiceBox.ChoiceBoxSelectionModel(box);
+        box.setSelectionModel(sm2);
+        
+        sm1.select(2);  // value should not change as we are using old SM
+        assertEquals("Orange", box.getValue());
+        
+        sm2.select(0);  // value should change, as we are using new SM
+        assertEquals("Apple", box.getValue());
+    }
+    
+    @Test public void ensureValueDoesNotChangeWhenBoundAndNoExceptions() {
+        box.getItems().addAll("Apple", "Orange", "Banana");
+        
+        StringProperty sp = new SimpleStringProperty("empty");
+        box.valueProperty().bind(sp);
+        
+        box.getSelectionModel().select(1);
+        assertEquals("empty", box.getValue());
+    }
+    
+    @Test public void ensureSelectionModelUpdatesWhenValueChanges() {
+        box.getItems().addAll("Apple", "Orange", "Banana");
+        assertNull(box.getSelectionModel().getSelectedItem());
+        box.setValue("Orange");
+        assertEquals("Orange", box.getSelectionModel().getSelectedItem());
+    }
+    
+    @Test public void ensureValueEqualsSelectedItemWhenNotInItemsList() {
+        box.getItems().addAll("Apple", "Orange", "Banana");
+        box.getSelectionModel().setSelectedItem("pineapple");
+        assertEquals("pineapple", box.getSelectionModel().getSelectedItem());
+        assertEquals("pineapple", box.getValue());
+    }
+    
+    @Test public void ensureSelectionModelUpdatesWhenValueChangesToNull() {
+        box.getItems().addAll("Apple", "Orange", "Banana");
+        box.setValue("pineapple");
+        assertEquals("pineapple", box.getSelectionModel().getSelectedItem());
+        assertEquals("pineapple", box.getValue());
+        box.setValue(null);
+        assertEquals(null, box.getSelectionModel().getSelectedItem());
+        assertEquals(-1, box.getSelectionModel().getSelectedIndex());
+        assertEquals(null, box.getValue());
+    }
+    
     /*********************************************************************
      * Tests for showing property                                        *
      ********************************************************************/
--- a/javafx-ui-controls/test/javafx/scene/control/ComboBoxTest.java	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-ui-controls/test/javafx/scene/control/ComboBoxTest.java	Tue Jan 17 18:02:40 2012 -0500
@@ -450,6 +450,13 @@
         assertEquals(null, comboBox.getValue());
     }
     
+    @Test public void ensureValueEqualsSelectedItemWhenNotInItemsList() {
+        comboBox.getItems().addAll("Apple", "Orange", "Banana");
+        comboBox.getSelectionModel().setSelectedItem("pineapple");
+        assertEquals("pineapple", comboBox.getSelectionModel().getSelectedItem());
+        assertEquals("pineapple", comboBox.getValue());
+    }
+    
     /*********************************************************************
      * Tests for default values                                         *
      ********************************************************************/
--- a/javafx-ui-controls/test/javafx/scene/control/KeyModifier.java	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-ui-controls/test/javafx/scene/control/KeyModifier.java	Tue Jan 17 18:02:40 2012 -0500
@@ -3,9 +3,21 @@
  */
 package javafx.scene.control;
 
+import com.sun.javafx.Utils;
+
 public enum KeyModifier {
     SHIFT,
     CTRL,
     ALT,
-    META;
+    META,
+    
+    // For Mac OS
+    CMD;
+    
+    /**
+     * Returns CMD on Mac OS, and CTRL on all other operating systems
+     */
+    public static KeyModifier getShortcutKey() {
+        return Utils.isMac() ? CMD : CTRL;
+    }
 }
--- a/javafx-ui-controls/test/javafx/scene/control/ListViewKeyInputTest.java	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-ui-controls/test/javafx/scene/control/ListViewKeyInputTest.java	Tue Jan 17 18:02:40 2012 -0500
@@ -61,7 +61,7 @@
      **************************************************************************/
     
     private String debug() {
-        StringBuilder sb = new StringBuilder("Selected Indices: ");
+        StringBuilder sb = new StringBuilder("Selected Indices: [");
         
         List<Integer> indices = sm.getSelectedIndices();
         for (Integer index : indices) {
@@ -69,7 +69,8 @@
             sb.append(", ");
         }
         
-        sb.append("\nAnchor: " + getAnchor());
+        sb.append("] \nFocus: " + fm.getFocusedIndex());
+        sb.append(" \nAnchor: " + getAnchor());
         return sb.toString();
     }
     
@@ -153,7 +154,7 @@
     // test 19
     @Test public void testCtrlDownMovesFocusButLeavesSelectionAlone() {
         assertTrue(fm.isFocused(0));
-        keyboard.doDownArrowPress(KeyModifier.CTRL);
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
         assertTrue(fm.isFocused(1));
         assertTrue(sm.isSelected(0));
         assertFalse(sm.isSelected(1));
@@ -162,7 +163,7 @@
     // test 20
     @Test public void testCtrlUpDoesNotMoveFocus() {
         assertTrue(fm.isFocused(0));
-        keyboard.doUpArrowPress(KeyModifier.CTRL);
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
         assertTrue(fm.isFocused(0));
         assertTrue(sm.isSelected(0));
     }
@@ -170,7 +171,7 @@
     // test 21
     @Test public void testCtrlLeftDoesNotMoveFocus() {
         assertTrue(fm.isFocused(0));
-        keyboard.doLeftArrowPress(KeyModifier.CTRL);
+        keyboard.doLeftArrowPress(KeyModifier.getShortcutKey());
         assertTrue(fm.isFocused(0));
         assertTrue(sm.isSelected(0));
     }
@@ -178,7 +179,7 @@
     // test 22
     @Test public void testCtrlRightDoesNotMoveFocus() {
         assertTrue(fm.isFocused(0));
-        keyboard.doRightArrowPress(KeyModifier.CTRL);
+        keyboard.doRightArrowPress(KeyModifier.getShortcutKey());
         assertTrue(fm.isFocused(0));
         assertTrue(sm.isSelected(0));
     }
@@ -188,7 +189,7 @@
         sm.clearAndSelect(1);
         assertTrue(fm.isFocused(1));
         assertTrue(sm.isSelected(1));
-        keyboard.doUpArrowPress(KeyModifier.CTRL);
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
         assertTrue(fm.isFocused(0));
         assertTrue(sm.isSelected(1));
     }
@@ -199,7 +200,7 @@
         sm.clearAndSelect(endIndex);
         assertTrue(fm.isFocused(endIndex));
         assertTrue(sm.isSelected(endIndex));
-        keyboard.doDownArrowPress(KeyModifier.CTRL);
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
         assertTrue(fm.isFocused(endIndex));
         assertTrue(sm.isSelected(endIndex));
     }
@@ -207,9 +208,9 @@
     // test 25
     @Test public void testCtrlDownArrowWithSpaceChangesAnchor() {
         sm.clearAndSelect(0);
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 1
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 2
-        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.CTRL);  // select 2
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 2
         assertTrue(isSelected(0, 2));
         assertTrue(isNotSelected(1));
         assertTrue(isAnchor(2));
@@ -218,9 +219,9 @@
     // test 26
     @Test public void testCtrlUpArrowWithSpaceChangesAnchor() {
         sm.clearAndSelect(2);
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 1
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 0
-        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.CTRL);  // select 0
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 0
         assertTrue(isSelected(0, 2));
         assertTrue(isNotSelected(1));
         assertTrue(isAnchor(0));
@@ -245,7 +246,7 @@
     // test 53
     @Test public void testCtrlHome() {
         sm.clearAndSelect(5);
-        keyboard.doKeyPress(KeyCode.HOME, KeyModifier.CTRL);
+        keyboard.doKeyPress(KeyCode.HOME, KeyModifier.getShortcutKey());
         assertTrue(isSelected(5));
         assertTrue(fm.isFocused(0));
     }
@@ -253,20 +254,19 @@
     // test 54
     @Test public void testCtrlEnd() {
         sm.clearAndSelect(5);
-        keyboard.doKeyPress(KeyCode.END, KeyModifier.CTRL);
+        keyboard.doKeyPress(KeyCode.END, KeyModifier.getShortcutKey());
         assertTrue(isSelected(5));
         assertTrue(fm.isFocused(listView.getItems().size() - 1));
     }
     
     // test 68
-    @Ignore("Bug still exists")
     @Test public void testCtrlSpaceToClearSelection() {
         sm.clearAndSelect(5);
         assertTrue(isSelected(5));
         assertTrue(fm.isFocused(5));
-        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.CTRL);
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());
         assertTrue(isNotSelected(5));
-        assertTrue(fm.isFocused(5));
+        assertTrue(debug(), fm.isFocused(5));
         assertTrue(isAnchor(5));
     }
     
@@ -384,13 +384,13 @@
     // test 27
     @Test public void testCtrlDownArrowWithSpaceChangesAnchor_extended() {
         sm.clearAndSelect(0);
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 1
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 2
-        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.CTRL);  // select 2
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 2
         
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 1
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 0
-        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.CTRL);  // deselect 0
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // deselect 0
         assertTrue(isSelected(2));
         assertTrue(isNotSelected(0, 1));
         assertTrue(isAnchor(0));
@@ -399,13 +399,13 @@
     // test 28
     @Test public void testCtrlUpArrowWithSpaceChangesAnchor_extended() {
         sm.clearAndSelect(2);
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 1
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 0
-        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.CTRL);  // select 0
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 0
         
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 1
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 2
-        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.CTRL);  // deselect 2
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // deselect 2
         assertTrue(isSelected(0));
         assertTrue(isNotSelected(1, 2));
         assertTrue(isAnchor(2));
@@ -414,13 +414,13 @@
     // test 29
     @Test public void testCtrlDownArrowWithSpaceChangesAnchor_extended2() {
         sm.clearAndSelect(0);
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 1
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 2
-        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.CTRL);  // select 2
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 2
         
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 3
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 4
-        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.CTRL);  // select 4
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 4
         assertTrue(isSelected(0, 2, 4));
         assertTrue(isNotSelected(1, 3, 5));
         assertTrue(isAnchor(4));
@@ -429,24 +429,23 @@
     // test 30
     @Test public void testCtrlUpArrowWithSpaceChangesAnchor_extended2() {
         sm.clearAndSelect(4);
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 3
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 2
-        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.CTRL);  // select 2
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 2
         
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 1
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 0
-        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.CTRL);  // select 0
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 0
         assertTrue(isSelected(0, 2, 4));
         assertTrue(isNotSelected(1, 3));
         assertTrue(isAnchor(0));
     }
     
     // test 31
-    @Ignore("Open question with Jindra")
     @Test public void testCtrlDownArrowThenShiftSpaceToSelectRange() {
         sm.clearAndSelect(0);
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 1
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 2
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);  // select 0,1,2
         assertTrue(isSelected(0, 1, 2));
         assertTrue(isNotSelected(3));
@@ -454,29 +453,28 @@
     }
     
     // test 32
-    @Ignore("Open question with Jindra")
     @Test public void testCtrlUpArrowThenShiftSpaceToSelectRange() {
         sm.clearAndSelect(2);
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 1
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 0
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);  // select 0,1,2
         assertTrue(isSelected(0, 1, 2));
         assertTrue(isNotSelected(3));
-        assertTrue(isAnchor(2));
+        assertTrue(debug(), isAnchor(2));
     }
     
     // test 33
     @Test public void testCtrlDownArrowThenSpaceToChangeSelection() {
         sm.clearAndSelect(0);
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 1
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 2
-        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.CTRL);  // select 2, keeping 0 selected
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 2, keeping 0 selected
         assertTrue(isSelected(0, 2));
         assertTrue(isNotSelected(1, 3));
         assertTrue(isAnchor(2));
         
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 3
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 4
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);  // select 2,3,4
         assertTrue(isSelected(2, 3, 4));
         assertTrue(isNotSelected(0, 1));
@@ -484,18 +482,17 @@
     }
     
     // test 34
-    @Ignore("Bug that must be fixed")
     @Test public void testCtrlUpArrowThenSpaceToChangeSelection() {
         sm.clearAndSelect(4);
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 3
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 2
-        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.CTRL);  // select 2, keeping 4 selected
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 2, keeping 4 selected
         assertTrue(isSelected(2, 4));
         assertTrue(isNotSelected(0, 1, 3));
         assertTrue(isAnchor(2));
         
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 1
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 0
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);  // select 0,1,2
         assertTrue(isSelected(0, 1, 2));
         assertTrue(isNotSelected(3, 4));
@@ -505,8 +502,8 @@
     // test 35
     @Test public void testCtrlDownTwiceThenShiftDown() {
         sm.clearAndSelect(0);
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 1
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 2
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT);  // select 0,1,2,3
         assertTrue(isSelected(0, 1, 2, 3));
     }
@@ -514,9 +511,9 @@
     // test 36
     @Test public void testCtrlUpTwiceThenShiftDown() {
         sm.clearAndSelect(3);
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 2
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 1
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 0
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
         keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT);  // select 1,2,3
         assertTrue(isSelected(1, 2, 3));
         assertTrue(isNotSelected(0));
@@ -525,9 +522,9 @@
     // test 37
     @Test public void testCtrlDownThriceThenShiftUp() {
         sm.clearAndSelect(0);
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 1
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 2
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 3
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);  // select 0,1,2
         assertTrue(isSelected(0, 1, 2));
         assertTrue(isNotSelected(3, 4));
@@ -536,8 +533,8 @@
     // test 38
     @Test public void testCtrlUpTwiceThenShiftUp() {
         sm.clearAndSelect(3);
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 2
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
         keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);  // select 0,1,2,3
         assertTrue(isSelected(0, 1, 2, 3));
         assertTrue(isNotSelected(4));
@@ -546,15 +543,15 @@
     // test 39
     @Test public void testCtrlDownTwiceThenSpace_extended() {
         sm.clearAndSelect(0);
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 1
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 2
-        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.CTRL);  // select 0,2
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 0,2
         assertTrue(isSelected(0, 2));
         assertTrue(isNotSelected(1, 3));
         assertTrue(isAnchor(2));
         
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 3
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 4
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
         keyboard.doDownArrowPress(KeyModifier.SHIFT);   // select 2,3,4,5
         assertTrue(isSelected(2, 3, 4, 5));
         assertTrue(isNotSelected(0, 1));
@@ -564,16 +561,16 @@
     // test 40
     @Test public void testCtrlUpTwiceThenSpace_extended() {
         sm.clearAndSelect(5);
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 4
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 3
-        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.CTRL);  // select 3,5
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 3,5
         assertTrue(isSelected(3,5));
         assertTrue(isNotSelected(0,1,2,4));
         assertTrue(isAnchor(3));
         
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 2
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 1
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 0
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
         keyboard.doDownArrowPress(KeyModifier.SHIFT);   // select 1,2,3
         assertTrue(isSelected(1,2,3));
         assertTrue(isNotSelected(0,4,5));
@@ -583,16 +580,16 @@
     // test 41
     @Test public void testCtrlDownTwiceThenSpace_extended2() {
         sm.clearAndSelect(0);
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 1
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 2
-        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.CTRL);  // select 0,2
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 0,2
         assertTrue(isSelected(0,2));
         assertTrue(isNotSelected(1,3,4));
         assertTrue(isAnchor(2));
         
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 3
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 4
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 5
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 5
         keyboard.doUpArrowPress(KeyModifier.SHIFT);     // select 2,3,4
         assertTrue(isSelected(2,3,4));
         assertTrue(isNotSelected(0,1,5));
@@ -600,18 +597,17 @@
     }
     
     // test 50
-    @Ignore("Test fails")
     @Test public void testCtrlDownThenShiftHome() {
         sm.clearAndSelect(0);
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 1
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 2
-        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.CTRL);  // select 0,2
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 0,2
         assertTrue(isSelected(0,2));
         assertTrue(isNotSelected(1,3,4));
         assertTrue(isAnchor(2));
         
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 3
-        keyboard.doDownArrowPress(KeyModifier.CTRL);    // move focus to 4
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT);
         assertTrue(isSelected(0,1,2));
         assertTrue(isNotSelected(3,4));
@@ -619,36 +615,35 @@
     }
     
     // test 51
-    @Ignore("Test fails")
     @Test public void testCtrlUpThenShiftEnd() {
         sm.clearAndSelect(5);
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 4
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 3
-        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.CTRL);  // select 3,5
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 3,5
         assertTrue(isSelected(3,5));
         assertTrue(isNotSelected(1,2,4));
         assertTrue(isAnchor(3));
         
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 2
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
         keyboard.doKeyPress(KeyCode.END, KeyModifier.SHIFT);
         assertTrue(isSelected(3,4,5,6,7,8,9));
         assertTrue(isNotSelected(0,1,2));
-        assertTrue(debug(),isAnchor(2));
+        assertTrue(debug(),isAnchor(3));
     }
     
     // test 42
     @Test public void testCtrlUpTwiceThenSpace_extended2() {
         sm.clearAndSelect(5);
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 4
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 3
-        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.CTRL);  // select 3,5
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 3,5
         assertTrue(isSelected(3,5));
         assertTrue(isNotSelected(0,1,2,4));
         assertTrue(isAnchor(3));
         
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 2
-        keyboard.doUpArrowPress(KeyModifier.CTRL);    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
         keyboard.doUpArrowPress(KeyModifier.SHIFT);     // select 0,1,2,3
         assertTrue(isSelected(0,1,2,3));
         assertTrue(isNotSelected(4,5));
@@ -674,13 +669,12 @@
     }
     
     // test 48
-    @Ignore("Bug still exists")
     @Test public void testShiftHome() {
         sm.clearAndSelect(3);
         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT);
         assertTrue(isSelected(0,1,2,3));
         assertTrue(isNotSelected(4,5));
-        assertTrue(isAnchor(3));
+        assertTrue(debug(), isAnchor(3));
     }
     
     // test 49
@@ -693,7 +687,6 @@
     }
     
     // test 52
-    @Ignore("Bug still exists")
     @Test public void testShiftHomeThenShiftEnd() {
         sm.clearAndSelect(5);
         keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT);
@@ -708,14 +701,14 @@
     // test 65
     @Test public void testShiftPageUp() {
         sm.clearAndSelect(0);
-        keyboard.doDownArrowPress(KeyModifier.CTRL);
-        keyboard.doDownArrowPress(KeyModifier.CTRL);
-        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.CTRL);
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());
         assertTrue(isSelected(0,2));
         assertTrue(isAnchor(2));
         
-        keyboard.doDownArrowPress(KeyModifier.CTRL);
-        keyboard.doDownArrowPress(KeyModifier.CTRL);
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
         keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT);
         assertTrue(isSelected(0,1,2));
         assertTrue(isAnchor(2));
@@ -724,7 +717,7 @@
     // test 67
     @Test public void testCtrlAToSelectAll() {
         sm.clearAndSelect(5);
-        keyboard.doKeyPress(KeyCode.A, KeyModifier.CTRL);
+        keyboard.doKeyPress(KeyCode.A, KeyModifier.getShortcutKey());
         assertTrue(isSelected(0,1,2,3,4,5,6,7,8,9));
     }
     
@@ -762,12 +755,12 @@
     
     @Test public void test_rt18642() {
         sm.clearAndSelect(1);                          // select 1
-        keyboard.doDownArrowPress(KeyModifier.CTRL);   // shift focus to 2
-        keyboard.doDownArrowPress(KeyModifier.CTRL);   // shift focus to 3
-        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.CTRL); // set anchor, and also select, 3
-        keyboard.doDownArrowPress(KeyModifier.CTRL);   // shift focus to 4
-        keyboard.doDownArrowPress(KeyModifier.CTRL);   // shift focus to 5
-        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.CTRL); // set anchor, and also select, 5
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // shift focus to 2
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // shift focus to 3
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey()); // set anchor, and also select, 3
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // shift focus to 4
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // shift focus to 5
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey()); // set anchor, and also select, 5
         
         assertTrue(isSelected(1, 3, 5));
         assertTrue(isNotSelected(0, 2, 4));
--- a/javafx-ui-controls/test/javafx/scene/control/TableViewKeyInputTest.java	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-ui-controls/test/javafx/scene/control/TableViewKeyInputTest.java	Tue Jan 17 18:02:40 2012 -0500
@@ -42,6 +42,12 @@
         fm = tableView.getFocusModel();
         
         sm.setSelectionMode(SelectionMode.MULTIPLE);
+        sm.setCellSelectionEnabled(false);
+        
+        tableView.getItems().setAll("1", "2", "3", "4", "5", "6", "7", "8", "9", "10");
+        tableView.getColumns().setAll(col1, col2, col3, col4, col5);
+        
+        sm.clearAndSelect(0);
         
         keyboard = new KeyEventFirer(tableView);
         
@@ -53,11 +59,6 @@
         
         group.getChildren().setAll(tableView);
         stage.show();
-
-        tableView.getItems().setAll("1", "2", "3", "4", "5", "6", "7", "8", "9", "10");
-        tableView.getColumns().setAll(col1, col2, col3, col4, col5);
-        
-        sm.clearAndSelect(0);
     }
     
     @After public void tearDown() {
@@ -69,7 +70,7 @@
      **************************************************************************/
     
     private String debug() {
-        StringBuilder sb = new StringBuilder("Selected Cells: ");
+        StringBuilder sb = new StringBuilder("Selected Cells: [");
         
         List<TablePosition> cells = sm.getSelectedCells();
         for (TablePosition tp : cells) {
@@ -79,6 +80,9 @@
             sb.append(tp.getColumn());
             sb.append("), ");
         }
+        
+        sb.append("] \nFocus: (" + fm.getFocusedCell().getRow() + ", " + fm.getFocusedCell().getColumn() + ")");
+        sb.append(" \nAnchor: (" + getAnchor().getRow() + ", " + getAnchor().getColumn() + ")");
         return sb.toString();
     }
     
@@ -102,6 +106,16 @@
         return TableViewAnchorRetriever.getAnchor(tableView);
     }
     
+    private boolean isAnchor(int row) {
+        TablePosition tp = new TablePosition(tableView, row, null);
+        return getAnchor() != null && getAnchor().equals(tp);
+    }
+    
+    private boolean isAnchor(int row, int col) {
+        TablePosition tp = new TablePosition(tableView, row, tableView.getColumns().get(col));
+        return getAnchor() != null && getAnchor().equals(tp);
+    }
+    
     /***************************************************************************
      * General tests
      **************************************************************************/    
@@ -124,6 +138,20 @@
         assertTrue(sm.isSelected(1));
     }
     
+    @Test public void testDownArrowDoesNotChangeSelectionWhenAtLastIndex() {
+        int endIndex = tableView.getItems().size() - 1;
+        sm.clearAndSelect(endIndex);
+        assertTrue(sm.isSelected(endIndex));
+        keyboard.doDownArrowPress();
+        assertTrue(sm.isSelected(endIndex));
+    }
+    
+    @Test public void testUpArrowDoesNotChangeSelectionWhenAt0Index() {
+        sm.clearAndSelect(0);
+        keyboard.doUpArrowPress();
+        testInitialState();
+    }
+    
     @Test public void testUpArrowChangesSelection() {
         sm.clearAndSelect(1);
         keyboard.doUpArrowPress();
@@ -141,6 +169,131 @@
         testInitialState();
     }
     
+    // test 19
+    @Test public void testCtrlDownMovesFocusButLeavesSelectionAlone() {
+        assertTrue(fm.isFocused(0));
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
+        assertTrue(fm.isFocused(1));
+        assertTrue(sm.isSelected(0));
+        assertFalse(sm.isSelected(1));
+    }
+    
+    // test 20
+    @Test public void testCtrlUpDoesNotMoveFocus() {
+        assertTrue(fm.isFocused(0));
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
+        assertTrue(fm.isFocused(0));
+        assertTrue(sm.isSelected(0));
+    }
+    
+    // test 21
+    @Test public void testCtrlLeftDoesNotMoveFocus() {
+        assertTrue(fm.isFocused(0));
+        keyboard.doLeftArrowPress(KeyModifier.getShortcutKey());
+        assertTrue(fm.isFocused(0));
+        assertTrue(sm.isSelected(0));
+    }
+    
+    // test 22
+    @Test public void testCtrlRightDoesNotMoveFocus() {
+        assertTrue(fm.isFocused(0));
+        keyboard.doRightArrowPress(KeyModifier.getShortcutKey());
+        assertTrue(fm.isFocused(0));
+        assertTrue(sm.isSelected(0));
+    }
+    
+    // test 23
+    @Test public void testCtrlUpMovesFocus() {
+        sm.clearAndSelect(1);
+        assertTrue(fm.isFocused(1));
+        assertTrue(sm.isSelected(1));
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
+        assertTrue(fm.isFocused(0));
+        assertTrue(sm.isSelected(1));
+    }
+    
+    // test 24
+    @Test public void testCtrlDownDoesNotMoveFocusWhenAtLastIndex() {
+        int endIndex = tableView.getItems().size() - 1;
+        sm.clearAndSelect(endIndex);
+        assertTrue(fm.isFocused(endIndex));
+        assertTrue(sm.isSelected(endIndex));
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
+        assertTrue(fm.isFocused(endIndex));
+        assertTrue(sm.isSelected(endIndex));
+    }
+    
+    // test 25
+    @Test public void testCtrlDownArrowWithSpaceChangesAnchor() {
+        sm.clearAndSelect(0);
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 2
+        assertTrue(isSelected(0, 2));
+        assertTrue(isNotSelected(1));
+        assertTrue(isAnchor(2));
+    }
+    
+    // test 26
+    @Test public void testCtrlUpArrowWithSpaceChangesAnchor() {
+        sm.clearAndSelect(2);
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 0
+        assertTrue(isSelected(0, 2));
+        assertTrue(isNotSelected(1));
+        assertTrue(isAnchor(0));
+    }
+    
+    // test 44
+    @Test public void testHomeKey() {
+        sm.clearAndSelect(3);
+        keyboard.doKeyPress(KeyCode.HOME);
+        assertTrue(isSelected(0));
+        assertTrue(isNotSelected(1,2,3));
+    }
+    
+    // test 45
+    @Test public void testEndKey() {
+        sm.clearAndSelect(3);
+        keyboard.doKeyPress(KeyCode.END);
+        assertTrue(isSelected(tableView.getItems().size() - 1));
+        assertTrue(isNotSelected(1,2,3));
+    }
+    
+    // test 53
+    @Test public void testCtrlHome() {
+        sm.clearAndSelect(5);
+        keyboard.doKeyPress(KeyCode.HOME, KeyModifier.getShortcutKey());
+        assertTrue(isSelected(5));
+        assertTrue(fm.isFocused(0));
+    }
+    
+    // test 54
+    @Test public void testCtrlEnd() {
+        sm.clearAndSelect(5);
+        keyboard.doKeyPress(KeyCode.END, KeyModifier.getShortcutKey());
+        assertTrue(isSelected(5));
+        assertTrue(fm.isFocused(tableView.getItems().size() - 1));
+    }
+    
+    // test 68
+    @Test public void testCtrlSpaceToClearSelection() {
+        sm.clearAndSelect(5);
+        assertTrue(isSelected(5));
+        assertTrue(fm.isFocused(5));
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());
+        assertTrue(isNotSelected(5));
+        assertTrue(debug(), fm.isFocused(5));
+        assertTrue(isAnchor(5));
+    }
+    
+    
+    
+    /***************************************************************************
+     * Tests for row-based multiple selection
+     **************************************************************************/
+    
     @Test public void testShiftDownArrowIncreasesSelection() {
         sm.clearAndSelect(0);
         keyboard.doDownArrowPress(KeyModifier.SHIFT);
@@ -148,6 +301,14 @@
         assertTrue(sm.isSelected(1));
     }
     
+    @Test public void testShiftDownArrowDoesNotChangeSelectionWhenAtLastIndex() {
+        int endIndex = tableView.getItems().size() - 1;
+        sm.clearAndSelect(endIndex);
+        assertTrue(sm.isSelected(endIndex));
+        keyboard.doDownArrowPress(KeyModifier.SHIFT);
+        assertTrue(sm.isSelected(endIndex));
+    }
+    
     @Test public void testShiftUpArrowIncreasesSelection() {
         sm.clearAndSelect(1);
         keyboard.doUpArrowPress(KeyModifier.SHIFT);
@@ -155,16 +316,435 @@
         assertTrue(sm.isSelected(1));
     }
     
-    /***************************************************************************
-     * Tests for row-based multiple selection
-     **************************************************************************/
+    @Test public void testShiftUpArrowWhenAt0Index() {
+        sm.clearAndSelect(0);
+        keyboard.doUpArrowPress(KeyModifier.SHIFT);
+        assertTrue(sm.isSelected(0));
+    }
+    
+    @Test public void testShiftLeftArrowWhenAt0Index() {
+        sm.clearAndSelect(0);
+        keyboard.doLeftArrowPress(KeyModifier.SHIFT);
+        assertTrue(sm.isSelected(0));
+        assertFalse(sm.isSelected(1));
+    }
+    
+    @Test public void testShiftRightArrowWhenAt0Index() {
+        sm.clearAndSelect(0);
+        keyboard.doRightArrowPress(KeyModifier.SHIFT);
+        assertTrue(sm.isSelected(0));
+        assertFalse(sm.isSelected(1));
+    }
+    
+    @Test public void testShiftDownTwiceThenShiftUp() {
+        sm.clearAndSelect(0);
+        keyboard.doDownArrowPress(KeyModifier.SHIFT);
+        keyboard.doDownArrowPress(KeyModifier.SHIFT);
+        keyboard.doUpArrowPress(KeyModifier.SHIFT);
+        assertTrue(debug(), sm.isSelected(0));
+        assertTrue(sm.isSelected(1));
+        assertFalse(sm.isSelected(2));
+    }
+    
+    @Test public void testShiftUpTwiceThenShiftDownFrom0Index() {
+        sm.clearAndSelect(0);
+        keyboard.doUpArrowPress(KeyModifier.SHIFT);
+        keyboard.doUpArrowPress(KeyModifier.SHIFT);
+        keyboard.doDownArrowPress(KeyModifier.SHIFT);
+        assertTrue(sm.isSelected(0));
+        assertTrue(sm.isSelected(1));
+        assertFalse(sm.isSelected(2));
+    }
+    
+    @Test public void testShiftLeftTwiceThenShiftRight() {
+        sm.clearAndSelect(0);
+        keyboard.doLeftArrowPress(KeyModifier.SHIFT);
+        keyboard.doLeftArrowPress(KeyModifier.SHIFT);
+        keyboard.doRightArrowPress(KeyModifier.SHIFT);
+        assertTrue(sm.isSelected(0));
+        assertFalse(sm.isSelected(1));
+        assertFalse(sm.isSelected(2));
+    }
+    
+    @Test public void testShiftRightTwiceThenShiftLeft() {
+        sm.clearAndSelect(0);
+        keyboard.doRightArrowPress(KeyModifier.SHIFT);
+        keyboard.doRightArrowPress(KeyModifier.SHIFT);
+        keyboard.doLeftArrowPress(KeyModifier.SHIFT);
+        assertTrue(sm.isSelected(0));
+        assertFalse(sm.isSelected(1));
+        assertFalse(sm.isSelected(2));
+    }
+    
+    @Test public void testShiftUpTwiceThenShiftDown() {
+        sm.clearAndSelect(2);                           // select 2
+        keyboard.doUpArrowPress(KeyModifier.SHIFT);     // also select 1
+        keyboard.doUpArrowPress(KeyModifier.SHIFT);     // also select 0
+        keyboard.doDownArrowPress(KeyModifier.SHIFT);   // deselect 0
+        assertFalse(debug(), sm.isSelected(0));
+        assertTrue(sm.isSelected(1));
+        assertTrue(sm.isSelected(2));
+        assertFalse(sm.isSelected(3));
+    }
+    
+    // test 18 from Jindra's testcases.rtf file
+    @Test public void testShiftDownTwiceThenShiftUpWhenAtLastIndex() {
+        int endIndex = tableView.getItems().size() - 1;
+        sm.clearAndSelect(endIndex);
+        keyboard.doDownArrowPress(KeyModifier.SHIFT);
+        keyboard.doDownArrowPress(KeyModifier.SHIFT);
+        keyboard.doUpArrowPress(KeyModifier.SHIFT);
+        assertTrue(sm.isSelected(endIndex));
+        assertTrue(sm.isSelected(endIndex - 1));
+        assertFalse(sm.isSelected(endIndex - 2));
+    }
+    
+    // test 27
+    @Test public void testCtrlDownArrowWithSpaceChangesAnchor_extended() {
+        sm.clearAndSelect(0);
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 2
+        
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // deselect 0
+        assertTrue(isSelected(2));
+        assertTrue(isNotSelected(0, 1));
+        assertTrue(isAnchor(0));
+    }
+    
+    // test 28
+    @Test public void testCtrlUpArrowWithSpaceChangesAnchor_extended() {
+        sm.clearAndSelect(2);
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 0
+        
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // deselect 2
+        assertTrue(isSelected(0));
+        assertTrue(isNotSelected(1, 2));
+        assertTrue(isAnchor(2));
+    }
+    
+    // test 29
+    @Test public void testCtrlDownArrowWithSpaceChangesAnchor_extended2() {
+        sm.clearAndSelect(0);
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 2
+        
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 4
+        assertTrue(isSelected(0, 2, 4));
+        assertTrue(isNotSelected(1, 3, 5));
+        assertTrue(isAnchor(4));
+    }
+    
+    // test 30
+    @Test public void testCtrlUpArrowWithSpaceChangesAnchor_extended2() {
+        sm.clearAndSelect(4);
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 2
+        
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 0
+        assertTrue(isSelected(0, 2, 4));
+        assertTrue(isNotSelected(1, 3));
+        assertTrue(isAnchor(0));
+    }
+    
+    // test 31
+    @Test public void testCtrlDownArrowThenShiftSpaceToSelectRange() {
+        sm.clearAndSelect(0);
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);  // select 0,1,2
+        assertTrue(isSelected(0, 1, 2));
+        assertTrue(isNotSelected(3));
+        assertTrue(isAnchor(0));
+    }
+    
+    // test 32
+    @Test public void testCtrlUpArrowThenShiftSpaceToSelectRange() {
+        sm.clearAndSelect(2);
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);  // select 0,1,2
+        assertTrue(isSelected(0, 1, 2));
+        assertTrue(isNotSelected(3));
+        assertTrue(debug(), isAnchor(2));
+    }
+    
+    // test 33
+    @Test public void testCtrlDownArrowThenSpaceToChangeSelection() {
+        sm.clearAndSelect(0);
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 2, keeping 0 selected
+        assertTrue(isSelected(0, 2));
+        assertTrue(isNotSelected(1, 3));
+        assertTrue(isAnchor(2));
+        
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);  // select 2,3,4
+        assertTrue(isSelected(2, 3, 4));
+        assertTrue(isNotSelected(0, 1));
+        assertTrue(isAnchor(2));
+    }
+    
+    // test 34
+    @Test public void testCtrlUpArrowThenSpaceToChangeSelection() {
+        sm.clearAndSelect(4);
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 2, keeping 4 selected
+        assertTrue(isSelected(2, 4));
+        assertTrue(isNotSelected(0, 1, 3));
+        assertTrue(isAnchor(2));
+        
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);  // select 0,1,2
+        assertTrue(isSelected(0, 1, 2));
+        assertTrue(isNotSelected(3, 4));
+        assertTrue(debug(), isAnchor(2));
+    }
+    
+    // test 35
+    @Test public void testCtrlDownTwiceThenShiftDown() {
+        sm.clearAndSelect(0);
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT);  // select 0,1,2,3
+        assertTrue(isSelected(0, 1, 2, 3));
+    }
+    
+    // test 36
+    @Test public void testCtrlUpTwiceThenShiftDown() {
+        sm.clearAndSelect(3);
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
+        keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT);  // select 1,2,3
+        assertTrue(isSelected(1, 2, 3));
+        assertTrue(isNotSelected(0));
+    }
+    
+    // test 37
+    @Test public void testCtrlDownThriceThenShiftUp() {
+        sm.clearAndSelect(0);
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);  // select 0,1,2
+        assertTrue(isSelected(0, 1, 2));
+        assertTrue(isNotSelected(3, 4));
+    }
+    
+    // test 38
+    @Test public void testCtrlUpTwiceThenShiftUp() {
+        sm.clearAndSelect(3);
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);  // select 0,1,2,3
+        assertTrue(isSelected(0, 1, 2, 3));
+        assertTrue(isNotSelected(4));
+    }
+    
+    // test 39
+    @Test public void testCtrlDownTwiceThenSpace_extended() {
+        sm.clearAndSelect(0);
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 0,2
+        assertTrue(isSelected(0, 2));
+        assertTrue(isNotSelected(1, 3));
+        assertTrue(isAnchor(2));
+        
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
+        keyboard.doDownArrowPress(KeyModifier.SHIFT);   // select 2,3,4,5
+        assertTrue(isSelected(2, 3, 4, 5));
+        assertTrue(isNotSelected(0, 1));
+        assertTrue(isAnchor(2));
+    }
+    
+    // test 40
+    @Test public void testCtrlUpTwiceThenSpace_extended() {
+        sm.clearAndSelect(5);
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 3,5
+        assertTrue(isSelected(3,5));
+        assertTrue(isNotSelected(0,1,2,4));
+        assertTrue(isAnchor(3));
+        
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
+        keyboard.doDownArrowPress(KeyModifier.SHIFT);   // select 1,2,3
+        assertTrue(isSelected(1,2,3));
+        assertTrue(isNotSelected(0,4,5));
+        assertTrue(isAnchor(3));
+    }
+    
+    // test 41
+    @Test public void testCtrlDownTwiceThenSpace_extended2() {
+        sm.clearAndSelect(0);
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 0,2
+        assertTrue(isSelected(0,2));
+        assertTrue(isNotSelected(1,3,4));
+        assertTrue(isAnchor(2));
+        
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 5
+        keyboard.doUpArrowPress(KeyModifier.SHIFT);     // select 2,3,4
+        assertTrue(isSelected(2,3,4));
+        assertTrue(isNotSelected(0,1,5));
+        assertTrue(isAnchor(2));
+    }
+    
+    // test 50
+    @Test public void testCtrlDownThenShiftHome() {
+        sm.clearAndSelect(0);
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 0,2
+        assertTrue(isSelected(0,2));
+        assertTrue(isNotSelected(1,3,4));
+        assertTrue(isAnchor(2));
+        
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
+        keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT);
+        assertTrue(isSelected(0,1,2));
+        assertTrue(isNotSelected(3,4));
+        assertTrue(debug(),isAnchor(2));
+    }
+    
+    // test 51
+    @Test public void testCtrlUpThenShiftEnd() {
+        sm.clearAndSelect(5);
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 3,5
+        assertTrue(isSelected(3,5));
+        assertTrue(isNotSelected(1,2,4));
+        assertTrue(isAnchor(3));
+        
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doKeyPress(KeyCode.END, KeyModifier.SHIFT);
+        assertTrue(isSelected(3,4,5,6,7,8,9));
+        assertTrue(isNotSelected(0,1,2));
+        assertTrue(debug(),isAnchor(3));
+    }
+    
+    // test 42
+    @Test public void testCtrlUpTwiceThenSpace_extended2() {
+        sm.clearAndSelect(5);
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 3,5
+        assertTrue(isSelected(3,5));
+        assertTrue(isNotSelected(0,1,2,4));
+        assertTrue(isAnchor(3));
+        
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.SHIFT);     // select 0,1,2,3
+        assertTrue(isSelected(0,1,2,3));
+        assertTrue(isNotSelected(4,5));
+        assertTrue(isAnchor(3));
+    }
+    
+    // test 46
+    @Test public void testHomeKey_withSelectedItems() {
+        sm.clearSelection();
+        sm.selectRange(4, 11);
+        keyboard.doKeyPress(KeyCode.HOME);
+        assertTrue(isSelected(0));
+        assertTrue(isNotSelected(1,2,3,4,5,6,7,8,9,10,11));
+    }
+    
+    // test 47
+    @Test public void testEndKey_withSelectedItems() {
+        sm.clearSelection();
+        sm.selectRange(4, 11);
+        keyboard.doKeyPress(KeyCode.END);
+        assertTrue(isSelected(tableView.getItems().size() - 1));
+        assertTrue(isNotSelected(1,2,3,4,5,6,7,8));
+    }
+    
+    // test 48
+    @Test public void testShiftHome() {
+        sm.clearAndSelect(3);
+        keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT);
+        assertTrue(isSelected(0,1,2,3));
+        assertTrue(isNotSelected(4,5));
+        assertTrue(debug(), isAnchor(3));
+    }
+    
+    // test 49
+    @Test public void testShiftEnd() {
+        sm.clearAndSelect(3);
+        keyboard.doKeyPress(KeyCode.END, KeyModifier.SHIFT);
+        assertTrue(isSelected(3,4,5,6,7,8,9));
+        assertTrue(isNotSelected(0,1,2));
+        assertTrue(debug(), isAnchor(3));
+    }
+    
+    // test 52
+    @Test public void testShiftHomeThenShiftEnd() {
+        sm.clearAndSelect(5);
+        keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT);
+        assertTrue(isSelected(0,1,2,3,4,5));
+        assertTrue(isAnchor(5));
+        
+        keyboard.doKeyPress(KeyCode.END, KeyModifier.SHIFT);
+        assertTrue(isSelected(5,6,7,8,9));
+        assertTrue(isAnchor(5));
+    }
+    
+    // test 65
+    @Test public void testShiftPageUp() {
+        sm.clearAndSelect(0);
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());
+        assertTrue(isSelected(0,2));
+        assertTrue(isAnchor(2));
+        
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
+        keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT);
+        assertTrue(isSelected(0,1,2));
+        assertTrue(isAnchor(2));
+    }
+    
+    // test 67
+    @Test public void testCtrlAToSelectAll() {
+        sm.clearAndSelect(5);
+        keyboard.doKeyPress(KeyCode.A, KeyModifier.getShortcutKey());
+        assertTrue(isSelected(0,1,2,3,4,5,6,7,8,9));
+    }
     
     
     /***************************************************************************
      * Tests for cell-based multiple selection
      **************************************************************************/    
     
-    @Ignore("This bug still exists")
+    @Ignore("Bug persists")
     @Test public void testSelectionPathDeviationWorks1() {
         // select horizontally, then select two items vertically, then go back
         // in opposite direction
@@ -190,7 +770,7 @@
         assertFalse(sm.isSelected(3, col3));
         
         keyboard.doUpArrowPress(KeyModifier.SHIFT);    // deselect (1, col3)
-        assertFalse(sm.isSelected(1, col3));
+        assertFalse(debug(), sm.isSelected(1, col3));
         assertFalse(sm.isSelected(2, col3));
         assertFalse(sm.isSelected(3, col3));
         
@@ -247,7 +827,6 @@
         assertTrue(sm.isSelected(1, col1));
     }
     
-    @Ignore("This bug still exists")
     @Test public void test_rt18488_comment1() {
         sm.setCellSelectionEnabled(true);
         sm.clearAndSelect(1, col1);
@@ -274,61 +853,60 @@
         assertTrue(sm.isSelected(1, col1));
     }
     
-    @Ignore("This bug still exists")
+    @Ignore("Bug persists")
     @Test public void test_rt18536_positive_horizontal() {
         // Test shift selection when focus is elsewhere (so as to select a range)
         sm.setCellSelectionEnabled(true);
         sm.clearAndSelect(1, col1);
         
         // move focus by holding down ctrl button
-        keyboard.doRightArrowPress(KeyModifier.CTRL);   // move focus to (1, col2)
-        keyboard.doRightArrowPress(KeyModifier.CTRL);   // move focus to (1, col3)
-        keyboard.doRightArrowPress(KeyModifier.CTRL);   // move focus to (1, col4)
-        keyboard.doRightArrowPress(KeyModifier.CTRL);   // move focus to (1, col5)
+        keyboard.doRightArrowPress(KeyModifier.getShortcutKey());   // move focus to (1, col2)
+        keyboard.doRightArrowPress(KeyModifier.getShortcutKey());   // move focus to (1, col3)
+        keyboard.doRightArrowPress(KeyModifier.getShortcutKey());   // move focus to (1, col4)
+        keyboard.doRightArrowPress(KeyModifier.getShortcutKey());   // move focus to (1, col5)
         assertTrue(fm.isFocused(1, col5));
         
         // press shift + space to select all cells between (1, col1) and (1, col5)
         keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);
         assertTrue(sm.isSelected(1, col5));
+        assertTrue(debug(), sm.isSelected(1, col4));
+        assertTrue(sm.isSelected(1, col3));
+        assertTrue(sm.isSelected(1, col2));
+        assertTrue(sm.isSelected(1, col1));
+    }
+    
+    @Ignore("Bug persists")
+    @Test public void test_rt18536_negative_horizontal() {
+        // Test shift selection when focus is elsewhere (so as to select a range)
+        sm.setCellSelectionEnabled(true);
+        sm.clearAndSelect(1, col5);
+        
+        // move focus by holding down ctrl button
+        keyboard.doLeftArrowPress(KeyModifier.getShortcutKey());   // move focus to (1, col4)
+        keyboard.doLeftArrowPress(KeyModifier.getShortcutKey());   // move focus to (1, col3)
+        keyboard.doLeftArrowPress(KeyModifier.getShortcutKey());   // move focus to (1, col2)
+        keyboard.doLeftArrowPress(KeyModifier.getShortcutKey());   // move focus to (1, col1)
+        assertTrue(fm.isFocused(1, col1));
+        
+        // press shift + space to select all cells between (1, col1) and (1, col5)
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);
+        assertTrue(debug(), sm.isSelected(1, col5));
         assertTrue(sm.isSelected(1, col4));
         assertTrue(sm.isSelected(1, col3));
         assertTrue(sm.isSelected(1, col2));
         assertTrue(sm.isSelected(1, col1));
     }
     
-    @Ignore("This bug still exists")
-    @Test public void test_rt18536_negative_horizontal() {
-        // Test shift selection when focus is elsewhere (so as to select a range)
-        sm.setCellSelectionEnabled(true);
-        sm.clearAndSelect(1, col5);
-        
-        // move focus by holding down ctrl button
-        keyboard.doLeftArrowPress(KeyModifier.CTRL);   // move focus to (1, col4)
-        keyboard.doLeftArrowPress(KeyModifier.CTRL);   // move focus to (1, col3)
-        keyboard.doLeftArrowPress(KeyModifier.CTRL);   // move focus to (1, col2)
-        keyboard.doLeftArrowPress(KeyModifier.CTRL);   // move focus to (1, col1)
-        assertTrue(fm.isFocused(1, col1));
-        
-        // press shift + space to select all cells between (1, col1) and (1, col5)
-        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);
-        assertTrue(sm.isSelected(1, col5));
-        assertTrue(sm.isSelected(1, col4));
-        assertTrue(sm.isSelected(1, col3));
-        assertTrue(sm.isSelected(1, col2));
-        assertTrue(sm.isSelected(1, col1));
-    }
-    
-    @Ignore("This bug still exists")
     @Test public void test_rt18536_positive_vertical() {
         // Test shift selection when focus is elsewhere (so as to select a range)
         sm.setCellSelectionEnabled(true);
         sm.clearAndSelect(1, col5);
         
         // move focus by holding down ctrl button
-        keyboard.doDownArrowPress(KeyModifier.CTRL);   // move focus to (2, col5)
-        keyboard.doDownArrowPress(KeyModifier.CTRL);   // move focus to (3, col5)
-        keyboard.doDownArrowPress(KeyModifier.CTRL);   // move focus to (4, col5)
-        keyboard.doDownArrowPress(KeyModifier.CTRL);   // move focus to (5, col5)
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // move focus to (2, col5)
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // move focus to (3, col5)
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // move focus to (4, col5)
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // move focus to (5, col5)
         assertTrue(fm.isFocused(5, col5));
         
         // press shift + space to select all cells between (1, col5) and (5, col5)
@@ -340,17 +918,16 @@
         assertTrue(sm.isSelected(5, col5));
     }
     
-    @Ignore("This bug still exists")
     @Test public void test_rt18536_negative_vertical() {
         // Test shift selection when focus is elsewhere (so as to select a range)
         sm.setCellSelectionEnabled(true);
         sm.clearAndSelect(5, col5);
         
         // move focus by holding down ctrl button
-        keyboard.doUpArrowPress(KeyModifier.CTRL);   // move focus to (4, col5)
-        keyboard.doUpArrowPress(KeyModifier.CTRL);   // move focus to (3, col5)
-        keyboard.doUpArrowPress(KeyModifier.CTRL);   // move focus to (2, col5)
-        keyboard.doUpArrowPress(KeyModifier.CTRL);   // move focus to (1, col5)
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());   // move focus to (4, col5)
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());   // move focus to (3, col5)
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());   // move focus to (2, col5)
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());   // move focus to (1, col5)
         assertTrue(fm.isFocused(1, col5));
         
         // press shift + space to select all cells between (1, col5) and (5, col5)
@@ -365,12 +942,12 @@
     @Test public void test_rt18642() {
         sm.setCellSelectionEnabled(false);
         sm.clearAndSelect(1);                          // select 1
-        keyboard.doDownArrowPress(KeyModifier.CTRL);   // shift focus to 2
-        keyboard.doDownArrowPress(KeyModifier.CTRL);   // shift focus to 3
-        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.CTRL); // set anchor, and also select, 3
-        keyboard.doDownArrowPress(KeyModifier.CTRL);   // shift focus to 4
-        keyboard.doDownArrowPress(KeyModifier.CTRL);   // shift focus to 5
-        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.CTRL); // set anchor, and also select, 5
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // shift focus to 2
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // shift focus to 3
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey()); // set anchor, and also select, 3
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // shift focus to 4
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // shift focus to 5
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey()); // set anchor, and also select, 5
         
         assertTrue(isSelected(1, 3, 5));
         assertTrue(isNotSelected(0, 2, 4));
--- a/javafx-ui-controls/test/javafx/scene/control/TreeViewKeyInputTest.java	Mon Jan 16 12:42:51 2012 +0100
+++ b/javafx-ui-controls/test/javafx/scene/control/TreeViewKeyInputTest.java	Tue Jan 17 18:02:40 2012 -0500
@@ -3,21 +3,14 @@
  */
 package javafx.scene.control;
 
-import com.sun.javafx.scene.control.behavior.ListViewAnchorRetriever;
 import com.sun.javafx.scene.control.behavior.TreeViewAnchorRetriever;
 import static org.junit.Assert.*;
 
-import javafx.scene.control.KeyEventFirer;
-import javafx.scene.control.KeyModifier;
-
-import java.util.Arrays;
 import java.util.List;
-import javafx.event.EventType;
 import javafx.scene.Group;
 import javafx.scene.Scene;
 
 import javafx.scene.input.KeyCode;
-import javafx.scene.input.KeyEvent;
 import javafx.stage.Stage;
 import org.junit.After;
 
@@ -25,7 +18,6 @@
 import org.junit.Ignore;
 import org.junit.Test;
 
-@Ignore("Not complete yet")
 public class TreeViewKeyInputTest {
     private TreeView<String> treeView;
     private MultipleSelectionModel<TreeItem<String>> sm;
@@ -37,43 +29,66 @@
     private Scene scene;
     private Group group;
     
-    private final TreeItem<String> root = new TreeItem<String>("Root");
-    private final TreeItem<String> child1 = new TreeItem<String>("Child 1");
-    private final TreeItem<String> child2 = new TreeItem<String>("Child 2");
-    private final TreeItem<String> child3 = new TreeItem<String>("Child 3");
-    private final TreeItem<String> child4 = new TreeItem<String>("Child 4");
-    private final TreeItem<String> child5 = new TreeItem<String>("Child 5");
-    private final TreeItem<String> child6 = new TreeItem<String>("Child 6");
-    private final TreeItem<String> child7 = new TreeItem<String>("Child 7");
-    private final TreeItem<String> child8 = new TreeItem<String>("Child 8");
-    private final TreeItem<String> child9 = new TreeItem<String>("Child 9");
-    private final TreeItem<String> child10 = new TreeItem<String>("Child 10");
+    private final TreeItem<String> root = new TreeItem<String>("Root");                     // 0
+        private final TreeItem<String> child1 = new TreeItem<String>("Child 1");            // 1
+        private final TreeItem<String> child2 = new TreeItem<String>("Child 2");            // 2
+        private final TreeItem<String> child3 = new TreeItem<String>("Child 3");            // 3
+            private final TreeItem<String> subchild1 = new TreeItem<String>("Subchild 1");  // 4
+            private final TreeItem<String> subchild2 = new TreeItem<String>("Subchild 2");  // 5
+            private final TreeItem<String> subchild3 = new TreeItem<String>("Subchild 3");  // 6
+        private final TreeItem<String> child4 = new TreeItem<String>("Child 4");            // 7
+        private final TreeItem<String> child5 = new TreeItem<String>("Child 5");            // 8
+        private final TreeItem<String> child6 = new TreeItem<String>("Child 6");            // 9
+        private final TreeItem<String> child7 = new TreeItem<String>("Child 7");            // 10
+        private final TreeItem<String> child8 = new TreeItem<String>("Child 8");            // 11
+        private final TreeItem<String> child9 = new TreeItem<String>("Child 9");            // 12
+        private final TreeItem<String> child10 = new TreeItem<String>("Child 10");          // 13
 
-    public TreeViewKeyInputTest() {
-        root.getChildren().setAll(child1, child2, child3, child4, child5, child6, 
-                                    child7, child8, child9, child10 );
-    }
-    
     @Before public void setup() {
+        // reset tree structure
+        root.getChildren().clear();
+        root.setExpanded(true);
+        root.getChildren().setAll(child1, child2, child3, child4, child5, child6, child7, child8, child9, child10 );
+        child1.getChildren().clear();
+        child1.setExpanded(false);
+        child2.getChildren().clear();
+        child2.setExpanded(false);
+        child3.getChildren().clear();
+        child3.setExpanded(true);
+        child3.getChildren().setAll(subchild1, subchild2, subchild3);
+        child4.getChildren().clear();
+        child4.setExpanded(false);
+        child5.getChildren().clear();
+        child5.setExpanded(false);
+        child6.getChildren().clear();
+        child6.setExpanded(false);
+        child7.getChildren().clear();
+        child7.setExpanded(false);
+        child8.getChildren().clear();
+        child8.setExpanded(false);
+        child9.getChildren().clear();
+        child9.setExpanded(false);
+        child10.getChildren().clear();
+        child10.setExpanded(false);
+        
+        // recreate treeview and gather models
         treeView = new TreeView<String>();
+        treeView.setRoot(root);
         sm = treeView.getSelectionModel();
+        sm.setSelectionMode(SelectionMode.MULTIPLE);
+        sm.clearAndSelect(0);
         fm = treeView.getFocusModel();
-        
-        sm.setSelectionMode(SelectionMode.MULTIPLE);
-        
+
+        // set up keyboard event firer
         keyboard = new KeyEventFirer(treeView);
         
+        // create a simple UI that will be shown (to send the keyboard events to)
         group = new Group();
+        group.getChildren().setAll(treeView);
         scene = new Scene(group);
-        
         stage = new Stage();
         stage.setScene(scene);
-        
-        group.getChildren().setAll(treeView);
         stage.show();
-
-        treeView.setRoot(root);
-        sm.clearAndSelect(0);
     }
     
     @After public void tearDown() {
@@ -86,13 +101,16 @@
      **************************************************************************/
     
     private String debug() {
-        StringBuilder sb = new StringBuilder("Selected Indices: ");
+        StringBuilder sb = new StringBuilder("Selected Indices: [");
         
         List<Integer> indices = sm.getSelectedIndices();
         for (Integer index : indices) {
             sb.append(index);
             sb.append(", ");
         }
+        
+        sb.append("] \nFocus: " + fm.getFocusedIndex());
+        sb.append(" \nAnchor: " + getAnchor());
         return sb.toString();
     }
     
@@ -116,12 +134,20 @@
         return TreeViewAnchorRetriever.getAnchor(treeView);
     }
     
+    private boolean isAnchor(int index) {
+        return getAnchor() == index;
+    }
+    
+    private int getItemCount() {
+        return root.getChildren().size() + child3.getChildren().size();
+    }
+    
     
     /***************************************************************************
      * General tests
      **************************************************************************/    
     
-    @Test public void testInitialState() {
+    @Ignore @Test public void testInitialState() {
         assertTrue(sm.isSelected(0));
         assertEquals(1, sm.getSelectedIndices().size());
         assertEquals(1, sm.getSelectedItems().size());
@@ -131,61 +157,836 @@
      * Tests for row-based single selection
      **************************************************************************/
     
-    @Test public void testDownArrowChangesSelection() {
+    @Ignore @Test public void testDownArrowChangesSelection() {
         sm.clearAndSelect(0);
         keyboard.doDownArrowPress();
         assertFalse(sm.isSelected(0));
         assertTrue(sm.isSelected(1));
     }
     
-    @Test public void testUpArrowChangesSelection() {
+    @Ignore @Test public void testDownArrowDoesNotChangeSelectionWhenAtLastIndex() {
+        int endIndex = getItemCount();
+        sm.clearAndSelect(endIndex);
+        assertTrue(debug(), sm.isSelected(endIndex));
+        keyboard.doDownArrowPress();
+        assertTrue(sm.isSelected(endIndex));
+    }
+    
+    @Ignore @Test public void testUpArrowDoesNotChangeSelectionWhenAt0Index() {
+        sm.clearAndSelect(0);
+        keyboard.doUpArrowPress();
+        testInitialState();
+    }
+    
+    @Ignore @Test public void testUpArrowChangesSelection() {
         sm.clearAndSelect(1);
         keyboard.doUpArrowPress();
         assertFalse(sm.isSelected(1));
         assertTrue(sm.isSelected(0));
     }
     
-    @Test public void testLeftArrowDoesNotChangeState() {
+    @Ignore @Test public void testLeftArrowDoesNotChangeState() {
         keyboard.doLeftArrowPress();
         testInitialState();
     }
     
-    @Test public void testRightArrowDoesNotChangeState() {
-        keyboard.doRightArrowPress();
-        testInitialState();
+    // test 19
+    @Ignore @Test public void testCtrlDownMovesFocusButLeavesSelectionAlone() {
+        assertTrue(fm.isFocused(0));
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
+        assertTrue(fm.isFocused(1));
+        assertTrue(sm.isSelected(0));
+        assertFalse(sm.isSelected(1));
     }
     
-    @Test public void testShiftDownArrowIncreasesSelection() {
+    // test 20
+    @Ignore @Test public void testCtrlUpDoesNotMoveFocus() {
+        assertTrue(fm.isFocused(0));
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
+        assertTrue(fm.isFocused(0));
+        assertTrue(sm.isSelected(0));
+    }
+    
+    // test 21
+    @Ignore @Test public void testCtrlLeftDoesNotMoveFocus() {
+        assertTrue(fm.isFocused(0));
+        keyboard.doLeftArrowPress(KeyModifier.getShortcutKey());
+        assertTrue(fm.isFocused(0));
+        assertTrue(sm.isSelected(0));
+    }
+    
+    // test 22
+    @Ignore @Test public void testCtrlRightDoesNotMoveFocus() {
+        assertTrue(fm.isFocused(0));
+        keyboard.doRightArrowPress(KeyModifier.getShortcutKey());
+        assertTrue(fm.isFocused(0));
+        assertTrue(sm.isSelected(0));
+    }
+    
+    // test 23
+    @Ignore @Test public void testCtrlUpMovesFocus() {
+        sm.clearAndSelect(1);
+        assertTrue(fm.isFocused(1));
+        assertTrue(sm.isSelected(1));
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());
+        assertTrue(fm.isFocused(0));
+        assertTrue(sm.isSelected(1));
+    }
+    
+    // test 24
+    @Ignore @Test public void testCtrlDownDoesNotMoveFocusWhenAtLastIndex() {
+        int endIndex = getItemCount();
+        sm.clearAndSelect(endIndex);
+        assertTrue(fm.isFocused(endIndex));
+        assertTrue(sm.isSelected(endIndex));
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
+        assertTrue(fm.isFocused(endIndex));
+        assertTrue(sm.isSelected(endIndex));
+    }
+    
+    // test 25
+    @Ignore @Test public void testCtrlDownArrowWithSpaceChangesAnchor() {
+        sm.clearAndSelect(0);
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 2
+        assertTrue(isSelected(0, 2));
+        assertTrue(isNotSelected(1));
+        assertTrue(isAnchor(2));
+    }
+    
+    // test 26
+    @Ignore @Test public void testCtrlUpArrowWithSpaceChangesAnchor() {
+        sm.clearAndSelect(2);
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 0
+        assertTrue(isSelected(0, 2));
+        assertTrue(isNotSelected(1));
+        assertTrue(isAnchor(0));
+    }
+    
+    // test 44
+    @Ignore @Test public void testHomeKey() {
+        sm.clearAndSelect(3);
+        keyboard.doKeyPress(KeyCode.HOME);
+        assertTrue(isSelected(0));
+        assertTrue(isNotSelected(1,2,3));
+    }
+    
+    // test 45
+    @Ignore @Test public void testEndKey() {
+        sm.clearAndSelect(3); 
+        keyboard.doKeyPress(KeyCode.END);
+        assertTrue(debug(), isSelected(getItemCount()));
+        assertTrue(isNotSelected(1,2,3));
+    }
+    
+    // test 53
+    @Ignore @Test public void testCtrlHome() {
+        sm.clearAndSelect(5);
+        keyboard.doKeyPress(KeyCode.HOME, KeyModifier.getShortcutKey());
+        assertTrue(isSelected(5));
+        assertTrue(fm.isFocused(0));
+    }
+    
+    // test 54
+    @Ignore @Test public void testCtrlEnd() {
+        sm.clearAndSelect(5);
+        keyboard.doKeyPress(KeyCode.END, KeyModifier.getShortcutKey());
+        assertTrue(isSelected(5));
+        assertTrue(fm.isFocused(getItemCount()));
+    }
+    
+    // test 68
+    @Ignore @Test public void testCtrlSpaceToClearSelection() {
+        sm.clearAndSelect(5);
+        assertTrue(isSelected(5));
+        assertTrue(fm.isFocused(5));
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());
+        assertTrue(isNotSelected(5));
+        assertTrue(debug(), fm.isFocused(5));
+        assertTrue(isAnchor(5));
+    }
+    
+    
+    
+    /***************************************************************************
+     * Tests for row-based multiple selection
+     **************************************************************************/
+    
+    @Ignore @Test public void testShiftDownArrowIncreasesSelection() {
         sm.clearAndSelect(0);
         keyboard.doDownArrowPress(KeyModifier.SHIFT);
         assertTrue(sm.isSelected(0));
         assertTrue(sm.isSelected(1));
     }
     
-    @Test public void testShiftUpArrowIncreasesSelection() {
+    @Ignore @Test public void testShiftDownArrowDoesNotChangeSelectionWhenAtLastIndex() {
+        int endIndex = getItemCount() - 1;
+        sm.clearAndSelect(endIndex);
+        assertTrue(sm.isSelected(endIndex));
+        keyboard.doDownArrowPress(KeyModifier.SHIFT);
+        assertTrue(sm.isSelected(endIndex));
+    }
+    
+    @Ignore @Test public void testShiftUpArrowIncreasesSelection() {
         sm.clearAndSelect(1);
         keyboard.doUpArrowPress(KeyModifier.SHIFT);
         assertTrue(sm.isSelected(0));
         assertTrue(sm.isSelected(1));
     }
     
+    @Ignore @Test public void testShiftUpArrowWhenAt0Index() {
+        sm.clearAndSelect(0);
+        keyboard.doUpArrowPress(KeyModifier.SHIFT);
+        assertTrue(sm.isSelected(0));
+    }
+    
+    @Ignore @Test public void testShiftLeftArrowWhenAt0Index() {
+        sm.clearAndSelect(0);
+        keyboard.doLeftArrowPress(KeyModifier.SHIFT);
+        assertTrue(sm.isSelected(0));
+        assertFalse(sm.isSelected(1));
+    }
+    
+    @Ignore @Test public void testShiftRightArrowWhenAt0Index() {
+        sm.clearAndSelect(0);
+        keyboard.doRightArrowPress(KeyModifier.SHIFT);
+        assertTrue(sm.isSelected(0));
+        assertFalse(sm.isSelected(1));
+    }
+    
+    @Ignore @Test public void testShiftDownTwiceThenShiftUp() {
+        sm.clearAndSelect(0);
+        keyboard.doDownArrowPress(KeyModifier.SHIFT);
+        keyboard.doDownArrowPress(KeyModifier.SHIFT);
+        keyboard.doUpArrowPress(KeyModifier.SHIFT);
+        assertTrue(debug(), sm.isSelected(0));
+        assertTrue(sm.isSelected(1));
+        assertFalse(sm.isSelected(2));
+    }
+    
+    @Ignore @Test public void testShiftUpTwiceThenShiftDownFrom0Index() {
+        sm.clearAndSelect(0);
+        keyboard.doUpArrowPress(KeyModifier.SHIFT);
+        keyboard.doUpArrowPress(KeyModifier.SHIFT);
+        keyboard.doDownArrowPress(KeyModifier.SHIFT);
+        assertTrue(sm.isSelected(0));
+        assertTrue(sm.isSelected(1));
+        assertFalse(sm.isSelected(2));
+    }
+    
+    @Ignore @Test public void testShiftLeftTwiceThenShiftRight() {
+        sm.clearAndSelect(0);
+        keyboard.doLeftArrowPress(KeyModifier.SHIFT);
+        keyboard.doLeftArrowPress(KeyModifier.SHIFT);
+        keyboard.doRightArrowPress(KeyModifier.SHIFT);
+        assertTrue(sm.isSelected(0));
+        assertFalse(sm.isSelected(1));
+        assertFalse(sm.isSelected(2));
+    }
+    
+    @Ignore @Test public void testShiftRightTwiceThenShiftLeft() {
+        sm.clearAndSelect(0);
+        keyboard.doRightArrowPress(KeyModifier.SHIFT);
+        keyboard.doRightArrowPress(KeyModifier.SHIFT);
+        keyboard.doLeftArrowPress(KeyModifier.SHIFT);
+        assertTrue(sm.isSelected(0));
+        assertFalse(sm.isSelected(1));
+        assertFalse(sm.isSelected(2));
+    }
+    
+    @Ignore @Test public void testShiftUpTwiceThenShiftDown() {
+        sm.clearAndSelect(2);
+        keyboard.doUpArrowPress(KeyModifier.SHIFT);
+        keyboard.doUpArrowPress(KeyModifier.SHIFT);
+        keyboard.doDownArrowPress(KeyModifier.SHIFT);
+        assertFalse(sm.isSelected(0));
+        assertTrue(sm.isSelected(1));
+        assertTrue(sm.isSelected(2));
+        assertFalse(sm.isSelected(3));
+    }
+    
+    // test 18 from Jindra's testcases.rtf file
+    @Ignore @Test public void testShiftDownTwiceThenShiftUpWhenAtLastIndex() {
+        int endIndex = getItemCount();
+        sm.clearAndSelect(endIndex);
+        keyboard.doDownArrowPress(KeyModifier.SHIFT);
+        keyboard.doDownArrowPress(KeyModifier.SHIFT);
+        keyboard.doUpArrowPress(KeyModifier.SHIFT);
+        assertTrue(sm.isSelected(endIndex));
+        assertTrue(sm.isSelected(endIndex - 1));
+        assertFalse(sm.isSelected(endIndex - 2));
+    }
+    
+    // test 27
+    @Ignore @Test public void testCtrlDownArrowWithSpaceChangesAnchor_extended() {
+        sm.clearAndSelect(0);
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 2
+        
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // deselect 0
+        assertTrue(isSelected(2));
+        assertTrue(isNotSelected(0, 1));
+        assertTrue(isAnchor(0));
+    }
+    
+    // test 28
+    @Ignore @Test public void testCtrlUpArrowWithSpaceChangesAnchor_extended() {
+        sm.clearAndSelect(2);
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 0
+        
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // deselect 2
+        assertTrue(isSelected(0));
+        assertTrue(isNotSelected(1, 2));
+        assertTrue(isAnchor(2));
+    }
+    
+    // test 29
+    @Ignore @Test public void testCtrlDownArrowWithSpaceChangesAnchor_extended2() {
+        sm.clearAndSelect(0);
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 2
+        
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 4
+        assertTrue(isSelected(0, 2, 4));
+        assertTrue(isNotSelected(1, 3, 5));
+        assertTrue(isAnchor(4));
+    }
+    
+    // test 30
+    @Ignore @Test public void testCtrlUpArrowWithSpaceChangesAnchor_extended2() {
+        sm.clearAndSelect(4);
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 2
+        
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 0
+        assertTrue(isSelected(0, 2, 4));
+        assertTrue(isNotSelected(1, 3));
+        assertTrue(isAnchor(0));
+    }
+    
+    // test 31
+    @Ignore @Test public void testCtrlDownArrowThenShiftSpaceToSelectRange() {
+        sm.clearAndSelect(0);
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);  // select 0,1,2
+        assertTrue(isSelected(0, 1, 2));
+        assertTrue(isNotSelected(3));
+        assertTrue(isAnchor(0));
+    }
+    
+    // test 32
+    @Ignore @Test public void testCtrlUpArrowThenShiftSpaceToSelectRange() {
+        sm.clearAndSelect(2);
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);  // select 0,1,2
+        assertTrue(isSelected(0, 1, 2));
+        assertTrue(isNotSelected(3));
+        assertTrue(debug(), isAnchor(2));
+    }
+    
+    // test 33
+    @Ignore @Test public void testCtrlDownArrowThenSpaceToChangeSelection() {
+        sm.clearAndSelect(0);
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 2, keeping 0 selected
+        assertTrue(isSelected(0, 2));
+        assertTrue(isNotSelected(1, 3));
+        assertTrue(isAnchor(2));
+        
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);  // select 2,3,4
+        assertTrue(isSelected(2, 3, 4));
+        assertTrue(isNotSelected(0, 1));
+        assertTrue(isAnchor(2));
+    }
+    
+    // test 34
+    @Ignore @Test public void testCtrlUpArrowThenSpaceToChangeSelection() {
+        sm.clearAndSelect(4);
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 2, keeping 4 selected
+        assertTrue(isSelected(2, 4));
+        assertTrue(isNotSelected(0, 1, 3));
+        assertTrue(isAnchor(2));
+        
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.SHIFT);  // select 0,1,2
+        assertTrue(isSelected(0, 1, 2));
+        assertTrue(isNotSelected(3, 4));
+        assertTrue(debug(), isAnchor(2));
+    }
+    
+    // test 35
+    @Ignore @Test public void testCtrlDownTwiceThenShiftDown() {
+        sm.clearAndSelect(0);
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT);  // select 0,1,2,3
+        assertTrue(isSelected(0, 1, 2, 3));
+    }
+    
+    // test 36
+    @Ignore @Test public void testCtrlUpTwiceThenShiftDown() {
+        sm.clearAndSelect(3);
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
+        keyboard.doKeyPress(KeyCode.DOWN, KeyModifier.SHIFT);  // select 1,2,3
+        assertTrue(isSelected(1, 2, 3));
+        assertTrue(isNotSelected(0));
+    }
+    
+    // test 37
+    @Ignore @Test public void testCtrlDownThriceThenShiftUp() {
+        sm.clearAndSelect(0);
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);  // select 0,1,2
+        assertTrue(isSelected(0, 1, 2));
+        assertTrue(isNotSelected(3, 4));
+    }
+    
+    // test 38
+    @Ignore @Test public void testCtrlUpTwiceThenShiftUp() {
+        sm.clearAndSelect(3);
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doKeyPress(KeyCode.UP, KeyModifier.SHIFT);  // select 0,1,2,3
+        assertTrue(isSelected(0, 1, 2, 3));
+        assertTrue(isNotSelected(4));
+    }
+    
+    // test 39
+    @Ignore @Test public void testCtrlDownTwiceThenSpace_extended() {
+        sm.clearAndSelect(0);
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 0,2
+        assertTrue(isSelected(0, 2));
+        assertTrue(isNotSelected(1, 3));
+        assertTrue(isAnchor(2));
+        
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
+        keyboard.doDownArrowPress(KeyModifier.SHIFT);   // select 2,3,4,5
+        assertTrue(isSelected(2, 3, 4, 5));
+        assertTrue(isNotSelected(0, 1));
+        assertTrue(isAnchor(2));
+    }
+    
+    // test 40
+    @Ignore @Test public void testCtrlUpTwiceThenSpace_extended() {
+        sm.clearAndSelect(5);
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 3,5
+        assertTrue(isSelected(3,5));
+        assertTrue(isNotSelected(0,1,2,4));
+        assertTrue(isAnchor(3));
+        
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 0
+        keyboard.doDownArrowPress(KeyModifier.SHIFT);   // select 1,2,3
+        assertTrue(isSelected(1,2,3));
+        assertTrue(isNotSelected(0,4,5));
+        assertTrue(isAnchor(3));
+    }
+    
+    // test 41
+    @Ignore @Test public void testCtrlDownTwiceThenSpace_extended2() {
+        sm.clearAndSelect(0);
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 0,2
+        assertTrue(isSelected(0,2));
+        assertTrue(isNotSelected(1,3,4));
+        assertTrue(isAnchor(2));
+        
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 5
+        keyboard.doUpArrowPress(KeyModifier.SHIFT);     // select 2,3,4
+        assertTrue(isSelected(2,3,4));
+        assertTrue(isNotSelected(0,1,5));
+        assertTrue(isAnchor(2));
+    }
+    
+    // test 50
+    @Ignore @Test public void testCtrlDownThenShiftHome() {
+        sm.clearAndSelect(0);
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 0,2
+        assertTrue(isSelected(0,2));
+        assertTrue(isNotSelected(1,3,4));
+        assertTrue(isAnchor(2));
+        
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
+        keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT);
+        assertTrue(isSelected(0,1,2));
+        assertTrue(isNotSelected(3,4));
+        assertTrue(debug(),isAnchor(2));
+    }
+    
+    // test 51
+    @Ignore @Test public void testCtrlUpThenShiftEnd() {
+        sm.clearAndSelect(5);
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 3,5
+        assertTrue(isSelected(3,5));
+        assertTrue(isNotSelected(1,2,4));
+        assertTrue(isAnchor(3));
+        
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doKeyPress(KeyCode.END, KeyModifier.SHIFT);
+        assertTrue(isSelected(3,4,5,6,7,8,9));
+        assertTrue(isNotSelected(0,1,2));
+        assertTrue(debug(),isAnchor(3));
+    }
+    
+    // test 42
+    @Ignore @Test public void testCtrlUpTwiceThenSpace_extended2() {
+        sm.clearAndSelect(5);
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 4
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 3
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());  // select 3,5
+        assertTrue(isSelected(3,5));
+        assertTrue(isNotSelected(0,1,2,4));
+        assertTrue(isAnchor(3));
+        
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 2
+        keyboard.doUpArrowPress(KeyModifier.getShortcutKey());    // move focus to 1
+        keyboard.doUpArrowPress(KeyModifier.SHIFT);     // select 0,1,2,3
+        assertTrue(isSelected(0,1,2,3));
+        assertTrue(isNotSelected(4,5));
+        assertTrue(isAnchor(3));
+    }
+    
+    // test 46
+    @Ignore @Test public void testHomeKey_withSelectedItems() {
+        sm.clearSelection();
+        sm.selectRange(4, 11);
+        keyboard.doKeyPress(KeyCode.HOME);
+        assertTrue(isSelected(0));
+        assertTrue(isNotSelected(1,2,3,4,5,6,7,8,9,10,11));
+    }
+    
+    // test 47
+    @Ignore @Test public void testEndKey_withSelectedItems() {
+        sm.clearSelection();
+        sm.selectRange(4, 11);
+        keyboard.doKeyPress(KeyCode.END);
+        assertTrue(isSelected(getItemCount()));
+        assertTrue(isNotSelected(1,2,3,4,5,6,7,8));
+    }
+    
+    // test 48
+    @Ignore @Test public void testShiftHome() {
+        sm.clearAndSelect(3);
+        keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT);
+        assertTrue(isSelected(0,1,2,3));
+        assertTrue(isNotSelected(4,5));
+        assertTrue(debug(), isAnchor(3));
+    }
+    
+    // test 49
+    @Ignore @Test public void testShiftEnd() {
+        sm.clearAndSelect(3);
+        keyboard.doKeyPress(KeyCode.END, KeyModifier.SHIFT);
+        assertTrue(isSelected(3,4,5,6,7,8,9));
+        assertTrue(isNotSelected(0,1,2));
+        assertTrue(isAnchor(3));
+    }
+    
+    // test 52
+    @Ignore @Test public void testShiftHomeThenShiftEnd() {
+        sm.clearAndSelect(5);
+        keyboard.doKeyPress(KeyCode.HOME, KeyModifier.SHIFT);
+        assertTrue(isSelected(0,1,2,3,4,5));
+        assertTrue(isAnchor(5));
+        
+        keyboard.doKeyPress(KeyCode.END, KeyModifier.SHIFT);
+        assertTrue(isSelected(5,6,7,8,9));
+        assertTrue(isAnchor(5));
+    }
+    
+    // test 65
+    @Ignore @Test public void testShiftPageUp() {
+        sm.clearAndSelect(0);
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey());
+        assertTrue(isSelected(0,2));
+        assertTrue(isAnchor(2));
+        
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());
+        keyboard.doKeyPress(KeyCode.PAGE_UP, KeyModifier.SHIFT);
+        assertTrue(isSelected(0,1,2));
+        assertTrue(isAnchor(2));
+    }
+    
+    // test 67
+    @Ignore @Test public void testCtrlAToSelectAll() {
+        sm.clearAndSelect(5);
+        keyboard.doKeyPress(KeyCode.A, KeyModifier.getShortcutKey());
+        assertTrue(isSelected(0,1,2,3,4,5,6,7,8,9));
+    }
+    
+    
     /***************************************************************************
-     * Tests for row-based multiple selection
+     * Tests for editing
      **************************************************************************/
     
+    // test 43 (part 1)
+    @Ignore @Test public void testF2EntersEditModeAndEscapeCancelsEdit_part1() {
+        treeView.setEditable(true);
+        
+        sm.clearAndSelect(0);
+        assertNull(treeView.getEditingItem());
+        keyboard.doKeyPress(KeyCode.F2);
+        assertEquals(root, treeView.getEditingItem());
+        
+        keyboard.doKeyPress(KeyCode.ESCAPE);
+        assertNull(treeView.getEditingItem());
+    }
+    
+//    // test 43 (part 2)
+//    @Ignore @Test public void testF2EntersEditModeAndEscapeCancelsEdit_part2() {
+//        treeView.setEditable(true);
+//        
+//        sm.clearAndSelect(0);
+//        keyboard.doKeyPress(KeyCode.F2);
+//        
+//        
+//    }
+    
+    
+    /***************************************************************************
+     * Tests for TreeView-specific functionality
+     **************************************************************************/ 
+    
+    // Test 1 (TreeView test cases)
+    @Ignore @Test public void testRightArrowExpandsBranch() {
+        sm.clearAndSelect(0);
+        root.setExpanded(false);
+        assertFalse(root.isExpanded());
+        keyboard.doRightArrowPress();
+        assertTrue(root.isExpanded());
+    }
+    
+    // Test 2 (TreeView test cases)
+    @Ignore @Test public void testRightArrowOnExpandedBranch() {
+        sm.clearAndSelect(0);
+        keyboard.doRightArrowPress();
+        assertTrue(isNotSelected(0));
+        assertTrue(isSelected(1));
+    }
+    
+    // Test 3 (TreeView test cases)
+    @Ignore @Test public void testRightArrowOnLeafNode() {
+        sm.clearAndSelect(1);
+        keyboard.doRightArrowPress();
+        assertTrue(isNotSelected(0));
+        assertTrue(isSelected(1));
+        assertTrue(isNotSelected(2));
+    }
+    
+    // Test 4 (TreeView test cases)
+    @Ignore @Test public void testLeftArrowCollapsesBranch() {
+        sm.clearAndSelect(0);
+        assertTrue(root.isExpanded());
+        keyboard.doLeftArrowPress();
+        assertFalse(root.isExpanded());
+    }
+    
+    // Test 5 (TreeView test cases)
+    @Ignore @Test public void testLeftArrowOnLeafMovesSelectionToParent() {
+        sm.clearAndSelect(2);
+        assertTrue(root.isExpanded());
+        keyboard.doLeftArrowPress();
+        assertTrue(root.isExpanded());
+        assertTrue(isSelected(0));
+        assertTrue(isNotSelected(2));
+    }
+    
+    // Test 6 (TreeView test cases)
+    @Ignore @Test public void testLeftArrowMultipleTimes() {
+        sm.clearAndSelect(5);
+        keyboard.doLeftArrowPress();
+        assertTrue(child3.isExpanded());
+        assertTrue(isSelected(3));
+        assertTrue(isNotSelected(5));
+        
+        keyboard.doLeftArrowPress();
+        assertFalse(child3.isExpanded());
+        assertTrue(isSelected(3));
+        
+        keyboard.doLeftArrowPress();
+        assertTrue(isSelected(0));
+        assertTrue(root.isExpanded());
+        
+        keyboard.doLeftArrowPress();
+        assertTrue(isSelected(0));
+        assertFalse(root.isExpanded());
+    }
+    
+    // Test 7 (TreeView test cases)
+    @Ignore @Test public void testDownArrowTwice() {
+        sm.clearAndSelect(0);
+        keyboard.doDownArrowPress();
+        keyboard.doDownArrowPress();
+        assertTrue(isSelected(2));
+        assertTrue(isNotSelected(0));
+    }
+    
+    // Test 8 (TreeView test cases)
+    @Ignore @Test public void testDownArrowFourTimes() {
+        // adding children to child2, but not expanding it
+        child2.getChildren().addAll(new TreeItem("another child"), new TreeItem("And another!"));
+        child2.setExpanded(false);
+        
+        child3.setExpanded(true);
+        sm.clearAndSelect(0);
+        keyboard.doDownArrowPress();
+        keyboard.doDownArrowPress();
+        keyboard.doDownArrowPress();
+        keyboard.doDownArrowPress();
+        assertTrue(isSelected(4));
+        assertTrue(isNotSelected(0));
+    }
+    
+    // Test 9 (TreeView test cases)
+    @Ignore @Test public void testUpArrow() {
+        sm.clearAndSelect(1);
+        keyboard.doUpArrowPress();
+        assertTrue(isSelected(0));
+        assertTrue(isNotSelected(1));
+    }
+    
+    // Test 9 (TreeView test cases)
+    @Ignore @Test public void testUpArrowFourTimes() {
+        // adding children to child2, but not expanding it
+        child2.getChildren().addAll(new TreeItem("another child"), new TreeItem("And another!"));
+        child2.setExpanded(false);
+        
+        sm.clearAndSelect(5);
+        keyboard.doUpArrowPress();
+        keyboard.doUpArrowPress();
+        keyboard.doUpArrowPress();
+        keyboard.doUpArrowPress();
+        
+        assertTrue(isSelected(1));
+        assertTrue(isNotSelected(5));
+    }
+    
+    // Test 20 (TreeView test cases)
+    @Ignore @Test public void testCtrlForwardSlashToSelectAll() {
+        sm.clearAndSelect(1);
+        keyboard.doKeyPress(KeyCode.SLASH, KeyModifier.getShortcutKey());
+        assertTrue(isSelected(0,1,2,3,4,5,6,7,8,9));
+    }
+    
+    // Test 21 (TreeView test cases)
+    @Ignore("Not yet working")
+    @Test public void testCtrlBackSlashToClearSelection() {
+        sm.selectAll();
+        fm.focus(1);
+        keyboard.doKeyPress(KeyCode.BACK_SLASH, KeyModifier.getShortcutKey());
+        assertTrue(isNotSelected(0,1,2,3,4,5,6,7,8,9));
+        assertTrue(fm.isFocused(1));
+    }
+    
+    // Test 24 (TreeView test cases)
+    @Ignore("Not yet working")
+    @Test public void testExpandCollapseImpactOnSelection() {
+        sm.clearAndSelect(5);
+        assertTrue(child3.isExpanded());
+        keyboard.doUpArrowPress(KeyModifier.SHIFT);
+        keyboard.doUpArrowPress(KeyModifier.SHIFT);
+        assertTrue(isSelected(3,4,5));
+        
+        keyboard.doLeftArrowPress();
+        assertFalse(child3.isExpanded());
+        assertTrue(isSelected(3));
+        
+        keyboard.doRightArrowPress();
+        assertTrue(child3.isExpanded());
+        assertTrue(isSelected(3,4,5));
+    }
+    
+    // Test 54 (TreeView test cases)
+    @Ignore @Test public void testAsteriskExpandsAllBranchesFromRoot() {
+        // adding children to child2, but not expanding it
+        child2.getChildren().addAll(new TreeItem("another child"), new TreeItem("And another!"));
+        child2.setExpanded(false);
+        
+        sm.clearAndSelect(0);
+        assertFalse(child2.isExpanded());
+        assertTrue(child3.isExpanded());
+        keyboard.doKeyPress(KeyCode.MULTIPLY);
+        
+        assertTrue(child2.isExpanded());
+        assertTrue(child3.isExpanded());
+    }
+    
+    // Test 57 (TreeView test cases)
+    @Ignore @Test public void testMinusCollapsesBranch() {
+        sm.clearAndSelect(3);
+        assertTrue(child3.isExpanded());
+        keyboard.doKeyPress(KeyCode.SUBTRACT);
+        assertFalse(child3.isExpanded());
+    }
+    
+    // Test 58 (TreeView test cases)
+    @Ignore @Test public void testPlusCollapsesBranch() {
+        sm.clearAndSelect(3);
+        child3.setExpanded(false);
+        assertFalse(child3.isExpanded());
+        keyboard.doKeyPress(KeyCode.ADD);
+        assertTrue(child3.isExpanded());
+    }
+    
     
     /***************************************************************************
      * Tests for specific bug reports
      **************************************************************************/
     
-    @Test public void test_rt18642() {
+    @Ignore @Test public void test_rt18642() {
         sm.clearAndSelect(1);                          // select 1
-        keyboard.doDownArrowPress(KeyModifier.CTRL);   // shift focus to 2
-        keyboard.doDownArrowPress(KeyModifier.CTRL);   // shift focus to 3
-        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.CTRL); // set anchor, and also select, 3
-        keyboard.doDownArrowPress(KeyModifier.CTRL);   // shift focus to 4
-        keyboard.doDownArrowPress(KeyModifier.CTRL);   // shift focus to 5
-        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.CTRL); // set anchor, and also select, 5
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // shift focus to 2
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // shift focus to 3
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey()); // set anchor, and also select, 3
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // shift focus to 4
+        keyboard.doDownArrowPress(KeyModifier.getShortcutKey());   // shift focus to 5
+        keyboard.doKeyPress(KeyCode.SPACE, KeyModifier.getShortcutKey()); // set anchor, and also select, 5
         
         assertTrue(isSelected(1, 3, 5));
         assertTrue(isNotSelected(0, 2, 4));