diff dwtx/jface/layout/AbstractColumnLayout.d @ 10:b6c35faf97c8

Viewers
author Frank Benoit <benoit@tionex.de>
date Mon, 31 Mar 2008 00:47:19 +0200
parents
children ea8ff534f622
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/layout/AbstractColumnLayout.d	Mon Mar 31 00:47:19 2008 +0200
@@ -0,0 +1,320 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation (original file dwtx.ui.texteditor.templates.ColumnLayout)
+ *     Tom Schindl <tom.schindl@bestsolution.at> - refactored to be widget independent (bug 171824)
+ *                                               - fix for bug 178280, 184342, 184045
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.layout.AbstractColumnLayout;
+
+
+
+import dwt.DWT;
+import dwt.graphics.Point;
+import dwt.graphics.Rectangle;
+import dwt.widgets.Composite;
+import dwt.widgets.Event;
+import dwt.widgets.Layout;
+import dwt.widgets.Listener;
+import dwt.widgets.Scrollable;
+import dwt.widgets.Widget;
+import dwtx.core.runtime.Assert;
+import dwtx.jface.util.Policy;
+import dwtx.jface.viewers.ColumnLayoutData;
+import dwtx.jface.viewers.ColumnPixelData;
+import dwtx.jface.viewers.ColumnWeightData;
+import dwtx.jface.viewers.TableLayout;
+
+import dwt.dwthelper.utils;
+
+/**
+ * The AbstractColumnLayout is a {@link Layout} used to set the size of a table
+ * in a consistent way even during a resize unlike a {@link TableLayout} which
+ * only sets initial sizes.
+ *
+ * <p><b>You can only add the layout to a container whose
+ * only child is the table/tree control you want the layouts applied to.</b>
+ * </p>
+ *
+ * @since 3.3
+ */
+abstract class AbstractColumnLayout : Layout {
+    /**
+     * The number of extra pixels taken as horizontal trim by the table column.
+     * To ensure there are N pixels available for the content of the column,
+     * assign N+COLUMN_TRIM for the column width.
+     *
+     * @since 3.1
+     */
+    private static int COLUMN_TRIM;
+
+    static const bool IS_GTK;
+
+    static const String LAYOUT_DATA;
+
+    static this(){
+        COLUMN_TRIM = "carbon".equals(DWT.getPlatform()) ? 24 : 3; //$NON-NLS-1$
+        IS_GTK = "gtk".equals(DWT.getPlatform());//$NON-NLS-1$
+        LAYOUT_DATA = Policy.JFACE ~ ".LAYOUT_DATA"; //$NON-NLS-1$
+    }
+
+    private bool inupdateMode = false;
+
+    private bool relayout = true;
+
+    private Listener resizeListener;
+    private void init_resizeListener(){
+        resizeListener = new class Listener {
+
+            public void handleEvent(Event event) {
+                if( ! inupdateMode ) {
+                    updateColumnData(event.widget);
+                }
+            }
+
+        };
+    }
+    public this(){
+        init_resizeListener();
+    }
+
+    /**
+     * Adds a new column of data to this table layout.
+     *
+     * @param column
+     *            the column
+     *
+     * @param data
+     *            the column layout data
+     */
+    public void setColumnData(Widget column, ColumnLayoutData data) {
+
+        if( column.getData(LAYOUT_DATA) is null ) {
+            column.addListener(DWT.Resize, resizeListener);
+        }
+
+        column.setData(LAYOUT_DATA, data);
+    }
+
+    /**
+     * Compute the size of the table or tree based on the ColumnLayoutData and
+     * the width and height hint.
+     *
+     * @param scrollable
+     *            the widget to compute
+     * @param wHint
+     *            the width hint
+     * @param hHint
+     *            the height hint
+     * @return Point where x is the width and y is the height
+     */
+    private Point computeTableTreeSize(Scrollable scrollable, int wHint,
+            int hHint) {
+        Point result = scrollable.computeSize(wHint, hHint);
+
+        int width = 0;
+        int size = getColumnCount(scrollable);
+        for (int i = 0; i < size; ++i) {
+            ColumnLayoutData layoutData = getLayoutData(scrollable,i);
+            if ( auto col = cast(ColumnPixelData)layoutData) {
+                width += col.width;
+                if (col.addTrim) {
+                    width += COLUMN_TRIM;
+                }
+            } else if ( auto col = cast(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;
+    }
+
+    /**
+     * Layout the scrollable based on the supplied width and area. Only increase
+     * the size of the scrollable if increase is <code>true</code>.
+     *
+     * @param scrollable
+     * @param width
+     * @param area
+     * @param increase
+     */
+    private void layoutTableTree(Scrollable scrollable, int width,
+            Rectangle area, bool increase) {
+        int size = getColumnCount(scrollable);
+        int[] widths = new int[size];
+
+        int[] weightIteration = new int[size];
+        int numberOfWeightColumns = 0;
+
+        int fixedWidth = 0;
+        int minWeightWidth = 0;
+        int totalWeight = 0;
+
+        // First calc space occupied by fixed columns
+        for (int i = 0; i < size; i++) {
+            ColumnLayoutData col = getLayoutData(scrollable,i);
+            if ( auto cpd = cast(ColumnPixelData)col ) {
+                int pixels = cpd.width;
+                if (cpd.addTrim) {
+                    pixels += COLUMN_TRIM;
+                }
+                widths[i] = pixels;
+                fixedWidth += pixels;
+            } else if ( auto cw = cast(ColumnWeightData) col ) {
+                weightIteration[numberOfWeightColumns] = i;
+                numberOfWeightColumns++;
+                totalWeight += cw.weight;
+                minWeightWidth += cw.minimumWidth;
+                widths[i] = cw.minimumWidth;
+            } else {
+                Assert.isTrue(false, "Unknown column layout data"); //$NON-NLS-1$
+            }
+        }
+
+        // Do we have columns that have a weight?
+        int restIncludingMinWidths = width - fixedWidth;
+        int rest = restIncludingMinWidths - minWeightWidth;
+        if (numberOfWeightColumns > 0 && rest > 0) {
+
+            // Modify the weights to reflect what each column already
+            // has due to its minimum. Otherwise, columns with low
+            // minimums get discriminated.
+            int totalWantedPixels = 0;
+            int[] wantedPixels = new int[numberOfWeightColumns];
+            for (int i = 0; i < numberOfWeightColumns; i++) {
+                ColumnWeightData cw = cast(ColumnWeightData) getLayoutData(scrollable,weightIteration[i]);
+                wantedPixels[i] = totalWeight is 0 ? 0 : cw.weight
+                        * restIncludingMinWidths / totalWeight;
+                totalWantedPixels += wantedPixels[i];
+            }
+
+            // Now distribute the rest to the columns with weight.
+            int totalDistributed = 0;
+            for (int i = 0; i < numberOfWeightColumns; ++i) {
+                int pixels = totalWantedPixels is 0 ? 0 : wantedPixels[i]
+                        * rest / totalWantedPixels;
+                totalDistributed += pixels;
+                widths[weightIteration[i]] += pixels;
+            }
+
+            // Distribute any remaining pixels to columns with weight.
+            int diff = rest - totalDistributed;
+            for (int i = 0; diff > 0; i = ((i + 1) % numberOfWeightColumns)) {
+                ++widths[weightIteration[i]];
+                --diff;
+            }
+        }
+
+        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);
+        }
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see dwt.widgets.Layout#computeSize(dwt.widgets.Composite,
+     *      int, int, bool)
+     */
+    protected Point computeSize(Composite composite, int wHint, int hHint,
+            bool flushCache) {
+        return computeTableTreeSize(getControl(composite), wHint, hHint);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see dwt.widgets.Layout#layout(dwt.widgets.Composite,
+     *      bool)
+     */
+    protected void layout(Composite composite, bool 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 (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();
+        }
+    }
+
+    /**
+     * Compute the area required for trim.
+     *
+     * @param area
+     * @param scrollable
+     * @param currentWidth
+     * @return int
+     */
+    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;
+    }
+
+    /**
+     * Get the control being laid out.
+     *
+     * @param composite
+     *            the composite with the layout
+     * @return {@link Scrollable}
+     */
+    Scrollable getControl(Composite composite) {
+        return cast(Scrollable) composite.getChildren()[0];
+    }
+
+    /**
+     * Get the number of columns for the receiver.
+     *
+     * @return the number of columns
+     */
+    abstract int getColumnCount(Scrollable tableTree);
+
+    /**
+     * Set the widths of the columns.
+     *
+     * @param widths
+     */
+    abstract void setColumnWidths(Scrollable tableTree, int[] widths);
+
+    abstract ColumnLayoutData getLayoutData(Scrollable tableTree, int columnIndex);
+
+    abstract void updateColumnData(Widget column);
+}