// Created on 22.08.2009 package org.eclipse.swt.custom; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.*; class HeaderController { static final int DEFAULT_ROW_HEADER_WIDTH = 25; static final int DEFAULT_COLUMN_HEADER_HEIGHT = SpreadSheetModel.DEFAULT_ROW_HEIGHT; static final String ROW_HEADER_MARKER = SpreadSheetLayout.class.getName() + "#RowHeader"; static final String COLUMN_HEADER_MARKER = SpreadSheetLayout.class.getName() + "#ColumnHeader"; private static final String SASH = SpreadSheetLayout.class.getName() + "#Sash"; private static final int SASH_BREADTH = 5; private static final int SASH_OFFSET = 2; private final Color headerColor; private final Composite spreadSheet; private final SpreadSheetModel model; private Control[] rowHeaders; private Control[] columnHeaders; private Composite rowContainer; private Composite columnContainer; private int bufferedRowOffset; private int bufferedColumnOffset; public HeaderController( final Composite spreadSheet, final SpreadSheetModel model ) { SpreadSheetUtils.checkNotNull( spreadSheet, "spreadSheet" ); SpreadSheetUtils.checkNotNull( model, "model" ); this.spreadSheet = spreadSheet; this.model = model; this.bufferedRowOffset = model.getRowOffset(); this.bufferedColumnOffset = model.getColumnOffset(); this.rowHeaders = new Control[ 0 ]; this.columnHeaders = new Control[ 0 ]; rowContainer = new Composite( spreadSheet, SWT.NONE ); columnContainer = new Composite( spreadSheet, SWT.NONE ); Display display = Display.getDefault(); this.headerColor = display.getSystemColor( SWT.COLOR_WIDGET_LIGHT_SHADOW ); rowContainer.setBackground( display.getSystemColor( SWT.COLOR_RED ) ); columnContainer.setBackground( display.getSystemColor( SWT.COLOR_RED ) ); } void adjustHeaderControls() { adjustRowHeaderContainer(); adjustColumnHeaderContainer(); adjustRowHeaders(); adjustColumnHeaders(); } private void adjustRowHeaderContainer() { Rectangle clientArea = spreadSheet.getClientArea(); int xPos = clientArea.x - DEFAULT_ROW_HEADER_WIDTH; int rowOffset = model.getRowOffset(); int yOffset = 0; for( int i = 0; i < rowOffset; i++ ) { yOffset += model.getRowHeight( i ); } int yPos = clientArea.y - yOffset; int width = DEFAULT_ROW_HEADER_WIDTH - CellController.DEFAULT_GRID_LINE_BREADTH; int height = clientArea.height + yOffset; rowContainer.setBounds( xPos, yPos, width, height ); } private void adjustColumnHeaderContainer() { Rectangle clientArea = spreadSheet.getClientArea(); int columnOffset = model.getColumnOffset(); int xOffset = 0; for( int i = 0; i < columnOffset; i++ ) { xOffset += model.getColumnWidth( i ); } int xPos = clientArea.x - xOffset; int yPos = clientArea.y - DEFAULT_COLUMN_HEADER_HEIGHT; int width = clientArea.width + xOffset; int height = DEFAULT_COLUMN_HEADER_HEIGHT - CellController.DEFAULT_GRID_LINE_BREADTH; columnContainer.setBounds( xPos, yPos, width, height ); } private void adjustColumnHeaders() { adjustColumnHeaderNumber(); adjustColumnHeaderBounds(); } private void adjustRowHeaders() { adjustRowHeaderNumber(); adjustRowHeaderBounds(); } private void adjustRowHeaderBounds() { int yBase = 0; int lowerBound = 0; for( int i = 0; i < rowHeaders.length; i++ ) { int row = i + model.getRowOffset(); int xPos = 0; int yPos = SpreadSheetUtils.calcYPosition( yBase, lowerBound, row, model ); yBase = yPos; lowerBound = row; int width = getRowHeaderWidth() - CellController.DEFAULT_GRID_LINE_BREADTH; int height = model.getRowHeight( row ) - CellController.DEFAULT_GRID_LINE_BREADTH; rowHeaders[ i ].setBounds( xPos, yPos, width, height ); Sash sash = ( Sash )rowHeaders[ i ].getData( SASH ); sash.setBounds( 0, yPos + height - SASH_OFFSET, width, SASH_BREADTH ); } } private void adjustRowHeaderNumber() { final Rectangle clientArea = spreadSheet.getClientArea(); int rows = model.getVisibleRows(); Control[] newRowHeaders = new Control[ rows ]; int maxRow = Math.max( rows, rowHeaders.length ); for( int i = 0; i < maxRow; i++ ) { if( i < rowHeaders.length && i < newRowHeaders.length ) { newRowHeaders[ i ] = rowHeaders[ i ]; } else if( i < newRowHeaders.length ) { Label rowHeader = new Label( rowContainer, SWT.NONE ); rowHeader.setBackground( headerColor ); rowHeader.setData( ROW_HEADER_MARKER, String.valueOf( i ) ); newRowHeaders[ i ] = rowHeader; Sash sash = new Sash( rowContainer, SWT.HORIZONTAL ); rowHeader.setData( SASH, sash ); final int rowIndex = i; sash.addSelectionListener( new SelectionAdapter() { public void widgetSelected( final SelectionEvent evt ) { int yOffset = clientArea.y - DEFAULT_COLUMN_HEADER_HEIGHT; int yPos = SpreadSheetUtils.calcYPosition( yOffset, 0, rowIndex, model ); int newRowHeight = Math.max( 0, evt.y - yPos + SASH_OFFSET + 1 ); model.setRowHeight( rowIndex, newRowHeight ); }; } ); } else { Sash sash = ( Sash )rowHeaders[ i ].getData( SASH ); sash.dispose(); rowHeaders[ i ].dispose(); } } if( bufferedRowOffset != model.getRowOffset() ) { int offSetChange = bufferedRowOffset - model.getRowOffset(); newRowHeaders = reorderHeaders( offSetChange, newRowHeaders ); bufferedRowOffset = model.getRowOffset(); } rowHeaders = newRowHeaders; } private Control[] reorderHeaders( int offSetChange, Control[] headerControls ) { Control[] offSetHeaders = new Control[ headerControls.length ]; for( int i = 0; i < headerControls.length; i++ ) { int position = i + offSetChange; if( position < 0 ) { offSetHeaders[ headerControls.length + position ] = headerControls[ i ]; } else if ( position >= headerControls.length ) { offSetHeaders[ position - headerControls.length ] = headerControls[ i ]; } else { offSetHeaders[ position ] = headerControls[ i ]; } } return offSetHeaders; } private void adjustColumnHeaderBounds() { int xBase = 0; int lowerBound = 0; for( int i = 0; i < columnHeaders.length; i++ ) { int col = i + model.getColumnOffset(); int xPos = SpreadSheetUtils.calcXPosition( xBase, lowerBound, col, model ); xBase = xPos; lowerBound = col; int yPos = 0; int width = model.getColumnWidth( col ) - CellController.DEFAULT_GRID_LINE_BREADTH; int height = getColumnHeaderHeight() - CellController.DEFAULT_GRID_LINE_BREADTH; columnHeaders[ i ].setBounds( xPos, yPos, width, height ); Sash sash = ( Sash )columnHeaders[ i ].getData( SASH ); sash.setBounds( xPos + width - SASH_OFFSET, 0, SASH_BREADTH, height ); } } private void adjustColumnHeaderNumber() { final Rectangle clientArea = spreadSheet.getClientArea(); int columns = model.getVisibleColumns(); Control[] newColumnHeaders = new Control[ columns ]; int maxColumns = Math.max( columns, columnHeaders.length ); for( int i = 0; i < maxColumns; i++ ) { if( i < columnHeaders.length && i < newColumnHeaders.length ) { newColumnHeaders[ i ] = columnHeaders[ i ]; } else if( i < newColumnHeaders.length ) { Label columnHeader = new Label( columnContainer, SWT.NONE ); columnHeader.setBackground( headerColor ); columnHeader.setData( COLUMN_HEADER_MARKER, String.valueOf( i ) ); newColumnHeaders[ i ] = columnHeader; Sash sash = new Sash( columnContainer, SWT.VERTICAL ); columnHeader.setData( SASH, sash ); final int columnIndex = i; sash.addSelectionListener( new SelectionAdapter() { public void widgetSelected( final SelectionEvent evt ) { int xOffset = clientArea.x - DEFAULT_ROW_HEADER_WIDTH; int xPos = SpreadSheetUtils.calcXPosition( xOffset, 0, columnIndex, model ); int newColumnWidth = Math.max( 0, evt.x - xPos + SASH_OFFSET + 1 ); model.setColumnWidth( columnIndex, newColumnWidth ); }; } ); } else { Sash sash = ( Sash )columnHeaders[ i ].getData( SASH ); sash.dispose(); columnHeaders[ i ].dispose(); } } if( bufferedColumnOffset != model.getColumnOffset() ) { int offSetChange = bufferedColumnOffset - model.getColumnOffset(); newColumnHeaders = reorderHeaders( offSetChange, newColumnHeaders ); bufferedColumnOffset = model.getColumnOffset(); } columnHeaders = newColumnHeaders; } Composite getColumnContainer() { return columnContainer; } Control[] getColumnHeaderControls() { return columnHeaders; } Composite getRowContainer() { return rowContainer; } Control[] getRowHeaderControls() { return rowHeaders; } int getRowHeaderWidth() { return DEFAULT_ROW_HEADER_WIDTH; } int getColumnHeaderHeight() { return DEFAULT_COLUMN_HEADER_HEIGHT; } static boolean isRowHeaderControl( final Control control ) { return control.getData( ROW_HEADER_MARKER ) != null; } static boolean isColumnHeaderControl( final Control control ) { return control.getData( COLUMN_HEADER_MARKER ) != null; } }