Add support for markup in tooltip
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 63386fb..34e1a3f 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
@@ -10,6 +10,8 @@
  ******************************************************************************/
 package org.eclipse.nebula.widgets.grid;
 
+import static org.eclipse.swt.internal.widgets.MarkupUtil.isMarkupEnabledFor;
+
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
@@ -36,7 +38,6 @@
 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.internal.widgets.MarkupValidator;
 import org.eclipse.swt.widgets.Canvas;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Event;
@@ -99,8 +100,6 @@
   private final IGridAdapter gridAdapter;
   private transient CompositeItemHolder itemHolder;
   boolean hasDifferingHeights;
-  boolean markupEnabled;
-  boolean markupValidationDisabled;
   LayoutCache layoutCache;
 
   /**
@@ -2280,12 +2279,9 @@
 
   @Override
   public void setData( String key, Object value ) {
-    if( RWT.MARKUP_ENABLED.equals( key ) && !markupEnabled ) {
-      markupEnabled = Boolean.TRUE.equals( value );
-    } else if( MarkupValidator.MARKUP_VALIDATION_DISABLED.equals( key ) ) {
-      markupValidationDisabled = Boolean.TRUE.equals( value );
+    if( !RWT.MARKUP_ENABLED.equals( key ) || !isMarkupEnabledFor( this ) ) {
+      super.setData( key, value );
     }
-    super.setData( key, value );
   }
 
   int newItem( GridItem item, int index, boolean root ) {
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 191fff3..87a3147 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
@@ -10,12 +10,17 @@
  ******************************************************************************/
 package org.eclipse.nebula.widgets.grid;
 
+import static org.eclipse.swt.internal.widgets.MarkupUtil.isToolTipMarkupEnabledFor;
+import static org.eclipse.swt.internal.widgets.MarkupValidator.isValidationDisabledFor;
+
+import org.eclipse.rap.rwt.RWT;
 import org.eclipse.rap.rwt.internal.textsize.TextSizeUtil;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.ControlListener;
 import org.eclipse.swt.events.SelectionListener;
 import org.eclipse.swt.graphics.Font;
 import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.internal.widgets.MarkupValidator;
 import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Item;
 import org.eclipse.swt.widgets.TypedListener;
@@ -814,7 +819,7 @@
   /**
    * Sets the tooltip text of the column header.
    *
-   * @param tooltip the tooltip text
+   * @param toolTipText the tooltip text
    * @throws org.eclipse.swt.SWTException
    *             <ul>
    *             <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed
@@ -823,9 +828,15 @@
    *             thread that created the receiver</li>
    *             </ul>
    */
