/*******************************************************************************
* Copyright (c) 2009 Markus Knittig 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:
* Markus Knittig - initial API and implementation
*******************************************************************************/
package com.googlecode.mylyn.ui;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.hyperlink.IHyperlink;
import org.eclipse.jface.text.hyperlink.URLHyperlink;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.IWizard;
import org.eclipse.mylyn.tasks.core.IRepositoryQuery;
import org.eclipse.mylyn.tasks.core.ITask;
import org.eclipse.mylyn.tasks.core.ITaskComment;
import org.eclipse.mylyn.tasks.core.ITaskMapping;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.tasks.ui.AbstractRepositoryConnectorUi;
import org.eclipse.mylyn.tasks.ui.TaskHyperlink;
import org.eclipse.mylyn.tasks.ui.wizards.ITaskRepositoryPage;
import org.eclipse.mylyn.tasks.ui.wizards.ITaskSearchPage;
import org.eclipse.mylyn.tasks.ui.wizards.NewTaskWizard;
import org.eclipse.mylyn.tasks.ui.wizards.RepositoryQueryWizard;
import com.googlecode.mylyn.core.GoogleCodeCorePlugin;
import com.googlecode.mylyn.core.util.QueryUtils;
import com.googlecode.mylyn.ui.wizard.GoogleCodeDefinitionQueryPage;
import com.googlecode.mylyn.ui.wizard.GoogleCodeQuerySelectionPage;
import com.googlecode.mylyn.ui.wizard.GoogleCodeRepositorySettingsPage;
public class GoogleCodeConnectorUi extends AbstractRepositoryConnectorUi {
private static final String ISSUE = "Issue";
private static final String REVISION = "r";
private static final String SPACE = " ?#? ?";
private static final String INTEGER = "\\d+";
/**
* Regular expression to extract issue ids.
* <ol>
* <li>Issue (case insensitive)</li>
* <li>optional:
* <ol>
* <li>space</li>
* <li>#</li>
* </ol>
* </li>
* <li>number, once or many times</li>
* </ol>
*/
private static final Pattern ISSUE_PATTERN = Pattern.compile("(" + ISSUE + ")(" + SPACE + ")(" + INTEGER + ")",
Pattern.CASE_INSENSITIVE);
/**
* Regular expression to extract revision ids.
* <ol>
* <li>r (case insensitive)</li>
* <li>optional:
* <ol>
* <li>space</li>
* <li>#</li>
* </ol>
* </li>
* <li>number, once or many times</li>
* </ol>
*/
private static final Pattern REVISION_PATTERN = Pattern.compile("(" + REVISION + ")(" + INTEGER + ")",
Pattern.CASE_INSENSITIVE);
/**
* Index of the group in which the issue id is.
*/
private static final int ISSUE_ID_GROUP = 3;
/**
* Index of the group in which the revision id is.
*/
private static final int REVISION_ID_GROUP = 2;
@Override
public String getConnectorKind() {
return GoogleCodeCorePlugin.CONNECTOR_KIND;
}
@Override
public IWizard getNewTaskWizard(TaskRepository taskRepository, ITaskMapping selection) {
return new NewTaskWizard(taskRepository, selection);
}
@Override
public IWizard getQueryWizard(TaskRepository taskRepository, IRepositoryQuery queryToEdit) {
RepositoryQueryWizard wizard = new RepositoryQueryWizard(taskRepository);
if (queryToEdit == null || QueryUtils.isCanQuery(queryToEdit)) {
//add the query selection page only for new queries or predefined ones,
//not for existing custom ones
wizard.addPage(new GoogleCodeQuerySelectionPage(taskRepository, queryToEdit));
}
wizard.addPage(new GoogleCodeDefinitionQueryPage(taskRepository, queryToEdit));
return wizard;
}
@Override
public ITaskSearchPage getSearchPage(TaskRepository repository, IStructuredSelection selection) {
return new GoogleCodeDefinitionQueryPage(repository, null);
}
@Override
public String getTaskKindLabel(ITask task) {
//This prefix is used in the task editor title bar "Issue 23"
//could be changed to ITask#getTaskKind()
return "Issue";
}
@Override
public ImageDescriptor getTaskKindOverlay(ITask task) {
String taskType = task.getTaskKind();
if (taskType != null) {
if ("Enhancement".equals(taskType)) { //$NON-NLS-1$
return GoogleCodeImages.OVERLAY_ENHANCEMENT;
} else {
return null;
}
}
return super.getTaskKindOverlay(task);
}
@Override
public IHyperlink[] findHyperlinks(TaskRepository repository, String text, int index, int textOffset) {
List<IHyperlink> links = new ArrayList<IHyperlink>();
Matcher matcher = ISSUE_PATTERN.matcher(text);
while (matcher.find()) {
if (index == -1 || (index >= matcher.start() && index <= matcher.end())) {
IHyperlink link = extractTaskHyperlink(repository, textOffset, matcher);
links.add(link);
}
}
matcher = REVISION_PATTERN.matcher(text);
while (matcher.find()) {
if (index == -1 || (index >= matcher.start() && index <= matcher.end())) {
IHyperlink link = extractRevisionHyperlink(repository, textOffset, matcher);
links.add(link);
}
}
return links.toArray(new IHyperlink[links.size()]);
}
private static IHyperlink extractRevisionHyperlink(TaskRepository repository, int regionOffset, Matcher matcher) {
int start = matcher.start();
int end = matcher.end();
start += regionOffset;
end += regionOffset;
String revisionId = matcher.group(REVISION_ID_GROUP).trim();
IRegion region = new Region(start, end - start);
return new URLHyperlink(region, repository.getRepositoryUrl() + "/source/detail?r=" + revisionId);
}
private static IHyperlink extractTaskHyperlink(TaskRepository repository, int regionOffset,
Matcher matcher) {
int start = matcher.start();
int end = matcher.end();
start += regionOffset;
end += regionOffset;
String issueId = matcher.group(ISSUE_ID_GROUP).trim();
IRegion region = new Region(start, end - start);
return new TaskHyperlink(region, repository, issueId);
}
@Override
public ITaskRepositoryPage getSettingsPage(TaskRepository taskRepository) {
return new GoogleCodeRepositorySettingsPage(taskRepository);
}
@Override
public boolean hasSearchPage() {
return true;
}
@Override
public String getReplyText(TaskRepository taskRepository, ITask task, ITaskComment taskComment,
boolean includeTask) {
if (taskComment == null) {
return "(In reply to comment #0)";
} else {
return MessageFormat.format("(In reply to comment #{0})", taskComment.getNumber());
}
}
@Override
public String getAccountCreationUrl(TaskRepository taskRepository) {
return "https://www.google.com/accounts/NewAccount";
}
@Override
public String getAccountManagementUrl(TaskRepository taskRepository) {
return "https://www.google.com/accounts/ManageAccount";
}
}