diff dwtx/ui/internal/forms/widgets/FormHeading.d @ 75:5d489b9f966c

Fix continue porting
author Frank Benoit <benoit@tionex.de>
date Sat, 24 May 2008 05:11:16 +0200
parents
children e193036d82c9
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/ui/internal/forms/widgets/FormHeading.d	Sat May 24 05:11:16 2008 +0200
@@ -0,0 +1,1025 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 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
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.ui.internal.forms.widgets.FormHeading;
+
+import dwtx.ui.internal.forms.widgets.TitleRegion;
+
+import dwt.DWT;
+import dwt.custom.CLabel;
+import dwt.dnd.DragSourceListener;
+import dwt.dnd.DropTargetListener;
+import dwt.dnd.Transfer;
+import dwt.events.DisposeEvent;
+import dwt.events.DisposeListener;
+import dwt.events.MouseEvent;
+import dwt.events.MouseMoveListener;
+import dwt.events.MouseTrackListener;
+import dwt.graphics.Color;
+import dwt.graphics.Font;
+import dwt.graphics.FontMetrics;
+import dwt.graphics.GC;
+import dwt.graphics.Image;
+import dwt.graphics.Point;
+import dwt.graphics.Rectangle;
+import dwt.widgets.Canvas;
+import dwt.widgets.Composite;
+import dwt.widgets.Control;
+import dwt.widgets.Event;
+import dwt.widgets.Layout;
+import dwt.widgets.Listener;
+import dwt.widgets.ToolBar;
+import dwtx.core.runtime.Assert;
+import dwtx.core.runtime.ListenerList;
+import dwtx.jface.action.IMenuManager;
+import dwtx.jface.action.IToolBarManager;
+import dwtx.jface.action.ToolBarManager;
+import dwtx.jface.dialogs.Dialog;
+import dwtx.jface.dialogs.IMessageProvider;
+import dwtx.jface.resource.JFaceResources;
+import dwtx.ui.forms.IFormColors;
+import dwtx.ui.forms.IMessage;
+import dwtx.ui.forms.events.IHyperlinkListener;
+import dwtx.ui.forms.widgets.Hyperlink;
+import dwtx.ui.forms.widgets.ILayoutExtension;
+import dwtx.ui.forms.widgets.SizeCache;
+import dwtx.ui.internal.forms.IMessageToolTipManager;
+import dwtx.ui.internal.forms.MessageManager;
+
+import dwt.dwthelper.utils;
+import tango.util.collection.HashMap;
+
+/**
+ * Form header moved out of the form class.
+ */
+public class FormHeading : Canvas {
+    private static const int TITLE_HMARGIN = 1;
+    private static const int SPACING = 5;
+    private static const int VSPACING = 5;
+    private static const int HMARGIN = 6;
+    private static const int VMARGIN = 1;
+    private static const int CLIENT_MARGIN = 1;
+
+    private static const int SEPARATOR = 1 << 1;
+    private static const int BOTTOM_TOOLBAR = 1 << 2;
+    private static const int BACKGROUND_IMAGE_TILED = 1 << 3;
+    private static const int SEPARATOR_HEIGHT = 2;
+    private static const int MESSAGE_AREA_LIMIT = 50;
+    static IMessage[] NULL_MESSAGE_ARRAY;
+
+    public static const String COLOR_BASE_BG = "baseBg"; //$NON-NLS-1$
+
+    private Image backgroundImage;
+
+    private Image gradientImage;
+
+    HashMap!(String,Object) colors;
+
+    private int flags;
+
+    private GradientInfo gradientInfo;
+
+    private ToolBarManager toolBarManager;
+
+    private SizeCache toolbarCache = new SizeCache();
+
+    private SizeCache clientCache = new SizeCache();
+
+    private SizeCache messageCache = new SizeCache();
+
+    private TitleRegion titleRegion;
+
+    private MessageRegion messageRegion;
+
+    private IMessageToolTipManager messageToolTipManager;
+
+    private Control headClient;
+
+    private class DefaultMessageToolTipManager :
+            IMessageToolTipManager {
+        public void createToolTip(Control control, bool imageLabel) {
+        }
+
+        public void update() {
+            String details = getMessageType() is 0 ? null : MessageManager
+                    .createDetails(getChildrenMessages());
+            if (messageRegion !is null)
+                messageRegion.updateToolTip(details);
+            if (getMessageType() > 0
+                    && (details is null || details.length() is 0))
+                details = getMessage();
+            titleRegion.updateToolTip(details);
+        }
+    }
+
+    private class GradientInfo {
+        Color[] gradientColors;
+
+        int[] percents;
+
+        bool vertical;
+    }
+
+    private class FormHeadingLayout : Layout, ILayoutExtension {
+        public int computeMinimumWidth(Composite composite, bool flushCache) {
+            return computeSize(composite, 5, DWT.DEFAULT, flushCache).x;
+        }
+
+        public int computeMaximumWidth(Composite composite, bool flushCache) {
+            return computeSize(composite, DWT.DEFAULT, DWT.DEFAULT, flushCache).x;
+        }
+
+        public Point computeSize(Composite composite, int wHint, int hHint,
+                bool flushCache) {
+            return layout(composite, false, 0, 0, wHint, hHint, flushCache);
+        }
+
+        protected void layout(Composite composite, bool flushCache) {
+            Rectangle rect = composite.getClientArea();
+            layout(composite, true, rect.x, rect.y, rect.width, rect.height,
+                    flushCache);
+        }
+
+        private Point layout(Composite composite, bool move, int x, int y,
+                int width, int height, bool flushCache) {
+            Point tsize = null;
+            Point msize = null;
+            Point tbsize = null;
+            Point clsize = null;
+
+            if (flushCache) {
+                clientCache.flush();
+                messageCache.flush();
+                toolbarCache.flush();
+            }
+            if (hasToolBar()) {
+                ToolBar tb = toolBarManager.getControl();
+                toolbarCache.setControl(tb);
+                tbsize = toolbarCache.computeSize(DWT.DEFAULT, DWT.DEFAULT);
+            }
+            if (headClient !is null) {
+                clientCache.setControl(headClient);
+                int cwhint = width;
+                if (cwhint !is DWT.DEFAULT) {
+                    cwhint -= HMARGIN * 2;
+                    if (tbsize !is null && getToolBarAlignment() is DWT.BOTTOM)
+                        cwhint -= tbsize.x + SPACING;
+                }
+                clsize = clientCache.computeSize(cwhint, DWT.DEFAULT);
+            }
+            int totalFlexWidth = width;
+            int flexWidth = totalFlexWidth;
+            if (totalFlexWidth !is DWT.DEFAULT) {
+                totalFlexWidth -= TITLE_HMARGIN * 2;
+                // complete right margin
+                if (hasToolBar() && getToolBarAlignment() is DWT.TOP
+                        || hasMessageRegion())
+                    totalFlexWidth -= SPACING;
+                // subtract tool bar
+                if (hasToolBar() && getToolBarAlignment() is DWT.TOP)
+                    totalFlexWidth -= tbsize.x + SPACING;
+                flexWidth = totalFlexWidth;
+                if (hasMessageRegion()) {
+                    // remove message region spacing and divide by 2
+                    flexWidth -= SPACING;
+                    // flexWidth /= 2;
+                }
+            }
+            /*
+             * // compute text and message sizes tsize =
+             * titleRegion.computeSize(flexWidth, DWT.DEFAULT); if (flexWidth !is
+             * DWT.DEFAULT && tsize.x < flexWidth) flexWidth += flexWidth -
+             * tsize.x;
+             *
+             * if (hasMessageRegion()) {
+             * messageCache.setControl(messageRegion.getMessageControl()); msize =
+             * messageCache.computeSize(flexWidth, DWT.DEFAULT); int maxWidth =
+             * messageCache.computeSize(DWT.DEFAULT, DWT.DEFAULT).x; if
+             * (maxWidth < msize.x) { msize.x = maxWidth; // recompute title
+             * with the reclaimed width int tflexWidth = totalFlexWidth -
+             * SPACING - msize.x; tsize = titleRegion.computeSize(tflexWidth,
+             * DWT.DEFAULT); } }
+             */
+            if (!hasMessageRegion()) {
+                tsize = titleRegion.computeSize(flexWidth, DWT.DEFAULT);
+            } else {
+                // Total flexible area in the first row is flexWidth.
+                // Try natural widths of title and
+                Point tsizeNatural = titleRegion.computeSize(DWT.DEFAULT,
+                        DWT.DEFAULT);
+                messageCache.setControl(messageRegion.getMessageControl());
+                Point msizeNatural = messageCache.computeSize(DWT.DEFAULT,
+                        DWT.DEFAULT);
+                // try to fit all
+                tsize = tsizeNatural;
+                msize = msizeNatural;
+                if (flexWidth !is DWT.DEFAULT) {
+                    int needed = tsizeNatural.x + msizeNatural.x;
+                    if (needed > flexWidth) {
+                        // too big - try to limit the message
+                        int mwidth = flexWidth - tsizeNatural.x;
+                        if (mwidth >= MESSAGE_AREA_LIMIT) {
+                            msize.x = mwidth;
+                        } else {
+                            // message is squeezed to the limit
+                            int flex = flexWidth - MESSAGE_AREA_LIMIT;
+                            tsize = titleRegion.computeSize(flex, DWT.DEFAULT);
+                            msize.x = MESSAGE_AREA_LIMIT;
+                        }
+                    }
+                }
+            }
+
+            Point size = new Point(width, height);
+            if (!move) {
+                // compute sizes
+                int width1 = 2 * TITLE_HMARGIN;
+                width1 += tsize.x;
+                if (msize !is null)
+                    width1 += SPACING + msize.x;
+                if (tbsize !is null && getToolBarAlignment() is DWT.TOP)
+                    width1 += SPACING + tbsize.x;
+                if (msize !is null
+                        || (tbsize !is null && getToolBarAlignment() is DWT.TOP))
+                    width1 += SPACING;
+                size.x = width1;
+                if (clsize !is null) {
+                    int width2 = clsize.x;
+                    if (tbsize !is null && getToolBarAlignment() is DWT.BOTTOM)
+                        width2 += SPACING + tbsize.x;
+                    width2 += 2 * HMARGIN;
+                    size.x = Math.max(width1, width2);
+                }
+                // height, first row
+                size.y = tsize.y;
+                if (msize !is null)
+                    size.y = Math.max(msize.y, size.y);
+                if (tbsize !is null && getToolBarAlignment() is DWT.TOP)
+                    size.y = Math.max(tbsize.y, size.y);
+                if (size.y > 0)
+                    size.y += VMARGIN * 2;
+                // add second row
+                int height2 = 0;
+                if (tbsize !is null && getToolBarAlignment() is DWT.BOTTOM)
+                    height2 = tbsize.y;
+                if (clsize !is null)
+                    height2 = Math.max(height2, clsize.y);
+                if (height2 > 0)
+                    size.y += VSPACING + height2 + CLIENT_MARGIN;
+                // add separator
+                if (size.y > 0 && isSeparatorVisible())
+                    size.y += SEPARATOR_HEIGHT;
+            } else {
+                // position controls
+                int xloc = x;
+                int yloc = y + VMARGIN;
+                int row1Height = tsize.y;
+                if (hasMessageRegion())
+                    row1Height = Math.max(row1Height, msize.y);
+                if (hasToolBar() && getToolBarAlignment() is DWT.TOP)
+                    row1Height = Math.max(row1Height, tbsize.y);
+                titleRegion.setBounds(xloc,
+                // yloc + row1Height / 2 - tsize.y / 2,
+                        yloc, tsize.x, tsize.y);
+                xloc += tsize.x;
+
+                if (hasMessageRegion()) {
+                    xloc += SPACING;
+                    int messageOffset = 0;
+                    if (tsize.y > 0) {
+                        // space between title area and title text
+                        int titleLeadingSpace = (tsize.y - titleRegion.getFontHeight()) / 2;
+                        // space between message control and message text
+                        int messageLeadingSpace = (msize.y - messageRegion.getFontHeight()) / 2;
+                        // how much to offset the message so baselines align
+                        messageOffset = (titleLeadingSpace + titleRegion.getFontBaselineHeight())
+                            - (messageLeadingSpace + messageRegion.getFontBaselineHeight());
+                    }
+
+                    messageRegion
+                            .getMessageControl()
+                            .setBounds(
+                                    xloc,
+                                    tsize.y > 0 ? (yloc + messageOffset)
+                                            : (yloc + row1Height / 2 - msize.y / 2),
+                                    msize.x, msize.y);
+                    xloc += msize.x;
+                }
+                if (toolBarManager !is null)
+                    toolBarManager.getControl().setVisible(
+                            !toolBarManager.isEmpty());
+                if (tbsize !is null && getToolBarAlignment() is DWT.TOP) {
+                    ToolBar tbar = toolBarManager.getControl();
+                    tbar.setBounds(x + width - 1 - tbsize.x - HMARGIN, yloc
+                            + row1Height - 1 - tbsize.y, tbsize.x, tbsize.y);
+                }
+                // second row
+                xloc = HMARGIN;
+                yloc += row1Height + VSPACING;
+                int tw = 0;
+
+                if (tbsize !is null && getToolBarAlignment() is DWT.BOTTOM) {
+                    ToolBar tbar = toolBarManager.getControl();
+                    tbar.setBounds(x + width - 1 - tbsize.x - HMARGIN, yloc,
+                            tbsize.x, tbsize.y);
+                    tw = tbsize.x + SPACING;
+                }
+                if (headClient !is null) {
+                    int carea = width - HMARGIN * 2 - tw;
+                    headClient.setBounds(xloc, yloc, carea, clsize.y);
+                }
+            }
+            return size;
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see dwt.widgets.Control#forceFocus()
+     */
+    public bool forceFocus() {
+        return false;
+    }
+
+    private bool hasToolBar() {
+        return toolBarManager !is null && !toolBarManager.isEmpty();
+    }
+
+    private bool hasMessageRegion() {
+        return messageRegion !is null && !messageRegion.isEmpty();
+    }
+
+    private class MessageRegion {
+        private String message;
+        private int messageType;
+        private CLabel messageLabel;
+        private IMessage[] messages;
+        private Hyperlink messageHyperlink;
+        private ListenerList listeners;
+        private Color fg;
+        private int fontHeight = -1;
+        private int fontBaselineHeight = -1;
+
+        public this() {
+        }
+
+        public bool isDisposed() {
+            Control c = getMessageControl();
+            return c !is null && c.isDisposed();
+        }
+
+        public bool isEmpty() {
+            Control c = getMessageControl();
+            if (c is null)
+                return true;
+            return !c.getVisible();
+        }
+
+        public int getFontHeight() {
+            if (fontHeight is -1) {
+                Control c = getMessageControl();
+                if (c is null)
+                    return 0;
+                GC gc = new GC(c.getDisplay());
+                gc.setFont(c.getFont());
+                fontHeight = gc.getFontMetrics().getHeight();
+                gc.dispose();
+            }
+            return fontHeight;
+        }
+
+        public int getFontBaselineHeight() {
+            if (fontBaselineHeight is -1) {
+                Control c = getMessageControl();
+                if (c is null)
+                    return 0;
+                GC gc = new GC(c.getDisplay());
+                gc.setFont(c.getFont());
+                FontMetrics fm = gc.getFontMetrics();
+                fontBaselineHeight = fm.getHeight() - fm.getDescent();
+                gc.dispose();
+            }
+            return fontBaselineHeight;
+        }
+
+        public void showMessage(String newMessage, int newType,
+                IMessage[] messages) {
+            Control oldControl = getMessageControl();
+            int oldType = messageType;
+            this.message = newMessage;
+            this.messageType = newType;
+            this.messages = messages;
+            if (newMessage is null) {
+                // clearing of the message
+                if (oldControl !is null && oldControl.getVisible())
+                    oldControl.setVisible(false);
+                return;
+            }
+            ensureControlExists();
+            if (needHyperlink()) {
+                messageHyperlink.setText(newMessage);
+                messageHyperlink.setHref(messages);
+            } else {
+                messageLabel.setText(newMessage);
+            }
+            if (oldType !is newType)
+                updateForeground();
+        }
+
+        public void updateToolTip(String toolTip) {
+            Control control = getMessageControl();
+            if (control !is null)
+                control.setToolTipText(toolTip);
+        }
+
+        public String getMessage() {
+            return message;
+        }
+
+        public int getMessageType() {
+            return messageType;
+        }
+
+        public IMessage[] getChildrenMessages() {
+            return messages;
+        }
+
+        public String getDetailedMessage() {
+            Control c = getMessageControl();
+            if (c !is null)
+                return c.getToolTipText();
+            return null;
+        }
+
+        public Control getMessageControl() {
+            if (needHyperlink() && messageHyperlink !is null)
+                return messageHyperlink;
+            return messageLabel;
+        }
+
+        public Image getMessageImage() {
+            switch (messageType) {
+            case IMessageProvider.INFORMATION:
+                return JFaceResources.getImage(Dialog.DLG_IMG_MESSAGE_INFO);
+            case IMessageProvider.WARNING:
+                return JFaceResources.getImage(Dialog.DLG_IMG_MESSAGE_WARNING);
+            case IMessageProvider.ERROR:
+                return JFaceResources.getImage(Dialog.DLG_IMG_MESSAGE_ERROR);
+            default:
+                return null;
+            }
+        }
+
+        public void addMessageHyperlinkListener(IHyperlinkListener listener) {
+            if (listeners is null)
+                listeners = new ListenerList();
+            listeners.add(listener);
+            ensureControlExists();
+            if (messageHyperlink !is null)
+                messageHyperlink.addHyperlinkListener(listener);
+            if (listeners.size() is 1)
+                updateForeground();
+        }
+
+        private void removeMessageHyperlinkListener(IHyperlinkListener listener) {
+            if (listeners !is null) {
+                listeners.remove(listener);
+                if (messageHyperlink !is null)
+                    messageHyperlink.removeHyperlinkListener(listener);
+                if (listeners.isEmpty())
+                    listeners = null;
+                ensureControlExists();
+                if (listeners is null && !isDisposed())
+                    updateForeground();
+            }
+        }
+
+        private void ensureControlExists() {
+            if (needHyperlink()) {
+                if (messageLabel !is null)
+                    messageLabel.setVisible(false);
+                if (messageHyperlink is null) {
+                    messageHyperlink = new Hyperlink(this.outer, DWT.NULL);
+                    messageHyperlink.setUnderlined(true);
+                    messageHyperlink.setText(message);
+                    messageHyperlink.setHref(messages);
+                    Object[] llist = listeners.getListeners();
+                    for (int i = 0; i < llist.length; i++)
+                        messageHyperlink
+                                .addHyperlinkListener(cast(IHyperlinkListener) llist[i]);
+                    if (messageToolTipManager !is null)
+                        messageToolTipManager.createToolTip(messageHyperlink, false);
+                } else if (!messageHyperlink.getVisible()) {
+                    messageHyperlink.setText(message);
+                    messageHyperlink.setHref(messages);
+                    messageHyperlink.setVisible(true);
+                }
+            } else {
+                // need a label
+                if (messageHyperlink !is null)
+                    messageHyperlink.setVisible(false);
+                if (messageLabel is null) {
+                    messageLabel = new CLabel(this.outer, DWT.NULL);
+                    messageLabel.setText(message);
+                    if (messageToolTipManager !is null)
+                        messageToolTipManager.createToolTip(messageLabel, false);
+                } else if (!messageLabel.getVisible()) {
+                    messageLabel.setText(message);
+                    messageLabel.setVisible(true);
+                }
+            }
+            layout(true);
+        }
+
+        private bool needHyperlink() {
+            return messageType > 0 && listeners !is null;
+        }
+
+        public void setBackground(Color bg) {
+            if (messageHyperlink !is null)
+                messageHyperlink.setBackground(bg);
+            if (messageLabel !is null)
+                messageLabel.setBackground(bg);
+        }
+
+        public void setForeground(Color fg) {
+            this.fg = fg;
+        }
+
+        private void updateForeground() {
+            Color theFg;
+
+            switch (messageType) {
+            case IMessageProvider.ERROR:
+                theFg = getDisplay().getSystemColor(DWT.COLOR_RED);
+                break;
+            case IMessageProvider.WARNING:
+                theFg = getDisplay().getSystemColor(DWT.COLOR_DARK_YELLOW);
+                break;
+            default:
+                theFg = fg;
+            }
+            getMessageControl().setForeground(theFg);
+        }
+    }
+
+    /**
+     * Creates the form content control as a child of the provided parent.
+     *
+     * @param parent
+     *            the parent widget
+     */
+    public this(Composite parent, int style) {
+        colors = new HashMap!(String,Object);
+        toolbarCache = new SizeCache();
+        clientCache = new SizeCache();
+        messageCache = new SizeCache();
+        messageToolTipManager = new DefaultMessageToolTipManager();
+
+        super(parent, style);
+        setBackgroundMode(DWT.INHERIT_DEFAULT);
+        addListener(DWT.Paint, new class Listener {
+            public void handleEvent(Event e) {
+                onPaint(e.gc);
+            }
+        });
+        addListener(DWT.Dispose, new class Listener {
+            public void handleEvent(Event e) {
+                if (gradientImage !is null) {
+                    FormImages.getInstance().markFinished(gradientImage);
+                    gradientImage = null;
+                }
+            }
+        });
+        addListener(DWT.Resize, new class Listener {
+            public void handleEvent(Event e) {
+                if (gradientInfo !is null
+                        || (backgroundImage !is null && !isBackgroundImageTiled()))
+                    updateGradientImage();
+            }
+        });
+        addMouseMoveListener(new class MouseMoveListener {
+            public void mouseMove(MouseEvent e) {
+                updateTitleRegionHoverState(e);
+            }
+        });
+        addMouseTrackListener(new class MouseTrackListener {
+            public void mouseEnter(MouseEvent e) {
+                updateTitleRegionHoverState(e);
+            }
+
+            public void mouseExit(MouseEvent e) {
+                titleRegion.setHoverState(TitleRegion.STATE_NORMAL);
+            }
+
+            public void mouseHover(MouseEvent e) {
+            }
+        });
+        super.setLayout(new FormHeadingLayout());
+        titleRegion = new TitleRegion(this);
+    }
+
+    /**
+     * Fully delegates the size computation to the internal layout manager.
+     */
+    public final Point computeSize(int wHint, int hHint, bool changed) {
+        return (cast(FormHeadingLayout) getLayout()).computeSize(this, wHint,
+                hHint, changed);
+    }
+
+    /**
+     * Prevents from changing the custom control layout.
+     */
+    public final void setLayout(Layout layout) {
+    }
+
+    /**
+     * Returns the title text that will be rendered at the top of the form.
+     *
+     * @return the title text
+     */
+    public String getText() {
+        return titleRegion.getText();
+    }
+
+    /**
+     * Returns the title image that will be rendered to the left of the title.
+     *
+     * @return the title image
+     * @since 3.2
+     */
+    public Image getImage() {
+        return titleRegion.getImage();
+    }
+
+    /**
+     * Sets the background color of the header.
+     */
+    public void setBackground(Color bg) {
+        super.setBackground(bg);
+        internalSetBackground(bg);
+    }
+
+    private void internalSetBackground(Color bg) {
+        titleRegion.setBackground(bg);
+        if (messageRegion !is null)
+            messageRegion.setBackground(bg);
+        if (toolBarManager !is null)
+            toolBarManager.getControl().setBackground(bg);
+        putColor(COLOR_BASE_BG, bg);
+    }
+
+    /**
+     * Sets the foreground color of the header.
+     */
+    public void setForeground(Color fg) {
+        super.setForeground(fg);
+        titleRegion.setForeground(fg);
+        if (messageRegion !is null)
+            messageRegion.setForeground(fg);
+    }
+
+    /**
+     * Sets the text to be rendered at the top of the form above the body as a
+     * title.
+     *
+     * @param text
+     *            the title text
+     */
+    public void setText(String text) {
+        titleRegion.setText(text);
+    }
+
+    public void setFont(Font font) {
+        super.setFont(font);
+        titleRegion.setFont(font);
+    }
+
+    /**
+     * Sets the image to be rendered to the left of the title.
+     *
+     * @param image
+     *            the title image or <code>null</code> to show no image.
+     * @since 3.2
+     */
+    public void setImage(Image image) {
+        titleRegion.setImage(image);
+        if (messageRegion !is null)
+            titleRegion.updateImage(messageRegion.getMessageImage(), true);
+        else
+            titleRegion.updateImage(null, true);
+    }
+
+    public void setTextBackground(Color[] gradientColors, int[] percents,
+            bool vertical) {
+        if (gradientColors !is null) {
+            gradientInfo = new GradientInfo();
+            gradientInfo.gradientColors = gradientColors;
+            gradientInfo.percents = percents;
+            gradientInfo.vertical = vertical;
+            setBackground(null);
+            updateGradientImage();
+        } else {
+            // reset
+            gradientInfo = null;
+            if (gradientImage !is null) {
+                FormImages.getInstance().markFinished(gradientImage);
+                gradientImage = null;
+                setBackgroundImage(null);
+            }
+        }
+    }
+
+    public void setHeadingBackgroundImage(Image image) {
+        this.backgroundImage = image;
+        if (image !is null)
+            setBackground(null);
+        if (isBackgroundImageTiled()) {
+            setBackgroundImage(image);
+        } else
+            updateGradientImage();
+    }
+
+    public Image getHeadingBackgroundImage() {
+        return backgroundImage;
+    }
+
+    public void setBackgroundImageTiled(bool tiled) {
+        if (tiled)
+            flags |= BACKGROUND_IMAGE_TILED;
+        else
+            flags &= ~BACKGROUND_IMAGE_TILED;
+        setHeadingBackgroundImage(this.backgroundImage);
+    }
+
+    public bool isBackgroundImageTiled() {
+        return (flags & BACKGROUND_IMAGE_TILED) !is 0;
+    }
+
+    public void setBackgroundImage(Image image) {
+        super.setBackgroundImage(image);
+        if (image !is null) {
+            internalSetBackground(null);
+        }
+    }
+
+    /**
+     * Returns the tool bar manager that is used to manage tool items in the
+     * form's title area.
+     *
+     * @return form tool bar manager
+     */
+    public IToolBarManager getToolBarManager() {
+        if (toolBarManager is null) {
+            toolBarManager = new ToolBarManager(DWT.FLAT);
+            ToolBar toolbar = toolBarManager.createControl(this);
+            toolbar.setBackground(getBackground());
+            toolbar.setForeground(getForeground());
+            toolbar.setCursor(FormsResources.getHandCursor());
+            addDisposeListener(new class DisposeListener {
+                public void widgetDisposed(DisposeEvent e) {
+                    if (toolBarManager !is null) {
+                        toolBarManager.dispose();
+                        toolBarManager = null;
+                    }
+                }
+            });
+        }
+        return toolBarManager;
+    }
+
+    /**
+     * Returns the menu manager that is used to manage tool items in the form's
+     * title area.
+     *
+     * @return form drop-down menu manager
+     * @since 3.3
+     */
+    public IMenuManager getMenuManager() {
+        return titleRegion.getMenuManager();
+    }
+
+    /**
+     * Updates the local tool bar manager if used. Does nothing if local tool
+     * bar manager has not been created yet.
+     */
+    public void updateToolBar() {
+        if (toolBarManager !is null)
+            toolBarManager.update(false);
+    }
+
+    private void onPaint(GC gc) {
+        if (!isSeparatorVisible() && getBackgroundImage() is null)
+            return;
+        Rectangle carea = getClientArea();
+        Image buffer = new Image(getDisplay(), carea.width, carea.height);
+        buffer.setBackground(getBackground());
+        GC igc = new GC(buffer);
+        igc.setBackground(getBackground());
+        igc.fillRectangle(0, 0, carea.width, carea.height);
+        if (getBackgroundImage() !is null) {
+            if (gradientInfo !is null)
+                drawBackground(igc, carea.x, carea.y, carea.width, carea.height);
+            else {
+                Image bgImage = getBackgroundImage();
+                Rectangle ibounds = bgImage.getBounds();
+                drawBackground(igc, carea.x, carea.y, ibounds.width,
+                        ibounds.height);
+            }
+        }
+
+        if (isSeparatorVisible()) {
+            // bg separator
+            if (hasColor(IFormColors.H_BOTTOM_KEYLINE1))
+                igc.setForeground(getColor(IFormColors.H_BOTTOM_KEYLINE1));
+            else
+                igc.setForeground(getBackground());
+            igc.drawLine(carea.x, carea.height - 2, carea.x + carea.width - 1,
+                    carea.height - 2);
+            if (hasColor(IFormColors.H_BOTTOM_KEYLINE2))
+                igc.setForeground(getColor(IFormColors.H_BOTTOM_KEYLINE2));
+            else
+                igc.setForeground(getForeground());
+            igc.drawLine(carea.x, carea.height - 1, carea.x + carea.width - 1,
+                    carea.height - 1);
+        }
+        igc.dispose();
+        gc.drawImage(buffer, carea.x, carea.y);
+        buffer.dispose();
+    }
+
+    private void updateTitleRegionHoverState(MouseEvent e) {
+        Rectangle titleRect = titleRegion.getBounds();
+        titleRect.width += titleRect.x + 15;
+        titleRect.height += titleRect.y + 15;
+        titleRect.x = 0;
+        titleRect.y = 0;
+        if (titleRect.contains(e.x, e.y))
+            titleRegion.setHoverState(TitleRegion.STATE_HOVER_LIGHT);
+        else
+            titleRegion.setHoverState(TitleRegion.STATE_NORMAL);
+    }
+
+    private void updateGradientImage() {
+        Rectangle rect = getBounds();
+        if (gradientImage !is null) {
+            FormImages.getInstance().markFinished(gradientImage);
+            gradientImage = null;
+        }
+        if (gradientInfo !is null) {
+            gradientImage = FormImages.getInstance().getGradient(getDisplay(), gradientInfo.gradientColors, gradientInfo.percents,
+                    gradientInfo.vertical ? rect.height : rect.width, gradientInfo.vertical, getColor(COLOR_BASE_BG));
+        } else if (backgroundImage !is null && !isBackgroundImageTiled()) {
+            gradientImage = new Image(getDisplay(), Math.max(rect.width, 1),
+                    Math.max(rect.height, 1));
+            gradientImage.setBackground(getBackground());
+            GC gc = new GC(gradientImage);
+            gc.drawImage(backgroundImage, 0, 0);
+            gc.dispose();
+        }
+        setBackgroundImage(gradientImage);
+    }
+
+    public bool isSeparatorVisible() {
+        return (flags & SEPARATOR) !is 0;
+    }
+
+    public void setSeparatorVisible(bool addSeparator) {
+        if (addSeparator)
+            flags |= SEPARATOR;
+        else
+            flags &= ~SEPARATOR;
+    }
+
+    public void setToolBarAlignment(int alignment) {
+        if (alignment is DWT.BOTTOM)
+            flags |= BOTTOM_TOOLBAR;
+        else
+            flags &= ~BOTTOM_TOOLBAR;
+    }
+
+    public int getToolBarAlignment() {
+        return (flags & BOTTOM_TOOLBAR) !is 0 ? DWT.BOTTOM : DWT.TOP;
+    }
+
+    public void addMessageHyperlinkListener(IHyperlinkListener listener) {
+        ensureMessageRegionExists();
+        messageRegion.addMessageHyperlinkListener(listener);
+    }
+
+    public void removeMessageHyperlinkListener(IHyperlinkListener listener) {
+        if (messageRegion !is null)
+            messageRegion.removeMessageHyperlinkListener(listener);
+    }
+
+    public String getMessage() {
+        return messageRegion !is null ? messageRegion.getMessage() : null;
+    }
+
+    public int getMessageType() {
+        return messageRegion !is null ? messageRegion.getMessageType() : 0;
+    }
+
+    public IMessage[] getChildrenMessages() {
+        return messageRegion !is null ? messageRegion.getChildrenMessages()
+                : NULL_MESSAGE_ARRAY;
+    }
+
+    private void ensureMessageRegionExists() {
+        // ensure message region exists
+        if (messageRegion is null)
+            messageRegion = new MessageRegion();
+    }
+
+    public void showMessage(String newMessage, int type, IMessage[] messages) {
+        if (messageRegion is null) {
+            // check the trivial case
+            if (newMessage is null)
+                return;
+        } else if (messageRegion.isDisposed())
+            return;
+        ensureMessageRegionExists();
+        messageRegion.showMessage(newMessage, type, messages);
+        titleRegion.updateImage(messageRegion.getMessageImage(), false);
+        if (messageToolTipManager !is null)
+            messageToolTipManager.update();
+        layout();
+        redraw();
+    }
+
+    /**
+     * Tests if the form is in the 'busy' state.
+     *
+     * @return <code>true</code> if busy, <code>false</code> otherwise.
+     */
+
+    public bool isBusy() {
+        return titleRegion.isBusy();
+    }
+
+    /**
+     * Sets the form's busy state. Busy form will display 'busy' animation in
+     * the area of the title image.
+     *
+     * @param busy
+     *            the form's busy state
+     */
+
+    public void setBusy(bool busy) {
+        if (titleRegion.setBusy(busy))
+            layout();
+    }
+
+    public Control getHeadClient() {
+        return headClient;
+    }
+
+    public void setHeadClient(Control headClient) {
+        if (headClient !is null)
+            Assert.isTrue(headClient.getParent() is this);
+        this.headClient = headClient;
+        layout();
+    }
+
+    public void putColor(String key, Color color) {
+        if (color is null)
+            colors.remove(key);
+        else
+            colors.put(key, color);
+    }
+
+    public Color getColor(String key) {
+        return cast(Color) colors.get(key);
+    }
+
+    public bool hasColor(String key) {
+        return colors.containsKey(key);
+    }
+
+    public void addDragSupport(int operations, Transfer[] transferTypes,
+            DragSourceListener listener) {
+        titleRegion.addDragSupport(operations, transferTypes, listener);
+    }
+
+    public void addDropSupport(int operations, Transfer[] transferTypes,
+            DropTargetListener listener) {
+        titleRegion.addDropSupport(operations, transferTypes, listener);
+    }
+
+    public IMessageToolTipManager getMessageToolTipManager() {
+        return messageToolTipManager;
+    }
+
+    public void setMessageToolTipManager(
+            IMessageToolTipManager messageToolTipManager) {
+        this.messageToolTipManager = messageToolTipManager;
+    }
+}