-  public void setHeaderTooltip(String tooltip) {
+  public void setHeaderTooltip( String toolTipText ) {
     checkWidget();
-    headerTooltip = tooltip;
+    if(    toolTipText != null
+        && isToolTipMarkupEnabledFor( this )
+        && !isValidationDisabledFor( this ) )
+    {
+      MarkupValidator.getInstance().validate( toolTipText );
+    }
+    headerTooltip = toolTipText;
   }
 
   /**
@@ -1003,6 +1014,13 @@
     parent.redraw();
   }
 
+  @Override
+  public void setData( String key, Object value ) {
+    if( !RWT.TOOLTIP_MARKUP_ENABLED.equals( key ) || !isToolTipMarkupEnabledFor( this ) ) {
+      super.setData( key, value );
+    }
+  }
+
   void repack() {
     if( packed ) {
       pack();
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 85c16df..af73cb9 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
@@ -10,6 +10,9 @@
  ******************************************************************************/
 package org.eclipse.nebula.widgets.grid;
 
+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;
 
@@ -829,7 +832,7 @@
     if( text == null ) {
       SWT.error( SWT.ERROR_NULL_ARGUMENT );
     }
-    if( parent.markupEnabled && !parent.markupValidationDisabled ) {
+    if( isMarkupEnabledFor( parent ) && !isValidationDisabledFor( parent ) ) {
       MarkupValidator.getInstance().validate( text );
     }
     Data itemData = getItemData( index );
diff --git a/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/gridkit/GridLCA.java b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/gridkit/GridLCA.java
index 0d87246..1d00e5a 100644
--- a/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/gridkit/GridLCA.java
+++ b/bundles/org.eclipse.rap.nebula.widgets.grid/src/org/eclipse/nebula/widgets/grid/internal/gridkit/GridLCA.java
@@ -29,6 +29,7 @@
 import static org.eclipse.rap.rwt.lifecycle.WidgetLCAUtil.wasEventSent;
 import static org.eclipse.rap.rwt.lifecycle.WidgetUtil.getId;
 import static org.eclipse.swt.internal.events.EventLCAUtil.isListening;
+import static org.eclipse.swt.internal.widgets.MarkupUtil.isMarkupEnabledFor;
 
 import java.io.IOException;
 
@@ -37,7 +38,6 @@
 import org.eclipse.nebula.widgets.grid.GridItem;
 import org.eclipse.nebula.widgets.grid.internal.IGridAdapter;
 import org.eclipse.rap.json.JsonArray;
-import org.eclipse.rap.rwt.RWT;
 import org.eclipse.rap.rwt.internal.protocol.ClientMessageConst;
 import org.eclipse.rap.rwt.internal.util.NumberFormatUtil;
 import org.eclipse.rap.rwt.lifecycle.AbstractWidgetLCA;
@@ -110,7 +110,7 @@
     remoteObject.set( "appearance", "tree" );
     IGridAdapter adapter = getGridAdapter( grid );
     remoteObject.set( "indentionWidth", adapter.getIndentationWidth() );
-    remoteObject.set( PROP_MARKUP_ENABLED, isMarkupEnabled( grid ) );
+    remoteObject.set( PROP_MARKUP_ENABLED, isMarkupEnabledFor( grid ) );
     ScrollBarLCAUtil.renderInitialization( grid );
   }
 
@@ -283,10 +283,6 @@
     return ( grid.getStyle() & SWT.VIRTUAL ) != 0;
   }
 
-  private static boolean isMarkupEnabled( Grid grid ) {
-    return Boolean.TRUE.equals( grid.getData( RWT.MARKUP_ENABLED ) );
-  }
-
   private static int getTreeColumn( Grid grid ) {
     int[] order = grid.getColumnOrder();
     return order.length > 0 ? order[ 0 ] : 0;
diff --git a/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/GridColumn_Test.java b/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/GridColumn_Test.java
index 124430a..9bde6c1 100644
--- a/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/GridColumn_Test.java
+++ b/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/GridColumn_Test.java
@@ -19,6 +19,7 @@
 
 import junit.framework.TestCase;
 
+import org.eclipse.rap.rwt.RWT;
 import org.eclipse.rap.rwt.internal.service.ContextProvider;
 import org.eclipse.rap.rwt.internal.service.ServiceStore;
 import org.eclipse.rap.rwt.lifecycle.PhaseId;
@@ -32,10 +33,12 @@
 import org.eclipse.swt.events.SelectionListener;
 import org.eclipse.swt.graphics.Font;
 import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.internal.widgets.MarkupValidator;
 import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.Shell;
+import org.junit.Test;
 
 
 @SuppressWarnings("restriction")
@@ -835,6 +838,61 @@
     assertFalse( column.isVisible() );
   }
 
