Switch read data to operation handlers

Create:
- GridOperationHandler
- GridItemOperationHandler
- GridColumnOperationHandler
- GridColumnGroupOperationHandler
diff --git a/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/gridcolumngroupkit/GridColumnGroupLCA.java b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/gridcolumngroupkit/GridColumnGroupLCA.java
index 6b8715a..8b2ed6a 100644
--- a/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/gridcolumngroupkit/GridColumnGroupLCA.java
+++ b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/gridcolumngroupkit/GridColumnGroupLCA.java
@@ -20,24 +20,18 @@
 import static org.eclipse.rap.rwt.lifecycle.WidgetLCAUtil.preserveProperty;
 import static org.eclipse.rap.rwt.lifecycle.WidgetLCAUtil.renderListener;
 import static org.eclipse.rap.rwt.lifecycle.WidgetLCAUtil.renderProperty;
-import static org.eclipse.rap.rwt.lifecycle.WidgetLCAUtil.wasEventSent;
 import static org.eclipse.rap.rwt.lifecycle.WidgetUtil.getId;
-import static org.eclipse.swt.internal.events.EventLCAUtil.isListening;
 
 import java.io.IOException;
 
 import org.eclipse.nebula.widgets.grid.Grid;
 import org.eclipse.nebula.widgets.grid.GridColumn;
 import org.eclipse.nebula.widgets.grid.GridColumnGroup;
-import org.eclipse.rap.rwt.internal.protocol.ClientMessageConst;
 import org.eclipse.rap.rwt.lifecycle.AbstractWidgetLCA;
-import org.eclipse.rap.rwt.lifecycle.ProcessActionRunner;
 import org.eclipse.rap.rwt.lifecycle.WidgetLCAUtil;
 import org.eclipse.rap.rwt.remote.RemoteObject;
-import org.eclipse.swt.SWT;
 import org.eclipse.swt.graphics.Font;
 import org.eclipse.swt.internal.widgets.ItemLCAUtil;
-import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Widget;
 
 
@@ -62,19 +56,12 @@
   public void renderInitialization( Widget widget ) throws IOException {
     GridColumnGroup group = ( GridColumnGroup )widget;
     RemoteObject remoteObject = createRemoteObject( group, TYPE );
+    remoteObject.setHandler( new GridColumnGroupOperationHandler( group ) );
     remoteObject.set( "parent", getId( group.getParent() ) );
     remoteObject.set( "style", createJsonArray( getStyles( group, ALLOWED_STYLES ) ) );
   }
 
   @Override
-  public void readData( Widget widget ) {
-    GridColumnGroup group = ( GridColumnGroup )widget;
-    readExpanded( group );
-    processTreeEvent( group, SWT.Expand, ClientMessageConst.EVENT_EXPAND );
-    processTreeEvent( group, SWT.Collapse, ClientMessageConst.EVENT_COLLAPSE );
-  }
-
-  @Override
   public void preserveValues( Widget widget ) {
     GridColumnGroup group = ( GridColumnGroup )widget;
     WidgetLCAUtil.preserveCustomVariant( group );
@@ -104,27 +91,6 @@
     renderListener( group, PROP_COLLAPSE_LISTENER, hasCollapseListener( group ), false );
   }
 
-  ////////////////////////////////////////////
-  // Helping methods to read client-side state
-
-  private static void readExpanded( final GridColumnGroup group ) {
-    final String expanded = WidgetLCAUtil.readPropertyValue( group, PROP_EXPANDED );
-    if( expanded != null ) {
-      ProcessActionRunner.add( new Runnable() {
-        public void run() {
-          group.setExpanded( Boolean.valueOf( expanded ).booleanValue() );
-//          preserveProperty( group, PROP_EXPANDED, group.getExpanded() );
-        }
-      } );
-    }
-  }
-
-  private static void processTreeEvent( GridColumnGroup group, int eventType, String eventName ) {
-    if( wasEventSent( group, eventName ) && isListening( group, eventType ) ) {
-      group.notifyListeners( eventType, new Event() );
-    }
-  }
-
   //////////////////////////////////////////////
   // Helping methods to render widget properties
 
@@ -179,12 +145,14 @@
     return result;
   }
 
+  @SuppressWarnings( "unused" )
   private static boolean hasExpandListener( GridColumnGroup group ) {
     // Always render listen for Expand and Collapse, currently required for columns
     // visibility update.
     return true;
   }
 
+  @SuppressWarnings( "unused" )
   private static boolean hasCollapseListener( GridColumnGroup group ) {
     // Always render listen for Expand and Collapse, currently required for columns
     // visibility update.
diff --git a/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/gridcolumngroupkit/GridColumnGroupOperationHandler.java b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/gridcolumngroupkit/GridColumnGroupOperationHandler.java
new file mode 100644
index 0000000..eb883f0
--- /dev/null
+++ b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/gridcolumngroupkit/GridColumnGroupOperationHandler.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2013 EclipseSource and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    EclipseSource - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.nebula.widgets.grid.internal.gridcolumngroupkit;
+
+import static org.eclipse.rap.rwt.internal.protocol.ClientMessageConst.EVENT_COLLAPSE;
+import static org.eclipse.rap.rwt.internal.protocol.ClientMessageConst.EVENT_EXPAND;
+
+import org.eclipse.nebula.widgets.grid.GridColumnGroup;
+import org.eclipse.rap.json.JsonObject;
+import org.eclipse.rap.json.JsonValue;
+import org.eclipse.rap.rwt.internal.protocol.WidgetOperationHandler;
+import org.eclipse.rap.rwt.lifecycle.ProcessActionRunner;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Event;
+
+
+@SuppressWarnings( "restriction" )
+public class GridColumnGroupOperationHandler extends WidgetOperationHandler<GridColumnGroup> {
+
+  private static final String PROP_EXPANDED = "expanded";
+
+  public GridColumnGroupOperationHandler( GridColumnGroup group ) {
+    super( group );
+  }
+
+  @Override
+  public void handleSet( GridColumnGroup group, JsonObject properties ) {
+    handleSetExpanded( group, properties );
+  }
+
+  @Override
+  public void handleNotify( GridColumnGroup group, String eventName, JsonObject properties ) {
+    if( EVENT_EXPAND.equals( eventName ) ) {
+      handleNotifyExpand( group, properties );
+    } else if( EVENT_COLLAPSE.equals( eventName ) ) {
+      handleNotifyCollapse( group, properties );
+    } else {
+      super.handleNotify( group, eventName, properties );
+    }
+  }
+
+  /*
+   * PROTOCOL SET expanded
+   *
+   * @param expanded (boolean) true if the group was expanded, false otherwise
+   */
+  public void handleSetExpanded( final GridColumnGroup group, JsonObject properties ) {
+    final JsonValue expanded = properties.get( PROP_EXPANDED );
+    if( expanded != null ) {
+      ProcessActionRunner.add( new Runnable() {
+        public void run() {
+          group.setExpanded( expanded.asBoolean() );
+//          preserveProperty( group, PROP_EXPANDED, group.getExpanded() );
+        }
+      } );
+    }
+  }
+
+  /*
+   * PROTOCOL NOTIFY Expand
+   */
+  @SuppressWarnings( "unused" )
+  public void handleNotifyExpand( GridColumnGroup group, JsonObject properties ) {
+    group.notifyListeners( SWT.Expand, new Event() );
+  }
+
+  /*
+   * PROTOCOL NOTIFY Collapse
+   */
+  @SuppressWarnings( "unused" )
+  public void handleNotifyCollapse( GridColumnGroup group, JsonObject properties ) {
+    group.notifyListeners( SWT.Collapse, new Event() );
+  }
+
+}
diff --git a/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/gridcolumnkit/GridColumnLCA.java b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/gridcolumnkit/GridColumnLCA.java
index d2cfec2..79733e0 100644
--- a/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/gridcolumnkit/GridColumnLCA.java
+++ b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/gridcolumnkit/GridColumnLCA.java
@@ -11,29 +11,20 @@
 package org.eclipse.nebula.widgets.grid.internal.gridcolumnkit;
 
 import static org.eclipse.rap.rwt.internal.protocol.ProtocolUtil.getJsonForFont;
-import static org.eclipse.rap.rwt.internal.protocol.ProtocolUtil.readCallPropertyValueAsString;
 import static org.eclipse.rap.rwt.internal.protocol.RemoteObjectFactory.createRemoteObject;
 import static org.eclipse.rap.rwt.internal.protocol.RemoteObjectFactory.getRemoteObject;
 import static org.eclipse.rap.rwt.lifecycle.WidgetLCAUtil.preserveListener;
 import static org.eclipse.rap.rwt.lifecycle.WidgetLCAUtil.preserveProperty;
 import static org.eclipse.rap.rwt.lifecycle.WidgetLCAUtil.renderListener;
 import static org.eclipse.rap.rwt.lifecycle.WidgetLCAUtil.renderProperty;
-import static org.eclipse.rap.rwt.lifecycle.WidgetUtil.getId;
 import static org.eclipse.swt.internal.events.EventLCAUtil.isListening;
 
 import java.io.IOException;
-import java.util.Arrays;
 
-import org.eclipse.nebula.widgets.grid.Grid;
 import org.eclipse.nebula.widgets.grid.GridColumn;
 import org.eclipse.nebula.widgets.grid.GridColumnGroup;
 import org.eclipse.nebula.widgets.grid.internal.IGridAdapter;
-import org.eclipse.rap.rwt.internal.protocol.ProtocolUtil;
-import org.eclipse.rap.rwt.internal.util.NumberFormatUtil;
 import org.eclipse.rap.rwt.lifecycle.AbstractWidgetLCA;
-import org.eclipse.rap.rwt.lifecycle.ControlLCAUtil;
-import org.eclipse.rap.rwt.lifecycle.ProcessActionRunner;
-import org.eclipse.rap.rwt.lifecycle.WidgetAdapter;
 import org.eclipse.rap.rwt.lifecycle.WidgetLCAUtil;
 import org.eclipse.rap.rwt.lifecycle.WidgetUtil;
 import org.eclipse.rap.rwt.remote.RemoteObject;
@@ -69,6 +60,7 @@
   public void renderInitialization( Widget widget ) throws IOException {
     GridColumn column = ( GridColumn )widget;
     RemoteObject remoteObject = createRemoteObject( column, TYPE );
+    remoteObject.setHandler( new GridColumnOperationHandler( column ) );
     remoteObject.set( "parent", WidgetUtil.getId( column.getParent() ) );
     GridColumnGroup group = column.getColumnGroup();
     if( group != null ) {
@@ -77,14 +69,6 @@
   }
 
   @Override
-  public void readData( Widget widget ) {
-    GridColumn column = ( GridColumn )widget;
-    readLeft( column );
-    readWidth( column );
-    ControlLCAUtil.processSelection( column, null, false );
-  }
-
-  @Override
   public void preserveValues( Widget widget ) {
     GridColumn column = ( GridColumn )widget;
     WidgetLCAUtil.preserveToolTipText( column, column.getHeaderTooltip() );
@@ -126,35 +110,6 @@
     renderListener( column, PROP_SELECTION_LISTENER, isListening( column, SWT.Selection ), false );
   }
 
-  ////////////////////////////////////////////
-  // Helping methods to read client-side state
-
-  private static void readLeft( final GridColumn column ) {
-    String methodName = "move";
-    if( ProtocolUtil.wasCallReceived( getId( column ), methodName ) ) {
-      String value = readCallPropertyValueAsString( getId( column ), methodName, "left" );
-      final int newLeft = NumberFormatUtil.parseInt( value );
-      ProcessActionRunner.add( new Runnable() {
-        public void run() {
-          moveColumn( column, newLeft );
-        }
-      } );
-    }
-  }
-
-  private static void readWidth( final GridColumn column ) {
-    String methodName = "resize";
-    if( ProtocolUtil.wasCallReceived( getId( column ), methodName ) ) {
-      String value = readCallPropertyValueAsString( getId( column ), methodName, "width" );
-      final int newWidth = NumberFormatUtil.parseInt( value );
-      ProcessActionRunner.add( new Runnable() {
-        public void run() {
-          column.setWidth( newWidth );
-        }
-      } );
-    }
-  }
-
   //////////////////////////////////////////////
   // Helping methods to render widget properties
 
@@ -165,80 +120,11 @@
     }
   }
 
-  /////////////////////////////////
-  // Helping methods to move column
-
-  static void moveColumn( GridColumn column, int newLeft ) {
-    Grid grid = column.getParent();
-    int index = grid.indexOf( column );
-    int targetColumn = findMoveTarget( grid, newLeft );
-    int[] columnOrder = grid.getColumnOrder();
-    int orderIndex = arrayIndexOf( columnOrder, index );
-    columnOrder = arrayRemove( columnOrder, orderIndex );
-    if( orderIndex < targetColumn ) {
-      targetColumn--;
-    }
-    columnOrder = arrayInsert( columnOrder, targetColumn, index );
-    if( Arrays.equals( columnOrder, grid.getColumnOrder() ) ) {
-      GridColumn[] columns = grid.getColumns();
-      for( int i = 0; i < columns.length; i++ ) {
-        WidgetAdapter adapter = WidgetUtil.getAdapter( columns[ i ] );
-        adapter.preserve( PROP_LEFT, null );
-      }
-    } else {
-      try {
-        grid.setColumnOrder( columnOrder );
-      } catch( IllegalArgumentException exception ) {
-        // move the column in/out of a group is invalid
-      } finally {
-        WidgetAdapter adapter = WidgetUtil.getAdapter( column );
-        adapter.preserve( PROP_LEFT, null );
-      }
-    }
-  }
-
-  private static int findMoveTarget( Grid grid, int newLeft ) {
-    int result = -1;
-    GridColumn[] columns = grid.getColumns();
-    int[] columnOrder = grid.getColumnOrder();
-    if( newLeft < 0 ) {
-      result = 0;
-    } else {
-      for( int i = 0; result == -1 && i < columns.length; i++ ) {
-        GridColumn column = columns[ columnOrder[ i ] ];
-        int left = getLeft( column );
-        int width = getWidth( column );
-        if( newLeft >= left && newLeft <= left + width ) {
-          result = i;
-          if( newLeft >= left + width / 2 && result < columns.length ) {
-            result++;
-          }
-        }
-      }
-    }
-    if( result == -1 ) {
-      result = columns.length;
-    }
-    return result;
-  }
-
   //////////////////
   // Helping methods
 
-  private static int getIndex( GridColumn column ) {
-    return column.getParent().indexOf( column );
-  }
-
   private static int getLeft( GridColumn column ) {
-    Grid grid = column.getParent();
-    IGridAdapter adapter = grid.getAdapter( IGridAdapter.class );
-    return adapter.getCellLeft( grid.indexOf( column ) );
-  }
-
-  private static int getWidth( GridColumn column ) {
-    Grid grid = column.getParent();
-    IGridAdapter adapter = grid.getAdapter( IGridAdapter.class );
-    return adapter.getCellWidth( grid.indexOf( column ) );
+    return getGridAdapter( column ).getCellLeft( getIndex( column ) );
   }
 
   private static String getAlignment( GridColumn column ) {
@@ -252,32 +138,12 @@
     return result;
   }
 
-  private static int arrayIndexOf( int[] array, int value ) {
-    int result = -1;
-    for( int i = 0; result == -1 && i < array.length; i++ ) {
-      if( array[ i ] == value ) {
-        result = i;
-      }
-    }
-    return result;
+  private static int getIndex( GridColumn column ) {
+    return column.getParent().indexOf( column );
   }
 
-  private static int[] arrayRemove( int[] array, int index ) {
-    int length = array.length;
-    int[] result = new int[ length - 1 ];
-    System.arraycopy( array, 0, result, 0, index );
-    if( index < length - 1 ) {
-      System.arraycopy( array, index + 1, result, index, length - index - 1 );
-    }
-    return result;
+  private static IGridAdapter getGridAdapter( GridColumn column ) {
+    return column.getParent().getAdapter( IGridAdapter.class );
   }
 
-  private static int[] arrayInsert( int[] array, int index, int value ) {
-    int length = array.length;
-    int[] result = new int[ length + 1 ];
-    System.arraycopy( array, 0, result, 0, length );
-    System.arraycopy( result, index, result, index + 1, length - index );
-    result[ index ] = value;
-    return result;
-  }
 }
diff --git a/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/gridcolumnkit/GridColumnOperationHandler.java b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/gridcolumnkit/GridColumnOperationHandler.java
new file mode 100644
index 0000000..2834e5b
--- /dev/null
+++ b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/gridcolumnkit/GridColumnOperationHandler.java
@@ -0,0 +1,213 @@
+/*******************************************************************************
+ * Copyright (c) 2013 EclipseSource and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    EclipseSource - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.nebula.widgets.grid.internal.gridcolumnkit;
+
+import static org.eclipse.rap.rwt.internal.protocol.ClientMessageConst.EVENT_DEFAULT_SELECTION;
+import static org.eclipse.rap.rwt.internal.protocol.ClientMessageConst.EVENT_SELECTION;
+
+import java.util.Arrays;
+
+import org.eclipse.nebula.widgets.grid.Grid;
+import org.eclipse.nebula.widgets.grid.GridColumn;
+import org.eclipse.nebula.widgets.grid.internal.IGridAdapter;
+import org.eclipse.rap.json.JsonObject;
+import org.eclipse.rap.rwt.internal.protocol.WidgetOperationHandler;
+import org.eclipse.rap.rwt.lifecycle.ProcessActionRunner;
+import org.eclipse.rap.rwt.lifecycle.WidgetAdapter;
+import org.eclipse.rap.rwt.lifecycle.WidgetUtil;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Event;
+
+
+@SuppressWarnings( "restriction" )
+public class GridColumnOperationHandler extends WidgetOperationHandler<GridColumn> {
+
+  private static final String METHOD_MOVE = "move";
+  private static final String METHOD_RESIZE = "resize";
+  private static final String PROP_LEFT = "left";
+  private static final String PROP_WIDTH = "width";
+
+  public GridColumnOperationHandler( GridColumn column ) {
+    super( column );
+  }
+
+  @Override
+  public void handleCall( GridColumn column, String method, JsonObject properties ) {
+    if( METHOD_MOVE.equals( method ) ) {
+      handleCallMove( column, properties );
+    } else if( METHOD_RESIZE.equals( method ) ) {
+      handleCallResize( column, properties );
+    }
+  }
+
+  @Override
+  public void handleNotify( GridColumn column, String eventName, JsonObject properties ) {
+    if( EVENT_SELECTION.equals( eventName ) ) {
+      handleNotifySelection( column, properties );
+    } else if( EVENT_DEFAULT_SELECTION.equals( eventName ) ) {
+      handleNotifyDefaultSelection( column, properties );
+    } else {
+      super.handleNotify( column, eventName, properties );
+    }
+  }
+
+  /*
+   * PROTOCOL CALL move
+   *
+   * @param left (int) the left position of the column
+   */
+  public void handleCallMove( final GridColumn column, JsonObject properties ) {
+    final int newLeft = properties.get( PROP_LEFT ).asInt();
+    ProcessActionRunner.add( new Runnable() {
+      public void run() {
+        moveColumn( column, newLeft );
+      }
+    } );
+  }
+
+  /*
+   * PROTOCOL CALL resize
+   *
+   * @param width (int) the width of the column
+   */
+  public void handleCallResize( final GridColumn column, JsonObject properties ) {
+    final int width = properties.get( PROP_WIDTH ).asInt();
+    ProcessActionRunner.add( new Runnable() {
+      public void run() {
+        column.setWidth( width );
+      }
+    } );
+  }
+
+  /*
+   * PROTOCOL NOTIFY Selection
+   *
+   * @param altKey (boolean) true if the ALT key was pressed
+   * @param ctrlKey (boolean) true if the CTRL key was pressed
+   * @param shiftKey (boolean) true if the SHIFT key was pressed
+   */
+  public void handleNotifySelection( GridColumn column, JsonObject properties ) {
+    Event event = createSelectionEvent( SWT.Selection, properties );
+    column.notifyListeners( SWT.Selection, event );
+  }
+
+  /*
+   * PROTOCOL NOTIFY DefaultSelection
+   *
+   * @param altKey (boolean) true if the ALT key was pressed
+   * @param ctrlKey (boolean) true if the CTRL key was pressed
+   * @param shiftKey (boolean) true if the SHIFT key was pressed
+   */
+  public void handleNotifyDefaultSelection( GridColumn column, JsonObject properties ) {
+    Event event = createSelectionEvent( SWT.DefaultSelection, properties );
+    column.notifyListeners( SWT.DefaultSelection, event );
+  }
+
+  static void moveColumn( GridColumn column, int newLeft ) {
+    Grid grid = column.getParent();
+    int index = grid.indexOf( column );
+    int targetColumn = findMoveTarget( grid, newLeft );
+    int[] columnOrder = grid.getColumnOrder();
+    int orderIndex = arrayIndexOf( columnOrder, index );
+    columnOrder = arrayRemove( columnOrder, orderIndex );
+    if( orderIndex < targetColumn ) {
+      targetColumn--;
+    }
+    columnOrder = arrayInsert( columnOrder, targetColumn, index );
+    if( Arrays.equals( columnOrder, grid.getColumnOrder() ) ) {
+      GridColumn[] columns = grid.getColumns();
+      for( int i = 0; i < columns.length; i++ ) {
+        WidgetAdapter adapter = WidgetUtil.getAdapter( columns[ i ] );
+        adapter.preserve( PROP_LEFT, null );
+      }
+    } else {
+      try {
+        grid.setColumnOrder( columnOrder );
+      } catch( IllegalArgumentException exception ) {
+        // move the column in/out of a group is invalid
+      } finally {
+        WidgetAdapter adapter = WidgetUtil.getAdapter( column );
+        adapter.preserve( PROP_LEFT, null );
+      }
+    }
+  }
+
+  private static int findMoveTarget( Grid grid, int newLeft ) {
+    int result = -1;
+    GridColumn[] columns = grid.getColumns();
+    int[] columnOrder = grid.getColumnOrder();
+    if( newLeft < 0 ) {
+      result = 0;
+    } else {
+      for( int i = 0; result == -1 && i < columns.length; i++ ) {
+        GridColumn column = columns[ columnOrder[ i ] ];
+        int left = getLeft( column );
+        int width = getWidth( column );
+        if( newLeft >= left && newLeft <= left + width ) {
+          result = i;
+          if( newLeft >= left + width / 2 && result < columns.length ) {
+            result++;
+          }
+        }
+      }
+    }
+    if( result == -1 ) {
+      result = columns.length;
+    }
+    return result;
+  }
+
+  private static int getLeft( GridColumn column ) {
+    return getGridAdapter( column ).getCellLeft( getIndex( column ) );
+  }
+
+  private static int getWidth( GridColumn column ) {
+    return getGridAdapter( column ).getCellWidth( getIndex( column ) );
+  }
+
+  private static int getIndex( GridColumn column ) {
+    return column.getParent().indexOf( column );
+  }
+
+  private static IGridAdapter getGridAdapter( GridColumn column ) {
+    return column.getParent().getAdapter( IGridAdapter.class );
+  }
+
+  private static int arrayIndexOf( int[] array, int value ) {
+    int result = -1;
+    for( int i = 0; result == -1 && i < array.length; i++ ) {
+      if( array[ i ] == value ) {
+        result = i;
+      }
+    }
+    return result;
+  }
+
+  private static int[] arrayRemove( int[] array, int index ) {
+    int length = array.length;
+    int[] result = new int[ length - 1 ];
+    System.arraycopy( array, 0, result, 0, index );
+    if( index < length - 1 ) {
+      System.arraycopy( array, index + 1, result, index, length - index - 1 );
+    }
+    return result;
+  }
+
+  private static int[] arrayInsert( int[] array, int index, int value ) {
+    int length = array.length;
+    int[] result = new int[ length + 1 ];
+    System.arraycopy( array, 0, result, 0, length );
+    System.arraycopy( result, index, result, index + 1, length - index );
+    result[ index ] = value;
+    return result;
+  }
+
+}
diff --git a/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/griditemkit/GridItemLCA.java b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/griditemkit/GridItemLCA.java
index d5e2a7e..afe482c 100644
--- a/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/griditemkit/GridItemLCA.java
+++ b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/griditemkit/GridItemLCA.java
@@ -14,7 +14,6 @@
 import static org.eclipse.rap.rwt.internal.protocol.RemoteObjectFactory.getRemoteObject;
 import static org.eclipse.rap.rwt.lifecycle.WidgetLCAUtil.preserveProperty;
 import static org.eclipse.rap.rwt.lifecycle.WidgetLCAUtil.renderProperty;
