blob: da374a9699cd8ec81eebf95b858767b1680d6ac6 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2000, 2020 IBM Corporation and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0.
#
# SPDX-License-Identifier: EPL-2.0
#
# Contributors:
# IBM Corporation - org.eclipse.jdt: initial API and implementation
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.ltk.ui.sourceediting;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.AbstractInformationControl;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IInformationControlCreator;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
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.Shell;
import org.eclipse.ui.editors.text.EditorsUI;
import org.eclipse.statet.ecommons.ui.util.LayoutUtils;
/**
* Information control to show sources or other text in a source viewer.
*/
public class SourceViewerInformationControl extends AbstractInformationControl {
private static final int MODE_SIMPLE= 1;
private static final int MODE_FOCUS= 2;
private final int mode;
private Composite contentComposite;
/** The control's text widget */
private StyledText text;
/** The control's source viewer */
private SourceViewer viewer;
private final SourceEditorViewerConfigurator configurator;
private IInformationControlCreator informationCreator;
/**
* The orientation of the shell
*/
private final int orientation;
/**
* Creates a source viewer information control with the given shell as parent. The given
* styles are applied to the created styled text widget. The status field will
* contain the given text or be hidden.
*
* @param parent the parent shell
* @param configurator used to configure the source viewer of the hover
* @param informationConfigurator used to configure the source viewer of the information presenter
* @param orientation the orientation
*/
public SourceViewerInformationControl(final Shell parent, final SourceEditorViewerConfigurator configurator, final int orientation, final IInformationControlCreator informationCreator) {
super(parent, EditorsUI.getTooltipAffordanceString());
assert (orientation == SWT.RIGHT_TO_LEFT || orientation == SWT.LEFT_TO_RIGHT || orientation == SWT.NONE);
this.mode= MODE_SIMPLE;
this.configurator= configurator;
this.orientation= orientation;
this.informationCreator= informationCreator;
create();
}
public SourceViewerInformationControl(final Shell parent, final SourceEditorViewerConfigurator configurator, final int orientation) {
super(parent, true);
assert (orientation == SWT.RIGHT_TO_LEFT || orientation == SWT.LEFT_TO_RIGHT || orientation == SWT.NONE);
this.mode= MODE_FOCUS;
this.configurator= configurator;
this.orientation= orientation;
create();
}
@Override
protected void createContent(final Composite parent) {
this.contentComposite= new Composite(parent, SWT.NONE) {
@Override
public Point computeSize(final int width, final int height, final boolean changed) {
return super.computeSize(width, height, changed || width != getSize().x);
}
};
this.contentComposite.setBackground(parent.getBackground());
final GridLayout gridLayout= LayoutUtils.newCompositeGrid(1);
this.contentComposite.setLayout(gridLayout);
final int vIndent= Math.max(1, LayoutUtils.defaultVSpacing() / 4);
final int hIndent= Math.max(2, LayoutUtils.defaultHSpacing() / 3);
// Source viewer
this.viewer= new SourceViewer(this.contentComposite, null, null, false, (this.mode == MODE_FOCUS ?
(SWT.V_SCROLL | SWT.H_SCROLL) : SWT.NONE) | SWT.MULTI | SWT.READ_ONLY | this.orientation);
this.viewer.setEditable(false);
final ViewerSourceEditorAdapter editor= new ViewerSourceEditorAdapter(this.viewer, this.configurator);
this.configurator.setTarget(editor);
this.text= this.viewer.getTextWidget();
final GridData gd= new GridData(SWT.FILL, SWT.FILL, true, true);
this.text.setLayoutData(gd);
this.text.setFont(JFaceResources.getTextFont());
this.text.setIndent(hIndent);
// this.text.addKeyListener(new KeyListener() {
// public void keyPressed(final KeyEvent e) {
// if (e.character == 0x1B) // ESC
// this.shell.dispose();
// }
// public void keyReleased(final KeyEvent e) {}
// });
setBackgroundColor(getShell().getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND));
setForegroundColor(getShell().getDisplay().getSystemColor(SWT.COLOR_INFO_FOREGROUND));
}
@Override
public void setBackgroundColor(final Color background) {
super.setBackgroundColor(background);
this.text.setBackground(background);
}
@Override
public void setForegroundColor(final Color foreground) {
super.setForegroundColor(foreground);
this.text.setForeground(foreground);
}
@Override
public void setInformation(String content) {
if (content == null) {
this.viewer.setInput(null);
return;
}
if (content.length() > 2
&& content.charAt(content.length()-1) == '\n') {
if (content.charAt(content.length()-2) == '\r') {
content= content.substring(0, content.length()-2);
}
else {
content= content.substring(0, content.length()-1);
}
}
final IDocument document= new Document(content);
this.configurator.getDocumentSetupParticipant().setup(document);
this.viewer.setInput(document);
}
@Override
public final void dispose() {
if (this.configurator != null) {
this.configurator.unconfigureTarget();
}
super.dispose();
this.text= null;
}
@Override
public void setFocus() {
this.text.setFocus();
super.setFocus();
}
@Override
public boolean hasContents() {
return this.text.getCharCount() > 0;
}
protected ISourceViewer getViewer() {
return this.viewer;
}
@Override
public Point computeSizeHint() {
final Point sizeConstraints= getSizeConstraints();
final Rectangle trim= computeTrim();
int widthHint= this.text.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x + LayoutUtils.defaultHSpacing();
final int widthMax= ((sizeConstraints != null && sizeConstraints.x != SWT.DEFAULT) ?
sizeConstraints.x : LayoutUtils.hintWidth(this.text, null, 80)) - trim.width;
if (widthHint > widthMax) {
widthHint= widthMax;
}
final int heightMax= ((sizeConstraints != null && sizeConstraints.y != SWT.DEFAULT) ?
sizeConstraints.y :
this.text.getLineHeight()*12) - trim.height;
final Point size= this.contentComposite.computeSize(widthHint, SWT.DEFAULT, false);
size.x= Math.max(Math.min(size.x, widthMax), 200) + trim.width;
size.y= Math.max(Math.min(size.y, heightMax), 80) + trim.height;
return size;
}
@Override
public Rectangle computeTrim() {
final Rectangle trim= super.computeTrim();
final Rectangle textTrim= this.text.computeTrim(0, 0, 0, 0);
trim.x+= textTrim.x;
trim.y+= textTrim.y;
trim.width+= textTrim.width;
trim.height+= textTrim.height;
return trim;
}
@Override
public Point computeSizeConstraints(final int widthInChars, final int heightInChars) {
final GC gc= new GC(this.text);
gc.setFont(JFaceResources.getDialogFont());
final double width= gc.getFontMetrics().getAverageCharacterWidth() * widthInChars;
final int height= gc.getFontMetrics().getHeight() * heightInChars;
gc.dispose();
return new Point((int)Math.round(width + 0x1.FFFFFp-2), height);
}
@Override
public IInformationControlCreator getInformationPresenterControlCreator() {
return this.informationCreator;
}
}