Project: egit-github
/*******************************************************************************
 * 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 <[email protected]> - initial contribution 
 *     Christian Trutz <[email protected]> - initial contribution 
 *     Chris Aniszczyk <[email protected]> - 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(truetrue).applyTo(labelsArea); 
  GridLayoutFactory.swtDefaults().applyTo(labelsArea); 
 
  labelsViewer = CheckboxTableViewer.newCheckList(labelsArea, SWT.BORDER 
    | SWT.V_SCROLL | SWT.H_SCROLL); 
  GridDataFactory.fillDefaults().grab(truetrue).hint(10080
    .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(truetrue).applyTo(optionsArea); 
 
  Composite statusArea = new Composite(optionsArea, SWT.NONE); 
  GridLayoutFactory.fillDefaults().numColumns(4).equalWidth(false
    .applyTo(statusArea); 
  GridDataFactory.fillDefaults().grab(truefalse).span(21
    .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(truefalse).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(truefalse
    .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(truefalse).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(truefalse).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(truetrue).applyTo(displayArea); 
 
  if (!inSearchContainer()) { 
   Composite titleArea = new Composite(displayArea, SWT.NONE); 
   GridLayoutFactory.fillDefaults().numColumns(2).applyTo(titleArea); 
   GridDataFactory.fillDefaults().grab(truefalse).span(21
     .applyTo(titleArea); 
 
   new Label(titleArea, SWT.NONE) 
     .setText(Messages.IssueRepositoryQueryPage_TitleLabel); 
   titleText = new Text(titleArea, SWT.SINGLE | SWT.BORDER); 
   GridDataFactory.fillDefaults().grab(truefalse).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); 
 
}