/******************************************************************************* * 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 * 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); } }