blob: 55ea3e0c7356b2f0d7d50d3a3626af85c9c839e2 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2016 Tasktop Technologies and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Tasktop Technologies - initial API and implementation
* Frank Becker - improvements for bug 231336
* Julio Gesser - fixes for bug 303509
*******************************************************************************/
package org.eclipse.mylyn.internal.tasks.ui.util;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import org.eclipse.mylyn.internal.tasks.core.AbstractTask;
import org.eclipse.mylyn.internal.tasks.core.DateRange;
import org.eclipse.mylyn.internal.tasks.core.DayDateRange;
import org.eclipse.mylyn.internal.tasks.ui.CategorizedPresentation;
import org.eclipse.mylyn.internal.tasks.ui.ScheduledPresentation;
import org.eclipse.mylyn.internal.tasks.ui.util.SortCriterion.SortKey;
import org.eclipse.mylyn.internal.tasks.ui.views.AbstractTaskListPresentation;
import org.eclipse.mylyn.internal.tasks.ui.views.TaskKeyComparator;
import org.eclipse.mylyn.internal.tasks.ui.views.TaskListView;
import org.eclipse.mylyn.tasks.core.IRepositoryElement;
import org.eclipse.mylyn.tasks.core.ITask;
import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
import org.eclipse.ui.IMemento;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
/**
* @author Mik Kersten
* @author Frank Becker
*/
public class TaskComparator implements Comparator<ITask> {
private static final String MEMENTO_KEY_SORT = "sort"; //$NON-NLS-1$
private final ListMultimap<String, SortCriterion> sortCriteria;
private String currentPresentation;
/**
* Return a array of values to pass to taskKeyComparator.compare() for sorting
*
* @param element
* the element to sort
* @return String array[component, taskId, summary]
*/
public static String[] getSortableFromElement(IRepositoryElement element) {
final String a[] = new String[] { "", null, element.getSummary() }; //$NON-NLS-1$
if (element instanceof ITask) {
ITask task1 = (ITask) element;
if (task1.getTaskKey() != null) {
a[1] = task1.getTaskKey();
}
}
return a;
}
private final TaskKeyComparator taskKeyComparator = new TaskKeyComparator();
public static final int CRITERIA_COUNT = SortKey.values().length - 1;
public TaskComparator() {
sortCriteria = ArrayListMultimap.create();
for (AbstractTaskListPresentation presentation : TaskListView.getPresentations()) {
String presentationId = presentation.getId();
for (int i = 0; i < CRITERIA_COUNT; i++) {
sortCriteria.put(presentationId, new SortCriterion());
}
}
for (String id : sortCriteria.keySet()) {
List<SortCriterion> presentationCriteria = sortCriteria.get(id);
if (id.equals(ScheduledPresentation.ID)) {
// scheduled presentation has specific defaults
presentationCriteria.get(0).setKey(SortKey.DUE_DATE);
presentationCriteria.get(0).setDirection(SortCriterion.ASCENDING);
presentationCriteria.get(1).setKey(SortKey.SCHEDULED_DATE);
presentationCriteria.get(1).setDirection(SortCriterion.ASCENDING);
presentationCriteria.get(2).setKey(SortKey.PRIORITY);
presentationCriteria.get(3).setKey(SortKey.RANK);
presentationCriteria.get(4).setKey(SortKey.DATE_CREATED);
} else {
// standard defaults
presentationCriteria.get(0).setKey(SortKey.PRIORITY);
presentationCriteria.get(1).setKey(SortKey.RANK);
presentationCriteria.get(2).setKey(SortKey.DATE_CREATED);
}
}
currentPresentation = CategorizedPresentation.ID;
}
public int compare(ITask element1, ITask element2) {
for (SortCriterion key : getCurrentCriteria()) {
int result;
switch (key.getKey()) {
case DATE_CREATED:
result = sortByCreationDate(element1, element2, key.getDirection());
break;
case RANK:
result = sortByRank(element1, element2, key.getDirection());
break;
case PRIORITY:
result = sortByPriority(element1, element2, key.getDirection());
break;
case SUMMARY:
result = sortBySummary(element1, element2, key.getDirection());
break;
case TASK_ID:
result = sortByID(element1, element2, key.getDirection());
break;
case TASK_TYPE:
result = compare(element1.getTaskKind(), element2.getTaskKind(), key.getDirection());
break;
case DUE_DATE:
result = sortByDueDate(element1, element2, key.getDirection());
break;
case MODIFICATION_DATE:
result = sortByModificationDate(element1, element2, key.getDirection());
break;
case SCHEDULED_DATE:
result = sortByScheduledDate(element1, element2, key.getDirection());
break;
default: // NONE
return 0;
}
if (result != 0) {
return result;
}
}
return 0;
}
public SortCriterion getSortCriterion(int index) {
return getCurrentCriteria().get(index);
}
public void restoreState(IMemento memento) {
if (memento != null) {
for (String presentationId : sortCriteria.keySet()) {
List<SortCriterion> criteria = sortCriteria.get(presentationId);
for (int i = 0; i < criteria.size(); i++) {
IMemento child = memento.getChild(MEMENTO_KEY_SORT + presentationId + i);
if (child != null) {
criteria.get(i).restoreState(child);
} else if (CategorizedPresentation.ID.equals(presentationId)) {
// attempt to read memento as it would have recorded before sort criteria were stored by presentation
child = memento.getChild(MEMENTO_KEY_SORT + i);
if (child != null) {
criteria.get(i).restoreState(child);
}
}
}
}
}
}
public void saveState(IMemento memento) {
if (memento != null) {
for (String presentationId : sortCriteria.keySet()) {
List<SortCriterion> criteria = sortCriteria.get(presentationId);
for (int i = 0; i < criteria.size(); i++) {
IMemento child = memento.createChild(MEMENTO_KEY_SORT + presentationId + i);
if (child != null) {
criteria.get(i).saveState(child);
}
}
}
}
}
public void presentationChanged(AbstractTaskListPresentation presentation) {
currentPresentation = presentation.getId();
}
private List<SortCriterion> getCurrentCriteria() {
return sortCriteria.get(currentPresentation);
}
private int sortByCreationDate(ITask task1, ITask task2, int sortDirection) {
Date date1 = task1.getCreationDate();
Date date2 = task2.getCreationDate();
return compare(date1, date2, sortDirection);
}
private int sortByDueDate(ITask task1, ITask task2, int sortDirection) {
Date date1 = task1.getDueDate();
Date date2 = task2.getDueDate();
return compare(date1, date2, sortDirection);
}
private int sortByModificationDate(ITask task1, ITask task2, int sortDirection) {
Date date1 = task1.getModificationDate();
Date date2 = task2.getModificationDate();
return compare(date1, date2, sortDirection);
}
private int sortByScheduledDate(ITask task1, ITask task2, int sortDirection) {
if (task1 instanceof AbstractTask && task2 instanceof AbstractTask) {
DateRange date1 = ((AbstractTask) task1).getScheduledForDate();
DateRange date2 = ((AbstractTask) task2).getScheduledForDate();
return compare(date1, date2, sortDirection);
}
return 0;
}
private int compare(DateRange date1, DateRange date2, int sortDirection) {
if (date1 == null) {
return date2 == null ? 0 : 1;
} else if (date2 == null) {
return -1;
} else if (date1 instanceof DayDateRange && !(date2 instanceof DayDateRange)) {
return -1;
} else if (date2 instanceof DayDateRange && !(date1 instanceof DayDateRange)) {
return 1;
}
return compare(date1.getEndDate(), date2.getEndDate(), sortDirection);
}
private <T> int compare(Comparable<T> key1, T key2, int sortDirection) {
if (key1 == null) {
return (key2 != null) ? sortDirection : 0;
} else if (key2 == null) {
return -sortDirection;
}
return sortDirection * key1.compareTo(key2);
}
private int sortByID(ITask task1, ITask task2, int sortDirection) {
String key1 = task1.getTaskKey();
String key2 = task2.getTaskKey();
if (key1 == null) {
return (key2 != null) ? sortDirection : 0;
} else if (key2 == null) {
return -sortDirection;
}
return sortDirection * taskKeyComparator.compare2(key1, key2);
}
private int sortByRank(ITask task1, ITask task2, int sortDirection) {
if (task1.getConnectorKind() != null && task2.getConnectorKind() != null
&& task1.getConnectorKind().equals(task2.getConnectorKind())) {
// only compare rank of elements from the same connector
if (task1.getRepositoryUrl() != null && task2.getRepositoryUrl() != null
&& task1.getRepositoryUrl().equals(task2.getRepositoryUrl())) {
// only compare the rank of elements in the same repository
String rankString1 = task1.getAttribute(TaskAttribute.RANK);
String rankString2 = task2.getAttribute(TaskAttribute.RANK);
try {
Double rank1 = rankString1 == null || rankString1.length() == 0
? Double.valueOf(0)
: Double.valueOf(rankString1);
Double rank2 = rankString2 == null || rankString2.length() == 0
? Double.valueOf(0)
: Double.valueOf(rankString2);
return compare(rank1, rank2, sortDirection);
} catch (NumberFormatException e) {
return compare(rankString1, rankString2, sortDirection);
}
}
}
return 0;
}
private int sortByPriority(ITask task1, ITask task2, int sortDirection) {
return sortDirection * task1.getPriority().compareToIgnoreCase(task2.getPriority());
}
private int sortBySummary(ITask task1, ITask task2, int sortDirection) {
String key1 = task1.getSummary();
String key2 = task2.getSummary();
if (key1 == null) {
return (key2 != null) ? sortDirection : 0;
} else if (key2 == null) {
return -sortDirection;
}
return sortDirection * key1.compareToIgnoreCase(key2);
}
}