/*******************************************************************************
* Copyright (c) 2011 Red Hat 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:
* David Green <david.green@tasktop.com> - initial contribution
* Christian Trutz <christian.trutz@gmail.com> - initial contribution
* Chris Aniszczyk <caniszczyk@gmail.com> - initial contribution
*******************************************************************************/
package org.eclipse.mylyn.internal.github.ui.issue;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.egit.github.core.Milestone;
import org.eclipse.egit.github.core.service.IssueService;
import org.eclipse.egit.github.core.util.LabelComparator;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.mylyn.commons.core.ICoreRunnable;
import org.eclipse.mylyn.commons.net.Policy;
import org.eclipse.mylyn.commons.ui.CommonUiUtil;
import org.eclipse.mylyn.internal.github.core.QueryUtils;
import org.eclipse.mylyn.internal.github.core.issue.IssueConnector;
import org.eclipse.mylyn.internal.github.ui.GitHubImages;
import org.eclipse.mylyn.internal.github.ui.GitHubRepositoryQueryPage;
import org.eclipse.mylyn.tasks.core.IRepositoryQuery;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.tasks.ui.TasksUiImages;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.ui.PlatformUI;
/**
* GitHub issue repository query page class.
*/
public class IssueRepositoryQueryPage extends GitHubRepositoryQueryPage {
private Button openButton;
private Button closedButton;
private Text titleText;
private Text assigneeText;
private Text mentionText;
private Combo milestoneCombo;
private CheckboxTableViewer labelsViewer;
private List<Milestone> milestones;
private SelectionListener completeListener = new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
setPageComplete(isPageComplete());
}
};
/**
* @param pageName
* @param taskRepository
* @param query
*/
public IssueRepositoryQueryPage(String pageName,
TaskRepository taskRepository, IRepositoryQuery query) {
super(pageName, taskRepository, query);
setDescription(Messages.IssueRepositoryQueryPage_Description);
setPageComplete(false);
}
/**
* @param taskRepository
* @param query
*/
public IssueRepositoryQueryPage(TaskRepository taskRepository,
IRepositoryQuery query) {
this("issueQueryPage", taskRepository, query); //$NON-NLS-1$
}
private void createLabelsArea(Composite parent) {
Group labelsArea = new Group(parent, SWT.NONE);
labelsArea.setText(Messages.IssueRepositoryQueryPage_LabelsLabel);
GridDataFactory.fillDefaults().grab(true, true).applyTo(labelsArea);
GridLayoutFactory.swtDefaults().applyTo(labelsArea);
labelsViewer = CheckboxTableViewer.newCheckList(labelsArea, SWT.BORDER
| SWT.V_SCROLL | SWT.H_SCROLL);
GridDataFactory.fillDefaults().grab(true, true).hint(100, 80)
.applyTo(labelsViewer.getControl());
labelsViewer.setContentProvider(ArrayContentProvider.getInstance());
labelsViewer.setLabelProvider(new LabelProvider() {
public Image getImage(Object element) {
return GitHubImages.get(GitHubImages.GITHUB_ISSUE_LABEL_OBJ);
}
});
labelsViewer
.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
setPageComplete(isPageComplete());
}
});
}
private void createOptionsArea(Composite parent) {
Composite optionsArea = new Composite(parent, SWT.NONE);
GridLayoutFactory.fillDefaults().numColumns(2).applyTo(optionsArea);
GridDataFactory.fillDefaults().grab(true, true).applyTo(optionsArea);
Composite statusArea = new Composite(optionsArea, SWT.NONE);
GridLayoutFactory.fillDefaults().numColumns(4).equalWidth(false)
.applyTo(statusArea);
GridDataFactory.fillDefaults().grab(true, false).span(2, 1)
.applyTo(statusArea);
new Label(statusArea, SWT.NONE)
.setText(Messages.IssueRepositoryQueryPage_StatusLabel);
openButton = new Button(statusArea, SWT.CHECK);
openButton.setSelection(true);
openButton.setText(Messages.IssueRepositoryQueryPage_StatusOpen);
openButton.addSelectionListener(completeListener);
closedButton = new Button(statusArea, SWT.CHECK);
closedButton.setSelection(true);
closedButton.setText(Messages.IssueRepositoryQueryPage_StatusClosed);
closedButton.addSelectionListener(completeListener);
ToolBar toolbar = new ToolBar(statusArea, SWT.FLAT);
ToolItem updateItem = new ToolItem(toolbar, SWT.PUSH);
final Image updateImage = TasksUiImages.REPOSITORY_UPDATE_CONFIGURATION
.createImage();
toolbar.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
updateImage.dispose();
}
});
updateItem.setImage(updateImage);
updateItem
.setToolTipText(Messages.IssueRepositoryQueryPage_TooltipUpdateRepository);
GridDataFactory.fillDefaults().align(SWT.END, SWT.FILL)
.grab(true, false).applyTo(toolbar);
updateItem.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
refreshRepository();
}
});
Label milestonesLabel = new Label(optionsArea, SWT.NONE);
milestonesLabel
.setText(Messages.IssueRepositoryQueryPage_MilestoneLabel);
milestoneCombo = new Combo(optionsArea, SWT.DROP_DOWN | SWT.READ_ONLY);
GridDataFactory.fillDefaults().grab(true, false)
.applyTo(milestoneCombo);
Label assigneeLabel = new Label(optionsArea, SWT.NONE);
assigneeLabel.setText(Messages.IssueRepositoryQueryPage_AssigneeLabel);
assigneeText = new Text(optionsArea, SWT.BORDER | SWT.SINGLE);
GridDataFactory.fillDefaults().grab(true, false).applyTo(assigneeText);
Label mentionLabel = new Label(optionsArea, SWT.NONE);
mentionLabel.setText(Messages.IssueRepositoryQueryPage_MentionsLabel);
mentionText = new Text(optionsArea, SWT.BORDER | SWT.SINGLE);
GridDataFactory.fillDefaults().grab(true, false).applyTo(mentionText);
}
/**
* @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
*/
public void createControl(Composite parent) {
Composite displayArea = new Composite(parent, SWT.NONE);
GridLayoutFactory.fillDefaults().numColumns(2).equalWidth(true)
.applyTo(displayArea);
GridDataFactory.fillDefaults().grab(true, true).applyTo(displayArea);
if (!inSearchContainer()) {
Composite titleArea = new Composite(displayArea, SWT.NONE);
GridLayoutFactory.fillDefaults().numColumns(2).applyTo(titleArea);
GridDataFactory.fillDefaults().grab(true, false).span(2, 1)
.applyTo(titleArea);
new Label(titleArea, SWT.NONE)
.setText(Messages.IssueRepositoryQueryPage_TitleLabel);
titleText = new Text(titleArea, SWT.SINGLE | SWT.BORDER);
GridDataFactory.fillDefaults().grab(true, false).applyTo(titleText);
titleText.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
setPageComplete(isPageComplete());
}
});
}
createOptionsArea(displayArea);
createLabelsArea(displayArea);
loadRepository();
initialize();
setControl(displayArea);
}
private void initialize() {
IRepositoryQuery query = getQuery();
if (query == null)
return;
String milestoneNumber = query
.getAttribute(IssueService.FILTER_MILESTONE);
if (milestoneNumber != null && milestones != null) {
int index = 0;
for (Milestone milestone : milestones) {
index++;
if (milestoneNumber.equals(Integer.toString(milestone
.getNumber()))) {
milestoneCombo.select(index);
break;
}
}
}
titleText.setText(query.getSummary());
labelsViewer.setCheckedElements(QueryUtils.getAttributes(
IssueService.FILTER_LABELS, query).toArray());
List<String> status = QueryUtils.getAttributes(
IssueService.FILTER_STATE, query);
closedButton.setSelection(status.contains(IssueService.STATE_CLOSED));
openButton.setSelection(status.contains(IssueService.STATE_OPEN));
String assignee = query.getAttribute(IssueService.FILTER_ASSIGNEE);
if (assignee != null)
assigneeText.setText(assignee);
String mentioning = query.getAttribute(IssueService.FILTER_MENTIONED);
if (mentioning != null)
mentionText.setText(mentioning);
}
private boolean updateLabels() {
if (labelsViewer.getControl().isDisposed())
return false;
IssueConnector connector = IssueConnectorUi.getCoreConnector();
TaskRepository repository = getTaskRepository();
boolean hasLabels = connector.hasCachedLabels(repository);
if (hasLabels) {
List<org.eclipse.egit.github.core.Label> labels = connector
.getLabels(repository);
Collections.sort(labels, new LabelComparator());
List<String> labelNames = new ArrayList<String>(labels.size());
for (org.eclipse.egit.github.core.Label label : labels)
labelNames.add(label.getName());
labelsViewer.setInput(labelNames);
}
return hasLabels;
}
private boolean updateMilestones() {
if (milestoneCombo.isDisposed())
return false;
IssueConnector connector = IssueConnectorUi.getCoreConnector();
TaskRepository repository = getTaskRepository();
boolean hasMilestones = connector.hasCachedMilestones(repository);
if (hasMilestones) {
milestones = connector.getMilestones(repository);
milestoneCombo.removeAll();
milestoneCombo.add(Messages.IssueRepositoryQueryPage_MilestoneNone);
Collections.sort(milestones, new Comparator<Milestone>() {
public int compare(Milestone m1, Milestone m2) {
return m1.getTitle().compareToIgnoreCase(m2.getTitle());
}
});
for (Milestone milestone : milestones)
milestoneCombo.add(milestone.getTitle());
milestoneCombo.select(0);
}
return hasMilestones;
}
private void refreshRepository() {
try {
ICoreRunnable runnable = new ICoreRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
Policy.monitorFor(monitor);
monitor.beginTask("", 2); //$NON-NLS-1$
IssueConnector connector = IssueConnectorUi
.getCoreConnector();
TaskRepository repository = getTaskRepository();
monitor.setTaskName(Messages.IssueRepositoryQueryPage_TaskLoadingLabels);
connector.refreshLabels(repository);
monitor.worked(1);
monitor.setTaskName(Messages.IssueRepositoryQueryPage_TaskLoadingMilestones);
connector.refreshMilestones(repository);
monitor.done();
PlatformUI.getWorkbench().getDisplay()
.asyncExec(new Runnable() {
public void run() {
updateLabels();
updateMilestones();
initialize();
}
});
}
};
IRunnableContext context = getContainer();
if (context == null)
if (inSearchContainer())
context = getSearchContainer().getRunnableContext();
else
context = PlatformUI.getWorkbench().getProgressService();
CommonUiUtil.run(context, runnable);
} catch (CoreException e) {
IStatus status = e.getStatus();
ErrorDialog.openError(getShell(),
Messages.IssueRepositoryQueryPage_ErrorLoading,
e.getLocalizedMessage(), status);
}
}
private void loadRepository() {
boolean labelsLoaded = updateLabels();
boolean milestonesLoaded = updateMilestones();
if (!labelsLoaded || !milestonesLoaded)
refreshRepository();
}
/**
* @see org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositoryQueryPage#isPageComplete()
*/
public boolean isPageComplete() {
boolean complete = inSearchContainer() ? true : super.isPageComplete();
if (complete) {
String message = null;
if (!openButton.getSelection() && !closedButton.getSelection())
message = Messages.IssueRepositoryQueryPage_ErrorStatus;
setErrorMessage(message);
complete = message == null;
}
return complete;
}
/**
* @see org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositoryQueryPage#getQueryTitle()
*/
public String getQueryTitle() {
return titleText != null ? titleText.getText() : null;
}
/**
* @see org.eclipse.mylyn.tasks.ui.wizards.AbstractRepositoryQueryPage#applyTo(org.eclipse.mylyn.tasks.core.IRepositoryQuery)
*/
public void applyTo(IRepositoryQuery query) {
query.setSummary(getQueryTitle());
List<String> statuses = new LinkedList<String>();
if (openButton.getSelection())
statuses.add(IssueService.STATE_OPEN);
if (closedButton.getSelection())
statuses.add(IssueService.STATE_CLOSED);
QueryUtils.setAttribute(IssueService.FILTER_STATE, statuses, query);
String assignee = assigneeText.getText().trim();
if (assignee.length() > 0)
query.setAttribute(IssueService.FILTER_ASSIGNEE, assignee);
else
query.setAttribute(IssueService.FILTER_ASSIGNEE, null);
String mentions = mentionText.getText().trim();
if (mentions.length() > 0)
query.setAttribute(IssueService.FILTER_MENTIONED, mentions);
else
query.setAttribute(IssueService.FILTER_MENTIONED, null);
int milestoneSelected = milestoneCombo.getSelectionIndex() - 1;
if (milestoneSelected >= 0)
query.setAttribute(IssueService.FILTER_MILESTONE, Integer
.toString(milestones.get(milestoneSelected).getNumber()));
else
query.setAttribute(IssueService.FILTER_MILESTONE, null);
List<String> labels = new LinkedList<String>();
for (Object label : labelsViewer.getCheckedElements())
labels.add(label.toString());
QueryUtils.setAttribute(IssueService.FILTER_LABELS, labels, query);
}
}