/** * Copyright (c) 2012 Todoroo Inc * * See the file "LICENSE" for the full license governing this code. */ package com.todoroo.astrid.core; import com.todoroo.andlib.sql.Criterion; import com.todoroo.andlib.sql.Functions; import com.todoroo.andlib.sql.Order; import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.TaskApiDao.TaskCriteria; /** * Helpers for sorting a list of tasks * * @author Tim Su <tim@todoroo.com> * */ public class SortHelper { public static final int FLAG_REVERSE_SORT = 1 << 0; public static final int FLAG_SHOW_COMPLETED = 1 << 1; public static final int FLAG_SHOW_HIDDEN = 1 << 2; public static final int FLAG_SHOW_DELETED = 1 << 3; public static final int FLAG_DRAG_DROP = 1 << 4; public static final int SORT_AUTO = 0; public static final int SORT_ALPHA = 1; public static final int SORT_DUE = 2; public static final int SORT_IMPORTANCE = 3; public static final int SORT_MODIFIED = 4; /** preference key for sort flags. stored in public prefs */ public static final String PREF_SORT_FLAGS = "sort_flags"; //$NON-NLS-1$ /** preference key for sort sort. stored in public prefs */ public static final String PREF_SORT_SORT = "sort_sort"; //$NON-NLS-1$ /** * Takes a SQL query, and if there isn't already an order, creates an order. * @param originalSql * @param flags * @param sort * @return */ @SuppressWarnings("nls") public static String adjustQueryForFlagsAndSort(String originalSql, int flags, int sort) { // sort if(originalSql == null) originalSql = ""; if(!originalSql.toUpperCase().contains("ORDER BY")) { Order order = orderForSortType(sort); if((flags & FLAG_REVERSE_SORT) > 0) order = order.reverse(); originalSql += " ORDER BY " + order; } // flags if((flags & FLAG_SHOW_COMPLETED) > 0) originalSql = originalSql.replace(Task.COMPLETION_DATE.eq(0).toString(), Criterion.all.toString()); if((flags & FLAG_SHOW_HIDDEN) > 0) originalSql = originalSql.replace(TaskCriteria.isVisible().toString(), Criterion.all.toString()); if((flags & FLAG_SHOW_DELETED) > 0) originalSql = originalSql.replace(Task.DELETION_DATE.eq(0).toString(), Criterion.all.toString()); return originalSql; } public static boolean isManualSort(int flags) { return (flags & FLAG_DRAG_DROP) > 0; } public static int setManualSort(int flags, boolean status) { flags = (flags & ~FLAG_DRAG_DROP); if(status) flags |= FLAG_DRAG_DROP; return flags; } @SuppressWarnings("nls") public static Order orderForSortType(int sortType) { Order order; switch(sortType) { case SORT_ALPHA: order = Order.asc(Functions.upper(Task.TITLE)); break; case SORT_DUE: order = Order.asc(Functions.caseStatement(Task.DUE_DATE.eq(0), Functions.now() + "*2", adjustedDueDateFunction()) + "+" + Task.IMPORTANCE + "+3*" + Task.COMPLETION_DATE); break; case SORT_IMPORTANCE: order = Order.asc(Task.IMPORTANCE + "*" + (2*DateUtilities.now()) + //$NON-NLS-1$ "+" + Functions.caseStatement(Task.DUE_DATE.eq(0), //$NON-NLS-1$ 2 * DateUtilities.now(), Task.DUE_DATE) + "+8*" + Task.COMPLETION_DATE); break; case SORT_MODIFIED: order = Order.desc(Task.MODIFICATION_DATE); break; default: order = defaultTaskOrder(); } if (sortType != SORT_ALPHA) order.addSecondaryExpression(Order.asc(Task.TITLE)); return order; } /** * Returns SQL task ordering that is astrid's default algorithm * @return */ @SuppressWarnings("nls") public static Order defaultTaskOrder() { return Order.asc(Functions.caseStatement(Task.DUE_DATE.eq(0), Functions.now() + "*2", adjustedDueDateFunction()) + " + " + (2 * DateUtilities.ONE_DAY) + " * " + Task.IMPORTANCE + " + 2*" + Task.COMPLETION_DATE); } @SuppressWarnings("nls") private static String adjustedDueDateFunction() { return new StringBuilder("(CASE WHEN (").append(Task.DUE_DATE.name).append(" / 1000) % 60 > 0") .append(" THEN ").append(Task.DUE_DATE.name).append(" ELSE ").append("(").append(Task.DUE_DATE.name) .append(" + ").append(DateUtilities.ONE_HOUR * 11 + DateUtilities.ONE_MINUTE * 59).append(") END)").toString(); } }