X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.browsing.ui.nattable%2Fsrc%2Forg%2Fsimantics%2Fbrowsing%2Fui%2Fnattable%2FNatTableColumnLayout.java;fp=bundles%2Forg.simantics.browsing.ui.nattable%2Fsrc%2Forg%2Fsimantics%2Fbrowsing%2Fui%2Fnattable%2FNatTableColumnLayout.java;h=b0b6904ce10e14df86dd1c652ad679bb7daa7fda;hp=0000000000000000000000000000000000000000;hb=96bb7ef9cbe42d82eb58306d8f9b62392cc29ba8;hpb=ae5bb63c5c88f6569518fed2a24df86fbd0570ff 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 index 000000000..b0b6904ce --- /dev/null +++ b/bundles/org.simantics.browsing.ui.nattable/src/org/simantics/browsing/ui/nattable/NatTableColumnLayout.java @@ -0,0 +1,282 @@ +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 + * + */ +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 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; + } + + + + +}