/******************************************************************************* * Copyright (c) 2011 Laurent CARON. * 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: * Laurent CARON (laurent.caron@gmail.com) - initial API and implementation *******************************************************************************/ package org.mihalis.opal.header; import org.eclipse.swt.SWT; import org.eclipse.swt.SWTException; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; 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.mihalis.opal.utils.SWTGraphicUtil; /** * Instances of this class provide a header, which is composed of a text, a * description and an image. * <p> * <dl> * <dt><b>Styles:</b></dt> * <dd>BORDER</dd> * <dt><b>Events:</b></dt> * <dd>(none)</dd> * </dl> */ public class Header extends Composite { private Image image; private String title; private String description; private Font titleFont; private Color titleColor; private Image previousGeneratedImage; private Color gradientEnd; private Color gradientStart; private Color separatorColor; /** * Constructs a new instance of this class given its parent and a style * value describing its behavior and appearance. * <p> * The style value is either one of the style constants defined in class * <code>SWT</code> which is applicable to instances of this class, or must * be built by <em>bitwise OR</em>'ing together (that is, using the * <code>int</code> "|" operator) two or more of those <code>SWT</code> * style constants. The class description lists the style constants that are * applicable to the class. Style bits are also inherited from superclasses. * </p> * * @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 * * @exception IllegalArgumentException <ul> * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> * </ul> * @exception SWTException <ul> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the * thread that created the parent</li> * </ul> * */ public Header(final Composite parent, final int style) { super(parent, style); initFontAndColors(); setBackgroundMode(SWT.INHERIT_FORCE); this.addListener(SWT.Resize, new Listener() { @Override public void handleEvent(final Event event) { redrawComposite(); } }); } private void initFontAndColors() { final Font defaultFont; final FontData[] fontData = getFont().getFontData(); if (fontData != null && fontData.length > 0) { final FontData fd = fontData[0]; fd.setStyle(SWT.BOLD); fd.setHeight(fd.getHeight() + 2); defaultFont = new Font(getDisplay(), fd); } else { defaultFont = null; } this.titleFont = defaultFont; SWTGraphicUtil.addDisposer(this, defaultFont); final Color defaultTitleColor = new Color(getDisplay(), 0, 88, 150); this.titleColor = defaultTitleColor; SWTGraphicUtil.addDisposer(this, defaultTitleColor); final Color defaultGradientEndColor = new Color(this.getDisplay(), 239, 239, 239); this.gradientEnd = defaultGradientEndColor; SWTGraphicUtil.addDisposer(this, defaultGradientEndColor); final Color defaultGradientStartColor = new Color(this.getDisplay(), 255, 255, 255); this.gradientStart = defaultGradientStartColor; SWTGraphicUtil.addDisposer(this, defaultGradientStartColor); final Color defaultSeparatorColor = new Color(this.getDisplay(), 229, 229, 229); this.separatorColor = defaultSeparatorColor; SWTGraphicUtil.addDisposer(this, defaultSeparatorColor); } /** * Redraw the composite */ private void redrawComposite() { // Dispose previous content for (final Control c : this.getChildren()) { c.dispose(); } int numberOfColumns = 1; if (this.image != null) { numberOfColumns++; } super.setLayout(new GridLayout(numberOfColumns, false)); createContent(); drawBackground(); } /** * Create the content (title, image, description) */ private void createContent() { if (this.title != null) { createTitle(); } if (this.image != null) { createImage(); } if (this.description != null) { createDescription(); } } /** * Create the title */ private void createTitle() { final Label labelTitle = new Label(this, SWT.NONE); labelTitle.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, false)); labelTitle.setFont(this.titleFont); labelTitle.setForeground(this.titleColor); labelTitle.setText(this.title); } /** * Create the image */ private void createImage() { int numberOfLines = 1; if (this.title != null && this.description != null) { numberOfLines++; } final Label labelImage = new Label(this, SWT.NONE); labelImage.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, false, true, 1, numberOfLines)); labelImage.setImage(this.image); } /** * Create the description */ private void createDescription() { final StyledText labelDescription = new StyledText(this, SWT.WRAP | SWT.READ_ONLY); labelDescription.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true)); labelDescription.setEnabled(false); labelDescription.setFont(getFont()); labelDescription.setForeground(getForeground()); labelDescription.setText(this.description); SWTGraphicUtil.applyHTMLFormating(labelDescription); } /** * Draw the background (a gradient+a separator) */ private void drawBackground() { final Display display = this.getDisplay(); final Rectangle rect = this.getClientArea(); final Image newImage = new Image(display, Math.max(1, rect.width), Math.max(1, rect.height)); final GC gc = new GC(newImage); gc.setForeground(this.gradientStart); gc.setBackground(this.gradientEnd); gc.fillGradientRectangle(rect.x, rect.y, rect.width, rect.height, false); gc.setForeground(this.separatorColor); gc.drawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width, rect.y + rect.height - 1); gc.dispose(); this.setBackgroundImage(newImage); if (this.previousGeneratedImage != null) { this.previousGeneratedImage.dispose(); } this.previousGeneratedImage = newImage; } /** * @see org.eclipse.swt.widgets.Composite#setLayout(org.eclipse.swt.widgets.Layout) */ @Override public void setLayout(final Layout layout) { throw new UnsupportedOperationException("Not supported"); } // ------------------------------------ Getters and Setters /** * Returns the receiver's description if it has one, or null if it does not. * * @return the receiver's description if it has one, or null if it does not * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been * disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the * thread that created the receiver</li> * </ul> */ public String getDescription() { checkWidget(); return this.description; } /** * Returns the receiver's gradient end color. * * @return the receiver's gradient end color * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been * disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the * thread that created the receiver</li> * </ul> */ public Color getGradientEnd() { checkWidget(); return this.gradientEnd; } /** * Returns the receiver's gradient start color. * * @return the receiver's gradient start color * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been * disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the * thread that created the receiver</li> * </ul> */ public Color getGradientStart() { checkWidget(); return this.gradientStart; } /** * Returns the receiver's image if it has one, or null if it does not. * * @return the receiver's image if it has one, or null if it does not * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been * disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the * thread that created the receiver</li> * </ul> */ public Image getImage() { checkWidget(); return this.image; } /** * Returns the receiver's separator color. * * @return the receiver's separator color * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been * disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the * thread that created the receiver</li> * </ul> */ public Color getSeparatorColor() { checkWidget(); return this.separatorColor; } /** * Returns the receiver's title if it has one, or null if it does not. * * @return the receiver's title if it has one, or null if it does not * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been * disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the * thread that created the receiver</li> * </ul> */ public String getTitle() { checkWidget(); return this.title; } /** * Returns the title's color. * * @return the title's color * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been * disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the * thread that created the receiver</li> * </ul> */ public Color getTitleColor() { checkWidget(); return this.titleColor; } /** * Returns the title's font. * * @return the title's font. * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been * disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the * thread that created the receiver</li> * </ul> */ public Font getTitleFont() { checkWidget(); return this.titleFont; } /** * Sets the receiver's description to the argument, which may be null * indicating that no description should be displayed. * * @param description the description of the header (may be null) * * @exception IllegalArgumentException <ul> * <li>ERROR_INVALID_ARGUMENT - if the image has been * disposed</li> * </ul> * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been * disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the * thread that created the receiver</li> * </ul> */ public void setDescription(final String description) { checkWidget(); this.description = description; } /** * Sets the receiver's gradient end color. * * @param gradientEnd the receiver's gradient end color * * @exception IllegalArgumentException <ul> * <li>ERROR_INVALID_ARGUMENT - if the image has been * disposed</li> * </ul> * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been * disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the * thread that created the receiver</li> * </ul> */ public void setGradientEnd(final Color gradientEnd) { checkWidget(); this.gradientEnd = gradientEnd; } /** * Sets the receiver's gradient start color. * * @param gradientStart the receiver's gradient start color * * @exception IllegalArgumentException <ul> * <li>ERROR_INVALID_ARGUMENT - if the image has been * disposed</li> * </ul> * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been * disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the * thread that created the receiver</li> * </ul> */ public void setGradientStart(final Color gradientStart) { checkWidget(); this.gradientStart = gradientStart; } /** * Sets the receiver's image to the argument, which may be null indicating * that no image should be displayed. * * @param image the image to display on the receiver (may be null) * * @exception IllegalArgumentException <ul> * <li>ERROR_INVALID_ARGUMENT - if the image has been * disposed</li> * </ul> * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been * disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the * thread that created the receiver</li> * </ul> */ public void setImage(final Image image) { checkWidget(); this.image = image; } /** * Sets the receiver's separator color. * * @param separatorColor the receiver's separator color * * @exception IllegalArgumentException <ul> * <li>ERROR_INVALID_ARGUMENT - if the image has been * disposed</li> * </ul> * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been * disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the * thread that created the receiver</li> * </ul> */ public void setSeparatorColor(final Color separatorColor) { this.separatorColor = separatorColor; } /** * Sets the receiver's title to the argument, which may be null indicating * that no title should be displayed. * * @param title the title * * @exception IllegalArgumentException <ul> * <li>ERROR_INVALID_ARGUMENT - if the image has been * disposed</li> * </ul> * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been * disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the * thread that created the receiver</li> * </ul> */ public void setTitle(final String title) { checkWidget(); this.title = title; } /** * Sets the receiver's title color. * * @param headerColor the receiver's title color * * @exception IllegalArgumentException <ul> * <li>ERROR_INVALID_ARGUMENT - if the image has been * disposed</li> * </ul> * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been * disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the * thread that created the receiver</li> * </ul> */ public void setTitleColor(final Color headerColor) { checkWidget(); this.titleColor = headerColor; } /** * Sets the receiver's title font. * * @param headerFont the receiver's title font * * @exception IllegalArgumentException <ul> * <li>ERROR_INVALID_ARGUMENT - if the image has been * disposed</li> * </ul> * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been * disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the * thread that created the receiver</li> * </ul> */ public void setTitleFont(final Font headerFont) { checkWidget(); this.titleFont = headerFont; } }