| /***************************************************************************** |
| * Copyright (c) 2015, 2020 CEA LIST. |
| * |
| * 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: |
| * Dirk Fauth <dirk.fauth@googlemail.com> - Initial API and implementation |
| * |
| *****************************************************************************/ |
| package org.eclipse.nebula.widgets.nattable.extension.nebula.richtext; |
| |
| import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry; |
| import org.eclipse.nebula.widgets.nattable.layer.cell.CellDisplayConversionUtils; |
| import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell; |
| import org.eclipse.nebula.widgets.nattable.painter.cell.AbstractCellPainter; |
| import org.eclipse.nebula.widgets.nattable.painter.cell.ICellPainter; |
| import org.eclipse.nebula.widgets.nattable.resize.command.ColumnResizeCommand; |
| import org.eclipse.nebula.widgets.nattable.resize.command.RowResizeCommand; |
| import org.eclipse.nebula.widgets.nattable.style.CellStyleAttributes; |
| import org.eclipse.nebula.widgets.nattable.style.CellStyleUtil; |
| import org.eclipse.nebula.widgets.nattable.style.IStyle; |
| import org.eclipse.nebula.widgets.nattable.util.GUIHelper; |
| import org.eclipse.nebula.widgets.richtext.RichTextPainter; |
| import org.eclipse.swt.graphics.Color; |
| import org.eclipse.swt.graphics.Font; |
| import org.eclipse.swt.graphics.GC; |
| import org.eclipse.swt.graphics.Rectangle; |
| |
| /** |
| * {@link ICellPainter} that is able to render HTML formatted text by using the |
| * Nebula {@link RichTextPainter}. |
| */ |
| public class RichTextCellPainter extends AbstractCellPainter { |
| |
| protected RichTextPainter richTextPainter; |
| |
| /** |
| * @since 1.1 |
| */ |
| protected boolean calculateByTextLength; |
| /** |
| * @since 1.1 |
| */ |
| protected boolean calculateByTextHeight; |
| |
| /** |
| * Creates a new {@link RichTextCellPainter} with text wrapping enabled and |
| * auto-resizing disabled. |
| */ |
| public RichTextCellPainter() { |
| this(true, false, false); |
| } |
| |
| /** |
| * Creates a new {@link RichTextCellPainter} with auto-resizing disabled. |
| * |
| * @param wrapText |
| * <code>true</code> to enable text wrapping, which means that |
| * text is wrapped for whole words. Words itself are not wrapped. |
| */ |
| public RichTextCellPainter(boolean wrapText) { |
| this(wrapText, false, false); |
| } |
| |
| /** |
| * Creates a new {@link RichTextCellPainter}. |
| * |
| * @param wrapText |
| * <code>true</code> to enable text wrapping, which means that |
| * text is wrapped for whole words. Words itself are not wrapped. |
| * @param calculate |
| * <code>true</code> to configure the text painter for |
| * auto-resizing which means to calculate the cell borders |
| * regarding the content |
| * @since 1.1 |
| */ |
| public RichTextCellPainter(boolean wrapText, boolean calculate) { |
| this(wrapText, calculate, calculate); |
| } |
| |
| /** |
| * Creates a new {@link RichTextCellPainter}. |
| * |
| * @param wrapText |
| * <code>true</code> to enable text wrapping, which means that |
| * text is wrapped for whole words. Words itself are not wrapped. |
| * @param calculateByTextLength |
| * <code>true</code> to configure the text painter to calculate |
| * the cell border by containing text length. This means the |
| * width of the cell is calculated by content. |
| * @param calculateByTextHeight |
| * <code>true</code> to configure the text painter to calculate |
| * the cell border by containing text height. This means the |
| * height of the cell is calculated by content. |
| * @since 1.1 |
| */ |
| public RichTextCellPainter(boolean wrapText, boolean calculateByTextLength, boolean calculateByTextHeight) { |
| this.richTextPainter = new RichTextPainter(wrapText); |
| this.calculateByTextLength = calculateByTextLength; |
| this.calculateByTextHeight = calculateByTextHeight; |
| } |
| |
| @Override |
| public void paintCell(ILayerCell cell, GC gc, Rectangle bounds, IConfigRegistry configRegistry) { |
| IStyle cellStyle = CellStyleUtil.getCellStyle(cell, configRegistry); |
| setupGCFromConfig(gc, cellStyle); |
| |
| String htmlText = CellDisplayConversionUtils.convertDataType(cell, configRegistry); |
| |
| Rectangle painterBounds = new Rectangle(bounds.x, bounds.y - this.richTextPainter.getParagraphSpace(), bounds.width, bounds.height); |
| this.richTextPainter.paintHTML(htmlText, gc, painterBounds); |
| |
| int height = this.richTextPainter.getPreferredSize().y - 2 * this.richTextPainter.getParagraphSpace(); |
| if (performRowResize(height, painterBounds)) { |
| cell.getLayer().doCommand( |
| new RowResizeCommand( |
| cell.getLayer(), |
| cell.getRowPosition(), |
| GUIHelper.convertVerticalDpiToPixel(height, configRegistry) + (cell.getBounds().height - bounds.height))); |
| } |
| |
| if (performColumnResize(this.richTextPainter.getPreferredSize().x, painterBounds)) { |
| cell.getLayer().doCommand( |
| new ColumnResizeCommand( |
| cell.getLayer(), |
| cell.getColumnPosition(), |
| GUIHelper.convertHorizontalDpiToPixel(this.richTextPainter.getPreferredSize().x, configRegistry) + (cell.getBounds().width - bounds.width))); |
| } |
| } |
| |
| @Override |
| public int getPreferredWidth(ILayerCell cell, GC gc, IConfigRegistry configRegistry) { |
| setupGCFromConfig(gc, CellStyleUtil.getCellStyle(cell, configRegistry)); |
| String htmlText = CellDisplayConversionUtils.convertDataType(cell, configRegistry); |
| |
| // using a zero size rectangle for calculation results in a content |
| // related preferred size |
| this.richTextPainter.preCalculate(htmlText, gc, new Rectangle(0, 0, 0, cell.getBounds().height), false); |
| return this.richTextPainter.getPreferredSize().x; |
| } |
| |
| @Override |
| public int getPreferredHeight(ILayerCell cell, GC gc, IConfigRegistry configRegistry) { |
| setupGCFromConfig(gc, CellStyleUtil.getCellStyle(cell, configRegistry)); |
| String htmlText = CellDisplayConversionUtils.convertDataType(cell, configRegistry); |
| |
| // using a zero size rectangle for calculation results in a content |
| // related preferred size |
| this.richTextPainter.preCalculate(htmlText, gc, new Rectangle(0, 0, cell.getBounds().width, 0), true); |
| // we subtract the top and bottom paragraph space |
| return this.richTextPainter.getPreferredSize().y - 2 * this.richTextPainter.getParagraphSpace(); |
| } |
| |
| /** |
| * Setup the {@link GC} by the values defined in the given cell style. |
| * |
| * @param gc |
| * The {@link GC} that is used for rendering. |
| * @param cellStyle |
| * The {@link IStyle} that contains the styles to apply. |
| */ |
| public void setupGCFromConfig(GC gc, IStyle cellStyle) { |
| Color fg = cellStyle.getAttributeValue(CellStyleAttributes.FOREGROUND_COLOR); |
| Color bg = cellStyle.getAttributeValue(CellStyleAttributes.BACKGROUND_COLOR); |
| Font font = cellStyle.getAttributeValue(CellStyleAttributes.FONT); |
| |
| gc.setAntialias(GUIHelper.DEFAULT_ANTIALIAS); |
| gc.setTextAntialias(GUIHelper.DEFAULT_TEXT_ANTIALIAS); |
| gc.setFont(font); |
| gc.setForeground(fg != null ? fg : GUIHelper.COLOR_LIST_FOREGROUND); |
| gc.setBackground(bg != null ? bg : GUIHelper.COLOR_LIST_BACKGROUND); |
| } |
| |
| /** |
| * Checks if a row resize needs to be triggered. |
| * |
| * @param contentHeight |
| * The necessary height to show the content completely |
| * @param rectangle |
| * The available rectangle to render to |
| * @return <code>true</code> if a row resize needs to be performed, |
| * <code>false</code> if not |
| * @since 1.1 |
| */ |
| protected boolean performRowResize(int contentHeight, Rectangle rectangle) { |
| return ((contentHeight > rectangle.height) && this.calculateByTextHeight); |
| } |
| |
| /** |
| * Checks if a column resize needs to be triggered. |
| * |
| * @param contentWidth |
| * The necessary width to show the content completely |
| * @param rectangle |
| * The available rectangle to render to |
| * @return <code>true</code> if a column resize needs to be performed, |
| * <code>false</code> if not |
| * @since 1.1 |
| */ |
| protected boolean performColumnResize(int contentWidth, Rectangle rectangle) { |
| return ((contentWidth > rectangle.width) && this.calculateByTextLength); |
| } |
| |
| /** |
| * @return <code>true</code> if this text painter is calculating the cell |
| * dimensions by containing text length. This means the <b>width</b> |
| * of the cell is calculated by content. |
| * @since 1.1 |
| */ |
| public boolean isCalculateByTextLength() { |
| return this.calculateByTextLength; |
| } |
| |
| /** |
| * Configure whether the text painter should calculate the cell dimensions |
| * by containing text length. This means the <b>width</b> of the cell is |
| * calculated by content. |
| * |
| * @param calculateByTextLength |
| * <code>true</code> to calculate and modify the cell dimension |
| * according to the text length, <code>false</code> to not |
| * modifying the cell dimensions. |
| * @since 1.1 |
| */ |
| public void setCalculateByTextLength(boolean calculateByTextLength) { |
| this.calculateByTextLength = calculateByTextLength; |
| } |
| |
| /** |
| * @return <code>true</code> if this text painter is calculating the cell |
| * dimensions by containing text height. This means the |
| * <b>height</b> of the cell is calculated by content. |
| * @since 1.1 |
| */ |
| public boolean isCalculateByTextHeight() { |
| return this.calculateByTextHeight; |
| } |
| |
| /** |
| * Configure whether the text painter should calculate the cell dimensions |
| * by containing text height. This means the <b>height</b> of the cell is |
| * calculated by content. |
| * |
| * @param calculateByTextHeight |
| * <code>true</code> to calculate and modify the cell dimension |
| * according to the text height, <code>false</code> to not |
| * modifying the cell dimensions. |
| * @since 1.1 |
| */ |
| public void setCalculateByTextHeight(boolean calculateByTextHeight) { |
| this.calculateByTextHeight = calculateByTextHeight; |
| } |
| |
| } |