Implement Grid virtual behavior

Due to complexity of the internal Grid structure and logic it's hard to
implement null virtual grid items.

Extract internal GridItem data in a separate class GridItemData. Create
this class lazily to reduce the memory footprint of "virtual" item.
Rework GridItemLCA in order to handle cached/uncached items (support
item data clear).
Optimize GridItem disposal to improve the performance when diposing huge
amount of items (reduce item count).
Some other small code re-factorings and optimizations.
diff --git a/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/Grid.java b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/Grid.java
index 34e1a3f..aeab3e4 100644
--- a/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/Grid.java
+++ b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/Grid.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012, 2013 EclipseSource and others.
+ * Copyright (c) 2012, 2014 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
@@ -25,9 +25,6 @@
 import org.eclipse.rap.rwt.internal.textsize.TextSizeUtil;
 import org.eclipse.rap.rwt.internal.theme.IThemeAdapter;
 import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ControlAdapter;
-import org.eclipse.swt.events.ControlEvent;
-import org.eclipse.swt.events.ControlListener;
 import org.eclipse.swt.events.SelectionListener;
 import org.eclipse.swt.events.TreeListener;
 import org.eclipse.swt.graphics.Font;
@@ -38,10 +35,10 @@
 import org.eclipse.swt.internal.widgets.ICellToolTipAdapter;
 import org.eclipse.swt.internal.widgets.ICellToolTipProvider;
 import org.eclipse.swt.internal.widgets.IItemHolderAdapter;
-import org.eclipse.swt.widgets.Canvas;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Item;
+import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.TypedListener;
 
 
@@ -64,7 +61,7 @@
  * </dl>
  */
 @SuppressWarnings("restriction")
-public class Grid extends Canvas {
+public class Grid extends Composite {
 
   private static final int MIN_ITEM_HEIGHT = 16;
   private static final int GRID_WIDTH = 1;
@@ -89,7 +86,8 @@
   private int customItemHeight = -1;
   private int groupHeaderHeight;
   private Point itemImageSize;
-  private ControlListener resizeListener;
+  private Listener resizeListener;
+  private Listener disposeListener;
   private boolean isTemporaryResize;
   private IScrollBarProxy vScroll;
   private IScrollBarProxy hScroll;
@@ -141,29 +139,9 @@
     }
     gridAdapter = new GridAdapter();
     layoutCache = new LayoutCache();
-    setScrollValuesObsolete();
     initListeners();
   }
 
-  @Override
-  public void dispose() {
-    disposing = true;
-    removeControlListener( resizeListener );
-    super.dispose();
-    for( Iterator<GridItem> iterator = items.iterator(); iterator.hasNext(); ) {
-      GridItem item = iterator.next();
-      item.dispose();
-    }
-    for( Iterator<GridColumn> iterator = columns.iterator(); iterator.hasNext(); ) {
-      GridColumn column = iterator.next();
-      column.dispose();
-    }
-    for( Iterator<GridColumnGroup> iterator = columnGroups.iterator(); iterator.hasNext(); ) {
-      GridColumnGroup group = iterator.next();
-      group.dispose();
-    }
-  }
-
   /**
    * {@inheritDoc}
    */
@@ -319,11 +297,13 @@
     checkWidget();
     int itemCount = Math.max( 0, count );
     while( itemCount < items.size() ) {
-      items.get( items.size() - 1 ).dispose();
+      int flatIndex = items.size() - 1;
+      items.get( flatIndex ).dispose( flatIndex );
     }
     while( itemCount > items.size() ) {
-      new GridItem( this, SWT.NONE );
+      new GridItem( this, null, SWT.NONE, -1 );
     }
