]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/NatTableColumnLayout.java
Sync git svn branch with SVN repository r33144.
[simantics/platform.git] / bundles / org.simantics.browsing.ui.nattable / src / org / simantics / browsing / ui / nattable / NatTableColumnLayout.java
diff --git a/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/NatTableColumnLayout.java b/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/NatTableColumnLayout.java
new file mode 100644 (file)
index 0000000..b0b6904
--- /dev/null
@@ -0,0 +1,282 @@
+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