+  @Test
+  public void testMarkupToolTipTextWithoutMarkupEnabled() {
+    GridColumn column = new GridColumn( grid, SWT.NONE );
+    column.setData( RWT.TOOLTIP_MARKUP_ENABLED, Boolean.FALSE );
+
+    try {
+      column.setHeaderTooltip( "invalid xhtml: <<&>>" );
+    } catch( IllegalArgumentException notExpected ) {
+      fail();
+    }
+  }
+
+  @Test
+  public void testMarkupToolTipTextWithMarkupEnabled() {
+    GridColumn column = new GridColumn( grid, SWT.NONE );
+    column.setData( RWT.TOOLTIP_MARKUP_ENABLED, Boolean.TRUE );
+
+    try {
+      column.setHeaderTooltip( "invalid xhtml: <<&>>" );
+      fail();
+    } catch( IllegalArgumentException expected ) {
+    }
+  }
+
+  @Test
+  public void testMarkupTextWithMarkupEnabled_ValidationDisabled() {
+    GridColumn column = new GridColumn( grid, SWT.NONE );
+    column.setData( RWT.TOOLTIP_MARKUP_ENABLED, Boolean.TRUE );
+    column.setData( MarkupValidator.MARKUP_VALIDATION_DISABLED, Boolean.TRUE );
+
+    try {
+      column.setHeaderTooltip( "invalid xhtml: <<&>>" );
+    } catch( IllegalArgumentException notExpected ) {
+      fail();
+    }
+  }
+
+  @Test
+  public void testDisableMarkupIsIgnored() {
+    GridColumn column = new GridColumn( grid, SWT.NONE );
+    column.setData( RWT.TOOLTIP_MARKUP_ENABLED, Boolean.TRUE );
+
+    column.setData( RWT.TOOLTIP_MARKUP_ENABLED, Boolean.FALSE );
+
+    assertEquals( Boolean.TRUE, column.getData( RWT.TOOLTIP_MARKUP_ENABLED ) );
+  }
+
+  @Test
+  public void testSetData() {
+    GridColumn column = new GridColumn( grid, SWT.NONE );
+    column.setData( "foo", "bar" );
+
+    assertEquals( "bar", column.getData( "foo" ) );
+  }
+
   //////////////////
   // 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 d91b6dd..6f5a794 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
@@ -2494,7 +2494,7 @@
 
     grid.setData( RWT.MARKUP_ENABLED, Boolean.FALSE );
 
-    assertTrue( grid.markupEnabled );
+    assertEquals( Boolean.TRUE, grid.getData( RWT.MARKUP_ENABLED ) );
   }
 
   //////////////////
diff --git a/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/gridcolumnkit/GridColumnLCA_Test.java b/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/gridcolumnkit/GridColumnLCA_Test.java
index 8e51a68..2655a65 100644
--- a/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/gridcolumnkit/GridColumnLCA_Test.java
+++ b/tests/org.eclipse.rap.nebula.widgets.grid.test/src/org/eclipse/nebula/widgets/grid/internal/gridcolumnkit/GridColumnLCA_Test.java
@@ -13,6 +13,7 @@
 import static org.eclipse.nebula.widgets.grid.GridTestUtil.createGridColumns;
 import static org.eclipse.nebula.widgets.grid.GridTestUtil.loadImage;
 import static org.eclipse.rap.rwt.lifecycle.WidgetUtil.getId;
+import static org.eclipse.rap.rwt.testfixture.Fixture.getProtocolMessage;
 
 import java.io.IOException;
 import java.util.LinkedList;
@@ -45,6 +46,7 @@
 import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Listener;
 import org.eclipse.swt.widgets.Shell;
+import org.junit.Test;
 
 
 @SuppressWarnings("restriction")
@@ -120,6 +122,27 @@
     assertEquals( WidgetUtil.getId( column ), operation.getTarget() );
   }
 
+  @Test
+  public void testRenderIntialToolTipMarkupEnabled() throws IOException {
+    column.setData( RWT.TOOLTIP_MARKUP_ENABLED, Boolean.TRUE );
+
+    lca.renderChanges( column );
+
+    Message message = getProtocolMessage();
+    assertTrue( "foo", message.findSetProperty( column, "toolTipMarkupEnabled" ).asBoolean() );
+  }
+
+  @Test
+  public void testRenderToolTipMarkupEnabled() throws IOException {
+    column.setData( RWT.TOOLTIP_MARKUP_ENABLED, Boolean.TRUE );
+    Fixture.markInitialized( column );
+
+    lca.renderChanges( column );
+
+    Message message = getProtocolMessage();
+    assertNull( message.findSetOperation( column, "toolTipMarkupEnabled" ) );
+  }
+
   public void testRenderInitialToolTip() throws IOException {
     lca.render( column );