/*******************************************************************************
* Copyright (c) 2004, 2005
* Thomas Hallgren, Kenneth Olwing, Mitch Sonies
* Pontus Rydin, Nils Unden, Peer Torngren
* The code, documentation and other materials contained herein have been
* licensed under the Eclipse Public License - v 1.0 by the individual
* copyright holders listed above, as Initial Contributors under such license.
* The text of such license is available at www.eclipse.org.
*******************************************************************************/
package org.eclipse.buckminster.ui.internal;
import java.util.ArrayList;
import org.eclipse.buckminster.ui.Messages;
import org.eclipse.jface.viewers.ColumnLayoutData;
import org.eclipse.jface.viewers.ColumnPixelData;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
/**
* A dynamic layout for a table that will resize the columns according to the
* client area. The layout will also deal with the fact that a vertical
* scrollbar may or may not be visible.<br/>
* Call {@link #addColumnData(ColumnLayoutData)} to add columns.
*
* @author Thomas Hallgren
*/
public class DynamicTableLayout extends Layout {
/**
* The number of extra pixels taken as horizontal trim by the table column.
* To ensure there are N pixels available for the content of the column,
* assign N+COLUMN_TRIM for the column width.
*
* @since 3.1
*/
private static final int COLUMN_TRIM = "carbon".equals(SWT.getPlatform()) ? 24 : 3; //$NON-NLS-1$
/**
* The list of column layout data.
*/
private final ArrayList<ColumnLayoutData> columns = new ArrayList<ColumnLayoutData>();
/**
* Minimum height of the table.
*/
private final int minimumHeight;
/**
* Creates a new table layout.
*/
public DynamicTableLayout(int minimumHeight) {
this.minimumHeight = minimumHeight;
}
/**
* Adds a new column of data to this table layout.
*
* @param data
* the column layout data
*/
public void addColumnData(ColumnLayoutData data) {
if (!((data instanceof ColumnPixelData) || (data instanceof ColumnWeightData)))
throw new IllegalArgumentException(NLS.bind(Messages.unknown_0_derivate, "ColumnLayoutData")); //$NON-NLS-1$
columns.add(data);
}
/*
* (non-Javadoc) Method declared on Layout.
*/
@Override
public Point computeSize(Composite c, int wHint, int hHint, boolean flush) {
if (wHint != SWT.DEFAULT && hHint != SWT.DEFAULT)
return new Point(wHint, hHint);
Table table = (Table) c;
// To avoid recursions.
//
table.setLayout(null);
Point result;
try {
// Use native layout algorithm
//
result = table.computeSize(wHint, hHint, flush);
} finally {
table.setLayout(this);
}
int width = 0;
for (ColumnLayoutData layoutData : columns) {
if (layoutData instanceof ColumnPixelData) {
ColumnPixelData col = (ColumnPixelData) layoutData;
width += col.width;
if (col.addTrim)
width += COLUMN_TRIM;
} else {
ColumnWeightData col = (ColumnWeightData) layoutData;
width += col.minimumWidth;
}
}
if (width > result.x)
result.x = width;
if (minimumHeight > result.y)
result.y = minimumHeight;
return result;
}
/*
* (non-Javadoc) Method declared on Layout.
*/
@Override
public void layout(Composite c, boolean flush) {
Table table = (Table) c;
int width = table.getClientArea().width;
// Layout is being called with an invalid value the first time
// it is being called on Linux. This method resets the
// Layout to null so we make sure we run it only when
// the value is OK.
//
if (width <= 1)
return;
ScrollBar vScroll = table.getVerticalBar();
if (vScroll != null && !vScroll.isEnabled())
width += vScroll.getSize().x;
TableColumn[] tableColumns = table.getColumns();
int size = Math.min(columns.size(), tableColumns.length);
int[] widths = new int[size];
int fixedWidth = 0;
int numberOfWeightColumns = 0;
int totalWeight = 0;
// First calc space occupied by fixed columns
for (int idx = 0; idx < size; idx++) {
ColumnLayoutData col = columns.get(idx);
if (col instanceof ColumnPixelData) {
ColumnPixelData cpd = (ColumnPixelData) col;
int pixels = cpd.width;
if (cpd.addTrim)
pixels += COLUMN_TRIM;
widths[idx] = pixels;
fixedWidth += pixels;
} else {
numberOfWeightColumns++;
totalWeight += ((ColumnWeightData) col).weight;
}
}
// Do we have columns that have a weight
//
if (numberOfWeightColumns > 0) {
// Now distribute the rest to the columns with weight.
//
int rest = width - fixedWidth;
int totalDistributed = 0;
for (int idx = 0; idx < size; ++idx) {
ColumnLayoutData col = columns.get(idx);
if (col instanceof ColumnWeightData) {
ColumnWeightData cw = (ColumnWeightData) col;
// calculate weight as above
// int weight = firstTime ? cw.weight :
// tableColumns[i].getWidth();
int weight = cw.weight;
int pixels = totalWeight == 0 ? 0 : weight * rest / totalWeight;
if (pixels < cw.minimumWidth)
pixels = cw.minimumWidth;
totalDistributed += pixels;
widths[idx] = pixels;
}
}
// Distribute any remaining pixels to columns with weight.
//
int diff = rest - totalDistributed;
for (int idx = 0; diff > 0; ++idx) {
if (idx == size)
idx = 0;
ColumnLayoutData col = columns.get(idx);
if (col instanceof ColumnWeightData) {
++widths[idx];
--diff;
}
}
}
for (int idx = 0; idx < size; idx++)
tableColumns[idx].setWidth(widths[idx]);
}
}