+    redraw();
   }
 
   /**
@@ -459,11 +439,7 @@
     if( item == null ) {
       SWT.error( SWT.ERROR_NULL_ARGUMENT );
     }
-    int result = -1;
-    if( item.getParent() == this ) {
-      result = items.indexOf( item );
-    }
-    return result;
+    return item.getParent() == this ? items.indexOf( item ) : -1;
   }
 
   /**
@@ -679,11 +655,7 @@
     if( column == null ) {
       SWT.error( SWT.ERROR_NULL_ARGUMENT );
     }
-    int result = -1;
-    if( column.getParent() == this ) {
-      result = columns.indexOf( column );
-    }
-    return result;
+    return column.getParent() == this ? columns.indexOf( column ): -1;
   }
 
   /**
@@ -1070,7 +1042,6 @@
     checkWidget();
     if( !selectionEnabled ) {
       selectedItems.clear();
-      redraw();
     }
     this.selectionEnabled = selectionEnabled;
   }
@@ -1114,7 +1085,6 @@
         selectedItems.clear();
       }
       internalSelect( index );
-      redraw();
     }
   }
 
@@ -1150,7 +1120,6 @@
       for( int index = Math.max( 0, start ); index <= Math.min( items.size() - 1, end ); index++ ) {
         internalSelect( index );
       }
-      redraw();
     }
   }
 
@@ -1192,7 +1161,6 @@
       for( int i = 0; i < indices.length; i++ ) {
         internalSelect( indices[ i ] );
       }
-      redraw();
     }
   }
 
@@ -1218,7 +1186,6 @@
       } else {
         selectedItems.clear();
         selectedItems.addAll( items );
-        redraw();
       }
     }
   }
@@ -1242,7 +1209,6 @@
     checkWidget();
     if( isValidItemIndex( index ) ) {
       internalDeselect( index );
-      redraw();
     }
   }
 
@@ -1269,7 +1235,6 @@
     for( int index = Math.max( 0, start ); index <= Math.min( items.size() - 1, end ); index++ ) {
       internalDeselect( index );
     }
-    redraw();
   }
 
   /**
@@ -1301,7 +1266,6 @@
     for( int i = 0; i < indices.length; i++ ) {
       internalDeselect( indices[ i ] );
     }
-    redraw();
   }
 
   /**
@@ -1318,7 +1282,6 @@
   public void deselectAll() {
     checkWidget();
     internalDeselectAll();
-    redraw();
   }
 
   /**
@@ -1341,7 +1304,6 @@
     if( selectionEnabled && isValidItemIndex( index ) ) {
       internalDeselectAll();
       internalSelect( index );
-      redraw();
     }
   }
 
@@ -1374,7 +1336,6 @@
       for( int index = Math.max( 0, start ); index <= Math.min( items.size() - 1, end ); index++ ) {
         internalSelect( index );
       }
-      redraw();
     }
   }
 
@@ -1412,7 +1373,6 @@
       for( int i = 0; i < indices.length; i++ ) {
         internalSelect( indices[ i ] );
       }
-      redraw();
     }
   }
 
@@ -1448,16 +1408,14 @@
     }
     if( selectionEnabled && !( selectionType == SWT.SINGLE && items.length > 1 ) ) {
       internalDeselectAll();
-      for( int i = 0; i < items.length; i++ ) {
-        GridItem item = items[ i ];
+      for( GridItem item : items ) {
         if( item != null ) {
           if( item.isDisposed() ) {
             SWT.error( SWT.ERROR_INVALID_ARGUMENT );
           }
-          internalSelect( indexOf( item ) );
+          internalSelect( this.items.indexOf( item ) );
         }
       }
-      redraw();
     }
   }
 
@@ -1587,8 +1545,7 @@
     int[] result = new int[ 0 ];
     if( cellSelectionEnabled ) {
       List<GridItem> selectedRows = new ArrayList<GridItem>();
-      for( Iterator<Point> iterator = selectedCells.iterator(); iterator.hasNext(); ) {
-        Point cell = iterator.next();
+      for( Point cell : selectedCells ) {
         GridItem item = getItem( cell.y );
         if( !selectedRows.contains( item ) ) {
           selectedRows.add( item );
@@ -1629,8 +1586,7 @@
     boolean result = false;
     if( isValidItemIndex( index ) ) {
       if( cellSelectionEnabled ) {
-        for( Iterator<Point> iterator = selectedCells.iterator(); iterator.hasNext(); ) {
-          Point cell = iterator.next();
+        for( Point cell : selectedCells ) {
           if( cell.y == index ) {
             result = true;
           }
@@ -1666,10 +1622,9 @@
     }
     boolean result = false;
     if( cellSelectionEnabled ) {
-      int index = indexOf( item );
+      int index = items.indexOf( item );
       if( index != -1 ) {
-        for( Iterator<Point> iterator = selectedCells.iterator(); iterator.hasNext(); ) {
-          Point cell = iterator.next();
+        for( Point cell : selectedCells ) {
           if( cell.y == index ) {
             result = true;
           }
@@ -1702,8 +1657,7 @@
     if( index < 0 || index > items.size() - 1 ) {
       SWT.error( SWT.ERROR_INVALID_RANGE );
     }
-    items.get( index ).dispose();
-    redraw();
+    items.get( index ).dispose( index );
   }
 
   /**
@@ -1730,9 +1684,8 @@
       if( i < 0 || i > items.size() - 1 ) {
         SWT.error( SWT.ERROR_INVALID_RANGE );
       }
-      items.get( i ).dispose();
+      items.get( i ).dispose( i );
     }
-    redraw();
   }
 
   /**
@@ -1770,7 +1723,6 @@
     for( int i = 0; i < removeThese.length; i++ ) {
       removeThese[ i ].dispose();
     }
-    redraw();
   }
 
   /**
@@ -1786,9 +1738,9 @@
   public void removeAll() {
     checkWidget();
     while( items.size() > 0 ) {
-      items.get( 0 ).dispose();
+      int flatIndex = items.size() - 1;
+      items.get( flatIndex ).dispose( flatIndex );
     }
-    redraw();
   }
 
   /**
@@ -1808,8 +1760,7 @@
     if( columnHeadersVisible != show ) {
       columnHeadersVisible = show;
       layoutCache.invalidateHeaderHeight();
-      invalidateTopBottomIndex();
-      setScrollValuesObsolete();
+      scheduleRedraw();
     }
   }
 
@@ -1867,8 +1818,7 @@
     if( columnFootersVisible != show ) {
       columnFootersVisible = show;
       layoutCache.invalidateFooterHeight();
-      invalidateTopBottomIndex();
-      setScrollValuesObsolete();
+      scheduleRedraw();
     }
   }
 
@@ -1939,7 +1889,6 @@
   public void setLinesVisible( boolean linesVisible ) {
     checkWidget();
     this.linesVisible = linesVisible;
-    redraw();
   }
 
   /**
@@ -2028,12 +1977,8 @@
     }
     if( customItemHeight != height ) {
       customItemHeight = height;
-      for( int i = 0; i < items.size(); i++ ) {
-        items.get( i ).setHeight( height );
-      }
       hasDifferingHeights = false;
-      invalidateTopBottomIndex();
-      setScrollValuesObsolete();
+      scheduleRedraw();
     }
   }
 
@@ -2053,21 +1998,20 @@
    */
   public int getItemHeight() {
     checkWidget();
-    int result = customItemHeight;
-    if( result == -1 ) {
+    if( customItemHeight == -1 ) {
       if( !layoutCache.hasItemHeight() ) {
         layoutCache.itemHeight = computeItemHeight();
       }
-      result = layoutCache.itemHeight;
+      return layoutCache.itemHeight;
     }
-    return result;
+    return customItemHeight;
   }
 
   @Override
   public void setFont( Font font ) {
     super.setFont( font );
     layoutCache.invalidateItemHeight();
-    setScrollValuesObsolete();
+    scheduleRedraw();
   }
 
   /**
@@ -2097,6 +2041,7 @@
         }
         vScroll.setSelection( vScrollAmount );
         invalidateTopBottomIndex();
+        redraw();
       }
     }
   }
@@ -2300,15 +2245,15 @@
         flatIndex = items.indexOf( rootItems.get( index ) );
       }
     } else if( !root ) {
-      if( index >= parentItem.getItems().length || index == -1 ) {
+      if( index >= parentItem.getItemCount() || index == -1 ) {
         GridItem rightMostDescendent = parentItem;
-        while( rightMostDescendent.getItems().length > 0 ) {
-          GridItem[] rightMostDescendentItems = rightMostDescendent.getItems();
-          rightMostDescendent = rightMostDescendentItems[ rightMostDescendentItems.length - 1 ];
+        while( rightMostDescendent.hasChildren() ) {
+          int lastChildIndex = rightMostDescendent.getItemCount() - 1;
+          rightMostDescendent = rightMostDescendent.getItem( lastChildIndex );
         }
-        flatIndex = indexOf( rightMostDescendent ) + 1;
+        flatIndex = items.indexOf( rightMostDescendent ) + 1;
       } else {
-        flatIndex = indexOf( parentItem.getItems()[ index ] );
+        flatIndex = items.indexOf( parentItem.getItem( index ) );
       }
     }
     if( flatIndex == -1 ) {
@@ -2318,13 +2263,13 @@
       items.add( flatIndex, item );
       row = flatIndex;
     }
-    invalidateTopBottomIndex();
     updateVisibleItems( 1 );
+    scheduleRedraw();
     return row;
   }
 
-  void removeItem( GridItem item ) {
-    items.remove( item );
+  void removeItem( int index ) {
+    GridItem item = items.remove( index );
     if( !disposing ) {
       selectedItems.remove (item );
 // TODO: [if] Implement cell selection
@@ -2335,24 +2280,33 @@
       if( focusItem == item ) {
         focusItem = null;
       }
-      invalidateTopBottomIndex();
       if( item.isVisible() ) {
         updateVisibleItems( -1 );
       }
-      setScrollValuesObsolete();
+      scheduleRedraw();
     }
   }
 
   void newRootItem( GridItem item, int index ) {
     if( index == -1 || index >= rootItems.size() ) {
       rootItems.add( item );
+      item.index = rootItems.size() - 1;
     } else {
       rootItems.add( index, item );
+      item.index = index;
     }
+    adjustItemIndices( item.index + 1 );
   }
 
-  void removeRootItem( GridItem item ) {
-    rootItems.remove( item );
+  void removeRootItem( int index ) {
+    rootItems.remove( index );
+    adjustItemIndices( index );
+  }
+
+  private void adjustItemIndices( int start ) {
+    for( int i = start; i < rootItems.size(); i++ ) {
+      rootItems.get( i ).index = i;
+    }
   }
 
   int newColumn( GridColumn column, int index ) {
@@ -2364,8 +2318,7 @@
       displayOrderedColumns.add( index, column );
     }
     updatePrimaryCheckColumn();
-    for( Iterator<GridItem> iterator = items.iterator(); iterator.hasNext(); ) {
-      GridItem item = iterator.next();
+    for( GridItem item : items ) {
       item.columnAdded( index );
     }
     if( column.isCheck() ) {
@@ -2373,18 +2326,16 @@
     }
     layoutCache.invalidateHeaderHeight();
     layoutCache.invalidateFooterHeight();
-    invalidateTopBottomIndex();
-    setScrollValuesObsolete();
+    scheduleRedraw();
     return columns.size() - 1;
   }
 
   void removeColumn( GridColumn column ) {
-    int index = indexOf( column );
-    columns.remove( column );
+    int index = columns.indexOf( column );
+    columns.remove( index );
     displayOrderedColumns.remove( column );
     updatePrimaryCheckColumn();
-    for( Iterator<GridItem> iterator = items.iterator(); iterator.hasNext(); ) {
-      GridItem item = iterator.next();
+    for( GridItem item : items ) {
       item.columnRemoved( index );
     }
     if( column.isCheck() ) {
@@ -2392,8 +2343,7 @@
     }
     layoutCache.invalidateHeaderHeight();
     layoutCache.invalidateFooterHeight();
-    invalidateTopBottomIndex();
-    setScrollValuesObsolete();
+    scheduleRedraw();
   }
 
   void newColumnGroup( GridColumnGroup group ) {
@@ -2401,8 +2351,7 @@
     if( columnGroups.size() == 1 ) {
       layoutCache.invalidateHeaderHeight();
     }
-    invalidateTopBottomIndex();
-    setScrollValuesObsolete();
+    scheduleRedraw();
   }
 
   void removeColumnGroup( GridColumnGroup group ) {
@@ -2410,8 +2359,7 @@
     if( columnGroups.size() == 0 ) {
       layoutCache.invalidateHeaderHeight();
     }
-    invalidateTopBottomIndex();
-    setScrollValuesObsolete();
+    scheduleRedraw();
   }
 
   boolean isDisposing() {
@@ -2433,12 +2381,13 @@
       Rectangle imageBounds = image.getBounds();
       itemImageSize = new Point( imageBounds.width, imageBounds.height );
       layoutCache.invalidateItemHeight();
-      setScrollValuesObsolete();
+      scheduleRedraw();
     }
   }
 
   int getMaxContentWidth( GridColumn column ) {
-    return getMaxInnerWidth( getRootItems(), indexOf( column ) );
+    doRedraw();
+    return getMaxInnerWidth( getRootItems(), columns.indexOf( column ) );
   }
 
   int getBottomIndex() {
@@ -2459,11 +2408,6 @@
     return bottomIndex;
   }
 
-  void invalidateTopBottomIndex() {
-    topIndex = -1;
-    bottomIndex = -1;
-  }
-
   Point getOrigin( GridColumn column, GridItem item ) {
     int x = column.getLeft() - hScroll.getSelection();
     int y = 0;
@@ -2512,12 +2456,33 @@
   }
 
   private void doRedraw() {
+    if( isVirtual() ) {
+      for( int index = getTopIndex(); index <= getBottomIndex(); index++ ) {
+        GridItem item = items.get( index );
+        if( item.isVisible() ) {
+          item.ensureItemData();
+          item.handleVirtual();
+        }
+      }
+    }
     updateScrollBars();
   }
 
-  void setScrollValuesObsolete() {
-    scrollValuesObsolete = true;
-    redraw();
+  private GridItem[] getResolvedItems() {
+    if( isVirtual() ) {
+      List<GridItem> resolvedItems = new ArrayList<GridItem>();
+      for( GridItem item : items ) {
+        if( item.isResolved() ) {
+          resolvedItems.add( item );
+        }
+      }
+      return resolvedItems.toArray( new GridItem[ 0 ] );
+    }
+    return getItems();
+  }
+
+  boolean isVirtual() {
+    return ( getStyle() & SWT.VIRTUAL ) != 0;
   }
 
   void updateScrollBars() {
@@ -2572,8 +2537,52 @@
   }
 
   private void initListeners() {
-    resizeListener = new ResizeListener();
-    addControlListener( resizeListener );
+    resizeListener = new Listener() {
+      public void handleEvent( Event event ) {
+        onResize();
+      }
+    };
+    addListener( SWT.Resize, resizeListener );
+    disposeListener = new Listener() {
+      public void handleEvent( Event event ) {
+        onDispose( event );
+      }
+    };
+    addListener( SWT.Dispose, disposeListener );
+  }
+
+  private void onResize() {
+    if( TextSizeUtil.isTemporaryResize() ) {
+      isTemporaryResize = true;
+      layoutCache.invalidateHeaderHeight();
+      layoutCache.invalidateFooterHeight();
+      layoutCache.invalidateItemHeight();
+    } else {
+      if( isTemporaryResize) {
+        isTemporaryResize = false;
+        repackColumns();
+      }
+      scheduleRedraw();
+    }
+  }
+
+  private void onDispose( Event event ) {
+    // We only want to dispose of our items and such *after* anybody else who may have been
+    // listening to the dispose has had a chance to do whatever.
+    removeListener( SWT.Resize, resizeListener );
+    removeListener( SWT.Dispose, disposeListener );
+    notifyListeners( SWT.Dispose, event );
+    event.type = SWT.None;
+    disposing = true;
+    for( GridItem item : items ) {
+      item.dispose();
+    }
+    for( GridColumn column : columns ) {
+      column.dispose();
+    }
+    for( GridColumnGroup group : columnGroups ) {
+      group.dispose();
+    }
   }
 
   void setCellToolTipsEnabled( boolean enabled ) {
@@ -2590,8 +2599,7 @@
       height += getFooterHeight();
     }
     height += getGridHeight();
-    for( Iterator<GridColumn> iterator = columns.iterator(); iterator.hasNext(); ) {
-      GridColumn column = iterator.next();
+    for( GridColumn column : columns ) {
       if( column.isVisible() ) {
         width += column.getWidth();
       }
@@ -2602,8 +2610,7 @@
   private int getGridHeight() {
     int result = 0;
     if( hasDifferingHeights ) {
-      for( int i = 0; i < items.size(); i++ ) {
-        GridItem item = items.get( i );
+      for( GridItem item : items ) {
         if( item.isVisible() ) {
           result += item.getHeight();
         }
@@ -2622,12 +2629,13 @@
 
   private static int getMaxInnerWidth( GridItem[] items, int index ) {
     int maxInnerWidth = 0;
-    for( int i = 0; i < items.length; i++ ) {
-      GridItem item = items[ i ];
-      maxInnerWidth = Math.max( maxInnerWidth, item.getPreferredWidth( index ) );
-      if( item.isExpanded() ) {
-        int innerWidth = getMaxInnerWidth( item.getItems(), index );
-        maxInnerWidth = Math.max( maxInnerWidth, innerWidth );
+    for( GridItem item : items ) {
+      if( item.isResolved() ) {
+        maxInnerWidth = Math.max( maxInnerWidth, item.getPreferredWidth( index ) );
+        if( item.isExpanded() ) {
+          int innerWidth = getMaxInnerWidth( item.getItems(), index );
+          maxInnerWidth = Math.max( maxInnerWidth, innerWidth );
+        }
       }
     }
     return maxInnerWidth;
@@ -2668,9 +2676,8 @@
   private void updatePrimaryCheckColumn() {
     if( ( getStyle() & SWT.CHECK ) == SWT.CHECK ) {
       boolean firstCol = true;
-      for( Iterator<GridColumn> iter = displayOrderedColumns.iterator(); iter.hasNext(); ) {
-        GridColumn col = iter.next();
-        col.setTableCheck( firstCol );
+      for( GridColumn column : displayOrderedColumns ) {
+        column.setTableCheck( firstCol );
         firstCol = false;
       }
     }
@@ -2753,17 +2760,6 @@
     }
   }
 
-  private int getItemIndex( GridItem item ) {
-    int result = -1;
-    GridItem parentItem = item.getParentItem();
-    if( parentItem == null ) {
-      result = rootItems.indexOf( item );
-    } else {
-      result = parentItem.indexOf( item );
-    }
-    return result;
-  }
-
   private int getColumnHeaderXPosition( GridColumn column ) {
     int result = -1;
     if( column.isVisible() ) {
@@ -3037,6 +3033,25 @@
     return index >= 0 && index < items.size();
   }
 
+  int internalIndexOf( GridItem item ) {
+    return items.indexOf( item );
+  }
+
+  void scheduleRedraw() {
+    invalidateScrollBars();
+    invalidateTopBottomIndex();
+    redraw();
+  }
+
+  void invalidateTopBottomIndex() {
+    topIndex = -1;
+    bottomIndex = -1;
+  }
+
+  void invalidateScrollBars() {
+    scrollValuesObsolete = true;
+  }
+
   ////////////////
   // Inner classes
 
@@ -3061,7 +3076,7 @@
     }
 
     public Item[] getItems() {
-      GridItem[] items = Grid.this.getItems();
+      GridItem[] items = getResolvedItems();
       GridColumn[] columns = getColumns();
       GridColumnGroup[] groups = getColumnGroups();
       Item[] result = new Item[ columns.length + items.length + groups.length ];
@@ -3072,25 +3087,6 @@
     }
   }
 
-  private final class ResizeListener extends ControlAdapter {
-    @Override
-    public void controlResized( ControlEvent event ) {
-      if( TextSizeUtil.isTemporaryResize() ) {
-        isTemporaryResize = true;
-        layoutCache.invalidateHeaderHeight();
-        layoutCache.invalidateFooterHeight();
-        layoutCache.invalidateItemHeight();
-      } else {
-        if( isTemporaryResize) {
-          isTemporaryResize = false;
-          repackColumns();
-        }
-        invalidateTopBottomIndex();
-        setScrollValuesObsolete();
-      }
-    }
-  }
-
   private final class GridAdapter
     implements IGridAdapter, ICellToolTipAdapter, SerializableCompatibility
   {
@@ -3102,7 +3098,8 @@
     }
 
     public void invalidateTopIndex() {
-      Grid.this.invalidateTopBottomIndex();
+      invalidateTopBottomIndex();
+      redraw();
     }
 
     public int getIndentationWidth() {
@@ -3142,7 +3139,7 @@
     }
 
     public int getItemIndex( GridItem item ) {
-      return Grid.this.getItemIndex( item );
+      return item.index;
     }
 
     public ICellToolTipProvider getCellToolTipProvider() {
diff --git a/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/GridColumn.java b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/GridColumn.java
index 87a3147..41946bb 100644
--- a/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/GridColumn.java
+++ b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/GridColumn.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012, 2013 EclipseSource and others.
+ * Copyright (c) 2012, 2014 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
@@ -378,12 +378,14 @@
   public void setText( String text ) {
     super.setText( text );
     parent.layoutCache.invalidateHeaderHeight();
+    parent.scheduleRedraw();
   }
 
   @Override
   public void setImage( Image image ) {
     super.setImage( image );
     parent.layoutCache.invalidateHeaderHeight();
+    parent.scheduleRedraw();
   }
 
   /**
@@ -794,8 +796,9 @@
     if( font != null && font.isDisposed() ) {
       SWT.error( SWT.ERROR_INVALID_ARGUMENT );
     }
-    parent.layoutCache.invalidateHeaderHeight();
     headerFont = font;
+    parent.layoutCache.invalidateHeaderHeight();
+    parent.scheduleRedraw();
   }
 
   /**
@@ -975,6 +978,7 @@
     }
     footerFont = font;
     parent.layoutCache.invalidateFooterHeight();
+    parent.scheduleRedraw();
   }
 
   /**
@@ -1081,7 +1085,8 @@
       this.width = newWidth;
       packed = false;
       processControlEvents();
-      parent.setScrollValuesObsolete();
+      parent.invalidateScrollBars();
+      parent.redraw();
     }
   }
 
diff --git a/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/GridColumnGroup.java b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/GridColumnGroup.java
index f6f44f1..a32eec6 100644
--- a/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/GridColumnGroup.java
+++ b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/GridColumnGroup.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012 EclipseSource and others.
+ * Copyright (c) 2012, 2014 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
@@ -188,7 +188,8 @@
     checkWidget();
     if( this.expanded != expanded ) {
       this.expanded = expanded;
-      parent.setScrollValuesObsolete();
+      parent.invalidateScrollBars();
+      parent.redraw();
     }
   }
 
@@ -248,20 +249,23 @@
     if( font != null && font.isDisposed() ) {
       SWT.error( SWT.ERROR_INVALID_ARGUMENT );
     }
-    parent.layoutCache.invalidateHeaderHeight();
     headerFont = font;
+    parent.layoutCache.invalidateHeaderHeight();
+    parent.scheduleRedraw();
   }
 
   @Override
   public void setText( String text ) {
     super.setText( text );
     parent.layoutCache.invalidateHeaderHeight();
+    parent.scheduleRedraw();
   }
 
   @Override
   public void setImage( Image image ) {
     super.setImage( image );
     parent.layoutCache.invalidateHeaderHeight();
+    parent.scheduleRedraw();
   }
 
   void newColumn( GridColumn column ) {
diff --git a/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/GridItem.java b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/GridItem.java
index 631853f..d7da85f 100644
--- a/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/GridItem.java
+++ b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/GridItem.java
@@ -14,9 +14,10 @@
 import static org.eclipse.swt.internal.widgets.MarkupUtil.isMarkupEnabledFor;
 import static org.eclipse.swt.internal.widgets.MarkupValidator.isValidationDisabledFor;
 
-import java.util.ArrayList;
-import java.util.Iterator;
+import java.util.List;
 
+import org.eclipse.nebula.widgets.grid.internal.GridItemData;
+import org.eclipse.nebula.widgets.grid.internal.GridItemData.CellData;
 import org.eclipse.nebula.widgets.grid.internal.IGridItemAdapter;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.graphics.Color;
@@ -24,7 +25,6 @@
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.internal.SerializableCompatibility;
 import org.eclipse.swt.internal.widgets.IWidgetColorAdapter;
 import org.eclipse.swt.internal.widgets.IWidgetFontAdapter;
 import org.eclipse.swt.internal.widgets.MarkupValidator;
@@ -54,18 +54,12 @@
 
   private Grid parent;
   private GridItem parentItem;
-  private ArrayList<Data> data;
-  private ArrayList<GridItem> children = new ArrayList<GridItem>();
+  private GridItemData data;
   private boolean hasChildren;
-  private int level;
-  private int customHeight = -1;
   private boolean visible = true;
-  private boolean expanded;
-  private boolean hasSetData;
-  private Font defaultFont;
-  private Color defaultBackground;
-  private Color defaultForeground;
+  private boolean cached;
   private transient IGridItemAdapter gridItemAdapter;
+  int index;
 
   /**
    * Creates a new instance of this class and places the item at the end of
@@ -88,7 +82,7 @@
    *             </ul>
    */
   public GridItem( Grid parent, int style ) {
-    this( parent, style, -1 );
+    this( parent, null, style, -1 );
   }
 
   /**
@@ -114,12 +108,7 @@
    *             </ul>
    */
   public GridItem( Grid parent, int style, int index ) {
-    super( parent, style, index );
-    this.parent = parent;
-    init();
-    parent.newItem( this, index, true );
-    parent.newRootItem( this, index );
-    parent.setScrollValuesObsolete();
+    this( parent, null, style, index );
   }
 
   /**
@@ -143,7 +132,7 @@
    *             </ul>
    */
   public GridItem( GridItem parent, int style ) {
-    this( parent, style, -1 );
+    this( parent == null ? null : parent.parent, parent, style, -1 );
   }
 
   /**
@@ -169,19 +158,21 @@
    *             </ul>
    */
   public GridItem( GridItem parent, int style, int index ) {
+    this( parent == null ? null : parent.parent, parent, style, index );
+  }
+
+  GridItem( Grid parent, GridItem parentItem, int style, int index ) {
     super( parent, style, index );
-    parentItem = parent;
-    this.parent = parentItem.getParent();
-    this.parent.newItem( this, index, false );
-    init();
-    level = parentItem.getLevel() + 1;
-    parentItem.newItem( this, index );
-    if( parent.isVisible() && parent.isExpanded() ) {
-      setVisible( true );
+    this.parent = parent;
+    this.parentItem = parentItem;
+    if( parentItem == null ) {
+      parent.newItem( this, index, true );
+      parent.newRootItem( this, index );
     } else {
-      setVisible( false );
+      parent.newItem( this, index, false );
+      parentItem.newItem( this, index );
+      setVisible( parentItem.isVisible() && parentItem.isExpanded() );
     }
-    this.parent.setScrollValuesObsolete();
   }
 
   /**
@@ -189,20 +180,30 @@
    */
   @Override
   public void dispose() {
+    dispose( SWT.DEFAULT );
+  }
+
+  void dispose( int flatIndex ) {
     if( !parent.isDisposing() && !isDisposed() ) {
-      for( int i = 0; i < parent.getColumnCount(); i++ ) {
-        Data itemData = getItemData( i );
-        updateColumnImageCount( i, itemData.image, null );
-        updateColumnTextCount( i, itemData.text, "" );
+      if( data != null ) {
+        for( int i = 0; i < parent.getColumnCount(); i++ ) {
+          CellData itemData = getCellData( i );
+          updateColumnImageCount( i, itemData.image, null );
+          updateColumnTextCount( i, itemData.text, "" );
+        }
       }
-      parent.removeItem( this );
+      int index = flatIndex == SWT.DEFAULT ? parent.internalIndexOf( this ) : flatIndex;
+      if( hasChildren ) {
+        List<GridItem> children = getItemData().getChildren();
+        while( hasChildren ) {
+          children.get( 0 ).dispose( index + 1 );
+        }
+      }
+      parent.removeItem( index );
       if( parentItem != null ) {
-        parentItem.remove( this );
+        parentItem.removeItem( this.index );
       } else {
-        parent.removeRootItem( this );
-      }
-      for( int i = children.size() - 1; i >= 0; i-- ) {
-        children.get( i ).dispose();
+        parent.removeRootItem( this.index );
       }
     }
     super.dispose();
@@ -314,7 +315,7 @@
    */
   public int getItemCount() {
     checkWidget();
-    return children.size();
+    return hasChildren ? getItemData().getChildren().size() : 0;
   }
 
   /**
@@ -335,7 +336,11 @@
    *             </ul>
    */
   public GridItem[] getItems() {
-    return children.toArray( new GridItem[ children.size() ] );
+    checkWidget();
+    if( hasChildren ) {
+      return getItemData().getChildren().toArray( new GridItem[ 0 ] );
+    }
+    return new GridItem[ 0 ];
   }
 
   /**
@@ -360,7 +365,10 @@
    */
   public GridItem getItem( int index ) {
     checkWidget();
-    return children.get( index );
+    if( !hasChildren ) {
+      throw new IllegalArgumentException( "GridItem has no children!" );
+    }
+    return getItemData().getChildren().get( index );
   }
 
   /**
@@ -394,7 +402,10 @@
     if( item.isDisposed() ) {
       SWT.error( SWT.ERROR_INVALID_ARGUMENT );
     }
-    return children.indexOf( item );
+    if( !hasChildren ) {
+      throw new IllegalArgumentException( "GridItem has no children!" );
+    }
+    return item.getParentItem() == this ? item.index : -1;
   }
 
   /**
@@ -429,7 +440,7 @@
    */
   public boolean isExpanded() {
     checkWidget();
-    return expanded;
+    return data == null ? false : data.expanded;
   }
 
   /**
@@ -447,30 +458,33 @@
    */
   public void setExpanded( boolean expanded ) {
     checkWidget();
-    this.expanded = expanded;
-    boolean unselected = false;
-    for( Iterator<GridItem> itemIterator = children.iterator(); itemIterator.hasNext(); ) {
-      GridItem item = itemIterator.next();
-      item.setVisible( expanded && visible );
-      if( !expanded ) {
-        if( parent.isSelected( item ) ) {
-          parent.deselect( parent.indexOf( item ) );
-          unselected = true;
-        }
-        if( deselectChildren( item ) ) {
-          unselected = true;
+    if( getItemData().expanded != expanded ) {
+      getItemData().expanded = expanded;
+      boolean unselected = false;
+      if( hasChildren ) {
+        for( GridItem item : getItemData().getChildren() ) {
+          item.setVisible( expanded && visible );
+          if( !expanded ) {
+            if( parent.isSelected( item ) ) {
+              parent.deselect( parent.internalIndexOf( item ) );
+              unselected = true;
+            }
+            if( deselectChildren( item ) ) {
+              unselected = true;
+            }
+          }
         }
       }
-    }
-    parent.invalidateTopBottomIndex();
-    parent.setScrollValuesObsolete();
-    if( unselected ) {
-      Event event = new Event();
-      event.item = this;
-      parent.notifyListeners( SWT.Selection, event );
-    }
-    if( parent.getFocusItem() != null && !parent.getFocusItem().isVisible() ) {
-      parent.setFocusItem( this );
+      parent.scheduleRedraw();
+      if( unselected ) {
+        Event event = new Event();
+        event.item = this;
+        parent.notifyListeners( SWT.Selection, event );
+      }
+      if( parent.getFocusItem() != null && !parent.getFocusItem().isVisible() ) {
+        parent.setFocusItem( this );
+      }
+      markCached();
     }
   }
 
@@ -488,7 +502,7 @@
    */
   public int getLevel() {
     checkWidget();
-    return level;
+    return parentItem == null ? 0 : parentItem.getLevel() + 1;
   }
 
   /**
@@ -516,8 +530,9 @@
     if( font != null && font.isDisposed() ) {
       SWT.error( SWT.ERROR_INVALID_ARGUMENT );
     }
-    defaultFont = font;
-    parent.redraw();
+    getItemData().defaultFont = font;
+    markCached();
+    parent.scheduleRedraw();
   }
 
   /**
@@ -535,6 +550,8 @@
    */
   public Font getFont() {
     checkWidget();
+    handleVirtual();
+    Font defaultFont = getItemData().defaultFont;
     return defaultFont == null ? parent.getFont() : defaultFont;
   }
 
@@ -565,8 +582,9 @@
     if( font != null && font.isDisposed() ) {
       SWT.error( SWT.ERROR_INVALID_ARGUMENT );
     }
-    getItemData( index ).font = font;
-    parent.redraw();
+    getCellData( index ).font = font;
+    markCached();
+    parent.scheduleRedraw();
   }
 
   /**
@@ -587,7 +605,11 @@
   public Font getFont( int index ) {
     checkWidget();
     handleVirtual();
-    return internalGetFont( index );
+    Font result = getCellData( index ).font;
+    if( result == null ) {
+      result = getFont();
+    }
+    return result;
   }
 
   /**
@@ -615,8 +637,8 @@
     if( background != null && background.isDisposed() ) {
       SWT.error( SWT.ERROR_INVALID_ARGUMENT );
     }
-    defaultBackground = background;
-    parent.redraw();
+    getItemData().defaultBackground = background;
+    markCached();
   }
 
   /**
@@ -633,6 +655,8 @@
    */
   public Color getBackground() {
     checkWidget();
+    handleVirtual();
+    Color defaultBackground = getItemData().defaultBackground;
     return defaultBackground == null ? parent.getBackground() : defaultBackground;
   }
 
@@ -663,8 +687,8 @@
     if( background != null && background.isDisposed() ) {
       SWT.error( SWT.ERROR_INVALID_ARGUMENT );
     }
-    getItemData( index ).background = background;
-    parent.redraw();
+    getCellData( index ).background = background;
+    markCached();
   }
 
   /**
@@ -684,7 +708,7 @@
   public Color getBackground( int index ) {
     checkWidget();
     handleVirtual();
-    Color result = getItemData( index ).background;
+    Color result = getCellData( index ).background;
      if( result == null ) {
        result = getBackground();
      }
@@ -716,8 +740,8 @@
     if( foreground != null && foreground.isDisposed() ) {
       SWT.error( SWT.ERROR_INVALID_ARGUMENT );
     }
-    defaultForeground = foreground;
-    parent.redraw();
+    getItemData().defaultForeground = foreground;
+    markCached();
   }
 
   /**
@@ -734,6 +758,8 @@
    */
   public Color getForeground() {
     checkWidget();
+    handleVirtual();
+    Color defaultForeground = getItemData().defaultForeground;
     return defaultForeground == null ? parent.getForeground() : defaultForeground;
   }
 
@@ -764,8 +790,8 @@
     if( foreground != null && foreground.isDisposed() ) {
       SWT.error( SWT.ERROR_INVALID_ARGUMENT );
     }
-    getItemData( index ).foreground = foreground;
-    parent.redraw();
+    getCellData( index ).foreground = foreground;
+    markCached();
   }
 
   /**
@@ -785,7 +811,7 @@
   public Color getForeground( int index ) {
     checkWidget();
     handleVirtual();
-    Color result = getItemData( index ).foreground;
+    Color result = getCellData( index ).foreground;
     if( result == null ) {
       result = getForeground();
     }
@@ -797,6 +823,7 @@
    */
   @Override
   public void setText( String string ) {
+    checkWidget();
     setText( 0, string );
   }
 
@@ -805,6 +832,7 @@
    */
   @Override
   public String getText() {
+    checkWidget();
     return getText( 0 );
   }
 
@@ -835,10 +863,10 @@
     if( isMarkupEnabledFor( parent ) && !isValidationDisabledFor( parent ) ) {
       MarkupValidator.getInstance().validate( text );
     }
-    Data itemData = getItemData( index );
-    updateColumnTextCount( index, itemData.text, text );
-    itemData.text = text;
-    parent.redraw();
+    CellData cellData = getCellData( index );
+    updateColumnTextCount( index, cellData.text, text );
+    cellData.text = text;
+    markCached();
   }
 
   /**
@@ -859,7 +887,7 @@
   public String getText( int index ) {
     checkWidget();
     handleVirtual();
-    return getItemData( index ).text;
+    return getCellData( index ).text;
   }
 
   /**
@@ -879,10 +907,11 @@
    */
   public void setToolTipText( int index, String tooltip ) {
     checkWidget();
-    getItemData( index ).tooltip = tooltip;
+    getCellData( index ).tooltip = tooltip;
     if( tooltip != null && tooltip.length() > 0 ) {
       parent.setCellToolTipsEnabled( true );
     }
+    markCached();
   }
 
   /**
@@ -902,7 +931,7 @@
   public String getToolTipText( int index ) {
     checkWidget();
     handleVirtual();
-    return getItemData( index ).tooltip;
+    return getCellData( index ).tooltip;
   }
 
   /**
@@ -910,8 +939,8 @@
    */
   @Override
   public void setImage( Image image ) {
+    checkWidget();
     setImage( 0, image );
-    parent.redraw();
   }
 
   /**
@@ -947,11 +976,11 @@
     if( image != null && image.isDisposed() ) {
       SWT.error( SWT.ERROR_INVALID_ARGUMENT );
     }
-    Data itemData = getItemData( index );
-    updateColumnImageCount( index, itemData.image, image );
-    itemData.image = image;
+    CellData cellData = getCellData( index );
+    updateColumnImageCount( index, cellData.image, image );
+    cellData.image = image;
     parent.imageSetOnItem( index, this );
-    parent.redraw();
+    markCached();
   }
 
   /**
@@ -972,7 +1001,7 @@
   public Image getImage( int index ) {
     checkWidget();
     handleVirtual();
-    return getItemData( index ).image;
+    return getCellData( index ).image;
   }
 
   /**
@@ -991,7 +1020,6 @@
   public void setChecked( boolean checked ) {
     checkWidget();
     setChecked( 0, checked );
-    parent.redraw();
   }
 
   /**
@@ -1029,8 +1057,8 @@
   public void setChecked( int index, boolean checked ) {
     checkWidget();
     // [if] TODO: probably need a check for parent.getColumn( index ).isCheck() ?
-    getItemData( index ).checked = checked;
-    parent.redraw();
+    getCellData( index ).checked = checked;
+    markCached();
   }
 
   /**
@@ -1050,7 +1078,7 @@
   public boolean getChecked( int index ) {
     checkWidget();
     handleVirtual();
-    return getItemData( index ).checked;
+    return getCellData( index ).checked;
   }
 
   /**
@@ -1071,7 +1099,6 @@
   public void setGrayed( boolean grayed ) {
     checkWidget();
     setGrayed( 0, grayed );
-    parent.redraw();
   }
 
   /**
@@ -1113,8 +1140,8 @@
   public void setGrayed( int index, boolean grayed ) {
     checkWidget();
     // [if] TODO: probably need a check for parent.getColumn( index ).isCheck() ?
-    getItemData( index ).grayed = grayed;
-    parent.redraw();
+    getCellData( index ).grayed = grayed;
+    markCached();
   }
 
   /**
@@ -1136,7 +1163,7 @@
   public boolean getGrayed( int index ) {
     checkWidget();
     handleVirtual();
-    return getItemData( index ).grayed;
+    return getCellData( index ).grayed;
   }
 
   /**
@@ -1160,8 +1187,8 @@
   public void setCheckable( int index, boolean checked ) {
     checkWidget();
     // [if] TODO: probably need a check for parent.getColumn( index ).isCheck() ?
-    getItemData( index ).checkable = checked;
-    parent.redraw();
+    getCellData( index ).checkable = checked;
+    markCached();
   }
 
   /**
@@ -1183,7 +1210,7 @@
   public boolean getCheckable( int index ) {
     checkWidget();
     handleVirtual();
-    boolean result = getItemData( index ).checkable;
+    boolean result = getCellData( index ).checkable;
     if( parent.getColumnCount() > 0 && !parent.getColumn( index ).getCheckable() ) {
       result = false;
     }
@@ -1208,11 +1235,11 @@
     if( height < 1 ) {
       SWT.error( SWT.ERROR_INVALID_ARGUMENT );
     }
-    if( customHeight != height ) {
-      customHeight = height;
+    if( getItemData().customHeight != height ) {
+      getItemData().customHeight = height;
       parent.hasDifferingHeights = true;
-      parent.invalidateTopBottomIndex();
-      parent.setScrollValuesObsolete();
+      markCached();
+      parent.scheduleRedraw();
     }
   }
 
@@ -1223,6 +1250,7 @@
    */
   public int getHeight() {
     checkWidget();
+    int customHeight = getItemData().customHeight;
     return customHeight != -1 ? customHeight : parent.getItemHeight();
   }
 
@@ -1239,7 +1267,8 @@
    */
   public void pack() {
     checkWidget();
-    // [if] As different item heights are not supported, we only invalidate the cache here
+    // [if] As different item heights (wordwrap and autoHeight) are not supported,
+    // we only invalidate the cache here
     parent.layoutCache.invalidateItemHeight();
   }
 
@@ -1288,10 +1317,6 @@
     return result;
   }
 
-  void setHasChildren( boolean hasChildren ) {
-    this.hasChildren = hasChildren;
-  }
-
   boolean isVisible() {
     return visible;
   }
@@ -1299,70 +1324,70 @@
   void setVisible( boolean visible ) {
     if( this.visible != visible ) {
       this.visible = visible;
-      if( visible ) {
-        parent.updateVisibleItems( 1 );
-      } else {
-        parent.updateVisibleItems( -1 );
-      }
+      parent.updateVisibleItems( visible ? 1 : -1 );
       if( hasChildren ) {
-        boolean childrenVisible = visible;
-        if( visible ) {
-          childrenVisible = expanded;
-        }
-        for( Iterator<GridItem> itemIterator = children.iterator(); itemIterator.hasNext(); ) {
-          GridItem item = itemIterator.next();
-          item.setVisible( childrenVisible );
+        for( GridItem item : getItemData().getChildren() ) {
+          item.setVisible( visible && isExpanded() );
         }
       }
     }
   }
 
   private void newItem( GridItem item, int index ) {
-    setHasChildren( true );
+    List<GridItem> children = getItemData().getChildren();
     if( index == -1 ) {
       children.add( item );
+      item.index = children.size() - 1;
     } else {
       children.add( index, item );
+      item.index = index;
     }
+    adjustItemIndices( item.index + 1 );
+    hasChildren = true;
   }
 
-  private void remove( GridItem child ) {
-    children.remove( child );
+  private void removeItem( int index ) {
+    if( !hasChildren ) {
+      throw new IllegalArgumentException( "GridItem has no children!" );
+    }
+    List<GridItem> children = getItemData().getChildren();
+    children.remove( index );
+    adjustItemIndices( index );
     hasChildren = children.size() > 0;
   }
 
+  private void adjustItemIndices( int start ) {
+    List<GridItem> children = getItemData().getChildren();
+    for( int i = start; i < children.size(); i++ ) {
+      children.get( i ).index = i;
+    }
+  }
+
   void columnAdded( int index ) {
-    if( parent.getColumnCount() > 1 ) {
-      if( index == -1 ) {
-        data.add( null );
-      } else {
-        data.add( index, null );
-      }
-      hasSetData = false;
+    if( data != null && parent.getColumnCount() > 1 ) {
+      data.addCellData( index );
     }
   }
 
   void columnRemoved( int index ) {
-    if( parent.getColumnCount() > 0 ) {
-      if( data.size() > index ) {
-        data.remove( index );
-      }
+    if( data != null && parent.getColumnCount() > 0 ) {
+      data.removeCellData( index );
     }
   }
 
   void clear( boolean allChildren ) {
-    for( int i = 0; i < parent.getColumnCount(); i++ ) {
-      Data itemData = getItemData( i );
-      updateColumnImageCount( i, itemData.image, null );
-      updateColumnTextCount( i, itemData.text, "" );
+    if( data != null ) {
+      for( int i = 0; i < parent.getColumnCount(); i++ ) {
+        CellData cellData = getCellData( i );
+        updateColumnImageCount( i, cellData.image, null );
+        updateColumnTextCount( i, cellData.text, "" );
+      }
+      data.clear();
     }
-    init();
-    defaultFont = null;
-    defaultBackground = null;
-    defaultForeground = null;
-    hasSetData = false;
+    cached = false;
     // Recursively clear children if requested.
-    if( allChildren ) {
+    if( allChildren && hasChildren ) {
+      List<GridItem> children = getItemData().getChildren();
       for( int i = children.size() - 1; i >= 0; i-- ) {
         children.get( i ).clear( true );
       }
@@ -1382,7 +1407,7 @@
   private int getIndentationWidth( int index ) {
     int result = 0;
     if( parent.isTreeColumn( index ) ) {
-      result = ( level + 1 ) * parent.getIndentationWidth();
+      result = ( getLevel() + 1 ) * parent.getIndentationWidth();
     }
     return result;
   }
@@ -1409,7 +1434,7 @@
 
   private int getSpacing( int index ) {
     int result = 0;
-    String text = getItemData( index ).text;
+    String text = getCellData( index ).text;
     if( parent.hasColumnImages( index ) && text.length() > 0 ) {
       result = parent.getCellSpacing();
     }
@@ -1417,7 +1442,7 @@
   }
 
   private int getTextWidth( int index ) {
-    String text = getItemData( index ).text;
+    String text = getCellData( index ).text;
     if( text.length() > 0 ) {
       return stringExtent( internalGetFont( index ), text, isMarkupEnabledFor( parent ) ).x;
     }
@@ -1436,9 +1461,12 @@
   }
 
   private Font internalGetFont( int index ) {
-    Font result = getItemData( index ).font;
+    Font result = getCellData( index ).font;
     if( result == null ) {
-      result = getFont();
+      result = getItemData().defaultFont;
+    }
+    if( result == null ) {
+      result = parent.getFont();
     }
     return result;
   }
@@ -1450,7 +1478,7 @@
       width += parent.getColumn( index + i ).getWidth();
     }
     GridItem item = this;
-    int itemIndex = parent.indexOf( item );
+    int itemIndex = parent.internalIndexOf( item );
     int height = getHeight();
     span = 0; // getRowSpan( index );
     for( int i = 1; i <= span && i < parent.getItemCount() - itemIndex; i++ ) {
@@ -1462,48 +1490,39 @@
     return new Point( width, height );
   }
 
-  private void init() {
+  private CellData getCellData( int index ) {
+    return getItemData().getCellData( index );
+  }
+
+  private GridItemData getItemData() {
+    ensureItemData();
+    return data;
+  }
+
+  void ensureItemData() {
     if( data == null ) {
-      data = new ArrayList<Data>();
-    } else {
-      data.clear();
-    }
-    data.add( null );
-    for( int i = 1; i < parent.getColumnCount(); i++ ) {
-      data.add( null );
+      data = new GridItemData( parent.getColumnCount() );
     }
   }
 
-  private Data getItemData( int index ) {
-    if( data.get( index ) == null ) {
-      data.set( index, new Data() );
-    }
-    return data.get( index );
-  }
-
-  private void handleVirtual() {
-    if( ( getParent().getStyle() & SWT.VIRTUAL ) != 0 && !hasSetData ) {
-      hasSetData = true;
+  void handleVirtual() {
+    if( !isCached() ) {
+      markCached();
       Event event = new Event();
       event.item = this;
-      if( parentItem == null ) {
-        event.index = getParent().indexOf( this );
-      } else {
-        event.index = parentItem.indexOf( this );
-      }
-      getParent().notifyListeners( SWT.SetData, event );
+      event.index = index;
+      parent.notifyListeners( SWT.SetData, event );
     }
   }
 
   private boolean deselectChildren( GridItem item ) {
     boolean flag = false;
-    GridItem[] kids = item.getItems();
-    for( int i = 0; i < kids.length; i++ ) {
-      if( parent.isSelected( kids[ i ] ) ) {
+    for( GridItem child : item.getItems() ) {
+      if( parent.isSelected( child ) ) {
         flag = true;
       }
-      parent.deselect( parent.indexOf( kids[ i ] ) );
-      if( deselectChildren( kids[ i ] ) ) {
+      parent.deselect( parent.internalIndexOf( child ) );
+      if( deselectChildren( child ) ) {
         flag = true;
       }
     }
@@ -1534,21 +1553,23 @@
     }
   }
 
+  boolean isCached() {
+    return parent.isVirtual() ? cached : true;
+  }
+
+  private void markCached() {
+    if( parent.isVirtual() ) {
+      cached = true;
+    }
+  }
+
+  boolean isResolved() {
+    return parent.isVirtual() ? data != null : true;
+  }
+
   ////////////////
   // Inner classes
 
-  private static final class Data implements SerializableCompatibility {
-    public Font font;
-    public Color background;
-    public Color foreground;
-    public String text = "";
-    public String tooltip;
-    public Image image;
-    public boolean checked;
-    public boolean grayed;
-    public boolean checkable = true;
-  }
-
   private final class GridItemAdapter
     implements IGridItemAdapter, IWidgetFontAdapter, IWidgetColorAdapter
   {
@@ -1558,23 +1579,27 @@
       return itemParent.isDisposed();
     }
 
+    public boolean isCached() {
+      return GridItem.this.isCached();
+    }
+
     public Color getUserBackground() {
-      return defaultBackground;
+      return getItemData().defaultBackground;
     }
 
     public Color getUserForeground() {
-      return defaultForeground;
+      return getItemData().defaultForeground;
     }
 
     public Font getUserFont() {
-      return defaultFont;
+      return getItemData().defaultFont;
     }
 
     public Color[] getCellBackgrounds() {
       int columnCount = Math.max( 1, getParent().getColumnCount() );
       Color[] result = new Color[ columnCount ];
       for( int i = 0; i < columnCount; i++ ) {
-        result[ i ] = getItemData( i ).background;
+        result[ i ] = getCellData( i ).background;
       }
       return result;
     }
@@ -1583,7 +1608,7 @@
       int columnCount = Math.max( 1, getParent().getColumnCount() );
       Color[] result = new Color[ columnCount ];
       for( int i = 0; i < columnCount; i++ ) {
-        result[ i ] = getItemData( i ).foreground;
+        result[ i ] = getCellData( i ).foreground;
       }
       return result;
     }
@@ -1592,7 +1617,7 @@
       int columnCount = Math.max( 1, getParent().getColumnCount() );
       Font[] result = new Font[ columnCount ];
       for( int i = 0; i < columnCount; i++ ) {
-        result[ i ] = getItemData( i ).font;
+        result[ i ] = getCellData( i ).font;
       }
       return result;
     }
diff --git a/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/GridItemData.java b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/GridItemData.java
new file mode 100644
index 0000000..f94d5e0
--- /dev/null
+++ b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/GridItemData.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2014 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;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.nebula.widgets.grid.GridItem;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.internal.SerializableCompatibility;
+
+
+@SuppressWarnings( "restriction" )
+public class GridItemData implements SerializableCompatibility {
+
+  public Font defaultFont;
+  public Color defaultBackground;
+  public Color defaultForeground;
+  public int customHeight = -1;
+  public boolean expanded;
+
+  List<GridItem> children;
+  final List<CellData> cellData;
+
+  public GridItemData( int cells ) {
+    cellData = new ArrayList<CellData>();
+    for( int i = 0; i < Math.max( 1, cells ); i++ ) {
+      cellData.add( null );
+    }
+  }
+
+  public List<GridItem> getChildren() {
+    if( children == null ) {
+      children = new ArrayList<GridItem>();
+    }
+    return children;
+  }
+
+  public void addCellData( int index ) {
+    if( index == -1 ) {
+      cellData.add( null );
+    } else {
+      cellData.add( index, null );
+    }
+  }
+
+  public void removeCellData( int index ) {
+    if( cellData.size() > index ) {
+      cellData.remove( index );
+    }
+  }
+
+  public CellData getCellData( int index ) {
+    if( cellData.get( index ) == null ) {
+      cellData.set( index, new CellData() );
+    }
+    return cellData.get( index );
+  }
+
+  public void clear() {
+    for( int index = 0; index < cellData.size(); index++ ) {
+      cellData.set( index, null );
+    }
+    defaultFont = null;
+    defaultBackground = null;
+    defaultForeground = null;
+  }
+
+  public static final class CellData implements SerializableCompatibility {
+    public Font font;
+    public Color background;
+    public Color foreground;
+    public String text = "";
+    public String tooltip;
+    public Image image;
+    public boolean checked;
+    public boolean grayed;
+    public boolean checkable = true;
+  }
+
+}
diff --git a/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/IGridItemAdapter.java b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/IGridItemAdapter.java
index 268c6ea..300816c 100644
--- a/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/IGridItemAdapter.java
+++ b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/IGridItemAdapter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012 EclipseSource and others.
+ * Copyright (c) 2012, 2014 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
@@ -20,5 +20,6 @@
   Color[] getCellForegrounds();
   Font[] getCellFonts();
   boolean isParentDisposed();
+  boolean isCached();
 
 }
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 1407fe5..ed139df 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
@@ -22,15 +22,17 @@
 import org.eclipse.nebula.widgets.grid.internal.IGridAdapter;
 import org.eclipse.nebula.widgets.grid.internal.IGridItemAdapter;
 import org.eclipse.rap.rwt.internal.lifecycle.AbstractWidgetLCA;
+import org.eclipse.rap.rwt.internal.lifecycle.WidgetAdapter;
 import org.eclipse.rap.rwt.internal.lifecycle.WidgetLCAUtil;
-import org.eclipse.rap.rwt.internal.remote.RemoteObjectImpl;
 import org.eclipse.rap.rwt.internal.lifecycle.WidgetUtil;
+import org.eclipse.rap.rwt.internal.remote.RemoteObjectImpl;
 import org.eclipse.rap.rwt.remote.RemoteObject;
 import org.eclipse.swt.graphics.Color;
 import org.eclipse.swt.graphics.Font;
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.internal.widgets.IWidgetColorAdapter;
 import org.eclipse.swt.internal.widgets.IWidgetFontAdapter;
+import org.eclipse.swt.internal.widgets.WidgetAdapterImpl;
 import org.eclipse.swt.widgets.Widget;
 
 
@@ -39,6 +41,7 @@
 
   private static final String TYPE = "rwt.widgets.GridItem";
 
+  private static final String PROP_INDEX = "index";
   private static final String PROP_ITEM_COUNT = "itemCount";
   private static final String PROP_HEIGHT = "height";
   private static final String PROP_TEXTS = "texts";
@@ -50,6 +53,7 @@
   private static final String PROP_CELL_CHECKED = "cellChecked";
   private static final String PROP_CELL_GRAYED = "cellGrayed";
   private static final String PROP_CELL_CHECKABLE = "cellCheckable";
+  private static final String PROP_CACHED = "cached";
 
   private static final int ZERO = 0;
 
@@ -59,33 +63,58 @@
     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 preserveValues( Widget widget ) {
     GridItem item = ( GridItem )widget;
-    WidgetLCAUtil.preserveCustomVariant( item );
-    WidgetLCAUtil.preserveData( item );
-    preserveProperty( item, PROP_ITEM_COUNT, item.getItemCount() );
-    preserveProperty( item, PROP_HEIGHT, item.getHeight() );
-    preserveProperty( item, PROP_TEXTS, getTexts( item ) );
-    preserveProperty( item, PROP_IMAGES, getImages( item ) );
-    WidgetLCAUtil.preserveBackground( item, getUserBackground( item ) );
-    WidgetLCAUtil.preserveForeground( item, getUserForeground( item ) );
-    WidgetLCAUtil.preserveFont( item, getUserFont( item ) );
-    preserveProperty( item, PROP_CELL_BACKGROUNDS, getCellBackgrounds( item ) );
-    preserveProperty( item, PROP_CELL_FOREGROUNDS, getCellForegrounds( item ) );
-    preserveProperty( item, PROP_CELL_FONTS, getCellFonts( item ) );
-    preserveProperty( item, PROP_EXPANDED, item.isExpanded() );
-    preserveProperty( item, PROP_CELL_CHECKED, getCellChecked( item ) );
-    preserveProperty( item, PROP_CELL_GRAYED, getCellGrayed( item ) );
-    preserveProperty( item, PROP_CELL_CHECKABLE, getCellCheckable( item ) );
+    preserveProperty( item, PROP_INDEX, getItemIndex( item ) );
+    preserveProperty( item, PROP_CACHED, isCached( item ) );
+    if( isCached( item ) ) {
+      WidgetLCAUtil.preserveCustomVariant( item );
+      WidgetLCAUtil.preserveData( item );
+      preserveProperty( item, PROP_ITEM_COUNT, item.getItemCount() );
+      preserveProperty( item, PROP_HEIGHT, item.getHeight() );
+      preserveProperty( item, PROP_TEXTS, getTexts( item ) );
+      preserveProperty( item, PROP_IMAGES, getImages( item ) );
+      WidgetLCAUtil.preserveBackground( item, getUserBackground( item ) );
+      WidgetLCAUtil.preserveForeground( item, getUserForeground( item ) );
+      WidgetLCAUtil.preserveFont( item, getUserFont( item ) );
+      preserveProperty( item, PROP_CELL_BACKGROUNDS, getCellBackgrounds( item ) );
+      preserveProperty( item, PROP_CELL_FOREGROUNDS, getCellForegrounds( item ) );
+      preserveProperty( item, PROP_CELL_FONTS, getCellFonts( item ) );
+      preserveProperty( item, PROP_EXPANDED, item.isExpanded() );
+      preserveProperty( item, PROP_CELL_CHECKED, getCellChecked( item ) );
+      preserveProperty( item, PROP_CELL_GRAYED, getCellGrayed( item ) );
+      preserveProperty( item, PROP_CELL_CHECKABLE, getCellCheckable( item ) );
+    }
   }
 
   @Override
   public void renderChanges( Widget widget ) throws IOException {
-    GridItem item = ( GridItem )widget;
+    final GridItem item = ( GridItem )widget;
+    renderProperty( item, PROP_INDEX, getItemIndex( item ), -1 );
+    if( wasCleared( item ) ) {
+      renderClear( item );
+    } else if( isCached( item ) ) {
+      preservingInitialized( item, new Runnable() {
+        public void run() {
+          // items that were uncached and are now cached (materialized) are handled as if they were
+          // just created (initialized = false)
+          if( !wasCached( item ) ) {
+            setInitialized( item, false );
+          }
+          renderProperties( item );
+        }
+      } );
+    }
+  }
+
+  private static void renderClear( GridItem item ) {
+    getRemoteObject( item ).call( "clear", null );
+  }
+
+  private static void renderProperties( GridItem item ) {
     WidgetLCAUtil.renderCustomVariant( item );
     WidgetLCAUtil.renderData( item );
     renderProperty( item, PROP_ITEM_COUNT, item.getItemCount(), ZERO );
@@ -134,9 +163,26 @@
     }
   }
 
+
   //////////////////
   // Helping methods
 
+  private static boolean wasCleared( GridItem item ) {
+    return !isCached( item ) && wasCached( item );
+  }
+
+  private static boolean isCached( GridItem item ) {
+    return getGridItemAdapter( item ).isCached();
+  }
+
+  private static boolean wasCached( GridItem item ) {
+    WidgetAdapter adapter = WidgetUtil.getAdapter( item );
+    if( adapter.isInitialized() ) {
+      return Boolean.TRUE.equals( adapter.getPreserved( PROP_CACHED ) );
+    }
+    return false;
+  }
+
   private static Widget getParent( GridItem item ) {
     Widget result = item.getParent();
     GridItem parentItem = item.getParentItem();
@@ -245,4 +291,16 @@
   private static IGridItemAdapter getGridItemAdapter( GridItem item ) {
     return item.getAdapter( IGridItemAdapter.class );
   }
+
+  private static void preservingInitialized( GridItem item, Runnable runnable ) {
+    boolean initialized = WidgetUtil.getAdapter( item ).isInitialized();
+    runnable.run();
+    setInitialized( item, initialized );
+  }
+
+  private static void setInitialized( GridItem item, boolean initialized ) {
+    WidgetAdapterImpl adapter = ( WidgetAdapterImpl )WidgetUtil.getAdapter( item );
+    adapter.setInitialized( initialized );
+  }
+
 }
diff --git a/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/GridItem_Test.java b/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/GridItem_Test.java
index 3d57f4e..8560267 100644
--- a/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/GridItem_Test.java
+++ b/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/GridItem_Test.java
@@ -52,7 +52,7 @@
   private List<Event> eventLog;
 
   @Before
-  public void setUp() throws Exception {
+  public void setUp() {
     Fixture.setUp();
     Fixture.fakePhase( PhaseId.PROCESS_ACTION );
     display = new Display();
@@ -123,6 +123,16 @@
   }
 
   @Test
+  public void testGridItemCreation_onVirtual_doesNotResolveItem() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    grid.setItemCount( 1 );
+
+    GridItem item = grid.getItem( 0 );
+
+    assertFalse( item.isResolved() );
+  }
+
+  @Test
   public void testGetItemCount() {
     createGridItems( grid, 1, 10 );
 
@@ -431,9 +441,20 @@
   }
 
   @Test
+  public void testSetText_marksItemCached() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    GridItem item = new GridItem( grid, SWT.NONE );
+
+    item.setText( "foo" );
+
+    assertTrue( item.isCached() );
+  }
+
+  @Test
   public void testHandleVirtual_RootItem() {
     grid = new Grid( shell, SWT.VIRTUAL );
     GridItem[] items = createGridItems( grid, 3, 3 );
+    grid.clearAll( true );
     grid.addListener( SWT.SetData, new LoggingListener() );
 
     items[ 4 ].getText();
@@ -442,13 +463,14 @@
     Event event = eventLog.get( 0 );
     assertSame( grid, event.widget );
     assertSame( items[ 4 ], event.item );
-    assertEquals( 4, event.index );
+    assertEquals( 1, event.index );
   }
 
   @Test
   public void testHandleVirtual_SubItem() {
     grid = new Grid( shell, SWT.VIRTUAL );
     GridItem[] items = createGridItems( grid, 3, 3 );
+    grid.clearAll( true );
     grid.addListener( SWT.SetData, new LoggingListener() );
 
     items[ 2 ].getText();
@@ -464,6 +486,7 @@
   public void testHandleVirtual_Twice() {
     grid = new Grid( shell, SWT.VIRTUAL );
     GridItem[] items = createGridItems( grid, 3, 3 );
+    grid.clearAll( true );
     grid.addListener( SWT.SetData, new LoggingListener() );
 
     items[ 2 ].getText();
@@ -499,6 +522,16 @@
   }
 
   @Test
+  public void testSetFont_marksItemCached() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    GridItem item = new GridItem( grid, SWT.NONE );
+
+    item.setFont( new Font( display, "Arial", 20, SWT.BOLD ) );
+
+    assertTrue( item.isCached() );
+  }
+
+  @Test
   public void testGetFontByIndex() {
     createGridColumns( grid, 3, SWT.NONE );
     GridItem item = new GridItem( grid, SWT.NONE );
@@ -530,6 +563,16 @@
   }
 
   @Test
+  public void testSetFontByIndex_marksItemCached() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    GridItem item = new GridItem( grid, SWT.NONE );
+
+    item.setFont( 0, new Font( display, "Arial", 20, SWT.BOLD ) );
+
+    assertTrue( item.isCached() );
+  }
+
+  @Test
   public void testGetBackground_Initial() {
     GridItem item = new GridItem( grid, SWT.NONE );
 
@@ -556,6 +599,16 @@
   }
 
   @Test
+  public void testSetBackground_marksItemCached() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    GridItem item = new GridItem( grid, SWT.NONE );
+
+    item.setBackground( new Color( display, 0, 0, 255 ) );
+
+    assertTrue( item.isCached() );
+  }
+
+  @Test
   public void testGetBackgroundByIndex() {
     createGridColumns( grid, 3, SWT.NONE );
     GridItem item = new GridItem( grid, SWT.NONE );
@@ -587,6 +640,16 @@
   }
 
   @Test
+  public void testSetBackgroundByIndex_marksItemCached() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    GridItem item = new GridItem( grid, SWT.NONE );
+
+    item.setBackground( 0, new Color( display, 0, 0, 255 ) );
+
+    assertTrue( item.isCached() );
+  }
+
+  @Test
   public void testGetForeground_Initial() {
     GridItem item = new GridItem( grid, SWT.NONE );
 
@@ -613,6 +676,16 @@
   }
 
   @Test
+  public void testSetForeground_marksItemCached() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    GridItem item = new GridItem( grid, SWT.NONE );
+
+    item.setForeground( new Color( display, 0, 0, 255 ) );
+
+    assertTrue( item.isCached() );
+  }
+
+  @Test
   public void testGetForegroundByIndex() {
     createGridColumns( grid, 3, SWT.NONE );
     GridItem item = new GridItem( grid, SWT.NONE );
@@ -644,6 +717,16 @@
   }
 
   @Test
+  public void testSetForegroundByIndex_marksItemCached() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    GridItem item = new GridItem( grid, SWT.NONE );
+
+    item.setForeground( 0, new Color( display, 0, 0, 255 ) );
+
+    assertTrue( item.isCached() );
+  }
+
+  @Test
   public void testClear() {
     GridItem item = new GridItem( grid, SWT.NONE );
     Font font = new Font( display, "Arial", 20, SWT.BOLD );
@@ -708,6 +791,16 @@
   }
 
   @Test
+  public void testSetImage_marksItemCached() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    GridItem item = new GridItem( grid, SWT.NONE );
+
+    item.setImage( loadImage( display, Fixture.IMAGE1 ) );
+
+    assertTrue( item.isCached() );
+  }
+
+  @Test
   public void testGetImageByIndex() {
     createGridColumns( grid, 3, SWT.NONE );
     GridItem item = new GridItem( grid, SWT.NONE );
@@ -755,6 +848,16 @@
   }
 
   @Test
+  public void testSetChecked_marksItemCached() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    GridItem item = new GridItem( grid, SWT.NONE );
+
+    item.setChecked( true );
+
+    assertTrue( item.isCached() );
+  }
+
+  @Test
   public void testGetCheckedByIndex() {
     createGridColumns( grid, 3, SWT.NONE );
     GridItem item = new GridItem( grid, SWT.NONE );
@@ -791,6 +894,16 @@
   }
 
   @Test
+  public void testSetGrayed_marksItemCached() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    GridItem item = new GridItem( grid, SWT.NONE );
+
+    item.setGrayed( true );
+
+    assertTrue( item.isCached() );
+  }
+
+  @Test
   public void testGetGrayedByIndex() {
     createGridColumns( grid, 3, SWT.NONE );
     GridItem item = new GridItem( grid, SWT.NONE );
@@ -828,6 +941,16 @@
     assertFalse( item.getCheckable( 1 ) );
   }
 
+  @Test
+  public void testSetCheckable_marksItemCached() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    GridItem item = new GridItem( grid, SWT.NONE );
+
+    item.setCheckable( 0, false );
+
+    assertTrue( item.isCached() );
+  }
+
   @Test( expected = IndexOutOfBoundsException.class )
   public void testGetCheckableByIndex_InvalidIndex() {
     createGridColumns( grid, 3, SWT.NONE );
@@ -1075,6 +1198,306 @@
     assertEquals( 1, columns[ 1 ].imageCount );
   }
 