-import static org.eclipse.rap.rwt.lifecycle.WidgetUtil.getId;
 
 import java.io.IOException;
 
@@ -22,10 +21,8 @@
 import org.eclipse.nebula.widgets.grid.GridItem;
 import org.eclipse.nebula.widgets.grid.internal.IGridAdapter;
 import org.eclipse.nebula.widgets.grid.internal.IGridItemAdapter;
-import org.eclipse.rap.rwt.internal.protocol.ProtocolUtil;
 import org.eclipse.rap.rwt.internal.remote.RemoteObjectImpl;
 import org.eclipse.rap.rwt.lifecycle.AbstractWidgetLCA;
-import org.eclipse.rap.rwt.lifecycle.ProcessActionRunner;
 import org.eclipse.rap.rwt.lifecycle.WidgetLCAUtil;
 import org.eclipse.rap.rwt.lifecycle.WidgetUtil;
 import org.eclipse.rap.rwt.remote.RemoteObject;
@@ -60,18 +57,12 @@
   public void renderInitialization( Widget widget ) throws IOException {
     GridItem item = ( GridItem )widget;
     RemoteObject remoteObject = createRemoteObject( item, TYPE );
+    remoteObject.setHandler( new GridItemOperationHandler( item ) );
     remoteObject.set( "parent", WidgetUtil.getId( getParent( item ) ) );
     remoteObject.set( "index", getItemIndex( item ) );
   }
 
   @Override
-  public void readData( Widget widget ) {
-    GridItem item = ( GridItem )widget;
-    readChecked( item );
-    readExpanded( item );
-  }
-
-  @Override
   public void preserveValues( Widget widget ) {
     GridItem item = ( GridItem )widget;
     WidgetLCAUtil.preserveCustomVariant( item );
@@ -143,30 +134,6 @@
     }
   }
 
-  ////////////////////////////////////////////
-  // Helping methods to read client-side state
-
-  private static void readChecked( GridItem item ) {
-    boolean[] value = ProtocolUtil.readPropertyValueAsBooleanArray( getId( item ), "cellChecked" );
-    if( value != null ) {
-      for( int i = 0; i < value.length; i++ ) {
-        item.setChecked( i, value[ i ] );
-      }
-    }
-  }
-
-  private static void readExpanded( final GridItem item ) {
-    final String expanded = WidgetLCAUtil.readPropertyValue( item, PROP_EXPANDED );
-    if( expanded != null ) {
-      ProcessActionRunner.add( new Runnable() {
-        public void run() {
-          item.setExpanded( Boolean.valueOf( expanded ).booleanValue() );
-          preserveProperty( item, PROP_EXPANDED, item.isExpanded() );
-        }
-      } );
-    }
-  }
-
   //////////////////
   // Helping methods
 
diff --git a/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/griditemkit/GridItemOperationHandler.java b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/griditemkit/GridItemOperationHandler.java
new file mode 100644
index 0000000..8873661
--- /dev/null
+++ b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/griditemkit/GridItemOperationHandler.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2013 EclipseSource and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    EclipseSource - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.nebula.widgets.grid.internal.griditemkit;
+
+import static org.eclipse.rap.rwt.lifecycle.WidgetLCAUtil.preserveProperty;
+
+import org.eclipse.nebula.widgets.grid.GridItem;
+import org.eclipse.rap.json.JsonArray;
+import org.eclipse.rap.json.JsonObject;
+import org.eclipse.rap.json.JsonValue;
+import org.eclipse.rap.rwt.internal.protocol.WidgetOperationHandler;
+import org.eclipse.rap.rwt.lifecycle.ProcessActionRunner;
+
+
+@SuppressWarnings( "restriction" )
+public class GridItemOperationHandler extends WidgetOperationHandler<GridItem> {
+
+  private static final String PROP_CELL_CHECKED = "cellChecked";
+  private static final String PROP_EXPANDED = "expanded";
+
+  public GridItemOperationHandler( GridItem item ) {
+    super( item );
+  }
+
+  @Override
+  public void handleSet( GridItem item, JsonObject properties ) {
+    handleSetChecked( item, properties );
+    handleSetExpanded( item, properties );
+  }
+
+  /*
+   * PROTOCOL SET checked
+   *
+   * @param checked ([boolean]) array with item checked states (by column)
+   */
+  public void handleSetChecked( GridItem item, JsonObject properties ) {
+    JsonValue value = properties.get( PROP_CELL_CHECKED );
+    if( value != null ) {
+      JsonArray arrayValue = value.asArray();
+      for( int i = 0; i < arrayValue.size(); i++ ) {
+        item.setChecked( i, arrayValue.get( i ).asBoolean() );
+      }
+    }
+  }
+
+  /*
+   * PROTOCOL SET expanded
+   *
+   * @param expanded (boolean) true if the item was expanded, false otherwise
+   */
+  public void handleSetExpanded( final GridItem item, JsonObject properties ) {
+    final JsonValue expanded = properties.get( PROP_EXPANDED );
+    if( expanded != null ) {
+      ProcessActionRunner.add( new Runnable() {
+        public void run() {
+          item.setExpanded( expanded.asBoolean() );
+          preserveProperty( item, PROP_EXPANDED, item.isExpanded() );
+        }
+      } );
+    }
+  }
+
+}
diff --git a/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/gridkit/GridLCA.java b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/gridkit/GridLCA.java
index 1d00e5a..1f2c6f5 100644
--- a/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/gridkit/GridLCA.java
+++ b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/gridkit/GridLCA.java
@@ -10,23 +10,14 @@
  ******************************************************************************/
 package org.eclipse.nebula.widgets.grid.internal.gridkit;
 
-import static org.eclipse.rap.rwt.internal.protocol.ClientMessageConst.EVENT_PARAM_DETAIL;
-import static org.eclipse.rap.rwt.internal.protocol.ClientMessageConst.EVENT_PARAM_INDEX;
-import static org.eclipse.rap.rwt.internal.protocol.ClientMessageConst.EVENT_PARAM_ITEM;
 import static org.eclipse.rap.rwt.internal.protocol.JsonUtil.createJsonArray;
-import static org.eclipse.rap.rwt.internal.protocol.ProtocolUtil.readCallPropertyValueAsString;
-import static org.eclipse.rap.rwt.internal.protocol.ProtocolUtil.readPropertyValueAsStringArray;
-import static org.eclipse.rap.rwt.internal.protocol.ProtocolUtil.wasCallReceived;
 import static org.eclipse.rap.rwt.internal.protocol.RemoteObjectFactory.createRemoteObject;
 import static org.eclipse.rap.rwt.internal.protocol.RemoteObjectFactory.getRemoteObject;
 import static org.eclipse.rap.rwt.lifecycle.WidgetLCAUtil.getStyles;
 import static org.eclipse.rap.rwt.lifecycle.WidgetLCAUtil.preserveListener;
 import static org.eclipse.rap.rwt.lifecycle.WidgetLCAUtil.preserveProperty;
-import static org.eclipse.rap.rwt.lifecycle.WidgetLCAUtil.readEventPropertyValue;
-import static org.eclipse.rap.rwt.lifecycle.WidgetLCAUtil.readPropertyValue;
 import static org.eclipse.rap.rwt.lifecycle.WidgetLCAUtil.renderListener;
 import static org.eclipse.rap.rwt.lifecycle.WidgetLCAUtil.renderProperty;
-import static org.eclipse.rap.rwt.lifecycle.WidgetLCAUtil.wasEventSent;
 import static org.eclipse.rap.rwt.lifecycle.WidgetUtil.getId;
 import static org.eclipse.swt.internal.events.EventLCAUtil.isListening;
 import static org.eclipse.swt.internal.widgets.MarkupUtil.isMarkupEnabledFor;
@@ -38,20 +29,15 @@
 import org.eclipse.nebula.widgets.grid.GridItem;
 import org.eclipse.nebula.widgets.grid.internal.IGridAdapter;
 import org.eclipse.rap.json.JsonArray;
-import org.eclipse.rap.rwt.internal.protocol.ClientMessageConst;
-import org.eclipse.rap.rwt.internal.util.NumberFormatUtil;
 import org.eclipse.rap.rwt.lifecycle.AbstractWidgetLCA;
 import org.eclipse.rap.rwt.lifecycle.ControlLCAUtil;
 import org.eclipse.rap.rwt.lifecycle.WidgetLCAUtil;
-import org.eclipse.rap.rwt.lifecycle.WidgetUtil;
 import org.eclipse.rap.rwt.remote.RemoteObject;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.internal.widgets.CellToolTipUtil;
 import org.eclipse.swt.internal.widgets.ICellToolTipAdapter;
-import org.eclipse.swt.internal.widgets.ICellToolTipProvider;
 import org.eclipse.swt.internal.widgets.ScrollBarLCAUtil;
 import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.ScrollBar;
 import org.eclipse.swt.widgets.Widget;
 
@@ -105,6 +91,7 @@
   public void renderInitialization( Widget widget ) throws IOException {
     Grid grid = ( Grid )widget;
     RemoteObject remoteObject = createRemoteObject( grid, TYPE );
+    remoteObject.setHandler( new GridOperationHandler( grid ) );
     remoteObject.set( "parent", getId( grid.getParent() ) );
     remoteObject.set( "style", createJsonArray( getStyles( grid, ALLOWED_STYLES ) ) );
     remoteObject.set( "appearance", "tree" );
@@ -116,21 +103,8 @@
 
   @Override
   public void readData( Widget widget ) {
-    Grid grid = ( Grid )widget;
-    readSelection( grid );
-    readScrollLeft( grid );
-    readTopItemIndex( grid );
-    readFocusItem( grid );
-    readCellToolTipTextRequested( grid );
-    processSelectionEvent( grid, ClientMessageConst.EVENT_SELECTION );
-    processSelectionEvent( grid, ClientMessageConst.EVENT_DEFAULT_SELECTION );
-    processTreeEvent( grid, SWT.Expand, ClientMessageConst.EVENT_EXPAND );
-    processTreeEvent( grid, SWT.Collapse, ClientMessageConst.EVENT_COLLAPSE );
-    ControlLCAUtil.processEvents( grid );
-    ControlLCAUtil.processKeyEvents( grid );
-    ControlLCAUtil.processMenuDetect( grid );
-    WidgetLCAUtil.processHelp( grid );
-    ScrollBarLCAUtil.processSelectionEvent( grid );
+    super.readData( widget );
+    ScrollBarLCAUtil.processSelectionEvent( ( Grid )widget );
   }
 
   @Override
@@ -196,7 +170,7 @@
     renderListener( grid, PROP_EXPAND_LISTENER, hasExpandListener( grid ), false );
     renderListener( grid, PROP_COLLAPSE_LISTENER, hasCollapseListener( grid ), false );
     renderProperty( grid, PROP_ENABLE_CELL_TOOLTIP, CellToolTipUtil.isEnabledFor( grid ), false );
-    renderProperty( grid, PROP_CELL_TOOLTIP_TEXT, getCellToolTipText( grid ), null );
+    renderProperty( grid, PROP_CELL_TOOLTIP_TEXT, getAndResetCellToolTipText( grid ), null );
     ScrollBarLCAUtil.renderChanges( grid );
   }
 
@@ -205,80 +179,16 @@
     getGridAdapter( ( Grid )control ).doRedraw();
   }
 
-  ////////////////////////////////////////////
-  // Helping methods to read client-side state
-
-  private static void readSelection( Grid grid ) {
-    String[] values = readPropertyValueAsStringArray( getId( grid ), "selection" );
-    if( values != null ) {
-      GridItem[] selectedItems = new GridItem[ values.length ];
-      boolean validItemFound = false;
-      for( int i = 0; i < values.length; i++ ) {
-        selectedItems[ i ] = getItem( grid, values[ i ] );
-        if( selectedItems[ i ] != null ) {
-          validItemFound = true;
-        }
-      }
-      if( !validItemFound ) {
-        selectedItems = new GridItem[ 0 ];
-      }
-      grid.setSelection( selectedItems );
-    }
-  }
-
-  private static void readScrollLeft( Grid grid ) {
-    String left = readPropertyValue( grid, "scrollLeft" );
-    if( left != null ) {
-      int leftOffset = NumberFormatUtil.parseInt( left );
-      processScrollBarSelection( grid.getHorizontalBar(), leftOffset );
-    }
-  }
-
-  private static void readTopItemIndex( Grid grid ) {
-    String topItemIndex = readPropertyValue( grid, "topItemIndex" );
-    if( topItemIndex != null ) {
-      int topOffset = NumberFormatUtil.parseInt( topItemIndex );
-      getGridAdapter( grid ).invalidateTopIndex();
-      processScrollBarSelection( grid.getVerticalBar(), topOffset );
-    }
-  }
-
-  private static void readFocusItem( Grid grid ) {
-    String value = readPropertyValue( grid, "focusItem" );
-    if( value != null ) {
-      GridItem item = getItem( grid, value );
-      if( item != null ) {
-        grid.setFocusItem( item );
-      }
-    }
-  }
-
-  ////////////////
-  // Cell tooltips
-
-  private static void readCellToolTipTextRequested( Grid grid ) {
-    ICellToolTipAdapter adapter = CellToolTipUtil.getAdapter( grid );
-    adapter.setCellToolTipText( null );
-    ICellToolTipProvider provider = adapter.getCellToolTipProvider();
-    String methodName = "renderToolTipText";
-    if( provider != null && wasCallReceived( getId( grid ), methodName ) ) {
-      String itemId = readCallPropertyValueAsString( getId( grid ), methodName, "item" );
-      String column = readCallPropertyValueAsString( getId( grid ), methodName, "column" );
-      int columnIndex = NumberFormatUtil.parseInt( column );
-      GridItem item = getItem( grid, itemId );
-      if( item != null && ( columnIndex == 0 || columnIndex < grid.getColumnCount() ) ) {
-        provider.getToolTipText( item, columnIndex );
-      }
-    }
-  }
-
-  private static String getCellToolTipText( Grid grid ) {
-    return CellToolTipUtil.getAdapter( grid ).getCellToolTipText();
-  }
-
   //////////////////
   // Helping methods
 
+  private static String getAndResetCellToolTipText( Grid grid ) {
+    ICellToolTipAdapter adapter = CellToolTipUtil.getAdapter( grid );
+    String toolTipText = adapter.getCellToolTipText();
+    adapter.setCellToolTipText( null );
+    return toolTipText;
+  }
+
   private static boolean listensToSetData( Grid grid ) {
     return ( grid.getStyle() & SWT.VIRTUAL ) != 0;
   }
@@ -339,59 +249,20 @@
     return result;
   }
 
-  private static GridItem getItem( Grid grid, String itemId ) {
-    return ( GridItem )WidgetUtil.find( grid, itemId );
-  }
-
-  private static void processScrollBarSelection( ScrollBar scrollBar, int selection ) {
-    if( scrollBar != null ) {
-      scrollBar.setSelection( selection );
-    }
-  }
-
-  private static void processSelectionEvent( Grid grid, String eventName ) {
-    if( wasEventSent( grid, eventName ) ) {
-      GridItem item = getItem( grid, readEventPropertyValue( grid, eventName, EVENT_PARAM_ITEM ) );
-      if( item != null ) {
-        if( eventName.equals( ClientMessageConst.EVENT_SELECTION ) ) {
-          String detail = readEventPropertyValue( grid, eventName, EVENT_PARAM_DETAIL );
-          if( "check".equals( detail ) ) {
-            String index = readEventPropertyValue( grid, eventName, EVENT_PARAM_INDEX );
-            item.fireCheckEvent( Integer.valueOf( index ).intValue() );
-          } else {
-            item.fireEvent( SWT.Selection );
-          }
-        } else {
-          item.fireEvent( SWT.DefaultSelection );
-        }
-      }
-    }
-  }
-
+  @SuppressWarnings( "unused" )
   private static boolean hasExpandListener( Grid grid ) {
     // Always render listen for Expand and Collapse, currently required for scrollbar
     // visibility update and setData events.
     return true;
   }
 
+  @SuppressWarnings( "unused" )
   private static boolean hasCollapseListener( Grid grid ) {
     // Always render listen for Expand and Collapse, currently required for scrollbar
     // visibility update and setData events.
     return true;
   }
 
-  /////////////////////////////////
-  // Process expand/collapse events
-
-  private static void processTreeEvent( Grid grid, int eventType, String eventName ) {
-    if( wasEventSent( grid, eventName ) ) {
-      String value = readEventPropertyValue( grid, eventName, ClientMessageConst.EVENT_PARAM_ITEM );
-      Event event = new Event();
-      event.item = getItem( grid, value );
-      grid.notifyListeners( eventType, event );
-    }
-  }
-
   ///////////////
   // Item Metrics
 
