-package org.simantics.browsing.ui.nattable;\r
-\r
-import java.util.HashMap;\r
-import java.util.Map;\r
-\r
-import org.eclipse.core.runtime.Assert;\r
-import org.eclipse.jface.util.Util;\r
-import org.eclipse.jface.viewers.ColumnLayoutData;\r
-import org.eclipse.jface.viewers.ColumnPixelData;\r
-import org.eclipse.jface.viewers.ColumnWeightData;\r
-import org.eclipse.nebula.widgets.nattable.NatTable;\r
-import org.eclipse.nebula.widgets.nattable.coordinate.Range;\r
-import org.eclipse.nebula.widgets.nattable.grid.layer.DefaultRowHeaderDataLayer;\r
-import org.eclipse.nebula.widgets.nattable.layer.ILayerListener;\r
-import org.eclipse.nebula.widgets.nattable.layer.event.ColumnDeleteEvent;\r
-import org.eclipse.nebula.widgets.nattable.layer.event.ColumnInsertEvent;\r
-import org.eclipse.nebula.widgets.nattable.layer.event.ILayerEvent;\r
-import org.eclipse.nebula.widgets.nattable.resize.event.ColumnResizeEvent;\r
-import org.eclipse.swt.graphics.Point;\r
-import org.eclipse.swt.graphics.Rectangle;\r
-import org.eclipse.swt.widgets.Composite;\r
-import org.eclipse.swt.widgets.Layout;\r
-import org.eclipse.swt.widgets.Scrollable;\r
-\r
-\r
-/**\r
- * Modified org.eclipse.jface.layout.AbstractColumnLayout and TreeColumnLayout to NatTable compatible.\r
- * \r
- * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
- *\r
- */\r
-public class NatTableColumnLayout extends Layout implements ILayerListener{\r
- private static int COLUMN_TRIM;\r
- static {\r
- if (Util.isWindows()) {\r
- COLUMN_TRIM = 4;\r
- } else if (Util.isMac()) {\r
- COLUMN_TRIM = 24;\r
- } else {\r
- COLUMN_TRIM = 3;\r
- }\r
- }\r
- \r
- NatTable natTable;\r
- GEColumnHeaderDataProvider columnHeaderDataProvider;\r
- DefaultRowHeaderDataLayer rowHeaderDataLayer;\r
- Map<Integer, ColumnLayoutData> layoutDatas = new HashMap<>();\r
- \r
- private boolean inupdateMode = false;\r
-\r
- private boolean relayout = true;\r
- \r
- public NatTableColumnLayout(NatTable natTable, GEColumnHeaderDataProvider columnHeaderDataProvider) {\r
- this.natTable = natTable;\r
- this.columnHeaderDataProvider = columnHeaderDataProvider;\r
- this.natTable.addLayerListener(this);\r
- }\r
- \r
- public NatTableColumnLayout(NatTable natTable, GEColumnHeaderDataProvider columnHeaderDataProvider, DefaultRowHeaderDataLayer rowHeaderDataLayer) {\r
- this.natTable = natTable;\r
- this.columnHeaderDataProvider = columnHeaderDataProvider;\r
- this.natTable.addLayerListener(this);\r
- this.rowHeaderDataLayer = rowHeaderDataLayer;\r
- }\r
- \r
- public void setColumnData(int column, ColumnLayoutData data) {\r
- layoutDatas.put(column, data);\r
- }\r
- \r
- protected void setColumnWidths(Scrollable tree, int[] widths) {\r
- for (int i=0; i < widths.length; i++) {\r
- columnHeaderDataProvider.getDataLayer().setColumnWidthByPosition(i, widths[i]);\r
- }\r
- }\r
- \r
- @Override\r
- public void handleLayerEvent(ILayerEvent event) {\r
- if (inupdateMode)\r
- return;\r
- if (event instanceof ColumnResizeEvent) {\r
- ColumnResizeEvent evt = (ColumnResizeEvent)event;\r
- for (Range r : evt.getColumnPositionRanges()) {\r
- int colIndex = evt.getLayer().getColumnIndexByPosition(r.start);\r
- int w = columnHeaderDataProvider.getDataLayer().getColumnWidthByPosition(colIndex);\r
- setColumnData(colIndex, new ColumnPixelData(w));\r
- }\r
- update();\r
- } else if (event instanceof ColumnInsertEvent ||\r
- event instanceof ColumnDeleteEvent) {\r
- update();\r
- } \r
- }\r
- \r
- boolean updateCalled = false;\r
- \r
- private void update() {\r
- if (updateCalled)\r
- return;\r
- updateCalled = true;\r
- natTable.getDisplay().asyncExec(new Runnable() {\r
- \r
- @Override\r
- public void run() {\r
- if (!natTable.isDisposed()) {\r
- natTable.update();\r
- natTable.getParent().layout();\r
- }\r
- updateCalled = false;\r
- }\r
- });\r
- }\r
-\r
- \r
- @Override\r
- protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {\r
- return computeTableTreeSize(getControl(composite), wHint, hHint);\r
- }\r
- \r
- Scrollable getControl(Composite composite) {\r
- return natTable;\r
- }\r
- \r
- \r
- @Override\r
- protected void layout(Composite composite, boolean flushCache) {\r
- Rectangle area = composite.getClientArea();\r
- Scrollable table = getControl(composite);\r
- int tableWidth = table.getSize().x;\r
- int trim = computeTrim(area, table, tableWidth);\r
- int width = Math.max(0, area.width - trim);\r
- if (rowHeaderDataLayer != null)\r
- width -= rowHeaderDataLayer.getWidth();\r
-\r
- if (width > 1)\r
- layoutTableTree(table, width, area, tableWidth < area.width);\r
-\r
- // For the first time we need to relayout because Scrollbars are not\r
- // calculate appropriately\r
- if (relayout) {\r
- relayout = false;\r
- composite.layout();\r
- }\r
- \r
- }\r
- \r
- protected ColumnLayoutData getLayoutData(Scrollable tableTree,\r
- int columnIndex) {\r
- return layoutDatas.get(columnIndex);\r
- }\r
- \r
- protected int getColumnCount(Scrollable tableTree) {\r
- return columnHeaderDataProvider.getColumnCount();\r
- }\r
- \r
- private Point computeTableTreeSize(Scrollable scrollable, int wHint,\r
- int hHint) {\r
- Point result = scrollable.computeSize(wHint, hHint);\r
-\r
- int width = 0;\r
- int size = getColumnCount(scrollable);\r
- if (rowHeaderDataLayer != null)\r
- width += rowHeaderDataLayer.getWidth();\r
- for (int i = 0; i < size; ++i) {\r
- ColumnLayoutData layoutData = getLayoutData(scrollable, i);\r
- if (layoutData instanceof ColumnPixelData) {\r
- ColumnPixelData col = (ColumnPixelData) layoutData;\r
- width += col.width;\r
- if (col.addTrim) {\r
- width += getColumnTrim();\r
- }\r
- } else if (layoutData instanceof ColumnWeightData) {\r
- ColumnWeightData col = (ColumnWeightData) layoutData;\r
- width += col.minimumWidth;\r
- } else {\r
- Assert.isTrue(false, "Unknown column layout data"); //$NON-NLS-1$\r
- }\r
- }\r
- if (width > result.x)\r
- result.x = width;\r
-\r
- return result;\r
- }\r
- \r
- private void layoutTableTree(final Scrollable scrollable, final int width,\r
- final Rectangle area, final boolean increase) {\r
- final int numberOfColumns = getColumnCount(scrollable);\r
- final int[] widths = new int[numberOfColumns];\r
-\r
- final int[] weightColumnIndices = new int[numberOfColumns];\r
- int numberOfWeightColumns = 0;\r
-\r
- int fixedWidth = 0;\r
- int totalWeight = 0;\r
-\r
- // First calc space occupied by fixed columns\r
- for (int i = 0; i < numberOfColumns; i++) {\r
- ColumnLayoutData col = getLayoutData(scrollable, i);\r
- if (col instanceof ColumnPixelData) {\r
- ColumnPixelData cpd = (ColumnPixelData) col;\r
- int pixels = cpd.width;\r
- if (cpd.addTrim) {\r
- pixels += getColumnTrim();\r
- }\r
- widths[i] = pixels;\r
- fixedWidth += pixels;\r
- } else if (col instanceof ColumnWeightData) {\r
- ColumnWeightData cw = (ColumnWeightData) col;\r
- weightColumnIndices[numberOfWeightColumns] = i;\r
- numberOfWeightColumns++;\r
- totalWeight += cw.weight;\r
- } else {\r
- Assert.isTrue(false, "Unknown column layout data"); //$NON-NLS-1$\r
- }\r
- }\r
-\r
- boolean recalculate;\r
- do {\r
- recalculate = false;\r
- for (int i = 0; i < numberOfWeightColumns; i++) {\r
- int colIndex = weightColumnIndices[i];\r
- ColumnWeightData cw = (ColumnWeightData) getLayoutData(\r
- scrollable, colIndex);\r
- final int minWidth = cw.minimumWidth;\r
- final int allowedWidth = totalWeight == 0 ? 0\r
- : (width - fixedWidth) * cw.weight / totalWeight;\r
- if (allowedWidth < minWidth) {\r
- /*\r
- * if the width assigned by weight is less than the minimum,\r
- * then treat this column as fixed, remove it from weight\r
- * calculations, and recalculate other weights.\r
- */\r
- numberOfWeightColumns--;\r
- totalWeight -= cw.weight;\r
- fixedWidth += minWidth;\r
- widths[colIndex] = minWidth;\r
- System.arraycopy(weightColumnIndices, i + 1,\r
- weightColumnIndices, i, numberOfWeightColumns - i);\r
- recalculate = true;\r
- break;\r
- }\r
- widths[colIndex] = allowedWidth;\r
- }\r
- } while (recalculate);\r
-\r
- if (increase) {\r
- scrollable.setSize(area.width, area.height);\r
- }\r
-\r
- inupdateMode = true;\r
- setColumnWidths(scrollable, widths);\r
- scrollable.update();\r
- inupdateMode = false;\r
-\r
- if (!increase) {\r
- scrollable.setSize(area.width, area.height);\r
- }\r
- }\r
- \r
- private int computeTrim(Rectangle area, Scrollable scrollable,\r
- int currentWidth) {\r
- int trim;\r
-\r
- if (currentWidth > 1) {\r
- trim = currentWidth - scrollable.getClientArea().width;\r
- } else {\r
- // initially, the table has no extend and no client area - use the\r
- // border with\r
- // plus some padding as educated guess\r
- trim = 2 * scrollable.getBorderWidth() + 1;\r
- }\r
-\r
- return trim;\r
- }\r
- \r
- protected int getColumnTrim() {\r
- return COLUMN_TRIM;\r
- }\r
- \r
- \r
- \r
-\r
-}\r
+package org.simantics.browsing.ui.nattable;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.util.Util;
+import org.eclipse.jface.viewers.ColumnLayoutData;
+import org.eclipse.jface.viewers.ColumnPixelData;
+import org.eclipse.jface.viewers.ColumnWeightData;
+import org.eclipse.nebula.widgets.nattable.NatTable;
+import org.eclipse.nebula.widgets.nattable.coordinate.Range;
+import org.eclipse.nebula.widgets.nattable.grid.layer.DefaultRowHeaderDataLayer;
+import org.eclipse.nebula.widgets.nattable.layer.ILayerListener;
+import org.eclipse.nebula.widgets.nattable.layer.event.ColumnDeleteEvent;
+import org.eclipse.nebula.widgets.nattable.layer.event.ColumnInsertEvent;
+import org.eclipse.nebula.widgets.nattable.layer.event.ILayerEvent;
+import org.eclipse.nebula.widgets.nattable.resize.event.ColumnResizeEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Layout;
+import org.eclipse.swt.widgets.Scrollable;
+
+
+/**
+ * Modified org.eclipse.jface.layout.AbstractColumnLayout and TreeColumnLayout to NatTable compatible.
+ *
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
+ *
+ */
+public class NatTableColumnLayout extends Layout implements ILayerListener{
+ private static int COLUMN_TRIM;
+ static {
+ if (Util.isWindows()) {
+ COLUMN_TRIM = 4;
+ } else if (Util.isMac()) {
+ COLUMN_TRIM = 24;
+ } else {
+ COLUMN_TRIM = 3;
+ }
+ }
+
+ NatTable natTable;
+ GEColumnHeaderDataProvider columnHeaderDataProvider;
+ DefaultRowHeaderDataLayer rowHeaderDataLayer;
+ Map<Integer, ColumnLayoutData> layoutDatas = new HashMap<>();
+
+ private boolean inupdateMode = false;
+
+ private boolean relayout = true;
+
+ public NatTableColumnLayout(NatTable natTable, GEColumnHeaderDataProvider columnHeaderDataProvider) {
+ this.natTable = natTable;
+ this.columnHeaderDataProvider = columnHeaderDataProvider;
+ this.natTable.addLayerListener(this);
+ }
+
+ public NatTableColumnLayout(NatTable natTable, GEColumnHeaderDataProvider columnHeaderDataProvider, DefaultRowHeaderDataLayer rowHeaderDataLayer) {
+ this.natTable = natTable;
+ this.columnHeaderDataProvider = columnHeaderDataProvider;
+ this.natTable.addLayerListener(this);
+ this.rowHeaderDataLayer = rowHeaderDataLayer;
+ }
+
+ public void setColumnData(int column, ColumnLayoutData data) {
+ layoutDatas.put(column, data);
+ }
+
+ protected void setColumnWidths(Scrollable tree, int[] widths) {
+ for (int i=0; i < widths.length; i++) {
+ columnHeaderDataProvider.getDataLayer().setColumnWidthByPosition(i, widths[i]);
+ }
+ }
+
+ @Override
+ public void handleLayerEvent(ILayerEvent event) {
+ if (inupdateMode)
+ return;
+ if (event instanceof ColumnResizeEvent) {
+ ColumnResizeEvent evt = (ColumnResizeEvent)event;
+ for (Range r : evt.getColumnPositionRanges()) {
+ int colIndex = evt.getLayer().getColumnIndexByPosition(r.start);
+ int w = columnHeaderDataProvider.getDataLayer().getColumnWidthByPosition(colIndex);
+ setColumnData(colIndex, new ColumnPixelData(w));
+ }
+ update();
+ } else if (event instanceof ColumnInsertEvent ||
+ event instanceof ColumnDeleteEvent) {
+ update();
+ }
+ }
+
+ boolean updateCalled = false;
+
+ private void update() {
+ if (updateCalled)
+ return;
+ updateCalled = true;
+ natTable.getDisplay().asyncExec(new Runnable() {
+
+ @Override
+ public void run() {
+ if (!natTable.isDisposed()) {
+ natTable.update();
+ natTable.getParent().layout();
+ }
+ updateCalled = false;
+ }
+ });
+ }
+
+
+ @Override
+ protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
+ return computeTableTreeSize(getControl(composite), wHint, hHint);
+ }
+
+ Scrollable getControl(Composite composite) {
+ return natTable;
+ }
+
+
+ @Override
+ protected void layout(Composite composite, boolean flushCache) {
+ Rectangle area = composite.getClientArea();
+ Scrollable table = getControl(composite);
+ int tableWidth = table.getSize().x;
+ int trim = computeTrim(area, table, tableWidth);
+ int width = Math.max(0, area.width - trim);
+ if (rowHeaderDataLayer != null)
+ width -= rowHeaderDataLayer.getWidth();
+
+ if (width > 1)
+ layoutTableTree(table, width, area, tableWidth < area.width);
+
+ // For the first time we need to relayout because Scrollbars are not
+ // calculate appropriately
+ if (relayout) {
+ relayout = false;
+ composite.layout();
+ }
+
+ }
+
+ protected ColumnLayoutData getLayoutData(Scrollable tableTree,
+ int columnIndex) {
+ return layoutDatas.get(columnIndex);
+ }
+
+ protected int getColumnCount(Scrollable tableTree) {
+ return columnHeaderDataProvider.getColumnCount();
+ }
+
+ private Point computeTableTreeSize(Scrollable scrollable, int wHint,
+ int hHint) {
+ Point result = scrollable.computeSize(wHint, hHint);
+
+ int width = 0;
+ int size = getColumnCount(scrollable);
+ if (rowHeaderDataLayer != null)
+ width += rowHeaderDataLayer.getWidth();
+ for (int i = 0; i < size; ++i) {
+ ColumnLayoutData layoutData = getLayoutData(scrollable, i);
+ if (layoutData instanceof ColumnPixelData) {
+ ColumnPixelData col = (ColumnPixelData) layoutData;
+ width += col.width;
+ if (col.addTrim) {
+ width += getColumnTrim();
+ }
+ } else if (layoutData instanceof ColumnWeightData) {
+ ColumnWeightData col = (ColumnWeightData) layoutData;
+ width += col.minimumWidth;
+ } else {
+ Assert.isTrue(false, "Unknown column layout data"); //$NON-NLS-1$
+ }
+ }
+ if (width > result.x)
+ result.x = width;
+
+ return result;
+ }
+
+ private void layoutTableTree(final Scrollable scrollable, final int width,
+ final Rectangle area, final boolean increase) {
+ final int numberOfColumns = getColumnCount(scrollable);
+ final int[] widths = new int[numberOfColumns];
+
+ final int[] weightColumnIndices = new int[numberOfColumns];
+ int numberOfWeightColumns = 0;
+
+ int fixedWidth = 0;
+ int totalWeight = 0;
+
+ // First calc space occupied by fixed columns
+ for (int i = 0; i < numberOfColumns; i++) {
+ ColumnLayoutData col = getLayoutData(scrollable, i);
+ if (col instanceof ColumnPixelData) {
+ ColumnPixelData cpd = (ColumnPixelData) col;
+ int pixels = cpd.width;
+ if (cpd.addTrim) {
+ pixels += getColumnTrim();
+ }
+ widths[i] = pixels;
+ fixedWidth += pixels;
+ } else if (col instanceof ColumnWeightData) {
+ ColumnWeightData cw = (ColumnWeightData) col;
+ weightColumnIndices[numberOfWeightColumns] = i;
+ numberOfWeightColumns++;
+ totalWeight += cw.weight;
+ } else {
+ Assert.isTrue(false, "Unknown column layout data"); //$NON-NLS-1$
+ }
+ }
+
+ boolean recalculate;
+ do {
+ recalculate = false;
+ for (int i = 0; i < numberOfWeightColumns; i++) {
+ int colIndex = weightColumnIndices[i];
+ ColumnWeightData cw = (ColumnWeightData) getLayoutData(
+ scrollable, colIndex);
+ final int minWidth = cw.minimumWidth;
+ final int allowedWidth = totalWeight == 0 ? 0
+ : (width - fixedWidth) * cw.weight / totalWeight;
+ if (allowedWidth < minWidth) {
+ /*
+ * if the width assigned by weight is less than the minimum,
+ * then treat this column as fixed, remove it from weight
+ * calculations, and recalculate other weights.
+ */
+ numberOfWeightColumns--;
+ totalWeight -= cw.weight;
+ fixedWidth += minWidth;
+ widths[colIndex] = minWidth;
+ System.arraycopy(weightColumnIndices, i + 1,
+ weightColumnIndices, i, numberOfWeightColumns - i);
+ recalculate = true;
+ break;
+ }
+ widths[colIndex] = allowedWidth;
+ }
+ } while (recalculate);
+
+ if (increase) {
+ scrollable.setSize(area.width, area.height);
+ }
+
+ inupdateMode = true;
+ setColumnWidths(scrollable, widths);
+ scrollable.update();
+ inupdateMode = false;
+
+ if (!increase) {
+ scrollable.setSize(area.width, area.height);
+ }
+ }
+
+ private int computeTrim(Rectangle area, Scrollable scrollable,
+ int currentWidth) {
+ int trim;
+
+ if (currentWidth > 1) {
+ trim = currentWidth - scrollable.getClientArea().width;
+ } else {
+ // initially, the table has no extend and no client area - use the
+ // border with
+ // plus some padding as educated guess
+ trim = 2 * scrollable.getBorderWidth() + 1;
+ }
+
+ return trim;
+ }
+
+ protected int getColumnTrim() {
+ return COLUMN_TRIM;
+ }
+
+
+
+
+}