/******************************************************************************* * 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 *******************************************************************************/ package org.eclipse.ui.internal.forms.widgets; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.DragSource; import org.eclipse.swt.dnd.DragSourceEffect; import org.eclipse.swt.dnd.DragSourceEvent; import org.eclipse.swt.dnd.DragSourceListener; import org.eclipse.swt.dnd.DropTarget; import org.eclipse.swt.dnd.DropTargetListener; import org.eclipse.swt.dnd.Transfer; //import org.eclipse.swt.events.MouseEvent; //import org.eclipse.swt.events.MouseMoveListener; //import org.eclipse.swt.events.MouseTrackListener; //import org.eclipse.swt.events.PaintEvent; //import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.FontMetrics; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.internal.graphics.Graphics; import org.eclipse.swt.widgets.Canvas; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Layout; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Menu; import org.eclipse.ui.forms.IFormColors; import org.eclipse.ui.forms.widgets.ILayoutExtension; import org.eclipse.ui.forms.widgets.SizeCache; import org.eclipse.ui.forms.widgets.Twistie; import org.eclipse.ui.internal.forms.IMessageToolTipManager; /** * Form heading title. */ public class TitleRegion extends Canvas { public static final int STATE_NORMAL = 0; public static final int STATE_HOVER_LIGHT = 1; public static final int STATE_HOVER_FULL = 2; private int hoverState; private static final int HMARGIN = 1; private static final int VMARGIN = 5; private static final int SPACING = 5; // RAP [rh] Unused code: was used by onPaint // private static final int ARC_WIDTH = 20; // private static final int ARC_HEIGHT = 20; private Image image; private BusyIndicator busyLabel; private Label titleLabel; private SizeCache titleCache; private int fontHeight = -1; private int fontBaselineHeight = -1; private MenuHyperlink menuHyperlink; private MenuManager menuManager; private boolean dragSupport; private int dragOperations; private Transfer[] dragTransferTypes; private DragSourceListener dragListener; private DragSource dragSource; private Image dragImage; // RAP [rh] Unused code since no MouseTrack- and MouseMove events supported // private class HoverListener implements MouseTrackListener, // MouseMoveListener { // // public void mouseEnter(MouseEvent e) { // setHoverState(STATE_HOVER_FULL); // } // // public void mouseExit(MouseEvent e) { // setHoverState(STATE_NORMAL); // } // // public void mouseHover(MouseEvent e) { // } // // public void mouseMove(MouseEvent e) { // if (e.button > 0) // setHoverState(STATE_NORMAL); // else // setHoverState(STATE_HOVER_FULL); // } // } private class MenuHyperlink extends Twistie { private boolean firstTime = true; public MenuHyperlink(Composite parent, int style) { super(parent, style); setExpanded(true); } public void setExpanded(boolean expanded) { if (firstTime) { super.setExpanded(expanded); firstTime = false; } else { Menu menu = menuManager.createContextMenu(menuHyperlink); // RAP [rh] map position of drop-down menu to the parents' origin Point location = getDisplay().map( getParent(), null, getLocation() ); location.y += this.getSize().y; menu.setLocation( location ); // RAP [rh] END map position of drop-down menu menu.setVisible(true); } } } private class TitleRegionLayout extends Layout implements ILayoutExtension { protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) { return layout(composite, false, 0, 0, wHint, hHint, flushCache); } protected void layout(Composite composite, boolean flushCache) { Rectangle carea = composite.getClientArea(); layout(composite, true, carea.x, carea.y, carea.width, carea.height, flushCache); } private Point layout(Composite composite, boolean move, int x, int y, int width, int height, boolean flushCache) { int iwidth = width == SWT.DEFAULT ? SWT.DEFAULT : width - HMARGIN * 2; Point bsize = null; Point tsize = null; Point msize = null; if (busyLabel != null) { bsize = busyLabel.computeSize(SWT.DEFAULT, SWT.DEFAULT); } if (menuManager != null) { menuHyperlink.setVisible(!menuManager.isEmpty() && titleLabel.getVisible()); if (menuHyperlink.getVisible()) msize = menuHyperlink.computeSize(SWT.DEFAULT, SWT.DEFAULT); } if (flushCache) titleCache.flush(); titleCache.setControl(titleLabel); int twidth = iwidth == SWT.DEFAULT ? iwidth : iwidth - SPACING * 2; if (bsize != null && twidth != SWT.DEFAULT) twidth -= bsize.x + SPACING; if (msize != null && twidth != SWT.DEFAULT) twidth -= msize.x + SPACING; if (titleLabel.getVisible()) { tsize = titleCache.computeSize(twidth, SWT.DEFAULT); if (twidth != SWT.DEFAULT) { // correct for the case when width hint is larger // than the maximum width - this is when the text // can be rendered on one line with width to spare int maxWidth = titleCache.computeSize(SWT.DEFAULT, SWT.DEFAULT).x; tsize.x = Math.min(tsize.x, maxWidth); // System.out.println("twidth="+twidth+", // tsize.x="+tsize.x); //$NON-NLS-1$//$NON-NLS-2$ } } else tsize = new Point(0, 0); Point size = new Point(width, height); if (!move) { // compute size size.x = tsize.x > 0 ? HMARGIN * 2 + SPACING * 2 + tsize.x : 0; size.y = tsize.y; if (bsize != null) { size.x += bsize.x + SPACING; size.y = Math.max(size.y, bsize.y); } if (msize != null) { size.x += msize.x + SPACING; size.y = Math.max(size.y, msize.y); } if (size.y > 0) size.y += VMARGIN * 2; // System.out.println("Compute size: width="+width+", // size.x="+size.x); //$NON-NLS-1$ //$NON-NLS-2$ } else { // position controls int xloc = x + HMARGIN + SPACING; int yloc = y + VMARGIN; if (bsize != null) { busyLabel.setBounds(xloc, // yloc + height / 2 - bsize.y / 2, yloc + (getFontHeight() >= bsize.y ? getFontHeight() : bsize.y) - 1 - bsize.y, bsize.x, bsize.y); xloc += bsize.x + SPACING; } if (titleLabel.getVisible()) { int tw = width - HMARGIN * 2 - SPACING * 2; if (bsize != null) tw -= bsize.x + SPACING; if (msize != null) tw -= msize.x + SPACING; titleLabel.setBounds(xloc, // yloc + height / 2 - tsize.y / 2, yloc, tw, tsize.y); // System.out.println("tw="+tw); //$NON-NLS-1$ xloc += tw + SPACING; } if (msize != null) { menuHyperlink.setBounds(xloc, yloc + getFontHeight() / 2 - msize.y / 2, msize.x, msize.y); } } return size; } public int computeMaximumWidth(Composite parent, boolean changed) { return computeSize(parent, SWT.DEFAULT, SWT.DEFAULT, changed).x; } public int computeMinimumWidth(Composite parent, boolean changed) { return computeSize(parent, 0, SWT.DEFAULT, changed).x; } } public TitleRegion(Composite parent) { super(parent, SWT.NULL); titleLabel = new Label(this, SWT.WRAP); titleLabel.setVisible(false); titleCache = new SizeCache(); super.setLayout(new TitleRegionLayout()); hookHoverListeners(); addListener(SWT.Dispose, new Listener() { public void handleEvent(Event e) { if (dragImage != null) { // RAP [rh] missing Image#dispose() API // dragImage.dispose(); dragImage = null; } } }); } /* (non-Javadoc) * @see org.eclipse.swt.widgets.Control#forceFocus() */ public boolean forceFocus() { return false; } private Color getColor(String key) { return (Color) ((FormHeading) getParent()).colors.get(key); } private void hookHoverListeners() { // RAP [rh] missing MouseTrack-, MouseMove- and Paint events // HoverListener listener = new HoverListener(); // addMouseTrackListener(listener); // addMouseMoveListener(listener); // titleLabel.addMouseTrackListener(listener); // titleLabel.addMouseMoveListener(listener); // addPaintListener(new PaintListener() { // public void paintControl(PaintEvent e) { // onPaint(e); // } // }); } // RAP [rh] Unused code since no Paint events are available // private void onPaint(PaintEvent e) { // if (hoverState == STATE_NORMAL) // return; // GC gc = e.gc; // Rectangle carea = getClientArea(); // gc.setBackground(getHoverBackground()); // int savedAntialias = gc.getAntialias(); // FormUtil.setAntialias(gc, SWT.ON); // gc.fillRoundRectangle(carea.x + HMARGIN, carea.y + 2, carea.width // - HMARGIN * 2, carea.height - 4, ARC_WIDTH, ARC_HEIGHT); // FormUtil.setAntialias(gc, savedAntialias); // } private Color getHoverBackground() { if (hoverState == STATE_NORMAL) return null; Color color = getColor(hoverState == STATE_HOVER_FULL ? IFormColors.H_HOVER_FULL : IFormColors.H_HOVER_LIGHT); if (color == null) color = getDisplay() .getSystemColor( hoverState == STATE_HOVER_FULL ? SWT.COLOR_WIDGET_BACKGROUND : SWT.COLOR_WIDGET_LIGHT_SHADOW); return color; } public void setHoverState(int state) { if (dragSource == null || this.hoverState == state) return; this.hoverState = state; Color color = getHoverBackground(); titleLabel.setBackground(color != null ? color : getColor(FormHeading.COLOR_BASE_BG)); if (busyLabel != null) busyLabel.setBackground(color != null ? color : getColor(FormHeading.COLOR_BASE_BG)); if (menuHyperlink != null) menuHyperlink.setBackground(color != null ? color : getColor(FormHeading.COLOR_BASE_BG)); redraw(); } /** * Fully delegates the size computation to the internal layout manager. */ public final Point computeSize(int wHint, int hHint, boolean changed) { return ((TitleRegionLayout) getLayout()).computeSize(this, wHint, hHint, changed); } public final void setLayout(Layout layout) { // do nothing } public Image getImage() { return image; } public void setImage(Image image) { this.image = image; } public void updateImage(Image newImage, boolean doLayout) { Image theImage = newImage != null ? newImage : this.image; if (theImage != null) { ensureBusyLabelExists(); } else if (busyLabel != null) { if (!busyLabel.isBusy()) { busyLabel.dispose(); busyLabel = null; } } if (busyLabel != null) { busyLabel.setImage(theImage); } if (doLayout) layout(); } public void updateToolTip(String toolTip) { if (busyLabel != null) busyLabel.setToolTipText(toolTip); } public void setBackground(Color bg) { super.setBackground(bg); titleLabel.setBackground(bg); if (busyLabel != null) busyLabel.setBackground(bg); if (menuHyperlink != null) menuHyperlink.setBackground(bg); } public void setForeground(Color fg) { super.setForeground(fg); titleLabel.setForeground(fg); if (menuHyperlink != null) menuHyperlink.setForeground(fg); } public void setText(String text) { if (text != null) titleLabel.setText(text); titleLabel.setVisible(text != null); layout(); redraw(); } public String getText() { return titleLabel.getText(); } public void setFont(Font font) { super.setFont(font); titleLabel.setFont(font); fontHeight = -1; fontBaselineHeight = -1; layout(); } private void ensureBusyLabelExists() { if (busyLabel == null) { busyLabel = new BusyIndicator(this, SWT.NULL); busyLabel.setBackground(getColor(FormHeading.COLOR_BASE_BG)); // RAP [rh] missing MouseTrack- and MouseMove events // HoverListener listener = new HoverListener(); // busyLabel.addMouseTrackListener(listener); // busyLabel.addMouseMoveListener(listener); if (menuManager != null) busyLabel.setMenu(menuManager.createContextMenu(this)); if (dragSupport) addDragSupport(busyLabel, dragOperations, dragTransferTypes, dragListener); IMessageToolTipManager mng = ((FormHeading) getParent()) .getMessageToolTipManager(); if (mng != null) mng.createToolTip(busyLabel, true); } } private void createMenuHyperlink() { menuHyperlink = new MenuHyperlink(this, SWT.NULL); menuHyperlink.setBackground(getColor(FormHeading.COLOR_BASE_BG)); menuHyperlink.setDecorationColor(getForeground()); menuHyperlink.setHoverDecorationColor(getDisplay().getSystemColor(SWT.COLOR_LIST_FOREGROUND)); // RAP [rh] missing MouseTrack- and MouseMove events, missing DnD support // HoverListener listener = new HoverListener(); // menuHyperlink.addMouseTrackListener(listener); // menuHyperlink.addMouseMoveListener(listener); if (dragSupport) addDragSupport(menuHyperlink, dragOperations, dragTransferTypes, dragListener); } /** * 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 boolean setBusy(boolean busy) { if (busy) ensureBusyLabelExists(); else if (busyLabel == null) return false; if (busy == busyLabel.isBusy()) return false; busyLabel.setBusy(busy); if (busyLabel.getImage() == null) { layout(); return true; } return false; } public boolean isBusy() { return busyLabel != null && busyLabel.isBusy(); } /* * Returns the complete height of the font. */ public int getFontHeight() { if (fontHeight == -1) { Font font = getFont(); GC gc = new GC(getDisplay()); gc.setFont(font); FontMetrics fm = gc.getFontMetrics(); fontHeight = fm.getHeight(); gc.dispose(); } return fontHeight; } /* * Returns the height of the font starting at the baseline, * i.e. without the descent. */ public int getFontBaselineHeight() { if (fontBaselineHeight == -1) { Font font = getFont(); GC gc = new GC(getDisplay()); gc.setFont(font); FontMetrics fm = gc.getFontMetrics(); // RAP [if] FontMetrics#getDescent() is missing; inaccurate as baseline-height // is faked by font-height // fontBaselineHeight = fm.getHeight() - fm.getDescent(); fontBaselineHeight = fm.getHeight(); gc.dispose(); } return fontBaselineHeight; } public IMenuManager getMenuManager() { if (menuManager == null) { menuManager = new MenuManager(); Menu menu = menuManager.createContextMenu(this); setMenu(menu); titleLabel.setMenu(menu); if (busyLabel != null) busyLabel.setMenu(menu); createMenuHyperlink(); } return menuManager; } public void addDragSupport(int operations, Transfer[] transferTypes, DragSourceListener listener) { dragSupport = true; dragOperations = operations; dragTransferTypes = transferTypes; dragListener = listener; dragSource = addDragSupport(titleLabel, operations, transferTypes, listener); addDragSupport(this, operations, transferTypes, listener); if (busyLabel != null) addDragSupport(busyLabel, operations, transferTypes, listener); if (menuHyperlink != null) addDragSupport(menuHyperlink, operations, transferTypes, listener); } private DragSource addDragSupport(Control control, int operations, Transfer[] transferTypes, DragSourceListener listener) { DragSource source = new DragSource(control, operations); source.setTransfer(transferTypes); source.addDragListener(listener); source.setDragSourceEffect(new DragSourceEffect(control) { public void dragStart(DragSourceEvent event) { event.image = createDragEffectImage(); } }); return source; } private Image createDragEffectImage() { /* * if (dragImage != null) { dragImage.dispose(); } GC gc = new GC(this); * Point size = getSize(); dragImage = new Image(getDisplay(), size.x, * size.y); gc.copyArea(dragImage, 0, 0); gc.dispose(); return * dragImage; */ return null; } public void addDropSupport(int operations, Transfer[] transferTypes, DropTargetListener listener) { final DropTarget target = new DropTarget(this, operations); target.setTransfer(transferTypes); target.addDropListener(listener); } }