diff --git a/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/gridkit/GridOperationHandler.java b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/gridkit/GridOperationHandler.java
new file mode 100644
index 0000000..ee40d41
--- /dev/null
+++ b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/gridkit/GridOperationHandler.java
@@ -0,0 +1,254 @@
+/*******************************************************************************
+ * Copyright (c) 2013 EclipseSource and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    EclipseSource - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.nebula.widgets.grid.internal.gridkit;
+
+import static org.eclipse.rap.rwt.internal.protocol.ClientMessageConst.EVENT_COLLAPSE;
+import static org.eclipse.rap.rwt.internal.protocol.ClientMessageConst.EVENT_DEFAULT_SELECTION;
+import static org.eclipse.rap.rwt.internal.protocol.ClientMessageConst.EVENT_EXPAND;
+import static org.eclipse.rap.rwt.internal.protocol.ClientMessageConst.EVENT_PARAM_INDEX;
+import static org.eclipse.rap.rwt.internal.protocol.ClientMessageConst.EVENT_PARAM_ITEM;
+import static org.eclipse.rap.rwt.internal.protocol.ClientMessageConst.EVENT_SELECTION;
+import static org.eclipse.rap.rwt.internal.protocol.ClientMessageConst.EVENT_SET_DATA;
+
+import org.eclipse.nebula.widgets.grid.Grid;
+import org.eclipse.nebula.widgets.grid.GridItem;
+import org.eclipse.nebula.widgets.grid.internal.IGridAdapter;
+import org.eclipse.rap.json.JsonArray;
+import org.eclipse.rap.json.JsonObject;
+import org.eclipse.rap.json.JsonValue;
+import org.eclipse.rap.rwt.internal.protocol.ControlOperationHandler;
+import org.eclipse.rap.rwt.lifecycle.WidgetUtil;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.internal.widgets.CellToolTipUtil;
+import org.eclipse.swt.internal.widgets.ICellToolTipAdapter;
+import org.eclipse.swt.internal.widgets.ICellToolTipProvider;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.ScrollBar;
+
+
+@SuppressWarnings( "restriction" )
+public class GridOperationHandler extends ControlOperationHandler<Grid> {
+
+  private static final String PROP_SELECTION = "selection";
+  private static final String PROP_SCROLL_LEFT = "scrollLeft";
+  private static final String PROP_TOP_ITEM_INDEX = "topItemIndex";
+  private static final String PROP_FOCUS_ITEM = "focusItem";
+  private static final String METHOD_RENDER_TOOLTIP_TEXT = "renderToolTipText";
+
+  public GridOperationHandler( Grid grid ) {
+    super( grid );
+  }
+
+  @Override
+  public void handleSet( Grid grid, JsonObject properties ) {
+    super.handleSet( grid, properties );
+    handleSetSelection( grid, properties );
+    handleSetScrollLeft( grid, properties );
+    handleSetTopItemIndex( grid, properties );
+    handleSetFocusItem( grid, properties );
+  }
+
+  @Override
+  public void handleCall( Grid grid, String method, JsonObject properties ) {
+    if( METHOD_RENDER_TOOLTIP_TEXT.equals( method ) ) {
+      handleCallRenderToolTipText( grid, properties );
+    }
+  }
+
+  @Override
+  public void handleNotify( Grid grid, String eventName, JsonObject properties ) {
+    if( EVENT_SELECTION.equals( eventName ) ) {
+      handleNotifySelection( grid, properties );
+    } else if( EVENT_DEFAULT_SELECTION.equals( eventName ) ) {
+      handleNotifyDefaultSelection( grid, properties );
+    } else if( EVENT_EXPAND.equals( eventName ) ) {
+      handleNotifyExpand( grid, properties );
+    } else if( EVENT_COLLAPSE.equals( eventName ) ) {
+      handleNotifyCollapse( grid, properties );
+    } else if( EVENT_SET_DATA.equals( eventName ) ) {
+      handleNotifySetData( grid, properties );
+    } else {
+      super.handleNotify( grid, eventName, properties );
+    }
+  }
+
+  /*
+   * PROTOCOL SET selection
+   *
+   * @param selection ([string]) array with ids of selected items
+   */
+  public void handleSetSelection( Grid grid, JsonObject properties ) {
+    JsonValue values = properties.get( PROP_SELECTION );
+    if( values != null ) {
+      JsonArray itemIds = values.asArray();
+      GridItem[] selectedItems = new GridItem[ itemIds.size() ];
+      boolean validItemFound = false;
+      for( int i = 0; i < itemIds.size(); i++ ) {
+        selectedItems[ i ] = getItem( grid, itemIds.get( i ).asString() );
+        if( selectedItems[ i ] != null ) {
+          validItemFound = true;
+        }
+      }
+      if( !validItemFound ) {
+        selectedItems = new GridItem[ 0 ];
+      }
+      grid.setSelection( selectedItems );
+    }
+  }
+
+  /*
+   * PROTOCOL SET scrollLeft
+   *
+   * @param scrollLeft (int) left scroll offset in pixels
+   */
+  public void handleSetScrollLeft( Grid grid, JsonObject properties ) {
+    JsonValue value = properties.get( PROP_SCROLL_LEFT );
+    if( value != null ) {
+      setScrollBarSelection( grid.getHorizontalBar(), value.asInt() );
+    }
+  }
+
+  /*
+   * PROTOCOL SET topItemIndex
+   *
+   * @param topItemIndex (int) visual index of the item, which is on the top of the grid
+   */
+  public void handleSetTopItemIndex( Grid grid, JsonObject properties ) {
+    JsonValue value = properties.get( PROP_TOP_ITEM_INDEX );
+    if( value != null ) {
+      getGridAdapter( grid ).invalidateTopIndex();
+      setScrollBarSelection( grid.getVerticalBar(), value.asInt() );
+    }
+  }
+
+  /*
+   * PROTOCOL SET focusItem
+   *
+   * @param focusItem (string) id of focus item
+   */
+  public void handleSetFocusItem( Grid grid, JsonObject properties ) {
+    JsonValue value = properties.get( PROP_FOCUS_ITEM );
+    if( value != null ) {
+      GridItem item = getItem( grid, value.asString() );
+      if( item != null ) {
+        grid.setFocusItem( item );
+      }
+    }
+  }
+
+  /*
+   * PROTOCOL CALL renderToolTipText
+   *
+   * @param item (string) id of the hovered item
+   * @param column (int) column index of the hovered cell
+   */
+  public void handleCallRenderToolTipText( Grid grid, JsonObject properties ) {
+    ICellToolTipAdapter adapter = CellToolTipUtil.getAdapter( grid );
+    ICellToolTipProvider provider = adapter.getCellToolTipProvider();
+    if( provider != null ) {
+      GridItem item = getItem( grid, properties.get( "item" ).asString() );
+      int columnIndex = properties.get( "column" ).asInt();
+      if( item != null && ( columnIndex == 0 || columnIndex < grid.getColumnCount() ) ) {
+        provider.getToolTipText( item, columnIndex );
+      }
+    }
+  }
+
+  /*
+   * PROTOCOL NOTIFY Selection
+   *
+   * @param altKey (boolean) true if the ALT key was pressed
+   * @param ctrlKey (boolean) true if the CTRL key was pressed
+   * @param shiftKey (boolean) true if the SHIFT key was pressed
+   * @param detail (string) "check" if checkbox is selected, "hyperlink" if RWT hyperlink is
+   *        selected
+   * @param item (string) id of selected item
+   * @param text (string) the value of href attribute or content of the selected RWT hyperlink
+   * @param index (int) index of the selected column
+   */
+  public void handleNotifySelection( Grid grid, JsonObject properties ) {
+    GridItem item = getItem( grid, properties.get( EVENT_PARAM_ITEM ).asString() );
+    if( item != null ) {
+      Event event = createSelectionEvent( SWT.Selection, properties );
+      event.item = item;
+      event.index = readIndex( properties );
+      grid.notifyListeners( SWT.Selection, event );
+    }
+  }
+
+  /*
+   * PROTOCOL NOTIFY DefaultSelection
+   *
+   * @param altKey (boolean) true if the ALT key was pressed
+   * @param ctrlKey (boolean) true if the CTRL key was pressed
+   * @param shiftKey (boolean) true if the SHIFT key was pressed
+   * @param detail (string) "check" is checkbox is selected
+   * @param item (string) id of selected item
+   */
+  public void handleNotifyDefaultSelection( Grid grid, JsonObject properties ) {
+    GridItem item = getItem( grid, properties.get( EVENT_PARAM_ITEM ).asString() );
+    if( item != null ) {
+      Event event = createSelectionEvent( SWT.Selection, properties );
+      event.item = item;
+      grid.notifyListeners( SWT.DefaultSelection, event );
+    }
+  }
+
+  /*
+   * PROTOCOL NOTIFY Expand
+   *
+   * @param item (string) id of expanded item
+   */
+  public void handleNotifyExpand( Grid grid, JsonObject properties ) {
+    Event event = new Event();
+    event.item = getItem( grid, properties.get( EVENT_PARAM_ITEM ).asString() );
+    grid.notifyListeners( SWT.Expand, event );
+  }
+
+  /*
+   * PROTOCOL NOTIFY Collapse
+   *
+   * @param item (string) id of collapsed item
+   */
+  public void handleNotifyCollapse( Grid grid, JsonObject properties ) {
+    Event event = new Event();
+    event.item = getItem( grid, properties.get( EVENT_PARAM_ITEM ).asString() );
+    grid.notifyListeners( SWT.Collapse, event );
+  }
+
+  /*
+   * PROTOCOL NOTIFY SetData
+   * ignored, SetData event is fired when set topItemIndex
+   */
+  @SuppressWarnings( "unused" )
+  public void handleNotifySetData( Grid grid, JsonObject properties ) {
+  }
+
+  private static GridItem getItem( Grid grid, String itemId ) {
+    return ( GridItem )WidgetUtil.find( grid, itemId );
+  }
+
+  private static void setScrollBarSelection( ScrollBar scrollBar, int selection ) {
+    if( scrollBar != null ) {
+      scrollBar.setSelection( selection );
+    }
+  }
+
+  private static int readIndex( JsonObject properties ) {
+    JsonValue value = properties.get( EVENT_PARAM_INDEX );
+    return value == null ? 0 : value.asInt();
+  }
+
+  private static IGridAdapter getGridAdapter( Grid grid ) {
+    return grid.getAdapter( IGridAdapter.class );
+  }
+
+}
diff --git a/tests/org.eclipse.rap.nebula.widgets.grid.test/META-INF/MANIFEST.MF b/tests/org.eclipse.rap.nebula.widgets.grid.test/META-INF/MANIFEST.MF
index 0bb4aa7..158ac9c 100644
--- a/tests/org.eclipse.rap.nebula.widgets.grid.test/META-INF/MANIFEST.MF
+++ b/tests/org.eclipse.rap.nebula.widgets.grid.test/META-INF/MANIFEST.MF
@@ -17,7 +17,7 @@
  org.eclipse.rap.rwt.testfixture.internal.engine;version="[2.0.0,3.0.0)",
  org.eclipse.rap.rwt.testfixture.internal.service;version="[2.0.0,3.0.0)"
 Export-Package: org.eclipse.nebula.widgets.grid,
- org.eclipse.nebula.widgets.grid.internal.gridcolumngroupkip;x-internal:=true,
+ org.eclipse.nebula.widgets.grid.internal.gridcolumngroupkit;x-internal:=true,
  org.eclipse.nebula.widgets.grid.internal.gridcolumnkit;x-internal:=true,
  org.eclipse.nebula.widgets.grid.internal.griditemkit;x-internal:=true,
  org.eclipse.nebula.widgets.grid.internal.gridkit;x-internal:=true
diff --git a/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/gridcolumngroupkip/GridColumnGroupLCA_Test.java b/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/gridcolumngroupkit/GridColumnGroupLCA_Test.java
similarity index 86%
rename from tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/gridcolumngroupkip/GridColumnGroupLCA_Test.java
rename to tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/gridcolumngroupkit/GridColumnGroupLCA_Test.java
index 4bb381b..dffa383 100644
--- a/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/gridcolumngroupkip/GridColumnGroupLCA_Test.java
+++ b/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/gridcolumngroupkit/GridColumnGroupLCA_Test.java
@@ -8,28 +8,30 @@
  * Contributors:
  *    EclipseSource - initial API and implementation
  ******************************************************************************/
-package org.eclipse.nebula.widgets.grid.internal.gridcolumngroupkip;
+package org.eclipse.nebula.widgets.grid.internal.gridcolumngroupkit;
 
 import static org.eclipse.nebula.widgets.grid.GridTestUtil.createGridColumns;
 import static org.eclipse.nebula.widgets.grid.GridTestUtil.loadImage;
 import static org.eclipse.rap.rwt.lifecycle.WidgetUtil.getId;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
 import java.util.Arrays;
-import java.util.LinkedList;
 import java.util.List;
 
-import junit.framework.TestCase;
-
 import org.eclipse.nebula.widgets.grid.Grid;
 import org.eclipse.nebula.widgets.grid.GridColumnGroup;
 import org.eclipse.nebula.widgets.grid.internal.gridcolumngroupkit.GridColumnGroupLCA;
+import org.eclipse.nebula.widgets.grid.internal.gridcolumngroupkit.GridColumnGroupOperationHandler;
 import org.eclipse.rap.json.JsonArray;
 import org.eclipse.rap.json.JsonObject;
 import org.eclipse.rap.json.JsonValue;
 import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.internal.protocol.ClientMessageConst;
+import org.eclipse.rap.rwt.internal.remote.RemoteObjectRegistry;
 import org.eclipse.rap.rwt.lifecycle.WidgetUtil;
+import org.eclipse.rap.rwt.remote.OperationHandler;
 import org.eclipse.rap.rwt.testfixture.Fixture;
 import org.eclipse.rap.rwt.testfixture.Message;
 import org.eclipse.rap.rwt.testfixture.Message.CreateOperation;
@@ -40,13 +42,14 @@
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.internal.graphics.ImageFactory;
 import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.Shell;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
 
 
 @SuppressWarnings("restriction")
-public class GridColumnGroupLCA_Test extends TestCase {
+public class GridColumnGroupLCA_Test {
 
   private Display display;
   private Shell shell;
@@ -54,8 +57,8 @@
   private GridColumnGroup group;
   private GridColumnGroupLCA lca;
 
-  @Override
-  protected void setUp() throws Exception {
+  @Before
+  public void setUp() {
     Fixture.setUp();
     display = new Display();
     shell = new Shell( display );
@@ -65,11 +68,12 @@
     Fixture.fakeNewRequest();
   }
 
-  @Override
-  protected void tearDown() throws Exception {
+  @After
+  public void tearDown() {
     Fixture.tearDown();
   }
 
+  @Test
   public void testRenderCreate() throws IOException {
     lca.renderInitialization( group );
 
@@ -78,6 +82,7 @@
     assertEquals( "rwt.widgets.GridColumnGroup", operation.getType() );
   }
 
+  @Test
   public void testRenderCreateWithAligment() throws IOException {
     group = new GridColumnGroup( grid, SWT.TOGGLE );
 
@@ -89,6 +94,17 @@
     assertTrue( styles.contains( "TOGGLE" ) );
   }
 
+  @Test
+  public void testRenderInitialization_setsOperationHandler() throws IOException {
+    String id = getId( group );
+
+    lca.renderInitialization( group );
+
+    OperationHandler handler = RemoteObjectRegistry.getInstance().get( id ).getHandler();
+    assertTrue( handler instanceof GridColumnGroupOperationHandler );
+  }
+
+  @Test
   public void testRenderParent() throws IOException {
     lca.renderInitialization( group );
 
@@ -97,6 +113,7 @@
     assertEquals( WidgetUtil.getId( group.getParent() ), operation.getParent() );
   }
 
+  @Test
   public void testRenderDispose() throws IOException {
     lca.renderDispose( group );
 
@@ -106,6 +123,7 @@
     assertEquals( WidgetUtil.getId( group ), operation.getTarget() );
   }
 
+  @Test
   public void testRenderInitialText() throws IOException {
     lca.render( group );
 
@@ -114,6 +132,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "text" ) == -1 );
   }
 
+  @Test
   public void testRenderText() throws IOException {
     group.setText( "foo" );
     lca.renderChanges( group );
@@ -122,6 +141,7 @@
     assertEquals( "foo", message.findSetProperty( group, "text" ).asString() );
   }
 
+  @Test
   public void testRenderTextUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( group );
@@ -134,6 +154,7 @@
     assertNull( message.findSetOperation( group, "text" ) );
   }
 
+  @Test
   public void testRenderInitialImage() throws IOException {
     lca.renderChanges( group );
 
@@ -141,6 +162,7 @@
     assertNull( message.findSetOperation( group, "image" ) );
   }
 
+  @Test
   public void testRenderImage() throws IOException {
     Image image = loadImage( display, Fixture.IMAGE_100x50 );
 
@@ -154,6 +176,7 @@
     assertEquals( JsonArray.readFrom( expected ), actual );
   }
 
+  @Test
   public void testRenderImageUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( group );
@@ -167,6 +190,7 @@
     assertNull( message.findSetOperation( group, "image" ) );
   }
 
+  @Test
   public void testRenderImageReset() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( group );
@@ -181,6 +205,7 @@
     assertEquals( JsonObject.NULL, message.findSetProperty( group, "image" ) );
   }
 
+  @Test
   public void testRenderInitialFont() throws IOException {
     lca.render( group );
 
@@ -189,6 +214,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "font" ) == -1 );
   }
 
+  @Test
   public void testRenderFont() throws IOException {
     group.setHeaderFont( new Font( display, "Arial", 20, SWT.BOLD ) );
     lca.renderChanges( group );
@@ -198,6 +224,7 @@
     assertEquals( expected, message.findSetProperty( group, "font" ) );
   }
 
+  @Test
   public void testRenderFontUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( group );
@@ -210,6 +237,7 @@
     assertNull( message.findSetOperation( group, "font" ) );
   }
 
+  @Test
   public void testRenderInitialExpanded() throws IOException {
     lca.render( group );
 
@@ -218,6 +246,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "expanded" ) == -1 );
   }
 
+  @Test
   public void testRenderExpanded() throws IOException {
     group.setExpanded( false );
     lca.renderChanges( group );
@@ -226,6 +255,7 @@
     assertEquals( JsonValue.FALSE, message.findSetProperty( group, "expanded" ) );
   }
 
+  @Test
   public void testRenderExpandedUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( group );
@@ -238,47 +268,7 @@
     assertNull( message.findSetOperation( group, "expanded" ) );
   }
 
-  public void testProcessTreeEvent_Expanded() {
-    List<Event> events = new LinkedList<Event>();
-    group.addListener( SWT.Expand, new LoggingTreeListener( events ) );
-    group.setExpanded( false );
-
-    Fixture.fakeNotifyOperation( getId( group ), ClientMessageConst.EVENT_EXPAND, null );
-    Fixture.readDataAndProcessAction( group );
-
-    assertEquals( 1, events.size() );
-    Event event = events.get( 0 );
-    assertEquals( group, event.widget );
-  }
-
-  public void testProcessTreeEvent_Collapsed() {
-    List<Event> events = new LinkedList<Event>();
-    group.addListener( SWT.Collapse, new LoggingTreeListener( events ) );
-
-    Fixture.fakeNotifyOperation( getId( group ), ClientMessageConst.EVENT_COLLAPSE, null );
-    Fixture.readDataAndProcessAction( group );
-
-    assertEquals( 1, events.size() );
-    Event event = events.get( 0 );
-    assertEquals( group, event.widget );
-  }
-
-  public void testReadExpanded_Expanded() {
-    group.setExpanded( false );
-
-    Fixture.fakeSetProperty( getId( group ), "expanded", true );
-    Fixture.readDataAndProcessAction( group );
-
-    assertTrue( group.getExpanded() );
-  }
-
-  public void testReadExpanded_Collapsed() {
-    Fixture.fakeSetProperty( getId( group ), "expanded", false );
-    Fixture.readDataAndProcessAction( group );
-
-    assertFalse( group.getExpanded() );
-  }
-
+  @Test
   public void testRenderInitialLeft() throws IOException {
     lca.render( group );
 
@@ -287,6 +277,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "left" ) == -1 );
   }
 
+  @Test
   public void testRenderLeft() throws IOException {
     createGridColumns( grid, 3, SWT.NONE );
     grid.getColumn( 1 ).setVisible( false );
@@ -299,6 +290,7 @@
     assertEquals( 90, message.findSetProperty( group, "left" ).asInt() );
   }
 
+  @Test
   public void testRenderLeftUnchanged() throws IOException {
     createGridColumns( grid, 3, SWT.NONE );
     grid.getColumn( 1 ).setVisible( false );
@@ -314,6 +306,7 @@
     assertNull( message.findSetOperation( group, "left" ) );
   }
 
+  @Test
   public void testRenderInitialWidth() throws IOException {
     lca.render( group );
 
@@ -322,6 +315,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "width" ) == -1 );
   }
 
+  @Test
   public void testRenderWidth() throws IOException {
     createGridColumns( group, 1, SWT.NONE );
 
@@ -331,6 +325,7 @@
     assertEquals( 20, message.findSetProperty( group, "width" ).asInt() );
   }
 
+  @Test
   public void testRenderWidthUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( group );
@@ -343,6 +338,7 @@
     assertNull( message.findSetOperation( group, "width" ) );
   }
 
+  @Test
   public void testRenderInitialHeight() throws IOException {
     lca.render( group );
 
@@ -351,6 +347,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "height" ) == -1 );
   }
 
+  @Test
   public void testRenderHeight() throws IOException {
     createGridColumns( group, 1, SWT.NONE );
     grid.setHeaderVisible( true );
@@ -361,6 +358,7 @@
     assertEquals( 31, message.findSetProperty( group, "height" ).asInt() );
   }
 
+  @Test
   public void testRenderHeightUnchanged() throws IOException {
     createGridColumns( group, 1, SWT.NONE );
     Fixture.markInitialized( display );
@@ -374,6 +372,7 @@
     assertNull( message.findSetOperation( group, "height" ) );
   }
 
+  @Test
   public void testRenderInitialVisible() throws IOException {
     createGridColumns( group, 1, SWT.NONE );
 
@@ -384,6 +383,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "visibility" ) == -1 );
   }
 
+  @Test
   public void testRenderVisible() throws IOException {
     createGridColumns( group, 1, SWT.NONE );
 
@@ -394,6 +394,7 @@
     assertEquals( JsonValue.FALSE, message.findSetProperty( group, "visibility" ) );
   }
 
+  @Test
   public void testRenderVisibleUnchanged() throws IOException {
     createGridColumns( group, 1, SWT.NONE );
     Fixture.markInitialized( display );
@@ -407,6 +408,7 @@
     assertNull( message.findSetOperation( group, "visibility" ) );
   }
 
+  @Test
   public void testRenderInitialCustomVariant() throws IOException {
     lca.render( group );
 
@@ -415,6 +417,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "customVariant" ) == -1 );
   }
 
+  @Test
   public void testRenderCustomVariant() throws IOException {
     group.setData( RWT.CUSTOM_VARIANT, "blue" );
     lca.renderChanges( group );
@@ -423,6 +426,7 @@
     assertEquals( "variant_blue", message.findSetProperty( group, "customVariant" ).asString() );
   }
 
+  @Test
   public void testRenderCustomVariantUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( group );
@@ -435,17 +439,4 @@
     assertNull( message.findSetOperation( group, "customVariant" ) );
   }
 
-  //////////////////
-  // Helping classes
-
-  private static class LoggingTreeListener implements Listener {
-    private final List<Event> events;
-    private LoggingTreeListener( List<Event> events ) {
-      this.events = events;
-    }
-    public void handleEvent( Event event ) {
-      events.add( event );
-    }
-  }
-
 }
