/******************************************************************************* * Copyright 2015 Software Evolution and Architecture Lab, University of Zurich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package eu.cloudwave.wp5.feedback.eclipse.base.ui.hovers; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.jdt.ui.text.java.hover.IJavaEditorTextHover; import org.eclipse.jface.text.IInformationControl; import org.eclipse.jface.text.IInformationControlCreator; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextHoverExtension; import org.eclipse.jface.text.ITextHoverExtension2; import org.eclipse.jface.text.ITextViewer; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IFileEditorInput; import com.google.common.base.Optional; import eu.cloudwave.wp5.feedback.eclipse.base.resources.core.FeedbackFile; import eu.cloudwave.wp5.feedback.eclipse.base.resources.core.FeedbackResourceFactory; /** * This class provides basic functionality for hovers that should be connected with annotations of {@link IMarker}'s * (i.e. the hover appears when the user moves the cursor onto a annotation of an {@link IMarker}). * * In fact there is a default hover for {@link IMarker}'s, but this only contains the one-line message that is also * shown in the problems view. Eclipse doesn't provide any functionality to directly connect a hover with an * {@link IMarker}. (More info: 'http://www.eclipse.org/forums/index.php/t/100609/' and * 'http://stackoverflow.com/questions/25323477/line-break-in-imarker-tooltips-at-the-left-border-of-the-eclipse-java-ed * i t o r ' ) * * To overcome that limitation, this class can be sub-classed to create a Hover that can be used in combination with * {@link IMarker}'s. The {@link IMarker}'s are passed as input content to the respective {@link IInformationControl} * that is used to fill the hover. */ public abstract class AbstractJavaEditorMarkerHover implements IJavaEditorTextHover, ITextHoverExtension, ITextHoverExtension2 { private IEditorPart editor; abstract protected FeedbackResourceFactory getFeedbackResourceFactory(); /** * {@inheritDoc} */ @Override public final void setEditor(final IEditorPart editor) { this.editor = editor; } /** * * {@inheritDoc} */ @Override public final String getHoverInfo(final ITextViewer textViewer, final IRegion hoverRegion) { return null; // deprecated getHoverInfo2() is used instead } /** * {@inheritDoc} */ @Override public final IRegion getHoverRegion(final ITextViewer textViewer, final int offset) { return null; // not used } /** * {@inheritDoc} */ @Override public Object getHoverInfo2(final ITextViewer textViewer, final IRegion hoverRegion) { final IFile file = ((IFileEditorInput) editor.getEditorInput()).getFile(); final Optional<? extends FeedbackFile> feedbackFileOptional = getFeedbackResourceFactory().create(file); if (feedbackFileOptional.isPresent()) { for (final IMarker marker : feedbackFileOptional.get().findMarkers(getMarkerId())) { if (isOffsetInMarkerRegion(hoverRegion.getOffset(), marker)) { return marker; } } } return null; } /** * Returns the id of the {@link IMarker} for which the hover should be displayed. * * @return the id of the {@link IMarker} for which the hover should be displayed */ protected abstract String getMarkerId(); /** * Checks whether the hover offset is in-between the start and end position of a marker annotation. * * @param hoverOffset * the hover offset (i.e. the cursor position) * @param marker * the {@link IMarker} * @return <code>true</code> if the hover offset is in-between the start and end position of the marker annotation, * <code>false</code> otherwise */ private boolean isOffsetInMarkerRegion(final int hoverOffset, final IMarker marker) { final int markerStartPosition = marker.getAttribute(IMarker.CHAR_START, Integer.MAX_VALUE); final int markerEndPosition = marker.getAttribute(IMarker.CHAR_END, -1); return hoverOffset >= markerStartPosition && hoverOffset <= markerEndPosition; } /** * {@inheritDoc} */ @Override public final IInformationControlCreator getHoverControlCreator() { return new IInformationControlCreator() { @Override public IInformationControl createInformationControl(final Shell parent) { return AbstractJavaEditorMarkerHover.this.createInformationControl(parent, false); } }; } /** * Creates the {@link IInformationControl} that is shown on hovering with the given {@link Shell} as parent. * * @param parent * the parent {@link Shell} * @param indicates * whether the control should be resizable * @return the created {@link IInformationControl} */ protected abstract IInformationControl createInformationControl(final Shell parent, final boolean resizable); }