blob: b5ee464c92442e6bc5f00f49c761d9d0a3b3fdb5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2016 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.commons.workbench.EditorHandle;
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 EditorHandle openTaskByKey(IWorkbenchPage page) {
if (reference != null) {
String taskUrl = reference.getTaskUrl();
if (taskUrl != null && openTaskByKey(page, taskUrl)) {
return new EditorHandle(Status.OK_STATUS);
}
}
return null;
}
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(getActivePage(), 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(IWorkbenchPage page, 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 && page != null) {
new OpenRepositoryTaskJob(repository, taskKey, taskFullUrl, page).schedule();
return true;
}
return false;
}
private IWorkbenchPage getActivePage() {
IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (window != null) {
return window.getActivePage();
}
return null;
}
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;
}
}