diff --git a/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/gridcolumngroupkit/GridColumnGroupOperationHandler_Test.java b/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/gridcolumngroupkit/GridColumnGroupOperationHandler_Test.java
new file mode 100644
index 0000000..8b51d44
--- /dev/null
+++ b/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/gridcolumngroupkit/GridColumnGroupOperationHandler_Test.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2013 EclipseSource and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    EclipseSource - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.nebula.widgets.grid.internal.gridcolumngroupkit;
+
+import static org.eclipse.rap.rwt.internal.protocol.ClientMessageConst.EVENT_COLLAPSE;
+import static org.eclipse.rap.rwt.internal.protocol.ClientMessageConst.EVENT_EXPAND;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import org.eclipse.nebula.widgets.grid.Grid;
+import org.eclipse.nebula.widgets.grid.GridColumnGroup;
+import org.eclipse.rap.json.JsonObject;
+import org.eclipse.rap.rwt.lifecycle.PhaseId;
+import org.eclipse.rap.rwt.testfixture.Fixture;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Shell;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+
+@SuppressWarnings( "restriction" )
+public class GridColumnGroupOperationHandler_Test {
+
+  private GridColumnGroup group;
+  private GridColumnGroupOperationHandler handler;
+
+  @Before
+  public void setUp() {
+    Fixture.setUp();
+    Display display = new Display();
+    Shell shell = new Shell( display, SWT.NONE );
+    Grid grid = new Grid( shell, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL );
+    grid.setBounds( 0, 0, 100, 100 );
+    group = mock( GridColumnGroup.class );
+    handler = new GridColumnGroupOperationHandler( group );
+  }
+
+  @After
+  public void tearDown() {
+    Fixture.tearDown();
+  }
+
+  @Test
+  public void testHandleSetЕxpanded_expand() {
+    Fixture.fakePhase( PhaseId.PROCESS_ACTION );
+
+    handler.handleSet( new JsonObject().add( "expanded", true ) );
+
+    verify( group ).setExpanded( true );
+  }
+
+  @Test
+  public void testHandleSetЕxpanded_collaps() {
+    Fixture.fakePhase( PhaseId.PROCESS_ACTION );
+
+    handler.handleSet( new JsonObject().add( "expanded", false ) );
+
+    verify( group ).setExpanded( false );
+  }
+
+  @Test
+  public void testHandleNotifyExpand() {
+    handler.handleNotify( EVENT_EXPAND, new JsonObject() );
+
+    verify( group ).notifyListeners( eq( SWT.Expand ), any( Event.class ) );
+  }
+
+  @Test
+  public void testHandleNotifyCollapse() {
+    handler.handleNotify( EVENT_COLLAPSE, new JsonObject() );
+
+    verify( group ).notifyListeners( eq( SWT.Collapse ), any( Event.class ) );
+  }
+
+}
diff --git a/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/gridcolumnkit/GridColumnLCA_Test.java b/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/gridcolumnkit/GridColumnLCA_Test.java
index 2655a65..a66fcf9 100644
--- a/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/gridcolumnkit/GridColumnLCA_Test.java
+++ b/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/gridcolumnkit/GridColumnLCA_Test.java
@@ -14,13 +14,16 @@
 import static org.eclipse.nebula.widgets.grid.GridTestUtil.loadImage;
 import static org.eclipse.rap.rwt.lifecycle.WidgetUtil.getId;
 import static org.eclipse.rap.rwt.testfixture.Fixture.getProtocolMessage;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
 import java.util.LinkedList;
 import java.util.List;
 
-import junit.framework.TestCase;
-
 import org.eclipse.nebula.widgets.grid.Grid;
 import org.eclipse.nebula.widgets.grid.GridColumn;
 import org.eclipse.nebula.widgets.grid.GridColumnGroup;
@@ -28,8 +31,9 @@
 import org.eclipse.rap.json.JsonObject;
 import org.eclipse.rap.json.JsonValue;
 import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.internal.protocol.ClientMessageConst;
+import org.eclipse.rap.rwt.internal.remote.RemoteObjectRegistry;
 import org.eclipse.rap.rwt.lifecycle.WidgetUtil;
+import org.eclipse.rap.rwt.remote.OperationHandler;
 import org.eclipse.rap.rwt.testfixture.Fixture;
 import org.eclipse.rap.rwt.testfixture.Message;
 import org.eclipse.rap.rwt.testfixture.Message.CreateOperation;
@@ -37,7 +41,6 @@
 import org.eclipse.rap.rwt.testfixture.Message.Operation;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.events.SelectionListener;
 import org.eclipse.swt.graphics.Font;
 import org.eclipse.swt.graphics.Image;
@@ -46,11 +49,13 @@
 import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.Shell;
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Test;
 
 
 @SuppressWarnings("restriction")
-public class GridColumnLCA_Test extends TestCase {
+public class GridColumnLCA_Test {
 
   private Display display;
   private Shell shell;
@@ -58,8 +63,8 @@
   private GridColumn column;
   private GridColumnLCA lca;
 
-  @Override
-  protected void setUp() throws Exception {
+  @Before
+  public void setUp() {
     Fixture.setUp();
     display = new Display();
     shell = new Shell( display );
@@ -69,11 +74,12 @@
     Fixture.fakeNewRequest();
   }
 
-  @Override
-  protected void tearDown() throws Exception {
+  @After
+  public void tearDown() {
     Fixture.tearDown();
   }
 
+  @Test
   public void testRenderCreate() throws IOException {
     lca.renderInitialization( column );
 
@@ -83,6 +89,7 @@
     assertFalse( operation.getPropertyNames().contains( "group" ) );
   }
 
+  @Test
   public void testRenderCreateWithAligment() throws IOException {
     column = new GridColumn( grid, SWT.RIGHT );
 
@@ -94,6 +101,17 @@
     assertEquals( "right", message.findCreateProperty( column, "alignment" ).asString() );
   }
 
+  @Test
+  public void testRenderInitialization_setsOperationHandler() throws IOException {
+    String id = getId( column );
+
+    lca.renderInitialization( column );
+
+    OperationHandler handler = RemoteObjectRegistry.getInstance().get( id ).getHandler();
+    assertTrue( handler instanceof GridColumnOperationHandler );
+  }
+
+  @Test
   public void testRenderParent() throws IOException {
     lca.renderInitialization( column );
 
@@ -102,6 +120,7 @@
     assertEquals( WidgetUtil.getId( column.getParent() ), operation.getParent() );
   }
 
+  @Test
   public void testRenderGroup() throws IOException {
     GridColumnGroup group = new GridColumnGroup( grid, SWT.NONE );
     column = new GridColumn( group, SWT.NONE );
@@ -113,6 +132,7 @@
     assertEquals( getId( group ), operation.getProperty( "group" ).asString() );
   }
 
+  @Test
   public void testRenderDispose() throws IOException {
     lca.renderDispose( column );
 
@@ -143,6 +163,7 @@
     assertNull( message.findSetOperation( column, "toolTipMarkupEnabled" ) );
   }
 
+  @Test
   public void testRenderInitialToolTip() throws IOException {
     lca.render( column );
 
@@ -151,6 +172,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "toolTip" ) == -1 );
   }
 
+  @Test
   public void testRenderToolTip() throws IOException {
     column.setHeaderTooltip( "foo" );
     lca.renderChanges( column );
@@ -159,6 +181,7 @@
     assertEquals( "foo", message.findSetProperty( column, "toolTip" ).asString() );
   }
 
+  @Test
   public void testRenderToolTipUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( column );
@@ -171,6 +194,7 @@
     assertNull( message.findSetOperation( column, "toolTip" ) );
   }
 
+  @Test
   public void testRenderInitialCustomVariant() throws IOException {
     lca.render( column );
 
@@ -179,6 +203,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "customVariant" ) == -1 );
   }
 
+  @Test
   public void testRenderCustomVariant() throws IOException {
     column.setData( RWT.CUSTOM_VARIANT, "blue" );
     lca.renderChanges( column );
@@ -187,6 +212,7 @@
     assertEquals( "variant_blue", message.findSetProperty( column, "customVariant" ).asString() );
   }
 
+  @Test
   public void testRenderCustomVariantUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( column );
@@ -199,6 +225,7 @@
     assertNull( message.findSetOperation( column, "customVariant" ) );
   }
 
+  @Test
   public void testRenderInitialText() throws IOException {
     lca.render( column );
 
@@ -207,6 +234,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "text" ) == -1 );
   }
 
+  @Test
   public void testRenderText() throws IOException {
     column.setText( "foo" );
     lca.renderChanges( column );
@@ -215,6 +243,7 @@
     assertEquals( "foo", message.findSetProperty( column, "text" ).asString() );
   }
 
+  @Test
   public void testRenderTextUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( column );
@@ -227,6 +256,7 @@
     assertNull( message.findSetOperation( column, "text" ) );
   }
 
+  @Test
   public void testRenderInitialImage() throws IOException {
     lca.renderChanges( column );
 
@@ -234,6 +264,7 @@
     assertNull( message.findSetOperation( column, "image" ) );
   }
 
+  @Test
   public void testRenderImage() throws IOException {
     Image image = loadImage( display, Fixture.IMAGE_100x50 );
 
@@ -247,6 +278,7 @@
     assertEquals( JsonArray.readFrom( expected ), actual );
   }
 
+  @Test
   public void testRenderImageUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( column );
@@ -260,6 +292,7 @@
     assertNull( message.findSetOperation( column, "image" ) );
   }
 
+  @Test
   public void testRenderImageReset() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( column );
@@ -274,6 +307,7 @@
     assertEquals( JsonObject.NULL, message.findSetProperty( column, "image" ) );
   }
 
+  @Test
   public void testRenderInitialIndex() throws IOException {
     lca.render( column );
 
@@ -281,6 +315,7 @@
     assertEquals( 0, message.findCreateProperty( column, "index" ).asInt() );
   }
 
+  @Test
   public void testRenderIndex() throws IOException {
     new GridColumn( grid, SWT.NONE, 0 );
     lca.renderChanges( column );
@@ -289,6 +324,7 @@
     assertEquals( 1, message.findSetProperty( column, "index" ).asInt() );
   }
 
+  @Test
   public void testRenderIndexUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( column );
@@ -301,6 +337,7 @@
     assertNull( message.findSetOperation( column, "index" ) );
   }
 
+  @Test
   public void testRenderInitialLeft() throws IOException {
     lca.render( column );
 
@@ -309,6 +346,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "left" ) == -1 );
   }
 
+  @Test
   public void testRenderLeft() throws IOException {
     GridColumn column2 = new GridColumn( grid, SWT.NONE, 0 );
     column2.setWidth( 50 );
@@ -318,6 +356,7 @@
     assertEquals( 50, message.findSetProperty( column, "left" ).asInt() );
   }
 
+  @Test
   public void testRenderLeftUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( column );
@@ -331,6 +370,7 @@
     assertNull( message.findSetOperation( column, "left" ) );
   }
 
+  @Test
   public void testRenderInitialWidth() throws IOException {
     lca.render( column );
 
@@ -338,6 +378,7 @@
     assertEquals( 10, message.findCreateProperty( column, "width" ).asInt() );
   }
 
+  @Test
   public void testRenderWidth() throws IOException {
     column.setWidth( 50 );
     lca.renderChanges( column );
@@ -346,6 +387,7 @@
     assertEquals( 50, message.findSetProperty( column, "width" ).asInt() );
   }
 
+  @Test
   public void testRenderWidthUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( column );
@@ -358,6 +400,7 @@
     assertNull( message.findSetOperation( column, "width" ) );
   }
 
+  @Test
   public void testRenderInitialAlignment() throws IOException {
     lca.render( column );
 
@@ -366,6 +409,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "alignment" ) == -1 );
   }
 
+  @Test
   public void testRenderAlignment() throws IOException {
     column.setAlignment( SWT.RIGHT );
     lca.renderChanges( column );
@@ -374,6 +418,7 @@
     assertEquals( "right", message.findSetProperty( column, "alignment" ).asString() );
   }
 
+  @Test
   public void testRenderAlignmentUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( column );
@@ -386,6 +431,7 @@
     assertNull( message.findSetOperation( column, "alignment" ) );
   }
 
+  @Test
   public void testRenderInitialResizable() throws IOException {
     lca.render( column );
 
@@ -394,6 +440,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "resizable" ) == -1 );
   }
 
+  @Test
   public void testRenderResizable() throws IOException {
     column.setResizeable( false );
     lca.renderChanges( column );
@@ -402,6 +449,7 @@
     assertEquals( JsonValue.FALSE, message.findSetProperty( column, "resizable" ) );
   }
 
+  @Test
   public void testRenderResizableUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( column );
@@ -414,6 +462,7 @@
     assertNull( message.findSetOperation( column, "resizable" ) );
   }
 
+  @Test
   public void testRenderInitialMoveable() throws IOException {
     lca.render( column );
 
@@ -422,6 +471,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "moveable" ) == -1 );
   }
 
+  @Test
   public void testRenderMoveable() throws IOException {
     column.setMoveable( true );
     lca.renderChanges( column );
@@ -430,6 +480,7 @@
     assertEquals( JsonValue.TRUE, message.findSetProperty( column, "moveable" ) );
   }
 
+  @Test
   public void testRenderMoveableUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( column );
@@ -442,6 +493,7 @@
     assertNull( message.findSetOperation( column, "moveable" ) );
   }
 
+  @Test
   public void testRenderInitialVisible() throws IOException {
     lca.render( column );
 
@@ -450,6 +502,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "visibility" ) == -1 );
   }
 
+  @Test
   public void testRenderVisible() throws IOException {
     column.setVisible( false );
     lca.renderChanges( column );
@@ -458,6 +511,7 @@
     assertEquals( JsonValue.FALSE, message.findSetProperty( column, "visibility" ) );
   }
 
+  @Test
   public void testRenderVisibleUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( column );
@@ -470,6 +524,7 @@
     assertNull( message.findSetOperation( column, "visibility" ) );
   }
 
+  @Test
   public void testRenderInitialCheck() throws IOException {
     lca.render( column );
 
@@ -478,6 +533,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "check" ) == -1 );
   }
 
+  @Test
   public void testRenderCheck() throws IOException {
     column = new GridColumn( grid, SWT.CHECK );
 
@@ -487,6 +543,7 @@
     assertEquals( JsonValue.TRUE, message.findSetProperty( column, "check" ) );
   }
 
+  @Test
   public void testRenderCheckUnchanged() throws IOException {
     column = new GridColumn( grid, SWT.CHECK );
     Fixture.markInitialized( display );
@@ -499,6 +556,7 @@
     assertNull( message.findSetOperation( column, "check" ) );
   }
 
+  @Test
   public void testRenderAddSelectionListener() throws Exception {
     Fixture.markInitialized( display );
     Fixture.markInitialized( column );
@@ -511,6 +569,7 @@
     assertEquals( JsonValue.TRUE, message.findListenProperty( column, "Selection" ) );
   }
 
+  @Test
   public void testRenderRemoveSelectionListener() throws Exception {
     SelectionListener listener = new SelectionAdapter() { };
     column.addSelectionListener( listener );
@@ -525,6 +584,7 @@
     assertEquals( JsonValue.FALSE, message.findListenProperty( column, "Selection" ) );
   }
 
+  @Test
   public void testRenderSelectionListenerUnchanged() throws Exception {
     Fixture.markInitialized( display );
     Fixture.markInitialized( column );
@@ -538,6 +598,7 @@
     assertNull( message.findListenOperation( column, "Selection" ) );
   }
 
+  @Test
   public void testReadWidth() {
     final List<Event> events = new LinkedList<Event>();
     GridColumn[] columns = createGridColumns( grid, 2, SWT.NONE );
@@ -566,6 +627,7 @@
     assertEquals( newLeft, message.findSetProperty( columns[ 1 ], "left" ).asInt() );
   }
 
+  @Test
   public void testReadLeft() {
     final List<Event> events = new LinkedList<Event>();
     GridColumn[] columns = createGridColumns( grid, 2, SWT.NONE );
@@ -593,266 +655,7 @@
     assertEquals( 0, message.findSetProperty( columns[ 0 ], "left" ).asInt() );
   }
 
-  public void testMoveColumn_1() {
-    column.dispose();
-    GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
-    columns[ 0 ].setWidth( 10 );
-    columns[ 1 ].setWidth( 20 );
-    columns[ 2 ].setWidth( 30 );
-    // Current order: Col 0: 0..10, Col 1: 11..30, Col 2: 31..60 (as created)
-    // Move Col 1 over Col 0 (left half), thereafter order should be:
-    // Col 1, Col 0, Col 2
-    grid.setColumnOrder( new int[]{
-      0, 1, 2
-    } );
-
-    GridColumnLCA.moveColumn( columns[ 1 ], 3 );
-
-    int[] columnOrder = grid.getColumnOrder();
-    assertEquals( 1, columnOrder[ 0 ] );
-    assertEquals( 0, columnOrder[ 1 ] );
-    assertEquals( 2, columnOrder[ 2 ] );
-  }
-
-  public void testMoveColumn_2() {
-    column.dispose();
-    GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
-    columns[ 0 ].setWidth( 10 );
-    columns[ 1 ].setWidth( 20 );
-    columns[ 2 ].setWidth( 30 );
-    // Current order: Col 1: 0..20, Col 0: 21..30, Col 2: 31..60
-    // Move Col 1 over Col 0 (right half), thereafter order should be:
-    // Col 0, Col 1, Col 2
-    grid.setColumnOrder( new int[]{
-      1, 0, 2
-    } );
-
-    GridColumnLCA.moveColumn( columns[ 1 ], 27 );
-
-    int[] columnOrder = grid.getColumnOrder();
-    assertEquals( 0, columnOrder[ 0 ] );
-    assertEquals( 1, columnOrder[ 1 ] );
-    assertEquals( 2, columnOrder[ 2 ] );
-  }
-
-  public void testMoveColumn_3() {
-    column.dispose();
-    GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
-    columns[ 0 ].setWidth( 10 );
-    columns[ 1 ].setWidth( 20 );
-    columns[ 2 ].setWidth( 30 );
-    // Current order: Col 0: 0..10, Col 1: 11..30, Col 2: 31..60
-    // Move Col 2 over Col 1 (left half), thereafter order should be:
-    // Col 0, Col 2, Col 1
-    grid.setColumnOrder( new int[]{
-      0, 1, 2
-    } );
-
-    GridColumnLCA.moveColumn( columns[ 2 ], 13 );
-
-    int[] columnOrder = grid.getColumnOrder();
-    assertEquals( 0, columnOrder[ 0 ] );
-    assertEquals( 2, columnOrder[ 1 ] );
-    assertEquals( 1, columnOrder[ 2 ] );
-  }
-
-  public void testMoveColumn_4() {
-    column.dispose();
-    GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
-    columns[ 0 ].setWidth( 10 );
-    columns[ 1 ].setWidth( 20 );
-    columns[ 2 ].setWidth( 30 );
-    // Current order: Col 0: 0..10, Col 1: 11..30, Col 2: 31..60
-    // Move Col 2 over Col 1 (right half), thereafter order should be:
-    // Col 2, Col 0, Col 1
-    grid.setColumnOrder( new int[]{
-      0, 1, 2
-    } );
-
-    GridColumnLCA.moveColumn( columns[ 2 ], 3 );
-
-    int[] columnOrder = grid.getColumnOrder();
-    assertEquals( 2, columnOrder[ 0 ] );
-    assertEquals( 0, columnOrder[ 1 ] );
-    assertEquals( 1, columnOrder[ 2 ] );
-  }
-
-  public void testMoveColumn_5() {
-    column.dispose();
-    GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
-    columns[ 0 ].setWidth( 10 );
-    columns[ 1 ].setWidth( 20 );
-    columns[ 2 ].setWidth( 30 );
-    // Current order: Col 0: 0..10, Col 1: 11..30, Col 2: 31..60
-    // Move Col 2 way left of Col 0, thereafter order should be:
-    // Col 2, Col 0, Col 1
-    grid.setColumnOrder( new int[]{
-      0, 1, 2
-    } );
-
-    GridColumnLCA.moveColumn( columns[ 2 ], -30 );
-
-    int[] columnOrder = grid.getColumnOrder();
-    assertEquals( 2, columnOrder[ 0 ] );
-    assertEquals( 0, columnOrder[ 1 ] );
-    assertEquals( 1, columnOrder[ 2 ] );
-  }
-
-  public void testMoveColumn_6() {
-    column.dispose();
-    GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
-    columns[ 0 ].setWidth( 10 );
-    columns[ 1 ].setWidth( 20 );
-    columns[ 2 ].setWidth( 30 );
-    // Current order: Col 0: 0..10, Col 1: 11..30, Col 2: 31..60
-    // Move Col 0 way right of Col 2, thereafter order should be:
-    // Col 1, Col 2, Col 0
-    grid.setColumnOrder( new int[]{
-      0, 1, 2
-    } );
-
-    GridColumnLCA.moveColumn( columns[ 0 ], 100 );
-
-    int[] columnOrder = grid.getColumnOrder();
-    assertEquals( 1, columnOrder[ 0 ] );
-    assertEquals( 2, columnOrder[ 1 ] );
-    assertEquals( 0, columnOrder[ 2 ] );
-  }
-
-  public void testMoveColumn_7() {
-    column.dispose();
-    GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
-    columns[ 0 ].setWidth( 10 );
-    columns[ 1 ].setWidth( 20 );
-    columns[ 2 ].setWidth( 30 );
-    // Current order: Col 0: 0..10, Col 1: 11..30, Col 2: 31..60
-    // Move Col 1 onto itself (left half), order should stay unchanged:
-    // Col 1, Col 2, Col 0
-    grid.setColumnOrder( new int[]{
-      0, 1, 2
-    } );
-
-    GridColumnLCA.moveColumn( columns[ 1 ], 13 );
-
-    int[] columnOrder = grid.getColumnOrder();
-    assertEquals( 0, columnOrder[ 0 ] );
-    assertEquals( 1, columnOrder[ 1 ] );
-    assertEquals( 2, columnOrder[ 2 ] );
-  }
-
-  public void testMoveColumn_8() {
-    column.dispose();
-    GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
-    columns[ 0 ].setWidth( 10 );
-    columns[ 1 ].setWidth( 20 );
-    columns[ 2 ].setWidth( 30 );
-    // Current order: Col 0: 0..10, Col 1: 11..30, Col 2: 31..60
-    // Move Col 0 over Col 2 (left half), order should be:
-    // Col 1, Col 0, Col 2
-    grid.setColumnOrder( new int[]{
-      0, 1, 2
-    } );
-
-    GridColumnLCA.moveColumn( columns[ 0 ], 33 );
-
-    int[] columnOrder = grid.getColumnOrder();
-    assertEquals( 1, columnOrder[ 0 ] );
-    assertEquals( 0, columnOrder[ 1 ] );
-    assertEquals( 2, columnOrder[ 2 ] );
-  }
-
-  public void testMoveColumn_MoveIntoGroup() {
-    column.dispose();
-    createGridColumns( grid, 2, SWT.NONE );
-    GridColumnGroup group = new GridColumnGroup( grid, SWT.NONE );
-    createGridColumns( group, 2, SWT.NONE );
-    grid.getColumn( 0 ).setWidth( 10 );
-    grid.getColumn( 1 ).setWidth( 20 );
-    grid.getColumn( 2 ).setWidth( 30 );
-    grid.getColumn( 3 ).setWidth( 40 );
-    // Current order: Col 0: 0..10, Col 1: 11..30, Col 2: 31..60, Col 3: 61..100
-    // Move Col 0 between Col 2 and Col 3 (inside the group)
-    // Movement should be ignored
-    grid.setColumnOrder( new int[]{
-      0, 1, 2, 3
-    } );
-
-    GridColumnLCA.moveColumn( grid.getColumn( 0 ), 55 );
-
-    int[] columnOrder = grid.getColumnOrder();
-    assertEquals( 0, columnOrder[ 0 ] );
-    assertEquals( 1, columnOrder[ 1 ] );
-    assertEquals( 2, columnOrder[ 2 ] );
-    assertEquals( 3, columnOrder[ 3 ] );
-  }
-
-  public void testMoveColumn_MoveOutsideGroup() {
-    column.dispose();
-    createGridColumns( grid, 2, SWT.NONE );
-    GridColumnGroup group = new GridColumnGroup( grid, SWT.NONE );
-    createGridColumns( group, 2, SWT.NONE );
-    grid.getColumn( 0 ).setWidth( 10 );
-    grid.getColumn( 1 ).setWidth( 20 );
-    grid.getColumn( 2 ).setWidth( 30 );
-    grid.getColumn( 3 ).setWidth( 40 );
-    // Current order: Col 0: 0..10, Col 1: 11..30, Col 2: 31..60, Col 3: 61..100
-    // Move Col 3 between Col 0 and Col 1 (outside the group)
-    // Movement should be ignored
-    grid.setColumnOrder( new int[]{
-      0, 1, 2, 3
-    } );
-
-    GridColumnLCA.moveColumn( grid.getColumn( 3 ), 15 );
-
-    int[] columnOrder = grid.getColumnOrder();
-    assertEquals( 0, columnOrder[ 0 ] );
-    assertEquals( 1, columnOrder[ 1 ] );
-    assertEquals( 2, columnOrder[ 2 ] );
-    assertEquals( 3, columnOrder[ 3 ] );
-  }
-
-  public void testMoveColumn_WithInvisibleColumns() {
-    column.dispose();
-    GridColumn[] columns = createGridColumns( grid, 4, SWT.NONE );
-    columns[ 0 ].setWidth( 10 );
-    columns[ 1 ].setWidth( 20 );
-    columns[ 2 ].setWidth( 30 );
-    columns[ 2 ].setVisible( false );
-    columns[ 3 ].setWidth( 40 );
-    // Current order: Col 0: 0..10, Col 1: 11..30, Col 2: not visible, Col 3: 31..70
-    // Move Col 0 over Col 3 (left half), order should be:
-    // Col 1, Col 2, Col 0, Col 3
-    grid.setColumnOrder( new int[]{
-      0, 1, 2, 3
-    } );
-
-    GridColumnLCA.moveColumn( grid.getColumn( 0 ), 33 );
-
-    int[] columnOrder = grid.getColumnOrder();
-    assertEquals( 1, columnOrder[ 0 ] );
-    assertEquals( 2, columnOrder[ 1 ] );
-    assertEquals( 0, columnOrder[ 2 ] );
-    assertEquals( 3, columnOrder[ 3 ] );
-  }
-
-  public void testReadSelectionEvent() {
-    final List<SelectionEvent> events = new LinkedList<SelectionEvent>();
-    column.addSelectionListener( new SelectionAdapter() {
-      @Override
-      public void widgetSelected( SelectionEvent event ) {
-        events.add( event );
-      }
-    } );
-
-    Fixture.fakeNewRequest();
-    Fixture.fakeNotifyOperation( getId( column ), ClientMessageConst.EVENT_SELECTION, null );
-    Fixture.readDataAndProcessAction( column );
-
-    assertEquals( 1, events.size() );
-    SelectionEvent event = events.get( 0 );
-    assertSame( column, event.widget );
-  }
-
+  @Test
   public void testRenderInitialFont() throws IOException {
     lca.render( column );
 
@@ -861,6 +664,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "font" ) == -1 );
   }
 
