/******************************************************************************* * Copyright (c) 2007, 2014 compeople AG 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: * compeople AG - initial API and implementation *******************************************************************************/ package org.eclipse.riena.ui.swt; import java.util.Collection; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; 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.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Canvas; import org.eclipse.swt.widgets.Composite; import org.eclipse.riena.core.marker.IMarker; import org.eclipse.riena.core.marker.Markable; import org.eclipse.riena.core.util.ListenerList; import org.eclipse.riena.core.util.StringUtils; import org.eclipse.riena.ui.core.marker.DisabledMarker; import org.eclipse.riena.ui.swt.facades.SWTFacade; import org.eclipse.riena.ui.swt.lnf.LnfKeyConstants; import org.eclipse.riena.ui.swt.lnf.LnfManager; import org.eclipse.riena.ui.swt.lnf.renderer.EmbeddedTitlebarRenderer; /** * Title bar of an embedded window (e.g. view of the current sub-module). */ public class EmbeddedTitleBar extends Canvas { private boolean windowActive; private boolean pressed; private boolean hover; private boolean closeButtonPressed; private boolean closeButtonHover; private boolean closeable; private Image image; private String title; private String toolTipText; private Collection<? extends IMarker> markers; protected ListenerList<IEmbeddedTitleBarListener> titleBarListeners; private PaintListener paintListener; private TitlebarMouseListener mouseListener; /** * Constructs a new instance of {@code EmbeddedTitleBar} given its parent * and a style value describing its behavior and appearance. * * @param parent * a composite control which will be the parent of the new * instance (cannot be null) * @param style * the style of control to construct */ public EmbeddedTitleBar(final Composite parent, final int style) { super(parent, style | SWT.DOUBLE_BUFFERED); addListeners(); titleBarListeners = new ListenerList<IEmbeddedTitleBarListener>(IEmbeddedTitleBarListener.class); } /** * Adds a {@code PaintListener} to this {@code EmbeddedTitleBar}. */ protected void addListeners() { paintListener = new PaintListener() { public void paintControl(final PaintEvent e) { onPaint(e); } }; addPaintListener(paintListener); mouseListener = new TitlebarMouseListener(); addMouseListener(mouseListener); final SWTFacade swtFacade = SWTFacade.getDefault(); swtFacade.addMouseMoveListener(this, mouseListener); swtFacade.addMouseTrackListener(this, mouseListener); } /** * Removes the paint listener from this {@code EmbeddedTitleBar}. */ protected void removeListeners() { if (mouseListener != null) { removeMouseListener(mouseListener); final SWTFacade swtFacade = SWTFacade.getDefault(); swtFacade.removeMouseMoveListener(this, mouseListener); swtFacade.removeMouseTrackListener(this, mouseListener); mouseListener = null; } if (paintListener != null) { removePaintListener(paintListener); paintListener = null; } } /** * Paints the title bar.<br> * Configures and calls the renderer that paints the title bar. * * @param e * an event containing information about the paint */ private void onPaint(final PaintEvent e) { final GC gc = e.gc; // title bar getLnfTitlebarRenderer().setActive(isWindowActive()); getLnfTitlebarRenderer().setCloseable(isCloseable()); getLnfTitlebarRenderer().setPressed(isPressed()); getLnfTitlebarRenderer().setHover(isHover()); getLnfTitlebarRenderer().setCloseButtonPressed(isCloseButtonPressed()); getLnfTitlebarRenderer().setCloseButtonHover(isCloseButtonHover()); getLnfTitlebarRenderer().setImage(getImage()); getLnfTitlebarRenderer().setTitle(getTitle()); getLnfTitlebarRenderer().setMarkers(getMarkers()); final Point titlebarSize = getLnfTitlebarRenderer().computeSize(gc, getBounds().width, 0); final Rectangle titlebarBounds = new Rectangle(0, 0, titlebarSize.x, titlebarSize.y); getLnfTitlebarRenderer().setBounds(titlebarBounds); getLnfTitlebarRenderer().paint(gc, this); } /** * Returns the renderer of the title bar. * * @return renderer */ protected EmbeddedTitlebarRenderer getLnfTitlebarRenderer() { EmbeddedTitlebarRenderer renderer = (EmbeddedTitlebarRenderer) LnfManager.getLnf().getRenderer( LnfKeyConstants.SUB_MODULE_VIEW_TITLEBAR_RENDERER); if (renderer == null) { renderer = new EmbeddedTitlebarRenderer(); } return renderer; } public void addEmbeddedTitleBarListener(final IEmbeddedTitleBarListener listener) { titleBarListeners.add(listener); } public void removeEmbeddedTitleBarListener(final IEmbeddedTitleBarListener listener) { titleBarListeners.remove(listener); } /** * @see org.eclipse.swt.widgets.Control#getSize() */ @Override public Point getSize() { Point size = super.getSize(); final GC gc = new GC(this); size = getLnfTitlebarRenderer().computeSize(gc, size.x, size.y); gc.dispose(); return size; } /** * @see org.eclipse.swt.widgets.Control#isFocusControl() */ @Override public boolean isFocusControl() { return false; } /** * @return the windowActive */ public boolean isWindowActive() { return windowActive; } /** * @param windowActive * the windowActive to set */ public void setWindowActive(final boolean active) { if (hasChanged(this.windowActive, active)) { this.windowActive = active; redraw(); } } /** * @return the pressed */ public boolean isPressed() { return pressed; } /** * @param pressed * the pressed to set */ public void setPressed(final boolean pressed) { if (isDisposed()) { return; } if (hasChanged(this.pressed, pressed)) { this.pressed = pressed; redraw(); } } /** * @return the hover */ public boolean isHover() { return hover; } /** * @param hover * the hover to set */ public void setHover(final boolean hover) { if (isDisposed()) { return; } if (hasChanged(this.hover, hover)) { this.hover = hover; redraw(); } } /** * @return the closeable */ public boolean isCloseable() { return closeable; } /** * @param closeable * the closeable to set */ public void setCloseable(final boolean closeable) { if (hasChanged(this.closeable, closeable)) { this.closeable = closeable; redraw(); } } /** * @return the title */ public String getTitle() { return title; } /** * @param title * the title to set */ public void setTitle(final String title) { if (hasChanged(this.title, title)) { this.title = title; redraw(); } } @Override public void setToolTipText(final String text) { toolTipText = text; } @Override public String getToolTipText() { return toolTipText; } /** * @param image * the image to set */ public void setImage(final Image image) { if (hasChanged(this.image, image)) { this.image = image; redraw(); } } /** * @return the image */ public Image getImage() { return image; } public void setMarkers(final Collection<? extends IMarker> markers) { this.markers = markers; } public Collection<? extends IMarker> getMarkers() { return markers; } public <T extends IMarker> Collection<T> getMarkersOfType(final Class<T> type) { return Markable.getMarkersOfType(getMarkers(), type); } protected boolean isOverClose(final Point point) { if (!isCloseable()) { return false; } final boolean inside = getLnfTitlebarRenderer().isInsideCloseButton(point); return inside; } public boolean isTextClipped() { final EmbeddedTitlebarRenderer titlebarRenderer = getLnfTitlebarRenderer(); titlebarRenderer.setBounds(getBounds()); final GC gc = new GC(this); final String clippedText = titlebarRenderer.getClippedText(gc, title); gc.dispose(); if (StringUtils.isEmpty(title)) { return false; } return !title.equals(clippedText); } /** * Compares the two given values. * * @param oldValue * old value * @param newValue * new value * @return true, if value has changed; otherwise false */ private boolean hasChanged(final Object oldValue, final Object newValue) { return (oldValue == null && newValue != null) || (oldValue != null && !oldValue.equals(newValue)); } public void setCloseButtonPressed(final boolean closeButtonPressed) { if (isDisposed()) { return; } if (hasChanged(this.closeButtonPressed, closeButtonPressed)) { this.closeButtonPressed = closeButtonPressed; redraw(); } } public boolean isCloseButtonPressed() { return closeButtonPressed; } public void setCloseButtonHover(final boolean closeButtonHover) { if (isDisposed()) { return; } if (hasChanged(this.closeButtonHover, closeButtonHover) && !isDisposed()) { this.closeButtonHover = closeButtonHover; redraw(); } } public boolean isCloseButtonHover() { return closeButtonHover; } @Override public void dispose() { removeListeners(); super.dispose(); } /** * After any mouse operation a method of this listener is called. The item * under the current mouse position is selected, pressed or "hovered". */ private class TitlebarMouseListener implements MouseListener, MouseTrackListener, MouseMoveListener { public void mouseUp(final MouseEvent e) { if (!isEnabled()) { return; } if (!shouldIgnore(e)) { final Point point = new Point(e.x, e.y); if (isOverClose(point)) { fireClosed(e); } else { fireActivated(e); } setPressed(false); } updateCloseButtonState(e); } public void mouseDown(final MouseEvent e) { if (!isEnabled()) { return; } if (!shouldIgnore(e)) { setPressed(true); } updateCloseButtonState(e); } public void mouseDoubleClick(final MouseEvent e) { // nothing to do } public void mouseEnter(final MouseEvent e) { if (!isEnabled()) { return; } setHover(true); updateCloseButtonState(e); } public void mouseExit(final MouseEvent e) { if (!isEnabled()) { return; } setHover(false); updateCloseButtonState(e); } public void mouseHover(final MouseEvent e) { } public void mouseMove(final MouseEvent e) { updateCloseButtonState(e); } /** * Updates the (hover and pressed) state of the close button. * * @param e */ private void updateCloseButtonState(final MouseEvent e) { final Point point = new Point(e.x, e.y); if (isOverClose(point)) { setCloseButtonHover(isHover()); setCloseButtonPressed(isPressed()); } else { setCloseButtonHover(false); setCloseButtonPressed(false); } } /** * Ignore mouse events if the component is null, not enabled, or the * event is not associated with the left mouse button. */ protected boolean shouldIgnore(final MouseEvent e) { return e.button != 1; } protected boolean isEnabled() { return getMarkersOfType(DisabledMarker.class).isEmpty(); } /** * Informs all listeners that the module is activated. * * @param event * origin mouse event */ private void fireActivated(final MouseEvent event) { for (final IEmbeddedTitleBarListener listener : titleBarListeners.getListeners()) { listener.windowActivated(event); } } /** * Informs all listeners that the close button was clicked. * * @param event * origin mouse event */ private void fireClosed(final MouseEvent event) { for (final IEmbeddedTitleBarListener listener : titleBarListeners.getListeners()) { listener.windowClosed(event); } } } }