ModelListener.js supports simple, optional AutoComplete
diff --git a/bundles/org.eclipse.rap.addons.dropdown.viewer/src/org/eclipse/rap/addons/dropdown/viewer/DropDownViewer.java b/bundles/org.eclipse.rap.addons.dropdown.viewer/src/org/eclipse/rap/addons/dropdown/viewer/DropDownViewer.java
index 8a93c52..75f677b 100644
--- a/bundles/org.eclipse.rap.addons.dropdown.viewer/src/org/eclipse/rap/addons/dropdown/viewer/DropDownViewer.java
+++ b/bundles/org.eclipse.rap.addons.dropdown.viewer/src/org/eclipse/rap/addons/dropdown/viewer/DropDownViewer.java
@@ -100,6 +100,13 @@
     model.addListener( SELECTION_CHANGED, modelSelectionListener );
   }
 
+  /**
+   * experimental
+   */
+  public void setAutoComplete( boolean value ) {
+    model.set( "autoComplete", value );
+  }
+
   @Override
   protected void inputChanged( Object input, Object oldInput ) {
     updateElements();
@@ -169,7 +176,7 @@
       dropDown.addListener( SWT.DefaultSelection, getClientListener( "DataBinding.js" ) );
       model.addListener( "change", getModelListener( "DataBinding.js" ) );
       model.addListener( "change", getModelListener( "ModelListener.js" ) );
-      model.addListener( "acceptSuggestion", getModelListener( "ModelListener.js" ) );
+      model.addListener( "accept", getModelListener( "ModelListener.js" ) );
     } else {
       text.addListener( ClientListener.Modify, getTextModifyListener() );
       text.addListener( ClientListener.Verify, getTextVerifyListener() );
diff --git a/bundles/org.eclipse.rap.addons.dropdown.viewer/src/org/eclipse/rap/addons/dropdown/viewer/internal/resources/DataBinding.js b/bundles/org.eclipse.rap.addons.dropdown.viewer/src/org/eclipse/rap/addons/dropdown/viewer/internal/resources/DataBinding.js
index ba9bd02..1f76d3b 100644
--- a/bundles/org.eclipse.rap.addons.dropdown.viewer/src/org/eclipse/rap/addons/dropdown/viewer/internal/resources/DataBinding.js
+++ b/bundles/org.eclipse.rap.addons.dropdown.viewer/src/org/eclipse/rap/addons/dropdown/viewer/internal/resources/DataBinding.js
@@ -90,7 +90,7 @@
 }
 
 function onDropDownDefaultSelection( model ) {
-  model.notify( "acceptSuggestion" );
+  model.notify( "accept" );
 }
 
 function onModelChangeResults( dropDown, results ) {
diff --git a/bundles/org.eclipse.rap.addons.dropdown.viewer/src/org/eclipse/rap/addons/dropdown/viewer/internal/resources/ModelListener.js b/bundles/org.eclipse.rap.addons.dropdown.viewer/src/org/eclipse/rap/addons/dropdown/viewer/internal/resources/ModelListener.js
index a044262..e233f1a 100644
--- a/bundles/org.eclipse.rap.addons.dropdown.viewer/src/org/eclipse/rap/addons/dropdown/viewer/internal/resources/ModelListener.js
+++ b/bundles/org.eclipse.rap.addons.dropdown.viewer/src/org/eclipse/rap/addons/dropdown/viewer/internal/resources/ModelListener.js
@@ -13,16 +13,19 @@
 // Event Delegation
 
 function handleEvent( model, type, event ) {
-  if( type === "acceptSuggestion" ) {
+  if( type === "accept" ) {
     onAcceptSuggestion.apply( model, [ event ] );
   } else {
     switch( event.property ) {
       case "userText":
-        onChangeText.apply( model, [ event ] );
+        onChangeUserText.apply( model, [ event ] );
       break;
       case "resultSelection":
         onChangeResultSelection.apply( model, [ event ] );
       break;
+      case "results":
+        onChangeResults.apply( model, [ event ] );
+      break;
     }
   }
 }
@@ -30,12 +33,21 @@
 //////////////////
 // Event Handling
 
-function onChangeText( options ) {
+function onChangeUserText( options ) {
   var query = createQuery( options.value.toLowerCase() );
   var results = searchItems( this.get( "elements" ), query );
   this.set( "results", results );
 }
 
+function onChangeResults( options ) {
+  if( this.get( "autoComplete" ) ) {
+    var items = this.get( "results" ).items;
+    if( items.length === 1 ) {
+      this.set( "text", items[ 0 ] );
+    }
+  }
+}
+
 function onChangeResultSelection( options ) {
   var text = this.get( "results" ).items[ options.value ] || "";
   this.set( "text", text, { "resultSelection" : true } );
diff --git a/bundles/org.eclipse.rap.addons.dropdown/src/org/eclipse/rap/addons/dropdown/internal/Model.java b/bundles/org.eclipse.rap.addons.dropdown/src/org/eclipse/rap/addons/dropdown/internal/Model.java
index 8cfe19b..c8cc48f 100644
--- a/bundles/org.eclipse.rap.addons.dropdown/src/org/eclipse/rap/addons/dropdown/internal/Model.java
+++ b/bundles/org.eclipse.rap.addons.dropdown/src/org/eclipse/rap/addons/dropdown/internal/Model.java
@@ -44,6 +44,10 @@
     remoteObject.set( name, value );
   }
 
+  public void set( String name, boolean value ) {
+    remoteObject.set( name, value );
+  }
+
   public void set( String name, JsonValue value ) {
     remoteObject.set( name, value );
   }
diff --git a/examples/org.eclipse.rap.addons.dropdown.demo/src/org/eclipse/rap/addons/dropdown/demo/DropDownDemo.java b/examples/org.eclipse.rap.addons.dropdown.demo/src/org/eclipse/rap/addons/dropdown/demo/DropDownDemo.java
index a51de71..a53b190 100644
--- a/examples/org.eclipse.rap.addons.dropdown.demo/src/org/eclipse/rap/addons/dropdown/demo/DropDownDemo.java
+++ b/examples/org.eclipse.rap.addons.dropdown.demo/src/org/eclipse/rap/addons/dropdown/demo/DropDownDemo.java
@@ -124,10 +124,11 @@
   private void createKFZExample( Composite parent ) {
     Group group = new Group( parent, SWT.NONE );
     group.setText( "DropDownViewer + server-side expand button, dynamic input (586 entries max)" );
-    group.setLayout( new GridLayout( 2, false) );
+    group.setLayout( new GridLayout( 3, false ) );
     final Text text = createKFZExample_Text( group );
     final DropDownViewer viewer = createKFZExample_Viewer( text );
     createKFZExample_Location( group, viewer );
+    createKFZExample_Config( group, viewer );
     createKFZExample_Log( group, viewer );
     createDisposeButton( group, text );
   }
@@ -145,7 +146,7 @@
   private void createKFZExample_Location( Group group, final DropDownViewer viewer ) {
     Group location = new Group( group, SWT.NONE );
     location.setText( "Location" );
-    GridData layoutData = new GridData( SWT.TOP, SWT.CENTER, false, true );
+    GridData layoutData = new GridData( SWT.CENTER, SWT.FILL, false, true );
     location.setLayoutData( layoutData );
     layoutData.verticalSpan = 2;
     location.setLayout( new GridLayout( 1, true ) );
@@ -177,6 +178,22 @@
     } );
   }
 
+  private void createKFZExample_Config( Group group, final DropDownViewer viewer ) {
+    Group location = new Group( group, SWT.NONE );
+    location.setText( "Config" );
+    GridData layoutData = new GridData( SWT.CENTER, SWT.FILL, false, true );
+    location.setLayoutData( layoutData );
+    layoutData.verticalSpan = 2;
+    location.setLayout( new GridLayout( 1, true ) );
+    final Button autoComplete = new Button( location, SWT.CHECK );
+    autoComplete.setText( "AutoComplete" );
+    autoComplete.addListener( SWT.Selection, new Listener() {
+      public void handleEvent( Event event ) {
+        viewer.setAutoComplete( autoComplete.getSelection() );
+      }
+    } );
+  }
+
   private DropDownViewer createKFZExample_Viewer( final Text text ) {
     DropDownViewer viewer = new DropDownViewer( text );
     viewer.setLabelProvider( new LabelProvider() {
diff --git a/tests/org.eclipse.rap.addons.dropdown.test/META-INF/MANIFEST.MF b/tests/org.eclipse.rap.addons.dropdown.test/META-INF/MANIFEST.MF
index 1fe7b72..787ddba 100644
--- a/tests/org.eclipse.rap.addons.dropdown.test/META-INF/MANIFEST.MF
+++ b/tests/org.eclipse.rap.addons.dropdown.test/META-INF/MANIFEST.MF
@@ -12,7 +12,8 @@
  org.eclipse.rap.addons.dropdown.viewer;bundle-version="0.1.0",
  org.junit;bundle-version="4.8.0";resolution:=optional,
  org.mockito.mockito-all;bundle-version="1.9.5";resolution:=optional,
- org.eclipse.rap.testrunner;bundle-version="1.0.0";resolution:=optional
+ org.eclipse.rap.testrunner;bundle-version="1.0.0";resolution:=optional,
+ org.eclipse.core.runtime;bundle-version="3.9.0"
 Import-Package: org.eclipse.rap.clientscripting;version="0.1.100",
  org.eclipse.rap.clientscripting.internal;version="0.2.0"
 Service-Component: OSGI-INF/*.xml
diff --git a/tests/org.eclipse.rap.addons.dropdown.test/jasmine/jasmine/specs/ModelListenerSpec.js b/tests/org.eclipse.rap.addons.dropdown.test/jasmine/jasmine/specs/ModelListenerSpec.js
index 86fa8a2..a987a17 100644
--- a/tests/org.eclipse.rap.addons.dropdown.test/jasmine/jasmine/specs/ModelListenerSpec.js
+++ b/tests/org.eclipse.rap.addons.dropdown.test/jasmine/jasmine/specs/ModelListenerSpec.js
@@ -177,14 +177,37 @@
 
     } );
 
-    describe( "acceptSuggestion", function() {
+    describe( "change:results", function() {
+
+      it( "does nothing without autocomplete", function() {
+        model.set( "text", "ban" );
+        model.addListener( "change:results", createClientListener( "ModelListener" ) );
+
+        model.set( "results", { "items" : [ "banana" ] } );
+
+        expect( model.get( "text" ) ).toEqual( "ban" );
+      } );
+
+      it( "autocompletes on single result", function() {
+        model.set( "text", "ban" );
+        model.set( "autoComplete", true );
+        model.addListener( "change:results", createClientListener( "ModelListener" ) );
+
+        model.set( "results", { "items" : [ "banana" ] } );
+
+        expect( model.get( "text" ) ).toEqual( "banana" );
+      } );
+
+    } );
+
+    describe( "accept", function() {
 
       it( "sets elementSelection", function() {
-        model.addListener( "acceptSuggestion", createClientListener( "ModelListener" ) );
+        model.addListener( "accept", createClientListener( "ModelListener" ) );
         model.set( "results", { "items" : [ "bar", "banana" ], "indicies" : [ 1, 3 ] } );
         model.set( "resultSelection", 1 );
 
-        model.notify( "acceptSuggestion" );
+        model.notify( "accept" );
 
         expect( model.get( "elementSelection" ) ).toBe( 3 );
       } );
diff --git a/tests/org.eclipse.rap.addons.dropdown.test/src/org/eclipse/rap/addons/dropdown/viewer/DropDownViewer_Test.java b/tests/org.eclipse.rap.addons.dropdown.test/src/org/eclipse/rap/addons/dropdown/viewer/DropDownViewer_Test.java
index 47ab376..b36a502 100644
--- a/tests/org.eclipse.rap.addons.dropdown.test/src/org/eclipse/rap/addons/dropdown/viewer/DropDownViewer_Test.java
+++ b/tests/org.eclipse.rap.addons.dropdown.test/src/org/eclipse/rap/addons/dropdown/viewer/DropDownViewer_Test.java
@@ -378,8 +378,8 @@
       }
     } );
 
-    JsonObject event = new JsonObject().add( "index", 2 );
-    handler.handleNotify( "SelectionChanged", event );
+    JsonObject event = new JsonObject().add( "value", 2 );
+    handler.handleNotify( "change:elementSelection", event );
 
     assertEquals( 1, log.size() );
   }
@@ -397,8 +397,8 @@
 
     viewer.addSelectionChangedListener( listener );
     viewer.addSelectionChangedListener( listener );
-    JsonObject event = new JsonObject().add( "index", 2 );
-    handler.handleNotify( "SelectionChanged", event );
+    JsonObject event = new JsonObject().add( "value", 2 );
+    handler.handleNotify( "change:elementSelection", event );
 
     assertEquals( 1, log.size() );
   }
@@ -414,8 +414,8 @@
       }
     } );
 
-    JsonObject event = new JsonObject().add( "index", 2 );
-    handler.handleNotify( "SelectionChanged", event );
+    JsonObject event = new JsonObject().add( "value", 2 );
+    handler.handleNotify( "change:elementSelection", event );
 
     IStructuredSelection selection = ( IStructuredSelection )log.get( 0 ).getSelection();
     assertEquals( new Integer( 21 ), selection.getFirstElement() );
@@ -505,6 +505,15 @@
     verify( provider ).dispose();
   }
 
+  @Test
+  public void testAutoComplete() {
+    createViewer();
+
+    viewer.setAutoComplete( true );
+
+    verify( remoteObject ).set( eq( "autoComplete" ), eq( true ) );
+  }
+
   //////////
   // Helpers