/******************************************************************************* * Copyright (c) 2004, 2009 Tasktop Technologies 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: * Tasktop Technologies - initial API and implementation * Frank Becker - improvements *******************************************************************************/ package org.eclipse.mylyn.tasks.ui; import java.lang.reflect.Method; import java.util.Iterator; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.text.DocumentEvent; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.TextPresentation; import org.eclipse.jface.text.hyperlink.DefaultHyperlinkPresenter; import org.eclipse.jface.text.hyperlink.IHyperlink; import org.eclipse.jface.text.hyperlink.MultipleHyperlinkPresenter; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.mylyn.commons.core.StatusHandler; import org.eclipse.mylyn.internal.tasks.core.TaskList; import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin; import org.eclipse.mylyn.internal.tasks.ui.editors.Messages; import org.eclipse.mylyn.internal.tasks.ui.util.TasksUiInternal; import org.eclipse.mylyn.tasks.core.ITask; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.RGB; /** * A hyperlink presenter that displays a tooltip when hovering over a {@link TaskHyperlink}. * * @author Steffen Pingel * @author Frank Becker * @since 3.1 */ public final class TaskHyperlinkPresenter extends MultipleHyperlinkPresenter { private IRegion activeRegion; /** * Stores which task a tooltip is being displayed for. It is used to avoid having the same tooltip being set * multiple times while you move the mouse over a task hyperlink (bug#209409) */ private ITask currentTask; private TaskHyperlink currentTaskHyperlink; private ITextViewer textViewer; private String oldToolTip; private boolean restoreToolTip; // TODO e3.7 remove all references to delegate and replace with calls to super methods private final MultipleHyperlinkPresenter delegate; private boolean errorLogged; /** * @see DefaultHyperlinkPresenter#DefaultHyperlinkPresenter(IPreferenceStore) */ public TaskHyperlinkPresenter(IPreferenceStore store) { super(store); delegate = new MultipleHyperlinkPresenter(store); } /** * @see DefaultHyperlinkPresenter#DefaultHyperlinkPresenter(RGB) */ public TaskHyperlinkPresenter(RGB color) { super(color); delegate = new MultipleHyperlinkPresenter(color); } @Override public void install(ITextViewer textViewer) { this.textViewer = textViewer; delegate.install(textViewer); } @Override public void uninstall() { hideHyperlinks(); this.textViewer = null; delegate.uninstall(); } @SuppressWarnings("unchecked") @Override public void applyTextPresentation(TextPresentation textPresentation) { delegate.applyTextPresentation(textPresentation); // decorate hyperlink as strike-through if task is completed, this is now also handled by TaskHyperlinkTextPresentationManager if (activeRegion != null && currentTask != null && currentTask.isCompleted()) { Iterator styleRangeIterator = textPresentation.getAllStyleRangeIterator(); while (styleRangeIterator.hasNext()) { StyleRange styleRange = styleRangeIterator.next(); if (activeRegion.getOffset() == styleRange.start && activeRegion.getLength() == styleRange.length) { styleRange.strikeout = true; break; } } } } // TODO e3.7 remove method @Override public void showHyperlinks(IHyperlink[] hyperlinks) { showHyperlinks(hyperlinks, false); } // TODO e3.7 add @Override annotation public void showHyperlinks(IHyperlink[] hyperlinks, boolean takesFocusWhenVisible) { activeRegion = null; // show task name in tooltip if (hyperlinks.length == 1 && hyperlinks[0] instanceof TaskHyperlink) { TaskHyperlink hyperlink = (TaskHyperlink) hyperlinks[0]; TaskList taskList = TasksUiPlugin.getTaskList(); String repositoryUrl = hyperlink.getRepository().getRepositoryUrl(); ITask task = taskList.getTask(repositoryUrl, hyperlink.getTaskId()); if (task == null) { task = taskList.getTaskByKey(repositoryUrl, hyperlink.getTaskId()); } if (!hyperlinks[0].equals(currentTaskHyperlink)) { currentTaskHyperlink = (TaskHyperlink) hyperlinks[0]; currentTask = task; activeRegion = hyperlink.getHyperlinkRegion(); if (textViewer != null && textViewer.getTextWidget() != null && !textViewer.getTextWidget().isDisposed()) { oldToolTip = textViewer.getTextWidget().getToolTipText(); restoreToolTip = true; if (task == null) { String taskLabel = TasksUiInternal.getTaskPrefix(hyperlink.getRepository().getConnectorKind()); taskLabel += currentTaskHyperlink.getTaskId(); textViewer.getTextWidget().setToolTipText( NLS.bind(Messages.TaskHyperlinkPresenter_Not_In_Task_List, taskLabel)); } else if (task.getTaskKey() == null) { textViewer.getTextWidget().setToolTipText(task.getSummary()); } else { textViewer.getTextWidget().setToolTipText(task.getTaskKey() + ": " + task.getSummary()); //$NON-NLS-1$ } } } } // invoke super implementation try { // Eclipse 3.7 Method method = MultipleHyperlinkPresenter.class.getDeclaredMethod("showHyperlinks", //$NON-NLS-1$ IHyperlink[].class, boolean.class); method.invoke(delegate, hyperlinks, takesFocusWhenVisible); } catch (NoSuchMethodException e) { // Eclipse 3.6 and earlier delegate.showHyperlinks(hyperlinks); } catch (Exception e) { if (!errorLogged) { errorLogged = true; StatusHandler.log(new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, "Unexpected error while displaying hyperlink", e)); //$NON-NLS-1$ } } } @Override public void hideHyperlinks() { if (currentTaskHyperlink != null) { if (restoreToolTip && textViewer != null && textViewer.getTextWidget() != null && !textViewer.getTextWidget().isDisposed()) { textViewer.getTextWidget().setToolTipText(oldToolTip); restoreToolTip = false; } currentTaskHyperlink = null; currentTask = null; } delegate.hideHyperlinks(); } @Override public boolean canHideHyperlinks() { return delegate.canHideHyperlinks(); } @Override public boolean canShowMultipleHyperlinks() { return delegate.canShowMultipleHyperlinks(); } @Override public void documentAboutToBeChanged(DocumentEvent event) { delegate.documentAboutToBeChanged(event); } @Override public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) { delegate.inputDocumentAboutToBeChanged(oldInput, newInput); } @Override public void inputDocumentChanged(IDocument oldInput, IDocument newInput) { delegate.inputDocumentChanged(oldInput, newInput); } @Override public void propertyChange(PropertyChangeEvent event) { delegate.propertyChange(event); } @Override public void setColor(Color color) { delegate.setColor(color); } }