+  @Test
+  public void testGetText_onVirtual_resolvesItem() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    grid.setItemCount( 1 );
+
+    GridItem item = grid.getItem( 0 );
+    item.getText();
+
+    assertTrue( item.isResolved() );
+  }
+
+  @Test
+  public void testSetText_onVirtual_resolvesItem() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    grid.setItemCount( 1 );
+
+    GridItem item = grid.getItem( 0 );
+    item.setText( "foo" );
+
+    assertTrue( item.isResolved() );
+  }
+
+  @Test
+  public void testGetToolTipText_onVirtual_resolvesItem() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    grid.setItemCount( 1 );
+
+    GridItem item = grid.getItem( 0 );
+    item.getToolTipText( 0 );
+
+    assertTrue( item.isResolved() );
+  }
+
+  @Test
+  public void testSetToolTipText_onVirtual_resolvesItem() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    grid.setItemCount( 1 );
+
+    GridItem item = grid.getItem( 0 );
+    item.setToolTipText( 0, "foo" );
+
+    assertTrue( item.isResolved() );
+  }
+
+  @Test
+  public void testGetImage_onVirtual_resolvesItem() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    grid.setItemCount( 1 );
+
+    GridItem item = grid.getItem( 0 );
+    item.getImage();
+
+    assertTrue( item.isResolved() );
+  }
+
+  @Test
+  public void testSetImage_onVirtual_resolvesItem() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    grid.setItemCount( 1 );
+
+    GridItem item = grid.getItem( 0 );
+    item.setImage( loadImage( display, Fixture.IMAGE1 ) );
+
+    assertTrue( item.isResolved() );
+  }
+
+  @Test
+  public void testGetChecked_onVirtual_resolvesItem() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    grid.setItemCount( 1 );
+
+    GridItem item = grid.getItem( 0 );
+    item.getChecked();
+
+    assertTrue( item.isResolved() );
+  }
+
+  @Test
+  public void testSetChecked_onVirtual_resolvesItem() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    grid.setItemCount( 1 );
+
+    GridItem item = grid.getItem( 0 );
+    item.setChecked( true );
+
+    assertTrue( item.isResolved() );
+  }
+
+  @Test
+  public void testGetGrayed_onVirtual_resolvesItem() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    grid.setItemCount( 1 );
+
+    GridItem item = grid.getItem( 0 );
+    item.getGrayed();
+
+    assertTrue( item.isResolved() );
+  }
+
+  @Test
+  public void testSetGrayed_onVirtual_resolvesItem() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    grid.setItemCount( 1 );
+
+    GridItem item = grid.getItem( 0 );
+    item.setGrayed( true );
+
+    assertTrue( item.isResolved() );
+  }
+
+  @Test
+  public void testGetCheckable_onVirtual_resolvesItem() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    grid.setItemCount( 1 );
+
+    GridItem item = grid.getItem( 0 );
+    item.getCheckable( 0 );
+
+    assertTrue( item.isResolved() );
+  }
+
+  @Test
+  public void testSetCheckable_onVirtual_resolvesItem() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    grid.setItemCount( 1 );
+
+    GridItem item = grid.getItem( 0 );
+    item.setCheckable( 0, true );
+
+    assertTrue( item.isResolved() );
+  }
+
+  @Test
+  public void testGetFont_onVirtual_resolvesItem() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    grid.setItemCount( 1 );
+
+    GridItem item = grid.getItem( 0 );
+    item.getFont();
+
+    assertTrue( item.isResolved() );
+  }
+
+  @Test
+  public void testSetFont_onVirtual_resolvesItem() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    grid.setItemCount( 1 );
+
+    GridItem item = grid.getItem( 0 );
+    item.setFont( new Font( display, "Arial", 20, SWT.BOLD ) );
+
+    assertTrue( item.isResolved() );
+  }
+
+  @Test
+  public void testGetBackground_onVirtual_resolvesItem() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    grid.setItemCount( 1 );
+
+    GridItem item = grid.getItem( 0 );
+    item.getBackground();
+
+    assertTrue( item.isResolved() );
+  }
+
+  @Test
+  public void testSetBackground_onVirtual_resolvesItem() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    grid.setItemCount( 1 );
+
+    GridItem item = grid.getItem( 0 );
+    item.setBackground( new Color( display, 0, 0, 255 ) );
+
+    assertTrue( item.isResolved() );
+  }
+
+  @Test
+  public void testGetForeground_onVirtual_resolvesItem() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    grid.setItemCount( 1 );
+
+    GridItem item = grid.getItem( 0 );
+    item.getForeground();
+
+    assertTrue( item.isResolved() );
+  }
+
+  @Test
+  public void testSetForeground_onVirtual_resolvesItem() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    grid.setItemCount( 1 );
+
+    GridItem item = grid.getItem( 0 );
+    item.setForeground( new Color( display, 0, 0, 255 ) );
+
+    assertTrue( item.isResolved() );
+  }
+
+  @Test
+  public void testIsExpanded_onVirtual_doesNotResolveItem() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    grid.setItemCount( 1 );
+
+    GridItem item = grid.getItem( 0 );
+    item.isExpanded();
+
+    assertFalse( item.isResolved() );
+  }
+
+  @Test
+  public void testSetExpanded_onVirtual_resolvesItem() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    grid.setItemCount( 1 );
+
+    GridItem item = grid.getItem( 0 );
+    item.setExpanded( true );
+
+    assertTrue( item.isResolved() );
+  }
+
+  @Test
+  public void testGetHeight_onVirtual_resolvesItem() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    grid.setItemCount( 1 );
+
+    GridItem item = grid.getItem( 0 );
+    item.getHeight();
+
+    assertTrue( item.isResolved() );
+  }
+
+  @Test
+  public void testSetHeight_onVirtual_resolvesItem() {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    grid.setItemCount( 1 );
+
+    GridItem item = grid.getItem( 0 );
+    item.setHeight( 30 );
+
+    assertTrue( item.isResolved() );
+  }
+
+  @Test
+  public void testItemIndex() {
+    createGridItems( grid, 3, 0 );
+
+    GridItem item = new GridItem( grid, SWT.NONE, 1 );
+
+    assertEquals( 1, item.index );
+  }
+
+  @Test
+  public void testItemIndex_isIncreasedAfterItemIsAdded() {
+    createGridItems( grid, 3, 0 );
+
+    new GridItem( grid, SWT.NONE, 1 );
+
+    assertEquals( 0, grid.getItem( 0 ).index );
+    assertEquals( 3, grid.getItem( 3 ).index );
+  }
+
+  @Test
+  public void testItemIndex_isDecreasedAfterItemIsRemoved() {
+    createGridItems( grid, 3, 0 );
+
+    grid.getItem( 1 ).dispose();
+
+    assertEquals( 0, grid.getItem( 0 ).index );
+    assertEquals( 1, grid.getItem( 1 ).index );
+  }
+
+  @Test
+  public void testItemIndex_ofSubItem() {
+    createGridItems( grid, 3, 3 );
+
+    GridItem item = new GridItem( grid.getItem( 0 ), SWT.NONE, 1 );
+
+    assertEquals( 1, item.index );
+  }
+
+  @Test
+  public void testItemIndex_ofSubItem_isIncreasedAfterItemIsAdded() {
+    createGridItems( grid, 3, 3 );
+
+    new GridItem( grid.getItem( 0 ), SWT.NONE, 1 );
+
+    assertEquals( 0, grid.getItem( 1 ).index );
+    assertEquals( 3, grid.getItem( 4 ).index );
+  }
+
+  @Test
+  public void testItemIndex_ofSubItem_isDecreasedAfterItemIsRemoved() {
+    createGridItems( grid, 3, 3 );
+
+    grid.getItem( 2 ).dispose();
+
+    assertEquals( 0, grid.getItem( 1 ).index );
+    assertEquals( 1, grid.getItem( 2 ).index );
+  }
+
   //////////////////
   // Helping methods
 
