blob: f4075c9b01e5516ba074328e412d473f60223130 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2010 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ui.texteditor.templates;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
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;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.viewers.ColumnLayoutData;
import org.eclipse.jface.viewers.ColumnPixelData;
import org.eclipse.jface.viewers.ColumnWeightData;
/**
* Layout for tables, adapted from <code>TableLayoutComposite</code>.
* <p>
* XXX: Should switch to use {@link org.eclipse.jface.layout.TableColumnLayout}.
* </p>
*
* @since 3.2
*/
final class ColumnLayout extends Layout {
private static final String RECALCULATE_LAYOUT= "recalculateKey"; //$NON-NLS-1$
/**
* 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.
* <p>
* XXX: Should either switch to use
* {@link org.eclipse.jface.layout.TableColumnLayout} or get API from JFace
* or SWT, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=218483
* </p>
*
* @since 3.1
*/
private static int COLUMN_TRIM;
static {
String platform= SWT.getPlatform();
if ("win32".equals(platform)) //$NON-NLS-1$
COLUMN_TRIM= 4;
else if ("carbon".equals(platform)) //$NON-NLS-1$
COLUMN_TRIM= 24;
else
COLUMN_TRIM= 3;
}
private List<ColumnLayoutData> columns= new ArrayList<>();
/**
* Adds a new column of data to this table layout.
*
* @param data the column layout data
*/
public void addColumnData(ColumnLayoutData data) {
columns.add(data);
}
private Point computeTableSize(Table table, int wHint, int hHint) {
Point result= table.computeSize(wHint, hHint);
int width= 0;
int size= columns.size();
for (int i= 0; i < size; ++i) {
ColumnLayoutData layoutData= columns.get(i);
if (layoutData instanceof ColumnPixelData) {
ColumnPixelData col= (ColumnPixelData) layoutData;
width += col.width;
if (col.addTrim) {
width += COLUMN_TRIM;
}
} else if (layoutData instanceof ColumnWeightData) {
ColumnWeightData col= (ColumnWeightData) layoutData;
width += col.minimumWidth;
} else {
Assert.isTrue(false, "Unknown column layout data"); //$NON-NLS-1$
}
}
if (width > result.x)
result.x= width;
return result;
}
private void layoutTable(final Table table, final int width, final Rectangle area, final boolean increase) {
final TableColumn[] tableColumns= table.getColumns();
final int size= Math.min(columns.size(), tableColumns.length);
final int[] widths= new int[size];
final int[] weightIteration= new int[size];
int numberOfWeightColumns= 0;
int fixedWidth= 0;
int minWeightWidth= 0;
int totalWeight= 0;
// First calc space occupied by fixed columns
for (int i= 0; i < size; i++) {
ColumnLayoutData col= columns.get(i);
if (col instanceof ColumnPixelData) {
ColumnPixelData cpd= (ColumnPixelData) col;
int pixels= cpd.width;
if (cpd.addTrim) {
pixels += COLUMN_TRIM;
}
widths[i]= pixels;
fixedWidth += pixels;
} else if (col instanceof ColumnWeightData) {
ColumnWeightData cw= (ColumnWeightData) col;
weightIteration[numberOfWeightColumns]= i;
numberOfWeightColumns++;
totalWeight += cw.weight;
minWeightWidth += cw.minimumWidth;
widths[i]= cw.minimumWidth;
} else {
Assert.isTrue(false, "Unknown column layout data"); //$NON-NLS-1$
}
}
// Do we have columns that have a weight?
final int restIncludingMinWidths= width - fixedWidth;
final int rest= restIncludingMinWidths - minWeightWidth;
if (numberOfWeightColumns > 0 && rest > 0) {
// Modify the weights to reflect what each column already
// has due to its minimum. Otherwise, columns with low
// minimums get discriminated.
int totalWantedPixels= 0;
final int[] wantedPixels= new int[numberOfWeightColumns];
for (int i= 0; i < numberOfWeightColumns; i++) {
ColumnWeightData cw= (ColumnWeightData) columns.get(weightIteration[i]);
wantedPixels[i]= totalWeight == 0 ? 0 : cw.weight * restIncludingMinWidths / totalWeight;
totalWantedPixels+= wantedPixels[i];
}
// Now distribute the rest to the columns with weight.
int totalDistributed= 0;
for (int i= 0; i < numberOfWeightColumns; ++i) {
int pixels= totalWantedPixels == 0 ? 0 : wantedPixels[i] * rest / totalWantedPixels;
totalDistributed += pixels;
widths[weightIteration[i]] += pixels;
}
// Distribute any remaining pixels to columns with weight.
int diff= rest - totalDistributed;
for (int i= 0; diff > 0; i= ((i + 1) % numberOfWeightColumns)) {
++widths[weightIteration[i]];
--diff;
}
}
if (increase) {
table.setSize(area.width, area.height);
}
for (int i= 0; i < size; i++) {
tableColumns[i].setWidth(widths[i]);
}
if (!increase) {
table.setSize(area.width, area.height);
}
}
@Override
protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
return computeTableSize(getTable(composite), wHint, hHint);
}
@Override
protected void layout(Composite composite, boolean flushCache) {
Rectangle area= composite.getClientArea();
Table table= getTable(composite);
int tableWidth= table.getSize().x;
int trim= computeTrim(area, table, tableWidth);
int width= Math.max(0, area.width - trim);
if (width > 1)
layoutTable(table, width, area, tableWidth < area.width);
if( composite.getData(RECALCULATE_LAYOUT) == null ) {
composite.setData(RECALCULATE_LAYOUT, Boolean.FALSE);
composite.layout();
}
}
private int computeTrim(Rectangle area, Table table, int tableWidth) {
Point preferredSize= computeTableSize(table, area.width, area.height);
int trim;
if (tableWidth > 1) {
trim= tableWidth - table.getClientArea().width;
} else {
// initially, the table has no extend and no client area - use the border with
// plus some padding as educated guess
trim= 2 * table.getBorderWidth() + 1 ;
}
if (preferredSize.y > area.height) {
// Subtract the scrollbar width from the total column width
// if a vertical scrollbar will be required, but is not currently showing
// (in which case it is already subtracted above)
ScrollBar vBar= table.getVerticalBar();
if (!vBar.isVisible()) {
Point vBarSize= vBar.getSize();
trim += vBarSize.x;
}
}
return trim;
}
private Table getTable(Composite composite) {
return (Table) composite.getChildren()[0];
}
}