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