| /******************************************************************************* |
| * Copyright (c) 2012, 2020 Original authors and others. |
| * |
| * This program and the accompanying materials are made |
| * available under the terms of the Eclipse Public License 2.0 |
| * which is available at https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Original authors and others - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.nebula.widgets.nattable.grid.layer; |
| |
| import org.eclipse.nebula.widgets.nattable.command.ILayerCommand; |
| import org.eclipse.nebula.widgets.nattable.export.command.ExportCommandHandler; |
| import org.eclipse.nebula.widgets.nattable.grid.GridRegion; |
| import org.eclipse.nebula.widgets.nattable.grid.command.AutoResizeColumnCommandHandler; |
| import org.eclipse.nebula.widgets.nattable.grid.command.AutoResizeRowCommandHandler; |
| import org.eclipse.nebula.widgets.nattable.grid.command.ClientAreaResizeCommand; |
| import org.eclipse.nebula.widgets.nattable.grid.layer.config.DefaultGridLayerConfiguration; |
| import org.eclipse.nebula.widgets.nattable.layer.CompositeLayer; |
| import org.eclipse.nebula.widgets.nattable.layer.ILayer; |
| import org.eclipse.nebula.widgets.nattable.print.command.PrintCommandHandler; |
| import org.eclipse.nebula.widgets.nattable.resize.command.AutoResizeColumnsCommand; |
| import org.eclipse.nebula.widgets.nattable.resize.command.AutoResizeRowsCommand; |
| import org.eclipse.nebula.widgets.nattable.selection.command.SelectCellCommand; |
| import org.eclipse.swt.graphics.Rectangle; |
| |
| /** |
| * Top level layer. It is composed of the smaller child layers: RowHeader, |
| * ColumnHeader, Corner and Body It does not have its own coordinate system |
| * unlike the other layers. It simply delegates most functions to its child |
| * layers. |
| */ |
| public class GridLayer extends CompositeLayer { |
| |
| public GridLayer( |
| ILayer bodyLayer, |
| ILayer columnHeaderLayer, |
| ILayer rowHeaderLayer, |
| ILayer cornerLayer) { |
| this(bodyLayer, columnHeaderLayer, rowHeaderLayer, cornerLayer, true); |
| } |
| |
| public GridLayer( |
| ILayer bodyLayer, |
| ILayer columnHeaderLayer, |
| ILayer rowHeaderLayer, |
| ILayer cornerLayer, |
| boolean useDefaultConfiguration) { |
| super(2, 2); |
| |
| setBodyLayer(bodyLayer); |
| setColumnHeaderLayer(columnHeaderLayer); |
| setRowHeaderLayer(rowHeaderLayer); |
| setCornerLayer(cornerLayer); |
| |
| init(useDefaultConfiguration); |
| } |
| |
| protected GridLayer(boolean useDefaultConfiguration) { |
| super(2, 2); |
| init(useDefaultConfiguration); |
| } |
| |
| protected void init(boolean useDefaultConfiguration) { |
| registerCommandHandlers(); |
| |
| if (useDefaultConfiguration) { |
| addConfiguration(new DefaultGridLayerConfiguration(this)); |
| } |
| } |
| |
| @Override |
| protected void registerCommandHandlers() { |
| registerCommandHandler(new PrintCommandHandler(this)); |
| registerCommandHandler(new ExportCommandHandler(this)); |
| registerCommandHandler(new AutoResizeColumnCommandHandler(this)); |
| registerCommandHandler(new AutoResizeRowCommandHandler(this)); |
| } |
| |
| /** |
| * How the GridLayer processes commands is very important. <strong>Do not |
| * change this unless you know what you are doing and understand the full |
| * ramifications of your change. Otherwise your grid will not behave |
| * correctly!</strong> |
| * |
| * The Body is always given the first chance to process a command. There are |
| * two reasons for this: (1) most commands (80%) are destined for the body |
| * anyways so it's faster to check there first (2) the other layers all |
| * transitively depend on the body so it's not wise to ask them to do stuff |
| * until after the body has done it. This is especially true of grid |
| * initialization where the body must be initialized before any of its |
| * dependent layers. |
| * |
| * Because of this, if you want to intercept well-known commands to |
| * implement custom behavior (for example, you want to intercept the |
| * {@link SelectCellCommand}) then <strong>you must inject your special |
| * layer into the body. </strong> An injected column or row header will |
| * never see the command because it will be consumed first by the body. In |
| * practice, it's a good idea to implement all your command-handling logic |
| * in the body. |
| **/ |
| @Override |
| protected boolean doCommandOnChildLayers(ILayerCommand command) { |
| if (doCommandOnChildLayer(command, getBodyLayer())) { |
| return true; |
| } else if (doCommandOnChildLayer(command, getColumnHeaderLayer())) { |
| return true; |
| } else if (doCommandOnChildLayer(command, getRowHeaderLayer())) { |
| return true; |
| } else { |
| return doCommandOnChildLayer(command, getCornerLayer()); |
| } |
| } |
| |
| private boolean doCommandOnChildLayer(ILayerCommand command, ILayer childLayer) { |
| ILayerCommand childCommand = command.cloneCommand(); |
| return childLayer.doCommand(childCommand); |
| } |
| |
| // Sub-layer accessors |
| |
| public ILayer getCornerLayer() { |
| return getChildLayerByLayoutCoordinate(0, 0); |
| } |
| |
| public void setCornerLayer(ILayer cornerLayer) { |
| setChildLayer(GridRegion.CORNER, cornerLayer, 0, 0); |
| } |
| |
| public ILayer getColumnHeaderLayer() { |
| return getChildLayerByLayoutCoordinate(1, 0); |
| } |
| |
| public void setColumnHeaderLayer(ILayer columnHeaderLayer) { |
| setChildLayer(GridRegion.COLUMN_HEADER, columnHeaderLayer, 1, 0); |
| } |
| |
| public ILayer getRowHeaderLayer() { |
| return getChildLayerByLayoutCoordinate(0, 1); |
| } |
| |
| public void setRowHeaderLayer(ILayer rowHeaderLayer) { |
| setChildLayer(GridRegion.ROW_HEADER, rowHeaderLayer, 0, 1); |
| } |
| |
| public ILayer getBodyLayer() { |
| return getChildLayerByLayoutCoordinate(1, 1); |
| } |
| |
| public void setBodyLayer(ILayer bodyLayer) { |
| setChildLayer(GridRegion.BODY, bodyLayer, 1, 1); |
| |
| // update the command handlers for auto resize because of the connection |
| // to the body layer stack |
| unregisterCommandHandler(AutoResizeColumnsCommand.class); |
| unregisterCommandHandler(AutoResizeRowsCommand.class); |
| |
| registerCommandHandler(new AutoResizeColumnCommandHandler(this)); |
| registerCommandHandler(new AutoResizeRowCommandHandler(this)); |
| } |
| |
| @Override |
| public String toString() { |
| return getClass().getSimpleName() + "[corner=" + getCornerLayer() //$NON-NLS-1$ |
| + " columnHeader=" + getColumnHeaderLayer() //$NON-NLS-1$ |
| + " rowHeader=" + getRowHeaderLayer() //$NON-NLS-1$ |
| + " bodyLayer=" + getBodyLayer() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| @Override |
| public boolean doCommand(ILayerCommand command) { |
| if (command instanceof ClientAreaResizeCommand |
| && command.convertToTargetLayer(this)) { |
| ClientAreaResizeCommand clientAreaResizeCommand = (ClientAreaResizeCommand) command; |
| Rectangle possibleArea = clientAreaResizeCommand.getScrollable() |
| .getClientArea(); |
| |
| // remove the column header height and the row header width from the |
| // client area to |
| // ensure that only the body region is used for percentage |
| // calculation |
| Rectangle rowLayerArea = getRowHeaderLayer() |
| .getClientAreaProvider().getClientArea(); |
| Rectangle columnLayerArea = getColumnHeaderLayer() |
| .getClientAreaProvider().getClientArea(); |
| possibleArea.width = possibleArea.width - rowLayerArea.width; |
| possibleArea.height = possibleArea.height - columnLayerArea.height; |
| |
| clientAreaResizeCommand.setCalcArea(possibleArea); |
| } |
| return super.doCommand(command); |
| } |
| |
| } |