/******************************************************************************* * 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 at gmail dot com) - initial API and implementation *******************************************************************************/ package org.mihalis.opal.tipOfTheDay; import java.util.ArrayList; import java.util.List; import java.util.Random; import org.eclipse.swt.SWT; import org.eclipse.swt.browser.Browser; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import org.mihalis.opal.header.Header; import org.mihalis.opal.utils.ResourceManager; import org.mihalis.opal.utils.SWTGraphicUtil; /** * Instances of this class are a "Tip of Day" box, which is composed of * <p> * <dl> * <dt><b>A tip</b></dt> * <dt><b>2 buttons to navigate between types</b></dt> * <dt><b>A close button</b></dt> * <dt><b>A checkbox "show tip on startup"</b></dt> * <dd>(optional)</dd> * <dt><b>A checkbox "remember the password"</b></dt> * <dd>(optional)</dd> * </dl> * </p> */ public class TipOfTheDay { private static final String BLUE_LIGHT_BULB = "images/light1.png"; private static final String YELLOW_LIGHT_BULB = "images/light2.png"; private static final String DEFAULT_FONT = "Arial"; /** * Types of opal dialog */ public enum TipStyle { TWO_COLUMNS, TWO_COLUMNS_LARGE, HEADER } private final List<String> tips; private boolean displayShowOnStartup = true; private boolean showOnStartup = true; private Shell shell; private Button close; private int index; private Browser tipArea; private String fontName; private TipStyle style; private Image image; /** * Constructor */ public TipOfTheDay() { this.tips = new ArrayList<String>(); this.index = -1; final Font temp = Display.getDefault().getSystemFont(); final FontData[] fontData = temp.getFontData(); if (fontData != null && fontData.length > 0) { this.fontName = fontData[0].getName(); } else { this.fontName = DEFAULT_FONT; } this.style = TipStyle.TWO_COLUMNS; } /** * Open the "tip of the day" box * * @param parent the parent shell */ public void open(final Shell parent) { if (this.index == -1) { this.index = new Random().nextInt(this.tips.size()); } buildShell(parent); if (this.style == TipStyle.HEADER) { buildHeader(); } else { buildLeftColumn(); } buildTip(); buildButtons(); openShell(); } /** * Build the shell * * @param parent parent shell */ private void buildShell(final Shell parent) { this.shell = new Shell(parent, SWT.SYSTEM_MODAL | SWT.TITLE | SWT.BORDER | SWT.CLOSE | SWT.RESIZE); this.shell.setText(ResourceManager.getLabel(ResourceManager.TIP_OF_THE_DAY)); this.shell.setLayout(new GridLayout(this.style == TipStyle.HEADER ? 1 : 2, false)); this.shell.addListener(SWT.Traverse, new Listener() { @Override public void handleEvent(final Event event) { switch (event.detail) { case SWT.TRAVERSE_ESCAPE: TipOfTheDay.this.shell.dispose(); event.detail = SWT.TRAVERSE_NONE; event.doit = false; break; } } }); } /** * Build the header */ private void buildHeader() { final Header header = new Header(this.shell, SWT.NONE); final GridData gd = new GridData(GridData.FILL, GridData.BEGINNING, true, false); gd.heightHint = 80; header.setLayoutData(gd); header.setTitle(ResourceManager.getLabel(ResourceManager.DID_YOU_KNOW)); if (this.image == null) { final Image img = SWTGraphicUtil.createImageFromFile(YELLOW_LIGHT_BULB); header.setImage(img); SWTGraphicUtil.addDisposer(this.shell, img); } else { header.setImage(this.image); } } /** * Build the left column */ private void buildLeftColumn() { final Composite composite = new Composite(this.shell, SWT.NONE); int numberOfRows = 1; if (this.style == TipStyle.TWO_COLUMNS_LARGE) { numberOfRows = this.displayShowOnStartup ? 5 : 4; } final GridData gd = new GridData(GridData.FILL, GridData.BEGINNING, false, true, 1, numberOfRows); composite.setLayoutData(gd); final FillLayout compositeLayout = new FillLayout(); compositeLayout.marginWidth = 2; composite.setLayout(compositeLayout); final Label label = new Label(composite, SWT.NONE); if (this.image == null) { final Image img = SWTGraphicUtil.createImageFromFile(BLUE_LIGHT_BULB); label.setImage(img); SWTGraphicUtil.addDisposer(this.shell, img); } else { label.setImage(this.image); } } /** * Build the tip area */ private void buildTip() { if (this.style == TipStyle.TWO_COLUMNS) { final Group group = new Group(this.shell, SWT.NONE); final GridData gd = new GridData(GridData.FILL, GridData.FILL, true, true); gd.widthHint = 300; gd.heightHint = 120; group.setLayoutData(gd); group.setText(ResourceManager.getLabel(ResourceManager.DID_YOU_KNOW)); final FillLayout fillLayout = new FillLayout(); fillLayout.marginWidth = 15; group.setLayout(fillLayout); this.tipArea = new Browser(group, SWT.BORDER); } else if (this.style == TipStyle.TWO_COLUMNS_LARGE) { final Label title = new Label(this.shell, SWT.NONE); final GridData gd = new GridData(GridData.FILL, GridData.FILL, true, false); gd.verticalIndent = 15; title.setLayoutData(gd); final Font tempFont = SWTGraphicUtil.buildFontFrom(title, SWT.BOLD, 16); title.setText(ResourceManager.getLabel(ResourceManager.TIP_OF_THE_DAY)); title.setFont(tempFont); SWTGraphicUtil.addDisposer(this.shell, tempFont); final Label separator = new Label(this.shell, SWT.SEPARATOR | SWT.HORIZONTAL); separator.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false)); this.tipArea = new Browser(this.shell, SWT.BORDER); final GridData gdTipArea = new GridData(GridData.FILL, GridData.FILL, true, true); gdTipArea.heightHint = 120; this.tipArea.setLayoutData(gdTipArea); } else { this.tipArea = new Browser(this.shell, SWT.BORDER); final GridData gd = new GridData(GridData.FILL, GridData.FILL, true, true); gd.heightHint = 120; this.tipArea.setLayoutData(gd); } fillTipArea(); } /** * Fill the tip area with the selected tip */ private void fillTipArea() { this.tipArea.setText("<html><body bgcolor=\"#ffffff\" text=\"#000000\"><p style=\"font-family:" + // this.fontName + // ";font-size=12px\">" + // this.tips.get(this.index) + // "</p></body></html>"); } /** * Build the button (checkbox, previous tip, next tip, close) */ private void buildButtons() { final Composite composite = new Composite(this.shell, SWT.NONE); int numberOfColumns; if (this.style == TipStyle.HEADER) { numberOfColumns = 1; } else if (this.style == TipStyle.TWO_COLUMNS) { numberOfColumns = 2; } else { numberOfColumns = 1; } final GridData gd = new GridData(GridData.FILL, GridData.BEGINNING, false, false, numberOfColumns, 1); composite.setLayoutData(gd); final GridLayout gridLayout = new GridLayout(); gridLayout.marginWidth = 2; if (this.style == TipStyle.TWO_COLUMNS_LARGE) { composite.setLayout(new GridLayout(3, false)); } else { composite.setLayout(new GridLayout(this.displayShowOnStartup ? 4 : 3, false)); } final GridData gridShowOnStartup, gridPrevious, gridNext, gridClose; if (this.style == TipStyle.TWO_COLUMNS_LARGE) { gridShowOnStartup = new GridData(GridData.BEGINNING, GridData.BEGINNING, true, false, 3, 1); gridPrevious = new GridData(GridData.END, GridData.CENTER, true, false); gridPrevious.widthHint = 120; gridNext = new GridData(GridData.CENTER, GridData.CENTER, false, false); gridNext.widthHint = 120; gridClose = new GridData(GridData.BEGINNING, GridData.CENTER, true, false); gridClose.widthHint = 120; } else { gridShowOnStartup = new GridData(GridData.BEGINNING, GridData.CENTER, true, false); gridPrevious = new GridData(GridData.END, GridData.CENTER, this.showOnStartup ? false : true, false); gridPrevious.widthHint = 120; gridNext = new GridData(GridData.FILL, GridData.CENTER, false, false); gridNext.widthHint = 120; gridClose = new GridData(GridData.FILL, GridData.CENTER, false, false); gridClose.widthHint = 120; } if (this.displayShowOnStartup) { buildShowOnStartup(composite, gridShowOnStartup); } buildPreviousButton(composite, gridPrevious); buildNextButton(composite, gridNext); buildCloseButton(composite, gridClose); } /** * Build the "show on startup" checkbox * * @param composite parent composite * @param gridData associated grid data */ private void buildShowOnStartup(final Composite composite, final GridData gridData) { final Button checkBox = new Button(composite, SWT.CHECK); checkBox.setLayoutData(gridData); checkBox.setText(ResourceManager.getLabel(ResourceManager.SHOW_TIP_AT_STARTUP)); checkBox.setSelection(this.showOnStartup); checkBox.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(final Event event) { TipOfTheDay.this.showOnStartup = checkBox.getSelection(); } }); } /** * Build the "previous tip" button * * @param composite parent composite * @param gridData associated grid data */ private void buildPreviousButton(final Composite composite, final GridData gridData) { final Button previous = new Button(composite, SWT.PUSH); previous.setText(ResourceManager.getLabel(ResourceManager.PREVIOUS_TIP)); previous.setLayoutData(gridData); previous.addSelectionListener(new SelectionAdapter() { /** * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) */ @Override public void widgetSelected(final SelectionEvent e) { if (TipOfTheDay.this.index == 0) { setIndex(TipOfTheDay.this.tips.size() - 1); } else { setIndex(TipOfTheDay.this.index - 1); } } }); } /** * Build the "next tip" button * * @param composite parent composite * @param gridData associated grid data */ private void buildNextButton(final Composite composite, final GridData gridData) { final Button next = new Button(composite, SWT.PUSH); next.setText(ResourceManager.getLabel(ResourceManager.NEXT_TIP)); next.setLayoutData(gridData); next.addSelectionListener(new SelectionAdapter() { /** * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) */ @Override public void widgetSelected(final SelectionEvent e) { if (TipOfTheDay.this.index == TipOfTheDay.this.tips.size() - 1) { setIndex(0); } else { setIndex(TipOfTheDay.this.index + 1); } } }); } /** * Build the "close" button * * @param composite parent composite * @param gridData associated grid data */ private void buildCloseButton(final Composite composite, final GridData gridData) { this.close = new Button(composite, SWT.PUSH); this.close.setText(ResourceManager.getLabel(ResourceManager.CLOSE)); this.close.setLayoutData(gridData); this.close.addSelectionListener(new SelectionAdapter() { /** * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) */ @Override public void widgetSelected(final SelectionEvent e) { TipOfTheDay.this.shell.dispose(); } }); } /** * Open the shell */ private void openShell() { this.shell.setDefaultButton(this.close); this.shell.pack(); this.shell.open(); SWTGraphicUtil.centerShell(this.shell); while (!this.shell.isDisposed()) { if (!this.shell.getDisplay().readAndDispatch()) { this.shell.getDisplay().sleep(); } } } /** * Add a tip * * @param tip tip to add * @return the current object */ public TipOfTheDay addTip(final String tip) { this.tips.add(tip); return this; } /** * @return the image */ public Image getImage() { return this.image; } /** * @return the index of the current tip */ public int getIndex() { return this.index; } /** * @return the style of the window */ public TipStyle getStyle() { return this.style; } /** * @return all the the tips */ public List<String> getTips() { return this.tips; } /** * @return if <code>true</code>, the "Show On Startup" checkbox is displayed */ public boolean isDisplayShowOnStartup() { return this.displayShowOnStartup; } /** * @return the value of the checkbox "Show On Startup" */ public boolean isShowOnStartup() { return this.showOnStartup; } /** * @param if <code>true</code>, the checkbox "Show on startup" is displayed */ public void setDisplayShowOnStartup(final boolean displayShowOnStartup) { this.displayShowOnStartup = displayShowOnStartup; } /** * @param index the index of the selected tip. By default, the tip is chosen * randomly */ public void setIndex(final int index) { if (index < 0 || index >= this.tips.size() || this.tips.get(index) == null) { throw new IllegalArgumentException("Index should be between 0 and " + (this.tips.size() - 1) + " (entered value:" + index + ")"); } this.index = index; if (this.tipArea != null && !this.tipArea.isDisposed()) { fillTipArea(); } } /** * @param image the image to set */ public void setImage(final Image image) { this.image = image; } /** * @param the value of the checkbox "Show on startup" */ public void setShowOnStartup(final boolean showOnStartup) { this.showOnStartup = showOnStartup; } /** * @param style the style of the window */ public void setStyle(final TipStyle style) { this.style = style; } }