1 package org.simantics.browsing.ui.nattable;
3 import java.util.HashMap;
6 import org.eclipse.core.runtime.Assert;
7 import org.eclipse.jface.util.Util;
8 import org.eclipse.jface.viewers.ColumnLayoutData;
9 import org.eclipse.jface.viewers.ColumnPixelData;
10 import org.eclipse.jface.viewers.ColumnWeightData;
11 import org.eclipse.nebula.widgets.nattable.NatTable;
12 import org.eclipse.nebula.widgets.nattable.coordinate.Range;
13 import org.eclipse.nebula.widgets.nattable.grid.layer.DefaultRowHeaderDataLayer;
14 import org.eclipse.nebula.widgets.nattable.layer.ILayerListener;
15 import org.eclipse.nebula.widgets.nattable.layer.event.ColumnDeleteEvent;
16 import org.eclipse.nebula.widgets.nattable.layer.event.ColumnInsertEvent;
17 import org.eclipse.nebula.widgets.nattable.layer.event.ILayerEvent;
18 import org.eclipse.nebula.widgets.nattable.resize.event.ColumnResizeEvent;
19 import org.eclipse.swt.graphics.Point;
20 import org.eclipse.swt.graphics.Rectangle;
21 import org.eclipse.swt.widgets.Composite;
22 import org.eclipse.swt.widgets.Layout;
23 import org.eclipse.swt.widgets.Scrollable;
27 * Modified org.eclipse.jface.layout.AbstractColumnLayout and TreeColumnLayout to NatTable compatible.
29 * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
32 public class NatTableColumnLayout extends Layout implements ILayerListener{
33 private static int COLUMN_TRIM;
35 if (Util.isWindows()) {
37 } else if (Util.isMac()) {
45 GEColumnHeaderDataProvider columnHeaderDataProvider;
46 DefaultRowHeaderDataLayer rowHeaderDataLayer;
47 Map<Integer, ColumnLayoutData> layoutDatas = new HashMap<>();
49 private boolean inupdateMode = false;
51 private boolean relayout = true;
53 public NatTableColumnLayout(NatTable natTable, GEColumnHeaderDataProvider columnHeaderDataProvider) {
54 this.natTable = natTable;
55 this.columnHeaderDataProvider = columnHeaderDataProvider;
56 this.natTable.addLayerListener(this);
59 public NatTableColumnLayout(NatTable natTable, GEColumnHeaderDataProvider columnHeaderDataProvider, DefaultRowHeaderDataLayer rowHeaderDataLayer) {
60 this.natTable = natTable;
61 this.columnHeaderDataProvider = columnHeaderDataProvider;
62 this.natTable.addLayerListener(this);
63 this.rowHeaderDataLayer = rowHeaderDataLayer;
66 public void setColumnData(int column, ColumnLayoutData data) {
67 layoutDatas.put(column, data);
70 protected void setColumnWidths(Scrollable tree, int[] widths) {
71 for (int i=0; i < widths.length; i++) {
72 columnHeaderDataProvider.getDataLayer().setColumnWidthByPosition(i, widths[i]);
77 public void handleLayerEvent(ILayerEvent event) {
80 if (event instanceof ColumnResizeEvent) {
81 ColumnResizeEvent evt = (ColumnResizeEvent)event;
82 for (Range r : evt.getColumnPositionRanges()) {
83 int colIndex = evt.getLayer().getColumnIndexByPosition(r.start);
84 int w = columnHeaderDataProvider.getDataLayer().getColumnWidthByPosition(colIndex);
85 setColumnData(colIndex, new ColumnPixelData(w));
88 } else if (event instanceof ColumnInsertEvent ||
89 event instanceof ColumnDeleteEvent) {
94 boolean updateCalled = false;
96 private void update() {
100 natTable.getDisplay().asyncExec(new Runnable() {
104 if (!natTable.isDisposed()) {
106 natTable.getParent().layout();
108 updateCalled = false;
115 protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
116 return computeTableTreeSize(getControl(composite), wHint, hHint);
119 Scrollable getControl(Composite composite) {
125 protected void layout(Composite composite, boolean flushCache) {
126 Rectangle area = composite.getClientArea();
127 Scrollable table = getControl(composite);
128 int tableWidth = table.getSize().x;
129 int trim = computeTrim(area, table, tableWidth);
130 int width = Math.max(0, area.width - trim);
131 if (rowHeaderDataLayer != null)
132 width -= rowHeaderDataLayer.getWidth();
135 layoutTableTree(table, width, area, tableWidth < area.width);
137 // For the first time we need to relayout because Scrollbars are not
138 // calculate appropriately
146 protected ColumnLayoutData getLayoutData(Scrollable tableTree,
148 return layoutDatas.get(columnIndex);
151 protected int getColumnCount(Scrollable tableTree) {
152 return columnHeaderDataProvider.getColumnCount();
155 private Point computeTableTreeSize(Scrollable scrollable, int wHint,
157 Point result = scrollable.computeSize(wHint, hHint);
160 int size = getColumnCount(scrollable);
161 if (rowHeaderDataLayer != null)
162 width += rowHeaderDataLayer.getWidth();
163 for (int i = 0; i < size; ++i) {
164 ColumnLayoutData layoutData = getLayoutData(scrollable, i);
165 if (layoutData instanceof ColumnPixelData) {
166 ColumnPixelData col = (ColumnPixelData) layoutData;
169 width += getColumnTrim();
171 } else if (layoutData instanceof ColumnWeightData) {
172 ColumnWeightData col = (ColumnWeightData) layoutData;
173 width += col.minimumWidth;
175 Assert.isTrue(false, "Unknown column layout data"); //$NON-NLS-1$
178 if (width > result.x)
184 private void layoutTableTree(final Scrollable scrollable, final int width,
185 final Rectangle area, final boolean increase) {
186 final int numberOfColumns = getColumnCount(scrollable);
187 final int[] widths = new int[numberOfColumns];
189 final int[] weightColumnIndices = new int[numberOfColumns];
190 int numberOfWeightColumns = 0;
195 // First calc space occupied by fixed columns
196 for (int i = 0; i < numberOfColumns; i++) {
197 ColumnLayoutData col = getLayoutData(scrollable, i);
198 if (col instanceof ColumnPixelData) {
199 ColumnPixelData cpd = (ColumnPixelData) col;
200 int pixels = cpd.width;
202 pixels += getColumnTrim();
205 fixedWidth += pixels;
206 } else if (col instanceof ColumnWeightData) {
207 ColumnWeightData cw = (ColumnWeightData) col;
208 weightColumnIndices[numberOfWeightColumns] = i;
209 numberOfWeightColumns++;
210 totalWeight += cw.weight;
212 Assert.isTrue(false, "Unknown column layout data"); //$NON-NLS-1$
219 for (int i = 0; i < numberOfWeightColumns; i++) {
220 int colIndex = weightColumnIndices[i];
221 ColumnWeightData cw = (ColumnWeightData) getLayoutData(
222 scrollable, colIndex);
223 final int minWidth = cw.minimumWidth;
224 final int allowedWidth = totalWeight == 0 ? 0
225 : (width - fixedWidth) * cw.weight / totalWeight;
226 if (allowedWidth < minWidth) {
228 * if the width assigned by weight is less than the minimum,
229 * then treat this column as fixed, remove it from weight
230 * calculations, and recalculate other weights.
232 numberOfWeightColumns--;
233 totalWeight -= cw.weight;
234 fixedWidth += minWidth;
235 widths[colIndex] = minWidth;
236 System.arraycopy(weightColumnIndices, i + 1,
237 weightColumnIndices, i, numberOfWeightColumns - i);
241 widths[colIndex] = allowedWidth;
243 } while (recalculate);
246 scrollable.setSize(area.width, area.height);
250 setColumnWidths(scrollable, widths);
252 inupdateMode = false;
255 scrollable.setSize(area.width, area.height);
259 private int computeTrim(Rectangle area, Scrollable scrollable,
263 if (currentWidth > 1) {
264 trim = currentWidth - scrollable.getClientArea().width;
266 // initially, the table has no extend and no client area - use the
268 // plus some padding as educated guess
269 trim = 2 * scrollable.getBorderWidth() + 1;
275 protected int getColumnTrim() {