/*******************************************************************************
* Copyright (c) 2012, 2016 Original authors 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:
* Original authors and others - initial API and implementation
******************************************************************************/
package org.eclipse.nebula.widgets.nattable.grid.layer;
import java.util.Collection;
import java.util.HashSet;
import java.util.Properties;
import org.eclipse.nebula.widgets.nattable.command.AbstractRegionCommand;
import org.eclipse.nebula.widgets.nattable.command.ILayerCommand;
import org.eclipse.nebula.widgets.nattable.config.ConfigRegistry;
import org.eclipse.nebula.widgets.nattable.coordinate.Range;
import org.eclipse.nebula.widgets.nattable.layer.AbstractLayer;
import org.eclipse.nebula.widgets.nattable.layer.ILayer;
import org.eclipse.nebula.widgets.nattable.layer.IUniqueIndexLayer;
import org.eclipse.nebula.widgets.nattable.layer.LabelStack;
import org.eclipse.nebula.widgets.nattable.layer.LayerUtil;
import org.eclipse.nebula.widgets.nattable.layer.cell.IConfigLabelAccumulator;
import org.eclipse.nebula.widgets.nattable.painter.layer.ILayerPainter;
import org.eclipse.nebula.widgets.nattable.ui.binding.UiBindingRegistry;
import org.eclipse.nebula.widgets.nattable.util.IClientAreaProvider;
/**
* <p>
* A DimensionallyDependentLayer is a layer whose horizontal and vertical
* dimensions are dependent on the horizontal and vertical dimensions of other
* layers. A DimensionallyDependentLayer takes three constructor parameters: the
* horizontal layer that the DimensionallyDependentLayer's horizontal dimension
* is linked to, the vertical layer that the DimensionallyDependentLayer is
* linked to, and a base layer to which all non-dimensionally related ILayer
* method calls will be delegated to (e.g. command, event methods)
* </p>
* <p>
* Prime examples of dimensionally dependent layers are the column header and
* row header layers. For example, the column header layer's horizontal
* dimension is linked to the body layer's horizontal dimension. This means that
* whatever columns are shown in the body area will also be shown in the column
* header area, and vice versa. Note that the column header layer maintains its
* own vertical dimension, however, so it's vertical layer dependency would be a
* separate data layer. The same is true for the row header layer, only with the
* vertical instead of the horizontal dimension. The constructors for the column
* header and row header layers would therefore look something like this:
* </p>
*
* <pre>
* ILayer columnHeaderLayer = new DimensionallyDependentLayer(
* columnHeaderRowDataLayer, bodyLayer, columnHeaderRowDataLayer);
* ILayer rowHeaderLayer = new DimensionallyDependentLayer(
* rowHeaderColumnDataLayer, bodyLayer, rowHeaderColumnDataLayer);
* </pre>
*/
public class DimensionallyDependentLayer extends AbstractLayer {
private final IUniqueIndexLayer baseLayer;
private ILayer horizontalLayerDependency;
private ILayer verticalLayerDependency;
private IClientAreaProvider clientAreaProvider;
protected DimensionallyDependentLayer(IUniqueIndexLayer baseLayer) {
this.baseLayer = baseLayer;
this.baseLayer.addLayerListener(this);
}
public DimensionallyDependentLayer(
IUniqueIndexLayer baseLayer, ILayer horizontalLayerDependency, ILayer verticalLayerDependency) {
this.baseLayer = baseLayer;
this.baseLayer.addLayerListener(this);
setHorizontalLayerDependency(horizontalLayerDependency);
setVerticalLayerDependency(verticalLayerDependency);
}
// Persistence
@Override
public void saveState(String prefix, Properties properties) {
super.saveState(prefix, properties);
this.baseLayer.saveState(prefix, properties);
}
@Override
public void loadState(String prefix, Properties properties) {
super.loadState(prefix, properties);
this.baseLayer.loadState(prefix, properties);
}
// Configuration
@Override
public void configure(ConfigRegistry configRegistry, UiBindingRegistry uiBindingRegistry) {
this.baseLayer.configure(configRegistry, uiBindingRegistry);
super.configure(configRegistry, uiBindingRegistry);
}
// Dependent layer accessors
public void setHorizontalLayerDependency(ILayer horizontalLayerDependency) {
this.horizontalLayerDependency = horizontalLayerDependency;
// this.horizontalLayerDependency.addLayerListener(new ILayerListener()
// {
//
// @Override
// public void handleLayerEvent(ILayerEvent event) {
// if (event instanceof IStructuralChangeEvent) {
// // TODO refresh horizontal structure
// }
// }
//
// });
}
public void setVerticalLayerDependency(ILayer verticalLayerDependency) {
this.verticalLayerDependency = verticalLayerDependency;
// this.verticalLayerDependency.addLayerListener(new ILayerListener() {
//
// @Override
// public void handleLayerEvent(ILayerEvent event) {
// if (event instanceof IStructuralChangeEvent) {
// // TODO refresh vertical structure
// }
// }
//
// });
}
public ILayer getHorizontalLayerDependency() {
return this.horizontalLayerDependency;
}
public ILayer getVerticalLayerDependency() {
return this.verticalLayerDependency;
}
public IUniqueIndexLayer getBaseLayer() {
return this.baseLayer;
}
// Commands
@Override
public boolean doCommand(ILayerCommand command) {
// Invoke command handler(s) on the Dimensionally dependent layer
ILayerCommand clonedCommand = command.cloneCommand();
if (super.doCommand(clonedCommand)) {
return true;
}
// in case we have a command for a specific region we need to ensure
// that no other regions are affected
if (!(command instanceof AbstractRegionCommand)) {
clonedCommand = command.cloneCommand();
if (this.horizontalLayerDependency.doCommand(clonedCommand)) {
return true;
}
clonedCommand = command.cloneCommand();
if (this.verticalLayerDependency.doCommand(clonedCommand)) {
return true;
}
}
return this.baseLayer.doCommand(command);
}
// Events
@Override
public ILayerPainter getLayerPainter() {
return (this.layerPainter != null) ? this.layerPainter : this.baseLayer.getLayerPainter();
}
// Horizontal features
// Columns
@Override
public int getColumnCount() {
return this.horizontalLayerDependency.getColumnCount();
}
@Override
public int getPreferredColumnCount() {
return this.horizontalLayerDependency.getPreferredColumnCount();
}
@Override
public int getColumnIndexByPosition(int columnPosition) {
return this.horizontalLayerDependency.getColumnIndexByPosition(columnPosition);
}
@Override
public int localToUnderlyingColumnPosition(int localColumnPosition) {
return this.horizontalLayerDependency.localToUnderlyingColumnPosition(localColumnPosition);
}
@Override
public int underlyingToLocalColumnPosition(ILayer sourceUnderlyingLayer, int underlyingColumnPosition) {
if (sourceUnderlyingLayer == this.horizontalLayerDependency) {
return underlyingColumnPosition;
}
return this.horizontalLayerDependency
.underlyingToLocalColumnPosition(sourceUnderlyingLayer, underlyingColumnPosition);
}
@Override
public Collection<Range> underlyingToLocalColumnPositions(
ILayer sourceUnderlyingLayer,
Collection<Range> underlyingColumnPositionRanges) {
if (sourceUnderlyingLayer == this.horizontalLayerDependency) {
return underlyingColumnPositionRanges;
}
return this.horizontalLayerDependency
.underlyingToLocalColumnPositions(sourceUnderlyingLayer, underlyingColumnPositionRanges);
}
// Width
@Override
public int getWidth() {
return this.horizontalLayerDependency.getWidth();
}
@Override
public int getPreferredWidth() {
return this.horizontalLayerDependency.getPreferredWidth();
}
@Override
public int getColumnWidthByPosition(int columnPosition) {
return this.horizontalLayerDependency.getColumnWidthByPosition(columnPosition);
}
// Column resize
@Override
public boolean isColumnPositionResizable(int columnPosition) {
return this.horizontalLayerDependency.isColumnPositionResizable(columnPosition);
}
// X
@Override
public int getColumnPositionByX(int x) {
return this.horizontalLayerDependency.getColumnPositionByX(x);
}
@Override
public int getStartXOfColumnPosition(int columnPosition) {
return this.horizontalLayerDependency.getStartXOfColumnPosition(columnPosition);
}
// Underlying
@Override
public Collection<ILayer> getUnderlyingLayersByColumnPosition(int columnPosition) {
Collection<ILayer> underlyingLayers = new HashSet<ILayer>();
underlyingLayers.add(this.baseLayer);
return underlyingLayers;
}
// Vertical features
// Rows
@Override
public int getRowCount() {
return this.verticalLayerDependency.getRowCount();
}
@Override
public int getPreferredRowCount() {
return this.verticalLayerDependency.getPreferredRowCount();
}
@Override
public int getRowIndexByPosition(int rowPosition) {
return this.verticalLayerDependency.getRowIndexByPosition(rowPosition);
}
@Override
public int localToUnderlyingRowPosition(int localRowPosition) {
return this.verticalLayerDependency.localToUnderlyingRowPosition(localRowPosition);
}
@Override
public int underlyingToLocalRowPosition(
ILayer sourceUnderlyingLayer, int underlyingRowPosition) {
if (sourceUnderlyingLayer == this.verticalLayerDependency) {
return underlyingRowPosition;
}
return this.verticalLayerDependency
.underlyingToLocalRowPosition(sourceUnderlyingLayer, underlyingRowPosition);
}
@Override
public Collection<Range> underlyingToLocalRowPositions(
ILayer sourceUnderlyingLayer, Collection<Range> underlyingRowPositionRanges) {
if (sourceUnderlyingLayer == this.verticalLayerDependency) {
return underlyingRowPositionRanges;
}
return this.verticalLayerDependency
.underlyingToLocalRowPositions(sourceUnderlyingLayer, underlyingRowPositionRanges);
}
// Height
@Override
public int getHeight() {
return this.verticalLayerDependency.getHeight();
}
@Override
public int getPreferredHeight() {
return this.verticalLayerDependency.getPreferredHeight();
}
@Override
public int getRowHeightByPosition(int rowPosition) {
return this.verticalLayerDependency.getRowHeightByPosition(rowPosition);
}
// Row resize
@Override
public boolean isRowPositionResizable(int rowPosition) {
return this.verticalLayerDependency.isRowPositionResizable(rowPosition);
}
// Y
@Override
public int getRowPositionByY(int y) {
return this.verticalLayerDependency.getRowPositionByY(y);
}
@Override
public int getStartYOfRowPosition(int rowPosition) {
return this.verticalLayerDependency.getStartYOfRowPosition(rowPosition);
}
// Underlying
@Override
public Collection<ILayer> getUnderlyingLayersByRowPosition(int rowPosition) {
Collection<ILayer> underlyingLayers = new HashSet<ILayer>();
underlyingLayers.add(this.baseLayer);
return underlyingLayers;
}
// Cell features
@Override
public String getDisplayModeByPosition(int columnPosition, int rowPosition) {
int baseColumnPosition = LayerUtil.convertColumnPosition(this, columnPosition, this.baseLayer);
int baseRowPosition = LayerUtil.convertRowPosition(this, rowPosition, this.baseLayer);
return this.baseLayer.getDisplayModeByPosition(baseColumnPosition, baseRowPosition);
}
@Override
public LabelStack getConfigLabelsByPosition(int columnPosition, int rowPosition) {
int baseColumnPosition = LayerUtil.convertColumnPosition(this, columnPosition, this.baseLayer);
int baseRowPosition = LayerUtil.convertRowPosition(this, rowPosition, this.baseLayer);
LabelStack labelStack = this.baseLayer.getConfigLabelsByPosition(baseColumnPosition, baseRowPosition);
IConfigLabelAccumulator configLabelAccumulator = getConfigLabelAccumulator();
if (configLabelAccumulator != null) {
configLabelAccumulator.accumulateConfigLabels(labelStack, columnPosition, rowPosition);
}
return labelStack;
}
@Override
public Object getDataValueByPosition(int columnPosition, int rowPosition) {
int baseColumnPosition = LayerUtil.convertColumnPosition(this, columnPosition, this.baseLayer);
int baseRowPosition = LayerUtil.convertRowPosition(this, rowPosition, this.baseLayer);
return this.baseLayer.getDataValueByPosition(baseColumnPosition, baseRowPosition);
}
// IRegionResolver
@Override
public LabelStack getRegionLabelsByXY(int x, int y) {
return this.baseLayer.getRegionLabelsByXY(x, y);
}
@Override
public IClientAreaProvider getClientAreaProvider() {
return this.clientAreaProvider;
}
@Override
public void setClientAreaProvider(IClientAreaProvider clientAreaProvider) {
this.clientAreaProvider = clientAreaProvider;
}
@Override
public ILayer getUnderlyingLayerByPosition(int columnPosition, int rowPosition) {
return this.baseLayer;
}
}