+  @Test
   public void testRenderFont() throws IOException {
     column.setHeaderFont( new Font( display, "Arial", 20, SWT.BOLD ) );
     lca.renderChanges( column );
@@ -870,6 +674,7 @@
     assertEquals( JsonArray.readFrom( "[[\"Arial\"], 20, true, false]" ), actual );
   }
 
+  @Test
   public void testRenderFontUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( column );
@@ -882,6 +687,7 @@
     assertNull( message.findSetOperation( column, "font" ) );
   }
 
+  @Test
   public void testRenderInitialFooterFont() throws IOException {
     lca.render( column );
 
@@ -890,6 +696,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "footerFont" ) == -1 );
   }
 
+  @Test
   public void testRenderFooterFont() throws IOException {
     column.setFooterFont( new Font( display, "Arial", 20, SWT.BOLD ) );
     lca.renderChanges( column );
@@ -899,6 +706,7 @@
     assertEquals( JsonArray.readFrom( "[[\"Arial\"], 20, true, false]" ), actual );
   }
 
+  @Test
   public void testRenderFooterFontUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( column );
@@ -911,6 +719,7 @@
     assertNull( message.findSetOperation( column, "footerFont" ) );
   }
 
+  @Test
   public void testRenderInitialFooterText() throws IOException {
     lca.render( column );
 
@@ -919,6 +728,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "footerText" ) == -1 );
   }
 
+  @Test
   public void testRenderFooterText() throws IOException {
     column.setFooterText( "foo" );
     lca.renderChanges( column );
@@ -927,6 +737,7 @@
     assertEquals( "foo", message.findSetProperty( column, "footerText" ).asString() );
   }
 
+  @Test
   public void testRenderFooterTextUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( column );
@@ -939,6 +750,7 @@
     assertNull( message.findSetOperation( column, "footerText" ) );
   }
 
+  @Test
   public void testRenderInitialFooterImage() throws IOException {
     lca.renderChanges( column );
 
@@ -946,6 +758,7 @@
     assertNull( message.findSetOperation( column, "footerImage" ) );
   }
 
+  @Test
   public void testRenderFooterImage() throws IOException {
     Image image = loadImage( display, Fixture.IMAGE_100x50 );
 
@@ -958,6 +771,7 @@
     assertEquals( expected, message.findSetProperty( column, "footerImage" ) );
   }
 
+  @Test
   public void testRenderFooterImageUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( column );
@@ -971,6 +785,7 @@
     assertNull( message.findSetOperation( column, "footerImage" ) );
   }
 
+  @Test
   public void testRenderFooterImageReset() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( column );
