/******************************************************************************
* Copyright (c) 2012, 2016 EclipseSource and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* EclipseSource - initial API and implementation
******************************************************************************/
package org.eclipse.nebula.widgets.grid.internal.gridkit;
import static org.eclipse.rap.rwt.internal.lifecycle.WidgetLCAUtil.getStyles;
import static org.eclipse.rap.rwt.internal.lifecycle.WidgetLCAUtil.preserveProperty;
import static org.eclipse.rap.rwt.internal.lifecycle.WidgetLCAUtil.renderListenDefaultSelection;
import static org.eclipse.rap.rwt.internal.lifecycle.WidgetLCAUtil.renderListenSelection;
import static org.eclipse.rap.rwt.internal.lifecycle.WidgetLCAUtil.renderProperty;
import static org.eclipse.rap.rwt.internal.lifecycle.WidgetUtil.getId;
import static org.eclipse.rap.rwt.internal.protocol.JsonUtil.createJsonArray;
import static org.eclipse.rap.rwt.internal.protocol.RemoteObjectFactory.createRemoteObject;
import static org.eclipse.rap.rwt.internal.protocol.RemoteObjectFactory.getRemoteObject;
import static org.eclipse.swt.internal.widgets.MarkupUtil.isMarkupEnabledFor;
import java.io.IOException;
import org.eclipse.nebula.widgets.grid.Grid;
import org.eclipse.nebula.widgets.grid.GridColumn;
import org.eclipse.nebula.widgets.grid.GridItem;
import org.eclipse.nebula.widgets.grid.internal.IGridAdapter;
import org.eclipse.rap.json.JsonArray;
import org.eclipse.rap.rwt.internal.lifecycle.ControlLCAUtil;
import org.eclipse.rap.rwt.internal.lifecycle.WidgetLCA;
import org.eclipse.rap.rwt.internal.lifecycle.WidgetLCAUtil;
import org.eclipse.rap.rwt.internal.template.TemplateLCAUtil;
import org.eclipse.rap.rwt.remote.RemoteObject;
import org.eclipse.swt.SWT;
import org.eclipse.swt.internal.widgets.CellToolTipUtil;
import org.eclipse.swt.internal.widgets.ICellToolTipAdapter;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.ScrollBar;
@SuppressWarnings("restriction")
public class GridLCA extends WidgetLCA<Grid> {
public static final GridLCA INSTANCE = new GridLCA();
private static final String TYPE = "rwt.widgets.Grid";
private static final String[] ALLOWED_STYLES = new String[] {
"SINGLE",
"MULTI",
"FULL_SELECTION",
"VIRTUAL",
"NO_FOCUS",
"BORDER"
};
private static final String PROP_ITEM_COUNT = "itemCount";
private static final String PROP_ITEM_HEIGHT = "itemHeight";
private static final String PROP_ITEM_METRICS = "itemMetrics";
private static final String PROP_COLUMN_COUNT = "columnCount";
private static final String PROP_COLUMN_ORDER = "columnOrder";
private static final String PROP_TREE_COLUMN = "treeColumn";
private static final String PROP_HEADER_HEIGHT = "headerHeight";
private static final String PROP_HEADER_VISIBLE = "headerVisible";
private static final String PROP_FOOTER_HEIGHT = "footerHeight";
private static final String PROP_FOOTER_VISIBLE = "footerVisible";
private static final String PROP_LINES_VISIBLE = "linesVisible";
private static final String PROP_TOP_ITEM_INDEX = "topItemIndex";
private static final String PROP_FOCUS_ITEM = "focusItem";
private static final String PROP_SCROLL_LEFT = "scrollLeft";
private static final String PROP_SELECTION = "selection";
private static final String PROP_AUTO_HEIGHT = "autoHeight";
private static final String PROP_INDENTION_WIDTH = "indentionWidth";
// TODO: [if] Sync sortDirection and sortColumn in GridColumnLCA when multiple sort columns are
// possible on the client
private static final String PROP_SORT_DIRECTION = "sortDirection";
private static final String PROP_SORT_COLUMN = "sortColumn";
private static final String PROP_SETDATA_LISTENER = "SetData";
private static final String PROP_EXPAND_LISTENER = "Expand";
private static final String PROP_COLLAPSE_LISTENER = "Collapse";
// TODO: [if] Sync toolTipText in GridItemLCA when it's possible on the client
private static final String PROP_ENABLE_CELL_TOOLTIP = "enableCellToolTip";
private static final String PROP_CELL_TOOLTIP_TEXT = "cellToolTipText";
private static final String PROP_MARKUP_ENABLED = "markupEnabled";
private static final int ZERO = 0 ;
private static final String[] DEFAULT_SELECTION = new String[ 0 ];
private static final String[] DEFAULT_COLUMN_ORDER = new String[ 0 ];
private static final String DEFAULT_SORT_DIRECTION = "none";
@Override
public void renderInitialization( Grid grid ) throws IOException {
RemoteObject remoteObject = createRemoteObject( grid, TYPE );
remoteObject.setHandler( new GridOperationHandler( grid ) );
remoteObject.set( "parent", getId( grid.getParent() ) );
remoteObject.set( "style", createJsonArray( getStyles( grid, ALLOWED_STYLES ) ) );
remoteObject.set( "appearance", "grid" );
remoteObject.set( PROP_MARKUP_ENABLED, isMarkupEnabledFor( grid ) );
TemplateLCAUtil.renderRowTemplate( grid );
remoteObject.listen( PROP_SETDATA_LISTENER, isVirtual( grid ) );
// Always render listen for Expand and Collapse, currently required for scrollbar
// visibility update and setData events.
remoteObject.listen( PROP_EXPAND_LISTENER, true );
remoteObject.listen( PROP_COLLAPSE_LISTENER, true );
}
@Override
public void preserveValues( Grid grid ) {
preserveProperty( grid, PROP_ITEM_COUNT, grid.getRootItemCount() );
preserveProperty( grid, PROP_ITEM_HEIGHT, grid.getItemHeight() );
preserveProperty( grid, PROP_ITEM_METRICS, getItemMetrics( grid ) );
preserveProperty( grid, PROP_COLUMN_COUNT, grid.getColumnCount() );
preserveProperty( grid, PROP_COLUMN_ORDER, getColumnOrder( grid ) );
preserveProperty( grid, PROP_TREE_COLUMN, getTreeColumn( grid ) );
preserveProperty( grid, PROP_HEADER_HEIGHT, grid.getHeaderHeight() );
preserveProperty( grid, PROP_HEADER_VISIBLE, grid.getHeaderVisible() );
preserveProperty( grid, PROP_FOOTER_HEIGHT, grid.getFooterHeight() );
preserveProperty( grid, PROP_FOOTER_VISIBLE, grid.getFooterVisible() );
preserveProperty( grid, PROP_LINES_VISIBLE, grid.getLinesVisible() );
preserveProperty( grid, PROP_TOP_ITEM_INDEX, getTopItemIndex( grid ) );
preserveProperty( grid, PROP_FOCUS_ITEM, grid.getFocusItem() );
preserveProperty( grid, PROP_SCROLL_LEFT, getScrollLeft( grid ) );
preserveProperty( grid, PROP_SELECTION, getSelection( grid ) );
preserveProperty( grid, PROP_AUTO_HEIGHT, grid.isAutoHeight() );
preserveProperty( grid, PROP_INDENTION_WIDTH, getIndentationWidth( grid ) );
preserveProperty( grid, PROP_SORT_DIRECTION, getSortDirection( grid ) );
preserveProperty( grid, PROP_SORT_COLUMN, getSortColumn( grid ) );
preserveProperty( grid, PROP_ENABLE_CELL_TOOLTIP, CellToolTipUtil.isEnabledFor( grid ) );
preserveProperty( grid, PROP_CELL_TOOLTIP_TEXT, null );
}
@Override
public void renderChanges( Grid grid ) throws IOException {
ControlLCAUtil.renderChanges( grid );
WidgetLCAUtil.renderCustomVariant( grid );
renderProperty( grid, PROP_ITEM_COUNT, grid.getRootItemCount(), ZERO );
renderProperty( grid, PROP_ITEM_HEIGHT, grid.getItemHeight(), ZERO );
renderItemMetrics( grid );
renderProperty( grid, PROP_COLUMN_COUNT, grid.getColumnCount(), ZERO );
renderProperty( grid, PROP_COLUMN_ORDER, getColumnOrder( grid ), DEFAULT_COLUMN_ORDER );
renderProperty( grid, PROP_TREE_COLUMN, getTreeColumn( grid ), ZERO );
renderProperty( grid, PROP_HEADER_HEIGHT, grid.getHeaderHeight(), ZERO );
renderProperty( grid, PROP_HEADER_VISIBLE, grid.getHeaderVisible(), false );
renderProperty( grid, PROP_FOOTER_HEIGHT, grid.getFooterHeight(), ZERO );
renderProperty( grid, PROP_FOOTER_VISIBLE, grid.getFooterVisible(), false );
renderProperty( grid, PROP_LINES_VISIBLE, grid.getLinesVisible(), false );
renderProperty( grid, PROP_TOP_ITEM_INDEX, getTopItemIndex( grid ), ZERO );
renderProperty( grid, PROP_FOCUS_ITEM, grid.getFocusItem(), null );
renderProperty( grid, PROP_SCROLL_LEFT, getScrollLeft( grid ), ZERO );
renderProperty( grid, PROP_SELECTION, getSelection( grid ), DEFAULT_SELECTION );
renderProperty( grid, PROP_AUTO_HEIGHT, grid.isAutoHeight(), false );
renderProperty( grid, PROP_INDENTION_WIDTH, getIndentationWidth( grid ), ZERO );
renderProperty( grid, PROP_SORT_DIRECTION, getSortDirection( grid ), DEFAULT_SORT_DIRECTION );
renderProperty( grid, PROP_SORT_COLUMN, getSortColumn( grid ), null );
renderListenSelection( grid );
renderListenDefaultSelection( grid );
renderProperty( grid, PROP_ENABLE_CELL_TOOLTIP, CellToolTipUtil.isEnabledFor( grid ), false );
renderProperty( grid, PROP_CELL_TOOLTIP_TEXT, getAndResetCellToolTipText( grid ), null );
}
@Override
public void doRedrawFake( Control control ) {
getGridAdapter( ( Grid )control ).doRedraw();
}
//////////////////
// Helping methods
private static String getAndResetCellToolTipText( Grid grid ) {
ICellToolTipAdapter adapter = CellToolTipUtil.getAdapter( grid );
String toolTipText = adapter.getCellToolTipText();
adapter.setCellToolTipText( null );
return toolTipText;
}
private static boolean isVirtual( Grid grid ) {
return ( grid.getStyle() & SWT.VIRTUAL ) != 0;
}
private static int getTreeColumn( Grid grid ) {
int[] order = grid.getColumnOrder();
return order.length > 0 ? order[ 0 ] : 0;
}
private static int getTopItemIndex( Grid grid ) {
int result = 0;
ScrollBar verticalBar = grid.getVerticalBar();
if( verticalBar != null ) {
result = verticalBar.getSelection();
}
return result;
}
private static int getScrollLeft( Grid grid ) {
int result = 0;
ScrollBar horizontalBar = grid.getHorizontalBar();
if( horizontalBar != null ) {
result = horizontalBar.getSelection();
}
return result;
}
private static String[] getSelection( Grid grid ) {
GridItem[] selection = grid.getSelection();
String[] result = new String[ selection.length ];
for( int i = 0; i < result.length; i++ ) {
result[ i ] = getId( selection[ i ] );
}
return result;
}
private static int getIndentationWidth( Grid grid ) {
return getGridAdapter( grid ).getIndentationWidth();
}
private static String getSortDirection( Grid grid ) {
String result = "none";
for( int i = 0; i < grid.getColumnCount() && result.equals( "none" ); i++ ) {
int sort = grid.getColumn( i ).getSort();
if( sort == SWT.UP ) {
result = "up";
} else if( sort == SWT.DOWN ) {
result = "down";
}
}
return result;
}
private static GridColumn getSortColumn( Grid grid ) {
GridColumn result = null;
for( int i = 0; i < grid.getColumnCount() && result == null; i++ ) {
GridColumn column = grid.getColumn( i );
if( column.getSort() != SWT.NONE ) {
result = column;
}
}
return result;
}
private static String[] getColumnOrder( Grid grid ) {
int[] order = grid.getColumnOrder();
String[] result = new String[ order.length ];
for( int i = 0; i < result.length; i++ ) {
result[ i ] = getId( grid.getColumn( order[ i ] ) );
}
return result;
}
///////////////
// Item Metrics
private static void renderItemMetrics( Grid grid ) {
ItemMetrics[] itemMetrics = getItemMetrics( grid );
if( WidgetLCAUtil.hasChanged( grid, PROP_ITEM_METRICS, itemMetrics ) ) {
JsonArray metrics = new JsonArray();
for( int i = 0; i < itemMetrics.length; i++ ) {
metrics.add( new JsonArray().add( i )
.add( itemMetrics[ i ].left )
.add( itemMetrics[ i ].width )
.add( itemMetrics[ i ].imageLeft )
.add( itemMetrics[ i ].imageWidth )
.add( itemMetrics[ i ].textLeft )
.add( itemMetrics[ i ].textWidth )
.add( itemMetrics[ i ].checkLeft )
.add( itemMetrics[ i ].checkWidth ) );
}
getRemoteObject( grid ).set( PROP_ITEM_METRICS, metrics );
}
}
static ItemMetrics[] getItemMetrics( Grid grid ) {
int columnCount = grid.getColumnCount();
ItemMetrics[] result = new ItemMetrics[ columnCount ];
IGridAdapter adapter = getGridAdapter( grid );
for( int i = 0; i < columnCount; i++ ) {
result[ i ] = new ItemMetrics();
result[ i ].left = adapter.getCellLeft( i );
result[ i ].width = adapter.getCellWidth( i );
result[ i ].checkLeft = result[ i ].left + adapter.getCheckBoxOffset( i );
result[ i ].checkWidth = adapter.getCheckBoxWidth( i );
result[ i ].imageLeft = result[ i ].left + adapter.getImageOffset( i );
result[ i ].imageWidth = adapter.getImageWidth( i );
result[ i ].textLeft = result[ i ].left + adapter.getTextOffset( i );
result[ i ].textWidth = adapter.getTextWidth( i );
}
return result;
}
private static IGridAdapter getGridAdapter( Grid grid ) {
return grid.getAdapter( IGridAdapter.class );
}
////////////////
// Inner classes
static final class ItemMetrics {
int left;
int width;
int checkLeft;
int checkWidth;
int imageLeft;
int imageWidth;
int textLeft;
int textWidth;
@Override
public boolean equals( Object obj ) {
boolean result;
if( obj == this ) {
result = true;
} else if( obj instanceof ItemMetrics ) {
ItemMetrics other = ( ItemMetrics )obj;
result = other.left == left
&& other.width == width
&& other.checkLeft == checkLeft
&& other.checkWidth == checkWidth
&& other.imageLeft == imageLeft
&& other.imageWidth == imageWidth
&& other.textLeft == textLeft
&& other.textWidth == textWidth;
} else {
result = false;
}
return result;
}
@Override
public int hashCode() {
String msg = "ItemMetrics#hashCode() not implemented";
throw new UnsupportedOperationException( msg );
}
}
}