org.eclipse.jface.text.hyperlink.MultipleHyperlinkPresenter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.eclipse.jface.text Show documentation
Show all versions of org.eclipse.jface.text Show documentation
This is org.eclipse.jface.text jar used by Scout SDK
The newest version!
/*******************************************************************************
* Copyright (c) 2008, 2012 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.jface.text.hyperlink;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.ShellAdapter;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
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.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.util.Geometry;
import org.eclipse.jface.util.Util;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.text.AbstractInformationControl;
import org.eclipse.jface.text.AbstractInformationControlManager;
import org.eclipse.jface.text.IInformationControl;
import org.eclipse.jface.text.IInformationControlCreator;
import org.eclipse.jface.text.IInformationControlExtension2;
import org.eclipse.jface.text.IInformationControlExtension3;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextHover;
import org.eclipse.jface.text.ITextHoverExtension;
import org.eclipse.jface.text.ITextHoverExtension2;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.IWidgetTokenKeeper;
import org.eclipse.jface.text.IWidgetTokenKeeperExtension;
import org.eclipse.jface.text.IWidgetTokenOwner;
import org.eclipse.jface.text.IWidgetTokenOwnerExtension;
import org.eclipse.jface.text.JFaceTextUtil;
import org.eclipse.jface.text.Region;
/**
* A hyperlink presenter capable of showing multiple hyperlinks in a hover.
*
* @since 3.4
*/
public class MultipleHyperlinkPresenter extends DefaultHyperlinkPresenter implements IHyperlinkPresenterExtension2 {
private static final boolean IS_OLD_WINDOWS;
static {
int majorVersion= Integer.MAX_VALUE;
if (Util.isWin32()) {
String osVersion= System.getProperty("os.version"); //$NON-NLS-1$
if (osVersion != null) {
int majorIndex = osVersion.indexOf('.');
if (majorIndex != -1) {
osVersion = osVersion.substring(0, majorIndex);
try {
majorVersion= Integer.parseInt(osVersion);
} catch (NumberFormatException exception) {
// use default
}
}
}
}
IS_OLD_WINDOWS= majorVersion < 6; // before Vista (6.0)
}
private static final boolean IS_MAC= Util.isMac();
private static final boolean IS_GTK= Util.isGtk();
/**
* An information control capable of showing a list of hyperlinks. The hyperlinks can be opened.
*/
private static class LinkListInformationControl extends AbstractInformationControl implements IInformationControlExtension2 {
private static final class LinkContentProvider implements IStructuredContentProvider {
@Override
public Object[] getElements(Object inputElement) {
return (Object[]) inputElement;
}
@Override
public void dispose() {
}
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
}
private static final class LinkLabelProvider extends ColumnLabelProvider {
@Override
public String getText(Object element) {
IHyperlink link= (IHyperlink)element;
String text= link.getHyperlinkText();
if (text != null)
return text;
return HyperlinkMessages.getString("LinkListInformationControl.unknownLink"); //$NON-NLS-1$
}
}
private final MultipleHyperlinkHoverManager fManager;
private IHyperlink[] fInput;
private Composite fParent;
private Table fTable;
private final Color fForegroundColor;
private final Color fBackgroundColor;
/**
* Creates a link list information control with the given shell as parent.
*
* @param parentShell the parent shell
* @param manager the hover manager
* @param foregroundColor the foreground color, must not be disposed
* @param backgroundColor the background color, must not be disposed
*/
public LinkListInformationControl(Shell parentShell, MultipleHyperlinkHoverManager manager, Color foregroundColor, Color backgroundColor) {
super(parentShell, false);
fManager= manager;
fForegroundColor= foregroundColor;
fBackgroundColor= backgroundColor;
create();
}
@Override
public void setInformation(String information) {
//replaced by IInformationControlExtension2#setInput(java.lang.Object)
}
@Override
public void setInput(Object input) {
fInput= (IHyperlink[]) input;
deferredCreateContent(fParent);
}
@Override
protected void createContent(Composite parent) {
fParent= parent;
GridLayout layout= new GridLayout();
if (IS_OLD_WINDOWS) {
layout.marginWidth= 0;
layout.marginHeight= 4;
layout.marginRight= 4;
} else if (IS_MAC) {
layout.marginWidth= 4;
layout.marginHeight= 0;
layout.marginTop= 4;
layout.marginBottom= 4 - 1;
} else if (IS_GTK) {
layout.marginWidth= 4;
layout.marginHeight= 0;
layout.marginTop= 4;
layout.marginBottom= 4 - 2;
} else {
layout.marginWidth= 4;
layout.marginHeight= 4;
}
fParent.setLayout(layout);
fParent.setForeground(fForegroundColor);
fParent.setBackground(fBackgroundColor);
}
@Override
public Point computeSizeHint() {
Point preferedSize= getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
Point constraints= getSizeConstraints();
if (constraints == null)
return preferedSize;
if (fTable.getVerticalBar() == null || fTable.getHorizontalBar() == null)
return Geometry.min(constraints, preferedSize);
int scrollBarWidth= fTable.getVerticalBar().getSize().x;
int scrollBarHeight= fTable.getHorizontalBar().getSize().y;
if (IS_MAC && fTable.getScrollbarsMode() == SWT.SCROLLBAR_OVERLAY) {
// workaround for https://bugs.eclipse.org/387732 : [10.8] Table scrollbar width is 16 (not 15) on Mountain Lion
scrollBarWidth--;
scrollBarHeight--;
}
int width;
if (preferedSize.y - scrollBarHeight <= constraints.y) {
width= preferedSize.x - scrollBarWidth;
fTable.getVerticalBar().setVisible(false);
} else {
width= Math.min(preferedSize.x, constraints.x);
}
int height;
if (preferedSize.x - scrollBarWidth <= constraints.x) {
height= preferedSize.y - scrollBarHeight;
fTable.getHorizontalBar().setVisible(false);
} else {
height= Math.min(preferedSize.y, constraints.y);
}
return new Point(width, height);
}
private void deferredCreateContent(Composite parent) {
fTable= new Table(parent, SWT.SINGLE | SWT.FULL_SELECTION);
fTable.setLinesVisible(false);
fTable.setHeaderVisible(false);
fTable.setForeground(fForegroundColor);
fTable.setBackground(fBackgroundColor);
fTable.setFont(JFaceResources.getDialogFont());
GridData data= new GridData(SWT.BEGINNING, SWT.BEGINNING, true, true);
fTable.setLayoutData(data);
final TableViewer viewer= new TableViewer(fTable);
viewer.setContentProvider(new LinkContentProvider());
viewer.setLabelProvider(new LinkLabelProvider());
viewer.setInput(fInput);
fTable.setSelection(0);
registerTableListeners();
getShell().addShellListener(new ShellAdapter() {
@Override
public void shellActivated(ShellEvent e) {
if (viewer.getTable().getSelectionCount() == 0) {
viewer.getTable().setSelection(0);
}
viewer.getTable().setFocus();
}
});
}
private void registerTableListeners() {
fTable.addMouseMoveListener(new MouseMoveListener() {
TableItem fLastItem= null;
@Override
public void mouseMove(MouseEvent e) {
if (fTable.equals(e.getSource())) {
Object o= fTable.getItem(new Point(e.x, e.y));
if (fLastItem == null ^ o == null) {
fTable.setCursor(o == null ? null : fTable.getDisplay().getSystemCursor(SWT.CURSOR_HAND));
}
if (o instanceof TableItem) {
TableItem item= (TableItem) o;
if (!o.equals(fLastItem)) {
fLastItem= (TableItem) o;
fTable.setSelection(new TableItem[] { fLastItem });
} else if (e.y < fTable.getItemHeight() / 4) {
// Scroll up
int index= fTable.indexOf(item);
if (index > 0) {
fLastItem= fTable.getItem(index - 1);
fTable.setSelection(new TableItem[] { fLastItem });
}
} else if (e.y > fTable.getBounds().height - fTable.getItemHeight() / 4) {
// Scroll down
int index= fTable.indexOf(item);
if (index < fTable.getItemCount() - 1) {
fLastItem= fTable.getItem(index + 1);
fTable.setSelection(new TableItem[] { fLastItem });
}
}
} else if (o == null) {
fLastItem= null;
}
}
}
});
fTable.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetDefaultSelected(SelectionEvent e) {
openSelectedLink();
}
});
fTable.addMouseListener(new MouseAdapter() {
@Override
public void mouseUp(MouseEvent e) {
if (fTable.getSelectionCount() < 1)
return;
if (e.button != 1)
return;
if (fTable.equals(e.getSource())) {
Object o= fTable.getItem(new Point(e.x, e.y));
TableItem selection= fTable.getSelection()[0];
if (selection.equals(o))
openSelectedLink();
}
}
});
fTable.addTraverseListener(new TraverseListener() {
@Override
public void keyTraversed(TraverseEvent e) {
if (e.keyCode == SWT.ESC) {
fManager.hideInformationControl();
}
}
});
}
@Override
public boolean hasContents() {
return true;
}
/**
* Opens the currently selected link.
*/
private void openSelectedLink() {
if (fTable.getSelectionCount() < 1)
return;
TableItem selection= fTable.getSelection()[0];
IHyperlink link= (IHyperlink)selection.getData();
fManager.hideInformationControl();
fManager.setCaret();
link.open();
}
}
private class MultipleHyperlinkHover implements ITextHover, ITextHoverExtension, ITextHoverExtension2 {
/**
* @see org.eclipse.jface.text.ITextHover#getHoverInfo(org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion)
* @deprecated As of 3.4, replaced by
* {@link ITextHoverExtension2#getHoverInfo2(ITextViewer, IRegion)}
*/
@Deprecated
@Override
public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) {
return null;
}
@Override
public IRegion getHoverRegion(ITextViewer textViewer, int offset) {
return fSubjectRegion;
}
@Override
public Object getHoverInfo2(ITextViewer textViewer, IRegion hoverRegion) {
return fHyperlinks;
}
@Override
public IInformationControlCreator getHoverControlCreator() {
return new IInformationControlCreator() {
@Override
public IInformationControl createInformationControl(Shell parent) {
Color foregroundColor= fTextViewer.getTextWidget().getForeground();
Color backgroundColor= fTextViewer.getTextWidget().getBackground();
return new LinkListInformationControl(parent, fManager, foregroundColor, backgroundColor);
}
};
}
}
private static class MultipleHyperlinkHoverManager extends AbstractInformationControlManager implements IWidgetTokenKeeper, IWidgetTokenKeeperExtension {
private class Closer implements IInformationControlCloser, Listener, KeyListener, MouseListener {
private Control fSubjectControl;
private Display fDisplay;
private IInformationControl fControl;
private Rectangle fSubjectArea;
@Override
public void setInformationControl(IInformationControl control) {
fControl= control;
}
@Override
public void setSubjectControl(Control subject) {
fSubjectControl= subject;
}
@Override
public void start(Rectangle subjectArea) {
fSubjectArea= subjectArea;
fDisplay= fSubjectControl.getDisplay();
if (!fDisplay.isDisposed()) {
fDisplay.addFilter(SWT.FocusOut, this);
fDisplay.addFilter(SWT.MouseMove, this);
fTextViewer.getTextWidget().addKeyListener(this);
fTextViewer.getTextWidget().addMouseListener(this);
}
}
@Override
public void stop() {
if (fDisplay != null && !fDisplay.isDisposed()) {
fDisplay.removeFilter(SWT.FocusOut, this);
fDisplay.removeFilter(SWT.MouseMove, this);
fTextViewer.getTextWidget().removeKeyListener(this);
fTextViewer.getTextWidget().removeMouseListener(this);
}
fSubjectArea= null;
}
@Override
public void handleEvent(Event event) {
switch (event.type) {
case SWT.FocusOut:
if (!fControl.isFocusControl())
disposeInformationControl();
break;
case SWT.MouseMove:
handleMouseMove(event);
break;
}
}
/**
* Handle mouse movement events.
*
* @param event the event
*/
private void handleMouseMove(Event event) {
if (!(event.widget instanceof Control))
return;
if (fControl.isFocusControl())
return;
Control eventControl= (Control) event.widget;
//transform coordinates to subject control:
Point mouseLoc= event.display.map(eventControl, fSubjectControl, event.x, event.y);
if (fSubjectArea.contains(mouseLoc))
return;
if (inKeepUpZone(mouseLoc.x, mouseLoc.y, ((IInformationControlExtension3) fControl).getBounds()))
return;
if (!isTakingFocusWhenVisible())
hideInformationControl();
}
/**
* Tests whether a given mouse location is within the keep-up zone.
* The hover should not be hidden as long as the mouse stays inside this zone.
*
* @param x the x coordinate, relative to the subject control
* @param y the y coordinate, relative to the subject control
* @param controlBounds the bounds of the current control
*
* @return true
iff the mouse event occurred in the keep-up zone
*/
private boolean inKeepUpZone(int x, int y, Rectangle controlBounds) {
// +-----------+
// |subjectArea|
// +-----------+
// |also keepUp|
// ++-----------+-------+
// | totalBounds |
// +--------------------+
if (fSubjectArea.contains(x, y))
return true;
Rectangle iControlBounds= fSubjectControl.getDisplay().map(null, fSubjectControl, controlBounds);
Rectangle totalBounds= Geometry.copy(iControlBounds);
if (totalBounds.contains(x, y))
return true;
int keepUpY= fSubjectArea.y + fSubjectArea.height;
Rectangle alsoKeepUp= new Rectangle(fSubjectArea.x, keepUpY, fSubjectArea.width, totalBounds.y - keepUpY);
return alsoKeepUp.contains(x, y);
}
@Override
public void keyPressed(KeyEvent e) {
hideInformationControl();
}
@Override
public void keyReleased(KeyEvent e) {
if (!isTakingFocusWhenVisible())
hideInformationControl();
}
@Override
public void mouseDoubleClick(MouseEvent e) {
}
@Override
public void mouseDown(MouseEvent e) {
}
@Override
public void mouseUp(MouseEvent e) {
hideInformationControl();
}
}
/**
* Priority of the hover managed by this manager.
* Default value: One higher then for the hovers
* managed by TextViewerHoverManager.
*/
private static final int WIDGET_TOKEN_PRIORITY= 1;
private final MultipleHyperlinkHover fHover;
private final ITextViewer fTextViewer;
private final MultipleHyperlinkPresenter fHyperlinkPresenter;
private final Closer fCloser;
private boolean fIsControlVisible;
/**
* Create a new MultipleHyperlinkHoverManager. The MHHM can show and hide
* the given MultipleHyperlinkHover inside the given ITextViewer.
*
* @param hover the hover to manage
* @param viewer the viewer to show the hover in
* @param hyperlinkPresenter the hyperlink presenter using this manager to present hyperlinks
*/
public MultipleHyperlinkHoverManager(MultipleHyperlinkHover hover, ITextViewer viewer, MultipleHyperlinkPresenter hyperlinkPresenter) {
super(hover.getHoverControlCreator());
fHover= hover;
fTextViewer= viewer;
fHyperlinkPresenter= hyperlinkPresenter;
fCloser= new Closer();
setCloser(fCloser);
fIsControlVisible= false;
}
@Override
protected void computeInformation() {
IRegion region= fHover.getHoverRegion(fTextViewer, -1);
if (region == null) {
setInformation(null, null);
return;
}
Rectangle area= JFaceTextUtil.computeArea(region, fTextViewer);
if (area == null || area.isEmpty()) {
setInformation(null, null);
return;
}
Object information= fHover.getHoverInfo2(fTextViewer, region);
setCustomInformationControlCreator(fHover.getHoverControlCreator());
setInformation(information, area);
}
@Override
protected Point computeInformationControlLocation(Rectangle subjectArea, Point controlSize) {
Point result= super.computeInformationControlLocation(subjectArea, controlSize);
Point cursorLocation= fTextViewer.getTextWidget().getDisplay().getCursorLocation();
if (isTakingFocusWhenVisible() || cursorLocation.x <= result.x + controlSize.x)
return result;
result.x= cursorLocation.x + 20 - controlSize.x;
return result;
}
@Override
protected void showInformationControl(Rectangle subjectArea) {
if (fTextViewer instanceof IWidgetTokenOwnerExtension) {
if (((IWidgetTokenOwnerExtension)fTextViewer).requestWidgetToken(this, WIDGET_TOKEN_PRIORITY)) {
super.showInformationControl(subjectArea);
fIsControlVisible= true;
}
} else if (fTextViewer instanceof IWidgetTokenOwner) {
if (((IWidgetTokenOwner)fTextViewer).requestWidgetToken(this)) {
super.showInformationControl(subjectArea);
fIsControlVisible= true;
}
} else {
super.showInformationControl(subjectArea);
fIsControlVisible= true;
}
}
/**
* Sets the caret where hyperlinking got initiated.
*
* @since 3.5
*/
private void setCaret() {
fHyperlinkPresenter.setCaret();
}
@Override
protected void hideInformationControl() {
super.hideInformationControl();
if (fTextViewer instanceof IWidgetTokenOwner) {
((IWidgetTokenOwner) fTextViewer).releaseWidgetToken(this);
}
fIsControlVisible= false;
fHyperlinkPresenter.hideHyperlinks();
}
@Override
public void disposeInformationControl() {
super.disposeInformationControl();
if (fTextViewer instanceof IWidgetTokenOwner) {
((IWidgetTokenOwner) fTextViewer).releaseWidgetToken(this);
}
fIsControlVisible= false;
fHyperlinkPresenter.hideHyperlinks();
}
@Override
public boolean requestWidgetToken(IWidgetTokenOwner owner) {
hideInformationControl();
return true;
}
@Override
public boolean requestWidgetToken(IWidgetTokenOwner owner, int priority) {
if (priority < WIDGET_TOKEN_PRIORITY)
return false;
hideInformationControl();
return true;
}
@Override
public boolean setFocus(IWidgetTokenOwner owner) {
return isTakingFocusWhenVisible();
}
/**
* Returns true
if the information control managed by
* this manager is visible, false
otherwise.
*
* @return true
if information control is visible
*/
public boolean isInformationControlVisible() {
return fIsControlVisible;
}
}
private ITextViewer fTextViewer;
private IHyperlink[] fHyperlinks;
private Region fSubjectRegion;
private MultipleHyperlinkHoverManager fManager;
/**
* The offset in the text viewer where hyperlinking got initiated.
* @since 3.5
*/
private int fCursorOffset;
/**
* Creates a new multiple hyperlink presenter which uses {@link #HYPERLINK_COLOR} to read the
* color from the given preference store.
*
* @param store the preference store
*/
public MultipleHyperlinkPresenter(IPreferenceStore store) {
super(store);
}
/**
* Creates a new multiple hyperlink presenter.
*
* @param color the hyperlink color, to be disposed by the caller
*/
public MultipleHyperlinkPresenter(RGB color) {
super(color);
}
@Override
public void install(ITextViewer viewer) {
super.install(viewer);
fTextViewer= viewer;
fManager= new MultipleHyperlinkHoverManager(new MultipleHyperlinkHover(), fTextViewer, this);
fManager.install(viewer.getTextWidget());
fManager.setSizeConstraints(100, 12, false, true);
}
@Override
public void uninstall() {
super.uninstall();
if (fTextViewer != null) {
fManager.dispose();
fTextViewer= null;
}
}
@Override
public boolean canShowMultipleHyperlinks() {
return true;
}
@Override
public boolean canHideHyperlinks() {
return !fManager.isInformationControlVisible();
}
@Override
public void hideHyperlinks() {
super.hideHyperlinks();
fHyperlinks= null;
}
@Override
public void showHyperlinks(IHyperlink[] hyperlinks) {
showHyperlinks(hyperlinks, false);
}
/**
* {@inheritDoc}
*
* @since 3.7
*/
@Override
public void showHyperlinks(IHyperlink[] activeHyperlinks, boolean takesFocusWhenVisible) {
fManager.takesFocusWhenVisible(takesFocusWhenVisible);
super.showHyperlinks(new IHyperlink[] { activeHyperlinks[0] });
fSubjectRegion= null;
fHyperlinks= activeHyperlinks;
if (activeHyperlinks.length == 1)
return;
int start= activeHyperlinks[0].getHyperlinkRegion().getOffset();
int end= start + activeHyperlinks[0].getHyperlinkRegion().getLength();
for (int i= 1; i < activeHyperlinks.length; i++) {
int hstart= activeHyperlinks[i].getHyperlinkRegion().getOffset();
int hend= hstart + activeHyperlinks[i].getHyperlinkRegion().getLength();
start= Math.min(start, hstart);
end= Math.max(end, hend);
}
fSubjectRegion= new Region(start, end - start);
fCursorOffset= JFaceTextUtil.getOffsetForCursorLocation(fTextViewer);
fManager.showInformation();
}
/**
* Sets the caret where hyperlinking got initiated.
*
* @since 3.5
*/
private void setCaret() {
Point selectedRange= fTextViewer.getSelectedRange();
if (fCursorOffset != -1 && !(fSubjectRegion.getOffset() <= selectedRange.x && selectedRange.x + selectedRange.y <= fSubjectRegion.getOffset() + fSubjectRegion.getLength()))
fTextViewer.setSelectedRange(fCursorOffset, 0);
}
}