/******************************************************************************* * Copyright (c) 2002, 2008 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 ******************************************************************************/ package org.eclipse.swt.internal.widgets.tablecolumnkit; import java.io.IOException; import java.util.Arrays; import org.eclipse.rwt.internal.lifecycle.JSConst; import org.eclipse.rwt.lifecycle.*; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.internal.widgets.ITableAdapter; import org.eclipse.swt.internal.widgets.ItemLCAUtil; import org.eclipse.swt.internal.widgets.tablekit.TableLCAUtil; import org.eclipse.swt.widgets.*; public final class TableColumnLCA extends AbstractWidgetLCA { // Property names to preserve values static final String PROP_LEFT = "left"; static final String PROP_WIDTH = "width"; static final String PROP_Z_INDEX = "zIndex"; static final String PROP_SORT_DIRECTION = "sortDirection"; static final String PROP_RESIZABLE = "resizable"; static final String PROP_MOVEABLE = "moveable"; private static final String PROP_SELECTION_LISTENERS = "selectionListeners"; private static final Integer DEFAULT_LEFT = new Integer( 0 ); private static final JSListenerInfo SELECTION_LISTENER = new JSListenerInfo( "click", "this.onClick", JSListenerType.ACTION ); public void preserveValues( final Widget widget ) { TableColumn column = ( TableColumn )widget; ItemLCAUtil.preserve( column ); IWidgetAdapter adapter = WidgetUtil.getAdapter( column ); WidgetLCAUtil.preserveToolTipText( column, column.getToolTipText() ); TableLCAUtil.preserveAlignment( column ); adapter.preserve( PROP_Z_INDEX, new Integer( getZIndex( column ) ) ); adapter.preserve( PROP_LEFT, new Integer( getLeft( column ) ) ); adapter.preserve( PROP_WIDTH, new Integer( column.getWidth() ) ); adapter.preserve( PROP_SORT_DIRECTION, getSortDirection( column ) ); adapter.preserve( PROP_RESIZABLE, Boolean.valueOf( column.getResizable() ) ); adapter.preserve( PROP_MOVEABLE, Boolean.valueOf( column.getMoveable() ) ); adapter.preserve( PROP_SELECTION_LISTENERS, Boolean.valueOf( SelectionEvent.hasListener( column ) ) ); WidgetLCAUtil.preserveCustomVariant( column ); } public void readData( final Widget widget ) { final TableColumn column = ( TableColumn )widget; // Though there is sent an event parameter called // org.eclipse.swt.events.controlResized // we will ignore it since setting the new width itself fires the // desired controlResized-event String value = WidgetLCAUtil.readPropertyValue( column, "width" ); if( value != null ) { // TODO [rh] HACK: force width to have changed when client-side changes // it. Since this is done while a column resize we must re-layout // all columns including the resized one. final int newWidth = Integer.parseInt( value ); ProcessActionRunner.add( new Runnable() { public void run() { column.setWidth( newWidth ); } } ); } // Though there is an org.eclipse.swt.events.controlMoved event sent, // we will ignore it since changing the column order fires the desired // controlMoved event value = WidgetLCAUtil.readPropertyValue( column, "left" ); if( value != null ) { final int newLeft = Integer.parseInt( value ); ProcessActionRunner.add( new Runnable() { public void run() { moveColumn( column, newLeft ); } } ); } ControlLCAUtil.processSelection( column, null, false ); } public void renderInitialization( final Widget widget ) throws IOException { TableColumn column = ( TableColumn )widget; JSWriter writer = JSWriter.getWriterFor( column ); Object[] args = new Object[] { column.getParent() }; writer.newWidget( "org.eclipse.swt.widgets.TableColumn", args ); } public void renderChanges( final Widget widget ) throws IOException { TableColumn column = ( TableColumn )widget; ItemLCAUtil.writeChanges( column ); writeLeft( column ); writeWidth( column ); writeZIndex( column ); WidgetLCAUtil.writeToolTip( column, column.getToolTipText() ); writeSortDirection( column ); writeResizable( column ); writeMoveable( column ); writeAlignment( column ); writeSelectionListener( column ); WidgetLCAUtil.writeCustomVariant( column ); } public void renderDispose( final Widget widget ) throws IOException { TableColumn column = ( TableColumn )widget; JSWriter writer = JSWriter.getWriterFor( column ); writer.dispose(); } ////////////////////////////////////////// // Helping method to write JavaScript code private static void writeLeft( final TableColumn column ) throws IOException { JSWriter writer = JSWriter.getWriterFor( column ); Integer newValue = new Integer( getLeft( column ) ); writer.set( PROP_LEFT, "left", newValue, DEFAULT_LEFT ); } private static void writeWidth( final TableColumn column ) throws IOException { JSWriter writer = JSWriter.getWriterFor( column ); Integer newValue = new Integer( column.getWidth() ); writer.set( PROP_WIDTH, "width", newValue, null ); } // TODO [rh] writing Z-Index seems unnecessary since it is relative to the // parent and thus could be hard-coded client-side private static void writeZIndex( final TableColumn column ) throws IOException { JSWriter writer = JSWriter.getWriterFor( column ); Integer newValue = new Integer( getZIndex( column ) ); writer.set( PROP_Z_INDEX, "zIndex", newValue, null ); } private static void writeSortDirection( final TableColumn column ) throws IOException { JSWriter writer = JSWriter.getWriterFor( column ); String newValue = getSortDirection( column ); writer.set( PROP_SORT_DIRECTION, "sortDirection", newValue, null ); } private static void writeResizable( final TableColumn column ) throws IOException { JSWriter writer = JSWriter.getWriterFor( column ); Boolean newValue = Boolean.valueOf( column.getResizable() ); writer.set( PROP_RESIZABLE, "resizable", newValue, Boolean.TRUE ); } private static void writeMoveable( final TableColumn column ) throws IOException { JSWriter writer = JSWriter.getWriterFor( column ); Boolean newValue = Boolean.valueOf( column.getMoveable() ); writer.set( PROP_MOVEABLE, "moveable", newValue, Boolean.FALSE ); } private static void writeAlignment( final TableColumn column ) throws IOException { JSWriter writer = JSWriter.getWriterFor( column ); if( TableLCAUtil.hasAlignmentChanged( column ) ) { Integer newValue = new Integer( column.getAlignment() ); JSVar alignment = JSConst.QX_CONST_ALIGN_LEFT; if( newValue.intValue() == SWT.CENTER ) { alignment = JSConst.QX_CONST_ALIGN_CENTER; } else if( newValue.intValue() == SWT.RIGHT ) { alignment = JSConst.QX_CONST_ALIGN_RIGHT; } writer.set( "horizontalChildrenAlign", new Object[] { alignment } ); } } // TODO [rh] selection event is also fired when resizing columns! private static void writeSelectionListener( final TableColumn column ) throws IOException { // TODO [rh] dispose of selection listener when widget is disposed of JSWriter writer = JSWriter.getWriterFor( column ); writer.updateListener( SELECTION_LISTENER, PROP_SELECTION_LISTENERS, SelectionEvent.hasListener( column ) ); } ////////////////////////////////////////////////// // Helping methods to obtain calculated properties static int getLeft( final TableColumn column ) { Object adapter = column.getParent().getAdapter( ITableAdapter.class ); ITableAdapter tableAdapter = ( ITableAdapter )adapter; return tableAdapter.getColumnLeft( column ); } static int getZIndex( final TableColumn column ) { return ControlLCAUtil.getZIndex( column.getParent() ) + 1; } static String getSortDirection( final TableColumn column ) { String result = null; Table table = column.getParent(); if( table.getSortColumn() == column ) { if( table.getSortDirection() == SWT.UP ) { result = "up"; } else if( table.getSortDirection() == SWT.DOWN ) { result = "down"; } } return result; } ///////////////////////////////// // Helping methods to move column static void moveColumn( final TableColumn column, final int newLeft ) { Table table = column.getParent(); int targetColumn = findMoveTarget( table, newLeft ); int[] columnOrder = table.getColumnOrder(); int index = table.indexOf( column ); int orderIndex = arrayIndexOf( columnOrder, index ); columnOrder = arrayRemove( columnOrder, orderIndex ); if( orderIndex < targetColumn ) { targetColumn--; } columnOrder = arrayInsert( columnOrder, targetColumn, index ); if( Arrays.equals( columnOrder, table.getColumnOrder() ) ) { // TODO [rh] HACK mark left as changed TableColumn[] columns = table.getColumns(); for( int i = 0; i < columns.length; i++ ) { IWidgetAdapter adapter = WidgetUtil.getAdapter( columns[ i ] ); adapter.preserve( PROP_LEFT, null ); } } else { table.setColumnOrder( columnOrder ); } } /* (intentionally non-JavaDoc'ed) * Returns the index in the columnOrder array at which the moved column * should be inserted (moving remaining columns to the right). A return * value of columnCount indicates that the moved column should be inserted * after the right-most column. */ private static int findMoveTarget( final Table table, final int newLeft ) { int result = -1; TableColumn[] columns = table.getColumns(); int[] columnOrder = table.getColumnOrder(); if( newLeft < 0 ) { result = 0; } else { for( int i = 0; result == -1 && i < columns.length; i++ ) { int left = getLeft( columns[ columnOrder [ i ] ] ); int width = columns[ columnOrder [ i ] ].getWidth(); if( newLeft >= left && newLeft <= left + width ) { result = i; if( newLeft >= left + width / 2 && result < columns.length ) { result++; } } } } // Column was moved right of the right-most column if( result == -1 ) { result = columns.length; } return result; } private static int arrayIndexOf( final int[] array, final int value ) { int result = -1; for( int i = 0; result == -1 && i < array.length; i++ ) { if( array[ i ] == value ) { result = i; } } return result; } private static int[] arrayRemove( final int[] array, final int index ) { int length = array.length; int[] result = new int[ length - 1 ]; System.arraycopy( array, 0, result, 0, index ); if( index < length - 1 ) { System.arraycopy( array, index + 1, result, index, length - index - 1 ); } return result; } private static int[] arrayInsert( final int[] array, final int index, final int value ) { int length = array.length; int[] result = new int[ length + 1 ]; System.arraycopy( array, 0, result, 0, length ); System.arraycopy( result, index, result, index + 1, length - index ); result[ index ] = value; return result; } }