001: /*******************************************************************************
002: * Copyright (c) 2000, 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.jface.viewers;
011:
012: import java.util.ArrayList;
013: import java.util.List;
014:
015: import org.eclipse.core.runtime.Assert;
016: import org.eclipse.jface.layout.TableColumnLayout;
017: import org.eclipse.swt.SWT;
018: import org.eclipse.swt.graphics.Point;
019: import org.eclipse.swt.widgets.Composite;
020: import org.eclipse.swt.widgets.Item;
021: import org.eclipse.swt.widgets.Layout;
022: import org.eclipse.swt.widgets.Table;
023: import org.eclipse.swt.widgets.TableColumn;
024: import org.eclipse.swt.widgets.Tree;
025: import org.eclipse.swt.widgets.TreeColumn;
026:
027: /**
028: * A layout for a table. Call <code>addColumnData</code> to add columns.
029: * The TableLayout {@link ColumnLayoutData} is only valid until the table
030: * is resized. To keep the proportions constant when the table is resized
031: * see {@link TableColumnLayout}
032: */
033: public class TableLayout extends Layout {
034:
035: /**
036: * The number of extra pixels taken as horizontal trim by the table column.
037: * To ensure there are N pixels available for the content of the column,
038: * assign N+COLUMN_TRIM for the column width.
039: *
040: * @since 3.1
041: */
042: private static int COLUMN_TRIM = "carbon".equals(SWT.getPlatform()) ? 24 : 3; //$NON-NLS-1$
043:
044: /**
045: * The list of column layout data (element type:
046: * <code>ColumnLayoutData</code>).
047: */
048: private List columns = new ArrayList();
049:
050: /**
051: * Indicates whether <code>layout</code> has yet to be called.
052: */
053: private boolean firstTime = true;
054:
055: /**
056: * Creates a new table layout.
057: */
058: public TableLayout() {
059: }
060:
061: /**
062: * Adds a new column of data to this table layout.
063: *
064: * @param data
065: * the column layout data
066: */
067: public void addColumnData(ColumnLayoutData data) {
068: columns.add(data);
069: }
070:
071: /*
072: * (non-Javadoc) Method declared on Layout.
073: */
074: public Point computeSize(Composite c, int wHint, int hHint,
075: boolean flush) {
076: if (wHint != SWT.DEFAULT && hHint != SWT.DEFAULT) {
077: return new Point(wHint, hHint);
078: }
079:
080: Table table = (Table) c;
081: // To avoid recursions.
082: table.setLayout(null);
083: // Use native layout algorithm
084: Point result = table.computeSize(wHint, hHint, flush);
085: table.setLayout(this );
086:
087: int width = 0;
088: int size = columns.size();
089: for (int i = 0; i < size; ++i) {
090: ColumnLayoutData layoutData = (ColumnLayoutData) columns
091: .get(i);
092: if (layoutData instanceof ColumnPixelData) {
093: ColumnPixelData col = (ColumnPixelData) layoutData;
094: width += col.width;
095: if (col.addTrim) {
096: width += COLUMN_TRIM;
097: }
098: } else if (layoutData instanceof ColumnWeightData) {
099: ColumnWeightData col = (ColumnWeightData) layoutData;
100: width += col.minimumWidth;
101: } else {
102: Assert.isTrue(false, "Unknown column layout data");//$NON-NLS-1$
103: }
104: }
105: if (width > result.x) {
106: result.x = width;
107: }
108: return result;
109: }
110:
111: /*
112: * (non-Javadoc) Method declared on Layout.
113: */
114: public void layout(Composite c, boolean flush) {
115: // Only do initial layout. Trying to maintain proportions when resizing
116: // is too hard,
117: // causes lots of widget flicker, causes scroll bars to appear and
118: // occasionally stick around (on Windows),
119: // requires hooking column resizing as well, and may not be what the
120: // user wants anyway.
121: if (!firstTime) {
122: return;
123: }
124:
125: int width = c.getClientArea().width;
126:
127: // XXX: Layout is being called with an invalid value the first time
128: // it is being called on Linux. This method resets the
129: // Layout to null so we make sure we run it only when
130: // the value is OK.
131: if (width <= 1) {
132: return;
133: }
134:
135: Item[] tableColumns = getColumns(c);
136: int size = Math.min(columns.size(), tableColumns.length);
137: int[] widths = new int[size];
138: int fixedWidth = 0;
139: int numberOfWeightColumns = 0;
140: int totalWeight = 0;
141:
142: // First calc space occupied by fixed columns
143: for (int i = 0; i < size; i++) {
144: ColumnLayoutData col = (ColumnLayoutData) columns.get(i);
145: if (col instanceof ColumnPixelData) {
146: ColumnPixelData cpd = (ColumnPixelData) col;
147: int pixels = cpd.width;
148: if (cpd.addTrim) {
149: pixels += COLUMN_TRIM;
150: }
151: widths[i] = pixels;
152: fixedWidth += pixels;
153: } else if (col instanceof ColumnWeightData) {
154: ColumnWeightData cw = (ColumnWeightData) col;
155: numberOfWeightColumns++;
156: // first time, use the weight specified by the column data,
157: // otherwise use the actual width as the weight
158: // int weight = firstTime ? cw.weight :
159: // tableColumns[i].getWidth();
160: int weight = cw.weight;
161: totalWeight += weight;
162: } else {
163: Assert.isTrue(false, "Unknown column layout data");//$NON-NLS-1$
164: }
165: }
166:
167: // Do we have columns that have a weight
168: if (numberOfWeightColumns > 0) {
169: // Now distribute the rest to the columns with weight.
170: int rest = width - fixedWidth;
171: int totalDistributed = 0;
172: for (int i = 0; i < size; ++i) {
173: ColumnLayoutData col = (ColumnLayoutData) columns
174: .get(i);
175: if (col instanceof ColumnWeightData) {
176: ColumnWeightData cw = (ColumnWeightData) col;
177: // calculate weight as above
178: // int weight = firstTime ? cw.weight :
179: // tableColumns[i].getWidth();
180: int weight = cw.weight;
181: int pixels = totalWeight == 0 ? 0 : weight * rest
182: / totalWeight;
183: if (pixels < cw.minimumWidth) {
184: pixels = cw.minimumWidth;
185: }
186: totalDistributed += pixels;
187: widths[i] = pixels;
188: }
189: }
190:
191: // Distribute any remaining pixels to columns with weight.
192: int diff = rest - totalDistributed;
193: for (int i = 0; diff > 0; ++i) {
194: if (i == size) {
195: i = 0;
196: }
197: ColumnLayoutData col = (ColumnLayoutData) columns
198: .get(i);
199: if (col instanceof ColumnWeightData) {
200: ++widths[i];
201: --diff;
202: }
203: }
204: }
205:
206: firstTime = false;
207:
208: for (int i = 0; i < size; i++) {
209: setWidth(tableColumns[i], widths[i]);
210: }
211: }
212:
213: /**
214: * Set the width of the item.
215: *
216: * @param item
217: * @param width
218: */
219: private void setWidth(Item item, int width) {
220: if (item instanceof TreeColumn) {
221: ((TreeColumn) item).setWidth(width);
222: } else {
223: ((TableColumn) item).setWidth(width);
224: }
225:
226: }
227:
228: /**
229: * Return the columns for the receiver.
230: *
231: * @param composite
232: * @return Item[]
233: */
234: private Item[] getColumns(Composite composite) {
235: if (composite instanceof Tree) {
236: return ((Tree) composite).getColumns();
237: }
238: return ((Table) composite).getColumns();
239: }
240: }
|