KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jface > layout > AbstractColumnLayout


1 /*******************************************************************************
2  * Copyright (c) 2006, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation (original file org.eclipse.ui.texteditor.templates.ColumnLayout)
10  * Tom Schindl <tom.schindl@bestsolution.at> - refactored to be widget independent (bug 171824)
11  * - fix for bug 178280, 184342, 184045
12  *******************************************************************************/

13 package org.eclipse.jface.layout;
14
15
16 import org.eclipse.core.runtime.Assert;
17 import org.eclipse.jface.util.Policy;
18 import org.eclipse.jface.viewers.ColumnLayoutData;
19 import org.eclipse.jface.viewers.ColumnPixelData;
20 import org.eclipse.jface.viewers.ColumnWeightData;
21 import org.eclipse.jface.viewers.TableLayout;
22 import org.eclipse.swt.SWT;
23 import org.eclipse.swt.graphics.Point;
24 import org.eclipse.swt.graphics.Rectangle;
25 import org.eclipse.swt.widgets.Composite;
26 import org.eclipse.swt.widgets.Event;
27 import org.eclipse.swt.widgets.Layout;
28 import org.eclipse.swt.widgets.Listener;
29 import org.eclipse.swt.widgets.Scrollable;
30 import org.eclipse.swt.widgets.Widget;
31
32 /**
33  * The AbstractColumnLayout is a {@link Layout} used to set the size of a table
34  * in a consistent way even during a resize unlike a {@link TableLayout} which
35  * only sets initial sizes.
36  *
37  * <p><b>You can only add the layout to a container whose
38  * only child is the table/tree control you want the layouts applied to.</b>
39  * </p>
40  *
41  * @since 3.3
42  */

