blob: d7c37c8f3d3e9d0b9ced56a73aed6989951f268c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011, 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.acceleo.ui.interpreter.internal;
import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.swt.SWT;
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.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Scrollable;
import org.eclipse.swt.widgets.Text;
/**
* This will be used by the interpreter view in order to create {@link Text} widgets that know how to hide
* their scroll bars when they are not needed.
*
* @author <a href="mailto:laurent.goubet@obeo.fr">Laurent Goubet</a>
*/
public final class SWTUtil {
/** Utility classes don't need default constructors. */
private SWTUtil() {
// 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 SourceViewer(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) {
if (clientArea.height > text.getHorizontalBar().getSize().y) {
text.getHorizontalBar().setVisible(false);
}
} else if (text.getHorizontalBar() != null) {
text.getHorizontalBar().setVisible(true);
}
if (clientArea.height > textSize.y && text.getVerticalBar() != null) {
if (clientArea.width > text.getVerticalBar().getSize().x) {
text.getVerticalBar().setVisible(false);
}
} else if (text.getVerticalBar() != null) {
text.getVerticalBar().setVisible(true);
}
}
}
}