001: /*******************************************************************************
002: * Copyright (c) 2005, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.texteditor.templates;
011:
012: import java.util.ArrayList;
013: import java.util.List;
014:
015: import org.eclipse.swt.SWT;
016: import org.eclipse.swt.graphics.Point;
017: import org.eclipse.swt.graphics.Rectangle;
018: import org.eclipse.swt.widgets.Composite;
019: import org.eclipse.swt.widgets.Layout;
020: import org.eclipse.swt.widgets.ScrollBar;
021: import org.eclipse.swt.widgets.Table;
022: import org.eclipse.swt.widgets.TableColumn;
023:
024: import org.eclipse.core.runtime.Assert;
025:
026: import org.eclipse.jface.viewers.ColumnLayoutData;
027: import org.eclipse.jface.viewers.ColumnPixelData;
028: import org.eclipse.jface.viewers.ColumnWeightData;
029:
030: /**
031: * Layout for tables, adapted from <code>TableLayoutComposite</code>.
032: *
033: * @since 3.2
034: */
035: final class ColumnLayout extends Layout {
036:
037: private static final String RECALCULATE_LAYOUT = "recalculateKey"; //$NON-NLS-1$
038:
039: /**
040: * The number of extra pixels taken as horizontal trim by the table column.
041: * To ensure there are N pixels available for the content of the column,
042: * assign N+COLUMN_TRIM for the column width.
043: *
044: * @since 3.1
045: */
046: private static int COLUMN_TRIM = "carbon".equals(SWT.getPlatform()) ? 24 : 3; //$NON-NLS-1$
047:
048: private List columns = new ArrayList();
049:
050: /**
051: * Adds a new column of data to this table layout.
052: *
053: * @param data the column layout data
054: */
055: public void addColumnData(ColumnLayoutData data) {
056: columns.add(data);
057: }
058:
059: private Point computeTableSize(Table table, int wHint, int hHint) {
060: Point result = table.computeSize(wHint, hHint);
061:
062: int width = 0;
063: int size = columns.size();
064: for (int i = 0; i < size; ++i) {
065: ColumnLayoutData layoutData = (ColumnLayoutData) columns
066: .get(i);
067: if (layoutData instanceof ColumnPixelData) {
068: ColumnPixelData col = (ColumnPixelData) layoutData;
069: width += col.width;
070: if (col.addTrim) {
071: width += COLUMN_TRIM;
072: }
073: } else if (layoutData instanceof ColumnWeightData) {
074: ColumnWeightData col = (ColumnWeightData) layoutData;
075: width += col.minimumWidth;
076: } else {
077: Assert.isTrue(false, "Unknown column layout data"); //$NON-NLS-1$
078: }
079: }
080: if (width > result.x)
081: result.x = width;
082: return result;
083: }
084:
085: private void layoutTable(final Table table, final int width,
086: final Rectangle area, final boolean increase) {
087: final TableColumn[] tableColumns = table.getColumns();
088: final int size = Math.min(columns.size(), tableColumns.length);
089: final int[] widths = new int[size];
090:
091: final int[] weightIteration = new int[size];
092: int numberOfWeightColumns = 0;
093:
094: int fixedWidth = 0;
095: int minWeightWidth = 0;
096: int totalWeight = 0;
097:
098: // First calc space occupied by fixed columns
099: for (int i = 0; i < size; i++) {
100: ColumnLayoutData col = (ColumnLayoutData) columns.get(i);
101: if (col instanceof ColumnPixelData) {
102: ColumnPixelData cpd = (ColumnPixelData) col;
103: int pixels = cpd.width;
104: if (cpd.addTrim) {
105: pixels += COLUMN_TRIM;
106: }
107: widths[i] = pixels;
108: fixedWidth += pixels;
109: } else if (col instanceof ColumnWeightData) {
110: ColumnWeightData cw = (ColumnWeightData) col;
111: weightIteration[numberOfWeightColumns] = i;
112: numberOfWeightColumns++;
113: totalWeight += cw.weight;
114: minWeightWidth += cw.minimumWidth;
115: widths[i] = cw.minimumWidth;
116: } else {
117: Assert.isTrue(false, "Unknown column layout data"); //$NON-NLS-1$
118: }
119: }
120:
121: // Do we have columns that have a weight?
122: final int restIncludingMinWidths = width - fixedWidth;
123: final int rest = restIncludingMinWidths - minWeightWidth;
124: if (numberOfWeightColumns > 0 && rest > 0) {
125:
126: // Modify the weights to reflect what each column already
127: // has due to its minimum. Otherwise, columns with low
128: // minimums get discriminated.
129: int totalWantedPixels = 0;
130: final int[] wantedPixels = new int[numberOfWeightColumns];
131: for (int i = 0; i < numberOfWeightColumns; i++) {
132: ColumnWeightData cw = (ColumnWeightData) columns
133: .get(weightIteration[i]);
134: wantedPixels[i] = totalWeight == 0 ? 0 : cw.weight
135: * restIncludingMinWidths / totalWeight;
136: totalWantedPixels += wantedPixels[i];
137: }
138:
139: // Now distribute the rest to the columns with weight.
140: int totalDistributed = 0;
141: for (int i = 0; i < numberOfWeightColumns; ++i) {
142: int pixels = totalWantedPixels == 0 ? 0
143: : wantedPixels[i] * rest / totalWantedPixels;
144: totalDistributed += pixels;
145: widths[weightIteration[i]] += pixels;
146: }
147:
148: // Distribute any remaining pixels to columns with weight.
149: int diff = rest - totalDistributed;
150: for (int i = 0; diff > 0; i = ((i + 1) % numberOfWeightColumns)) {
151: ++widths[weightIteration[i]];
152: --diff;
153: }
154: }
155:
156: if (increase) {
157: table.setSize(area.width, area.height);
158: }
159: for (int i = 0; i < size; i++) {
160: tableColumns[i].setWidth(widths[i]);
161: }
162: if (!increase) {
163: table.setSize(area.width, area.height);
164: }
165: }
166:
167: /*
168: * @see org.eclipse.swt.widgets.Layout#computeSize(org.eclipse.swt.widgets.Composite, int, int, boolean)
169: */
170: protected Point computeSize(Composite composite, int wHint,
171: int hHint, boolean flushCache) {
172: return computeTableSize(getTable(composite), wHint, hHint);
173: }
174:
175: /*
176: * @see org.eclipse.swt.widgets.Layout#layout(org.eclipse.swt.widgets.Composite, boolean)
177: */
178: protected void layout(Composite composite, boolean flushCache) {
179: Rectangle area = composite.getClientArea();
180: Table table = getTable(composite);
181: int tableWidth = table.getSize().x;
182: int trim = computeTrim(area, table, tableWidth);
183: int width = Math.max(0, area.width - trim);
184:
185: if (width > 1)
186: layoutTable(table, width, area, tableWidth < area.width);
187:
188: if (composite.getData(RECALCULATE_LAYOUT) == null) {
189: composite.setData(RECALCULATE_LAYOUT, Boolean.FALSE);
190: composite.layout();
191: }
192: }
193:
194: private int computeTrim(Rectangle area, Table table, int tableWidth) {
195: Point preferredSize = computeTableSize(table, area.width,
196: area.height);
197: int trim;
198: if (tableWidth > 1) {
199: trim = tableWidth - table.getClientArea().width;
200: } else {
201: // initially, the table has no extend and no client area - use the border with
202: // plus some padding as educated guess
203: trim = 2 * table.getBorderWidth() + 1;
204: }
205: if (preferredSize.y > area.height) {
206: // Subtract the scrollbar width from the total column width
207: // if a vertical scrollbar will be required, but is not currently showing
208: // (in which case it is already subtracted above)
209: ScrollBar vBar = table.getVerticalBar();
210: if (!vBar.isVisible()) {
211: Point vBarSize = vBar.getSize();
212: trim += vBarSize.x;
213: }
214: }
215: return trim;
216: }
217:
218: private Table getTable(Composite composite) {
219: return (Table) composite.getChildren()[0];
220: }
221:
222: }
|