43 abstract class AbstractColumnLayout extends Layout {
44     /**
45      * The number of extra pixels taken as horizontal trim by the table column.
46      * To ensure there are N pixels available for the content of the column,
47      * assign N+COLUMN_TRIM for the column width.
48      *
49      * @since 3.1
50      */

51     private static int COLUMN_TRIM = "carbon".equals(SWT.getPlatform()) ? 24 : 3; //$NON-NLS-1$
52

53     static final boolean IS_GTK = "gtk".equals(SWT.getPlatform());//$NON-NLS-1$
54

55     static final String JavaDoc LAYOUT_DATA = Policy.JFACE + ".LAYOUT_DATA"; //$NON-NLS-1$
56

57     private boolean inupdateMode = false;
58     
59     private boolean relayout = true;
60     
61     private Listener resizeListener = new Listener() {
62
63         public void handleEvent(Event event) {
64             if( ! inupdateMode ) {
65                 updateColumnData(event.widget);
66             }
67         }
68         
69     };
70     
71     /**
72      * Adds a new column of data to this table layout.
73      *
74      * @param column
75      * the column
76      *
77      * @param data
78      * the column layout data
79      */

80     public void setColumnData(Widget column, ColumnLayoutData data) {
81
82         if( column.getData(LAYOUT_DATA) == null ) {
83             column.addListener(SWT.Resize, resizeListener);
84         }
85         
86         column.setData(LAYOUT_DATA, data);
87     }
88
89     /**
90      * Compute the size of the table or tree based on the ColumnLayoutData and
91      * the width and height hint.
92      *
93      * @param scrollable
94      * the widget to compute
95      * @param wHint
96      * the width hint
97      * @param hHint
98      * the height hint
99      * @return Point where x is the width and y is the height
100      */

101     private Point computeTableTreeSize(Scrollable scrollable, int wHint,
102             int hHint) {
103         Point result = scrollable.computeSize(wHint, hHint);
104                 
105         int width = 0;
106         int size = getColumnCount(scrollable);
107         for (int i = 0; i < size; ++i) {
108             ColumnLayoutData layoutData = getLayoutData(scrollable,i);
109             if (layoutData instanceof ColumnPixelData) {
110                 ColumnPixelData col = (ColumnPixelData) layoutData;
111                 width += col.width;
112                 if (col.addTrim) {
113                     width += COLUMN_TRIM;
114                 }
115             } else if (layoutData instanceof ColumnWeightData) {
116                 ColumnWeightData col = (ColumnWeightData) layoutData;
117                 width += col.minimumWidth;
118             } else {
119                 Assert.isTrue(false, "Unknown column layout data"); //$NON-NLS-1$
120
}
121         }
122         if (width > result.x)
123             result.x = width;
124         
125         return result;
126     }
127
128     /**
129      * Layout the scrollable based on the supplied width and area. Only increase
130      * the size of the scrollable if increase is <code>true</code>.
131      *
132      * @param scrollable
133      * @param width
134      * @param area
135      * @param increase
136      */

137     private void layoutTableTree(final Scrollable scrollable, final int width,
138             final Rectangle area, final boolean increase) {
139         final int size = getColumnCount(scrollable);
140         final int[] widths = new int[size];
141
142         final int[] weightIteration = new int[size];
143         int numberOfWeightColumns = 0;
144
145         int fixedWidth = 0;
146         int minWeightWidth = 0;
147         int totalWeight = 0;
148
149         // First calc space occupied by fixed columns
150
for (int i = 0; i < size; i++) {
151             ColumnLayoutData col = getLayoutData(scrollable,i);
152             if (col instanceof ColumnPixelData) {
153                 ColumnPixelData cpd = (ColumnPixelData) col;
154                 int pixels = cpd.width;
155                 if (cpd.addTrim) {
156                     pixels += COLUMN_TRIM;
157                 }
158                 widths[i] = pixels;
159                 fixedWidth += pixels;
160             } else if (col instanceof ColumnWeightData) {
161                 ColumnWeightData cw = (ColumnWeightData) col;
162                 weightIteration[numberOfWeightColumns] = i;
163                 numberOfWeightColumns++;
164                 totalWeight += cw.weight;
165                 minWeightWidth += cw.minimumWidth;
166                 widths[i] = cw.minimumWidth;
167             } else {
168                 Assert.isTrue(false, "Unknown column layout data"); //$NON-NLS-1$
169
}
170         }
171
172         // Do we have columns that have a weight?
173
final int restIncludingMinWidths = width - fixedWidth;
174         final int rest = restIncludingMinWidths - minWeightWidth;
175         if (numberOfWeightColumns > 0 && rest > 0) {
176
177             // Modify the weights to reflect what each column already
178
// has due to its minimum. Otherwise, columns with low
179
// minimums get discriminated.
180
int totalWantedPixels = 0;
181             final int[] wantedPixels = new int[numberOfWeightColumns];
182             for (int i = 0; i < numberOfWeightColumns; i++) {
183                 ColumnWeightData cw = (ColumnWeightData) getLayoutData(scrollable,weightIteration[i]);
184                 wantedPixels[i] = totalWeight == 0 ? 0 : cw.weight
185                         * restIncludingMinWidths / totalWeight;
186                 totalWantedPixels += wantedPixels[i];
187             }
188
189             // Now distribute the rest to the columns with weight.
190
int totalDistributed = 0;
191             for (int i = 0; i < numberOfWeightColumns; ++i) {
192                 int pixels = totalWantedPixels == 0 ? 0 : wantedPixels[i]
193                         * rest / totalWantedPixels;
194                 totalDistributed += pixels;
195                 widths[weightIteration[i]] += pixels;
196             }
197
198             // Distribute any remaining pixels to columns with weight.
199
int diff = rest - totalDistributed;
200             for (int i = 0; diff > 0; i = ((i + 1) % numberOfWeightColumns)) {
201                 ++widths[weightIteration[i]];
202                 --diff;
203             }
204         }
205
206         if (increase) {
207             scrollable.setSize(area.width, area.height);
208         }
209
210         inupdateMode = true;
211         setColumnWidths(scrollable, widths);
212         scrollable.update();
213         inupdateMode = false;
214         
215         if (!increase) {
216             scrollable.setSize(area.width, area.height);
217         }
218     }
219
220     /*
221      * (non-Javadoc)
222      *
223      * @see org.eclipse.swt.widgets.Layout#computeSize(org.eclipse.swt.widgets.Composite,
224      * int, int, boolean)
225      */

226     protected Point computeSize(Composite composite, int wHint, int hHint,
227             boolean flushCache) {
228         return computeTableTreeSize(getControl(composite), wHint, hHint);
229     }
230
231     /*
232      * (non-Javadoc)
233      *
234      * @see org.eclipse.swt.widgets.Layout#layout(org.eclipse.swt.widgets.Composite,
235      * boolean)
236      */

237     protected void layout(Composite composite, boolean flushCache) {
238         Rectangle area = composite.getClientArea();
239         Scrollable table = getControl(composite);
240         int tableWidth = table.getSize().x;
241         int trim = computeTrim(area, table, tableWidth);
242         int width = Math.max(0, area.width - trim);
243
244         if (width > 1)
245             layoutTableTree(table, width, area, tableWidth < area.width);
246
247         // For the first time we need to relayout because Scrollbars are not
248
// calculate appropriately
249
if (relayout) {
250             relayout = false;
251             composite.layout();
252         }
253     }
254
255     /**
256      * Compute the area required for trim.
257      *
258      * @param area
259      * @param scrollable
260      * @param currentWidth
261      * @return int
262      */

263     private int computeTrim(Rectangle area, Scrollable scrollable,
264             int currentWidth) {
265         int trim;
266
267         if (currentWidth > 1) {
268             trim = currentWidth - scrollable.getClientArea().width;
269         } else {
270             // initially, the table has no extend and no client area - use the
271
// border with
272
// plus some padding as educated guess
273
trim = 2 * scrollable.getBorderWidth() + 1;
274         }
275
276         return trim;
277     }
278
279     /**
280      * Get the control being laid out.
281      *
282      * @param composite
283      * the composite with the layout
284      * @return {@link Scrollable}
285      */

286     Scrollable getControl(Composite composite) {
287         return (Scrollable) composite.getChildren()[0];
288     }
289
290     /**
291      * Get the number of columns for the receiver.
292      *
293      * @return the number of columns
294      */

295     abstract int getColumnCount(Scrollable tableTree);
296
297     /**
298      * Set the widths of the columns.
299      *
300      * @param widths
301      */

302     abstract void setColumnWidths(Scrollable tableTree, int[] widths);
303     
304     abstract ColumnLayoutData getLayoutData(Scrollable tableTree, int columnIndex);
305     
306     abstract void updateColumnData(Widget column);
307 }
Popular Tags