Introduce generic "change" event in Model.js

This allows to use much less event bindings to ModelListener
diff --git a/bundles/org.eclipse.rap.addons.dropdown.viewer/js/rwt/remote/Model.js b/bundles/org.eclipse.rap.addons.dropdown.viewer/js/rwt/remote/Model.js
index 2e74bdb..f15be0f 100644
--- a/bundles/org.eclipse.rap.addons.dropdown.viewer/js/rwt/remote/Model.js
+++ b/bundles/org.eclipse.rap.addons.dropdown.viewer/js/rwt/remote/Model.js
@@ -44,8 +44,14 @@
         var value = arguments[ 1 ];
         var options = arguments[ 2 ] || {};
         if( this._.properties[ property ] !== value ) {
+          var notifyOptions = {
+            "value" : value,
+            "property" : property
+          }
+          rwt.util.Objects.mergeWith( notifyOptions, options, false );
           this._.properties[ property ] = value;
-          this.notify( "change:" + property, options );
+          this.notify( "change:" + property, notifyOptions );
+          this.notify( "change", notifyOptions );
         }
       }
     },
@@ -89,8 +95,7 @@
         this._.properties = null;
         this._ = null;
       }
-    },
-
+    }
 
   };
 
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 ca6f61a..1219e3e 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
@@ -39,14 +39,14 @@
     = "rwt/remote/Model.js";
   private static final String ATTR_CLIENT_LISTNER_HOLDER
     = ClientListenerHolder.class.getName() + "#instance";
-  private static final String SELECTION_CHANGED = "SelectionChanged";
+  private static final String SELECTION_CHANGED = "change:elementSelection";
   private static final String VIEWER_LINK = DropDownViewer.class.getName() + "#viewer";
   private static final String DROPDOWN_KEY = "dropDown";
   private static final String TEXT_KEY = "text";
   private static final String DECORATOR_KEY = "decorator";
   private static final String ELEMENTS_KEY = "elements";
   private static final String SELECTION_KEY = "selection";
-  private static final boolean USE_NEW_SCRIPTS = true;
+  private static final boolean USE_NEW_SCRIPTS = false;
   private final static String PREFIX
     = "org/eclipse/rap/addons/dropdown/viewer/internal/resources/";
 
@@ -166,11 +166,8 @@
       text.addListener( SWT.Modify, getClientListener( "DataBinding.js" ) );
       text.addListener( SWT.Verify, getClientListener( "DataBinding.js" ) );
       dropDown.addListener( SWT.Selection, getClientListener( "DataBinding.js" ) );