diff --git a/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/Grid_Test.java b/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/Grid_Test.java
index 19a89d7..5c94f7d 100644
--- a/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/Grid_Test.java
+++ b/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/Grid_Test.java
@@ -13,16 +13,23 @@
 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.junit.Assert.assertArrayEquals;
+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.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
-import junit.framework.TestCase;
-
 import org.eclipse.nebula.widgets.grid.internal.IGridAdapter;
 import org.eclipse.nebula.widgets.grid.internal.NullScrollBarProxy;
 import org.eclipse.nebula.widgets.grid.internal.ScrollBarProxyAdapter;
@@ -40,6 +47,7 @@
 import org.eclipse.swt.graphics.Rectangle;
 import org.eclipse.swt.internal.widgets.ICellToolTipAdapter;
 import org.eclipse.swt.internal.widgets.IItemHolderAdapter;
+import org.eclipse.swt.internal.widgets.ItemHolder;
 import org.eclipse.swt.internal.widgets.MarkupValidator;
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Event;
@@ -47,12 +55,15 @@
 import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.ScrollBar;
 import org.eclipse.swt.widgets.Shell;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
 
 
 @SuppressWarnings({
   "restriction", "deprecation"
 })
-public class Grid_Test extends TestCase {
+public class Grid_Test {
 
   private Display display;
   private Shell shell;
@@ -61,8 +72,8 @@
   private ScrollBar horizontalBar;
   private List<Event> eventLog;
 
-  @Override
-  protected void setUp() {
+  @Before
+  public void setUp() {
     Fixture.setUp();
     Fixture.fakePhase( PhaseId.PROCESS_ACTION );
     display = new Display();
@@ -74,11 +85,12 @@
     eventLog = new ArrayList<Event>();
   }
 
-  @Override
-  protected void tearDown() {
+  @After
+  public void tearDown() {
     Fixture.tearDown();
   }
 
+  @Test
   public void testGridCreation() {
     grid = new Grid( shell, SWT.NONE );
     assertNotNull( grid );
@@ -89,6 +101,7 @@
     assertEquals( 0, grid.getRootItemCount() );
   }
 
+  @Test
   public void testGridCreationWithScrollBars() {
     grid = new Grid( shell, SWT.H_SCROLL | SWT.V_SCROLL );
     assertTrue( grid.getHorizontalScrollBarProxy() instanceof ScrollBarProxyAdapter );
@@ -97,6 +110,7 @@
     assertFalse( grid.getVerticalBar().isVisible() );
   }
 
+  @Test
   public void testStyle() {
     Grid grid = new Grid( shell, SWT.NONE );
     assertTrue( ( grid.getStyle() & SWT.DOUBLE_BUFFERED ) != 0 );
@@ -115,18 +129,21 @@
     assertTrue( ( grid.getStyle() & SWT.CHECK ) != 0 );
   }
 
+  @Test
   public void testGetRootItemCount() {
     createGridItems( grid, 5, 1 );
 
     assertEquals( 5, grid.getRootItemCount() );
   }
 
+  @Test
   public void testGetItemCount() {
     createGridItems( grid, 5, 1 );
 
     assertEquals( 10, grid.getItemCount() );
   }
 
+  @Test
   public void testSetItemCount_MoreItems() {
     createGridItems( grid, 3, 3 );
 
@@ -136,6 +153,7 @@
     assertEquals( 6, grid.getRootItemCount() );
   }
 
+  @Test
   public void testSetItemCount_LessItems() {
     GridItem[] items = createGridItems( grid, 3, 3 );
 
@@ -146,6 +164,7 @@
     assertEquals( 1, items[ 4 ].getItemCount() );
   }
 
+  @Test
   public void testSetItemCount_NoChange() {
     GridItem[] items = createGridItems( grid, 3, 3 );
 
@@ -154,6 +173,7 @@
     assertTrue( Arrays.equals( items, grid.getItems() ) );
   }
 
+  @Test
   public void testGetRootItems() {
     GridItem[] items = createGridItems( grid, 3, 1 );
 
@@ -163,12 +183,14 @@
     assertSame( items[ 4 ], rootItems[ 2 ] );
   }
 
+  @Test
   public void testGetItems() {
     GridItem[] items = createGridItems( grid, 3, 1 );
 
     assertTrue( Arrays.equals( items, grid.getItems() ) );
   }
 
+  @Test
   public void testGetRootItem() {
     GridItem[] items = createGridItems( grid, 3, 1 );
 
@@ -176,16 +198,14 @@
     assertSame( items[ 4 ], grid.getRootItem( 2 ) );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testGetRootItem_InvalidIndex() {
     createGridItems( grid, 3, 1 );
 
-    try {
-      grid.getRootItem( 10 );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.getRootItem( 10 );
   }
 
+  @Test
   public void testGetItem() {
     GridItem[] items = createGridItems( grid, 3, 1 );
 
@@ -193,32 +213,28 @@
     assertSame( items[ 4 ], grid.getItem( 4 ) );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testGetItem_InvalidIndex() {
     createGridItems( grid, 3, 1 );
 
-    try {
-      grid.getItem( 10 );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.getItem( 10 );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testGetItemByPoint_NullArgument() {
     createGridItems( grid, 3, 1 );
 
-    try {
-      grid.getItem( null );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.getItem( null );
   }
 
+  @Test
   public void testGetItemByPoint() {
     GridItem[] items = createGridItems( grid, 10, 0 );
 
     assertSame( items[ 2 ], grid.getItem( new Point( 10, 60 ) ) );
   }
 
+  @Test
   public void testGetItemByPoint_WithHeaderVisible() {
     grid.setHeaderVisible( true );
     createGridColumns( grid, 1, SWT.NONE );
@@ -227,6 +243,7 @@
     assertSame( items[ 1 ], grid.getItem( new Point( 10, 60 ) ) );
   }
 
+  @Test
   public void testGetItemByPoint_WithinHeader() {
     grid.setHeaderVisible( true );
     createGridColumns( grid, 1, SWT.NONE );
@@ -235,6 +252,7 @@
     assertNull( grid.getItem( new Point( 10, 20 ) ) );
   }
 
+  @Test
   public void testIndexOf() {
     GridItem[] items = createGridItems( grid, 3, 1 );
 
@@ -242,14 +260,12 @@
     assertEquals( 4, grid.indexOf( items[ 4 ] ) );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testIndexOf_NullArgument() {
-    try {
-      grid.indexOf( ( GridItem )null );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.indexOf( ( GridItem )null );
   }
 
+  @Test
   public void testIndexOf_DifferentParent() {
     Grid otherGrid = new Grid( shell, SWT.NONE );
     GridItem item = new GridItem( otherGrid, SWT.NONE );
@@ -257,6 +273,7 @@
     assertEquals( -1, grid.indexOf( item ) );
   }
 
+  @Test
   public void testIndexOf_AfterDispose() {
     GridItem[] items = createGridItems( grid, 3, 1 );
 
@@ -266,18 +283,21 @@
     assertEquals( 2, grid.indexOf( items[ 4 ] ) );
   }
 
+  @Test
   public void testGetColumnCount() {
     createGridColumns( grid, 5, SWT.NONE );
 
     assertEquals( 5, grid.getColumnCount() );
   }
 
+  @Test
   public void testGetColumns() {
     GridColumn[] columns = createGridColumns( grid, 5, SWT.NONE );
 
     assertTrue( Arrays.equals( columns, grid.getColumns() ) );
   }
 
+  @Test
   public void testGetColumn() {
     GridColumn[] columns = createGridColumns( grid, 5, SWT.NONE );
 
@@ -285,16 +305,14 @@
     assertSame( columns[ 4 ], grid.getColumn( 4 ) );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testGetColumn_InvalidIndex() {
     createGridColumns( grid, 3, SWT.NONE );
 
-    try {
-      grid.getColumn( 10 );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.getColumn( 10 );
   }
 
+  @Test
   public void testIndexOfColumn() {
     GridColumn[] columns = createGridColumns( grid, 5, SWT.NONE );
 
@@ -302,14 +320,12 @@
     assertEquals( 4, grid.indexOf( columns[ 4 ] ) );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testIndexOfColumn_NullArgument() {
-    try {
-      grid.indexOf( ( GridColumn )null );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.indexOf( ( GridColumn )null );
   }
 
+  @Test
   public void testIndexOfColumn_DifferentParent() {
     Grid otherGrid = new Grid( shell, SWT.NONE );
     GridColumn column = new GridColumn( otherGrid, SWT.NONE );
@@ -317,6 +333,7 @@
     assertEquals( -1, grid.indexOf( column ) );
   }
 
+  @Test
   public void testIndexOfColumn_AfterDispose() {
     GridColumn[] columns = createGridColumns( grid, 5, SWT.NONE );
 
@@ -325,6 +342,7 @@
     assertEquals( 3, grid.indexOf( columns[ 4 ] ) );
   }
 
+  @Test
   public void testDispose() {
     grid.dispose();
 
@@ -332,6 +350,17 @@
     assertTrue( grid.isDisposed() );
   }
 
+  @Test
+  public void testDispose_fireDisposeEventOnlyOnce() {
+    Listener listener = mock( Listener.class );
+    grid.addListener( SWT.Dispose, listener );
+
+    grid.dispose();
+
+    verify( listener, times( 1 ) ).handleEvent( any( Event.class ) );
+  }
+
+  @Test
   public void testDispose_WithItems() {
     GridItem[] items = createGridItems( grid, 1, 1 );
 
@@ -341,6 +370,7 @@
     assertTrue( items[ 1 ].isDisposed() );
   }
 
+  @Test
   public void testDispose_WithColumns() {
     GridColumn[] columns = createGridColumns( grid, 2, SWT.NONE );
 
@@ -350,6 +380,7 @@
     assertTrue( columns[ 1 ].isDisposed() );
   }
 
+  @Test
   public void testSendDisposeEvent() {
     DisposeListener listener = mock( DisposeListener.class );
     grid.addDisposeListener( listener );
@@ -359,6 +390,7 @@
     verify( listener ).widgetDisposed( any( DisposeEvent.class ) );
   }
 
+  @Test
   public void testAddRemoveSelectionListener() {
     SelectionListener listener = mock( SelectionListener.class );
     grid.addSelectionListener( listener );
@@ -371,6 +403,7 @@
     assertFalse( grid.isListening( SWT.DefaultSelection ) );
   }
 
+  @Test
   public void testAddRemoveTreeListener() {
     TreeListener listener = mock( TreeListener.class );
     grid.addTreeListener( listener );
@@ -383,6 +416,7 @@
     assertFalse( grid.isListening( SWT.Collapse ) );
   }
 
+  @Test
   public void testClearAll() {
     GridItem[] items = createGridItems( grid, 3, 3 );
     items[ 0 ].setText( "foo" );
@@ -397,6 +431,7 @@
     assertEquals( "", items[ 4 ].getText() );
   }
 
+  @Test
   public void testClearByIndex() {
     GridItem[] items = createGridItems( grid, 3, 3 );
     items[ 0 ].setText( "foo" );
@@ -410,6 +445,7 @@
     assertEquals( "root", items[ 4 ].getText() );
   }
 
+  @Test
   public void testClearByIndex_AllChildren() {
     GridItem[] items = createGridItems( grid, 3, 3 );
     items[ 0 ].setText( "foo" );
@@ -423,16 +459,14 @@
     assertEquals( "root", items[ 4 ].getText() );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testClearByIndex_InvalidIndex() {
     createGridItems( grid, 3, 3 );
 
-    try {
-      grid.clear( 20, false );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.clear( 20, false );
   }
 
+  @Test
   public void testClearByIndexRange() {
     GridItem[] items = createGridItems( grid, 3, 3 );
     items[ 0 ].setText( "foo" );
@@ -448,6 +482,7 @@
     assertEquals( "root", items[ 4 ].getText() );
   }
 
+  @Test
   public void testClearByIndexRange_AllChildren() {
     GridItem[] items = createGridItems( grid, 3, 3 );
     items[ 0 ].setText( "first" );
@@ -465,26 +500,21 @@
     assertEquals( "", items[ 7 ].getText() );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testClearByIndexRange_InvalidIndex1() {
     createGridItems( grid, 3, 3 );
 
-    try {
-      grid.clear( -1, 4, false );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.clear( -1, 4, false );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testClearByIndexRange_InvalidIndex2() {
     createGridItems( grid, 3, 3 );
 
-    try {
-      grid.clear( 1, 20, false );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.clear( 1, 20, false );
   }
 
+  @Test
   public void testClearByIndexRange_InvalidIndex3() {
     GridItem[] items = createGridItems( grid, 3, 3 );
     items[ 0 ].setText( "foo" );
@@ -500,6 +530,7 @@
     assertEquals( "root", items[ 4 ].getText() );
   }
 
+  @Test
   public void testClearByIndices() {
     GridItem[] items = createGridItems( grid, 3, 3 );
     items[ 0 ].setText( "foo" );
@@ -515,6 +546,7 @@
     assertEquals( "root", items[ 4 ].getText() );
   }
 
+  @Test
   public void testClearByIndices_AllChildren() {
     GridItem[] items = createGridItems( grid, 3, 3 );
     items[ 0 ].setText( "foo" );
@@ -530,6 +562,7 @@
     assertEquals( "root", items[ 4 ].getText() );
   }
 
+  @Test
   public void testClearByIndices_NullArgument() {
     createGridItems( grid, 3, 3 );
 
@@ -539,6 +572,7 @@
     }
   }
 
+  @Test
   public void testClearByIndices_InvalidIndex() {
     createGridItems( grid, 3, 3 );
 
@@ -548,6 +582,7 @@
     }
   }
 
+  @Test
   public void testSendSetDataEventAfterClear() {
     grid = new Grid( shell, SWT.VIRTUAL );
     GridItem[] items = createGridItems( grid, 3, 3 );
@@ -566,6 +601,7 @@
     assertEquals( "bar", items[ 0 ].getText() );
   }
 
+  @Test
   public void testClearWithColumns() {
     grid = new Grid( shell, SWT.VIRTUAL );
     GridItem[] items = createGridItems( grid, 3, 3 );
@@ -581,16 +617,19 @@
     assertEquals( "", items[ 1 ].getText( 2 ) );
   }
 
+  @Test
   public void testGetSelectionEnabled_Initial() {
     assertTrue( grid.getSelectionEnabled() );
   }
 
+  @Test
   public void testGetSelectionEnabled() {
     grid.setSelectionEnabled( false );
 
     assertFalse( grid.getSelectionEnabled() );
   }
 
+  @Test
   public void testSetSelectionEnabled_ClearSelectedItems() {
     createGridItems( grid, 3, 0 );
     grid.select( 0 );
@@ -600,10 +639,12 @@
     assertEquals( 0, grid.getSelectionCount() );
   }
 
+  @Test
   public void testGetSelectionCount_Initial() {
     assertEquals( 0, grid.getSelectionCount() );
   }
 
+  @Test
   public void testGetSelectionCount() {
     createGridItems( grid, 3, 0 );
 
@@ -612,10 +653,12 @@
     assertEquals( 1, grid.getSelectionCount() );
   }
 
+  @Test
   public void testGetSelection_Initial() {
     assertTrue( Arrays.equals( new GridItem[ 0 ], grid.getSelection() ) );
   }
 
+  @Test
   public void testGetSelection() {
     createGridItems( grid, 3, 0 );
 
@@ -624,6 +667,7 @@
     assertSame( grid.getItem( 0 ), grid.getSelection()[ 0 ] );
   }
 
+  @Test
   public void testGetSelection_AfterDisposeItem() {
     grid = new Grid( shell, SWT.MULTI );
     GridItem[] items = createGridItems( grid, 5, 0 );
@@ -635,6 +679,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testSelectByIndex_Single() {
     grid = new Grid( shell, SWT.SINGLE );
     GridItem[] items = createGridItems( grid, 3, 0 );
@@ -646,6 +691,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testSelectByIndex_Multi() {
     grid = new Grid( shell, SWT.MULTI );
     GridItem[] items = createGridItems( grid, 3, 0 );
@@ -657,6 +703,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testSelectByIndex_WithSelectionDisabled() {
     grid.setSelectionEnabled( false );
     createGridItems( grid, 3, 0 );
@@ -666,6 +713,7 @@
     assertTrue( Arrays.equals( new GridItem[ 0 ], grid.getSelection() ) );
   }
 
+  @Test
   public void testSelectByIndex_WithInvalidIndex() {
     grid = new Grid( shell, SWT.MULTI );
     GridItem[] items = createGridItems( grid, 3, 0 );
@@ -677,6 +725,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testSelectByIndex_Twice() {
     grid = new Grid( shell, SWT.MULTI );
     GridItem[] items = createGridItems( grid, 3, 0 );
@@ -688,6 +737,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testSelectByRange_Single() {
     grid = new Grid( shell, SWT.SINGLE );
     GridItem[] items = createGridItems( grid, 5, 0 );
@@ -698,6 +748,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testSelectByRange_SingleWithDifferentSrartEnd() {
     grid = new Grid( shell, SWT.SINGLE );
     createGridItems( grid, 5, 0 );
@@ -707,6 +758,7 @@
     assertTrue( Arrays.equals( new GridItem[ 0 ], grid.getSelection() ) );
   }
 
+  @Test
   public void testSelectByRange_Multi() {
     grid = new Grid( shell, SWT.MULTI );
     GridItem[] items = createGridItems( grid, 5, 0 );
@@ -717,6 +769,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testSelectByRange_WithSelectionDisabled() {
     grid = new Grid( shell, SWT.MULTI );
     grid.setSelectionEnabled( false );
@@ -727,6 +780,7 @@
     assertTrue( Arrays.equals( new GridItem[ 0 ], grid.getSelection() ) );
   }
 
+  @Test
   public void testSelectByRange_StartBiggerThanEnd() {
     grid = new Grid( shell, SWT.MULTI );
     createGridItems( grid, 5, 0 );
@@ -736,6 +790,7 @@
     assertTrue( Arrays.equals( new GridItem[ 0 ], grid.getSelection() ) );
   }
 
+  @Test
   public void testSelectByIndices_Single() {
     grid = new Grid( shell, SWT.SINGLE );
     GridItem[] items = createGridItems( grid, 5, 0 );
@@ -746,6 +801,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testSelectByIndices_SingleWithMultipleIndices() {
     grid = new Grid( shell, SWT.SINGLE );
     createGridItems( grid, 5, 0 );
@@ -755,6 +811,7 @@
     assertTrue( Arrays.equals( new GridItem[ 0 ], grid.getSelection() ) );
   }
 
+  @Test
   public void testSelectByIndices_Multi() {
     grid = new Grid( shell, SWT.MULTI );
     GridItem[] items = createGridItems( grid, 5, 0 );
@@ -765,16 +822,14 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testSelectByIndices_NullArgument() {
     grid = new Grid( shell, SWT.MULTI );
 
-    try {
-      grid.select( null );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.select( null );
   }
 
+  @Test
   public void testSelectByIndices_InvalidIndex() {
     grid = new Grid( shell, SWT.MULTI );
     GridItem[] items = createGridItems( grid, 5, 0 );
@@ -785,6 +840,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testSelectByIndices_DuplicateIndex() {
     grid = new Grid( shell, SWT.MULTI );
     GridItem[] items = createGridItems( grid, 5, 0 );
@@ -795,6 +851,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testSelectAll_Single() {
     grid = new Grid( shell, SWT.SINGLE );
     createGridItems( grid, 5, 0 );
@@ -804,6 +861,7 @@
     assertTrue( Arrays.equals( new GridItem[ 0 ], grid.getSelection() ) );
   }
 
+  @Test
   public void testSelectAll_Multi() {
     grid = new Grid( shell, SWT.MULTI );
     GridItem[] items = createGridItems( grid, 3, 0 );
@@ -814,6 +872,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testSelectAll_AfterSelect() {
     grid = new Grid( shell, SWT.MULTI );
     GridItem[] items = createGridItems( grid, 3, 0 );
@@ -825,6 +884,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testSetSelectionByIndex() {
     GridItem[] items = createGridItems( grid, 3, 0 );
 
@@ -834,6 +894,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testSetSelectionByIndex_ClearPreviousSelection() {
     GridItem[] items = createGridItems( grid, 3, 0 );
     grid.select( 0 );
@@ -844,6 +905,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testSetSelectionByIndex_WithSelectionDisabled() {
     grid.setSelectionEnabled( false );
     createGridItems( grid, 3, 0 );
@@ -853,6 +915,7 @@
     assertTrue( Arrays.equals( new GridItem[ 0 ], grid.getSelection() ) );
   }
 
+  @Test
   public void testSetSelectionByIndex_WithInvalidIndex() {
     createGridItems( grid, 3, 0 );
 
@@ -861,6 +924,7 @@
     assertTrue( Arrays.equals( new GridItem[ 0 ], grid.getSelection() ) );
   }
 
+  @Test
   public void testSetSelectionByRange_Single() {
     grid = new Grid( shell, SWT.SINGLE );
     GridItem[] items = createGridItems( grid, 5, 0 );
@@ -872,6 +936,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testSetSelectionByRange_SingleWithDifferentSrartEnd() {
     grid = new Grid( shell, SWT.SINGLE );
     GridItem[] items = createGridItems( grid, 5, 0 );
@@ -883,6 +948,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testSetSelectionByRange_Multi() {
     grid = new Grid( shell, SWT.MULTI );
     GridItem[] items = createGridItems( grid, 5, 0 );
@@ -894,6 +960,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testSetSelectionByRange_WithSelectionDisabled() {
     grid = new Grid( shell, SWT.MULTI );
     grid.setSelectionEnabled( false );
@@ -904,6 +971,7 @@
     assertTrue( Arrays.equals( new Grid[ 0 ], grid.getSelection() ) );
   }
 
+  @Test
   public void testSetSelectionByRange_StartBiggerThanEnd() {
     grid = new Grid( shell, SWT.MULTI );
     createGridItems( grid, 5, 0 );
@@ -914,6 +982,7 @@
     assertTrue( Arrays.equals( new Grid[ 0 ], grid.getSelection() ) );
   }
 
+  @Test
   public void testSetSelectionByIndices_Single() {
     grid = new Grid( shell, SWT.SINGLE );
     GridItem[] items = createGridItems( grid, 5, 0 );
@@ -925,6 +994,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testSetSelectionByIndices_SingleWithMultipleIndices() {
     grid = new Grid( shell, SWT.SINGLE );
     GridItem[] items = createGridItems( grid, 5, 0 );
@@ -936,6 +1006,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testSetSelectionByIndices_Multi() {
     grid = new Grid( shell, SWT.MULTI );
     GridItem[] items = createGridItems( grid, 5, 0 );
@@ -947,14 +1018,12 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testSetSelectionByIndices_NullArgument() {
-    try {
-      grid.setSelection( ( int[] )null );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.setSelection( ( int[] )null );
   }
 
+  @Test
   public void testSetSelectionByIndices_InvalidIndex() {
     grid = new Grid( shell, SWT.MULTI );
     GridItem[] items = createGridItems( grid, 5, 0 );
@@ -965,6 +1034,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testSetSelectionByIndices_DuplicateIndex() {
     grid = new Grid( shell, SWT.MULTI );
     GridItem[] items = createGridItems( grid, 5, 0 );
@@ -975,6 +1045,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testSetSelectionByItems_Single() {
     grid = new Grid( shell, SWT.SINGLE );
     GridItem[] items = createGridItems( grid, 5, 0 );
@@ -985,6 +1056,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testSetSelectionByItems_SingleWithMultipleItems() {
     grid = new Grid( shell, SWT.SINGLE );
     GridItem[] items = createGridItems( grid, 5, 0 );
@@ -994,6 +1066,7 @@
     assertTrue( Arrays.equals( new GridItem[ 0 ], grid.getSelection() ) );
   }
 
+  @Test
   public void testSetSelectionByItems_WithSelectionDisabled() {
     grid.setSelectionEnabled( false );
     GridItem[] items = createGridItems( grid, 5, 0 );
@@ -1003,6 +1076,7 @@
     assertTrue( Arrays.equals( new GridItem[ 0 ], grid.getSelection() ) );
   }
 
+  @Test
   public void testSetSelectionByItems_Multi() {
     grid = new Grid( shell, SWT.MULTI );
     GridItem[] items = createGridItems( grid, 5, 0 );
@@ -1014,14 +1088,12 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testSetSelectionByItems_NullArgument() {
-    try {
-      grid.setSelection( ( GridItem[] )null );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.setSelection( ( GridItem[] )null );
   }
 
+  @Test
   public void testSetSelectionByItems_NullItem() {
     grid = new Grid( shell, SWT.MULTI );
     GridItem[] items = createGridItems( grid, 5, 0 );
@@ -1032,6 +1104,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testSetSelectionByItems_ItemWithDifferentParent() {
     grid = new Grid( shell, SWT.MULTI );
     GridItem[] items = createGridItems( grid, 5, 0 );
@@ -1044,18 +1117,16 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testSetSelectionByItems_DisposedItem() {
     grid = new Grid( shell, SWT.MULTI );
     GridItem[] items = createGridItems( grid, 5, 0 );
     items[ 2 ].dispose();
 
-    try {
-      grid.setSelection( new GridItem[]{ items[ 1 ], items[ 2 ], items[ 3 ] } );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.setSelection( new GridItem[]{ items[ 1 ], items[ 2 ], items[ 3 ] } );
   }
 
+  @Test
   public void testDeselectByIndex() {
     grid = new Grid( shell, SWT.MULTI );
     GridItem[] items = createGridItems( grid, 5, 0 );
@@ -1067,6 +1138,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testDeselectByIndex_InvalidIndex() {
     grid = new Grid( shell, SWT.MULTI );
     GridItem[] items = createGridItems( grid, 5, 0 );
@@ -1078,6 +1150,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testDeselectByRange() {
     grid = new Grid( shell, SWT.MULTI );
     GridItem[] items = createGridItems( grid, 5, 0 );
@@ -1089,6 +1162,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testDeselectByRange_OutOfItemsSize() {
     grid = new Grid( shell, SWT.MULTI );
     GridItem[] items = createGridItems( grid, 5, 0 );
@@ -1100,6 +1174,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testDeselectByIndices() {
     grid = new Grid( shell, SWT.MULTI );
     GridItem[] items = createGridItems( grid, 5, 0 );
@@ -1111,6 +1186,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testDeselectByIndices_NullArgument() {
     try {
       grid.deselect( null );
@@ -1118,6 +1194,7 @@
     }
   }
 
+  @Test
   public void testDeselectByIndices_DuplicateIndex() {
     grid = new Grid( shell, SWT.MULTI );
     GridItem[] items = createGridItems( grid, 5, 0 );
@@ -1129,6 +1206,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testDeselectByIndices_InvalidIndex() {
     grid = new Grid( shell, SWT.MULTI );
     GridItem[] items = createGridItems( grid, 5, 0 );
@@ -1140,6 +1218,7 @@
     assertTrue( Arrays.equals( expected, grid.getSelection() ) );
   }
 
+  @Test
   public void testDeselectAll() {
     grid = new Grid( shell, SWT.MULTI );
     createGridItems( grid, 5, 0 );
@@ -1150,6 +1229,7 @@
     assertTrue( Arrays.equals( new GridItem[ 0 ], grid.getSelection() ) );
   }
 
+  @Test
   public void testRemoveByIndex() {
     createGridItems( grid, 3, 3 );
 
@@ -1159,14 +1239,12 @@
     assertEquals( 2, grid.getRootItemCount() );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testRemoveByIndex_InvalidIndex() {
-    try {
-      grid.remove( 50 );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.remove( 50 );
   }
 
+  @Test
   public void testRemoveByIndex_RemoveFromSelection() {
     createGridItems( grid, 3, 3 );
     grid.select( 6 );
@@ -1176,6 +1254,7 @@
     assertEquals( 0, grid.getSelectionCount() );
   }
 
+  @Test
   public void testRemoveByRange() {
     createGridItems( grid, 3, 3 );
 
@@ -1185,16 +1264,14 @@
     assertEquals( 1, grid.getRootItemCount() );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testRemoveByRange_InvalidRange() {
     createGridItems( grid, 3, 3 );
 
-    try {
-      grid.remove( 3, 60 );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.remove( 3, 60 );
   }
 
+  @Test
   public void testRemoveByIndices() {
     createGridItems( grid, 3, 3 );
 
@@ -1204,14 +1281,12 @@
     assertEquals( 2, grid.getRootItemCount() );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testRemoveByIndices_NullArgument() {
-    try {
-      grid.remove( null );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.remove( null );
   }
 
+  @Test
   public void testRemoveByIndices_DuplicateIndex() {
     createGridItems( grid, 3, 3 );
 
@@ -1221,16 +1296,14 @@
     assertEquals( 3, grid.getRootItemCount() );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testRemoveByIndices_InvalidIndex() {
     createGridItems( grid, 3, 3 );
 
-    try {
-      grid.remove(new int[]{ 3, 5, 100 } );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.remove(new int[]{ 3, 5, 100 } );
   }
 
+  @Test
   public void testRemoveAll() {
     createGridItems( grid, 3, 3 );
 
@@ -1240,6 +1313,7 @@
     assertEquals( 0, grid.getRootItemCount() );
   }
 
+  @Test
   public void testGetSelectionIndex() {
     grid = new Grid( shell, SWT.MULTI );
     createGridItems( grid, 3, 3 );
@@ -1250,10 +1324,12 @@
     assertEquals( 3, grid.getSelectionIndex() );
   }
 
+  @Test
   public void testGetSelectionIndex_WithoutSelection() {
     assertEquals( -1, grid.getSelectionIndex() );
   }
 
+  @Test
   public void testGetSelectionIndicies() {
     grid = new Grid( shell, SWT.MULTI );
     createGridItems( grid, 3, 3 );
@@ -1264,10 +1340,12 @@
     assertTrue( Arrays.equals( indicies, grid.getSelectionIndices() ) );
   }
 
+  @Test
   public void testGetSelectionIndicies_WithoutSelection() {
     assertTrue( Arrays.equals( new int[ 0 ], grid.getSelectionIndices() ) );
   }
 
+  @Test
   public void testIsSelectedByIndex_Initial() {
     createGridItems( grid, 3, 0 );
 
@@ -1276,6 +1354,7 @@
     assertFalse( grid.isSelected( 2 ) );
   }
 
+  @Test
   public void testIsSelectedByIndex() {
     createGridItems( grid, 3, 0 );
 
@@ -1286,12 +1365,14 @@
     assertFalse( grid.isSelected( 2 ) );
   }
 
+  @Test
   public void testIsSelectedByIndex_InvalidIndex() {
     createGridItems( grid, 3, 0 );
 
     assertFalse( grid.isSelected( 5 ) );
   }
 
+  @Test
   public void testIsSelectedByItem_Initial() {
     GridItem[] items = createGridItems( grid, 3, 0 );
 
@@ -1300,6 +1381,7 @@
     assertFalse( grid.isSelected( items[ 2 ] ) );
   }
 
+  @Test
   public void testIsSelectedByItem() {
     GridItem[] items = createGridItems( grid, 3, 0 );
 
@@ -1310,14 +1392,12 @@
     assertFalse( grid.isSelected( items[ 2 ] ) );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testIsSelectedByItem_NullArgument() {
-    try {
-      grid.isSelected( null );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.isSelected( null );
   }
 
+  @Test
   public void testIsSelectedByItem_DisposedItem() {
     GridItem[] items = createGridItems( grid, 3, 0 );
     grid.select( 1 );
@@ -1327,40 +1407,48 @@
     assertFalse( grid.isSelected( items[ 1 ] ) );
   }
 
+  @Test
   public void testGetHeaderVisible_Initial() {
     assertFalse( grid.getHeaderVisible() );
   }
 
+  @Test
   public void testSetHeaderVisible() {
     grid.setHeaderVisible( true );
 
     assertTrue( grid.getHeaderVisible() );
   }
 
+  @Test
   public void testGetFooterVisible_Initial() {
     assertFalse( grid.getFooterVisible() );
   }
 
+  @Test
   public void testSetFooterVisible() {
     grid.setFooterVisible( true );
 
     assertTrue( grid.getFooterVisible() );
   }
 
+  @Test
   public void testGetLinesVisible_Initial() {
     assertTrue( grid.getLinesVisible() );
   }
 
+  @Test
   public void testGetLinesVisible() {
     grid.setLinesVisible( false );
 
     assertFalse( grid.getLinesVisible() );
   }
 
+  @Test
   public void testGetFocusItem_Initial() {
     assertNull( grid.getFocusItem() );
   }
 
+  @Test
   public void testSetFocusItem() {
     GridItem[] items = createGridItems( grid, 3, 3 );
 
@@ -1369,52 +1457,42 @@
     assertSame( items[ 4 ], grid.getFocusItem() );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testSetFocusItem_NullArgument() {
-    try {
-      grid.setFocusItem( null );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.setFocusItem( null );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testSetFocusItem_DisposedItem() {
     GridItem item = new GridItem( grid, SWT.NONE );
     item.dispose();
 
-    try {
-      grid.setFocusItem( item );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.setFocusItem( item );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testSetFocusItem_WithOtherParent() {
     Grid otherGrid = new Grid( shell, SWT.NONE );
     GridItem item = new GridItem( otherGrid, SWT.NONE );
 
-    try {
-      grid.setFocusItem( item );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.setFocusItem( item );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testSetFocusItem_InvisibleItem() {
     GridItem[] items = createGridItems( grid, 3, 3 );
 
-    try {
-      grid.setFocusItem( items[ 2 ] );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.setFocusItem( items[ 2 ] );
   }
 
+  @Test
   public void testGetColumnOrder_Initial() {
     createGridColumns( grid, 5, SWT.NONE );
 
     assertTrue( Arrays.equals( new int[]{ 0, 1, 2, 3, 4 }, grid.getColumnOrder() ) );
   }
 
+  @Test
   public void testSetColumnOrder() {
     createGridColumns( grid, 5, SWT.NONE );
     int[] order = new int[]{ 4, 1, 3, 2, 0 };
@@ -1424,60 +1502,46 @@
     assertTrue( Arrays.equals( order, grid.getColumnOrder() ) );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testSetColumnOrder_NullArgument() {
-    try {
-      grid.setColumnOrder( null );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.setColumnOrder( null );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testSetColumnOrder_DifferentArraySize() {
     createGridColumns( grid, 5, SWT.NONE );
     int[] order = new int[]{ 4, 1, 3, 2, 0, 6 };
 
-    try {
-      grid.setColumnOrder( order );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.setColumnOrder( order );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testSetColumnOrder_InvalidColumnIndex() {
     createGridColumns( grid, 5, SWT.NONE );
     int[] order = new int[]{ 4, 1, 33, 2, 0 };
 
-    try {
-      grid.setColumnOrder( order );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.setColumnOrder( order );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testSetColumnOrder_DuplicateColumnIndex() {
     createGridColumns( grid, 5, SWT.NONE );
     int[] order = new int[]{ 3, 1, 3, 2, 0 };
 
-    try {
-      grid.setColumnOrder( order );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.setColumnOrder( order );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testSetColumnOrder_MoveToColumnGroup() {
     createGridColumns( grid, 2, SWT.NONE );
     GridColumnGroup group = new GridColumnGroup( grid, SWT.NONE );
     createGridColumns( group, 2, SWT.NONE );
     createGridColumns( grid, 2, SWT.NONE );
 
-    try {
-      grid.setColumnOrder( new int[]{ 1, 2, 0, 3, 4, 5 } );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.setColumnOrder( new int[]{ 1, 2, 0, 3, 4, 5 } );
   }
 
+  @Test
   public void testSetColumnOrder_MoveInSameColumnGroup() {
     createGridColumns( grid, 2, SWT.NONE );
     GridColumnGroup group = new GridColumnGroup( grid, SWT.NONE );
@@ -1490,6 +1554,7 @@
     assertTrue( Arrays.equals( order, grid.getColumnOrder() ) );
   }
 
+  @Test
   public void testGetColumnOrder_AfterColumnAdd() {
     createGridColumns( grid, 5, SWT.NONE );
     grid.setColumnOrder( new int[]{ 4, 1, 3, 2, 0 } );
@@ -1500,6 +1565,7 @@
     assertTrue( Arrays.equals( expected, grid.getColumnOrder() ) );
   }
 
+  @Test
   public void testGetColumnOrder_AfterColumnRemove() {
     GridColumn[] columns = createGridColumns( grid, 5, SWT.NONE );
     grid.setColumnOrder( new int[]{ 4, 1, 3, 2, 0 } );
@@ -1510,6 +1576,7 @@
     assertTrue( Arrays.equals( expected, grid.getColumnOrder() ) );
   }
 
+  @Test
   public void testGetColumnOrder_UpdatePrimaryCheckColumn() {
     grid = new Grid( shell, SWT.CHECK );
     GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
@@ -1519,12 +1586,14 @@
     assertTrue( columns[ 2 ].isCheck() );
   }
 
+  @Test
   public void testGetNextVisibleItem_CollapsedItem() {
     GridItem[] items = createGridItems( grid, 3, 3 );
 
     assertSame( items[ 8 ], grid.getNextVisibleItem( items[ 4 ] ) );
   }
 
+  @Test
   public void testGetNextVisibleItem_ExpandedItem() {
     GridItem[] items = createGridItems( grid, 3, 3 );
     items[ 4 ].setExpanded( true );
@@ -1532,30 +1601,35 @@
     assertSame( items[ 5 ], grid.getNextVisibleItem( items[ 4 ] ) );
   }
 
+  @Test
   public void testGetNextVisibleItem_NullArgument() {
     GridItem[] items = createGridItems( grid, 3, 3 );
 
     assertSame( items[ 0 ], grid.getNextVisibleItem( null ) );
   }
 
+  @Test
   public void testGetNextVisibleItem_LastItem() {
     GridItem[] items = createGridItems( grid, 3, 3 );
 
     assertNull( grid.getNextVisibleItem( items[ 11 ] ) );
   }
 
+  @Test
   public void testGetNextVisibleItem_AllNextNotVisible() {
     GridItem[] items = createGridItems( grid, 3, 3 );
 
     assertNull( grid.getNextVisibleItem( items[ 8 ] ) );
   }
 
+  @Test
   public void testGetPreviousVisibleItem_CollapsedItem() {
     GridItem[] items = createGridItems( grid, 3, 3 );
 
     assertSame( items[ 0 ], grid.getPreviousVisibleItem( items[ 4 ] ) );
   }
 
+  @Test
   public void testGetPreviousVisibleItem_ExpandedItem() {
     GridItem[] items = createGridItems( grid, 3, 3 );
     items[ 0 ].setExpanded( true );
@@ -1563,18 +1637,21 @@
     assertSame( items[ 3 ], grid.getPreviousVisibleItem( items[ 4 ] ) );
   }
 
+  @Test
   public void testGetPreviousVisibleItem_NullArgument() {
     GridItem[] items = createGridItems( grid, 3, 3 );
 
     assertSame( items[ 8 ], grid.getPreviousVisibleItem( null ) );
   }
 
+  @Test
   public void testGetPreviousVisibleItem_FirstItem() {
     GridItem[] items = createGridItems( grid, 3, 3 );
 
     assertNull( grid.getPreviousVisibleItem( items[ 0 ] ) );
   }
 
+  @Test
   public void testGetNextVisibleColumn_NextNotVisible() {
     GridColumn[] columns = createGridColumns( grid, 5, SWT.NONE );
     columns[ 3 ].setVisible( false );
@@ -1582,24 +1659,28 @@
     assertSame( columns[ 4 ], grid.getNextVisibleColumn( columns[ 2 ] ) );
   }
 
+  @Test
   public void testGetNextVisibleColumn_NextVisible() {
     GridColumn[] columns = createGridColumns( grid, 5, SWT.NONE );
 
     assertSame( columns[ 3 ], grid.getNextVisibleColumn( columns[ 2 ] ) );
   }
 
+  @Test
   public void testGetNextVisibleColumn_NullArgument() {
     GridColumn[] columns = createGridColumns( grid, 5, SWT.NONE );
 
     assertSame( columns[ 0 ], grid.getNextVisibleColumn( null ) );
   }
 
+  @Test
   public void testGetNextVisibleColumn_LastColumn() {
     GridColumn[] columns = createGridColumns( grid, 5, SWT.NONE );
 
     assertNull( grid.getNextVisibleColumn( columns[ 4 ] ) );
   }
 
+  @Test
   public void testGetNextVisibleColumn_AllNextNotVisible() {
     GridColumn[] columns = createGridColumns( grid, 5, SWT.NONE );
     columns[ 3 ].setVisible( false );
@@ -1608,6 +1689,7 @@
     assertNull( grid.getNextVisibleColumn( columns[ 2 ] ) );
   }
 
+  @Test
   public void testGetNextVisibleColumn_WithColumnOrder() {
     GridColumn[] columns = createGridColumns( grid, 5, SWT.NONE );
     grid.setColumnOrder( new int[]{ 4, 0, 2, 1, 3 } );
@@ -1615,6 +1697,7 @@
     assertSame( columns[ 1 ], grid.getNextVisibleColumn( columns[ 2 ] ) );
   }
 
+  @Test
   public void testGetPreviousVisibleColumn_PreviousNotVisible() {
     GridColumn[] columns = createGridColumns( grid, 5, SWT.NONE );
     columns[ 1 ].setVisible( false );
@@ -1622,24 +1705,28 @@
     assertSame( columns[ 0 ], grid.getPreviousVisibleColumn( columns[ 2 ] ) );
   }
 
+  @Test
   public void testGetPreviousVisibleColumn_PreviousVisible() {
     GridColumn[] columns = createGridColumns( grid, 5, SWT.NONE );
 
     assertSame( columns[ 1 ], grid.getPreviousVisibleColumn( columns[ 2 ] ) );
   }
 
+  @Test
   public void testGetPreviousVisibleColumn_NullArgument() {
     GridColumn[] columns = createGridColumns( grid, 5, SWT.NONE );
 
     assertSame( columns[ 4 ], grid.getPreviousVisibleColumn( null ) );
   }
 
+  @Test
   public void testGetPreviousVisibleColumn_FirstColumn() {
     GridColumn[] columns = createGridColumns( grid, 5, SWT.NONE );
 
     assertNull( grid.getPreviousVisibleColumn( columns[ 0 ] ) );
   }
 
+  @Test
   public void testGetPreviousVisibleColumn_WithColumnOrder() {
     GridColumn[] columns = createGridColumns( grid, 5, SWT.NONE );
     grid.setColumnOrder( new int[]{ 4, 0, 2, 1, 3 } );
@@ -1647,16 +1734,19 @@
     assertSame( columns[ 0 ], grid.getPreviousVisibleColumn( columns[ 2 ] ) );
   }
 
+  @Test
   public void testGetItemHeight_Initial() {
     assertEquals( 27, grid.getItemHeight() );
   }
 
+  @Test
   public void testGetItemHeight() {
     grid.setItemHeight( 30 );
 
     assertEquals( 30, grid.getItemHeight() );
   }
 
+  @Test
   public void testGetItemHeight_AfterFontChange() {
     // fill the cache
     grid.getItemHeight();
@@ -1667,6 +1757,7 @@
     assertEquals( 33, grid.getItemHeight() );
   }
 
+  @Test
   public void testGetItemHeight_MinHeight() {
     Font font = new Font( display, "Arial", 8, SWT.NORMAL );
     fakeCellPadding( grid, new Rectangle( 0, 0, 0, 0 ) );
@@ -1675,12 +1766,14 @@
     assertEquals( 16, grid.getItemHeight() );
   }
 
+  @Test
   public void testGetItemHeight_WithGridCheck() {
     grid = new Grid( shell, SWT.CHECK );
 
     assertEquals( 30, grid.getItemHeight() );
   }
 
+  @Test
   public void testGetItemHeight_WithItemImage() {
     createGridColumns( grid, 3, SWT.NONE );
     GridItem item = new GridItem( grid, SWT.NONE );
@@ -1693,6 +1786,7 @@
     assertEquals( 63, grid.getItemHeight() );
   }
 
+  @Test
   public void testGetItemHeight_AfterClearAll() {
     createGridColumns( grid, 3, SWT.NONE );
     GridItem item = new GridItem( grid, SWT.NONE );
@@ -1704,12 +1798,14 @@
     assertEquals( 27, grid.getItemHeight() );
   }
 
+  @Test
   public void testGetHeaderHeight_Initial() {
     createGridColumns( grid, 3, SWT.NONE );
 
     assertEquals( 0, grid.getHeaderHeight() );
   }
 
+  @Test
   public void testGetHeaderHeight() {
     grid.setHeaderVisible( true );
     GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
@@ -1720,6 +1816,7 @@
     assertEquals( 67, grid.getHeaderHeight() );
   }
 
+  @Test
   public void testGetHeaderHeight_WithColumnGroup() {
     grid.setHeaderVisible( true );
     Image image = loadImage( display, Fixture.IMAGE_100x50 );
@@ -1735,6 +1832,7 @@
     assertEquals( 67, grid.getGroupHeaderHeight() );
   }
 
+  @Test
   public void testGetHeaderHeight_DifferentColumnHeaderFonts() {
     grid.setHeaderVisible( true );
     GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
@@ -1744,6 +1842,7 @@
     assertEquals( 37, grid.getHeaderHeight() );
   }
 
+  @Test
   public void testGetHeaderHeight_AfterColumnDispose() {
     grid.setHeaderVisible( true );
     GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
@@ -1758,6 +1857,7 @@
     assertEquals( 31, grid.getHeaderHeight() );
   }
 
+  @Test
   public void testGetHeaderHeight_AfterTextChange() {
     grid.setHeaderVisible( true );
     GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
@@ -1770,6 +1870,7 @@
     assertEquals( 52, grid.getHeaderHeight() );
   }
 
+  @Test
   public void testGetHeaderHeight_AfterImageChange() {
     grid.setHeaderVisible( true );
     GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
@@ -1784,6 +1885,7 @@
     assertEquals( 31, grid.getHeaderHeight() );
   }
 
+  @Test
   public void testGetHeaderHeight_AfterFontChange() {
     grid.setHeaderVisible( true );
     GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
@@ -1796,12 +1898,14 @@
     assertEquals( 37, grid.getHeaderHeight() );
   }
 
+  @Test
   public void testGetFooterHeight_Initial() {
     createGridColumns( grid, 3, SWT.NONE );
 
     assertEquals( 0, grid.getFooterHeight() );
   }
 
+  @Test
   public void testGetFooterHeight() {
     grid.setFooterVisible( true );
     GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
@@ -1812,6 +1916,7 @@
     assertEquals( 67, grid.getFooterHeight() );
   }
 
+  @Test
   public void testGetFooterHeight_DifferentColumnFooterFonts() {
     grid.setFooterVisible( true );
     GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
@@ -1821,6 +1926,7 @@
     assertEquals( 37, grid.getFooterHeight() );
   }
 
+  @Test
   public void testGetFooterHeight_AfterColumnDispose() {
     grid.setFooterVisible( true );
     GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
@@ -1835,6 +1941,7 @@
     assertEquals( 31, grid.getFooterHeight() );
   }
 
+  @Test
   public void testGetFooterHeight_AfterTextChange() {
     grid.setFooterVisible( true );
     GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
@@ -1847,6 +1954,7 @@
     assertEquals( 52, grid.getFooterHeight() );
   }
 
+  @Test
   public void testGetFooterHeight_AfterImageChange() {
     grid.setFooterVisible( true );
     GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
@@ -1861,6 +1969,7 @@
     assertEquals( 31, grid.getFooterHeight() );
   }
 
+  @Test
   public void testGetFooterHeight_AfterFontChange() {
     grid.setFooterVisible( true );
     GridColumn[] columns = createGridColumns( grid, 3, SWT.NONE );
@@ -1873,6 +1982,7 @@
     assertEquals( 37, grid.getFooterHeight() );
   }
 
+  @Test
   public void testGetGroupHeaderHeight_Initial() {
     createGridColumns( grid, 1, SWT.NONE );
     GridColumnGroup group = new GridColumnGroup( grid, SWT.NONE );
@@ -1881,6 +1991,7 @@
     assertEquals( 0, grid.getGroupHeaderHeight() );
   }
 
+  @Test
   public void testGetGroupHeaderHeight() {
     grid.setHeaderVisible( true );
     createGridColumns( grid, 1, SWT.NONE );
@@ -1893,6 +2004,7 @@
     assertEquals( 67, grid.getGroupHeaderHeight() );
   }
 
+  @Test
   public void testComputeSize() {
     grid = new Grid( shell, SWT.NONE );
     createGridColumns( grid, 3, SWT.NONE );
@@ -1905,6 +2017,7 @@
     assertEquals( 3 * itemHeight, preferredSize.y );
   }
 
+  @Test
   public void testComputeSize_WithScrollBars() {
     createGridColumns( grid, 3, SWT.NONE );
     createGridItems( grid, 3, 3 );
@@ -1917,6 +2030,7 @@
     assertEquals( 3 * itemHeight + scrollbarSize, preferredSize.y );
   }
 
+  @Test
   public void testComputeSize_WithBorder() {
     grid = new Grid( shell, SWT.BORDER );
     createGridColumns( grid, 3, SWT.NONE );
@@ -1930,6 +2044,7 @@
     assertEquals( 3 * itemHeight + 2 * borderWidth, preferredSize.y );
   }
 
+  @Test
   public void testComputeSize_WithExpandedItems() {
     grid = new Grid( shell, SWT.NONE );
     createGridColumns( grid, 3, SWT.NONE );
@@ -1944,6 +2059,7 @@
     assertEquals( 9 * itemHeight, preferredSize.y );
   }
 
+  @Test
   public void testUpdateScrollBars_Initial() {
     doFakeRedraw();
 
@@ -1955,6 +2071,7 @@
     assertEquals( 1, horizontalBar.getMaximum() );
   }
 
+  @Test
   public void testUpdateScrollBars() {
     createGridColumns( grid, 5, SWT.NONE );
     createGridItems( grid, 20, 3 );
@@ -1969,6 +2086,7 @@
     assertEquals( 300, horizontalBar.getMaximum() );
   }
 
+  @Test
   public void testUpdateScrollBars_OnColumnChange() {
     createGridColumns( grid, 4, SWT.NONE );
 
@@ -1981,6 +2099,7 @@
     assertFalse( horizontalBar.getVisible() );
   }
 
+  @Test
   public void testUpdateScrollBars_OnColumnWidthChange() {
     createGridColumns( grid, 4, SWT.NONE );
 
@@ -1993,6 +2112,7 @@
     assertFalse( horizontalBar.getVisible() );
   }
 
+  @Test
   public void testUpdateScrollBars_OnItemExpandChange() {
     createGridItems( grid, 3, 10 );
 
@@ -2005,6 +2125,7 @@
     assertFalse( verticalBar.getVisible() );
   }
 
+  @Test
   public void testUpdateScrollBars_OnResize() {
     createGridColumns( grid, 5, SWT.NONE );
     createGridItems( grid, 10, 3 );
@@ -2016,6 +2137,7 @@
     assertFalse( horizontalBar.getVisible() );
   }
 
+  @Test
   public void testUpdateScrollBars_OnHeaderVisible() {
     createGridColumns( grid, 1, SWT.NONE );
     createGridItems( grid, 7, 3 );
@@ -2026,6 +2148,7 @@
     assertTrue( verticalBar.getVisible() );
   }
 
+  @Test
   public void testUpdateScrollBars_OnFooterVisible() {
     createGridColumns( grid, 1, SWT.NONE );
     createGridItems( grid, 7, 3 );
@@ -2036,6 +2159,7 @@
     assertTrue( verticalBar.getVisible() );
   }
 
+  @Test
   public void testUpdateScrollBars_OnCollapseColumnGroup() {
     grid.setSize( 90, 100 );
     GridColumnGroup group = new GridColumnGroup( grid, SWT.NONE );
@@ -2049,12 +2173,14 @@
     assertFalse( horizontalBar.getVisible() );
   }
 
+  @Test
   public void testGetTopIndex_Initial() {
     createGridItems( grid, 20, 3 );
 
     assertEquals( 0, grid.getTopIndex() );
   }
 
+  @Test
   public void testSetTopIndex() {
     createGridItems( grid, 20, 3 );
 
@@ -2063,6 +2189,7 @@
     assertEquals( 4, grid.getTopIndex() );
   }
 
+  @Test
   public void testSetTopIndex_InvisibleSubItem() {
     createGridItems( grid, 20, 3 );
 
@@ -2071,6 +2198,7 @@
     assertEquals( 0, grid.getTopIndex() );
   }
 
+  @Test
   public void testSetTopIndex_VisibleSubItem() {
     createGridItems( grid, 20, 3 );
     grid.getItem( 4 ).setExpanded( true );
@@ -2080,6 +2208,7 @@
     assertEquals( 6, grid.getTopIndex() );
   }
 
+  @Test
   public void testSetTopIndex_AdjustTopIndex() {
     createGridItems( grid, 20, 0 );
 
@@ -2088,6 +2217,7 @@
     assertEquals( 13, grid.getTopIndex() );
   }
 
+  @Test
   public void testGetTopIndex_OnItemAdd() {
     createGridItems( grid, 20, 3 );
     grid.setTopIndex( 12 );
@@ -2097,6 +2227,7 @@
     assertEquals( 9, grid.getTopIndex() );
   }
 
+  @Test
   public void testGetTopIndex_DifferentItemHeight() {
     GridItem[] items = createGridItems( grid, 20, 0 );
     items[ 16 ].setHeight( grid.getItemHeight() * 2  );
@@ -2106,6 +2237,7 @@
     assertEquals( 14, grid.getTopIndex() );
   }
 
+  @Test
   public void testAdjustTopIndexOnResize() {
     createGridItems( grid, 15, 3 );
     grid.setTopIndex( 4 );
@@ -2115,25 +2247,20 @@
     assertEquals( 0, grid.getTopIndex() );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testShowItem_NullArgument() {
-    try {
-      grid.showItem( null );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.showItem( null );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testShowItem_DisposedItem() {
     GridItem item = new GridItem( grid, SWT.NONE );
     item.dispose();
 
-    try {
-      grid.showItem( item );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.showItem( item );
   }
 
+  @Test
   public void testShowItem_ScrollDown() {
     GridItem[] items = createGridItems( grid, 20, 3 );
 
@@ -2142,6 +2269,7 @@
     assertEquals( 40, grid.getTopIndex() );
   }
 
+  @Test
   public void testShowItem_ScrollUp() {
     GridItem[] items = createGridItems( grid, 20, 3 );
     grid.setTopIndex( 12 );
@@ -2151,6 +2279,7 @@
     assertEquals( 4, grid.getTopIndex() );
   }
 
+  @Test
   public void testShowItem_NoScroll() {
     GridItem[] items = createGridItems( grid, 20, 3 );
     grid.setTopIndex( 12 );
@@ -2160,6 +2289,7 @@
     assertEquals( 12, grid.getTopIndex() );
   }
 
+  @Test
   public void testShowItem_SubItemScrollDown() {
     GridItem[] items = createGridItems( grid, 20, 3 );
 
@@ -2169,6 +2299,7 @@
     assertTrue( items[ 40 ].isExpanded() );
   }
 
+  @Test
   public void testShowItem_SubItemScrollUp() {
     GridItem[] items = createGridItems( grid, 20, 3 );
     grid.setTopIndex( 12 );
@@ -2179,6 +2310,7 @@
     assertTrue( items[ 4 ].isExpanded() );
   }
 
+  @Test
   public void testShowItem_FireExpandEvent() {
     grid.addListener( SWT.Expand, new LoggingListener() );
     GridItem[] items = createGridItems( grid, 20, 3 );
@@ -2189,25 +2321,20 @@
     assertSame( items[ 40 ], eventLog.get( 0 ).item );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testShowColumn_NullArgument() {
-    try {
-      grid.showColumn( null );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.showColumn( null );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testShowColumn_DisposedColumn() {
     GridColumn column = new GridColumn( grid, SWT.NONE );
     column.dispose();
 
-    try {
-      grid.showColumn( column );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.showColumn( column );
   }
 
+  @Test
   public void testShowColumn_ScrollRight() {
     GridColumn[] columns = createGridColumns( grid, 10, SWT.NONE );
 
@@ -2216,6 +2343,7 @@
     assertEquals( 100, horizontalBar.getSelection() );
   }
 
+  @Test
   public void testShowColumn_ScrollLeft() {
     GridColumn[] columns = createGridColumns( grid, 10, SWT.NONE );
     horizontalBar.setSelection( 150 );
@@ -2225,6 +2353,7 @@
     assertEquals( 60, horizontalBar.getSelection() );
   }
 
+  @Test
   public void testShowColumn_NoScroll() {
     GridColumn[] columns = createGridColumns( grid, 10, SWT.NONE );
     horizontalBar.setSelection( 30 );
@@ -2234,6 +2363,7 @@
     assertEquals( 30, horizontalBar.getSelection() );
   }
 
+  @Test
   public void testShowColumn_FireExpandEvent() {
     GridColumnGroup group = new GridColumnGroup( grid, SWT.NONE );
     group.addListener( SWT.Collapse, new LoggingListener() );
@@ -2247,6 +2377,7 @@
     assertSame( group, eventLog.get( 0 ).widget );
   }
 
+  @Test
   public void testShowSelection() {
     grid = new Grid( shell, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL );
     grid.setSize( 200, 200 );
@@ -2259,6 +2390,7 @@
     assertEquals( 4, grid.getTopIndex() );
   }
 
+  @Test
   public void testGetOrigin() {
     GridColumn[] columns = createGridColumns( grid, 10, SWT.NONE );
     GridItem[] items = createGridItems( grid, 20, 3 );
@@ -2269,6 +2401,7 @@
     assertEquals( expected, grid.getOrigin( columns[ 3 ], items[ 48 ] ) );
   }
 
+  @Test
   public void testGetOrigin_SubItems() {
     GridColumn[] columns = createGridColumns( grid, 10, SWT.NONE );
     GridItem[] items = createGridItems( grid, 20, 3 );
@@ -2280,6 +2413,7 @@
     assertEquals( expected, grid.getOrigin( columns[ 3 ], items[ 48 ] ) );
   }
 
+  @Test
   public void testGetOrigin_HeaderVisible() {
     GridColumn[] columns = createGridColumns( grid, 10, SWT.NONE );
     GridItem[] items = createGridItems( grid, 20, 3 );
@@ -2291,6 +2425,7 @@
     assertEquals( expected, grid.getOrigin( columns[ 3 ], items[ 48 ] ) );
   }
 
+  @Test
   public void testIsShown() {
     GridItem[] items = createGridItems( grid, 20, 0 );
     grid.setTopIndex( 5 );
@@ -2298,6 +2433,7 @@
     assertTrue( grid.isShown( items[ 6 ] ) );
   }
 
+  @Test
   public void testIsShown_HiddenItem() {
     GridItem[] items = createGridItems( grid, 20, 0 );
     grid.setTopIndex( 5 );
@@ -2305,6 +2441,7 @@
     assertFalse( grid.isShown( items[ 4 ] ) );
   }
 
+  @Test
   public void testIsShown_InvisibleItem() {
     GridItem[] items = createGridItems( grid, 20, 3 );
     grid.setTopIndex( 20 );
@@ -2312,6 +2449,7 @@
     assertFalse( grid.isShown( items[ 22 ] ) );
   }
 
+  @Test
   public void testIsShown_PartlyVisibleItem() {
     GridItem[] items = createGridItems( grid, 20, 0 );
     grid.setTopIndex( 7 );
@@ -2320,14 +2458,17 @@
     assertFalse( grid.isShown( items[ 14 ] ) );
   }
 
+  @Test
   public void testGetAdapter_IGridAdapter() {
     assertNotNull( grid.getAdapter( IGridAdapter.class ) );
   }
 
+  @Test
   public void testGetAdapter_IItemHolderAdapter() {
     assertNotNull( grid.getAdapter( IItemHolderAdapter.class ) );
   }
 
+  @Test
   public void testIItemHolderAdapter_GetItems() {
     GridColumnGroup group = new GridColumnGroup( grid, SWT.NONE );
     GridColumn column = new GridColumn( group, SWT.NONE );
@@ -2340,14 +2481,17 @@
     assertSame( item, items[ 2 ] );
   }
 
+  @Test
   public void testGetAdapter_ICellToolTipAdapter() {
     assertNotNull( grid.getAdapter( ICellToolTipAdapter.class ) );
   }
 
+  @Test
   public void testICellToolTipAdapter_hasCellToolTipProvider() {
     assertNotNull( grid.getAdapter( ICellToolTipAdapter.class ).getCellToolTipProvider() );
   }
 
+  @Test
   public void testICellToolTipAdapter_GetCellToolTipText() {
     createGridColumns( grid, 3, SWT.NONE );
     GridItem[] items = createGridItems( grid, 3, 0 );
@@ -2359,16 +2503,19 @@
     assertEquals( "foo", cellToolTipAdapter.getCellToolTipText() );
   }
 
+  @Test
   public void testColumnGroup_Initial() {
     assertEquals( 0, grid.getColumnGroupCount() );
   }
 
+  @Test
   public void testGetColumnGroupCount_AddGroup() {
     new GridColumnGroup( grid, SWT.NONE );
 
     assertEquals( 1, grid.getColumnGroupCount() );
   }
 
+  @Test
   public void testGetColumnGroupCount_RemoveGroup() {
     GridColumnGroup group = new GridColumnGroup( grid, SWT.NONE );
 
@@ -2377,6 +2524,7 @@
     assertEquals( 0, grid.getColumnGroupCount() );
   }
 
+  @Test
   public void testGetColumnGroups() {
     GridColumnGroup group1 = new GridColumnGroup( grid, SWT.NONE );
     GridColumnGroup group2 = new GridColumnGroup( grid, SWT.NONE );
@@ -2385,6 +2533,7 @@
     assertTrue( Arrays.equals( expected, grid.getColumnGroups() ) );
   }
 
+  @Test
   public void testGetColumnGroup() {
     GridColumnGroup group1 = new GridColumnGroup( grid, SWT.NONE );
     GridColumnGroup group2 = new GridColumnGroup( grid, SWT.NONE );
@@ -2393,14 +2542,12 @@
     assertSame( group2, grid.getColumnGroup( 1 ) );
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testGetColumnGroup_InvalidIndex() {
-    try{
-      grid.getColumnGroup( 3 );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    grid.getColumnGroup( 3 );
   }
 
+  @Test
   public void testDisposeColumnGroupOnGridDispose() {
     GridColumnGroup group = new GridColumnGroup( grid, SWT.NONE );
 
@@ -2409,6 +2556,7 @@
     assertTrue( group.isDisposed() );
   }
 
+  @Test
   public void testCheckBoxLeftOffset() {
     GridColumn[] columns = createGridColumns( grid, 2, SWT.CHECK );
     columns[ 0 ].setWidth( 100 );
@@ -2419,6 +2567,7 @@
     assertEquals( 6, getCheckBoxOffset( 1 ) );
   }
 
+  @Test
   public void testCheckBoxLeftOffset_CenteredWithoutContent() {
     GridColumn[] columns = createGridColumns( grid, 2, SWT.CHECK | SWT.CENTER );
     columns[ 0 ].setWidth( 100 );
@@ -2429,6 +2578,7 @@
     assertEquals( 39, getCheckBoxOffset( 1 ) );
   }
 
+  @Test
   public void testCheckBoxLeftOffset_CenteredWithContent() {
     GridColumn[] columns = createGridColumns( grid, 2, SWT.CHECK | SWT.CENTER );
     columns[ 0 ].setWidth( 100 );
@@ -2440,6 +2590,7 @@
     assertEquals( 6, getCheckBoxOffset( 1 ) );
   }
 
+  @Test
   public void testGetBottomIndex_SameItemHeight() {
     createGridItems( grid, 20, 0 );
 
@@ -2448,6 +2599,7 @@
     assertEquals( 11, grid.getBottomIndex() );
   }
 
+  @Test
   public void testGetBottomIndex_DifferentItemHeight() {
     GridItem[] items = createGridItems( grid, 20, 0 );
     items[ 6 ].setHeight( grid.getItemHeight() * 2  );
@@ -2457,6 +2609,7 @@
     assertEquals( 10, grid.getBottomIndex() );
   }
 
+  @Test
   public void testMarkupTextWithoutMarkupEnabled() {
     grid.setData( RWT.MARKUP_ENABLED, Boolean.FALSE );
     GridItem item = new GridItem( grid, SWT.NONE );
@@ -2468,17 +2621,15 @@
     }
   }
 
+  @Test( expected = IllegalArgumentException.class )
   public void testMarkupTextWithMarkupEnabled() {
     grid.setData( RWT.MARKUP_ENABLED, Boolean.TRUE );
     GridItem item = new GridItem( grid, SWT.NONE );
 
-    try {
-      item.setText( "invalid xhtml: <<&>>" );
-      fail();
-    } catch( IllegalArgumentException expected ) {
-    }
+    item.setText( "invalid xhtml: <<&>>" );
   }
 
+  @Test
   public void testMarkupTextWithMarkupEnabled_ValidationDisabled() {
     grid.setData( RWT.MARKUP_ENABLED, Boolean.TRUE );
     grid.setData( MarkupValidator.MARKUP_VALIDATION_DISABLED, Boolean.TRUE );
@@ -2491,6 +2642,7 @@
     }
   }
 
+  @Test
   public void testDisableMarkupIsIgnored() {
     grid.setData( RWT.MARKUP_ENABLED, Boolean.TRUE );
 
@@ -2499,9 +2651,184 @@
     assertEquals( Boolean.TRUE, grid.getData( RWT.MARKUP_ENABLED ) );
   }
 
+  @Test
+  public void testResolvedItems() {
+    grid.setSize( 200, 100 );
+    grid.setItemCount( 100 );
+
+    doFakeRedraw();
+
+    assertEquals( 100, countResolvedGridItems() );
+  }
+
+  @Test
+  public void testResolvedItems_onVirtual() {
+    grid = new Grid( shell, SWT.V_SCROLL | SWT.VIRTUAL );
+    grid.setSize( 200, 100 );
+    grid.setItemCount( 100 );
+
+    doFakeRedraw();
+
+    assertEquals( 4, countResolvedGridItems() );
+  }
+
+  @Test
+  public void testResolvedItems_onVirtual_afterTopIndexChange() {
+    grid = new Grid( shell, SWT.V_SCROLL | SWT.VIRTUAL );
+    grid.setSize( 200, 100 );
+    grid.setItemCount( 100 );
+    doFakeRedraw();
+
+    grid.setTopIndex( 50 );
+    doFakeRedraw();
+
+    assertEquals( 8, countResolvedGridItems() );
+  }
+
+  @Test
+  public void testResolvedItems_onVirtual_afterItemDisposal() {
+    grid = new Grid( shell, SWT.V_SCROLL | SWT.VIRTUAL );
+    grid.setSize( 200, 100 );
+    grid.setItemCount( 100 );
+    doFakeRedraw();
+
+    grid.getItem( 1 ).dispose();
+    doFakeRedraw();
+
+    assertEquals( 4, countResolvedGridItems() );
+  }
+
+  @Test
+  public void testResolvedItems_onVirtual_afterClear() {
+    grid = new Grid( shell, SWT.V_SCROLL | SWT.VIRTUAL );
+    grid.setSize( 200, 100 );
+    grid.setItemCount( 100 );
+    doFakeRedraw();
+
+    grid.setTopIndex( 50 );
+    doFakeRedraw();
+
+    grid.clearAll( true );
+    doFakeRedraw();
+
+    assertEquals( 8, countResolvedGridItems() );
+  }
+
+  @Test
+  public void testResolvedItems_onVirtual_afterAddingHiddenItemsInSetData() {
+    grid = new Grid( shell, SWT.V_SCROLL | SWT.VIRTUAL );
+    grid.setSize( 200, 100 );
+    grid.setItemCount( 100 );
+    grid.addListener( SWT.SetData, new Listener() {
+      public void handleEvent( Event event ) {
+        GridItem item = ( GridItem )event.item;
+        if( event.index == 0 && item.getParentItem() == null ) {
+          for( int i = 0; i < 5; i++ ) {
+            new GridItem( item, SWT.NONE );
+          }
+        }
+      }
+    } );
+
+    doFakeRedraw();
+
+    assertEquals( 4, countResolvedGridItems() );
+    assertTrue( grid.getItem( 0 ).isResolved() );
+    assertTrue( grid.getItem( 6 ).isResolved() );
+    assertTrue( grid.getItem( 7 ).isResolved() );
+    assertTrue( grid.getItem( 8 ).isResolved() );
+  }
+
+  @Test
+  public void testResolvedItems_onVirtual_afterAddingVisibleItemsInSetData() {
+    grid = new Grid( shell, SWT.V_SCROLL | SWT.VIRTUAL );
+    grid.setSize( 200, 100 );
+    grid.setItemCount( 100 );
+    grid.addListener( SWT.SetData, new Listener() {
+      public void handleEvent( Event event ) {
+        GridItem item = ( GridItem )event.item;
+        if( event.index == 0 && item.getParentItem() == null ) {
+          item.setExpanded( true );
+          for( int i = 0; i < 5; i++ ) {
+            new GridItem( item, SWT.NONE );
+          }
+        }
+      }
+    } );
+
+    doFakeRedraw();
+
+    assertEquals( 4, countResolvedGridItems() );
+    assertTrue( grid.getItem( 0 ).isResolved() );
+    assertTrue( grid.getItem( 1 ).isResolved() );
+    assertTrue( grid.getItem( 2 ).isResolved() );
+    assertTrue( grid.getItem( 3 ).isResolved() );
+  }
+
+  @Test
+  public void testRemoveAll_disposeInReverseOrder() {
+    final List<String> log = new ArrayList<String>();
+    createGridItems( grid, 5, 0 );
+    for( GridItem item : grid.getItems() ) {
+      item.addDisposeListener( new DisposeListener() {
+        public void widgetDisposed( DisposeEvent event ) {
+          GridItem item = ( GridItem )event.getSource();
+          log.add( item.getText() );
+        }
+      } );
+    }
+
+    grid.removeAll();
+
+    String[] expected = { "root_4", "root_3", "root_2", "root_1", "root_0" };
+    assertArrayEquals( expected, log.toArray( new String[ 0 ] ) );
+  }
+
+  @Test
+  public void testSetItemCount_disposeInReverseOrder() {
+    final List<String> log = new ArrayList<String>();
+    createGridItems( grid, 5, 0 );
+    for( GridItem item : grid.getItems() ) {
+      item.addDisposeListener( new DisposeListener() {
+        public void widgetDisposed( DisposeEvent event ) {
+          GridItem item = ( GridItem )event.getSource();
+          log.add( item.getText() );
+        }
+      } );
+    }
+
+    grid.setItemCount( 0 );
+
+    String[] expected = { "root_4", "root_3", "root_2", "root_1", "root_0" };
+    assertArrayEquals( expected, log.toArray( new String[ 0 ] ) );
+  }
+
+  @Test
+  public void testGetMaxContentWidth_resolveOnlyVisibleItems() {
+    grid = new Grid( shell, SWT.V_SCROLL | SWT.VIRTUAL );
+    GridColumn column = new GridColumn( grid, SWT.NONE );
+    grid.setSize( 200, 100 );
+    grid.setItemCount( 100 );
+
+    grid.getMaxContentWidth( column );
+
+    assertEquals( 4, countResolvedGridItems() );
+  }
+
   //////////////////
   // Helping methods
 
+  private int countResolvedGridItems() {
+    int counter = 0;
+    Item[] items = ItemHolder.getItemHolder( grid ).getItems();
+    for( Item item : items ) {
+      if( item instanceof GridItem ) {
+        counter++;
+      }
+    }
+    return counter;
+  }
+
   private void doFakeRedraw() {
     grid.getAdapter( IGridAdapter.class ).doRedraw();
   }
diff --git a/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/GridItemData_Test.java b/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/GridItemData_Test.java
new file mode 100644
index 0000000..6adde27
--- /dev/null
+++ b/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/GridItemData_Test.java
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * Copyright (c) 2014 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;
+
+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.mock;
+
+import org.eclipse.rap.rwt.testfixture.Fixture;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.widgets.Display;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+
+public class GridItemData_Test {
+
+  private Display display;
+  private GridItemData data;
+
+  @Before
+  public void setUp() {
+    Fixture.setUp();
+    display = new Display();
+    data = new GridItemData( 3 );
+  }
+
+  @After
+  public void tearDown() {
+    Fixture.tearDown();
+  }
+
+  @Test
+  public void testCreate_defaultValues() {
+    assertNull( data.defaultFont );
+    assertNull( data.defaultBackground );
+    assertNull( data.defaultForeground );
+    assertEquals( -1, data.customHeight );
+    assertFalse( data.expanded );
+    assertNull( data.children );
+    assertNotNull( data.cellData );
+  }
+
+  @Test
+  public void testCreate_zeroCells() {
+    data = new GridItemData( 0 );
+
+    assertEquals( 1, data.cellData.size() );
+  }
+
+  @Test
+  public void testCreate_nonZeroCells() {
+    assertEquals( 3, data.cellData.size() );
+  }
+
+  @Test
+  public void testGetCellData() {
+    assertNotNull( data.getCellData( 1 ) );
+  }
+
+  @Test( expected = IndexOutOfBoundsException.class )
+  public void testGetCellData_invalidIndex() {
+    data.getCellData( 4 );
+  }
+
+  @Test
+  public void testAddCellData_atEnd() {
+    data = new GridItemData( 1 );
+    data.getCellData( 0 );
+
+    data.addCellData( -1 );
+
+    assertNotNull( data.cellData.get( 0 ) );
+    assertNull( data.cellData.get( 1 ) );
+  }
+
+  @Test
+  public void testAddCellData_atIndex() {
+    data = new GridItemData( 1 );
+    data.getCellData( 0 );
+
+    data.addCellData( 0 );
+
+    assertNull( data.cellData.get( 0 ) );
+    assertNotNull( data.cellData.get( 1 ) );
+  }
+
+  @Test
+  public void testRemoveCellData() {
+    data = new GridItemData( 1 );
+
+    data.removeCellData( 0 );
+
+    assertEquals( 0, data.cellData.size() );
+  }
+
+  @Test
+  public void testGetChildren() {
+    assertNotNull( data.getChildren() );
+  }
+
+  @Test
+  public void testClear() {
+    data.defaultFont = new Font( display, "Arial", 14, SWT.NORMAL );
+    data.defaultBackground = mock( Color.class );
+    data.defaultForeground = mock( Color.class );
+    data.customHeight = 10;
+    data.expanded = true;
+    data.getCellData( 1 );
+
+    data.clear();
+
+    assertEquals( 3, data.cellData.size() );
+    assertNull( data.cellData.get( 1 ) );
+    assertNull( data.defaultFont );
+    assertNull( data.defaultBackground );
+    assertNull( data.defaultForeground );
+    assertEquals( 10, data.customHeight );
+    assertTrue( data.expanded );
+  }
+
+}
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 075f395..8add018 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
@@ -29,6 +29,7 @@
 import org.eclipse.rap.json.JsonObject;
 import org.eclipse.rap.json.JsonValue;
 import org.eclipse.rap.rwt.RWT;
+import org.eclipse.rap.rwt.internal.lifecycle.WidgetAdapter;
 import org.eclipse.rap.rwt.internal.lifecycle.WidgetUtil;
 import org.eclipse.rap.rwt.internal.protocol.Operation.CreateOperation;
 import org.eclipse.rap.rwt.internal.protocol.Operation.DestroyOperation;
@@ -81,19 +82,6 @@
     TestMessage message = Fixture.getProtocolMessage();
     CreateOperation operation = message.findCreateOperation( items[ 8 ] );
     assertEquals( "rwt.widgets.GridItem", operation.getType() );
-    assertEquals( 3, operation.getProperties().get( "index" ).asInt() );
-  }
-
-  @Test
-  public void testRenderCreate_WithParentItem() throws IOException {
-    GridItem[] items = createGridItems( grid, 3, 3 );
-
-    lca.renderInitialization( items[ 10 ] );
-
-    TestMessage message = Fixture.getProtocolMessage();
-    CreateOperation operation = message.findCreateOperation( items[ 10 ] );
-    assertEquals( "rwt.widgets.GridItem", operation.getType() );
-    assertEquals( 1, operation.getProperties().get( "index" ).asInt() );
   }
 
   @Test
@@ -168,6 +156,68 @@
   }
 
   @Test
+  public void testRenderInitialIndex() throws IOException {
+    GridItem gridItem = new GridItem( grid, SWT.NONE );
+
+    lca.render( gridItem );
+
+    TestMessage message = Fixture.getProtocolMessage();
+    CreateOperation operation = message.findCreateOperation( gridItem );
+    assertEquals( 1, operation.getProperties().get( "index" ).asInt() );
+  }
+
+  @Test
+  public void testRenderIndex() throws IOException {
+    new GridItem( grid, SWT.NONE, 0 );
+    lca.renderChanges( item );
+
+    TestMessage message = Fixture.getProtocolMessage();
+    assertEquals( 1, message.findSetProperty( item, "index" ).asInt() );
+  }
+
+  @Test
+  public void testRenderIndex_VirtualAfterClear() throws IOException {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    item = new GridItem( grid, SWT.NONE );
+    Fixture.markInitialized( display );
+    Fixture.markInitialized( item );
+    Fixture.preserveWidgets();
+
+    new GridItem( grid, SWT.NONE, 0 );
+    grid.clear( 1, false );
+    lca.renderChanges( item );
+
+    TestMessage message = Fixture.getProtocolMessage();
+    assertEquals( 1, message.findSetProperty( item, "index" ).asInt() );
+  }
+
+  @Test
+  public void testRenderIndexWithParentItem() throws IOException {
+    GridItem rootItem = new GridItem( grid, SWT.NONE );
+    new GridItem( rootItem, SWT.NONE );
+    GridItem item = new GridItem( rootItem, SWT.NONE );
+
+    new GridItem( rootItem, SWT.NONE, 0 );
+    lca.renderChanges( item );
+
+    TestMessage message = Fixture.getProtocolMessage();
+    assertEquals( 2, message.findSetProperty( item, "index" ).asInt() );
+  }
+
+  @Test
+  public void testRenderIndexUnchanged() throws IOException {
+    Fixture.markInitialized( display );
+    Fixture.markInitialized( item );
+
+    new GridItem( grid, SWT.NONE, 0 );
+    Fixture.preserveWidgets();
+    lca.renderChanges( item );
+
+    TestMessage message = Fixture.getProtocolMessage();
+    assertNull( message.findSetOperation( item, "index" ) );
+  }
+
+  @Test
   public void testRenderInitialCustomVariant() throws IOException {
     lca.render( item );
 
@@ -754,4 +804,101 @@
     assertEquals( 0, message.getOperationCount() );
   }
 
+  @Test
+  public void testRender_onVirtual() throws IOException {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    grid.setItemCount( 1 );
+    // Ensure that nothing is written for an item that is virtual and whose
+    // cached was false and remains unchanged while processing the life cycle
+    GridItem item = grid.getItem( 0 );
+    grid.clear( 0, false );
+    Fixture.markInitialized( item );
+    // Ensure that nothing else than the 'index' and 'cached' property gets preserved
+    lca.preserveValues( item );
+    WidgetAdapter adapter = WidgetUtil.getAdapter( item );
+
+    assertEquals( Boolean.FALSE, adapter.getPreserved( "cached" ) );
+    assertEquals( Integer.valueOf( 0 ), adapter.getPreserved( "index" ) );
+    assertNull( adapter.getPreserved( "itemCount" ) );
+    assertNull( adapter.getPreserved( "texts" ) );
+    assertNull( adapter.getPreserved( "images" ) );
+    assertNull( adapter.getPreserved( "cellChecked" ) );
+
+    // ... and no operations are generated for a uncached item that was already
+    // uncached when entering the life cycle
+    lca.renderChanges( item );
+
+    assertEquals( 0, Fixture.getProtocolMessage().getOperationCount() );
+  }
+
+  @Test
+  public void testRender_onVirtual_rendersOnlyChangedProperties() throws IOException {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    grid.setItemCount( 1 );
+    GridItem item = grid.getItem( 0 );
+    Fixture.markInitialized( item );
+    lca.preserveValues( item );
+    item.setText( "foo" );
+
+    lca.renderChanges( item );
+
+    TestMessage message = Fixture.getProtocolMessage();
+    assertNotNull( message.findSetOperation( item, "texts" ) );
+    assertNull( message.findSetOperation( item, "itemCount" ) );
+    assertNull( message.findSetOperation( item, "height" ) );
+    assertNull( message.findSetOperation( item, "images" ) );
+    assertNull( message.findSetOperation( item, "cellChecked" ) );
+    assertNull( message.findSetOperation( item, "cellGrayed" ) );
+    assertNull( message.findSetOperation( item, "cellCheckable" ) );
+    assertNull( message.findSetOperation( item, "font" ) );
+    assertNull( message.findSetOperation( item, "foreground" ) );
+    assertNull( message.findSetOperation( item, "background" ) );
+    assertNull( message.findSetOperation( item, "cellFonts" ) );
+    assertNull( message.findSetOperation( item, "cellBackgrounds" ) );
+    assertNull( message.findSetOperation( item, "cellForegrounds" ) );
+  }
+
+  @Test
+  public void testRender_onVirtual_preservesInitializedFlag() throws IOException {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    grid.setItemCount( 1 );
+    GridItem item = grid.getItem( 0 );
+    Fixture.markInitialized( item );
+    lca.preserveValues( item );
+    item.setText( "foo" );
+
+    lca.renderChanges( item );
+
+    assertTrue( WidgetUtil.getAdapter( item ).isInitialized() );
+  }
+
+  @Test
+  public void testRenderClear_onNonInitializedItem() throws IOException {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    grid.setItemCount( 1 );
+    GridItem item = grid.getItem( 0 );
+    item.getText();
+
+    lca.renderChanges( item );
+
+    TestMessage message = Fixture.getProtocolMessage();
+    assertNull( message.findCallOperation( item, "clear" ) );
+  }
+
+  @Test
+  public void testRenderClear_onInitializedItem() throws IOException {
+    grid = new Grid( shell, SWT.VIRTUAL );
+    grid.setItemCount( 1 );
+    GridItem item = grid.getItem( 0 );
+    item.getText();
+    Fixture.markInitialized( item );
+
+    lca.preserveValues( item );
+    grid.clear( 0, false );
+    lca.renderChanges( item );
+
+    TestMessage message = Fixture.getProtocolMessage();
+    assertNotNull( message.findCallOperation( item, "clear" ) );
+  }
+
 }