/******************************************************************************* * Copyright (c) 2002, 2015 Innoopract Informationssysteme GmbH 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: * Innoopract Informationssysteme GmbH - initial API and implementation * EclipseSource - ongoing development ******************************************************************************/ package org.eclipse.swt.internal.widgets.tablekit; import static org.eclipse.rap.rwt.internal.lifecycle.WidgetLCAUtil.getStyles; import static org.eclipse.rap.rwt.internal.lifecycle.WidgetLCAUtil.hasChanged; 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.getAdapter; 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.rap.json.JsonArray; import org.eclipse.rap.rwt.internal.lifecycle.WidgetLCA; import org.eclipse.rap.rwt.internal.lifecycle.ControlLCAUtil; 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.graphics.Rectangle; import org.eclipse.swt.internal.widgets.CellToolTipUtil; import org.eclipse.swt.internal.widgets.ICellToolTipAdapter; import org.eclipse.swt.internal.widgets.IItemHolderAdapter; import org.eclipse.swt.internal.widgets.ITableAdapter; import org.eclipse.swt.internal.widgets.WidgetRemoteAdapter; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Item; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableItem; public final class TableLCA extends WidgetLCA<Table> { public static final TableLCA INSTANCE = new TableLCA(); private static final String TYPE = "rwt.widgets.Grid"; private static final String[] ALLOWED_STYLES = { "SINGLE", "MULTI", "CHECK", "FULL_SELECTION", "HIDE_SELECTION", "VIRTUAL", "NO_SCROLL", "NO_RADIO_GROUP", "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_FIXED_COLUMNS = "fixedColumns"; private static final String PROP_HEADER_HEIGHT = "headerHeight"; private static final String PROP_HEADER_VISIBLE = "headerVisible"; 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_SORT_DIRECTION = "sortDirection"; private static final String PROP_SORT_COLUMN = "sortColumn"; private static final String PROP_SETDATA_LISTENER = "SetData"; private static final String PROP_ALWAYS_HIDE_SELECTION = "alwaysHideSelection"; 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 preserveValues( Table table ) { preserveProperty( table, PROP_ITEM_COUNT, table.getItemCount() ); preserveProperty( table, PROP_ITEM_HEIGHT, table.getItemHeight() ); preserveProperty( table, PROP_ITEM_METRICS, getItemMetrics( table ) ); preserveProperty( table, PROP_COLUMN_COUNT, table.getColumnCount() ); preserveProperty( table, PROP_COLUMN_ORDER, getColumnOrder( table ) ); preserveProperty( table, PROP_FIXED_COLUMNS, getFixedColumns( table ) ); preserveProperty( table, PROP_HEADER_HEIGHT, table.getHeaderHeight() ); preserveProperty( table, PROP_HEADER_VISIBLE, table.getHeaderVisible() ); preserveProperty( table, PROP_LINES_VISIBLE, table.getLinesVisible() ); preserveProperty( table, PROP_TOP_ITEM_INDEX, table.getTopIndex() ); preserveProperty( table, PROP_FOCUS_ITEM, getFocusItem( table ) ); preserveProperty( table, PROP_SCROLL_LEFT, getScrollLeft( table ) ); preserveProperty( table, PROP_SELECTION, getSelection( table ) ); preserveProperty( table, PROP_SORT_DIRECTION, getSortDirection( table ) ); preserveProperty( table, PROP_SORT_COLUMN, table.getSortColumn() ); preserveProperty( table, PROP_ALWAYS_HIDE_SELECTION, hasAlwaysHideSelection( table ) ); preserveProperty( table, PROP_ENABLE_CELL_TOOLTIP, CellToolTipUtil.isEnabledFor( table ) ); preserveProperty( table, PROP_CELL_TOOLTIP_TEXT, null ); } @Override public void renderInitialization( Table table ) throws IOException { RemoteObject remoteObject = createRemoteObject( table, TYPE ); remoteObject.setHandler( new TableOperationHandler( table ) ); remoteObject.set( "parent", getId( table.getParent() ) ); remoteObject.set( "style", createJsonArray( getStyles( table, ALLOWED_STYLES ) ) ); remoteObject.set( "appearance", "table" ); ITableAdapter adapter = getTableAdapter( table ); if( ( table.getStyle() & SWT.CHECK ) != 0 ) { JsonArray metrics = new JsonArray() .add( adapter.getCheckLeft() ) .add( adapter.getCheckWidth() ); remoteObject.set( "checkBoxMetrics", metrics ); } if( getFixedColumns( table ) >= 0 ) { remoteObject.set( "splitContainer", true ); } remoteObject.set( "indentionWidth", 0 ); remoteObject.set( PROP_TREE_COLUMN, -1 ); remoteObject.set( PROP_MARKUP_ENABLED, isMarkupEnabledFor( table ) ); TemplateLCAUtil.renderRowTemplate( table ); remoteObject.listen( PROP_SETDATA_LISTENER, isVirtual( table ) ); } @Override public void renderChanges( final Table table ) throws IOException { ControlLCAUtil.renderChanges( table ); WidgetLCAUtil.renderCustomVariant( table ); renderProperty( table, PROP_ITEM_COUNT, table.getItemCount(), ZERO ); renderProperty( table, PROP_ITEM_HEIGHT, table.getItemHeight(), ZERO ); renderItemMetrics( table ); renderProperty( table, PROP_COLUMN_COUNT, table.getColumnCount(), ZERO ); renderProperty( table, PROP_COLUMN_ORDER, getColumnOrder( table ), DEFAULT_COLUMN_ORDER ); renderProperty( table, PROP_FIXED_COLUMNS, getFixedColumns( table ), -1 ); renderProperty( table, PROP_HEADER_HEIGHT, table.getHeaderHeight(), ZERO ); renderProperty( table, PROP_HEADER_VISIBLE, table.getHeaderVisible(), false ); renderProperty( table, PROP_LINES_VISIBLE, table.getLinesVisible(), false ); renderProperty( table, PROP_SORT_DIRECTION, getSortDirection( table ), DEFAULT_SORT_DIRECTION ); renderAfterItems( table, new Runnable() { @Override public void run() { renderProperty( table, PROP_TOP_ITEM_INDEX, table.getTopIndex(), ZERO ); renderProperty( table, PROP_SCROLL_LEFT, getScrollLeft( table ), ZERO ); renderProperty( table, PROP_FOCUS_ITEM, getFocusItem( table ), null ); renderProperty( table, PROP_SELECTION, getSelection( table ), DEFAULT_SELECTION ); renderProperty( table, PROP_SORT_COLUMN, table.getSortColumn(), null ); } } ); renderListenSelection( table ); renderListenDefaultSelection( table ); renderProperty( table, PROP_ALWAYS_HIDE_SELECTION, hasAlwaysHideSelection( table ), false ); renderProperty( table, PROP_ENABLE_CELL_TOOLTIP, CellToolTipUtil.isEnabledFor( table ), false ); renderProperty( table, PROP_CELL_TOOLTIP_TEXT, getAndResetCellToolTipText( table ), null ); } @Override public void doRedrawFake( Control control ) { Table table = ( Table )control; getTableAdapter( table ).checkData(); } private static String getAndResetCellToolTipText( Table table ) { ICellToolTipAdapter adapter = CellToolTipUtil.getAdapter( table ); String toolTipText = adapter.getCellToolTipText(); adapter.setCellToolTipText( null ); return toolTipText; } private static boolean isVirtual( Table table ) { return ( table.getStyle() & SWT.VIRTUAL ) != 0; } private static String[] getSelection( Table table ) { TableItem[] selection = table.getSelection(); String[] result = new String[ selection.length ]; for( int i = 0; i < result.length; i++ ) { result[ i ] = getId( selection[ i ] ); } return result; } private static String[] getColumnOrder( Table table ) { int[] order = table.getColumnOrder(); String[] result = new String[ order.length ]; for( int i = 0; i < result.length; i++ ) { result[ i ] = getId( table.getColumn( order[ i ] ) ); } return result; } private static int getFixedColumns( Table table ) { return getTableAdapter( table ).getFixedColumns(); } private static int getScrollLeft( Table table ) { return getTableAdapter( table ).getLeftOffset(); } private static TableItem getFocusItem( Table table ) { TableItem result = null; int focusIndex = getTableAdapter( table ).getFocusIndex(); if( focusIndex != -1 ) { // TODO [rh] do something about when index points to unresolved item! result = table.getItem( focusIndex ); } return result; } private static String getSortDirection( Table table ) { String result = "none"; if( table.getSortDirection() == SWT.UP ) { result = "up"; } else if( table.getSortDirection() == SWT.DOWN ) { result = "down"; } return result; } static boolean hasAlwaysHideSelection( Table table ) { Object data = table.getData( Table.ALWAYS_HIDE_SELECTION ); return Boolean.TRUE.equals( data ); } private static ITableAdapter getTableAdapter( Table table ) { return table.getAdapter( ITableAdapter.class ); } private static void renderAfterItems( Table table, Runnable runnable ) { Item[] items = table.getAdapter( IItemHolderAdapter.class ).getItems(); if( items.length > 0 ) { Item lastItem = items[ items.length - 1 ]; WidgetRemoteAdapter adapter = ( WidgetRemoteAdapter )getAdapter( lastItem ); adapter.addRenderRunnable( runnable ); } else { runnable.run(); } } private static void renderItemMetrics( Table table ) { ItemMetrics[] itemMetrics = getItemMetrics( table ); if( hasChanged( table, 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 ) ); } getRemoteObject( table ).set( PROP_ITEM_METRICS, metrics ); } } static ItemMetrics[] getItemMetrics( Table table ) { int columnCount = Math.max( 1, table.getColumnCount() ); ItemMetrics[] result = new ItemMetrics[ columnCount ]; for( int i = 0; i < columnCount; i++ ) { result[ i ] = new ItemMetrics(); } ITableAdapter tableAdapter = getTableAdapter( table ); TableItem measureItem = tableAdapter.getMeasureItem(); if( measureItem != null ) { for( int i = 0; i < columnCount; i++ ) { int leftOffset = tableAdapter.getColumnLeftOffset( i ); Rectangle bounds = measureItem.getBounds( i ); Rectangle imageBounds = measureItem.getImageBounds( i ); Rectangle textBounds = measureItem.getTextBounds( i ); // If in column mode, cut image width if image exceeds right cell border int imageWidth = tableAdapter.getItemImageWidth( i ); if( table.getColumnCount() > 0 ) { TableColumn column = table.getColumn( i ); int columnLeft = tableAdapter.getColumnLeft( column ); int columnWidth = column.getWidth(); int maxImageWidth = columnWidth - ( imageBounds.x - columnLeft + leftOffset ); if( imageWidth > maxImageWidth ) { imageWidth = Math.max( 0, maxImageWidth ); } } result[ i ].left = bounds.x + leftOffset; result[ i ].width = bounds.width; result[ i ].imageLeft = imageBounds.x + leftOffset; result[ i ].imageWidth = imageWidth; result[ i ].textLeft = textBounds.x + leftOffset; result[ i ].textWidth = textBounds.width; } } else if( table.getColumnCount() > 0 ) { for( int i = 0; i < columnCount; i++ ) { TableColumn column = table.getColumn( i ); int columnLeft = tableAdapter.getColumnLeft( column ); int columnWidth = column.getWidth(); result[ i ].left = columnLeft; result[ i ].width = columnWidth; } } return result; } static final class ItemMetrics { int left; int width; 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.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 ); } } private TableLCA() { // prevent instantiation } }