-      // TODO [tb] : introduce "change" event
-      model.addListener( "change:results", getModelListener( "DataBinding.js" ) );
-      model.addListener( "change:resultSelection", getModelListener( "ModelListener.js" ) );
-      model.addListener( "change:userText", getModelListener( "ModelListener.js" ) );
-      model.addListener( "change:text", getModelListener( "DataBinding.js" ) );
+      model.addListener( "change", getModelListener( "ModelListener.js" ) );
+      model.addListener( "change", getModelListener( "DataBinding.js" ) );
     } else {
       text.addListener( ClientListener.Modify, getTextModifyListener() );
       text.addListener( ClientListener.Verify, getTextVerifyListener() );
@@ -280,7 +277,7 @@
 
   private class ModelSelectionListener implements ModelListener {
     public void handleEvent( JsonObject properties ) {
-      int index = properties.get( "index" ).asInt();
+      int index = properties.get( "value" ).asInt();
       fireSelectionChanged( index );
     }
   }
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 ab3d178..1ccf28a 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
@@ -63,12 +63,12 @@
 function handleModelEvent( model, type, event ) {
   var textWidget = rap.getObject( model.get( "textWidgetId" ) );
   var dropDown = rap.getObject( model.get( "dropDownWidgetId" ) );
-  switch( type ) {
-    case "change:text":
-      onModelChangeText( textWidget, model.get( "text" ) );
+  switch( event.property ) {
+    case "text":
+      onModelChangeText( textWidget, event.value );
     break;
-    case "change:results":
-      onModelChangeResults( dropDown, model.get( "results" ) );
+    case "results":
+      onModelChangeResults( dropDown, event.value );
     break;
   }
 }
diff --git a/bundles/org.eclipse.rap.addons.dropdown.viewer/src/org/eclipse/rap/addons/dropdown/viewer/internal/resources/DropDownEventListener.js b/bundles/org.eclipse.rap.addons.dropdown.viewer/src/org/eclipse/rap/addons/dropdown/viewer/internal/resources/DropDownEventListener.js
index 3368c33..e3c6527 100644
--- a/bundles/org.eclipse.rap.addons.dropdown.viewer/src/org/eclipse/rap/addons/dropdown/viewer/internal/resources/DropDownEventListener.js
+++ b/bundles/org.eclipse.rap.addons.dropdown.viewer/src/org/eclipse/rap/addons/dropdown/viewer/internal/resources/DropDownEventListener.js
@@ -83,7 +83,7 @@
   var viewer = rap.getObject( dropdown.getData( VIEWER_KEY ) );
   var text = rap.getObject( viewer.get( "text" ) );
   if( viewer.get( "selection" ) !== elementIndex ) {
-    viewer.notify( "SelectionChanged", { "index" : elementIndex } );
+    viewer.notify( "change:elementSelection", { "value" : elementIndex } );
     viewer.set( "selection", elementIndex );
   }
   text.setData( "selecting", true );
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 d4b7902..556bf1f 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,12 +13,12 @@
 // Event Delegation
 
 function handleEvent( model, type, event ) {
-  switch( type ) {
-    case "change:userText":
-      onChangeText.apply( model, [ event, model.get( "userText" ) ] );
+  switch( event.property ) {
+    case "userText":
+      onChangeText.apply( model, [ event ] );
     break;
-    case "change:resultSelection":
-      onChangeResultSelection.apply( model, [ event, model.get( "resultSelection" ) ] );
+    case "resultSelection":
+      onChangeResultSelection.apply( model, [ event ] );
     break;
   }
 }
@@ -26,14 +26,14 @@
 //////////////////
 // Event Handling
 
-function onChangeText( options, value ) {
-  var query = createQuery( value.toLowerCase() );
+function onChangeText( options ) {
+  var query = createQuery( options.value.toLowerCase() );
   var results = searchItems( this.get( "elements" ), query );
   this.set( "results", results );
 }
 
-function onChangeResultSelection( options, value ) {
-  var text = this.get( "results" ).items[ value ] || "";
+function onChangeResultSelection( options ) {
+  var text = this.get( "results" ).items[ options.value ] || "";
   this.set( "text", text, { "resultSelection" : true } );
 }
 
diff --git a/tests/org.eclipse.rap.addons.dropdown.test/jasmine/jasmine/fixture/rwt-mock.js b/tests/org.eclipse.rap.addons.dropdown.test/jasmine/jasmine/fixture/rwt-mock.js
index e3d9ede..481440a 100644
--- a/tests/org.eclipse.rap.addons.dropdown.test/jasmine/jasmine/fixture/rwt-mock.js
+++ b/tests/org.eclipse.rap.addons.dropdown.test/jasmine/jasmine/fixture/rwt-mock.js
@@ -15,6 +15,22 @@
       removeAt : function(arr, i) {
         return arr.splice(i, 1)[0];
       }
+    },
+    Objects : {
+      mergeWith : function( target, source, overwrite ) {
+        if (overwrite === undefined) {
+          overwrite = true;
+        }
+
+        for (var key in source)
+        {
+          if (overwrite || target[key] === undefined) {
+            target[key] = source[key];
+          }
+        }
+
+        return target;
+      }
     }
   },
   qx : {
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 d8fce95..31ec344 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
@@ -140,6 +140,7 @@
       rap = new RapMock();
       model = rap.typeHandler[ "rwt.remote.Model" ].factory();
       model.set( "elements", [ "foo", "bar", "foobar", "banana", "apple", "cherry" ] );
+      // NOTE: server uses "change", not "change:property", but this is better for unit testing:
       model.addListener( "change:userText", createClientListener( "ModelListener" ) );
     } );
 
diff --git a/tests/org.eclipse.rap.addons.dropdown.test/jasmine/jasmine/specs/ModelSpec.js b/tests/org.eclipse.rap.addons.dropdown.test/jasmine/jasmine/specs/ModelSpec.js
index 4582aa7..9f8e845 100644
--- a/tests/org.eclipse.rap.addons.dropdown.test/jasmine/jasmine/specs/ModelSpec.js
+++ b/tests/org.eclipse.rap.addons.dropdown.test/jasmine/jasmine/specs/ModelSpec.js
@@ -108,6 +108,7 @@
       model.set( "foo", 23 );
 
       expect( log.length ).toBe( 1 );
+      expect( log[ 0 ][ 2 ] ).toEqual( { value : 23, property : "foo" } );
     } );
 
     it( "notifies change listener with options", function() {
@@ -115,7 +116,16 @@
 
       model.set( "foo", 23, { x : 1 } );
 
-      expect( log[ 0 ][ 2 ] ).toEqual( { x : 1 } );
+      expect( log[ 0 ][ 2 ] ).toEqual( { value : 23, x : 1, property : "foo" } );
+    } );
+
+    it( "notifies global change listener", function() {
+      model.addListener( "change", logger );
+
+      model.set( "foo", 23 );
+      model.set( "bar", 25 );
+
+      expect( log.length ).toBe( 2 );
     } );
 
     it( "does not notify change listener if value is unchanged", function() {