blob: af0cda5da9537e390a30324304825f7ea3b3fe1e [file] [log] [blame]
/*******************************************************************************
* 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.layer;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Properties;
import org.eclipse.nebula.widgets.nattable.NatTable;
import org.eclipse.nebula.widgets.nattable.command.ILayerCommand;
import org.eclipse.nebula.widgets.nattable.command.ILayerCommandHandler;
import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry;
import org.eclipse.nebula.widgets.nattable.coordinate.Range;
import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell;
import org.eclipse.nebula.widgets.nattable.layer.event.ILayerEvent;
import org.eclipse.nebula.widgets.nattable.layer.event.IVisualChangeEvent;
import org.eclipse.nebula.widgets.nattable.painter.cell.ICellPainter;
import org.eclipse.nebula.widgets.nattable.painter.layer.ILayerPainter;
import org.eclipse.nebula.widgets.nattable.persistence.IPersistable;
import org.eclipse.nebula.widgets.nattable.style.DisplayMode;
import org.eclipse.nebula.widgets.nattable.ui.binding.UiBindingRegistry;
import org.eclipse.nebula.widgets.nattable.util.IClientAreaProvider;
import org.eclipse.swt.graphics.Rectangle;
/**
* <p>
* A Layer is a rectangular region of grid cells. A layer has methods to access
* its columns, rows, width and height. A layer can be stacked on top of another
* layer in order to expose a transformed view of its underlying layer's grid
* cell structure.
* </p>
* <p>
* Columns and rows in a layer are referenced either by <b>position</b> or
* <b>index</b>. The position of a column/row in a layer corresponds to the
* physical location of the column/row in the layer. The index of a column/row
* in a layer corresponds to the location of the column/row in the lowest level
* layer in the layer stack. These concepts are illustrated by the following
* example:
* </p>
*
* <pre>
* Hide Layer C
* 0 1 2 3 4 &lt;- column positions
* 1 0 3 4 5 &lt;- column indexes
*
* Reorder Layer B
* 0 1 2 3 4 5 &lt;- column positions
* 2 1 0 3 4 5 &lt;- column indexes
*
* Data Layer A
* 0 1 2 3 4 5 &lt;- column positions
* 0 1 2 3 4 5 &lt;- column indexes
* </pre>
* <p>
* In the above example, Hide Layer C is stacked on top of Reorder Layer B,
* which is in turn stacked on top of Data Layer A. The positions in Data Layer
* A are the same as its indexes, because it is the lowest level layer in the
* stack. Reorder Layer B reorders column 0 of its underlying layer (Data Layer
* A) after column 2 of its underlying layer. Hide Layer C hides the first
* column of its underlying layer (Reorder Layer B).
* </p>
* <p>
* Layers can also be laterally composed into larger layers. For instance, the
* standard grid layer is composed of a body layer, column header layer, row
* header layer, and corner layer:
* </p>
* <table border=1>
* <caption>layer composition</caption>
* <tr>
* <td>corner</td>
* <td>column header</td>
* </tr>
* <tr>
* <td>row header</td>
* <td>body</td>
* </tr>
* </table>
*
* @see CompositeLayer
*/
public interface ILayer extends ILayerListener, IPersistable {
// Dispose
/**
* Dispose any resource allocated by this layer.
*/
public void dispose();
// Persistence
/**
* Register an {@link IPersistable} that can write its state to the state
* {@link Properties} instance when the layer is persisted.
*
* @param persistable
* The persistable that should be registered.
*/
public void registerPersistable(IPersistable persistable);
/**
* Unregister the given {@link IPersistable}.
*
* @param persistable
* The persistable to unregister.
*/
public void unregisterPersistable(IPersistable persistable);
// Configuration
/**
* Configure this layer, e.g. add any key/mouse bindings and other general
* configuration.
* <p>
* This method is triggered by {@link NatTable#configure()} and executed
* down the layer stack.
* </p>
*
* @param configRegistry
* The {@link IConfigRegistry} instance owned by the
* {@link NatTable} this layer is attached to.
* @param uiBindingRegistry
* The {@link UiBindingRegistry} instance owned by
* {@link NatTable} this layer is attached to.
*
* @since 2.0
*/
public void configure(IConfigRegistry configRegistry, UiBindingRegistry uiBindingRegistry);
// Region
/**
* Return the {@link LabelStack} containing the region labels for the cell
* at the given pixel position.
*
* @param x
* the x pixel coordinate
* @param y
* the y pixel coordinate
* @return LabelStack containing the region labels for the cell at the given
* pixel position.
*/
public LabelStack getRegionLabelsByXY(int x, int y);
// Commands
/**
* Opportunity to respond to a command as it flows down the stack. If the
* layer is not interested in the command it should allow the command to
* keep traveling down the stack.
* <p>
* <b>Note:</b> Before the layer can process a command it <i>must</i>
* convert the command to its local coordinates using
* {@link ILayerCommand#convertToTargetLayer(ILayer)}
*
* @param command
* The command to execute.
* @return <code>true</code> if the command has been handled and was
* therefore consumed, <code>false</code> otherwise.
*/
public boolean doCommand(ILayerCommand command);
/**
* Register an {@link ILayerCommandHandler} to handle a command in this
* layer. Only one {@link ILayerCommandHandler} per {@link ILayerCommand}
* can be registered per layer.
*
* @param commandHandler
* The command handler to register with this layer.
*/
public void registerCommandHandler(ILayerCommandHandler<?> commandHandler);
/**
* Unregister the {@link ILayerCommandHandler} that is registered for the
* given {@link ILayerCommand} class.
*
* @param commandClass
* The {@link ILayerCommand} class for which the
* {@link ILayerCommandHandler} should be unregistered.
*/
public void unregisterCommandHandler(Class<? extends ILayerCommand> commandClass);
// Events
/**
* Events can be fired to notify other components of the grid. Events travel
* <i>up</i> the layer stack and may cause a repaint.
* <p>
* Example: When the contents of the grid change {@link IVisualChangeEvent}
* can be fired to notify other layers to refresh their caches etc.
*
* @param event
* the event to fire
*/
public void fireLayerEvent(ILayerEvent event);
/**
* Add a general {@link ILayerListener} to handle {@link ILayerEvent}s on
* this layer.
*
* @param listener
* The {@link ILayerListener} to add.
*/
public void addLayerListener(ILayerListener listener);
/**
* Remove the given {@link ILayerListener} from this layer.
*
* @param listener
* The {@link ILayerListener} to remove.
*/
public void removeLayerListener(ILayerListener listener);
/**
* Check if an {@link ILayerListener} of the given type is registered on
* this layer or not.
*
* @param layerListenerClass
* The type of {@link ILayerListener} to check for.
* @return <code>true</code> if this {@link ILayer} has a
* {@link ILayerListener} of the specified type registered,
* <code>false</code> if there is no such listener registered.
*/
public boolean hasLayerListener(Class<? extends ILayerListener> layerListenerClass);
/**
*
* @return The {@link ILayerPainter} used to render this layer.
*/
public ILayerPainter getLayerPainter();
// Client area
/**
*
* @return The {@link IClientAreaProvider} that specifies the rectangular
* area available on this layer.
*/
public IClientAreaProvider getClientAreaProvider();
/**
*
* @param clientAreaProvider
* The {@link IClientAreaProvider} that specifies the rectangular
* area available on this layer.
*/
public void setClientAreaProvider(IClientAreaProvider clientAreaProvider);
// Horizontal features
// Columns
/**
* @return The number of columns in this layer.
*/
public int getColumnCount();
public int getPreferredColumnCount();
/**
* Gets the underlying non-transformed column index for the given column
* position on this layer.
*
* @param columnPosition
* The column position relative to this layer.
* @return An underlying non-transformed column index, or -1 if the given
* column position does not exist within this coordinate system.
*/
public int getColumnIndexByPosition(int columnPosition);
/**
* Convert a column position to the coordinates of the underlying layer.
* This is possible since each layer is aware of its underlying layer.
*
* @param localColumnPosition
* column position in local (the layer's own) coordinates
* @return column position in the underlying layer's coordinates
*/
public int localToUnderlyingColumnPosition(int localColumnPosition);
/**
* Transforms the column position relative to the given underlying layer to
* this layer coordinates.
*
* @param sourceUnderlyingLayer
* The underlying layer to which the given column position
* matches.
* @param underlyingColumnPosition
* The column position in the given underlying layer that should
* be converted to a local column position.
* @return The given column position transformed to be local to this layer.
*/
public int underlyingToLocalColumnPosition(
ILayer sourceUnderlyingLayer,
int underlyingColumnPosition);
/**
* Transforms the column position ranges relative to the given underlying
* layer to this layer coordinates.
*
* @param sourceUnderlyingLayer
* The underlying layer to which the given column positions
* match.
* @param underlyingColumnPositionRanges
* The column position ranges relative to the given underlying
* layer that should be converted to local column positions.
* @return The given column position ranges transformed to this layer.
*/
public Collection<Range> underlyingToLocalColumnPositions(
ILayer sourceUnderlyingLayer,
Collection<Range> underlyingColumnPositionRanges);
// Width
/**
* Returns the total width in pixels of this layer.
*
* @return The total width in pixels of this layer.
*/
public int getWidth();
public int getPreferredWidth();
/**
* Returns the width in pixels of the given column.
*
* The width of invisible and non-existing columns is 0.
*
* @param columnPosition
* The column position in this layer.
*
* @return The width of the column.
*/
public int getColumnWidthByPosition(int columnPosition);
// Column resize
/**
* Check if the column at the given position is resizable.
*
* @param columnPosition
* The column position to check.
* @return <code>true</code> if the column is resizable, <code>false</code>
* if not.
*/
public boolean isColumnPositionResizable(int columnPosition);
// X
/**
* Returns the column position that contains the given x coordinate.
*
* @param x
* A horizontal pixel location relative to the pixel boundary of
* this layer.
* @return A column position relative to the associated coordinate system,
* or -1 if there is no column that contains x.
*/
public int getColumnPositionByX(int x);
/**
* Returns the x offset in pixels of the given column.
*
* @param columnPosition
* The column position in this layer.
* @return The x offset of the column, or -1.
*/
public int getStartXOfColumnPosition(int columnPosition);
// Underlying
/**
* Returns the layers that are directly below this layer for the given
* column position. For simple layers this collection will typically only
* have one entry. Layer compositions might return multiple values, e.g. in
* a default grid there will be 2 layers in the collection as there are two
* layers involved in a column.
*
* @param columnPosition
* The column position for which the underlying layers are
* requested.
* @return The layers that are directly below this layer for the given
* column position or <code>null</code> if this layer has no
* underlying layers.
*/
public Collection<ILayer> getUnderlyingLayersByColumnPosition(int columnPosition);
// Vertical features
// Rows
/**
* @return The number of rows in this layer.
*/
public int getRowCount();
public int getPreferredRowCount();
/**
* Gets the underlying non-transformed row index for the given row position
* on this layer.
*
* @param rowPosition
* The row position relative to this layer.
* @return An underlying non-transformed row index, or -1 if the given row
* position does not exist within this coordinate system.
*/
public int getRowIndexByPosition(int rowPosition);
/**
* Convert a row position to the coordinates of the underlying layer. This
* is possible since each layer is aware of its underlying layer.
*
* @param localRowPosition
* row position in local (the layer's own) coordinates
* @return row position in the underlying layer's coordinates
*/
public int localToUnderlyingRowPosition(int localRowPosition);
/**
* Transforms the row position relative to the given underlying layer to
* this layer coordinates.
*
* @param sourceUnderlyingLayer
* The underlying layer to which the given row position matches.
* @param underlyingRowPosition
* The row position in the given underlying layer that should be
* converted to a local row position.
* @return The given row position transformed to be local to this layer.
*/
public int underlyingToLocalRowPosition(
ILayer sourceUnderlyingLayer,
int underlyingRowPosition);
/**
* Transforms the row position ranges relative to the given underlying layer
* to this layer coordinates.
*
* @param sourceUnderlyingLayer
* The underlying layer to which the given row positions match.
* @param underlyingRowPositionRanges
* The row position ranges relative to the given underlying layer
* that should be converted to local row positions.
* @return The given row position ranges transformed to this layer.
*/
public Collection<Range> underlyingToLocalRowPositions(
ILayer sourceUnderlyingLayer,
Collection<Range> underlyingRowPositionRanges);
// Height
/**
* Returns the total height in pixels of this layer.
*
* @return The total height in pixels of this layer.
*/
public int getHeight();
public int getPreferredHeight();
/**
* Returns the height in pixels of the given row.
*
* The height of invisible and non-existing rows is 0.
*
* @param rowPosition
* The row position in this layer.
*
* @return The height of the row.
*/
public int getRowHeightByPosition(int rowPosition);
// Row resize
/**
* Check if the row at the given position is resizable.
*
* @param rowPosition
* The row position to check.
* @return <code>true</code> if the row is resizable, <code>false</code> if
* not.
*/
public boolean isRowPositionResizable(int rowPosition);
// Y
/**
* Returns the row position that contains the given y coordinate.
*
* @param y
* a vertical pixel location relative to the pixel boundary of
* this layer
* @return a row position relative to the associated coordinate system, or
* -1 if there is no row that contains y
*/
public int getRowPositionByY(int y);
/**
* Returns the y offset in pixels of the given row.
*
* @param rowPosition
* the row position in this layer
*
* @return the y offset of the row, or -1
*/
public int getStartYOfRowPosition(int rowPosition);
// Underlying
/**
* Returns the layers that are directly below this layer for the given row
* position. For simple layers this collection will typically only have one
* entry. Layer compositions might return multiple values, e.g. in a default
* grid there will be 2 layers in the collection as there are two layers
* involved in a row.
*
* @param rowPosition
* The row position for which the underlying layers are
* requested.
* @return The layers that are directly below this layer for the given row
* position or <code>null</code> if this layer has no underlying
* layers.
*/
public Collection<ILayer> getUnderlyingLayersByRowPosition(int rowPosition);
// Cell features
/**
* Returns the cell for the given coordinates on this layer.
*
* @param columnPosition
* The column position of the requested cell.
* @param rowPosition
* The row position of the requested cell.
* @return The {@link ILayerCell} for the given coordinates in this layer or
* <code>null</code> if the coordinates are invalid on this layer.
*/
public ILayerCell getCellByPosition(int columnPosition, int rowPosition);
/**
* Calculates the bounds in pixel for the given cell position.
*
* @param columnPosition
* the column position of the cell
* @param rowPosition
* the row position of the cell
*
* @return the bounds, or <code>null</code> if there are no valid bounds
*/
public Rectangle getBoundsByPosition(int columnPosition, int rowPosition);
/**
* Returns the active {@link DisplayMode} for the cell at the given
* coordinates. Needed to retrieve the corresponding configurations out of
* the {@link IConfigRegistry}. The default value is
* {@link DisplayMode#NORMAL}. The SelectionLayer for example overrides this
* to return {@link DisplayMode#SELECT} for cells that are currently
* selected.
*
* @param columnPosition
* The column position of the cell.
* @param rowPosition
* The row position of the cell.
* @return {@link DisplayMode} for the cell at the given coordinates.
*/
public String getDisplayModeByPosition(int columnPosition, int rowPosition);
/**
* Returns the config labels for the cell at the given coordinates. Needed
* to retrieve the corresponding configurations out of the
* {@link IConfigRegistry}.
*
* @param columnPosition
* The column position of the cell.
* @param rowPosition
* The row position of the cell.
* @return The {@link LabelStack} with the config labels for the cell at the
* given coordinates.
*/
public LabelStack getConfigLabelsByPosition(int columnPosition, int rowPosition);
/**
* Returns the data value for the cell at the given coordinates.
*
* @param columnPosition
* The column position of the cell.
* @param rowPosition
* The row position of the cell.
* @return The data value for the cell at the given coordinates.
*/
public Object getDataValueByPosition(int columnPosition, int rowPosition);
/**
* Returns the layer that is directly below this layer for the given cell
* coordinate.
*
* @param columnPosition
* The column position for which the underlying layer is
* requested.
* @param rowPosition
* The row position for which the underlying layer is requested.
* @return The layer that is directly below this layer for the given cell
* coordinates or <code>null</code> if this layer has no underlying
* layers.
*/
public ILayer getUnderlyingLayerByPosition(int columnPosition, int rowPosition);
/**
* Return the {@link ICellPainter} for the given {@link ILayerCell} at the
* given coordinates out of the given {@link IConfigRegistry}.
*
* @param columnPosition
* The column position of the cell.
* @param rowPosition
* The row position of the cell.
* @param cell
* The {@link ILayerCell} for which the {@link ICellPainter} is
* requested.
* @param configRegistry
* The {@link IConfigRegistry} to retrieve the painter from.
* @return The {@link ICellPainter} for the given cell at the given
* coordinates or <code>null</code> if no painter is configured.
*/
public ICellPainter getCellPainter(
int columnPosition,
int rowPosition,
ILayerCell cell,
IConfigRegistry configRegistry);
/**
* @return <code>true</code> if the layer has a dynamic size (e.g. viewport)
* or a fixed size.
* @since 2.0
*/
public default boolean isDynamicSizeLayer() {
return false;
}
/**
* @return The collection of labels that are provided by this layer used
* e.g. for CSS styling.
* @since 2.0
*/
public default Collection<String> getProvidedLabels() {
return new LinkedHashSet<>();
}
}