blob: a55b97549a55dd97cb5545c940e8bc1b5304205a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012, 2020 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.tree.painter;
import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry;
import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell;
import org.eclipse.nebula.widgets.nattable.painter.cell.CellPainterWrapper;
import org.eclipse.nebula.widgets.nattable.painter.cell.ICellPainter;
import org.eclipse.nebula.widgets.nattable.painter.cell.decorator.CellPainterDecorator;
import org.eclipse.nebula.widgets.nattable.tree.config.DefaultTreeLayerConfiguration;
import org.eclipse.nebula.widgets.nattable.ui.util.CellEdgeEnum;
import org.eclipse.nebula.widgets.nattable.util.GUIHelper;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Rectangle;
/**
* Implementation of CellPainterWrapper that is used to render tree structures
* in NatTable. It puts indentation to tree nodes to visualize the tree
* structure and adds expand/collapse icons corresponding to the state if a tree
* node has children.
*/
public class IndentedTreeImagePainter extends CellPainterWrapper {
/**
* The number of pixels to indent per depth.
*/
private final int treeIndent;
private final CellPainterDecorator internalPainter;
/**
* Creates an IndentedTreeImagePainter. Will use 10 pixels for indentation
* per depth and a default TreeImagePainter for rendering the icons in the
* tree.
*/
public IndentedTreeImagePainter() {
this(10, new TreeImagePainter());
}
/**
* Creates an IndentedTreeImagePainter. Will use the given number of pixels
* for indentation per depth and a default {@link TreeImagePainter} for
* rendering the icons in the tree.
*
* @param treeIndent
* The number of pixels to indent per depth.
*/
public IndentedTreeImagePainter(int treeIndent) {
this(treeIndent, new TreeImagePainter());
}
/**
* Creates an IndentedTreeImagePainter using the given indentation per depth
* and {@link ICellPainter} for painting the icons in the tree.
*
* @param treeIndent
* The number of pixels to indent per depth.
* @param treeImagePainter
* The {@link ICellPainter} that should be used to paint the
* images in the tree. When using the
* DefaultTreeLayerConfiguration the content painter needs to be
* of type of {@link TreeImagePainter} that paints
* expand/collapse/leaf icons regarding the node state, because
* the ui bindings for expand/collapse are registered against
* that type.
* @since 1.6
*/
public IndentedTreeImagePainter(int treeIndent, ICellPainter treeImagePainter) {
this(treeIndent, CellEdgeEnum.LEFT, treeImagePainter);
}
/**
* Creates an IndentedTreeImagePainter using the given indentation per depth
* and {@link ICellPainter} for painting the icons in the tree to the
* specified cell edge.
*
* @param treeIndent
* The number of pixels to indent per depth.
* @param cellEdge
* the edge of the cell on which the tree state indicator
* decoration should be applied
* @param treeImagePainter
* The {@link ICellPainter} that should be used to paint the
* images in the tree. When using the
* DefaultTreeLayerConfiguration the content painter needs to be
* of type of {@link TreeImagePainter} that paints
* expand/collapse/leaf icons regarding the node state, because
* the ui bindings for expand/collapse are registered against
* that type.
* @since 1.6
*/
public IndentedTreeImagePainter(
int treeIndent,
CellEdgeEnum cellEdge,
ICellPainter treeImagePainter) {
this.treeIndent = treeIndent;
this.internalPainter =
new CellPainterDecorator(null, cellEdge, treeImagePainter);
setWrappedPainter(this.internalPainter);
}
// the following constructors are intended to configure the
// CellPainterDecorator that is created as
// the wrapped painter of this IndentedTreeImagePainter
/**
* Creates a {@link IndentedTreeImagePainter} that uses the given
* {@link ICellPainter} as base {@link ICellPainter}. It will use the
* {@link TreeImagePainter} as decorator for tree state related decorations
* at the specified cell edge, which can be configured to render the
* background or not via method parameter. With the additional parameters,
* the behaviour of the created {@link CellPainterDecorator} can be
* configured in terms of rendering.
*
* @param treeIndent
* The number of pixels to indent per depth.
* @param interiorPainter
* the base {@link ICellPainter} to use
* @param cellEdge
* the edge of the cell on which the tree state indicator
* decoration should be applied
* @param paintBg
* flag to configure whether the {@link TreeImagePainter} should
* paint the background or not
* @param spacing
* the number of pixels that should be used as spacing between
* cell edge and decoration
* @param paintDecorationDependent
* flag to configure if the base {@link ICellPainter} should
* render decoration dependent or not. If it is set to
* <code>false</code>, the base painter will always paint at the
* same coordinates, using the whole cell bounds,
* <code>true</code> will cause the bounds of the cell to shrink
* for the base painter.
*/
public IndentedTreeImagePainter(
int treeIndent,
ICellPainter interiorPainter,
CellEdgeEnum cellEdge,
boolean paintBg,
int spacing,
boolean paintDecorationDependent) {
this.treeIndent = treeIndent;
ICellPainter painter = new TreeImagePainter(paintBg);
this.internalPainter =
new CellPainterDecorator(
interiorPainter,
cellEdge,
spacing,
painter,
paintDecorationDependent,
paintBg);
setWrappedPainter(this.internalPainter);
}
/**
* Creates a {@link IndentedTreeImagePainter} that uses the given
* {@link ICellPainter} as base {@link ICellPainter}. It will use the given
* {@link ICellPainter} as decorator for tree state related decorations at
* the specified cell edge, which can be configured to render the background
* or not via method parameter. With the additional parameters, the
* behaviour of the created {@link CellPainterDecorator} can be configured
* in terms of rendering.
*
* @param treeIndent
* The number of pixels to indent per depth.
* @param interiorPainter
* the base {@link ICellPainter} to use
* @param cellEdge
* the edge of the cell on which the tree state indicator
* decoration should be applied
* @param decoratorPainter
* the {@link ICellPainter} that should be used to paint the tree
* state related decoration
* @param paintBg
* flag to configure whether the {@link CellPainterDecorator}
* should paint the background or not
* @param spacing
* the number of pixels that should be used as spacing between
* cell edge and decoration
* @param paintDecorationDependent
* flag to configure if the base {@link ICellPainter} should
* render decoration dependent or not. If it is set to
* <code>false</code>, the base painter will always paint at the
* same coordinates, using the whole cell bounds,
* <code>true</code> will cause the bounds of the cell to shrink
* for the base painter.
*/
public IndentedTreeImagePainter(
int treeIndent,
ICellPainter interiorPainter,
CellEdgeEnum cellEdge,
ICellPainter decoratorPainter,
boolean paintBg,
int spacing,
boolean paintDecorationDependent) {
this.treeIndent = treeIndent;
this.internalPainter =
new CellPainterDecorator(
interiorPainter,
cellEdge,
spacing,
decoratorPainter,
paintDecorationDependent,
paintBg);
setWrappedPainter(this.internalPainter);
}
/**
* Creates a {@link IndentedTreeImagePainter} that uses the given
* {@link ICellPainter} as base {@link ICellPainter} and decorate it with
* the {@link TreeImagePainter} on the right edge of the cell. This
* constructor gives the opportunity to configure the behaviour of the
* {@link TreeImagePainter} and the {@link CellPainterDecorator} for some
* attributes. Remains because of downwards compatibility.
*
* @param treeIndent
* The number of pixels to indent per depth.
* @param interiorPainter
* the base {@link ICellPainter} to use
* @param paintBg
* flag to configure whether the {@link TreeImagePainter} should
* paint the background or not
* @param interiorPainterToSpanFullWidth
* flag to configure how the bounds of the base painter should be
* calculated
*/
public IndentedTreeImagePainter(
int treeIndent,
ICellPainter interiorPainter,
boolean paintBg,
boolean interiorPainterToSpanFullWidth) {
this.treeIndent = treeIndent;
ICellPainter painter = new TreeImagePainter(paintBg);
this.internalPainter =
new CellPainterDecorator(
interiorPainter,
CellEdgeEnum.RIGHT,
0,
painter,
!interiorPainterToSpanFullWidth,
paintBg);
setWrappedPainter(this.internalPainter);
}
/**
* @return The ICellPainter that is used to paint the images in the tree.
* Usually it is some type of TreeImagePainter that paints
* expand/collapse/leaf icons regarding the node state.
*/
public ICellPainter getTreeImagePainter() {
return this.internalPainter.getDecoratorCellPainter();
}
/**
* @param cellPainter
* The {@link ICellPainter} that should be used to paint the
* images in the tree. Usually it is some type of
* {@link TreeImagePainter} that paints expand/collapse/leaf
* icons regarding the node state.
*/
public void setTreeImagePainter(ICellPainter cellPainter) {
this.internalPainter.setDecoratorCellPainter(cellPainter);
}
/**
* @param cellPainter
* The base {@link ICellPainter} that should be used to render
* the cell content.
*/
public void setBaseCellPainter(ICellPainter cellPainter) {
this.internalPainter.setBaseCellPainter(cellPainter);
}
/**
*
* @return The {@link CellPainterDecorator} that is wrapped by this
* {@link IndentedTreeImagePainter}. Can be used to perform specific
* decoration configurations, e.g. set the decoration dependent
* rendering option.
* @since 1.6
*/
public CellPainterDecorator getInternalPainter() {
return this.internalPainter;
}
@Override
public Rectangle getWrappedPainterBounds(
ILayerCell cell, GC gc, Rectangle bounds, IConfigRegistry configRegistry) {
int depth = getDepth(cell);
int indent = getIndent(depth, configRegistry);
return new Rectangle(
bounds.x + indent,
bounds.y,
bounds.width - indent,
bounds.height);
}
@Override
public void paintCell(ILayerCell cell, GC gc, Rectangle bounds, IConfigRegistry configRegistry) {
super.paintCell(
cell,
gc,
getWrappedPainterBounds(cell, gc, bounds, configRegistry),
configRegistry);
}
@Override
public int getPreferredWidth(ILayerCell cell, GC gc, IConfigRegistry configRegistry) {
int depth = getDepth(cell);
int indent = getIndent(depth, configRegistry);
return indent + super.getPreferredWidth(cell, gc, configRegistry);
}
/**
* @param depth
* The depth/level in the tree structure for which the indent is
* requested.
* @param configRegistry
* The {@link IConfigRegistry} needed for accessing the dpi
* converter.
* @return The number of pixels the content should be indented.
* @since 2.0
*/
protected int getIndent(int depth, IConfigRegistry configRegistry) {
return GUIHelper.convertHorizontalPixelToDpi(this.treeIndent * depth, configRegistry);
}
/**
* @param cell
* The cell for which the depth/level in the tree structure is
* requested.
* @return The depth/level in the tree structure the given cell is located.
*
* @since 1.4
*/
protected int getDepth(ILayerCell cell) {
int depth = 0;
for (String configLabel : cell.getConfigLabels()) {
if (configLabel.startsWith(DefaultTreeLayerConfiguration.TREE_DEPTH_CONFIG_TYPE)) {
String[] tokens = configLabel.split("_"); //$NON-NLS-1$
depth = Integer.valueOf(tokens[tokens.length - 1]).intValue();
}
}
return depth;
}
}