blob: 0a09d1ba21abb7650197fc69461aa388ce4db07c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012 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.rwt.lifecycle.WidgetLCAUtil.preserveListener;
import static org.eclipse.rwt.lifecycle.WidgetLCAUtil.preserveProperty;
import static org.eclipse.rwt.lifecycle.WidgetLCAUtil.renderListener;
import static org.eclipse.rwt.lifecycle.WidgetLCAUtil.renderProperty;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
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.rwt.internal.lifecycle.JSConst;
import org.eclipse.rwt.internal.protocol.ClientObjectFactory;
import org.eclipse.rwt.internal.protocol.IClientObject;
import org.eclipse.rwt.internal.service.ContextProvider;
import org.eclipse.rwt.internal.util.NumberFormatUtil;
import org.eclipse.rwt.lifecycle.AbstractWidgetLCA;
import org.eclipse.rwt.lifecycle.ControlLCAUtil;
import org.eclipse.rwt.lifecycle.WidgetLCAUtil;
import org.eclipse.rwt.lifecycle.WidgetUtil;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.internal.events.EventLCAUtil;
import org.eclipse.swt.internal.widgets.CellToolTipUtil;
import org.eclipse.swt.internal.widgets.ICellToolTipAdapter;
import org.eclipse.swt.internal.widgets.ICellToolTipProvider;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Widget;
@SuppressWarnings("restriction")
public class GridLCA extends AbstractWidgetLCA {
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_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";
// 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_SCROLLBARS_VISIBLE = "scrollBarsVisible";
private static final String PROP_SCROLLBARS_SELECTION_LISTENER = "scrollBarsSelection";
private static final String PROP_SELECTION_LISTENER = "selection";
// 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 int ZERO = 0 ;
private static final String[] DEFAULT_SELECTION = new String[ 0 ];
private static final String DEFAULT_SORT_DIRECTION = "none";
private static final boolean[] DEFAULT_SCROLLBARS_VISIBLE = new boolean[] { false, false };
@Override
public void renderInitialization( Widget widget ) throws IOException {
Grid grid = ( Grid )widget;
IClientObject clientObject = ClientObjectFactory.getClientObject( grid );
clientObject.create( TYPE );
clientObject.set( "parent", WidgetUtil.getId( grid.getParent() ) );
clientObject.set( "style", WidgetLCAUtil.getStyles( grid, ALLOWED_STYLES ) );
clientObject.set( "appearance", "tree" );
IGridAdapter adapter = getGridAdapter( grid );
clientObject.set( "indentionWidth", adapter.getIndentationWidth() );
}
public void readData( Widget widget ) {
Grid grid = ( Grid )widget;
readSelection( grid );
readScrollLeft( grid );
readTopItemIndex( grid );
readCellToolTipTextRequested( grid );
processSelectionEvent( grid, JSConst.EVENT_WIDGET_SELECTED );
processSelectionEvent( grid, JSConst.EVENT_WIDGET_DEFAULT_SELECTED );
ControlLCAUtil.processMouseEvents( grid );
ControlLCAUtil.processKeyEvents( grid );
ControlLCAUtil.processMenuDetect( grid );
WidgetLCAUtil.processHelp( grid );
}
@Override
public void preserveValues( Widget widget ) {
Grid grid = ( Grid )widget;
ControlLCAUtil.preserveValues( ( Control )widget );
WidgetLCAUtil.preserveCustomVariant( 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_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_SORT_DIRECTION, getSortDirection( grid ) );
preserveProperty( grid, PROP_SORT_COLUMN, getSortColumn( grid ) );
preserveProperty( grid, PROP_SCROLLBARS_VISIBLE, getScrollBarsVisible( grid ) );
preserveListener( grid,
PROP_SCROLLBARS_SELECTION_LISTENER,
hasScrollBarsSelectionListener( grid ) );
preserveListener( grid, PROP_SELECTION_LISTENER, SelectionEvent.hasListener( grid ) );
preserveProperty( grid, PROP_ENABLE_CELL_TOOLTIP, CellToolTipUtil.isEnabledFor( grid ) );
preserveProperty( grid, PROP_CELL_TOOLTIP_TEXT, null );
}
@Override
public void renderChanges( Widget widget ) throws IOException {
Grid grid = ( Grid )widget;
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_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_SORT_DIRECTION, getSortDirection( grid ), DEFAULT_SORT_DIRECTION );
renderProperty( grid, PROP_SORT_COLUMN, getSortColumn( grid ), null );
renderProperty( grid,
PROP_SCROLLBARS_VISIBLE,
getScrollBarsVisible( grid ),
DEFAULT_SCROLLBARS_VISIBLE );
renderListener( grid,
PROP_SCROLLBARS_SELECTION_LISTENER,
hasScrollBarsSelectionListener( grid ),
false );
renderListener( grid, PROP_SELECTION_LISTENER, SelectionEvent.hasListener( grid ), false );
renderProperty( grid, PROP_ENABLE_CELL_TOOLTIP, CellToolTipUtil.isEnabledFor( grid ), false );
renderProperty( grid, PROP_CELL_TOOLTIP_TEXT, getCellToolTipText( grid ), null );
}
@Override
public void renderDispose( Widget widget ) throws IOException {
ClientObjectFactory.getClientObject( widget ).destroy();
}
////////////////////////////////////////////
// Helping methods to read client-side state
private static void readSelection( Grid grid ) {
String value = WidgetLCAUtil.readPropertyValue( grid, "selection" );
if( value != null ) {
String[] values = value.split( "," );
GridItem[] selectedItems = new GridItem[ values.length ];
boolean validItemFound = false;
for( int i = 0; i < values.length; i++ ) {
selectedItems[ i ] = getItem( grid, values[ i ] );
if( selectedItems[ i ] != null ) {
validItemFound = true;
}
}
if( !validItemFound ) {
selectedItems = new GridItem[ 0 ];
}
grid.setSelection( selectedItems );
}
}
private static void readScrollLeft( Grid grid ) {
String left = WidgetLCAUtil.readPropertyValue( grid, "scrollLeft" );
if( left != null ) {
int leftOffset = NumberFormatUtil.parseInt( left );
processScrollBarSelection( grid.getHorizontalBar(), leftOffset );
}
}
private static void readTopItemIndex( Grid grid ) {
String topItemIndex = WidgetLCAUtil.readPropertyValue( grid, "topItemIndex" );
if( topItemIndex != null ) {
int topOffset = NumberFormatUtil.parseInt( topItemIndex );
getGridAdapter( grid ).invalidateTopIndex();
processScrollBarSelection( grid.getVerticalBar(), topOffset );
}
}
////////////////
// Cell tooltips
private static void readCellToolTipTextRequested( Grid grid ) {
ICellToolTipAdapter adapter = CellToolTipUtil.getAdapter( grid );
adapter.setCellToolTipText( null );
String event = JSConst.EVENT_CELL_TOOLTIP_REQUESTED;
if( WidgetLCAUtil.wasEventSent( grid, event ) ) {
ICellToolTipProvider provider = adapter.getCellToolTipProvider();
if( provider != null ) {
HttpServletRequest request = ContextProvider.getRequest();
String cell = request.getParameter( JSConst.EVENT_CELL_TOOLTIP_DETAILS );
String[] details = cell.split( "," );
String itemId = details[ 0 ];
int columnIndex = NumberFormatUtil.parseInt( details[ 1 ] );
GridItem item = getItem( grid, itemId );
if( item != null && ( columnIndex >= 0 && columnIndex < grid.getColumnCount() ) ) {
provider.getToolTipText( item, columnIndex );
}
}
}
}
private static String getCellToolTipText( Grid grid ) {
return CellToolTipUtil.getAdapter( grid ).getCellToolTipText();
}
//////////////////
// Helping methods
private static 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 ] = WidgetUtil.getId( selection[ i ] );
}
return result;
}
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 boolean[] getScrollBarsVisible( Grid grid ) {
boolean horizontalBarVisible = false;
ScrollBar horizontalBar = grid.getHorizontalBar();
if( horizontalBar != null ) {
horizontalBarVisible = horizontalBar.getVisible();
}
boolean verticalBarVisible = false;
ScrollBar verticalBar = grid.getVerticalBar();
if( verticalBar != null ) {
verticalBarVisible = verticalBar.getVisible();
}
return new boolean[] { horizontalBarVisible, verticalBarVisible };
}
private static boolean hasScrollBarsSelectionListener( Grid grid ) {
boolean result = false;
ScrollBar horizontalBar = grid.getHorizontalBar();
if( horizontalBar != null ) {
result = result || SelectionEvent.hasListener( horizontalBar );
}
ScrollBar verticalBar = grid.getVerticalBar();
if( verticalBar != null ) {
result = result || SelectionEvent.hasListener( verticalBar );
}
return result;
}
private static GridItem getItem( Grid grid, String itemId ) {
return ( GridItem )WidgetUtil.find( grid, itemId );
}
private static void processScrollBarSelection( ScrollBar scrollBar, int selection ) {
if( scrollBar != null ) {
scrollBar.setSelection( selection );
if( SelectionEvent.hasListener( scrollBar ) ) {
int eventId = SelectionEvent.WIDGET_SELECTED;
SelectionEvent evt = new SelectionEvent( scrollBar, null, eventId );
evt.stateMask = EventLCAUtil.readStateMask( JSConst.EVENT_WIDGET_SELECTED_MODIFIER );
evt.processEvent();
}
}
}
private static void processSelectionEvent( Grid grid, String eventName ) {
if( WidgetLCAUtil.wasEventSent( grid, eventName ) ) {
HttpServletRequest request = ContextProvider.getRequest();
GridItem item = getItem( grid, request.getParameter( eventName + ".item" ) );
if( item != null ) {
if( eventName.equals( JSConst.EVENT_WIDGET_SELECTED ) ) {
String detail = request.getParameter( eventName + ".detail" );
if( "check".equals( detail ) ) {
String index = request.getParameter( eventName + ".index" );
item.fireCheckEvent( Integer.valueOf( index ).intValue() );
} else {
item.fireEvent( SWT.Selection );
}
} else {
item.fireEvent( SWT.DefaultSelection );
}
}
}
}
///////////////
// Item Metrics
private static void renderItemMetrics( Grid grid ) {
ItemMetrics[] itemMetrics = getItemMetrics( grid );
if( WidgetLCAUtil.hasChanged( grid, PROP_ITEM_METRICS, itemMetrics ) ) {
int[][] metrics = new int[ itemMetrics.length ][ 9 ];
for( int i = 0; i < itemMetrics.length; i++ ) {
metrics[ i ] = new int[] {
i,
itemMetrics[ i ].left,
itemMetrics[ i ].width,
itemMetrics[ i ].imageLeft,
itemMetrics[ i ].imageWidth,
itemMetrics[ i ].textLeft,
itemMetrics[ i ].textWidth,
itemMetrics[ i ].checkLeft,
itemMetrics[ i ].checkWidth
};
}
IClientObject clientObject = ClientObjectFactory.getClientObject( grid );
clientObject.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 );
}
}
}