| /******************************************************************************* |
| * Copyright (c) 2004, 2011 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 |
| * Eugene Kuleshov - improvements |
| *******************************************************************************/ |
| |
| package org.eclipse.mylyn.internal.team.ui.actions; |
| |
| import java.net.URL; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Set; |
| |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.jface.dialogs.MessageDialog; |
| import org.eclipse.mylyn.internal.tasks.core.RepositoryTaskHandleUtil; |
| import org.eclipse.mylyn.internal.tasks.core.TaskList; |
| import org.eclipse.mylyn.internal.tasks.core.TaskRepositoryManager; |
| import org.eclipse.mylyn.internal.tasks.ui.OpenRepositoryTaskJob; |
| import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin; |
| import org.eclipse.mylyn.internal.tasks.ui.actions.OpenRepositoryTaskAction; |
| import org.eclipse.mylyn.internal.tasks.ui.util.TasksUiInternal; |
| import org.eclipse.mylyn.internal.team.ui.FocusedTeamUiPlugin; |
| import org.eclipse.mylyn.internal.team.ui.LinkedTaskInfo; |
| import org.eclipse.mylyn.internal.team.ui.templates.CommitTemplateManager; |
| import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector; |
| import org.eclipse.mylyn.tasks.core.ITask; |
| import org.eclipse.mylyn.tasks.core.TaskRepository; |
| import org.eclipse.mylyn.tasks.ui.AbstractRepositoryConnectorUi; |
| import org.eclipse.mylyn.tasks.ui.TasksUi; |
| import org.eclipse.mylyn.tasks.ui.TasksUiUtil; |
| import org.eclipse.mylyn.team.ui.AbstractTaskReference; |
| import org.eclipse.ui.IWorkbenchPage; |
| import org.eclipse.ui.IWorkbenchWindow; |
| import org.eclipse.ui.PlatformUI; |
| |
| /** |
| * Action used to open linked task. TODO: this class has evolved into a complete mess and has to be fixed. |
| * |
| * @author Mik Kersten |
| * @author Eugene Kuleshov |
| */ |
| public class TaskFinder { |
| |
| private static final String PREFIX_HTTP = "http://"; //$NON-NLS-1$ |
| |
| private static final String PREFIX_HTTPS = "https://"; //$NON-NLS-1$ |
| |
| public static String getTaskIdFromLegacy07Label(String comment) { |
| String PREFIX_DELIM = ":"; //$NON-NLS-1$ |
| String PREFIX_START_1 = Messages.OpenCorrespondingTaskAction_Progress_on; |
| String PREFIX_START_2 = Messages.OpenCorrespondingTaskAction_Completed; |
| String usedPrefix = PREFIX_START_1; |
| int firstDelimIndex = comment.indexOf(PREFIX_START_1); |
| if (firstDelimIndex == -1) { |
| firstDelimIndex = comment.indexOf(PREFIX_START_2); |
| usedPrefix = PREFIX_START_2; |
| } |
| if (firstDelimIndex != -1) { |
| int idStart = firstDelimIndex + usedPrefix.length(); |
| int idEnd = comment.indexOf(PREFIX_DELIM, firstDelimIndex + usedPrefix.length());// comment.indexOf(PREFIX_DELIM); |
| if (idEnd != -1 && idStart < idEnd) { |
| String id = comment.substring(idStart, idEnd); |
| if (id != null) { |
| return id.trim(); |
| } |
| } else { |
| return comment.substring(0, firstDelimIndex); |
| } |
| } |
| return null; |
| } |
| |
| public static String getUrlFromComment(String comment) { |
| int httpIndex = comment.indexOf(PREFIX_HTTP); |
| int httpsIndex = comment.indexOf(PREFIX_HTTPS); |
| int idStart = -1; |
| if (httpIndex != -1) { |
| idStart = httpIndex; |
| } else if (httpsIndex != -1) { |
| idStart = httpsIndex; |
| } |
| if (idStart != -1) { |
| int idEnd; |
| for (idEnd = idStart; idEnd < comment.length() && !Character.isWhitespace(comment.charAt(idEnd)); idEnd++) { |
| ; |
| } |
| return comment.substring(idStart, idEnd); |
| } |
| return null; |
| } |
| |
| /** |
| * Reconcile <code>ILinkedTaskInfo</code> data. This is used in order to keep LinkedTaskInfo lightweight with |
| * minimal dependencies. |
| */ |
| private static AbstractTaskReference reconcile(AbstractTaskReference info) { |
| ITask task; |
| long timestamp; |
| |
| if (info instanceof LinkedTaskInfo) { |
| task = ((LinkedTaskInfo) info).getTask(); |
| timestamp = ((LinkedTaskInfo) info).getTimestamp(); |
| } else { |
| task = null; |
| timestamp = 0; |
| } |
| |
| if (task != null) { |
| return info; |
| } |
| |
| String repositoryUrl = info.getRepositoryUrl(); |
| String taskId = info.getTaskId(); |
| String taskFullUrl = info.getTaskUrl(); |
| String comment = info.getText(); |
| |
| TaskRepositoryManager repositoryManager = TasksUiPlugin.getRepositoryManager(); |
| |
| TaskRepository repository = null; |
| if (repositoryUrl != null) { |
| repository = repositoryManager.getRepository(repositoryUrl); |
| } |
| |
| if (taskFullUrl == null && comment != null) { |
| taskFullUrl = getUrlFromComment(comment); |
| } |
| |
| AbstractRepositoryConnector connector = null; |
| if (taskFullUrl != null) { |
| connector = repositoryManager.getConnectorForRepositoryTaskUrl(taskFullUrl); |
| } |
| if (connector == null && repository != null) { |
| connector = repositoryManager.getRepositoryConnector(repository.getConnectorKind()); |
| } |
| |
| if (repositoryUrl == null && connector != null) { |
| repositoryUrl = connector.getRepositoryUrlFromTaskUrl(taskFullUrl); |
| if (repository == null) { |
| repository = repositoryManager.getRepository(repositoryUrl); |
| } |
| } |
| |
| if (taskId == null && connector != null) { |
| taskId = connector.getTaskIdFromTaskUrl(taskFullUrl); |
| } |
| |
| // XXX: clean up and remove break to label |
| if (taskId == null && comment != null) { |
| Collection<AbstractRepositoryConnector> connectors = connector != null |
| ? Collections.singletonList(connector) |
| : TasksUi.getRepositoryManager().getRepositoryConnectors(); |
| REPOSITORIES: for (AbstractRepositoryConnector c : connectors) { |
| Collection<TaskRepository> repositories = repository != null |
| ? Collections.singletonList(repository) |
| : TasksUi.getRepositoryManager().getRepositories(c.getConnectorKind()); |
| for (TaskRepository r : repositories) { |
| String[] ids = c.getTaskIdsFromComment(r, comment); |
| if (ids != null && ids.length > 0) { |
| taskId = ids[0]; |
| connector = c; |
| repository = r; |
| repositoryUrl = r.getRepositoryUrl(); |
| break REPOSITORIES; |
| } |
| } |
| } |
| } |
| if (taskId == null && comment != null) { |
| CommitTemplateManager commitTemplateManager = FocusedTeamUiPlugin.getDefault().getCommitTemplateManager(); |
| taskId = commitTemplateManager.getTaskIdFromCommentOrLabel(comment); |
| if (taskId == null) { |
| taskId = getTaskIdFromLegacy07Label(comment); |
| } |
| } |
| |
| if (taskFullUrl == null && repositoryUrl != null && taskId != null && connector != null) { |
| taskFullUrl = connector.getTaskUrl(repositoryUrl, taskId); |
| } |
| |
| if (task == null) { |
| if (taskId != null && repositoryUrl != null) { |
| // XXX fix this hack (jira ids don't work here) |
| if (!taskId.contains(RepositoryTaskHandleUtil.HANDLE_DELIM)) { |
| task = TasksUiInternal.getTaskList().getTask(repositoryUrl, taskId); |
| } |
| } |
| if (task == null && taskFullUrl != null) { |
| task = TasksUiInternal.getTaskByUrl(taskFullUrl); |
| } |
| } |
| |
| return new LinkedTaskInfo(repositoryUrl, taskId, taskFullUrl, comment, timestamp, task); |
| } |
| |
| private final AbstractTaskReference reference; |
| |
| private ITask task; |
| |
| private long timestamp; |
| |
| public TaskFinder(Object element) { |
| this.reference = initialize(element); |
| } |
| |
| public AbstractTaskReference getReference() { |
| return reference; |
| } |
| |
| public ITask getTask() { |
| return task; |
| } |
| |
| private AbstractTaskReference initialize(Object element) { |
| AbstractTaskReference info = null; |
| if (element instanceof AbstractTaskReference) { |
| info = (AbstractTaskReference) element; |
| } else if (element instanceof IAdaptable) { |
| info = (AbstractTaskReference) ((IAdaptable) element).getAdapter(AbstractTaskReference.class); |
| } |
| if (info == null) { |
| info = (AbstractTaskReference) Platform.getAdapterManager() |
| .getAdapter(element, AbstractTaskReference.class); |
| } |
| |
| if (info != null) { |
| info = reconcile(info); |
| if (info instanceof LinkedTaskInfo) { |
| task = ((LinkedTaskInfo) info).getTask(); |
| timestamp = ((LinkedTaskInfo) info).getTimestamp(); |
| } |
| } |
| return info; |
| } |
| |
| public IStatus open() { |
| if (reference != null) { |
| if (task != null) { |
| PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { |
| public void run() { |
| TasksUiUtil.openTask(task); |
| } |
| }); |
| return Status.OK_STATUS; |
| } |
| |
| if (reference.getRepositoryUrl() != null && reference.getTaskId() != null) { |
| TaskRepository repository = TasksUiPlugin.getRepositoryManager().getRepository( |
| reference.getRepositoryUrl()); |
| String taskId = reference.getTaskId(); |
| if (repository != null && taskId != null) { |
| AbstractRepositoryConnectorUi connectorUi = TasksUiPlugin.getConnectorUi(repository.getConnectorKind()); |
| if (connectorUi != null) { |
| TasksUiInternal.openRepositoryTask(connectorUi.getConnectorKind(), |
| repository.getRepositoryUrl(), taskId, null, timestamp); |
| return Status.OK_STATUS; |
| } |
| } |
| } |
| |
| final String taskFullUrl = reference.getTaskUrl(); |
| if (taskFullUrl != null) { |
| if (!openTaskByKey(taskFullUrl)) { |
| PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { |
| public void run() { |
| TasksUiUtil.openUrl(taskFullUrl); |
| } |
| }); |
| } |
| return Status.OK_STATUS; |
| } |
| } |
| |
| // task not found |
| PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() { |
| public void run() { |
| IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); |
| boolean openDialog = MessageDialog.openQuestion(window.getShell(), |
| Messages.OpenCorrespondingTaskAction_Open_Task, |
| Messages.OpenCorrespondingTaskAction_Unable_to_match_task); |
| if (openDialog) { |
| new OpenRepositoryTaskAction().run(null); |
| } |
| } |
| }); |
| return Status.OK_STATUS; |
| } |
| |
| private boolean openTaskByKey(final String taskFullUrl) { |
| String taskKey = null; |
| TaskRepository repository = guessRepository(taskFullUrl); |
| if (repository != null) { |
| AbstractRepositoryConnector connector = TasksUiPlugin.getRepositoryManager().getRepositoryConnector( |
| repository.getConnectorKind()); |
| if (connector != null) { |
| taskKey = guessTaskKey(connector, repository, taskFullUrl); |
| } |
| } |
| if (taskKey != null) { |
| IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); |
| if (window != null) { |
| IWorkbenchPage page = window.getActivePage(); |
| new OpenRepositoryTaskJob(repository, taskKey, taskFullUrl, page).schedule(); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private TaskRepository guessRepository(String taskFullUrl) { |
| for (TaskRepository repository : TasksUi.getRepositoryManager().getAllRepositories()) { |
| if (taskFullUrl.startsWith(repository.getRepositoryUrl())) { |
| return repository; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Using a task for which we know the task key and browser URL, try to guess the task key from the given URL. |
| */ |
| private static String guessTaskKey(AbstractRepositoryConnector connector, TaskRepository repository, |
| String taskFullUrl) { |
| Set<ITask> tasks = ((TaskList) TasksUiInternal.getTaskList()).getTasks(repository.getRepositoryUrl()); |
| if (!tasks.isEmpty()) { |
| ITask task = tasks.iterator().next(); |
| URL browserUrl = connector.getBrowserUrl(repository, task); |
| if (browserUrl != null) { |
| return guessTaskKey(taskFullUrl, browserUrl.toExternalForm(), task.getTaskKey()); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * @noreference This method is not intended to be referenced by clients. |
| */ |
| public static String guessTaskKey(String taskFullUrl, String knownTaskUrl, String knownTaskKey) { |
| int index = knownTaskUrl.indexOf(knownTaskKey); |
| if (index != -1) { |
| String prefix = knownTaskUrl.substring(0, index); |
| String postfix = knownTaskUrl.substring(index + knownTaskKey.length()); |
| return extractTaskId(taskFullUrl, prefix, postfix); |
| } |
| return null; |
| } |
| |
| /** |
| * @noreference This method is not intended to be referenced by clients. |
| */ |
| public static String extractTaskId(String taskFullUrl, String prefix, String postfix) { |
| if (!prefix.isEmpty() && taskFullUrl.startsWith(prefix) && taskFullUrl.endsWith(postfix)) { |
| return taskFullUrl.substring(prefix.length(), taskFullUrl.length() - postfix.length()); |
| } |
| return null; |
| } |
| } |