| /******************************************************************************* |
| * Copyright (c) 2005, 2016 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.help.ui.internal.views; |
| |
| import org.eclipse.help.ui.internal.Messages; |
| import org.eclipse.jface.action.ContributionItem; |
| import org.eclipse.jface.action.IContributionItem; |
| import org.eclipse.jface.action.ToolBarManager; |
| import org.eclipse.jface.dialogs.DialogTray; |
| import org.eclipse.jface.dialogs.IDialogPage; |
| import org.eclipse.jface.dialogs.IPageChangeProvider; |
| import org.eclipse.jface.dialogs.IPageChangedListener; |
| import org.eclipse.jface.dialogs.PageChangedEvent; |
| import org.eclipse.jface.dialogs.TrayDialog; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.graphics.Color; |
| import org.eclipse.swt.graphics.GC; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.swt.graphics.ImageData; |
| import org.eclipse.swt.graphics.PaletteData; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.graphics.RGB; |
| 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.Listener; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.swt.widgets.TabFolder; |
| import org.eclipse.swt.widgets.TabItem; |
| import org.eclipse.swt.widgets.ToolBar; |
| import org.eclipse.swt.widgets.ToolItem; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.forms.HyperlinkGroup; |
| import org.eclipse.ui.forms.widgets.FormToolkit; |
| |
| /** |
| * The tray that appears on the side of dialogs when the user summons context |
| * help or a cheat sheet follows the user into a dialog. |
| */ |
| public class HelpTray extends DialogTray implements IPageChangedListener { |
| |
| public static final int MINIMUM_HEIGHT = 450; |
| private static final int DEFAULT_WIDTH = 210; |
| |
| private int originalHeight; |
| private int heightAdded; |
| |
| private FormToolkit toolkit; |
| private ReusableHelpPart helpPart; |
| private Shell shell; |
| private IContributionItem closeAction; |
| private Image normal; |
| private Image hover; |
| |
| /** |
| * Creates any actions needed by the tray. |
| */ |
| private void createActions() { |
| createImages(); |
| closeAction = new ContributionItem() { |
| |
| @Override |
| public void fill(ToolBar parent, int index) { |
| final ToolItem item = new ToolItem(parent, SWT.PUSH); |
| item.setImage(normal); |
| item.setHotImage(hover); |
| item.setToolTipText(Messages.ReusableHelpPart_closeAction_tooltip); |
| item.addListener(SWT.Selection, event -> { |
| // close the tray |
| TrayDialog dialog = (TrayDialog) shell.getData(); |
| dialog.closeTray(); |
| }); |
| } |
| }; |
| } |
| |
| /** |
| * Creates the contents of the tray. |
| * |
| * @param parent the parent composite that will contain the tray |
| */ |
| @Override |
| protected Control createContents(Composite parent) { |
| // if the dialog is too short, make it taller |
| ensureMinimumHeight(parent.getShell()); |
| |
| toolkit = new FormToolkit(parent.getDisplay()); |
| toolkit.getHyperlinkGroup().setHyperlinkUnderlineMode(HyperlinkGroup.UNDERLINE_HOVER); |
| toolkit.getColors().initializeSectionToolBarColors(); |
| Composite container = new Composite(parent, SWT.NONE); |
| GridLayout layout = new GridLayout(); |
| layout.marginWidth = layout.marginHeight = 0; |
| layout.verticalSpacing = 0; |
| container.setLayout(layout); |
| container.addListener(SWT.Dispose, event -> dispose()); |
| |
| ToolBarManager tbm = new ToolBarManager(SWT.FLAT); |
| tbm.createControl(container); |
| GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_END); |
| gd.grabExcessHorizontalSpace = true; |
| tbm.getControl().setLayoutData(gd); |
| Label separator = new Label(container, SWT.SEPARATOR | SWT.HORIZONTAL); |
| gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL); |
| gd.heightHint = 1; |
| separator.setLayoutData(gd); |
| helpPart = new ReusableHelpPart(PlatformUI.getWorkbench().getProgressService()); |
| helpPart.init(null, tbm, null, null, null); |
| helpPart.setDefaultContextHelpText(Messages.HelpView_defaultText); |
| helpPart.createControl(container, toolkit); |
| gd = new GridData(GridData.FILL_BOTH); |
| gd.widthHint = DEFAULT_WIDTH; |
| helpPart.getControl().setLayoutData(gd); |
| |
| createActions(); |
| tbm.add(closeAction); |
| |
| shell = parent.getShell(); |
| hookPageChangeListener(shell); |
| helpPart.getControl().addListener(SWT.Dispose, event -> unhookPageChangeListener(shell)); |
| |
| return container; |
| } |
| |
| /** |
| * Creates any custom needed by the tray, such as the close button. |
| */ |
| private void createImages() { |
| Display display = Display.getCurrent(); |
| int[] shape = new int[] { |
| 3, 3, 5, 3, 7, 5, 8, 5, 10, 3, 12, 3, |
| 12, 5, 10, 7, 10, 8, 12,10, 12,12, |
| 10,12, 8, 10, 7, 10, 5, 12, 3, 12, |
| 3, 10, 5, 8, 5, 7, 3, 5 |
| }; |
| |
| /* |
| * Use magenta as transparency color since it is used infrequently. |
| */ |
| Color border = display.getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW); |
| Color background = display.getSystemColor(SWT.COLOR_LIST_BACKGROUND); |
| Color backgroundHot = new Color(display, new RGB(252, 160, 160)); |
| Color transparent = display.getSystemColor(SWT.COLOR_MAGENTA); |
| |
| PaletteData palette = new PaletteData(new RGB[] { transparent.getRGB(), border.getRGB(), background.getRGB(), backgroundHot.getRGB() }); |
| ImageData data = new ImageData(16, 16, 8, palette); |
| data.transparentPixel = 0; |
| |
| normal = new Image(display, data); |
| normal.setBackground(transparent); |
| GC gc = new GC(normal); |
| gc.setBackground(background); |
| gc.fillPolygon(shape); |
| gc.setForeground(border); |
| gc.drawPolygon(shape); |
| gc.dispose(); |
| |
| hover = new Image(display, data); |
| hover.setBackground(transparent); |
| gc = new GC(hover); |
| gc.setBackground(backgroundHot); |
| gc.fillPolygon(shape); |
| gc.setForeground(border); |
| gc.drawPolygon(shape); |
| gc.dispose(); |
| |
| backgroundHot.dispose(); |
| } |
| |
| /** |
| * Disposes any resources used by the tray. |
| */ |
| private void dispose() { |
| normal.dispose(); |
| hover.dispose(); |
| toolkit.dispose(); |
| helpPart.dispose(); |
| |
| /* |
| * Shell is about to be closed. Add a one-time-only listener |
| * that will return the dialog height back to original. |
| */ |
| shell.addListener(SWT.Resize, new Listener() { |
| |
| @Override |
| public void handleEvent(Event event) { |
| shell.removeListener(SWT.Resize, this); |
| Point p = shell.getSize(); |
| if (heightAdded > 0 && p.y > originalHeight) { |
| p.y = Math.max(p.y - heightAdded, originalHeight); |
| shell.setSize(p); |
| } |
| } |
| }); |
| } |
| |
| /** |
| * Ensures that the dialog's height is sufficient to contain the help tray. |
| * If the dialog is too short, its height is increased. When closing the tray, |
| * the height is returned to original (see dispose()). |
| * |
| * @param shell the dialog's shell |
| */ |
| private void ensureMinimumHeight(Shell shell) { |
| Point p = shell.getSize(); |
| originalHeight = p.y; |
| if (p.y < MINIMUM_HEIGHT) { |
| heightAdded = MINIMUM_HEIGHT - p.y; |
| p.y = MINIMUM_HEIGHT; |
| shell.setSize(p); |
| } |
| else { |
| heightAdded = 0; |
| } |
| } |
| |
| /** |
| * Returns the ReusableHelpPart contained in the tray. |
| * |
| * @return the tray's ReusableHelpPart |
| */ |
| public ReusableHelpPart getHelpPart() { |
| return helpPart; |
| } |
| |
| /** |
| * Add the listener that gets notified of page changes (to automatically |
| * update context help). |
| * |
| * @param parent the Composite to hook the listener to |
| */ |
| private void hookPageChangeListener(Composite parent) { |
| Object data = parent.getData(); |
| if (data instanceof IPageChangeProvider) { |
| ((IPageChangeProvider)data).addPageChangedListener(this); |
| } |
| } |
| |
| /** |
| * Returns whether or not the help tray can handle the given shell. In some |
| * cases the help tray is not appropriate for shells that are too short and |
| * not resizable. In these cases infopops are used. |
| * |
| * @param shell the shell to check |
| * @return whether or not the help tray is appropriate for the hsell |
| */ |
| public static boolean isAppropriateFor(Shell shell) { |
| if (shell != null && !shell.isDisposed() && shell.isVisible()) { |
| Object data = shell.getData(); |
| return (data instanceof TrayDialog && (shell.getSize().y >= MINIMUM_HEIGHT || (shell.getStyle() & SWT.RESIZE) != 0)); |
| } |
| return false; |
| } |
| |
| /** |
| * Called whenever the dialog we're inside has changed pages. This updates |
| * the context help page if it is visible. |
| * |
| * @param event the page change event |
| */ |
| @Override |
| public void pageChanged(PageChangedEvent event) { |
| Object page = event.getSelectedPage(); |
| Control c = null; |
| if (page instanceof IDialogPage) { |
| c = ((IDialogPage) page).getControl(); |
| } else { |
| c = shell.getDisplay().getFocusControl(); |
| if (c instanceof TabFolder) { |
| TabFolder folder = (TabFolder) c; |
| TabItem[] selection = folder.getSelection(); |
| if (selection.length == 1) { |
| c = selection[0].getControl(); |
| } |
| } |
| } |
| helpPart.update(null, null, null, c, false); |
| } |
| |
| /** |
| * Remove the listener that gets notified of page changes (to automatically |
| * update context help). |
| * |
| * @param parent the Composite that had the listener |
| */ |
| private void unhookPageChangeListener(Composite parent) { |
| Object data = parent.getData(); |
| if (data instanceof IPageChangeProvider) { |
| ((IPageChangeProvider)data).removePageChangedListener(this); |
| } |
| } |
| } |