blob: 04c62da62c43a1c01a97290133338f32acfe445e [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.resize;
import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry;
import org.eclipse.nebula.widgets.nattable.grid.command.AutoResizeColumnCommandHandler;
import org.eclipse.nebula.widgets.nattable.grid.command.AutoResizeRowCommandHandler;
import org.eclipse.nebula.widgets.nattable.layer.ILayer;
import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell;
import org.eclipse.nebula.widgets.nattable.painter.cell.ICellPainter;
import org.eclipse.nebula.widgets.nattable.util.GCFactory;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Rectangle;
/**
* Helper class that does the calculations needed for the auto resizing feature.
*
* @see AutoResizeColumnCommandHandler
* @see AutoResizeRowCommandHandler
* @see AutoResizeHelper
*/
public class MaxCellBoundsHelper {
private MaxCellBoundsHelper() {
// private default constructor for helper class
}
/**
* Calculates the preferred column widths of the given columns based on the
* given {@link IConfigRegistry}. The preferred column width is the width
* needed at minimum to fit all the contents horizontally.
*
* @param configRegistry
* The {@link IConfigRegistry} to get the required configuration
* values.
* @param gcFactory
* The {@link GCFactory} for creating a temporary {@link GC}
* needed for UI related calculations without blocking the UI
* thread.
* @param layer
* The layer to which the column positions match.
* @param columnPositions
* The column positions for which the preferred width should be
* calculated.
* @return The preferred column widths of the given columns or
* <code>null</code> if an error occurred on processing.
*/
public static int[] getPreferredColumnWidths(
IConfigRegistry configRegistry, GCFactory gcFactory, ILayer layer, int[] columnPositions) {
GC gc = gcFactory.createGC();
if (gc != null) {
int[] columnWidths = new int[columnPositions.length];
for (int i = 0; i < columnPositions.length; i++) {
columnWidths[i] = getPreferredColumnWidth(layer, columnPositions[i], configRegistry, gc);
}
gc.dispose();
return columnWidths;
} else {
return new int[0];
}
}
/**
* Calculates the minimum width (in pixels) required to display the complete
* contents of the cells in a column. Takes into account the font settings
* and display type conversion.
*
* @param layer
* The layer to which the column position matches.
* @param columnPosition
* The column position whose preferred width should be
* calculated.
* @param configRegistry
* The {@link IConfigRegistry} to get the required configuration
* values.
* @param gc
* The {@link GC} needed for UI related calculations.
* @return The preferred column width of the given column or -1 if there are
* no cells for the specified column position.
*/
private static int getPreferredColumnWidth(ILayer layer, int columnPosition, IConfigRegistry configRegistry, GC gc) {
int maxWidth = -1;
ICellPainter painter;
ILayerCell cell;
for (int rowPosition = 0; rowPosition < layer.getRowCount(); rowPosition++) {
cell = layer.getCellByPosition(columnPosition, rowPosition);
if (cell != null) {
boolean atEndOfCellSpan = (cell.getOriginColumnPosition() + cell.getColumnSpan() - 1) == columnPosition;
if (atEndOfCellSpan) {
painter = layer.getCellPainter(cell.getColumnPosition(), cell.getRowPosition(), cell, configRegistry);
if (painter != null) {
int preferredWidth = painter.getPreferredWidth(cell, gc, configRegistry);
// Adjust width
Rectangle bounds = cell.getBounds();
bounds.width = preferredWidth;
Rectangle adjustedCellBounds = cell
.getLayer()
.getLayerPainter()
.adjustCellBounds(columnPosition, rowPosition, bounds);
preferredWidth += preferredWidth - adjustedCellBounds.width;
if (cell.getColumnSpan() > 1) {
int columnStartX = layer.getStartXOfColumnPosition(columnPosition);
int cellStartX = layer.getStartXOfColumnPosition(cell.getOriginColumnPosition());
preferredWidth = Math.max(0, preferredWidth - (columnStartX - cellStartX));
}
maxWidth = (preferredWidth > maxWidth) ? preferredWidth : maxWidth;
}
}
}
}
return maxWidth;
}
/**
* Calculates the preferred row heights of the given rows based on the given
* {@link IConfigRegistry}. The preferred row height is the height needed at
* minimum to fit all the content vertically.
*
* @param configRegistry
* The {@link IConfigRegistry} to get the required configuration
* values.
* @param gcFactory
* The {@link GCFactory} for creating a temporary {@link GC}
* needed for UI related calculations without blocking the UI
* thread.
* @param layer
* The layer to which the row positions match.
* @param rowPositions
* The row positions for which the preferred height should be
* calculated.
* @return The preferred row heights of the given rows or <code>null</code>
* if an error occurred on processing.
*/
public static int[] getPreferredRowHeights(
IConfigRegistry configRegistry, GCFactory gcFactory, ILayer layer, int[] rowPositions) {
GC gc = gcFactory.createGC();
if (gc != null) {
int[] rowHeights = new int[rowPositions.length];
for (int i = 0; i < rowPositions.length; i++) {
rowHeights[i] = getPreferredRowHeight(layer, rowPositions[i], configRegistry, gc);
}
gc.dispose();
return rowHeights;
} else {
return new int[0];
}
}
/**
* Calculates the minimum height (in pixels) required to display the
* complete contents of the cells in a row. Takes into account the font
* settings and display type conversion.
*
* @param layer
* The layer to which the column position matches.
* @param rowPosition
* The row position whose preferred height should be calculated.
* @param configRegistry
* The {@link IConfigRegistry} to get the required configuration
* values.
* @param gc
* The {@link GC} needed for UI related calculations.
* @return The preferred row height of the given row or -1 if there are no
* cells for the specified row position.
*/
private static int getPreferredRowHeight(ILayer layer, int rowPosition, IConfigRegistry configRegistry, GC gc) {
int maxHeight = -1;
ICellPainter painter;
ILayerCell cell;
for (int columnPosition = 0; columnPosition < layer.getColumnCount(); columnPosition++) {
cell = layer.getCellByPosition(columnPosition, rowPosition);
if (cell != null) {
boolean atEndOfCellSpan = (cell.getOriginRowPosition() + cell.getRowSpan() - 1) == rowPosition;
if (atEndOfCellSpan) {
painter = layer.getCellPainter(cell.getColumnPosition(), cell.getRowPosition(), cell, configRegistry);
if (painter != null) {
int preferredHeight = painter.getPreferredHeight(cell, gc, configRegistry);
// Adjust height
Rectangle bounds = cell.getBounds();
bounds.height = preferredHeight;
Rectangle adjustedCellBounds = cell
.getLayer()
.getLayerPainter()
.adjustCellBounds(columnPosition, rowPosition, bounds);
preferredHeight += preferredHeight - adjustedCellBounds.height;
if (cell.getRowSpan() > 1) {
int rowStartY = layer.getStartYOfRowPosition(rowPosition);
int cellStartY = layer.getStartYOfRowPosition(cell.getOriginRowPosition());
preferredHeight = Math.max(0, preferredHeight - (rowStartY - cellStartY));
}
maxHeight = (preferredHeight > maxHeight) ? preferredHeight : maxHeight;
}
}
}
}
return maxHeight;
}
/**
* Traverse the two arrays and return the greater element in each index
* position.
*/
public static int[] greater(int[] array1, int[] array2) {
int resultSize = (array1.length < array2.length) ? array1.length : array2.length;
int[] result = new int[resultSize];
for (int i = 0; i < resultSize; i++) {
result[i] = (array1[i] > array2[i]) ? array1[i] : array2[i];
}
return result;
}
}