/******************************************************************************* * Copyright (c) 2008, 2012 Obeo. * 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: * Obeo - initial API and implementation *******************************************************************************/ package org.eclipse.emf.eef.runtime.ui.widgets; import java.awt.Toolkit; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.text.source.IVerticalRuler; import org.eclipse.jface.text.source.SourceViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CLabel; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.events.ControlAdapter; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; 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.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.Label; import org.eclipse.swt.widgets.Scrollable; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.ToolBar; import org.eclipse.swt.widgets.ToolItem; /** * @author <a href="mailto:goulwen.lefur@obeo.fr">Goulwen Le Fur</a> */ public final class SWTUtils { /** * Image registry key for help image (value <code>"dialog_help_image"</code> ). */ public static final String DLG_IMG_HELP = "dialog_help_image"; //$NON-NLS-1$ /** * Create a label describing a properties of the view * * @param parent * the parent composite * @param text * the label text * @param required * defines if the associated properties is required or not */ public static Label createPartLabel(Composite parent, String text, boolean required) { Label label = new Label(parent, SWT.NONE); label.setText(text); if (required) label.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DEFAULT_FONT)); return label; } /** * Creates a button with a help image and put the defined tooltip in parameter. * * @param parent * the parent composite * @param the * message to use for tooltip */ public static Control createHelpButton(final Composite parent, String helpMessage, String helpID) { Image image = JFaceResources.getImage(DLG_IMG_HELP); if (helpID != null && !"".equals(helpID)) { //$NON-NLS-1$ ToolBar result = new ToolBar(parent, SWT.FLAT | SWT.NO_FOCUS); ((GridLayout)parent.getLayout()).numColumns++; result.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER)); ToolItem item = new ToolItem(result, SWT.NONE); item.setImage(image); if (helpMessage != null && !"".equals(helpMessage)) //$NON-NLS-1$ item.setToolTipText(helpMessage); return result; } else { CLabel result = new CLabel(parent, SWT.NONE); if (helpMessage != null && !"".equals(helpMessage)) { //$NON-NLS-1$ result.setImage(image); result.setToolTipText(helpMessage); } return result; } } public static final double HEIGHT = 0.66; public static final double WIDTH = 0.66; public static int getHeight() { return (int)(HEIGHT * Toolkit.getDefaultToolkit().getScreenSize().height) + 1; } public static int getWidth() { return (int)(WIDTH * Toolkit.getDefaultToolkit().getScreenSize().width) + 1; } public static int getEntireWidth() { return Toolkit.getDefaultToolkit().getScreenSize().width; } /** Utility classes don't need default constructors. */ private SWTUtils() { // Hides default constructor. } /** * Creates a {@link SourceViewer} widget that knows how to hide its scroll bars. * * @param parent * The parent composite for this viewer. * @param style * Style of the created viewer. * @return The created {@link SourceViewer}. */ public static SourceViewer createScrollableSourceViewer(Composite parent, int style) { SourceViewer viewer = new ScrollableSourceViewer(parent, null, style); setUpScrollableListener(viewer.getTextWidget()); return viewer; } /** * Creates a {@link StyledText} widget that knows how to hide its scroll bars. * * @param parent * The parent composite for this text. * @param style * Style of the created text. * @return The created {@link StyledText} widget. */ public static StyledText createScrollableStyledText(Composite parent, int style) { final StyledText text = new StyledText(parent, style); // If this text has no scroll bars, simply return it. if ((style & (SWT.H_SCROLL | SWT.V_SCROLL)) == 0) { return text; } // Otherwise, set up its listeners setUpScrollableListener(text); return text; } /** * Creates a {@link Text} widget that knows how to hide its scroll bars. * * @param parent * The parent composite for this text. * @param style * Style of the created text. * @return The created {@link Text} widget. */ public static Text createScrollableText(Composite parent, int style) { final Text text = new Text(parent, style); // If this text has no scroll bars, simply return it. if ((style & (SWT.H_SCROLL | SWT.V_SCROLL)) == 0) { return text; } // Otherwise, set up its listeners setUpScrollableListener(text); return text; } /** * Sets up the listeners allowing us to hide the scroll bars of the given scrollable when they are not * needed. * * @param scrollable * The scrollable widget to setup. */ public static void setUpScrollableListener(final Scrollable scrollable) { final ControlAdapter resizeListener = new ScrollableResizeListener(scrollable); scrollable.addControlListener(resizeListener); final ModifyListener modifyListener = new ScrollableModifyListener(scrollable); if (scrollable instanceof Text) { ((Text)scrollable).addModifyListener(modifyListener); } else if (scrollable instanceof StyledText) { ((StyledText)scrollable).addModifyListener(modifyListener); } scrollable.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { scrollable.removeControlListener(resizeListener); if (scrollable instanceof Text) { ((Text)scrollable).removeModifyListener(modifyListener); } else if (scrollable instanceof StyledText) { ((StyledText)scrollable).removeModifyListener(modifyListener); } } }); } /** * Computes the size of the text displayed by the given {@link Text} widget. * * @param widget * The widget on which is displayed the text. * @param text * The actual displayed text. * @return The actual size of the {@link Text} widget's content. */ protected static Point computeTextSize(Control widget, String text) { String[] lines = text.split("\r\n|\n|\r"); //$NON-NLS-1$ String longestLine = ""; //$NON-NLS-1$ if (lines.length > 0) { longestLine = lines[0]; for (int i = 0; i < lines.length; i++) { if (lines[i].length() > longestLine.length()) { longestLine = lines[i]; } } } GC gc = new GC(widget); gc.setFont(widget.getFont()); final int textWidth = gc.stringExtent(longestLine).x; final int textHeight = gc.stringExtent("W").y * lines.length; //$NON-NLS-1$ gc.dispose(); return new Point(textWidth, textHeight); } /** * This will be used as the resize listener for our scrollable text controls in order to determine whether * the scroll bars are needed. * * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a> */ protected static class ScrollableModifyListener implements ModifyListener { /** The {@link Scrollable} widget against which this listener has been registered. */ private final Scrollable text; /** * Instantiates our modify listener for the given text widget. * * @param text * The text widget to listen to. */ public ScrollableModifyListener(Scrollable text) { this.text = text; } /** * {@inheritDoc} * * @see org.eclipse.swt.events.ModifyListener#modifyText(org.eclipse.swt.events.ModifyEvent) */ public void modifyText(ModifyEvent e) { final Rectangle clientArea = text.getClientArea(); final String currentText; if (text instanceof Text) { currentText = ((Text)text).getText(); } else if (text instanceof StyledText) { currentText = ((StyledText)text).getText(); } else { return; } final Point textSize = computeTextSize(text, currentText); if (clientArea.width > textSize.x && text.getHorizontalBar() != null) { text.getHorizontalBar().setVisible(false); } else if (text.getHorizontalBar() != null) { text.getHorizontalBar().setVisible(true); } if (clientArea.height > textSize.y && text.getVerticalBar() != null) { text.getVerticalBar().setVisible(false); } else if (text.getVerticalBar() != null) { text.getVerticalBar().setVisible(true); } } } /** * This will be used as the resize listener for our scrollable text controls in order to determine whether * the scroll bars are needed. * * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a> */ protected static class ScrollableResizeListener extends ControlAdapter { /** Keeps a reference to the last size we computed. */ private Point lastSize; /** Keeps a reference to the last text we computed a size for. */ private String lastText; /** The {@link Scrollable} widget against which this listener has been registered. */ private final Scrollable text; /** * Instantiates our resize listener for the given text widget. * * @param text * The text widget to listen to. */ public ScrollableResizeListener(Scrollable text) { this.text = text; } /** * {@inheritDoc} * * @see org.eclipse.swt.events.ControlAdapter#controlResized(org.eclipse.swt.events.ControlEvent) */ @Override public void controlResized(ControlEvent e) { final Rectangle clientArea = text.getClientArea(); final String currentText; if (text instanceof Text) { currentText = ((Text)text).getText(); } else if (text instanceof StyledText) { currentText = ((StyledText)text).getText(); } else { return; } Point textSize = lastSize; if (textSize == null || !lastText.equals(currentText)) { textSize = computeTextSize(text, currentText); lastText = currentText; lastSize = textSize; } if (clientArea.width > textSize.x && text.getHorizontalBar() != null) { text.getHorizontalBar().setVisible(false); } else if (text.getHorizontalBar() != null) { text.getHorizontalBar().setVisible(true); } if (clientArea.height > textSize.y && text.getVerticalBar() != null) { text.getVerticalBar().setVisible(false); } else if (text.getVerticalBar() != null) { text.getVerticalBar().setVisible(true); } } } /** * This subclass of a source viewer will only show its scroll bars if they are needed. * * @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a> */ protected static class ScrollableSourceViewer extends SourceViewer { /** * Constructs a new source viewer. The vertical ruler is initially visible. The viewer has not yet * been initialized with a source viewer configuration. * * @param parent * the parent of the viewer's control. * @param ruler * the vertical ruler used by this source viewer. * @param styles * the SWT style bits for the viewer's control, * <em>if <code>SWT.WRAP</code> is set then a custom document adapter needs to be provided, see {@link #createDocumentAdapter()}. */ public ScrollableSourceViewer(Composite parent, IVerticalRuler ruler, int styles) { super(parent, ruler, styles); } /** * {@inheritDoc} * * @see org.eclipse.jface.text.TextViewer#createTextWidget(org.eclipse.swt.widgets.Composite, int) */ @Override protected StyledText createTextWidget(Composite parent, int styles) { return super.createTextWidget(parent, styles); } } }