/******************************************************************************* * Copyright (c) 2002, 2009 Innoopract Informationssysteme GmbH. * 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 java.io.IOException; import javax.servlet.http.HttpServletRequest; import org.eclipse.rwt.internal.lifecycle.JSConst; import org.eclipse.rwt.internal.service.ContextProvider; import org.eclipse.rwt.lifecycle.*; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.internal.events.EventLCAUtil; import org.eclipse.swt.internal.widgets.ITableAdapter; import org.eclipse.swt.internal.widgets.ICellToolTipProvider; import org.eclipse.swt.widgets.*; public final class TableLCA extends AbstractWidgetLCA { // Request cell tooltip text event static final String EVENT_CELL_TOOLTIP_TEXT_REQUESTED = "org.eclipse.swt.events.cellToolTipTextRequested"; // Parameter names that specify further event details static final String EVENT_CELL_TOOLTIP_TEXT_REQUESTED_CELL = "org.eclipse.swt.events.cellToolTipTextRequested.cell"; // Property names to preserve values static final String PROP_HEADER_HEIGHT = "headerHeight"; static final String PROP_HEADER_VISIBLE = "headerVisible"; static final String PROP_LINES_VISIBLE = "linesVisible"; static final String PROP_ITEM_HEIGHT = "itemHeight"; static final String PROP_TOP_INDEX = "topIndex"; static final String PROP_SELECTION_LISTENERS = "selectionListeners"; static final String PROP_DEFAULT_COLUMN_WIDTH = "defaultColumnWidth"; static final String PROP_ITEM_COUNT = "itemCount"; static final String PROP_HIDE_SELECTION = "hideSelection"; static final String PROP_HAS_H_SCROLL_BAR = "hasHScrollBar"; static final String PROP_HAS_V_SCROLL_BAR = "hasVScrollBar"; static final String PROP_LEFT_OFFSET = "leftOffset"; static final String PROP_SCROLLBARS_SELECTION_LISTENER = "scrollBarsSelectionListeners"; private static final Integer DEFAULT_TOP_INDEX = new Integer( 0 ); private static final Integer DEFAULT_ITEM_COUNT = new Integer( 0 ); private static final Integer DEFAUT_ITEM_HEIGHT = new Integer( 0 ); private static final Integer DEFAULT_COLUMN_WIDTH = new Integer( 0 ); private static final Integer DEFAULT_LEFT_OFFSET = new Integer( 0 ); private static final JSListenerInfo SELECTION_LISTENER = new JSListenerInfo( "itemselected", "this.onItemSelected", JSListenerType.ACTION ); private static final JSListenerInfo DEFAULT_SELECTION_LISTENER = new JSListenerInfo( "itemdefaultselected", "this.onItemDefaultSelected", JSListenerType.ACTION ); private static final JSListenerInfo CHECK_SELECTION_LISTENER = new JSListenerInfo( "itemchecked", "this.onItemChecked", JSListenerType.ACTION ); public void preserveValues( final Widget widget ) { Table table = ( Table )widget; ControlLCAUtil.preserveValues( table ); IWidgetAdapter adapter = WidgetUtil.getAdapter( table ); adapter.preserve( PROP_HEADER_HEIGHT, new Integer( table.getHeaderHeight() ) ); adapter.preserve( PROP_HEADER_VISIBLE, Boolean.valueOf( table.getHeaderVisible() ) ); adapter.preserve( PROP_LINES_VISIBLE, Boolean.valueOf( table.getLinesVisible() ) ); adapter.preserve( PROP_ITEM_HEIGHT, new Integer( table.getItemHeight() ) ); TableLCAUtil.preserveItemMetrics( table ); adapter.preserve( PROP_ITEM_COUNT, new Integer( table.getItemCount() ) ); adapter.preserve( PROP_TOP_INDEX, new Integer( table.getTopIndex() ) ); adapter.preserve( PROP_SELECTION_LISTENERS, Boolean.valueOf( SelectionEvent.hasListener( table ) ) ); adapter.preserve( PROP_DEFAULT_COLUMN_WIDTH, new Integer( getDefaultColumnWidth( table ) ) ); TableLCAUtil.preserveFocusIndex( table ); WidgetLCAUtil.preserveCustomVariant( table ); adapter.preserve( PROP_HIDE_SELECTION, hideSelection( table ) ); adapter.preserve( PROP_HAS_H_SCROLL_BAR, hasHScrollBar( table ) ); adapter.preserve( PROP_HAS_V_SCROLL_BAR, hasVScrollBar( table ) ); adapter.preserve( PROP_LEFT_OFFSET, getLeftOffset( table ) ); adapter.preserve( PROP_SCROLLBARS_SELECTION_LISTENER, hasScrollBarsSelectionListener( table ) ); } public void readData( final Widget widget ) { Table table = ( Table )widget; readTopIndex( table ); // topIndex MUST be read *before* processSetData readLeftOffset( table ); readSelection( table ); readFocusIndex( table ); // must be called *after* readSelection readSetData( table ); readWidgetSelected( table ); readWidgetDefaultSelected( table ); readCellToolTipTextRequested( table ); ControlLCAUtil.processMouseEvents( table ); ControlLCAUtil.processKeyEvents( table ); ControlLCAUtil.processMenuDetect( table ); } public void renderInitialization( final Widget widget ) throws IOException { final Table table = ( Table )widget; JSWriter writer = JSWriter.getWriterFor( table ); String style = ""; if( ( table.getStyle() & SWT.CHECK ) != 0 ) { style = "check"; } if( ( table.getStyle() & SWT.MULTI ) != 0 ) { style += "|multi"; } if( Boolean.TRUE.equals( table.getData( Table.ENABLE_CELL_TOOLTIP ) ) ) { style += "|enableCellToolTip"; } Object[] args = new Object[] { WidgetUtil.getId( table ), style }; writer.newWidget( "org.eclipse.swt.widgets.Table", args ); ControlLCAUtil.writeStyleFlags( table ); writer.set( "borderWidth", table.getBorderWidth() ); } public void renderChanges( final Widget widget ) throws IOException { Table table = ( Table )widget; ControlLCAUtil.writeChanges( table ); writeHeaderHeight( table ); writeHeaderVisible( table ); writeItemHeight( table ); TableLCAUtil.writeItemMetrics( table ); writeItemCount( table ); writeTopIndex( table ); writeFocusIndex( table ); writeLinesVisible( table ); writeSelectionListener( table ); writeScrollBarsSelectionListener( table ); writeDefaultColumnWidth( table ); writeHideSelection( table ); writeScrollBarsVisible( table ); writeLeftOffset( table ); writeCellToolTipText( table ); WidgetLCAUtil.writeCustomVariant( table ); } public void renderDispose( final Widget widget ) throws IOException { JSWriter writer = JSWriter.getWriterFor( widget ); writer.dispose(); } public void doRedrawFake( final Control control ) { Table table = ( Table )control; Object adapter = table.getAdapter( ITableAdapter.class ); ITableAdapter tableAdapter = ( ITableAdapter )adapter; tableAdapter.checkData(); } //////////////////////////////////////////////////// // Helping methods to read client-side state changes private static void readSelection( final Table table ) { String value = WidgetLCAUtil.readPropertyValue( table, "selection" ); if( value != null ) { int[] newSelection; if( "".equals( value ) ) { newSelection = new int[ 0 ]; } else { String[] selectedIndices = value.split( "," ); newSelection = new int[ selectedIndices.length ]; for( int i = 0; i < selectedIndices.length; i++ ) { newSelection[ i ] = Integer.parseInt( selectedIndices[ i ] ); } } table.deselectAll(); table.select( newSelection ); } } private static void readTopIndex( final Table table ) { String value = WidgetLCAUtil.readPropertyValue( table, "topIndex" ); if( value != null ) { int topIndex = Integer.parseInt( value ); int topOffset = topIndex * table.getItemHeight(); table.setTopIndex( topIndex ); processScrollBarSelection( table.getVerticalBar(), topOffset ); } } private static void readFocusIndex( final Table table ) { String value = WidgetLCAUtil.readPropertyValue( table, "focusIndex" ); if( value != null ) { ITableAdapter adapter = ( ITableAdapter )table.getAdapter( ITableAdapter.class ); adapter.setFocusIndex( Integer.parseInt( value ) ); } } private static void readLeftOffset( final Table table ) { String value = WidgetLCAUtil.readPropertyValue( table, "leftOffset" ); if( value != null ) { int leftOffset = Integer.parseInt( value ); Object adapter = table.getAdapter( ITableAdapter.class ); ITableAdapter tableAdapter = ( ITableAdapter )adapter; tableAdapter.setLeftOffset( leftOffset ); processScrollBarSelection( table.getHorizontalBar(), leftOffset ); } } private static void readSetData( final Table table ) { if( WidgetLCAUtil.wasEventSent( table, JSConst.EVENT_SET_DATA ) ) { HttpServletRequest request = ContextProvider.getRequest(); String value = request.getParameter( JSConst.EVENT_SET_DATA_INDEX ); String[] indices = value.split( "," ); Object adapter = table.getAdapter( ITableAdapter.class ); ITableAdapter tableAdapter = ( ITableAdapter )adapter; for( int i = 0; i < indices.length; i++ ) { int index = Integer.parseInt( indices[ i ] ); if( index > -1 && index < table.getItemCount() ) { tableAdapter.checkData( index ); } } } } private static void readWidgetSelected( final Table table ) { if( WidgetLCAUtil.wasEventSent( table, JSConst.EVENT_WIDGET_SELECTED ) ) { // TODO [rh] do something reasonable when index points to unresolved item int index = getWidgetSelectedIndex(); // Bugfix: check if index is valid before firing event to avoid problems // with fast scrolling if( index > -1 && index < table.getItemCount() ) { TableItem item = table.getItem( index ); int detail = getWidgetSelectedDetail(); int id = SelectionEvent.WIDGET_SELECTED; Rectangle bounds = new Rectangle( 0, 0, 0, 0 ); int stateMask = EventLCAUtil.readStateMask( JSConst.EVENT_WIDGET_SELECTED_MODIFIER ); SelectionEvent event = new SelectionEvent( table, item, id, bounds, stateMask, "", true, detail ); event.processEvent(); } } } private static void readWidgetDefaultSelected( final Table table ) { String defaultSelectedParam = JSConst.EVENT_WIDGET_DEFAULT_SELECTED; if( WidgetLCAUtil.wasEventSent( table, defaultSelectedParam ) ) { // A default-selected event can occur without a selection being present. // In this case the event.item field points to the focused item TableItem item = getFocusedItem( table ); int selectedIndex = getWidgetSelectedIndex(); if( selectedIndex != -1 ) { // TODO [rh] do something about when index points to unresolved item! item = table.getItem( selectedIndex ); } int id = SelectionEvent.WIDGET_DEFAULT_SELECTED; SelectionEvent event = new SelectionEvent( table, item, id ); event.stateMask = EventLCAUtil.readStateMask( JSConst.EVENT_WIDGET_SELECTED_MODIFIER ); event.processEvent(); } } private static int getWidgetSelectedDetail() { HttpServletRequest request = ContextProvider.getRequest(); String value = request.getParameter( JSConst.EVENT_WIDGET_SELECTED_DETAIL ); return "check".equals( value ) ? SWT.CHECK : SWT.NONE; } private static int getWidgetSelectedIndex() { HttpServletRequest request = ContextProvider.getRequest(); String value = request.getParameter( JSConst.EVENT_WIDGET_SELECTED_INDEX ); return Integer.parseInt( value ); } private static TableItem getFocusedItem( final Table table ) { TableItem result = null; ITableAdapter tableAdapter = ( ITableAdapter )table.getAdapter( ITableAdapter.class ); int focusIndex = tableAdapter.getFocusIndex(); if( focusIndex != -1 ) { // TODO [rh] do something about when index points to unresolved item! result = table.getItem( focusIndex ); } return result; } private static void readCellToolTipTextRequested( final Table table ) { Object adapter = table.getAdapter( ITableAdapter.class ); ITableAdapter tableAdapter = ( ITableAdapter )adapter; tableAdapter.setToolTipText( null ); String event = EVENT_CELL_TOOLTIP_TEXT_REQUESTED; if( WidgetLCAUtil.wasEventSent( table, event ) ) { HttpServletRequest request = ContextProvider.getRequest(); String cell = request.getParameter( EVENT_CELL_TOOLTIP_TEXT_REQUESTED_CELL ); String[] indices = cell.split( "," ); int itemIndex = Integer.parseInt( indices[ 0 ] ); int columnIndex = Integer.parseInt( indices[ 1 ] ); ICellToolTipProvider provider = tableAdapter.getCellToolTipProvider(); if( provider != null ) { provider.getToolTipText( itemIndex, columnIndex ); } } } /////////////////////////////////////////// // Helping methods to write JavaScript code private static void writeHeaderHeight( final Table table ) throws IOException { JSWriter writer = JSWriter.getWriterFor( table ); Integer newValue = new Integer( table.getHeaderHeight() ); writer.set( PROP_HEADER_HEIGHT, "headerHeight", newValue, null ); } private static void writeHeaderVisible( final Table table ) throws IOException { JSWriter writer = JSWriter.getWriterFor( table ); Boolean newValue = Boolean.valueOf( table.getHeaderVisible() ); writer.set( PROP_HEADER_VISIBLE, "headerVisible", newValue, null ); } private static void writeItemHeight( final Table table ) throws IOException { JSWriter writer = JSWriter.getWriterFor( table ); Integer newValue = new Integer( table.getItemHeight( ) ); writer.set( PROP_ITEM_HEIGHT, "itemHeight", newValue, DEFAUT_ITEM_HEIGHT ); } private static void writeItemCount( final Table table ) throws IOException { JSWriter writer = JSWriter.getWriterFor( table ); Integer newValue = new Integer( table.getItemCount() ); writer.set( PROP_ITEM_COUNT, "itemCount", newValue, DEFAULT_ITEM_COUNT ); } private static void writeTopIndex( final Table table ) throws IOException { // TODO [rh] investigate if we can optimize item updates by rendering // item.update()-JS-code from the server-side. e.g. compare // item.preservedIsVisible != item.currentIsVisible JSWriter writer = JSWriter.getWriterFor( table ); Integer newValue = new Integer( table.getTopIndex() ); writer.set( PROP_TOP_INDEX, "topIndex", newValue, DEFAULT_TOP_INDEX ); } private static void writeFocusIndex( final Table table ) throws IOException { if( TableLCAUtil.hasFocusIndexChanged( table ) ) { ITableAdapter adapter = ( ITableAdapter )table.getAdapter( ITableAdapter.class ); // TableItemLCA renders focusIndex in case != -1 if( adapter.getFocusIndex() == -1 ) { JSWriter writer = JSWriter.getWriterFor( table ); writer.set( "focusIndex", new Object[]{ new Integer( -1 ) } ); } } } private static void writeLinesVisible( final Table table ) throws IOException { JSWriter writer = JSWriter.getWriterFor( table ); Boolean newValue = Boolean.valueOf( table.getLinesVisible() ); writer.set( PROP_LINES_VISIBLE, "linesVisible", newValue, Boolean.FALSE ); } private static void writeSelectionListener( final Table table ) throws IOException { JSWriter writer = JSWriter.getWriterFor( table ); writer.updateListener( SELECTION_LISTENER, PROP_SELECTION_LISTENERS, SelectionEvent.hasListener( table ) ); writer.updateListener( DEFAULT_SELECTION_LISTENER, PROP_SELECTION_LISTENERS, SelectionEvent.hasListener( table ) ); if( ( table.getStyle() & SWT.CHECK ) != 0 ) { writer.updateListener( CHECK_SELECTION_LISTENER, PROP_SELECTION_LISTENERS, SelectionEvent.hasListener( table ) ); } } private static void writeScrollBarsSelectionListener( final Table table ) throws IOException { Boolean newValue = hasScrollBarsSelectionListener( table ); String prop = PROP_SCROLLBARS_SELECTION_LISTENER; if( WidgetLCAUtil.hasChanged( table, prop, newValue, Boolean.FALSE ) ) { JSWriter writer = JSWriter.getWriterFor( table ); writer.set( "hasScrollBarsSelectionListener", newValue ); } } private static void writeDefaultColumnWidth( final Table table ) throws IOException { JSWriter writer = JSWriter.getWriterFor( table ); String prop = PROP_DEFAULT_COLUMN_WIDTH; Integer newValue = new Integer( getDefaultColumnWidth( table ) ); Integer defValue = DEFAULT_COLUMN_WIDTH; writer.set( prop, "defaultColumnWidth", newValue, defValue ); } private void writeHideSelection( final Table table ) throws IOException { JSWriter writer = JSWriter.getWriterFor( table ); Boolean newValue = hideSelection( table ); Boolean defValue = Boolean.FALSE; writer.set( PROP_HIDE_SELECTION, "hideSelection", newValue, defValue ); } private void writeScrollBarsVisible( final Table table ) throws IOException { boolean hasHChanged = WidgetLCAUtil.hasChanged( table, PROP_HAS_H_SCROLL_BAR, hasHScrollBar( table ), Boolean.TRUE ); boolean hasVChanged = WidgetLCAUtil.hasChanged( table, PROP_HAS_V_SCROLL_BAR, hasVScrollBar( table ), Boolean.TRUE ); if( hasHChanged || hasVChanged ) { JSWriter writer = JSWriter.getWriterFor( table ); Object[] args = new Object[]{ hasHScrollBar( table ), hasVScrollBar( table ) }; writer.call( "setScrollBarsVisibile", args ); } } private void writeLeftOffset( final Table table ) throws IOException { JSWriter writer = JSWriter.getWriterFor( table ); Integer newValue = getLeftOffset( table ); writer.set( PROP_LEFT_OFFSET, "leftOffset", newValue, DEFAULT_LEFT_OFFSET ); } private void writeCellToolTipText( final Table table ) throws IOException { Object adapter = table.getAdapter( ITableAdapter.class ); ITableAdapter tableAdapter = ( ITableAdapter )adapter; String text = tableAdapter.getToolTipText(); if( text != null ) { JSWriter writer = JSWriter.getWriterFor( table ); text = WidgetLCAUtil.escapeText( text, false ); text = WidgetLCAUtil.replaceNewLines( text, "<br>" ); writer.call( "setCellToolTipText", new String[]{ text } ); } } ////////////////// // Helping methods private Boolean hasHScrollBar( final Table table ) { Object adapter = table.getAdapter( ITableAdapter.class ); ITableAdapter tableAdapter = ( ITableAdapter )adapter; return Boolean.valueOf( tableAdapter.hasHScrollBar() ); } private Boolean hasVScrollBar( final Table table ) { Object adapter = table.getAdapter( ITableAdapter.class ); ITableAdapter tableAdapter = ( ITableAdapter )adapter; return Boolean.valueOf( tableAdapter.hasVScrollBar() ); } private Integer getLeftOffset( final Table table ) { Object adapter = table.getAdapter( ITableAdapter.class ); ITableAdapter tableAdapter = ( ITableAdapter )adapter; return new Integer( tableAdapter.getLeftOffset() ); } private static Boolean hasScrollBarsSelectionListener( final Table table ) { boolean result = false; ScrollBar horizontalBar = table.getHorizontalBar(); if( horizontalBar != null ) { result = result || SelectionEvent.hasListener( horizontalBar ); } ScrollBar verticalBar = table.getVerticalBar(); if( verticalBar != null ) { result = result || SelectionEvent.hasListener( verticalBar ); } return Boolean.valueOf( result ); } private static void processScrollBarSelection( final ScrollBar scrollBar, final 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(); } } } static int getDefaultColumnWidth( final Table table ) { int result = 0; if( table.getColumnCount() == 0 ) { Object adapter = table.getAdapter( ITableAdapter.class ); ITableAdapter tableAdapter = ( ITableAdapter )adapter; result = tableAdapter.getDefaultColumnWidth(); } return result; } static Boolean hideSelection( final Table table ) { Boolean result = Boolean.FALSE; Object data = table.getData( Table.HIDE_SELECTION ); if( Boolean.TRUE.equals( data ) ) { result = Boolean.TRUE; } return result; } }