diff --git a/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/gridcolumnkit/GridColumnOperationHandler_Test.java b/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/gridcolumnkit/GridColumnOperationHandler_Test.java
new file mode 100644
index 0000000..6e194f4
--- /dev/null
+++ b/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/gridcolumnkit/GridColumnOperationHandler_Test.java
@@ -0,0 +1,372 @@
+/*******************************************************************************
+ * Copyright (c) 2013 EclipseSource and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    EclipseSource - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.nebula.widgets.grid.internal.gridcolumnkit;
+
+import static org.eclipse.nebula.widgets.grid.GridTestUtil.createGridColumns;
+import static org.eclipse.nebula.widgets.grid.internal.gridcolumnkit.GridColumnOperationHandler.moveColumn;
+import static org.eclipse.rap.rwt.internal.protocol.ClientMessageConst.EVENT_DEFAULT_SELECTION;
+import static org.eclipse.rap.rwt.internal.protocol.ClientMessageConst.EVENT_SELECTION;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import org.eclipse.nebula.widgets.grid.Grid;
+import org.eclipse.nebula.widgets.grid.GridColumn;
+import org.eclipse.nebula.widgets.grid.GridColumnGroup;
+import org.eclipse.rap.json.JsonObject;
+import org.eclipse.rap.rwt.lifecycle.PhaseId;
+import org.eclipse.rap.rwt.testfixture.Fixture;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Shell;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+
+@SuppressWarnings( "restriction" )
+public class GridColumnOperationHandler_Test {
+
+  private Display display;
+  private Shell shell;
+  private Grid grid;
+  private GridColumn column;
+  private GridColumnOperationHandler handler;
+
+  @Before
+  public void setUp() {
+    Fixture.setUp();
+    display = new Display();
+    shell = new Shell( display, SWT.NONE );
+    grid = new Grid( shell, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL );
+    grid.setBounds( 0, 0, 100, 100 );
+    column = new GridColumn( grid, SWT.NONE );
+    column.setWidth( 50 );
+    handler = new GridColumnOperationHandler( column );
+  }
+
+  @After
+  public void tearDown() {
+    Fixture.tearDown();
+  }
+
+  @Test
+  public void testHandleNotifySelection() {
+    GridColumn spyColumn = spy( column );
+    handler = new GridColumnOperationHandler( spyColumn );
+    JsonObject properties = new JsonObject()
+      .add( "altKey", true )
+      .add( "shiftKey", true );
+
+    handler.handleNotify( EVENT_SELECTION, properties );
+
+    ArgumentCaptor<Event> captor = ArgumentCaptor.forClass( Event.class );
+    verify( spyColumn ).notifyListeners( eq( SWT.Selection ), captor.capture() );
+    Event event = captor.getValue();
+    assertEquals( SWT.ALT | SWT.SHIFT, event.stateMask );
+  }
+
+  @Test
+  public void testHandleNotifyDefaultSelection() {
+    GridColumn spyColumn = spy( column );
+    handler = new GridColumnOperationHandler( spyColumn );
+    JsonObject properties = new JsonObject()
+      .add( "altKey", true )
+      .add( "shiftKey", true );
+
+    handler.handleNotify( EVENT_DEFAULT_SELECTION, properties );
+
+    ArgumentCaptor<Event> captor = ArgumentCaptor.forClass( Event.class );
+    verify( spyColumn ).notifyListeners( eq( SWT.DefaultSelection ), captor.capture() );
+    Event event = captor.getValue();
+    assertEquals( SWT.ALT | SWT.SHIFT, event.stateMask );
+  }
+
+  @Test
+  public void testHandleCallResize() {
+    Fixture.fakePhase( PhaseId.PROCESS_ACTION );
+    JsonObject properties = new JsonObject().add( "width", 123 );
+
+    handler.handleCall( "resize", properties );
+
+    assertEquals( 123, column.getWidth() );
+  }
+
+  @Test
+  public void testHandleCallMove() {
+    Fixture.fakePhase( PhaseId.PROCESS_ACTION );
+    GridColumn column1 = new GridColumn( grid, SWT.NONE );
+    column1.setWidth( 100 );
+    JsonObject properties = new JsonObject().add( "left", 123 );
+
+    handler.handleCall( "move", properties );
+
+    assertArrayEquals( new int[] { 1, 0 }, grid.getColumnOrder() );
+  }
+
+  @Test
+  public void testMoveColumn_1() {
+    column.dispose();
+    GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
+    columns[ 0 ].setWidth( 10 );
+    columns[ 1 ].setWidth( 20 );
+    columns[ 2 ].setWidth( 30 );
+    // Current order: Col 0: 0..10, Col 1: 11..30, Col 2: 31..60 (as created)
+    // Move Col 1 over Col 0 (left half), thereafter order should be:
+    // Col 1, Col 0, Col 2
+    grid.setColumnOrder( new int[]{
+      0, 1, 2
+    } );
+
+    moveColumn( columns[ 1 ], 3 );
+
+    int[] columnOrder = grid.getColumnOrder();
+    assertEquals( 1, columnOrder[ 0 ] );
+    assertEquals( 0, columnOrder[ 1 ] );
+    assertEquals( 2, columnOrder[ 2 ] );
+  }
+
+  @Test
+  public void testMoveColumn_2() {
+    column.dispose();
+    GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
+    columns[ 0 ].setWidth( 10 );
+    columns[ 1 ].setWidth( 20 );
+    columns[ 2 ].setWidth( 30 );
+    // Current order: Col 1: 0..20, Col 0: 21..30, Col 2: 31..60
+    // Move Col 1 over Col 0 (right half), thereafter order should be:
+    // Col 0, Col 1, Col 2
+    grid.setColumnOrder( new int[]{
+      1, 0, 2
+    } );
+
+    moveColumn( columns[ 1 ], 27 );
+
+    int[] columnOrder = grid.getColumnOrder();
+    assertEquals( 0, columnOrder[ 0 ] );
+    assertEquals( 1, columnOrder[ 1 ] );
+    assertEquals( 2, columnOrder[ 2 ] );
+  }
+
+  @Test
+  public void testMoveColumn_3() {
+    column.dispose();
+    GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
+    columns[ 0 ].setWidth( 10 );
+    columns[ 1 ].setWidth( 20 );
+    columns[ 2 ].setWidth( 30 );
+    // Current order: Col 0: 0..10, Col 1: 11..30, Col 2: 31..60
+    // Move Col 2 over Col 1 (left half), thereafter order should be:
+    // Col 0, Col 2, Col 1
+    grid.setColumnOrder( new int[]{
+      0, 1, 2
+    } );
+
+    moveColumn( columns[ 2 ], 13 );
+
+    int[] columnOrder = grid.getColumnOrder();
+    assertEquals( 0, columnOrder[ 0 ] );
+    assertEquals( 2, columnOrder[ 1 ] );
+    assertEquals( 1, columnOrder[ 2 ] );
+  }
+
+  @Test
+  public void testMoveColumn_4() {
+    column.dispose();
+    GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
+    columns[ 0 ].setWidth( 10 );
+    columns[ 1 ].setWidth( 20 );
+    columns[ 2 ].setWidth( 30 );
+    // Current order: Col 0: 0..10, Col 1: 11..30, Col 2: 31..60
+    // Move Col 2 over Col 1 (right half), thereafter order should be:
+    // Col 2, Col 0, Col 1
+    grid.setColumnOrder( new int[]{
+      0, 1, 2
+    } );
+
+    moveColumn( columns[ 2 ], 3 );
+
+    int[] columnOrder = grid.getColumnOrder();
+    assertEquals( 2, columnOrder[ 0 ] );
+    assertEquals( 0, columnOrder[ 1 ] );
+    assertEquals( 1, columnOrder[ 2 ] );
+  }
+
+  @Test
+  public void testMoveColumn_5() {
+    column.dispose();
+    GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
+    columns[ 0 ].setWidth( 10 );
+    columns[ 1 ].setWidth( 20 );
+    columns[ 2 ].setWidth( 30 );
+    // Current order: Col 0: 0..10, Col 1: 11..30, Col 2: 31..60
+    // Move Col 2 way left of Col 0, thereafter order should be:
+    // Col 2, Col 0, Col 1
+    grid.setColumnOrder( new int[]{
+      0, 1, 2
+    } );
+
+    moveColumn( columns[ 2 ], -30 );
+
+    int[] columnOrder = grid.getColumnOrder();
+    assertEquals( 2, columnOrder[ 0 ] );
+    assertEquals( 0, columnOrder[ 1 ] );
+    assertEquals( 1, columnOrder[ 2 ] );
+  }
+
+  @Test
+  public void testMoveColumn_6() {
+    column.dispose();
+    GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
+    columns[ 0 ].setWidth( 10 );
+    columns[ 1 ].setWidth( 20 );
+    columns[ 2 ].setWidth( 30 );
+    // Current order: Col 0: 0..10, Col 1: 11..30, Col 2: 31..60
+    // Move Col 0 way right of Col 2, thereafter order should be:
+    // Col 1, Col 2, Col 0
+    grid.setColumnOrder( new int[]{
+      0, 1, 2
+    } );
+
+    moveColumn( columns[ 0 ], 100 );
+
+    int[] columnOrder = grid.getColumnOrder();
+    assertEquals( 1, columnOrder[ 0 ] );
+    assertEquals( 2, columnOrder[ 1 ] );
+    assertEquals( 0, columnOrder[ 2 ] );
+  }
+
+  @Test
+  public void testMoveColumn_7() {
+    column.dispose();
+    GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
+    columns[ 0 ].setWidth( 10 );
+    columns[ 1 ].setWidth( 20 );
+    columns[ 2 ].setWidth( 30 );
+    // Current order: Col 0: 0..10, Col 1: 11..30, Col 2: 31..60
+    // Move Col 1 onto itself (left half), order should stay unchanged:
+    // Col 1, Col 2, Col 0
+    grid.setColumnOrder( new int[]{
+      0, 1, 2
+    } );
+
+    moveColumn( columns[ 1 ], 13 );
+
+    int[] columnOrder = grid.getColumnOrder();
+    assertEquals( 0, columnOrder[ 0 ] );
+    assertEquals( 1, columnOrder[ 1 ] );
+    assertEquals( 2, columnOrder[ 2 ] );
+  }
+
+  @Test
+  public void testMoveColumn_8() {
+    column.dispose();
+    GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
+    columns[ 0 ].setWidth( 10 );
+    columns[ 1 ].setWidth( 20 );
+    columns[ 2 ].setWidth( 30 );
+    // Current order: Col 0: 0..10, Col 1: 11..30, Col 2: 31..60
+    // Move Col 0 over Col 2 (left half), order should be:
+    // Col 1, Col 0, Col 2
+    grid.setColumnOrder( new int[]{
+      0, 1, 2
+    } );
+
+    moveColumn( columns[ 0 ], 33 );
+
+    int[] columnOrder = grid.getColumnOrder();
+    assertEquals( 1, columnOrder[ 0 ] );
+    assertEquals( 0, columnOrder[ 1 ] );
+    assertEquals( 2, columnOrder[ 2 ] );
+  }
+
+  @Test
+  public void testMoveColumn_MoveIntoGroup() {
+    column.dispose();
+    createGridColumns( grid, 2, SWT.NONE );
+    GridColumnGroup group = new GridColumnGroup( grid, SWT.NONE );
+    createGridColumns( group, 2, SWT.NONE );
+    grid.getColumn( 0 ).setWidth( 10 );
+    grid.getColumn( 1 ).setWidth( 20 );
+    grid.getColumn( 2 ).setWidth( 30 );
+    grid.getColumn( 3 ).setWidth( 40 );
+    // Current order: Col 0: 0..10, Col 1: 11..30, Col 2: 31..60, Col 3: 61..100
+    // Move Col 0 between Col 2 and Col 3 (inside the group)
+    // Movement should be ignored
+    grid.setColumnOrder( new int[]{
+      0, 1, 2, 3
+    } );
+
+    moveColumn( grid.getColumn( 0 ), 55 );
+
+    int[] columnOrder = grid.getColumnOrder();
+    assertEquals( 0, columnOrder[ 0 ] );
+    assertEquals( 1, columnOrder[ 1 ] );
+    assertEquals( 2, columnOrder[ 2 ] );
+    assertEquals( 3, columnOrder[ 3 ] );
+  }
+
+  @Test
+  public void testMoveColumn_MoveOutsideGroup() {
+    column.dispose();
+    createGridColumns( grid, 2, SWT.NONE );
+    GridColumnGroup group = new GridColumnGroup( grid, SWT.NONE );
+    createGridColumns( group, 2, SWT.NONE );
+    grid.getColumn( 0 ).setWidth( 10 );
+    grid.getColumn( 1 ).setWidth( 20 );
+    grid.getColumn( 2 ).setWidth( 30 );
+    grid.getColumn( 3 ).setWidth( 40 );
+    // Current order: Col 0: 0..10, Col 1: 11..30, Col 2: 31..60, Col 3: 61..100
+    // Move Col 3 between Col 0 and Col 1 (outside the group)
+    // Movement should be ignored
+    grid.setColumnOrder( new int[]{
+      0, 1, 2, 3
+    } );
+
+    moveColumn( grid.getColumn( 3 ), 15 );
+
+    int[] columnOrder = grid.getColumnOrder();
+    assertEquals( 0, columnOrder[ 0 ] );
+    assertEquals( 1, columnOrder[ 1 ] );
+    assertEquals( 2, columnOrder[ 2 ] );
+    assertEquals( 3, columnOrder[ 3 ] );
+  }
+
+  @Test
+  public void testMoveColumn_WithInvisibleColumns() {
+    column.dispose();
+    GridColumn[] columns = createGridColumns( grid, 4, SWT.NONE );
+    columns[ 0 ].setWidth( 10 );
+    columns[ 1 ].setWidth( 20 );
+    columns[ 2 ].setWidth( 30 );
+    columns[ 2 ].setVisible( false );
+    columns[ 3 ].setWidth( 40 );
+    // Current order: Col 0: 0..10, Col 1: 11..30, Col 2: not visible, Col 3: 31..70
+    // Move Col 0 over Col 3 (left half), order should be:
+    // Col 1, Col 2, Col 0, Col 3
+    grid.setColumnOrder( new int[]{
+      0, 1, 2, 3
+    } );
+
+    moveColumn( grid.getColumn( 0 ), 33 );
+
+    int[] columnOrder = grid.getColumnOrder();
+    assertEquals( 1, columnOrder[ 0 ] );
+    assertEquals( 2, columnOrder[ 1 ] );
+    assertEquals( 0, columnOrder[ 2 ] );
+    assertEquals( 3, columnOrder[ 3 ] );
+  }
+
+}
diff --git a/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/griditemkit/GridItemLCA_Test.java b/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/griditemkit/GridItemLCA_Test.java
index 3868c03..104167a 100644
--- a/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/griditemkit/GridItemLCA_Test.java
+++ b/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/griditemkit/GridItemLCA_Test.java
@@ -13,13 +13,14 @@
 import static org.eclipse.nebula.widgets.grid.GridTestUtil.createGridColumns;
 import static org.eclipse.nebula.widgets.grid.GridTestUtil.createGridItems;
 import static org.eclipse.nebula.widgets.grid.GridTestUtil.loadImage;
+import static org.eclipse.rap.rwt.internal.protocol.RemoteObjectFactory.getRemoteObject;
 import static org.eclipse.rap.rwt.lifecycle.WidgetUtil.getId;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
-import java.util.LinkedList;
-import java.util.List;
-
-import junit.framework.TestCase;
 
 import org.eclipse.nebula.widgets.grid.Grid;
 import org.eclipse.nebula.widgets.grid.GridItem;
@@ -27,10 +28,10 @@
 import org.eclipse.rap.json.JsonObject;
 import org.eclipse.rap.json.JsonValue;
 import org.eclipse.rap.rwt.RWT;
-import org.eclipse.rap.rwt.internal.protocol.ClientMessageConst;
 import org.eclipse.rap.rwt.internal.remote.RemoteObjectImpl;
 import org.eclipse.rap.rwt.internal.remote.RemoteObjectRegistry;
 import org.eclipse.rap.rwt.lifecycle.WidgetUtil;
+import org.eclipse.rap.rwt.remote.OperationHandler;
 import org.eclipse.rap.rwt.testfixture.Fixture;
 import org.eclipse.rap.rwt.testfixture.Message;
 import org.eclipse.rap.rwt.testfixture.Message.CreateOperation;
@@ -39,14 +40,14 @@
 import org.eclipse.swt.graphics.Font;
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.Shell;
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Test;
 
 
 @SuppressWarnings("restriction")
-public class GridItemLCA_Test extends TestCase {
+public class GridItemLCA_Test {
 
   private Display display;
   private Shell shell;
@@ -54,8 +55,8 @@
   private GridItem item;
   private GridItemLCA lca;
 
-  @Override
-  protected void setUp() throws Exception {
+  @Before
+  public void setUp() {
     Fixture.setUp();
     display = new Display();
     shell = new Shell( display );
@@ -65,11 +66,12 @@
     Fixture.fakeNewRequest();
   }
 
-  @Override
-  protected void tearDown() throws Exception {
+  @After
+  public void tearDown() {
     Fixture.tearDown();
   }
 
+  @Test
   public void testRenderCreate() throws IOException {
     GridItem[] items = createGridItems( grid, 3, 3 );
 
@@ -81,6 +83,7 @@
     assertEquals( 3, operation.getProperty( "index" ).asInt() );
   }
 
+  @Test
   public void testRenderCreate_WithParentItem() throws IOException {
     GridItem[] items = createGridItems( grid, 3, 3 );
 
@@ -92,6 +95,17 @@
     assertEquals( 1, operation.getProperty( "index" ).asInt() );
   }
 
+  @Test
+  public void testRenderInitialization_setsOperationHandler() throws IOException {
+    String id = getId( item );
+
+    lca.renderInitialization( item );
+
+    OperationHandler handler = RemoteObjectRegistry.getInstance().get( id ).getHandler();
+    assertTrue( handler instanceof GridItemOperationHandler );
+  }
+
+  @Test
   public void testRenderParent() throws IOException {
     lca.renderInitialization( item );
 
@@ -100,6 +114,7 @@
     assertEquals( WidgetUtil.getId( item.getParent() ), operation.getParent() );
   }
 
+  @Test
   public void testRenderParent_WithParentItem() throws IOException {
     GridItem subitem = new GridItem( item, SWT.NONE );
 
@@ -110,6 +125,7 @@
     assertEquals( WidgetUtil.getId( item ), operation.getParent() );
   }
 
+  @Test
   public void testRenderDispose() throws IOException {
     lca.renderDispose( item );
 
@@ -118,6 +134,7 @@
     assertEquals( WidgetUtil.getId( item ), operation.getTarget() );
   }
 
+  @Test
   public void testRenderDispose_WithDisposedGrid() throws IOException {
     grid.dispose();
 
@@ -127,6 +144,7 @@
     assertEquals( 0, message.getOperationCount() );
   }
 
+  @Test
   public void testRenderDispose_WithDisposedParentItem() throws IOException {
     GridItem[] items = createGridItems( grid, 3, 3 );
     items[ 0 ].dispose();
@@ -148,6 +166,7 @@
     assertTrue( remoteObject.isDestroyed() );
   }
 
+  @Test
   public void testRenderInitialCustomVariant() throws IOException {
     lca.render( item );
 
@@ -156,6 +175,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "customVariant" ) == -1 );
   }
 
+  @Test
   public void testRenderCustomVariant() throws IOException {
     item.setData( RWT.CUSTOM_VARIANT, "blue" );
     lca.renderChanges( item );
@@ -164,6 +184,7 @@
     assertEquals( "variant_blue", message.findSetProperty( item, "customVariant" ).asString() );
   }
 
+  @Test
   public void testRenderCustomVariantUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( item );
@@ -176,6 +197,7 @@
     assertNull( message.findSetOperation( item, "customVariant" ) );
   }
 
+  @Test
   public void testRenderInitialItemCount() throws IOException {
     lca.render( item );
 
@@ -184,6 +206,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "itemCount" ) == -1 );
   }
 
+  @Test
   public void testRenderItemCount() throws IOException {
     GridItem[] items = createGridItems( grid, 1, 10 );
     lca.renderChanges( items[ 0 ] );
@@ -192,6 +215,7 @@
     assertEquals( 10, message.findSetProperty( items[ 0 ], "itemCount" ).asInt() );
   }
 
+  @Test
   public void testRenderItemCountUnchanged() throws IOException {
     GridItem[] items = createGridItems( grid, 1, 10 );
     Fixture.markInitialized( display );
@@ -204,6 +228,7 @@
     assertNull( message.findSetOperation( items[ 0 ], "itemCount" ) );
   }
 
+  @Test
   public void testRenderInitialHeight() throws IOException {
     lca.render( item );
 
@@ -212,6 +237,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "height" ) == -1 );
   }
 
+  @Test
   public void testRenderHeight() throws IOException {
     item.setHeight( 10 );
 
@@ -221,6 +247,7 @@
     assertEquals( 10, message.findSetProperty( item, "height" ).asInt() );
   }
 
+  @Test
   public void testRenderHeightUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( item );
@@ -233,6 +260,7 @@
     assertNull( message.findSetOperation( item, "height" ) );
   }
 
+  @Test
   public void testRenderInitialTexts() throws IOException {
     createGridColumns( grid, 2, SWT.NONE );
 
@@ -243,6 +271,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "texts" ) == -1 );
   }
 
+  @Test
   public void testRenderTexts() throws IOException {
     createGridColumns( grid, 2, SWT.NONE );
 
@@ -255,6 +284,7 @@
     assertEquals( expected, message.findSetProperty( item, "texts" ) );
   }
 
+  @Test
   public void testRenderTextsUnchanged() throws IOException {
     createGridColumns( grid, 2, SWT.NONE );
     Fixture.markInitialized( display );
@@ -269,6 +299,7 @@
     assertNull( message.findSetOperation( item, "texts" ) );
   }
 
+  @Test
   public void testRenderInitialImages() throws IOException {
     createGridColumns( grid, 2, SWT.NONE );
 
@@ -279,6 +310,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "images" ) == -1 );
   }
 
+  @Test
   public void testRenderImages() throws IOException {
     createGridColumns( grid, 2, SWT.NONE );
     Image image = loadImage( display, Fixture.IMAGE1 );
@@ -292,6 +324,7 @@
     assertEquals( JsonArray.readFrom( expected ), actual );
   }
 
+  @Test
   public void testRenderImagesUnchanged() throws IOException {
     createGridColumns( grid, 2, SWT.NONE );
     Fixture.markInitialized( display );
@@ -306,6 +339,7 @@
     assertNull( message.findSetOperation( item, "images" ) );
   }
 
+  @Test
   public void testRenderInitialBackground() throws IOException {
     lca.render( item );
 
@@ -314,6 +348,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "background" ) == -1 );
   }
 
+  @Test
   public void testRenderBackground() throws IOException {
     item.setBackground( display.getSystemColor( SWT.COLOR_GREEN ) );
     lca.renderChanges( item );
@@ -323,6 +358,7 @@
     assertEquals( JsonArray.readFrom( "[0,255,0,255]" ), actual );
   }
 
+  @Test
   public void testRenderBackgroundUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( item );
@@ -335,6 +371,7 @@
     assertNull( message.findSetOperation( item, "background" ) );
   }
 
+  @Test
   public void testRenderInitialForeground() throws IOException {
     lca.render( item );
 
@@ -343,6 +380,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "foreground" ) == -1 );
   }
 
+  @Test
   public void testRenderForeground() throws IOException {
     item.setForeground( display.getSystemColor( SWT.COLOR_GREEN ) );
     lca.renderChanges( item );
@@ -352,6 +390,7 @@
     assertEquals( JsonArray.readFrom( "[0,255,0,255]" ), actual );
   }
 
+  @Test
   public void testRenderForegroundUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( item );
@@ -364,6 +403,7 @@
     assertNull( message.findSetOperation( item, "foreground" ) );
   }
 
+  @Test
   public void testRenderInitialFont() throws IOException {
     lca.render( item );
 
@@ -372,6 +412,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "font" ) == -1 );
   }
 
+  @Test
   public void testRenderFont() throws IOException {
     item.setFont( new Font( display, "Arial", 20, SWT.BOLD ) );
     lca.renderChanges( item );
@@ -381,6 +422,7 @@
     assertEquals( JsonArray.readFrom( "[[\"Arial\"], 20, true, false]" ), actual );
   }
 
+  @Test
   public void testRenderFontUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( item );
@@ -393,6 +435,7 @@
     assertNull( message.findSetOperation( item, "font" ) );
   }
 
+  @Test
   public void testRenderInitialCellBackgrounds() throws IOException {
     createGridColumns( grid, 2, SWT.NONE );
 
@@ -403,6 +446,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "cellBackgrounds" ) == -1 );
   }
 
+  @Test
   public void testRenderCellBackgrounds() throws IOException {
     createGridColumns( grid, 2, SWT.NONE );
 
@@ -414,6 +458,7 @@
     assertEquals( JsonArray.readFrom( "[null, [0,255,0,255]]" ), actual );
   }
 
+  @Test
   public void testRenderCellBackgroundsUnchanged() throws IOException {
     createGridColumns( grid, 2, SWT.NONE );
     Fixture.markInitialized( display );
@@ -427,6 +472,7 @@
     assertNull( message.findSetOperation( item, "cellBackgrounds" ) );
   }
 
+  @Test
   public void testRenderInitialCellForegrounds() throws IOException {
     createGridColumns( grid, 2, SWT.NONE );
 
@@ -437,6 +483,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "cellForegrounds" ) == -1 );
   }
 
+  @Test
   public void testRenderCellForegrounds() throws IOException {
     createGridColumns( grid, 2, SWT.NONE );
 
@@ -448,6 +495,7 @@
     assertEquals( JsonArray.readFrom( "[null, [0,255,0,255]]" ), actual );
   }
 
+  @Test
   public void testRenderCellForegroundsUnchanged() throws IOException {
     createGridColumns( grid, 2, SWT.NONE );
     Fixture.markInitialized( display );
@@ -461,6 +509,7 @@
     assertNull( message.findSetOperation( item, "cellForegrounds" ) );
   }
 
+  @Test
   public void testRenderInitialCellFonts() throws IOException {
     createGridColumns( grid, 2, SWT.NONE );
 
@@ -471,6 +520,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "cellFonts" ) == -1 );
   }
 
+  @Test
   public void testRenderCellFonts() throws IOException {
     createGridColumns( grid, 2, SWT.NONE );
 
@@ -482,6 +532,7 @@
     assertEquals( JsonArray.readFrom( "[null, [[\"Arial\"], 20, true, false]]" ), actual );
   }
 
+  @Test
   public void testRenderCellFontsUnchanged() throws IOException {
     createGridColumns( grid, 2, SWT.NONE );
     Fixture.markInitialized( display );
@@ -495,6 +546,7 @@
     assertNull( message.findSetOperation( item, "cellFonts" ) );
   }
 
+  @Test
   public void testRenderInitialExpanded() throws IOException {
     lca.render( item );
 
@@ -503,6 +555,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "expanded" ) == -1 );
   }
 
+  @Test
   public void testRenderExpanded() throws IOException {
     new GridItem( item, SWT.NONE );
 
@@ -513,6 +566,7 @@
     assertEquals( JsonValue.TRUE, message.findSetProperty( item, "expanded" ) );
   }
 
+  @Test
   public void testRenderExpandedUnchanged() throws IOException {
     new GridItem( item, SWT.NONE );
     Fixture.markInitialized( display );
@@ -526,6 +580,7 @@
     assertNull( message.findSetOperation( item, "expanded" ) );
   }
 
+  @Test
   public void testRenderInitialCellChecked() throws IOException {
     grid = new Grid( shell, SWT.CHECK );
     createGridColumns( grid, 2, SWT.NONE );
@@ -538,6 +593,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "cellChecked" ) == -1 );
   }
 
+  @Test
   public void testRenderCellChecked() throws IOException {
     grid = new Grid( shell, SWT.CHECK );
     createGridColumns( grid, 2, SWT.NONE );
@@ -551,6 +607,7 @@
     assertEquals( expected, message.findSetProperty( item, "cellChecked" ) );
   }
 
+  @Test
   public void testRenderCellCheckedUnchanged() throws IOException {
     grid = new Grid( shell, SWT.CHECK );
     createGridColumns( grid, 2, SWT.NONE );
@@ -566,6 +623,7 @@
     assertNull( message.findSetOperation( item, "cellChecked" ) );
   }
 
+  @Test
   public void testRenderInitialCellGrayed() throws IOException {
     grid = new Grid( shell, SWT.CHECK );
     createGridColumns( grid, 2, SWT.NONE );
@@ -578,6 +636,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "cellGrayed" ) == -1 );
   }
 
+  @Test
   public void testRenderCellGrayed() throws IOException {
     grid = new Grid( shell, SWT.CHECK );
     createGridColumns( grid, 2, SWT.NONE );
@@ -591,6 +650,7 @@
     assertEquals( expected, message.findSetProperty( item, "cellGrayed" ) );
   }
 
+  @Test
   public void testRenderGrayedUnchanged() throws IOException {
     grid = new Grid( shell, SWT.CHECK );
     createGridColumns( grid, 2, SWT.NONE );
@@ -606,6 +666,7 @@
     assertNull( message.findSetOperation( item, "cellGrayed" ) );
   }
 
+  @Test
   public void testRenderInitialCellCheckable() throws IOException {
     grid = new Grid( shell, SWT.CHECK );
     createGridColumns( grid, 2, SWT.NONE );
@@ -618,6 +679,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "cellCheckable" ) == -1 );
   }
 
+  @Test
   public void testRenderCellCheckable() throws IOException {
     grid = new Grid( shell, SWT.CHECK );
     createGridColumns( grid, 2, SWT.NONE );
@@ -631,6 +693,7 @@
     assertEquals( expected, message.findSetProperty( item, "cellCheckable" ) );
   }
 
+  @Test
   public void testRenderCellCheckableUnchanged() throws IOException {
     grid = new Grid( shell, SWT.CHECK );
     createGridColumns( grid, 2, SWT.NONE );
@@ -646,60 +709,13 @@
     assertNull( message.findSetOperation( item, "cellCheckable" ) );
   }
 
-  public void testReadChecked() {
-    grid = new Grid( shell, SWT.CHECK );
-    createGridColumns( grid, 3, SWT.NONE );
-    item = new GridItem( grid, SWT.NONE );
-
-    JsonArray cellChecked = new JsonArray()
-      .add( true )
-      .add( false )
-      .add( true );
-    Fixture.fakeSetProperty( getId( item ), "cellChecked", cellChecked );
-    Fixture.readDataAndProcessAction( item );
-
-    assertTrue( item.getChecked( 0 ) );
-    assertFalse( item.getChecked( 1 ) );
-    assertTrue( item.getChecked( 2 ) );
-  }
-
-  public void testProcessTreeEvent_Expanded() {
-    List<Event> events = new LinkedList<Event>();
-    grid.addListener( SWT.Expand, new LoggingTreeListener( events ) );
-    new GridItem( item, SWT.NONE );
-
-    Fixture.fakeSetProperty( getId( item ), "expanded", true );
-    fakeTreeEvent( item, ClientMessageConst.EVENT_EXPAND );
-    Fixture.readDataAndProcessAction( display );
-
-    assertEquals( 1, events.size() );
-    Event event = events.get( 0 );
-    assertEquals( grid, event.widget );
-    assertEquals( item, event.item );
-    assertTrue( item.isExpanded() );
-  }
-
-  public void testProcessTreeEvent_Collapsed() {
-    List<Event> events = new LinkedList<Event>();
-    grid.addListener( SWT.Collapse, new LoggingTreeListener( events ) );
-    new GridItem( item, SWT.NONE );
-    item.setExpanded( true );
-
-    Fixture.fakeSetProperty( getId( item ), "expanded", false );
-    fakeTreeEvent( item, ClientMessageConst.EVENT_COLLAPSE );
-    Fixture.readDataAndProcessAction( display );
-
-    assertEquals( 1, events.size() );
-    Event event = events.get( 0 );
-    assertEquals( grid, event.widget );
-    assertEquals( item, event.item );
-    assertFalse( item.isExpanded() );
-  }
-
+  @Test
   public void testRenderScrollbarsVisibleAfterExpanded() {
     grid.setSize( 200, 200 );
     createGridColumns( grid, 3, SWT.NONE );
     GridItem[] items = createGridItems( grid, 5, 10 );
+    Fixture.markInitialized( items[ 0 ] );
+    getRemoteObject( items[ 0 ] ).setHandler( new GridItemOperationHandler( items[ 0 ] ) );
 
     Fixture.markInitialized( grid );
     Fixture.fakeSetProperty( getId( items[ 0 ] ), "expanded", true );
@@ -737,23 +753,4 @@
     assertEquals( 0, message.getOperationCount() );
   }
 
-  private static void fakeTreeEvent( GridItem item, String eventName ) {
-    JsonObject parameters = new JsonObject()
-      .add( ClientMessageConst.EVENT_PARAM_ITEM, getId( item ) );
-    Fixture.fakeNotifyOperation( getId( item.getParent() ), eventName, parameters );
-  }
-
-  //////////////////
-  // Helping classes
-
-  private static class LoggingTreeListener implements Listener {
-    private final List<Event> events;
-    private LoggingTreeListener( List<Event> events ) {
-      this.events = events;
-    }
-    public void handleEvent( Event event ) {
-      events.add( event );
-    }
-  }
-
 }
diff --git a/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/griditemkit/GridItemOperationHandler_Test.java b/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/griditemkit/GridItemOperationHandler_Test.java
new file mode 100644
index 0000000..e8d8ed7
--- /dev/null
+++ b/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/griditemkit/GridItemOperationHandler_Test.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2013 EclipseSource and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    EclipseSource - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.nebula.widgets.grid.internal.griditemkit;
+
+import static org.eclipse.nebula.widgets.grid.GridTestUtil.createGridColumns;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.nebula.widgets.grid.Grid;
+import org.eclipse.nebula.widgets.grid.GridItem;
+import org.eclipse.rap.json.JsonArray;
+import org.eclipse.rap.json.JsonObject;
+import org.eclipse.rap.rwt.lifecycle.PhaseId;
+import org.eclipse.rap.rwt.testfixture.Fixture;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+
+@SuppressWarnings( "restriction" )
+public class GridItemOperationHandler_Test {
+
+  private Grid grid;
+  private GridItem item;
+  private GridItemOperationHandler handler;
+
+  @Before
+  public void setUp() {
+    Fixture.setUp();
+    Display display = new Display();
+    Shell shell = new Shell( display, SWT.NONE );
+    grid = new Grid( shell, SWT.CHECK );
+    grid.setBounds( 0, 0, 100, 100 );
+    item = new GridItem( grid, SWT.NONE );
+    new GridItem( item, SWT.NONE );
+    handler = new GridItemOperationHandler( item );
+  }
+
+  @After
+  public void tearDown() {
+    Fixture.tearDown();
+  }
+
+  @Test
+  public void testHandleSetChecked() {
+    createGridColumns( grid, 3, SWT.NONE );
+
+    JsonArray cellChecked = new JsonArray()
+      .add( true )
+      .add( false )
+      .add( true );
+    handler.handleSet( new JsonObject().add( "cellChecked", cellChecked ) );
+
+    assertTrue( item.getChecked( 0 ) );
+    assertFalse( item.getChecked( 1 ) );
+    assertTrue( item.getChecked( 2 ) );
+  }
+
+  @Test
+  public void testHandleSetЕxpanded_expand() {
+    Fixture.fakePhase( PhaseId.PROCESS_ACTION );
+
+    handler.handleSet( new JsonObject().add( "expanded", true ) );
+
+    assertTrue( item.isExpanded() );
+  }
+
+  @Test
+  public void testHandleSetЕxpanded_collaps() {
+    Fixture.fakePhase( PhaseId.PROCESS_ACTION );
+    item.setExpanded( true );
+
+    handler.handleSet( new JsonObject().add( "expanded", false ) );
+
+    assertFalse( item.isExpanded() );
+  }
+
+}
diff --git a/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/gridkit/GridLCA_Test.java b/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/gridkit/GridLCA_Test.java
index a3e4fce..309f78a 100644
--- a/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/gridkit/GridLCA_Test.java
+++ b/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/gridkit/GridLCA_Test.java
@@ -13,15 +13,20 @@
 import static org.eclipse.nebula.widgets.grid.GridTestUtil.createGridColumns;
 import static org.eclipse.nebula.widgets.grid.GridTestUtil.createGridItems;
 import static org.eclipse.nebula.widgets.grid.GridTestUtil.loadImage;
+import static org.eclipse.rap.rwt.internal.protocol.RemoteObjectFactory.getRemoteObject;
 import static org.eclipse.rap.rwt.lifecycle.WidgetUtil.getId;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
 
 import java.io.IOException;
 import java.util.Arrays;
-import java.util.LinkedList;
 import java.util.List;
 
-import junit.framework.TestCase;
-
 import org.eclipse.nebula.widgets.grid.Grid;
 import org.eclipse.nebula.widgets.grid.GridColumn;
 import org.eclipse.nebula.widgets.grid.GridItem;
@@ -31,7 +36,9 @@
 import org.eclipse.rap.json.JsonObject;
 import org.eclipse.rap.json.JsonValue;
 import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.internal.remote.RemoteObjectRegistry;
 import org.eclipse.rap.rwt.lifecycle.WidgetUtil;
+import org.eclipse.rap.rwt.remote.OperationHandler;
 import org.eclipse.rap.rwt.testfixture.Fixture;
 import org.eclipse.rap.rwt.testfixture.Message;
 import org.eclipse.rap.rwt.testfixture.Message.CreateOperation;
@@ -41,22 +48,28 @@
 import org.eclipse.swt.events.SelectionAdapter;
 import org.eclipse.swt.events.SelectionListener;
 import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.internal.widgets.CellToolTipUtil;
+import org.eclipse.swt.internal.widgets.ICellToolTipAdapter;
+import org.eclipse.swt.internal.widgets.ICellToolTipProvider;
 import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Event;
-import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Item;
 import org.eclipse.swt.widgets.ScrollBar;
 import org.eclipse.swt.widgets.Shell;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
 
 
-public class GridLCA_Test extends TestCase {
+@SuppressWarnings( "restriction" )
+public class GridLCA_Test {
 
   private Display display;
   private Shell shell;
   private Grid grid;
   private GridLCA lca;
 
-  @Override
-  protected void setUp() throws Exception {
+  @Before
+  public void setUp() {
     Fixture.setUp();
     display = new Display();
     shell = new Shell( display );
@@ -65,11 +78,12 @@
     Fixture.fakeNewRequest();
   }
 
-  @Override
-  protected void tearDown() throws Exception {
+  @After
+  public void tearDown() {
     Fixture.tearDown();
   }
 
+  @Test
   public void testRenderCreate() throws IOException {
     lca.renderInitialization( grid );
 
@@ -83,6 +97,7 @@
     assertTrue( styles.contains( "FULL_SELECTION" ) );
   }
 
+  @Test
   public void testRenderParent() throws IOException {
     lca.renderInitialization( grid );
 
@@ -91,6 +106,7 @@
     assertEquals( getId( grid.getParent() ), operation.getParent() );
   }
 
+  @Test
   public void testRenderCreateWithVirtualMulti() throws IOException {
     grid = new Grid( shell, SWT.VIRTUAL | SWT.MULTI );
 
@@ -104,6 +120,28 @@
     assertEquals( JsonValue.TRUE, message.findListenProperty( grid, "SetData" ) );
   }
 
+  @Test
+  public void testRenderInitialization_setsOperationHandler() throws IOException {
+    String id = getId( grid );
+
+    lca.renderInitialization( grid );
+
+    OperationHandler handler = RemoteObjectRegistry.getInstance().get( id ).getHandler();
+    assertTrue( handler instanceof GridOperationHandler );
+  }
+
+  @Test
+  public void testReadData_usesOperationHandler() {
+    GridOperationHandler handler = spy( new GridOperationHandler( grid ) );
+    getRemoteObject( getId( grid ) ).setHandler( handler );
+
+    Fixture.fakeNotifyOperation( getId( grid ), "Help", new JsonObject() );
+    lca.readData( grid );
+
+    verify( handler ).handleNotifyHelp( grid, new JsonObject() );
+  }
+
+  @Test
   public void testRenderDispose() throws IOException {
     lca.renderDispose( grid );
 
@@ -113,6 +151,7 @@
     assertEquals( getId( grid ), operation.getTarget() );
   }
 
+  @Test
   public void testRenderInitialItemCount() throws IOException {
     lca.render( grid );
 
@@ -121,6 +160,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "itemCount" ) == -1 );
   }
 
+  @Test
   public void testRenderItemCount() throws IOException {
     createGridItems( grid, 10, 3 );
     lca.renderChanges( grid );
@@ -129,6 +169,7 @@
     assertEquals( 10, message.findSetProperty( grid, "itemCount" ).asInt() );
   }
 
+  @Test
   public void testRenderItemCountUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( grid );
@@ -141,6 +182,7 @@
     assertNull( message.findSetOperation( grid, "itemCount" ) );
   }
 
+  @Test
   public void testRenderInitialItemHeight() throws IOException {
     lca.render( grid );
 
@@ -148,6 +190,7 @@
     assertNotNull( message.findSetOperation( grid, "itemHeight" ) );
   }
 
+  @Test
   public void testRenderItemHeight() throws IOException {
     grid.setItemHeight( 40 );
     lca.renderChanges( grid );
@@ -156,6 +199,7 @@
     assertEquals( 40, message.findSetProperty( grid, "itemHeight" ).asInt() );
   }
 
+  @Test
   public void testRenderItemHeightUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( grid );
@@ -168,6 +212,7 @@
     assertNull( message.findSetOperation( grid, "itemHeight" ) );
   }
 
+  @Test
   public void testRenderInitialItemMetrics() throws IOException {
     lca.render( grid );
 
@@ -175,6 +220,7 @@
     assertNotNull( message.findSetOperation( grid, "itemMetrics" ) );
   }
 
+  @Test
   public void testRenderItemMetrics() throws IOException {
     GridColumn column = new GridColumn( grid, SWT.NONE );
     column.setWidth( 50 );
@@ -188,6 +234,7 @@
     assertEquals( JsonArray.readFrom( "[0, 0, 50, 0, 0, 0, 44, 0, 0]" ), actual.get( 0 ) );
   }
 
+  @Test
   public void testRenderItemMetrics_WithCheck() throws IOException {
     createGridColumns( grid, 2, SWT.CHECK );
     GridItem[] items = createGridItems( grid, 3, 1 );
@@ -201,6 +248,7 @@
     assertEquals( JsonArray.readFrom( "[1, 20, 40, 49, 0, 49, 5, 26, 21]" ), actual.get( 1 ) );
   }
 
+  @Test
   public void testRenderItemMetricsUnchanged() throws IOException {
     createGridColumns( grid, 3, SWT.NONE );
     GridItem item = new GridItem( grid, SWT.NONE );
@@ -215,6 +263,7 @@
     assertNull( message.findSetOperation( grid, "itemMetrics" ) );
   }
 
+  @Test
   public void testRenderInitialColumnCount() throws IOException {
     lca.render( grid );
 
@@ -223,6 +272,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "columnCount" ) == -1 );
   }
 
+  @Test
   public void testRenderColumnCount() throws IOException {
     new GridColumn( grid, SWT.NONE );
     lca.renderChanges( grid );
@@ -231,6 +281,7 @@
     assertEquals( 1, message.findSetProperty( grid, "columnCount" ).asInt() );
   }
 
+  @Test
   public void testRenderColumnCountUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( grid );
@@ -243,6 +294,7 @@
     assertNull( message.findSetOperation( grid, "columnCount" ) );
   }
 
+  @Test
   public void testRenderInitialTreeColumn() throws IOException {
     createGridColumns( grid, 2, SWT.NONE );
 
@@ -253,6 +305,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "treeColumn" ) == -1 );
   }
 
+  @Test
   public void testRenderTreeColumn() throws IOException {
     createGridColumns( grid, 2, SWT.NONE );
 
@@ -263,6 +316,7 @@
     assertEquals( 1, message.findSetProperty( grid, "treeColumn" ).asInt() );
   }
 
+  @Test
   public void testRenderTreeColumnUnchanged() throws IOException {
     createGridColumns( grid, 2, SWT.NONE );
     Fixture.markInitialized( display );
@@ -276,6 +330,7 @@
     assertNull( message.findSetOperation( grid, "treeColumn" ) );
   }
 
+  @Test
   public void testRenderInitialHeaderHeight() throws IOException {
     new GridColumn( grid, SWT.NONE );
 
@@ -286,6 +341,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "headerHeight" ) == -1 );
   }
 
+  @Test
   public void testRenderHeaderHeight() throws IOException {
     new GridColumn( grid, SWT.NONE );
     grid.setHeaderVisible( true );
@@ -296,6 +352,7 @@
     assertEquals( 31, message.findSetProperty( grid, "headerHeight" ).asInt() );
   }
 
+  @Test
   public void testRenderHeaderHeightUnchanged() throws IOException {
     new GridColumn( grid, SWT.NONE );
     Fixture.markInitialized( display );
@@ -309,6 +366,7 @@
     assertNull( message.findSetOperation( grid, "headerHeight" ) );
   }
 
+  @Test
   public void testRenderInitialHeaderVisible() throws IOException {
     lca.render( grid );
 
@@ -317,6 +375,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "headerVisible" ) == -1 );
   }
 
+  @Test
   public void testRenderHeaderVisible() throws IOException {
     grid.setHeaderVisible( true );
     lca.renderChanges( grid );
@@ -325,6 +384,7 @@
     assertEquals( JsonValue.TRUE, message.findSetProperty( grid, "headerVisible" ) );
   }
 
+  @Test
   public void testRenderHeaderVisibleUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( grid );
@@ -337,6 +397,7 @@
     assertNull( message.findSetOperation( grid, "headerVisible" ) );
   }
 
+  @Test
   public void testRenderInitialFooterHeight() throws IOException {
     new GridColumn( grid, SWT.NONE );
 
@@ -347,6 +408,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "footerHeight" ) == -1 );
   }
 
+  @Test
   public void testRenderFooterHeight() throws IOException {
     new GridColumn( grid, SWT.NONE );
     grid.setFooterVisible( true );
@@ -357,6 +419,7 @@
     assertEquals( 31, message.findSetProperty( grid, "footerHeight" ).asInt() );
   }
 
+  @Test
   public void testRenderFooterHeightUnchanged() throws IOException {
     new GridColumn( grid, SWT.NONE );
     Fixture.markInitialized( display );
@@ -370,6 +433,7 @@
     assertNull( message.findSetOperation( grid, "footerHeight" ) );
   }
 
+  @Test
   public void testRenderInitialFooterVisible() throws IOException {
     lca.render( grid );
 
@@ -378,6 +442,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "footerVisible" ) == -1 );
   }
 
+  @Test
   public void testRenderFooterVisible() throws IOException {
     grid.setFooterVisible( true );
     lca.renderChanges( grid );
@@ -386,6 +451,7 @@
     assertEquals( JsonValue.TRUE, message.findSetProperty( grid, "footerVisible" ) );
   }
 
+  @Test
   public void testRenderFooterVisibleUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( grid );
@@ -398,6 +464,7 @@
     assertNull( message.findSetOperation( grid, "footerVisible" ) );
   }
 
+  @Test
   public void testRenderInitialLinesVisible() throws IOException {
     lca.render( grid );
 
@@ -405,6 +472,7 @@
     assertEquals( JsonValue.TRUE, message.findSetProperty( grid, "linesVisible" ) );
   }
 
+  @Test
   public void testRenderLinesVisible() throws IOException {
     Fixture.markInitialized( grid );
     grid.setLinesVisible( false );
@@ -414,6 +482,7 @@
     assertEquals( JsonValue.FALSE, message.findSetProperty( grid, "linesVisible" ) );
   }
 
+  @Test
   public void testRenderLinesVisibleUnchanged() throws IOException {
     Fixture.markInitialized( display );
     Fixture.markInitialized( grid );
@@ -426,6 +495,7 @@
     assertNull( message.findSetOperation( grid, "linesVisible" ) );
   }
 
+  @Test
   public void testRenderInitialTopItemIndex() throws IOException {
     grid.setSize( 100, 100 );
 
@@ -436,6 +506,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "topItemIndex" ) == -1 );
   }
 
+  @Test
   public void testRenderTopItemIndex() throws IOException {
     grid.setSize( 100, 100 );
     createGridItems( grid, 10, 3 );
@@ -448,6 +519,7 @@
     assertEquals( 2, message.findSetProperty( grid, "topItemIndex" ).asInt() );
   }
 
+  @Test
   public void testRenderTopItemIndexUnchanged() throws IOException {
     grid.setSize( 100, 100 );
     createGridItems( grid, 10, 3 );
@@ -462,6 +534,7 @@
     assertNull( message.findSetOperation( grid, "topItemIndex" ) );
   }
 
+  @Test
   public void testRenderInitialFocusItem() throws IOException {
     lca.render( grid );
 
@@ -470,6 +543,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "focusItem" ) == -1 );
   }
 
+  @Test
   public void testRenderFocusItem() throws IOException {
     GridItem[] items = createGridItems( grid, 3, 0 );
 
@@ -480,6 +554,7 @@
     assertEquals( getId( items[ 1 ] ), message.findSetProperty( grid, "focusItem" ).asString() );
   }
 
+  @Test
   public void testRenderFocusItemUnchanged() throws IOException {
     GridItem[] items = createGridItems( grid, 3, 0 );
     Fixture.markInitialized( display );
@@ -493,6 +568,7 @@
     assertNull( message.findSetOperation( grid, "focusItem" ) );
   }
 
+  @Test
   public void testRenderInitialScrollLeft() throws IOException {
     createGridColumns( grid, 3, SWT.NONE );
     lca.render( grid );
@@ -502,6 +578,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "scrollLeft" ) == -1 );
   }
 
+  @Test
   public void testRenderScrollLeft() throws IOException {
     createGridColumns( grid, 3, SWT.NONE );
     grid.getHorizontalBar().setSelection( 10 );
@@ -511,6 +588,7 @@
     assertEquals( 10, message.findSetProperty( grid, "scrollLeft" ).asInt() );
   }
 
+  @Test
   public void testRenderScrollLeftUnchanged() throws IOException {
     createGridColumns( grid, 3, SWT.NONE );
     Fixture.markInitialized( display );
@@ -524,6 +602,7 @@
     assertNull( message.findSetOperation( grid, "scrollLeft" ) );
   }
 
+  @Test
   public void testRenderInitialSelection() throws IOException {
     lca.render( grid );
 
@@ -532,6 +611,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "selection" ) == -1 );
   }
 
+  @Test
   public void testRenderSelection() throws IOException {
     GridItem[] items = createGridItems( grid, 3, 3 );
 
@@ -545,6 +625,7 @@
     assertEquals( expected, message.findSetProperty( grid, "selection" ) );
   }
 
+  @Test
   public void testRenderSelectionUnchanged() throws IOException {
     createGridItems( grid, 3, 3 );
     Fixture.markInitialized( display );
@@ -558,6 +639,7 @@
     assertNull( message.findSetOperation( grid, "selection" ) );
   }
 
+  @Test
   public void testRenderInitialSortDirection() throws IOException {
     lca.render( grid );
 
@@ -566,6 +648,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "sortDirection" ) == -1 );
   }
 
+  @Test
   public void testRenderSortDirection() throws IOException {
     GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
 
@@ -576,6 +659,7 @@
     assertEquals( "up", message.findSetProperty( grid, "sortDirection" ).asString() );
   }
 
+  @Test
   public void testRenderSortDirectionUnchanged() throws IOException {
     GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
     Fixture.markInitialized( display );
@@ -589,6 +673,7 @@
     assertNull( message.findSetOperation( grid, "sortDirection" ) );
   }
 
+  @Test
   public void testRenderInitialSortColumn() throws IOException {
     lca.render( grid );
 
@@ -597,6 +682,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "sortColumn" ) == -1 );
   }
 
+  @Test
   public void testRenderSortColumn() throws IOException {
     GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
 
@@ -607,6 +693,7 @@
     assertEquals( getId( columns[ 1 ] ), message.findSetProperty( grid, "sortColumn" ).asString() );
   }
 
+  @Test
   public void testRenderSortColumnUnchanged() throws IOException {
     GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
     Fixture.markInitialized( display );
@@ -620,6 +707,7 @@
     assertNull( message.findSetOperation( grid, "sortColumn" ) );
   }
 
+  @Test
   public void testRenderInitialScrollBarsVisible() throws IOException {
     doFakeRedraw();
 
@@ -630,6 +718,7 @@
     assertNull( message.findSetOperation( grid.getVerticalBar(), "visibility" ) );
   }
 
+  @Test
   public void testRenderScrollBarsVisible_Horizontal() throws IOException {
     grid.setSize( 200, 200 );
     GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
@@ -643,6 +732,7 @@
     assertNull( message.findSetOperation( grid.getVerticalBar(), "visibility" ) );
   }
 
+  @Test
   public void testRenderScrollBarsVisible_Vertical() throws IOException {
     grid.setSize( 200, 200 );
     createGridColumns( grid, 3, SWT.NONE );
@@ -656,6 +746,7 @@
     assertEquals( JsonValue.TRUE, message.findSetProperty( grid.getVerticalBar(), "visibility" ) );
   }
 
+  @Test
   public void testRenderScrollBarsVisibleUnchanged() throws IOException {
     grid.setSize( 200, 200 );
     GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
@@ -675,6 +766,7 @@
     assertNull( message.findSetOperation( grid.getVerticalBar(), "visibility" ) );
   }
 
+  @Test
   public void testRenderAddScrollBarsSelectionListener_Horizontal() throws Exception {
     ScrollBar hScroll = grid.getHorizontalBar();
     Fixture.markInitialized( display );
@@ -689,6 +781,7 @@
     assertEquals( JsonValue.TRUE, message.findListenProperty( hScroll, "Selection" ) );
   }
 
+  @Test
   public void testRenderRemoveScrollBarsSelectionListener_Horizontal() throws Exception {
     ScrollBar hScroll = grid.getHorizontalBar();
     SelectionListener listener = new SelectionAdapter() { };
@@ -705,6 +798,7 @@
     assertEquals( JsonValue.FALSE, message.findListenProperty( hScroll, "Selection" ) );
   }
 
+  @Test
   public void testRenderScrollBarsSelectionListenerUnchanged_Horizontal() throws Exception {
     ScrollBar hScroll = grid.getHorizontalBar();
     Fixture.markInitialized( display );
@@ -720,6 +814,7 @@
     assertNull( message.findListenOperation( hScroll, "Selection" ) );
   }
 
+  @Test
   public void testRenderAddScrollBarsSelectionListener_Vertical() throws Exception {
     ScrollBar vScroll = grid.getVerticalBar();
     Fixture.markInitialized( display );
@@ -734,6 +829,7 @@
     assertEquals( JsonValue.TRUE, message.findListenProperty( vScroll, "Selection" ) );
   }
 
+  @Test
   public void testRenderRemoveScrollBarsSelectionListener_Vertical() throws Exception {
     ScrollBar vScroll = grid.getVerticalBar();
     SelectionListener listener = new SelectionAdapter() { };
@@ -750,6 +846,7 @@
     assertEquals( JsonValue.FALSE, message.findListenProperty( vScroll, "Selection" ) );
   }
 
+  @Test
   public void testRenderScrollBarsSelectionListenerUnchanged_Vertical() throws Exception {
     ScrollBar vScroll = grid.getVerticalBar();
     Fixture.markInitialized( display );
@@ -765,6 +862,7 @@
     assertNull( message.findListenOperation( vScroll, "Selection" ) );
   }
 
+  @Test
   public void testRenderAddSelectionListener() throws Exception {
     Fixture.markInitialized( display );
     Fixture.markInitialized( grid );
@@ -778,6 +876,7 @@
     assertEquals( JsonValue.TRUE, message.findListenProperty( grid, "DefaultSelection" ) );
   }
 
+  @Test
   public void testRenderRemoveSelectionListener() throws Exception {
     SelectionListener listener = new SelectionAdapter() { };
     grid.addSelectionListener( listener );
@@ -793,6 +892,7 @@
     assertEquals( JsonValue.FALSE, message.findListenProperty( grid, "DefaultSelection" ) );
   }
 
+  @Test
   public void testRenderSelectionListenerUnchanged() throws Exception {
     Fixture.markInitialized( display );
     Fixture.markInitialized( grid );
@@ -807,6 +907,7 @@
     assertNull( message.findListenOperation( grid, "DefaultSelection" ) );
   }
 
+  @Test
   public void testRenderInitialEnableCellToolTip() throws IOException {
     lca.render( grid );
 
@@ -815,6 +916,7 @@
     assertTrue( operation.getPropertyNames().indexOf( "enableCellToolTip" ) == -1 );
   }
 
+  @Test
   public void testRenderEnableCellToolTip() throws IOException {
     createGridColumns( grid, 3, SWT.NONE );
     GridItem item = new GridItem( grid, SWT.NONE );
@@ -826,6 +928,7 @@
     assertEquals( JsonValue.TRUE, message.findSetProperty( grid, "enableCellToolTip" ) );
   }
 
+  @Test
   public void testRenderEnableCellToolTipUnchanged() throws IOException {
     createGridColumns( grid, 3, SWT.NONE );
     GridItem item = new GridItem( grid, SWT.NONE );
@@ -840,7 +943,9 @@
     assertNull( message.findSetOperation( grid, "enableCellToolTip" ) );
   }
 
+  @Test
   public void testRenderCellToolTipText() {
+    getRemoteObject( grid ).setHandler( new GridOperationHandler( grid ) );
     createGridColumns( grid, 3, SWT.NONE );
     GridItem item = new GridItem( grid, SWT.NONE );
     item.setToolTipText( 1, "foo" );
@@ -854,119 +959,37 @@
     assertEquals( "foo", message.findSetProperty( grid, "cellToolTipText" ).asString() );
   }
 
-  public void testReadSelection() {
-    GridItem[] items = createGridItems( grid, 3, 0 );
-    Fixture.fakeNewRequest();
-    Fixture.fakeSetProperty( getId( grid ),
-                              "selection",
-                              createArray( getId( items[ 0 ] ), getId( items[ 2 ] ) ) );
-    Fixture.readDataAndProcessAction( grid );
+  @Test
+  public void testRenderCellToolTipText_resetsText() throws IOException {
+    ICellToolTipAdapter adapter = CellToolTipUtil.getAdapter( grid );
+    adapter.setCellToolTipText( "foo" );
 
-    GridItem[] selectedItems = grid.getSelection();
-    assertEquals( 2, selectedItems.length );
-    assertSame( items[ 0 ], selectedItems[ 0 ] );
-    assertSame( items[ 2 ], selectedItems[ 1 ] );
+    lca.renderChanges( grid );
+
+    assertNull( adapter.getCellToolTipText() );
   }
 
-  public void testReadSelectionDisposedItem() {
-    GridItem[] items = createGridItems( grid, 3, 0 );
-    items[ 0 ].dispose();
+  @Test
+  public void testRenderCellToolTipTextNull() {
+    getRemoteObject( grid ).setHandler( new GridOperationHandler( grid ) );
+    Fixture.markInitialized( display );
+    Fixture.markInitialized( grid );
+    createGridItems( grid, 5, 5 );
+    final ICellToolTipAdapter adapter = CellToolTipUtil.getAdapter( grid );
+    adapter.setCellToolTipProvider( new ICellToolTipProvider() {
+      public void getToolTipText( Item item, int columnIndex ) {
+        adapter.setCellToolTipText( null );
+      }
+    } );
 
-    Fixture.fakeNewRequest();
-    Fixture.fakeSetProperty( getId( grid ),
-                              "selection",
-                              createArray( getId( items[ 0 ] ), getId( items[ 2 ] ) ) );
-    Fixture.readDataAndProcessAction( grid );
+    String itemId = WidgetUtil.getId( grid.getItem( 2 ) );
+    processCellToolTipRequest( grid, itemId, 0 );
 
-    GridItem[] selectedItems = grid.getSelection();
-    assertEquals( 1, selectedItems.length );
-    assertSame( items[ 2 ], selectedItems[ 0 ] );
+    Message message = Fixture.getProtocolMessage();
+    assertNull( message.findSetOperation( grid, "cellToolTipText" ) );
   }
 
-  public void testReadScrollLeft() {
-    grid.setSize( 100, 100 );
-    createGridColumns( grid, 5, SWT.NONE );
-    createGridItems( grid, 10, 0 );
-
-    Fixture.fakeNewRequest();
-    Fixture.fakeSetProperty( getId( grid ), "scrollLeft", 30 );
-    Fixture.readDataAndProcessAction( grid );
-
-    assertEquals( 30, grid.getHorizontalBar().getSelection() );
-  }
-
-  public void testReadTopIndex() {
-    grid.setSize( 100, 100 );
-    createGridColumns( grid, 5, SWT.NONE );
-    GridItem[] items = createGridItems( grid, 10, 3 );
-    items[ 4 ].setExpanded( true );
-
-    Fixture.fakeNewRequest();
-    Fixture.fakeSetProperty( getId( grid ), "topItemIndex", 3 );
-    Fixture.readDataAndProcessAction( grid );
-
-    assertEquals( 3, grid.getVerticalBar().getSelection() );
-    assertEquals( 6, grid.getTopIndex() );
-  }
-
-  public void testProcessSelectionEvent() {
-    List<Event> events = new LinkedList<Event>();
-    GridItem item = new GridItem( grid, SWT.NONE );
-    grid.addListener( SWT.Selection, new LoggingListener( events ) );
-
-    Fixture.fakeNewRequest();
-    JsonObject parameters = new JsonObject().add( "item", getId( item ) );
-    Fixture.fakeNotifyOperation( getId( grid ), "Selection", parameters );
-    Fixture.readDataAndProcessAction( display );
-
-    assertEquals( 1, events.size() );
-    Event event = events.get( 0 );
-    assertEquals( SWT.Selection, event.type );
-    assertEquals( grid, event.widget );
-    assertEquals( item, event.item );
-    assertEquals( SWT.NONE, event.detail );
-  }
-
-  public void testProcessSelectionEvent_Check() {
-    List<Event> events = new LinkedList<Event>();
-    GridItem item = new GridItem( grid, SWT.NONE );
-    grid.addListener( SWT.Selection, new LoggingListener( events ) );
-
-    Fixture.fakeNewRequest();
-    JsonObject parameters = new JsonObject()
-      .add( "item", getId( item ) )
-      .add( "detail", "check" )
-      .add( "index", 3 );
-    Fixture.fakeNotifyOperation( getId( grid ), "Selection", parameters );
-    Fixture.readDataAndProcessAction( display );
-
-    assertEquals( 1, events.size() );
-    Event event = events.get( 0 );
-    assertEquals( SWT.Selection, event.type );
-    assertEquals( grid, event.widget );
-    assertEquals( item, event.item );
-    assertEquals( SWT.CHECK, event.detail );
-    assertEquals( 3, event.index );
-  }
-
-  public void testProcessDefaultSelectionEvent() {
-    List<Event> events = new LinkedList<Event>();
-    GridItem item = new GridItem( grid, SWT.NONE );
-    grid.addListener( SWT.DefaultSelection, new LoggingListener( events ) );
-
-    Fixture.fakeNewRequest();
-    JsonObject parameters = new JsonObject().add( "item", getId( item ) );
-    Fixture.fakeNotifyOperation( getId( grid ), "DefaultSelection", parameters );
-    Fixture.readDataAndProcessAction( display );
-
-    assertEquals( 1, events.size() );
-    Event event = events.get( 0 );
-    assertEquals( SWT.DefaultSelection, event.type );
-    assertEquals( grid, event.widget );
-    assertEquals( item, event.item );
-    assertEquals( SWT.NONE, event.detail );
-  }
-
+  @Test
   public void testGetItemMetrics_CellLeft() {
     GridColumn[] columns = createGridColumns( grid, 2, SWT.NONE );
     columns[ 0 ].setWidth( 100 );
@@ -978,6 +1001,7 @@
     assertEquals( 100, metrics[ 1 ].left );
   }
 
+  @Test
   public void testGetItemMetrics_CellWidth() {
     GridColumn[] columns = createGridColumns( grid, 2, SWT.NONE );
     columns[ 0 ].setWidth( 100 );
@@ -989,6 +1013,7 @@
     assertEquals( 150, metrics[ 1 ].width );
   }
 
+  @Test
   public void testGetItemMetrics_ImageLeft() {
     Image image1 = loadImage( display, Fixture.IMAGE_100x50 );
     Image image2 = loadImage( display, Fixture.IMAGE_50x100 );
@@ -1009,6 +1034,7 @@
     assertEquals( 106, metrics[ 1 ].imageLeft );
   }
 
+  @Test
   public void testGetItemMetrics_ImageWidth() {
     Image image1 = loadImage( display, Fixture.IMAGE_100x50 );
     Image image2 = loadImage( display, Fixture.IMAGE_50x100 );
@@ -1033,6 +1059,7 @@
     assertEquals( 0, metrics[ 0 ].imageWidth );
   }
 
+  @Test
   public void testGetItemMetrics_TextLeftWithImage() {
     Image image = loadImage( display, Fixture.IMAGE_100x50 );
     GridColumn[] columns = createGridColumns( grid, 2, SWT.NONE );
@@ -1049,6 +1076,7 @@
     assertEquals( 206, metrics[ 1 ].textLeft );
   }
 
+  @Test
   public void testGetItemMetrics_TextLeftWithCheckbox() {
     Image image = loadImage( display, Fixture.IMAGE_100x50 );
     grid = new Grid( shell, SWT.CHECK );
@@ -1063,6 +1091,7 @@
     assertEquals( 123, metrics[ 0 ].textLeft );
   }
 
+  @Test
   public void testGetItemMetrics_TextWidthWithCheckbox() {
     Image image = loadImage( display, Fixture.IMAGE_100x50 );
     grid = new Grid( shell, SWT.CHECK );
@@ -1077,6 +1106,7 @@
     assertEquals( 71, metrics[ 0 ].textWidth );
   }
 
+  @Test
   public void testRenderMarkupEnabled() throws IOException {
     grid.setData( RWT.MARKUP_ENABLED, Boolean.TRUE );
 
@@ -1086,6 +1116,7 @@
     assertEquals( JsonValue.TRUE, message.findCreateProperty( grid, "markupEnabled" ) );
   }
 
+  @Test
   public void testRenderAddExpandListener() throws Exception {
     lca.renderChanges( grid );
 
@@ -1093,6 +1124,7 @@
     assertEquals( JsonValue.TRUE, message.findListenProperty( grid, "Expand" ) );
   }
 
+  @Test
   public void testRenderAddCollapseListener() throws Exception {
     lca.renderChanges( grid );
 
@@ -1100,6 +1132,7 @@
     assertEquals( JsonValue.TRUE, message.findListenProperty( grid, "Collapse" ) );
   }
 
+  @Test
   public void testDontRenderSetDataListenerTwice() throws Exception {
     grid = new Grid( shell, SWT.VIRTUAL | SWT.MULTI );
     Fixture.markInitialized( display );
@@ -1112,6 +1145,7 @@
     assertNull( message.findListenOperation( grid, "SetData" ) );
   }
 
+  @Test
   public void testDontRenderSetDataWithoutVirtual() throws Exception {
     Fixture.markInitialized( display );
     Fixture.markInitialized( grid );
@@ -1123,23 +1157,6 @@
     assertNull( message.findListenOperation( grid, "SetData" ) );
   }
 
-  public void testReadFocusItem() {
-    GridItem[] items = createGridItems( grid, 3, 1 );
-
-    Fixture.fakeSetProperty( getId( grid ), "focusItem", getId( items[ 2 ] ) );
-    lca.readData( grid );
-
-    assertSame( items[ 2 ], grid.getFocusItem() );
-  }
-
-  private static JsonValue createArray( String... values ) {
-    JsonArray array = new JsonArray();
-    for( int i = 0; i < values.length; i++ ) {
-      array.add( values[ i ] );
-    }
-    return array;
-  }
-
   //////////////////
   // Helping methods
 
@@ -1156,17 +1173,4 @@
     grid.getAdapter( IGridAdapter.class ).doRedraw();
   }
 
-  //////////////////
-  // Helping classes
-
-  private static class LoggingListener implements Listener {
-    private final List<Event> events;
-    private LoggingListener( List<Event> events ) {
-      this.events = events;
-    }
-    public void handleEvent( Event event ) {
-      events.add( event );
-    }
-  }
-
 }
diff --git a/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/gridkit/GridOperationHandler_Test.java b/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/gridkit/GridOperationHandler_Test.java
new file mode 100644
index 0000000..e48469b
--- /dev/null
+++ b/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/gridkit/GridOperationHandler_Test.java
@@ -0,0 +1,281 @@
+/*******************************************************************************
+ * Copyright (c) 2013 EclipseSource and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    EclipseSource - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.nebula.widgets.grid.internal.gridkit;
+
+import static org.eclipse.nebula.widgets.grid.GridTestUtil.createGridItems;
+import static org.eclipse.rap.rwt.internal.protocol.ClientMessageConst.EVENT_COLLAPSE;
+import static org.eclipse.rap.rwt.internal.protocol.ClientMessageConst.EVENT_DEFAULT_SELECTION;
+import static org.eclipse.rap.rwt.internal.protocol.ClientMessageConst.EVENT_EXPAND;
+import static org.eclipse.rap.rwt.internal.protocol.ClientMessageConst.EVENT_SELECTION;
+import static org.eclipse.rap.rwt.internal.protocol.ClientMessageConst.EVENT_SET_DATA;
+import static org.eclipse.rap.rwt.lifecycle.WidgetUtil.getId;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import org.eclipse.nebula.widgets.grid.Grid;
+import org.eclipse.nebula.widgets.grid.GridItem;
+import org.eclipse.rap.json.JsonArray;
+import org.eclipse.rap.json.JsonObject;
+import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.testfixture.Fixture;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.internal.widgets.CellToolTipUtil;
+import org.eclipse.swt.internal.widgets.ICellToolTipAdapter;
+import org.eclipse.swt.internal.widgets.ICellToolTipProvider;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Item;
+import org.eclipse.swt.widgets.Shell;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+
+@SuppressWarnings( "restriction" )
+public class GridOperationHandler_Test {
+
+  private Display display;
+  private Shell shell;
+  private Grid grid;
+  private GridOperationHandler handler;
+
+  @Before
+  public void setUp() {
+    Fixture.setUp();
+    display = new Display();
+    shell = new Shell( display, SWT.NONE );
+    grid = new Grid( shell, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL );
+    grid.setBounds( 0, 0, 100, 100 );
+    handler = new GridOperationHandler( grid );
+  }
+
+  @After
+  public void tearDown() {
+    Fixture.tearDown();
+  }
+
+  @Test
+  public void testHandleSetSelection_single() {
+    createGridItems( grid, 3, 3 );
+    GridItem item = grid.getItem( 1 );
+
+    JsonArray selection = new JsonArray().add( getId( item ) );
+    handler.handleSet( new JsonObject().add( "selection", selection ) );
+
+    GridItem[] selectedItems = grid.getSelection();
+    assertEquals( 1, selectedItems.length );
+    assertSame( item, selectedItems[ 0 ] );
+  }
+
+  @Test
+  public void testHandleSetSelection_multi() {
+    createGridItems( grid, 3, 3 );
+    GridItem item1 = grid.getItem( 0 );
+    GridItem item2 = grid.getItem( 2 );
+
+    JsonArray selection = new JsonArray().add( getId( item1 ) ).add( getId( item2 ) );
+    handler.handleSet( new JsonObject().add( "selection", selection ) );
+
+    GridItem[] selectedItems = grid.getSelection();
+    assertEquals( 2, selectedItems.length );
+    assertSame( item1, selectedItems[ 0 ] );
+    assertSame( item2, selectedItems[ 1 ] );
+  }
+
+  @Test
+  public void testHandleSetSelection_disposedItem() {
+    createGridItems( grid, 3, 3 );
+    GridItem item1 = grid.getItem( 0 );
+    item1.dispose();
+    GridItem item2 = grid.getItem( 2 );
+
+    JsonArray selection = new JsonArray().add( getId( item1 ) ).add( getId( item2 ) );
+    handler.handleSet( new JsonObject().add( "selection", selection ) );
+
+    GridItem[] selectedItems = grid.getSelection();
+    assertEquals( 1, selectedItems.length );
+    assertSame( item2, selectedItems[ 0 ] );
+  }
+
+  @Test
+  public void testHandleSetScrollLeft() {
+    createGridItems( grid, 3, 3 );
+    GridItem item = grid.getItem( 0 );
+    item.setText( "very long text that makes horizontal bar visible" );
+
+    handler.handleSet( new JsonObject().add( "scrollLeft", 1 ) );
+
+    assertEquals( 1, grid.getHorizontalBar().getSelection() );
+  }
+
+  @Test
+  public void testHandleSetTopItemIndex() {
+    GridItem[] items = createGridItems( grid, 10, 3 );
+    items[ 4 ].setExpanded( true );
+
+    handler.handleSet( new JsonObject().add( "topItemIndex", 3 ) );
+
+    assertEquals( 3, grid.getVerticalBar().getSelection() );
+    assertEquals( 6, grid.getTopIndex() );
+  }
+
+  @Test
+  public void testHandleSetFocusItem() {
+    GridItem[] items = createGridItems( grid, 3, 1 );
+
+    handler.handleSet( new JsonObject().add( "focusItem", getId( items[ 2 ] ) ) );
+
+    assertSame( items[ 2 ], grid.getFocusItem() );
+  }
+
+  @Test
+  public void testHandleCallRenderToolTipText() {
+    GridItem item = new GridItem( grid, SWT.NONE );
+    final ICellToolTipAdapter adapter = CellToolTipUtil.getAdapter( grid );
+    adapter.setCellToolTipProvider( new ICellToolTipProvider() {
+      public void getToolTipText( Item item, int columnIndex ) {
+        StringBuilder buffer = new StringBuilder();
+        buffer.append( getId( item ) );
+        buffer.append( "," );
+        buffer.append( columnIndex );
+        adapter.setCellToolTipText( buffer.toString() );
+      }
+    } );
+
+    JsonObject properties = new JsonObject().add( "item", getId( item ) ).add( "column", 0 );
+    handler.handleCall( "renderToolTipText", properties );
+
+    assertEquals( getId( item ) + ",0", CellToolTipUtil.getAdapter( grid ).getCellToolTipText() );
+  }
+
+  @Test
+  public void testHandleNotifySelection() {
+    Grid spyGrid = spy( grid );
+    handler = new GridOperationHandler( spyGrid );
+    GridItem item = new GridItem( spyGrid, SWT.NONE );
+
+    JsonObject properties = new JsonObject()
+      .add( "altKey", true )
+      .add( "shiftKey", true )
+      .add( "item", getId( item ) );
+    handler.handleNotify( EVENT_SELECTION, properties );
+
+    ArgumentCaptor<Event> captor = ArgumentCaptor.forClass( Event.class );
+    verify( spyGrid ).notifyListeners( eq( SWT.Selection ), captor.capture() );
+    Event event = captor.getValue();
+    assertEquals( SWT.ALT | SWT.SHIFT, event.stateMask );
+    assertEquals( item, event.item );
+  }
+
+  @Test
+  public void testHandleNotifySelection_withDetail_hyperlink() {
+    Grid spyGrid = spy( grid );
+    handler = new GridOperationHandler( spyGrid );
+    GridItem item = new GridItem( spyGrid, SWT.NONE );
+
+    JsonObject properties = new JsonObject()
+      .add( "item", getId( item ) )
+      .add( "detail", "hyperlink" )
+      .add( "text", "foo" );
+    handler.handleNotify( EVENT_SELECTION, properties );
+
+    ArgumentCaptor<Event> captor = ArgumentCaptor.forClass( Event.class );
+    verify( spyGrid ).notifyListeners( eq( SWT.Selection ), captor.capture() );
+    Event event = captor.getValue();
+    assertEquals( item, event.item );
+    assertEquals( RWT.HYPERLINK, event.detail );
+    assertEquals( "foo", event.text );
+  }
+
+  @Test
+  public void testHandleNotifySelection_withDetail_check() {
+    Grid spyGrid = spy( grid );
+    handler = new GridOperationHandler( spyGrid );
+    GridItem item = new GridItem( spyGrid, SWT.NONE );
+
+    JsonObject properties = new JsonObject()
+      .add( "item", getId( item ) )
+      .add( "detail", "check" )
+      .add( "index", 3 );
+    handler.handleNotify( EVENT_SELECTION, properties );
+
+    ArgumentCaptor<Event> captor = ArgumentCaptor.forClass( Event.class );
+    verify( spyGrid ).notifyListeners( eq( SWT.Selection ), captor.capture() );
+    Event event = captor.getValue();
+    assertEquals( item, event.item );
+    assertEquals( SWT.CHECK, event.detail );
+    assertEquals( 3, event.index );
+  }
+
+  @Test
+  public void testHandleNotifyDefaultSelection() {
+    Grid spyGrid = spy( grid );
+    handler = new GridOperationHandler( spyGrid );
+    GridItem item = new GridItem( spyGrid, SWT.NONE );
+
+    JsonObject properties = new JsonObject()
+      .add( "altKey", true )
+      .add( "shiftKey", true )
+      .add( "item", getId( item ) );
+    handler.handleNotify( EVENT_DEFAULT_SELECTION, properties );
+
+    ArgumentCaptor<Event> captor = ArgumentCaptor.forClass( Event.class );
+    verify( spyGrid ).notifyListeners( eq( SWT.DefaultSelection ), captor.capture() );
+    Event event = captor.getValue();
+    assertEquals( SWT.ALT | SWT.SHIFT, event.stateMask );
+    assertEquals( item, event.item );
+  }
+
+  @Test
+  public void testHandleNotifyExpand() {
+    Grid spyGrid = spy( grid );
+    handler = new GridOperationHandler( spyGrid );
+    GridItem item = new GridItem( spyGrid, SWT.NONE );
+
+    JsonObject properties = new JsonObject().add( "item", getId( item ) );
+    handler.handleNotify( EVENT_EXPAND, properties );
+
+    ArgumentCaptor<Event> captor = ArgumentCaptor.forClass( Event.class );
+    verify( spyGrid ).notifyListeners( eq( SWT.Expand ), captor.capture() );
+    assertEquals( item, captor.getValue().item );
+  }
+
+  @Test
+  public void testHandleNotifyCollapse() {
+    Grid spyGrid = spy( grid );
+    handler = new GridOperationHandler( spyGrid );
+    GridItem item = new GridItem( spyGrid, SWT.NONE );
+
+    JsonObject properties = new JsonObject().add( "item", getId( item ) );
+    handler.handleNotify( EVENT_COLLAPSE, properties );
+
+    ArgumentCaptor<Event> captor = ArgumentCaptor.forClass( Event.class );
+    verify( spyGrid ).notifyListeners( eq( SWT.Collapse ), captor.capture() );
+    assertEquals( item, captor.getValue().item );
+  }
+
+  @Test
+  public void testHandleNotifySetData() {
+    Grid spyGrid = spy( grid );
+    handler = new GridOperationHandler( spyGrid );
+
+    handler.handleNotify( EVENT_SET_DATA, new JsonObject() );
+
+    verify( spyGrid, never() ).notifyListeners( eq( SWT.SetData ), any( Event.class ) );
+  }
+
+}