| /** |
| * Copyright (c) 2012,2016 Eclipse contributors 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 |
| */ |
| package org.eclipse.cdt.arduino.ui.internal; |
| |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| |
| import org.eclipse.jface.internal.text.InformationControlReplacer; |
| import org.eclipse.jface.resource.JFaceResources; |
| import org.eclipse.jface.text.AbstractHoverInformationControlManager; |
| import org.eclipse.jface.text.AbstractInformationControl; |
| import org.eclipse.jface.text.AbstractReusableInformationControlCreator; |
| import org.eclipse.jface.text.IInformationControl; |
| import org.eclipse.jface.text.IInformationControlCreator; |
| import org.eclipse.jface.text.IInformationControlExtension3; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.ScrolledComposite; |
| import org.eclipse.swt.events.ControlEvent; |
| import org.eclipse.swt.events.ControlListener; |
| import org.eclipse.swt.events.FocusEvent; |
| import org.eclipse.swt.events.FocusListener; |
| import org.eclipse.swt.events.KeyEvent; |
| import org.eclipse.swt.events.KeyListener; |
| import org.eclipse.swt.events.MouseEvent; |
| import org.eclipse.swt.events.MouseListener; |
| import org.eclipse.swt.graphics.Font; |
| import org.eclipse.swt.graphics.FontData; |
| 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.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.ui.PartInitException; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.forms.events.HyperlinkAdapter; |
| import org.eclipse.ui.forms.events.HyperlinkEvent; |
| import org.eclipse.ui.forms.widgets.FormText; |
| |
| /** |
| * A utility class for showing rich JDT-style HTML content in tool tip hovers. This class is final |
| * to avoid long term API commitments. If you feel the need to specialize it, please open a bugzilla |
| * to explain what your use case and requirements. |
| */ |
| @SuppressWarnings("restriction") |
| public abstract class FormTextHoverManager extends AbstractHoverInformationControlManager { |
| |
| private static class FormTextInformationControl extends AbstractInformationControl { |
| private ScrolledComposite comp; |
| private FormText formText; |
| private String text; |
| |
| public FormTextInformationControl(Shell parentShell, boolean inFocus) { |
| super(parentShell, true); |
| |
| // Need to do our own status bar if not in focus |
| if (!inFocus) { |
| Shell shell = getShell(); |
| Composite statusComposite = new Composite(shell, SWT.NONE); |
| GridData gridData = new GridData(SWT.FILL, SWT.BOTTOM, true, false); |
| statusComposite.setLayoutData(gridData); |
| GridLayout statusLayout = new GridLayout(1, false); |
| statusLayout.marginHeight = 0; |
| statusLayout.marginWidth = 0; |
| statusLayout.verticalSpacing = 1; |
| statusComposite.setLayout(statusLayout); |
| |
| Label separator = new Label(statusComposite, SWT.SEPARATOR | SWT.HORIZONTAL); |
| separator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); |
| |
| Label statusLabel = new Label(statusComposite, SWT.RIGHT); |
| statusLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); |
| statusLabel.setText("Press F2 for focus"); |
| |
| FontData[] fontDatas = JFaceResources.getDialogFont().getFontData(); |
| for (int i = 0; i < fontDatas.length; i++) { |
| fontDatas[i].setHeight(fontDatas[i].getHeight() * 9 / 10); |
| } |
| Font statusLabelFont = new Font(statusLabel.getDisplay(), fontDatas); |
| statusLabel.setFont(statusLabelFont); |
| } |
| |
| create(); |
| } |
| |
| @Override |
| public boolean hasContents() { |
| return text != null; |
| } |
| |
| @Override |
| public void setInformation(String information) { |
| this.text = information; |
| if (text != null) { |
| formText.setText(text, true, true); |
| comp.setMinSize(formText.computeSize(SWT.DEFAULT, SWT.DEFAULT)); |
| } |
| } |
| |
| @Override |
| protected void createContent(Composite parent) { |
| comp = new ScrolledComposite(parent, SWT.V_SCROLL | SWT.H_SCROLL); |
| comp.setExpandHorizontal(true); |
| comp.setExpandVertical(true); |
| |
| formText = new FormText(comp, SWT.NONE); |
| comp.setContent(formText); |
| formText.addHyperlinkListener(new HyperlinkAdapter() { |
| @Override |
| public void linkActivated(HyperlinkEvent event) { |
| try { |
| PlatformUI.getWorkbench().getBrowserSupport().getExternalBrowser() |
| .openURL(new URL((String) event.getHref())); |
| } catch (MalformedURLException | PartInitException e) { |
| Activator.log(e); |
| } |
| } |
| }); |
| } |
| |
| @Override |
| public IInformationControlCreator getInformationPresenterControlCreator() { |
| return new IInformationControlCreator() { |
| @Override |
| public IInformationControl createInformationControl(Shell parent) { |
| return new FormTextInformationControl(parent, true); |
| } |
| }; |
| } |
| |
| public Control getControl() { |
| return getShell(); |
| } |
| } |
| |
| protected IInformationControlCloser closer; |
| |
| public FormTextHoverManager() { |
| super(new AbstractReusableInformationControlCreator() { |
| @Override |
| protected IInformationControl doCreateInformationControl(Shell parent) { |
| return new FormTextInformationControl(parent, false); |
| } |
| }); |
| |
| getInternalAccessor().setInformationControlReplacer(new InformationControlReplacer( |
| new AbstractReusableInformationControlCreator() { |
| @Override |
| protected IInformationControl doCreateInformationControl(Shell parent) { |
| return new FormTextInformationControl(parent, true); |
| } |
| }) { |
| { |
| this.setCloser(new Closer()); |
| } |
| |
| class Closer implements IInformationControlCloser, ControlListener, MouseListener, KeyListener, |
| FocusListener, Listener { |
| protected boolean isActive; |
| protected Display display; |
| protected Control subjectControl; |
| protected IInformationControl informationControl; |
| |
| @Override |
| public void setSubjectControl(Control control) { |
| subjectControl = control; |
| } |
| |
| @Override |
| public void setInformationControl(IInformationControl control) { |
| this.informationControl = control; |
| } |
| |
| @Override |
| public void start(Rectangle informationArea) { |
| if (!isActive) { |
| isActive = true; |
| |
| if (subjectControl != null && !subjectControl.isDisposed()) { |
| subjectControl.addControlListener(this); |
| subjectControl.addMouseListener(this); |
| subjectControl.addKeyListener(this); |
| } |
| |
| if (informationControl != null) { |
| informationControl.addFocusListener(this); |
| } |
| |
| display = subjectControl.getDisplay(); |
| if (!display.isDisposed()) { |
| display.addFilter(SWT.MouseMove, this); |
| display.addFilter(SWT.FocusOut, this); |
| } |
| } |
| } |
| |
| @Override |
| public void stop() { |
| if (isActive) { |
| isActive = false; |
| |
| if (subjectControl != null && !subjectControl.isDisposed()) { |
| subjectControl.removeControlListener(this); |
| subjectControl.removeMouseListener(this); |
| subjectControl.removeKeyListener(this); |
| } |
| |
| if (informationControl != null) { |
| informationControl.removeFocusListener(this); |
| } |
| |
| if (display != null && !display.isDisposed()) { |
| display.removeFilter(SWT.MouseMove, this); |
| display.removeFilter(SWT.FocusOut, this); |
| } |
| display = null; |
| } |
| } |
| |
| @Override |
| public void controlResized(ControlEvent event) { |
| hideInformationControl(); |
| } |
| |
| @Override |
| public void controlMoved(ControlEvent event) { |
| hideInformationControl(); |
| } |
| |
| @Override |
| public void mouseDown(MouseEvent event) { |
| hideInformationControl(); |
| } |
| |
| @Override |
| public void mouseUp(MouseEvent event) { |
| // Ignore. |
| } |
| |
| @Override |
| public void mouseDoubleClick(MouseEvent event) { |
| hideInformationControl(); |
| } |
| |
| @Override |
| public void keyPressed(KeyEvent event) { |
| hideInformationControl(); |
| } |
| |
| @Override |
| public void keyReleased(KeyEvent event) { |
| // Ignore. |
| } |
| |
| @Override |
| public void focusGained(FocusEvent event) { |
| // Ignore. |
| } |
| |
| @Override |
| public void focusLost(FocusEvent event) { |
| if (display != null && !display.isDisposed()) { |
| display.asyncExec(new Runnable() { |
| @Override |
| public void run() { |
| hideInformationControl(); |
| } |
| }); |
| } |
| } |
| |
| @Override |
| public void handleEvent(Event event) { |
| if (event.type == SWT.MouseMove) { |
| if (event.widget instanceof Control && event.widget.isDisposed()) { |
| if (informationControl != null && !informationControl.isFocusControl() |
| && informationControl instanceof IInformationControlExtension3) { |
| Rectangle controlBounds = ((IInformationControlExtension3) informationControl) |
| .getBounds(); |
| if (controlBounds != null) { |
| Point mouseLocation = event.display.map((Control) event.widget, null, event.x, |
| event.y); |
| if (!controlBounds.contains(mouseLocation)) { |
| hideInformationControl(); |
| } |
| } |
| } else { |
| if (display != null && !display.isDisposed()) { |
| display.removeFilter(SWT.MouseMove, this); |
| } |
| } |
| } |
| } else if (event.type == SWT.FocusOut) { |
| if (informationControl != null && !informationControl.isFocusControl()) { |
| hideInformationControl(); |
| } |
| } |
| } |
| } |
| }); |
| } |
| |
| @Override |
| protected void setCloser(IInformationControlCloser closer) { |
| this.closer = closer; |
| super.setCloser(closer); |
| } |
| |
| @Override |
| protected boolean canClearDataOnHide() { |
| return false; |
| } |
| |
| protected KeyListener keyListener = new KeyListener() { |
| @Override |
| public void keyReleased(KeyEvent event) { |
| if (event.keyCode == SWT.F2) { |
| IInformationControl informationControl = getInformationControl(); |
| if (informationControl instanceof FormTextInformationControl) { |
| Control myControl = ((FormTextInformationControl) informationControl).getControl(); |
| Event mouseEvent = new Event(); |
| mouseEvent.display = myControl.getDisplay(); |
| mouseEvent.widget = myControl; |
| mouseEvent.type = SWT.MouseUp; |
| ((Listener) closer).handleEvent(mouseEvent); |
| event.doit = false; |
| } |
| } |
| } |
| |
| @Override |
| public void keyPressed(KeyEvent event) { |
| // Ignore. |
| } |
| }; |
| |
| @Override |
| public void install(Control subjectControl) { |
| Control oldSubjectControl = getSubjectControl(); |
| |
| if (oldSubjectControl != null && !oldSubjectControl.isDisposed()) { |
| oldSubjectControl.removeKeyListener(keyListener); |
| } |
| |
| if (subjectControl != null) { |
| subjectControl.addKeyListener(keyListener); |
| } |
| |
| super.install(subjectControl); |
| getInternalAccessor().getInformationControlReplacer().install(subjectControl); |
| } |
| |
| @Override |
| public void dispose() { |
| Control subjectControl = getSubjectControl(); |
| if (subjectControl != null && !subjectControl.isDisposed()) { |
| subjectControl.removeKeyListener(keyListener); |
| } |
| super.dispose(); |
| } |
| |
| } |