From 1e4b5557f6b3a27917146b0049b1ade6c0715c09 Mon Sep 17 00:00:00 2001 From: Tim Su Date: Fri, 23 Jul 2010 00:22:15 -0700 Subject: [PATCH] Re-added data stuff for legacy backup :| --- .../timsu/astrid/data/AbstractController.java | 112 +++ .../com/timsu/astrid/data/AbstractModel.java | 263 +++++++ .../com/timsu/astrid/data/Identifier.java | 55 ++ .../com/timsu/astrid/data/alerts/Alert.java | 133 ++++ .../astrid/data/alerts/AlertController.java | 144 ++++ .../timsu/astrid/data/enums/Importance.java | 66 ++ .../astrid/data/enums/RepeatInterval.java | 77 ++ .../timsu/astrid/data/location/GeoPoint.java | 39 ++ .../astrid/data/sync/SyncDataController.java | 196 ++++++ .../timsu/astrid/data/sync/SyncMapping.java | 172 +++++ .../astrid/data/tag/AbstractTagModel.java | 196 ++++++ .../timsu/astrid/data/tag/TagController.java | 328 +++++++++ .../timsu/astrid/data/tag/TagIdentifier.java | 31 + .../astrid/data/tag/TagModelForView.java | 102 +++ .../astrid/data/tag/TagToTaskMapping.java | 131 ++++ .../astrid/data/task/AbstractTaskModel.java | 628 +++++++++++++++++ .../astrid/data/task/TaskController.java | 656 ++++++++++++++++++ .../astrid/data/task/TaskIdentifier.java | 30 + .../astrid/data/task/TaskModelForEdit.java | 208 ++++++ .../data/task/TaskModelForHandlers.java | 170 +++++ .../astrid/data/task/TaskModelForList.java | 267 +++++++ .../astrid/data/task/TaskModelForNotify.java | 101 +++ .../data/task/TaskModelForProvider.java | 78 +++ .../data/task/TaskModelForReminder.java | 83 +++ .../astrid/data/task/TaskModelForSync.java | 236 +++++++ .../astrid/data/task/TaskModelForWidget.java | 73 ++ .../astrid/data/task/TaskModelForXml.java | 218 ++++++ .../timsu/astrid/provider/TasksProvider.java | 4 +- .../utilities/LegacyTasksXmlExporter.java | 17 +- 29 files changed, 4804 insertions(+), 10 deletions(-) create mode 100644 astrid/src-legacy/com/timsu/astrid/data/AbstractController.java create mode 100644 astrid/src-legacy/com/timsu/astrid/data/AbstractModel.java create mode 100644 astrid/src-legacy/com/timsu/astrid/data/Identifier.java create mode 100644 astrid/src-legacy/com/timsu/astrid/data/alerts/Alert.java create mode 100644 astrid/src-legacy/com/timsu/astrid/data/alerts/AlertController.java create mode 100644 astrid/src-legacy/com/timsu/astrid/data/enums/Importance.java create mode 100644 astrid/src-legacy/com/timsu/astrid/data/enums/RepeatInterval.java create mode 100644 astrid/src-legacy/com/timsu/astrid/data/location/GeoPoint.java create mode 100644 astrid/src-legacy/com/timsu/astrid/data/sync/SyncDataController.java create mode 100644 astrid/src-legacy/com/timsu/astrid/data/sync/SyncMapping.java create mode 100644 astrid/src-legacy/com/timsu/astrid/data/tag/AbstractTagModel.java create mode 100644 astrid/src-legacy/com/timsu/astrid/data/tag/TagController.java create mode 100644 astrid/src-legacy/com/timsu/astrid/data/tag/TagIdentifier.java create mode 100644 astrid/src-legacy/com/timsu/astrid/data/tag/TagModelForView.java create mode 100644 astrid/src-legacy/com/timsu/astrid/data/tag/TagToTaskMapping.java create mode 100644 astrid/src-legacy/com/timsu/astrid/data/task/AbstractTaskModel.java create mode 100644 astrid/src-legacy/com/timsu/astrid/data/task/TaskController.java create mode 100644 astrid/src-legacy/com/timsu/astrid/data/task/TaskIdentifier.java create mode 100644 astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForEdit.java create mode 100644 astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForHandlers.java create mode 100644 astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForList.java create mode 100644 astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForNotify.java create mode 100644 astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForProvider.java create mode 100644 astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForReminder.java create mode 100644 astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForSync.java create mode 100644 astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForWidget.java create mode 100644 astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForXml.java diff --git a/astrid/src-legacy/com/timsu/astrid/data/AbstractController.java b/astrid/src-legacy/com/timsu/astrid/data/AbstractController.java new file mode 100644 index 000000000..9aa7d4439 --- /dev/null +++ b/astrid/src-legacy/com/timsu/astrid/data/AbstractController.java @@ -0,0 +1,112 @@ +/* + * ASTRID: Android's Simple Task Recording Dashboard + * + * Copyright (c) 2009 Tim Su + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package com.timsu.astrid.data; + +import java.lang.reflect.InvocationTargetException; +import java.util.Iterator; + +import android.content.Context; +import android.database.Cursor; +import android.util.Log; + +import com.todoroo.andlib.service.Autowired; +import com.todoroo.andlib.service.DependencyInjectionService; + +/** Abstract controller class. Mostly contains some static fields */ +abstract public class AbstractController { + + protected Context context; + + // special columns + public static final String KEY_ROWID = "_id"; + + // database and table names + + @Autowired + protected String tasksTable; + + @Autowired + protected String tagsTable; + + @Autowired + protected String tagTaskTable; + + @Autowired + protected String alertsTable; + + @Autowired + protected String syncTable; + + // stuff + + public AbstractController(Context context) { + this.context = context; + DependencyInjectionService.getInstance().inject(this); + } + + abstract public void open(); + abstract public void close(); + + // cursor iterator + + public static class CursorIterator implements Iterator { + Cursor cursor; + Class cls; + + public CursorIterator(Cursor cursor, Class cls) { + this.cursor = cursor; + this.cls = cls; + } + + public boolean hasNext() { + return !cursor.isLast(); + } + + public TYPE next() { + try { + TYPE model = cls.getConstructor(Cursor.class).newInstance(cursor); + cursor.moveToNext(); + return model; + + // ugh... + } catch (IllegalArgumentException e) { + Log.e("CursorIterator", e.toString()); + } catch (SecurityException e) { + Log.e("CursorIterator", e.toString()); + } catch (InstantiationException e) { + Log.e("CursorIterator", e.toString()); + } catch (IllegalAccessException e) { + Log.e("CursorIterator", e.toString()); + } catch (InvocationTargetException e) { + Log.e("CursorIterator", e.toString()); + } catch (NoSuchMethodException e) { + Log.e("CursorIterator", e.toString()); + } + + return null; + } + + public void remove() { + throw new UnsupportedOperationException("Can't remove this way"); + } + + } + +} diff --git a/astrid/src-legacy/com/timsu/astrid/data/AbstractModel.java b/astrid/src-legacy/com/timsu/astrid/data/AbstractModel.java new file mode 100644 index 000000000..8faebb456 --- /dev/null +++ b/astrid/src-legacy/com/timsu/astrid/data/AbstractModel.java @@ -0,0 +1,263 @@ +/* + * ASTRID: Android's Simple Task Recording Dashboard + * + * Copyright (c) 2009 Tim Su + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package com.timsu.astrid.data; + +import java.util.Date; +import java.util.HashMap; + +import android.content.ContentValues; +import android.database.Cursor; + +/** A data object backed by a database */ +public abstract class AbstractModel { + + /* Data Source Ordering: + * + * In order to return the best data, we want to check first what the user + * has explicitly set (setValues), then the values we have read out of + * the database (values), the database itself (cursor), then defaults + * (getDefaultValues) + */ + + /** User set values */ + protected ContentValues setValues = new ContentValues(); + + /** Cached values from database */ + private ContentValues values = new ContentValues(); + + /** Cursor into the database */ + private Cursor cursor = null; + + // --- constructors + + /** Construct a model from scratch */ + public AbstractModel() { + // ... + } + + /** Construct a model from a database object */ + public AbstractModel(Cursor cursor) { + this.cursor = cursor; + } + + // --- data source getters + + /** Get the user-set values for this object */ + public ContentValues getSetValues() { + return setValues; + } + + /** Get the default values for this object */ + abstract public ContentValues getDefaultValues(); + + /** Get a list of all field/value pairs merged across data sources */ + public ContentValues getMergedValues() { + ContentValues mergedValues = new ContentValues(); + + mergedValues.putAll(getDefaultValues()); + mergedValues.putAll(values); + mergedValues.putAll(setValues); + + return mergedValues; + } + + /** Return the database cursor */ + public Cursor getCursor() { + return cursor; + } + + // --- checking against cached values + + protected void putIfChangedFromDatabase(String field, String newValue) { + if(!setValues.containsKey(field) && values.containsKey(field)) { + String value = values.getAsString(field); + if(value == null) { + if(newValue == null) + return; + } else if(value.equals(newValue)) + return; + } + setValues.put(field, newValue); + } + + protected void putIfChangedFromDatabase(String field, Long newValue) { + if(!setValues.containsKey(field) && values.containsKey(field)) { + Long value = values.getAsLong(field); + if(value == null) { + if(newValue == null) + return; + } else if(value.equals(newValue)) + return; + } + setValues.put(field, newValue); + } + + protected void putIfChangedFromDatabase(String field, Integer newValue) { + if(!setValues.containsKey(field) && values.containsKey(field)) { + Integer value = values.getAsInteger(field); + if(value == null) { + if(newValue == null) + return; + } else if(value.equals(newValue)) + return; + } + setValues.put(field, newValue); + } + + protected void putIfChangedFromDatabase(String field, Double newValue) { + if(!setValues.containsKey(field) && values.containsKey(field)) { + Double value = values.getAsDouble(field); + if(value == null) { + if(newValue == null) + return; + } else if(value.equals(newValue)) + return; + } + setValues.put(field, newValue); + } + + protected static final HashMap, HashMap> + columnIndexCache = new HashMap, HashMap>(); + private int getColumnIndex(String field) { + HashMap classCache; + classCache = columnIndexCache.get(getClass()); + if(classCache == null) { + classCache = new HashMap(); + columnIndexCache.put(getClass(), classCache); + } + + Integer index = classCache.get(field); + if(index == null) { + index = cursor.getColumnIndexOrThrow(field); + classCache.put(field, index); + } + + return index; + } + + // --- data retrieval for the different object types + + protected String retrieveString(String field) { + if(setValues.containsKey(field)) + return setValues.getAsString(field); + + if(values.containsKey(field)) + return values.getAsString(field); + + // if we have a database to hit, do that now + if(cursor != null) { + String value = cursor.getString(getColumnIndex(field)); + values.put(field, value); + return value; + } + + // do we have defaults? + ContentValues defaults = getDefaultValues(); + if(defaults != null && defaults.containsKey(field)) + return defaults.getAsString(field); + + throw new UnsupportedOperationException("Could not read field " + field); + } + + protected Integer retrieveInteger(String field) { + if(setValues.containsKey(field)) + return setValues.getAsInteger(field); + + if(values.containsKey(field)) + return values.getAsInteger(field); + + // if we have a database to hit, do that now + if(cursor != null) { + try { + Integer value = cursor.getInt(getColumnIndex(field)); + values.put(field, value); + return value; + } catch (Exception e) { + // error reading from cursor, try to continue + } + } + + // do we have defaults? + ContentValues defaults = getDefaultValues(); + if(defaults != null && defaults.containsKey(field)) + return defaults.getAsInteger(field); + + throw new UnsupportedOperationException("Could not read field " + field); + } + + protected Long retrieveLong(String field) { + if(setValues.containsKey(field)) + return setValues.getAsLong(field); + + if(values.containsKey(field)) + return values.getAsLong(field); + + // if we have a database to hit, do that now + if(cursor != null) { + Long value = cursor.getLong(getColumnIndex(field)); + values.put(field, value); + return value; + } + + // do we have defaults? + ContentValues defaults = getDefaultValues(); + if(defaults != null && defaults.containsKey(field)) + return defaults.getAsLong(field); + + throw new UnsupportedOperationException("Could not read field " + field); + } + + protected Double retrieveDouble(String field) { + if(setValues.containsKey(field)) + return setValues.getAsDouble(field); + + if(values.containsKey(field)) + return values.getAsDouble(field); + + // if we have a database to hit, do that now + if(cursor != null) { + Double value = cursor.getDouble(getColumnIndex(field)); + values.put(field, value); + return value; + } + + // do we have defaults? + ContentValues defaults = getDefaultValues(); + if(defaults != null && defaults.containsKey(field)) + return defaults.getAsDouble(field); + + throw new UnsupportedOperationException("Could not read field " + field); + } + + // --- retrieving composite objects + + protected Date retrieveDate(String field) { + Long time; + try { + time = retrieveLong(field); + if(time == null || time == 0) + return null; + } catch (NullPointerException e) { + return null; + } + + return new Date(time); + } +} diff --git a/astrid/src-legacy/com/timsu/astrid/data/Identifier.java b/astrid/src-legacy/com/timsu/astrid/data/Identifier.java new file mode 100644 index 000000000..68a228116 --- /dev/null +++ b/astrid/src-legacy/com/timsu/astrid/data/Identifier.java @@ -0,0 +1,55 @@ +/* + * ASTRID: Android's Simple Task Recording Dashboard + * + * Copyright (c) 2009 Tim Su + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package com.timsu.astrid.data; + +/** Identifier of a single object. Extend this class to create your own */ +public abstract class Identifier { + private long id; + + public Identifier(long id) { + this.id = id; + } + + public long getId() { + return id; + } + + public String idAsString() { + return Long.toString(id); + } + + @Override + public int hashCode() { + return (int)id; + } + + @Override + public boolean equals(Object o) { + if(o == null || o.getClass() != getClass()) + return false; + + return ((Identifier)o).getId() == getId(); + } + + @Override + public String toString() { + return getClass().getSimpleName() + ": " + id; + } +} diff --git a/astrid/src-legacy/com/timsu/astrid/data/alerts/Alert.java b/astrid/src-legacy/com/timsu/astrid/data/alerts/Alert.java new file mode 100644 index 000000000..656deff4c --- /dev/null +++ b/astrid/src-legacy/com/timsu/astrid/data/alerts/Alert.java @@ -0,0 +1,133 @@ +/* + * ASTRID: Android's Simple Task Recording Dashboard + * + * Copyright (c) 2009 Tim Su + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package com.timsu.astrid.data.alerts; + +import java.util.Date; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.util.Log; + +import com.timsu.astrid.data.AbstractController; +import com.timsu.astrid.data.AbstractModel; +import com.timsu.astrid.data.task.TaskIdentifier; + + +/** A single alert on a task */ +public class Alert extends AbstractModel { + + /** Version number of this model */ + static final int VERSION = 1; + + // field names + + public static final String TASK = "task"; + public static final String DATE = "date"; + + /** Default values container */ + private static final ContentValues defaultValues = new ContentValues(); + + @Override + public ContentValues getDefaultValues() { + return defaultValues; + } + + static String[] FIELD_LIST = new String[] { + AbstractController.KEY_ROWID, + TASK, + DATE, + }; + + // --- database helper + + /** Database Helper manages creating new tables and updating old ones */ + static class AlertDatabaseHelper extends SQLiteOpenHelper { + String tableName; + Context context; + + AlertDatabaseHelper(Context context, String databaseName, String tableName) { + super(context, databaseName, null, VERSION); + this.tableName = tableName; + this.context = context; + } + + @Override + public synchronized void onCreate(SQLiteDatabase db) { + String sql = new StringBuilder(). + append("CREATE TABLE IF NOT EXISTS ").append(tableName).append(" ("). + append(AbstractController.KEY_ROWID).append(" integer primary key autoincrement, "). + append(TASK).append(" integer not null,"). + append(DATE).append(" integer not null,"). + append("unique (").append(TASK).append(",").append(DATE).append(")"). + append(");").toString(); + db.execSQL(sql); + } + + @Override + public synchronized void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + Log.w(getClass().getSimpleName(), "Upgrading database from version " + + oldVersion + " to " + newVersion + "."); + + switch(oldVersion) { + default: + // we don't know how to handle it... show an error + Log.e(getClass().getSimpleName(), "Unsupported migration from " + oldVersion + " to " + newVersion); + } + } + } + + + // --- constructor pass-through + + Alert(TaskIdentifier task, Date date) { + super(); + setTask(task); + setDate(date); + } + + public Alert(Cursor cursor) { + super(cursor); + } + + // --- getters and setters: expose them as you see fit + + public boolean isNew() { + return getCursor() == null; + } + + public TaskIdentifier getTask() { + return new TaskIdentifier(retrieveLong(TASK)); + } + + public Date getDate() { + return new Date(retrieveLong(DATE)); + } + + private void setTask(TaskIdentifier task) { + setValues.put(TASK, task.getId()); + } + + private void setDate(Date date) { + setValues.put(DATE, date.getTime()); + } +} diff --git a/astrid/src-legacy/com/timsu/astrid/data/alerts/AlertController.java b/astrid/src-legacy/com/timsu/astrid/data/alerts/AlertController.java new file mode 100644 index 000000000..6b2fb04cc --- /dev/null +++ b/astrid/src-legacy/com/timsu/astrid/data/alerts/AlertController.java @@ -0,0 +1,144 @@ +/* + * ASTRID: Android's Simple Task Recording Dashboard + * + * Copyright (c) 2009 Tim Su + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package com.timsu.astrid.data.alerts; + +import java.util.Date; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.SQLException; +import android.database.sqlite.SQLiteDatabase; + +import com.timsu.astrid.data.AbstractController; +import com.timsu.astrid.data.alerts.Alert.AlertDatabaseHelper; +import com.timsu.astrid.data.task.TaskIdentifier; + +/** Controller for Tag-related operations */ +public class AlertController extends AbstractController { + + private SQLiteDatabase alertDatabase; + + /** Get a cursor to tag identifiers */ + public Cursor getTaskAlertsCursor(TaskIdentifier taskId) throws SQLException { + Cursor cursor = alertDatabase.query(alertsTable, + Alert.FIELD_LIST, Alert.TASK + " = ?", + new String[] { taskId.idAsString() }, null, null, null); + return cursor; + } + + /** Get a list of alerts for the given task */ + public List getTaskAlerts(TaskIdentifier + taskId) throws SQLException { + List list = new LinkedList(); + Cursor cursor = alertDatabase.query(alertsTable, + Alert.FIELD_LIST, Alert.TASK + " = ?", + new String[] { taskId.idAsString() }, null, null, null); + + try { + if(cursor.getCount() == 0) + return list; + do { + cursor.moveToNext(); + list.add(new Alert(cursor).getDate()); + } while(!cursor.isLast()); + + return list; + } finally { + cursor.close(); + } + } + + + /** Get a list of alerts that are set for the future */ + public Set getTasksWithActiveAlerts() throws SQLException { + Set list = new HashSet(); + Cursor cursor = alertDatabase.query(alertsTable, + Alert.FIELD_LIST, Alert.DATE + " > ?", + new String[] { Long.toString(System.currentTimeMillis()) }, null, null, null); + + try { + if(cursor.getCount() == 0) + return list; + do { + cursor.moveToNext(); + list.add(new Alert(cursor).getTask()); + } while(!cursor.isLast()); + + return list; + } finally { + cursor.close(); + } + } + + /** Remove all alerts from the task */ + public boolean removeAlerts(TaskIdentifier taskId) + throws SQLException{ + return alertDatabase.delete(alertsTable, + String.format("%s = ?", + Alert.TASK), + new String[] { taskId.idAsString() }) > 0; + } + + /** Add the given tag to the task */ + public boolean addAlert(TaskIdentifier taskId, Date date) + throws SQLException { + ContentValues values = new ContentValues(); + values.put(Alert.DATE, date.getTime()); + values.put(Alert.TASK, taskId.getId()); + return alertDatabase.insert(alertsTable, Alert.TASK, + values) >= 0; + } + + // --- boilerplate + + /** + * Constructor - takes the context to allow the database to be + * opened/created + */ + public AlertController(Context context) { + super(context); + } + + /** + * Open the notes database. If it cannot be opened, try to create a new + * instance of the database. If it cannot be created, throw an exception to + * signal the failure + * + * @return this (self reference, allowing this to be chained in an + * initialization call) + * @throws SQLException if the database could be neither opened or created + */ + @Override + public void open() throws SQLException { + alertDatabase = new AlertDatabaseHelper(context, + alertsTable, alertsTable).getWritableDatabase(); + } + + /** Closes database resource */ + @Override + public void close() { + alertDatabase.close(); + } +} diff --git a/astrid/src-legacy/com/timsu/astrid/data/enums/Importance.java b/astrid/src-legacy/com/timsu/astrid/data/enums/Importance.java new file mode 100644 index 000000000..b7082d225 --- /dev/null +++ b/astrid/src-legacy/com/timsu/astrid/data/enums/Importance.java @@ -0,0 +1,66 @@ +/* + * ASTRID: Android's Simple Task Recording Dashboard + * + * Copyright (c) 2009 Tim Su + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package com.timsu.astrid.data.enums; + +import com.timsu.astrid.R; + +public enum Importance { + // MOST IMPORTANT + + LEVEL_1(R.string.importance_1, + R.color.importance_1, + R.color.task_list_importance_1), + LEVEL_2(R.string.importance_2, + R.color.importance_2, + R.color.task_list_importance_2), + LEVEL_3(R.string.importance_3, + R.color.importance_3, + R.color.task_list_importance_3), + LEVEL_4(R.string.importance_4, + R.color.importance_4, + R.color.task_list_importance_4), + + // LEAST IMPORTANT + ; + + int label; + int color; + int taskListColor; + public static final Importance DEFAULT = LEVEL_3; + + private Importance(int label, int color, int taskListColor) { + this.label = label; + this.color = color; + this.taskListColor = taskListColor; + } + + public int getLabelResource() { + return label; + } + + public int getColorResource() { + return color; + } + + public int getTaskListColor() { + return taskListColor; + } + +} diff --git a/astrid/src-legacy/com/timsu/astrid/data/enums/RepeatInterval.java b/astrid/src-legacy/com/timsu/astrid/data/enums/RepeatInterval.java new file mode 100644 index 000000000..dd1239013 --- /dev/null +++ b/astrid/src-legacy/com/timsu/astrid/data/enums/RepeatInterval.java @@ -0,0 +1,77 @@ +/* + * ASTRID: Android's Simple Task Recording Dashboard + * + * Copyright (c) 2009 Tim Su + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package com.timsu.astrid.data.enums; + +import java.util.Date; + +import android.content.res.Resources; + +import com.timsu.astrid.R; + +public enum RepeatInterval { + + DAYS(R.string.repeat_days) { + @Override + public void offsetDateBy(Date input, int number) { + input.setDate(input.getDate() + number); + } + }, + WEEKS(R.string.repeat_weeks) { + @Override + public void offsetDateBy(Date input, int number) { + input.setDate(input.getDate() + 7 * number); + } + }, + MONTHS(R.string.repeat_months) { + @Override + public void offsetDateBy(Date input, int number) { + input.setMonth(input.getMonth() + number); + } + }, + HOURS(R.string.repeat_hours) { + @Override + public void offsetDateBy(Date input, int number) { + input.setHours(input.getHours() + number); + } + }, + + ; + + int label; + + private RepeatInterval(int label) { + this.label = label; + } + + public int getLabelResource() { + return label; + } + + abstract public void offsetDateBy(Date input, int number); + + public static String[] getLabels(Resources r) { + int intervalCount = RepeatInterval.values().length; + String[] result = new String[intervalCount]; + + for(int i = 0; i < intervalCount; i++) + result[i] = r.getString(RepeatInterval.values()[i].getLabelResource()); + return result; + } +} diff --git a/astrid/src-legacy/com/timsu/astrid/data/location/GeoPoint.java b/astrid/src-legacy/com/timsu/astrid/data/location/GeoPoint.java new file mode 100644 index 000000000..e3bfbcb9d --- /dev/null +++ b/astrid/src-legacy/com/timsu/astrid/data/location/GeoPoint.java @@ -0,0 +1,39 @@ +/* + * ASTRID: Android's Simple Task Recording Dashboard + * + * Copyright (c) 2009 Tim Su + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package com.timsu.astrid.data.location; + +public class GeoPoint { + + private int latitude, longitude; + + public GeoPoint(int latitude, int longitude) { + this.latitude = latitude; + this.longitude = longitude; + } + + public int getLatitudeE6() { + return latitude; + } + + public int getLongitudeE6() { + return longitude; + } + +} diff --git a/astrid/src-legacy/com/timsu/astrid/data/sync/SyncDataController.java b/astrid/src-legacy/com/timsu/astrid/data/sync/SyncDataController.java new file mode 100644 index 000000000..6c6319621 --- /dev/null +++ b/astrid/src-legacy/com/timsu/astrid/data/sync/SyncDataController.java @@ -0,0 +1,196 @@ +/* + * ASTRID: Android's Simple Task Recording Dashboard + * + * Copyright (c) 2009 Tim Su + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package com.timsu.astrid.data.sync; + +import java.util.HashSet; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.SQLException; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +import com.timsu.astrid.data.AbstractController; +import com.timsu.astrid.data.sync.SyncMapping.SyncMappingDatabaseHelper; +import com.timsu.astrid.data.task.AbstractTaskModel; +import com.timsu.astrid.data.task.TaskIdentifier; +import com.timsu.astrid.data.task.TaskModelForSync; + +/** Controller for Tag-related operations */ +public class SyncDataController extends AbstractController { + + private SQLiteDatabase syncDatabase; + + + // --- updated tasks list + + /** Mark all updated tasks as finished synchronizing */ + public boolean clearUpdatedTaskList(int syncServiceId) throws SQLException { + ContentValues values = new ContentValues(); + values.put(SyncMapping.UPDATED, 0); + return syncDatabase.update(syncTable, values, + SyncMapping.SYNC_SERVICE + " = " + syncServiceId, null) > 0; + } + + /** Indicate that this task's properties were updated */ + public boolean addToUpdatedList(TaskIdentifier taskId) throws SQLException { + ContentValues values = new ContentValues(); + values.put(SyncMapping.UPDATED, 1); + return syncDatabase.update(syncTable, values, + SyncMapping.TASK + " = " + taskId.getId(), null) > 0; + } + + public static void taskUpdated(Context context, AbstractTaskModel task) { + if(!(task instanceof TaskModelForSync)) { + SyncDataController syncController = new SyncDataController(context); + syncController.open(); + syncController.addToUpdatedList(task.getTaskIdentifier()); + syncController.close(); + } + } + + // --- sync mapping + + /** Get all mappings for the given synchronization service */ + public HashSet getSyncMappings(int syncServiceId) throws SQLException { + HashSet list = new HashSet(); + Cursor cursor = syncDatabase.query(syncTable, + SyncMapping.FIELD_LIST, + SyncMapping.SYNC_SERVICE + " = " + syncServiceId, + null, null, null, null); + + try { + if(cursor.getCount() == 0) + return list; + do { + cursor.moveToNext(); + list.add(new SyncMapping(cursor)); + } while(!cursor.isLast()); + + return list; + } finally { + cursor.close(); + } + } + + /** Get all mappings for specified task for all synchronization services */ + public HashSet getSyncMappings(TaskIdentifier taskId) + throws SQLException { + HashSet list = new HashSet(); + Cursor cursor = syncDatabase.query(syncTable, + SyncMapping.FIELD_LIST, + SyncMapping.TASK + " = ?", + new String[] { "" + taskId.getId() }, + null, null, null); + + try { + if(cursor.getCount() == 0) + return list; + do { + cursor.moveToNext(); + list.add(new SyncMapping(cursor)); + } while(!cursor.isLast()); + + return list; + } finally { + cursor.close(); + } + } + + /** Get mapping for given task */ + public SyncMapping getSyncMapping(int syncServiceId, TaskIdentifier taskId) + throws SQLException { + Cursor cursor = syncDatabase.query(syncTable, + SyncMapping.FIELD_LIST, + SyncMapping.SYNC_SERVICE + " = ? AND " + + SyncMapping.TASK + " = ?", + new String[] { "" + syncServiceId, "" + taskId.getId() }, + null, null, null); + + try { + if(cursor.getCount() == 0) + return null; + cursor.moveToNext(); + return new SyncMapping(cursor); + } finally { + cursor.close(); + } + } + + /** Saves the given task to the database. Returns true on success. */ + public boolean saveSyncMapping(SyncMapping mapping) { + long newRow = syncDatabase.insert(syncTable, SyncMapping.TASK, + mapping.getMergedValues()); + + mapping.setId(newRow); + + return newRow >= 0; + } + + /** Deletes the given mapping. Returns true on success */ + public boolean deleteSyncMapping(SyncMapping mapping) { + // was never saved + if(mapping.getId() == 0) + return false; + + return syncDatabase.delete(syncTable, KEY_ROWID + "=" + + mapping.getId(), null) > 0; + } + + /** Deletes the given mapping. Returns true on success */ + public boolean deleteAllMappings(int syncServiceId) { + return syncDatabase.delete(syncTable, SyncMapping.SYNC_SERVICE + + "=" + syncServiceId, null) > 0; + } + + // --- boilerplate + + /** + * Constructor - takes the context to allow the database to be + * opened/created + */ + public SyncDataController(Context context) { + super(context); + } + + /** + * Open the notes database. If it cannot be opened, try to create a new + * instance of the database. If it cannot be created, throw an exception to + * signal the failure + * + * @return this (self reference, allowing this to be chained in an + * initialization call) + * @throws SQLException if the database could be neither opened or created + */ + @Override + public synchronized void open() throws SQLException { + SQLiteOpenHelper helper = new SyncMappingDatabaseHelper(context, + syncTable, syncTable); + syncDatabase = helper.getWritableDatabase(); + } + + /** Closes database resource */ + @Override + public void close() { + if(syncDatabase != null) + syncDatabase.close(); + } +} diff --git a/astrid/src-legacy/com/timsu/astrid/data/sync/SyncMapping.java b/astrid/src-legacy/com/timsu/astrid/data/sync/SyncMapping.java new file mode 100644 index 000000000..fe64bae87 --- /dev/null +++ b/astrid/src-legacy/com/timsu/astrid/data/sync/SyncMapping.java @@ -0,0 +1,172 @@ +/* + * ASTRID: Android's Simple Task Recording Dashboard + * + * Copyright (c) 2009 Tim Su + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package com.timsu.astrid.data.sync; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.util.Log; + +import com.timsu.astrid.data.AbstractController; +import com.timsu.astrid.data.AbstractModel; +import com.timsu.astrid.data.task.TaskIdentifier; + + +/** A single tag on a task */ +public class SyncMapping extends AbstractModel { + + + /** Version number of this model */ + static final int VERSION = 1; + + // field names + + static final String TASK = "task"; + static final String SYNC_SERVICE = "service"; + static final String REMOTE_ID = "remoteId"; + static final String UPDATED = "updated"; + + /** Default values container */ + private static final ContentValues defaultValues = new ContentValues(); + static { + defaultValues.put(UPDATED, 0); + } + + @Override + public ContentValues getDefaultValues() { + return defaultValues; + } + + static String[] FIELD_LIST = new String[] { + AbstractController.KEY_ROWID, + TASK, + SYNC_SERVICE, + REMOTE_ID, + UPDATED, + }; + + // --- database helper + + /** Database Helper manages creating new tables and updating old ones */ + static class SyncMappingDatabaseHelper extends SQLiteOpenHelper { + String tableName; + Context context; + + SyncMappingDatabaseHelper(Context context, String databaseName, String tableName) { + super(context, databaseName, null, VERSION); + this.tableName = tableName; + this.context = context; + } + + @Override + public synchronized void onCreate(SQLiteDatabase db) { + String sql = new StringBuilder(). + append("CREATE TABLE IF NOT EXISTS ").append(tableName).append(" ("). + append(AbstractController.KEY_ROWID).append(" integer primary key autoincrement, "). + append(TASK).append(" integer not null,"). + append(SYNC_SERVICE).append(" integer not null,"). + append(REMOTE_ID).append(" text not null,"). + append(UPDATED).append(" integer not null,"). + append("unique (").append(TASK).append(",").append(SYNC_SERVICE).append(")"). + append(");").toString(); + db.execSQL(sql); + } + + @Override + public synchronized void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + Log.w(getClass().getSimpleName(), "Upgrading database from version " + + oldVersion + " to " + newVersion + "."); + + switch(oldVersion) { + default: + // we don't know how to handle it... show an error + Log.e(getClass().getSimpleName(), "Unsupported migration from " + oldVersion + " to " + newVersion); + + } + } + } + + + // --- constructor pass-through +// +// public SyncMapping(TaskIdentifier task, TaskProxy taskProxy) { +// this(task, taskProxy.getSyncServiceId(), taskProxy.getRemoteId()); +// } + + public SyncMapping(TaskIdentifier task, int syncServiceId, String remoteId) { + super(); + setTask(task); + setSyncServiceId(syncServiceId); + setRemoteId(remoteId); + } + + SyncMapping(Cursor cursor) { + super(cursor); + getId(); + getTask(); + getSyncServiceId(); + getRemoteId(); + isUpdated(); + } + + // --- getters and setters + + public void setId(long id) { + putIfChangedFromDatabase(AbstractController.KEY_ROWID, id); + } + + public long getId() { + try { + return retrieveLong(AbstractController.KEY_ROWID); + } catch (UnsupportedOperationException e) { + return 0; + } + } + + public TaskIdentifier getTask() { + return new TaskIdentifier(retrieveLong(TASK)); + } + + public int getSyncServiceId() { + return retrieveInteger(SYNC_SERVICE); + } + + public String getRemoteId() { + return retrieveString(REMOTE_ID); + } + + public boolean isUpdated() { + return retrieveInteger(UPDATED) == 1; + } + + private void setTask(TaskIdentifier task) { + setValues.put(TASK, task.getId()); + } + + private void setSyncServiceId(int id) { + setValues.put(SYNC_SERVICE, id); + } + + private void setRemoteId(String remoteId) { + setValues.put(REMOTE_ID, remoteId); + } +} diff --git a/astrid/src-legacy/com/timsu/astrid/data/tag/AbstractTagModel.java b/astrid/src-legacy/com/timsu/astrid/data/tag/AbstractTagModel.java new file mode 100644 index 000000000..4d49ce47c --- /dev/null +++ b/astrid/src-legacy/com/timsu/astrid/data/tag/AbstractTagModel.java @@ -0,0 +1,196 @@ +/* + * ASTRID: Android's Simple Task Recording Dashboard + * + * Copyright (c) 2009 Tim Su + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package com.timsu.astrid.data.tag; + +import java.util.Date; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.util.Log; + +import com.timsu.astrid.data.AbstractController; +import com.timsu.astrid.data.AbstractModel; + + +/** Abstract model of a task. Subclasses implement the getters and setters + * they are interested in. + * + * @author timsu + * + */ +public abstract class AbstractTagModel extends AbstractModel { + + /** Version number of this model */ + static final int VERSION = 1; + + // field names + + static final String NAME = "name"; + static final String NOTES = "notes"; + // reserved fields + static final String ICON = "icon"; + static final String PARENT = "parent"; + static final String FLAGS = "flags"; + static final String LOCATION_LAT = "locationLat"; + static final String LOCATION_LONG = "locationLong"; + static final String NOTIFICATIONS = "notifications"; + // end reserved fields + static final String CREATION_DATE = "creationDate"; + + /** Default values container */ + private static final ContentValues defaultValues = new ContentValues(); + + static { + defaultValues.put(NAME, ""); + defaultValues.put(NOTES, ""); + defaultValues.put(ICON, 0); + defaultValues.put(PARENT, 0); + defaultValues.put(FLAGS, 0); + defaultValues.put(LOCATION_LAT, 0); + defaultValues.put(LOCATION_LONG, 0); + defaultValues.put(NOTIFICATIONS, 0); + } + + @Override + public ContentValues getDefaultValues() { + return defaultValues; + } + + // --- database helper + + /** Database Helper manages creating new tables and updating old ones */ + static class TagModelDatabaseHelper extends SQLiteOpenHelper { + String tableName; + Context context; + + TagModelDatabaseHelper(Context context, String databaseName, String tableName) { + super(context, databaseName, null, VERSION); + this.tableName = tableName; + this.context = context; + } + + @Override + public synchronized void onCreate(SQLiteDatabase db) { + String sql = new StringBuilder(). + append("CREATE TABLE IF NOT EXISTS ").append(tableName).append(" ("). + append(AbstractController.KEY_ROWID).append(" integer primary key autoincrement, "). + append(NAME).append(" text unique,"). + append(NOTES).append(" text,"). + append(ICON).append(" integer,"). + append(PARENT).append(" integer,"). + append(FLAGS).append(" integer,"). + append(LOCATION_LAT).append(" integer,"). + append(LOCATION_LONG).append(" integer,"). + append(NOTIFICATIONS).append(" integer,"). + append(CREATION_DATE).append(" integer"). + append(");").toString(); + db.execSQL(sql); + } + + @Override + public synchronized void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + Log.w(getClass().getSimpleName(), "Upgrading database from version " + + oldVersion + " to " + newVersion + "."); + + switch(oldVersion) { + default: + // we don't know how to handle it... show an error + Log.e(getClass().getSimpleName(), "Unsupported migration from " + oldVersion + " to " + newVersion); + } + } + } + + // --- utility methods + + + + // --- identifier + + private TagIdentifier identifier = null; + + public TagIdentifier getTagIdentifier() { + return identifier; + } + + void setTagIdentifier(TagIdentifier identifier) { + this.identifier = identifier; + } + + // --- constructor pass-through + + AbstractTagModel() { + super(); + } + + /** Read identifier from database */ + AbstractTagModel(Cursor cursor) { + super(cursor); + + Integer id = retrieveInteger(AbstractController.KEY_ROWID); + setTagIdentifier(new TagIdentifier(id)); + } + + /** Get identifier from argument */ + AbstractTagModel(TagIdentifier identifier, Cursor cursor) { + super(cursor); + + setTagIdentifier(identifier); + } + + // --- getters and setters: expose them as you see fit + + protected String getName() { + return retrieveString(NAME); + } + + protected String getNotes() { + return retrieveString(NOTES); + } + + protected Date getCreationDate() { + return retrieveDate(CREATION_DATE); + } + + // --- setters + + protected void setName(String name) { + setValues.put(NAME, name.trim()); + } + + protected void setNotes(String notes) { + setValues.put(NOTES, notes); + } + + protected void setCreationDate(Date creationDate) { + putDate(setValues, CREATION_DATE, creationDate); + } + + // --- utility methods + + static void putDate(ContentValues cv, String fieldName, Date date) { + if(date == null) + cv.put(fieldName, (Long)null); + else + cv.put(fieldName, date.getTime()); + } +} diff --git a/astrid/src-legacy/com/timsu/astrid/data/tag/TagController.java b/astrid/src-legacy/com/timsu/astrid/data/tag/TagController.java new file mode 100644 index 000000000..957113731 --- /dev/null +++ b/astrid/src-legacy/com/timsu/astrid/data/tag/TagController.java @@ -0,0 +1,328 @@ +/* + * ASTRID: Android's Simple Task Recording Dashboard + * + * Copyright (c) 2009 Tim Su + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package com.timsu.astrid.data.tag; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.SQLException; +import android.database.sqlite.SQLiteDatabase; + +import com.timsu.astrid.data.AbstractController; +import com.timsu.astrid.data.tag.AbstractTagModel.TagModelDatabaseHelper; +import com.timsu.astrid.data.tag.TagToTaskMapping.TagToTaskMappingDatabaseHelper; +import com.timsu.astrid.data.task.AbstractTaskModel.TaskModelDatabaseHelper; +import com.timsu.astrid.data.task.TaskIdentifier; +import com.timsu.astrid.provider.TasksProvider; + +/** Controller for Tag-related operations */ +public class TagController extends AbstractController { + + private SQLiteDatabase tagDatabase, tagToTaskMapDatabase; + + // --- tag batch operations + + /** Get a list of all tags */ + public LinkedList getAllTags() + throws SQLException { + LinkedList list = new LinkedList(); + Cursor cursor = tagDatabase.query(tagsTable, + TagModelForView.FIELD_LIST, null, null, null, null, null, null); + + try { + if(cursor.getCount() == 0) + return list; + do { + cursor.moveToNext(); + list.add(new TagModelForView(cursor)); + } while(!cursor.isLast()); + } finally { + cursor.close(); + } + + return list; + } + + // --- tag to task map batch operations + + /** Get a list of all tags as an id => tag map */ + public HashMap getAllTagsAsMap() throws SQLException { + HashMap map = new HashMap(); + for(TagModelForView tag : getAllTags()) + map.put(tag.getTagIdentifier(), tag); + return map; + } + + /** Get a list of tag identifiers for the given task */ + public LinkedList getTaskTags(TaskIdentifier + taskId) throws SQLException { + LinkedList list = new LinkedList(); + Cursor cursor = tagToTaskMapDatabase.query(tagTaskTable, + TagToTaskMapping.FIELD_LIST, TagToTaskMapping.TASK + " = ?", + new String[] { taskId.idAsString() }, null, null, null); + + try { + if(cursor.getCount() == 0) + return list; + do { + cursor.moveToNext(); + list.add(new TagToTaskMapping(cursor).getTag()); + } while(!cursor.isLast()); + } finally { + cursor.close(); + } + + return list; + } + + /** Get a list of task identifiers for the given tag. + * This searches for TAGGED tasks only. + * Use getUntaggedTasks() to get a list of UNTAGGED tasks **/ + public LinkedList getTaggedTasks(TagIdentifier tagId) + throws SQLException { + LinkedList list = new LinkedList(); + Cursor cursor = tagToTaskMapDatabase.query(tagTaskTable, + TagToTaskMapping.FIELD_LIST, TagToTaskMapping.TAG + " = ?", + new String[] { tagId.idAsString() }, null, null, null); + + try { + if(cursor.getCount() == 0) + return list; + do { + cursor.moveToNext(); + list.add(new TagToTaskMapping(cursor).getTask()); + } while(!cursor.isLast()); + } finally { + cursor.close(); + } + + return list; + } + + /** Returns a list of task identifiers in the provided set that are UNtagged. + * + * The calling SubActivity must provide the set of tasks, since + * TagController cannot access the appropriate instance of TaskController. + * + * The current implementation is not very efficient, because queries + * the TagToTask map once for each active task. + **/ + public LinkedList getUntaggedTasks() throws SQLException { + HashSet ids = new HashSet(); + + String[] tagMapColumns = new String[] { TagToTaskMapping.TASK }; + Cursor tagMapCursor = tagToTaskMapDatabase.query(tagTaskTable, + tagMapColumns, null, null, TagToTaskMapping.TASK, null, + TagToTaskMapping.TASK + " ASC"); + + SQLiteDatabase taskDatabase = new TaskModelDatabaseHelper(context, + tasksTable, tasksTable).getReadableDatabase(); + String[] taskColumns = new String[] { KEY_ROWID }; + Cursor taskCursor = taskDatabase.query(tasksTable, taskColumns, + null, null, null, null, KEY_ROWID + " ASC"); + + LinkedList list = new LinkedList(); + try { + if(taskCursor.getCount() == 0) + return list; + + do { + taskCursor.moveToNext(); + ids.add(taskCursor.getLong(0)); + } while(!taskCursor.isLast()); + + if(tagMapCursor.getCount() > 0) { + do { + tagMapCursor.moveToNext(); + ids.remove(tagMapCursor.getLong(0)); + } while(!tagMapCursor.isLast()); + } + } finally { + taskCursor.close(); + tagMapCursor.close(); + taskDatabase.close(); + } + + for(Long id : ids) + list.add(new TaskIdentifier(id)); + return list; + } + + + // --- single tag operations + + public TagIdentifier createTag(String name) throws SQLException { + if(name == null) + throw new NullPointerException("Name can't be null"); + + TagModelForView newTag = new TagModelForView(name); + long row = tagDatabase.insertOrThrow(tagsTable, AbstractTagModel.NAME, + newTag.getMergedValues()); + return new TagIdentifier(row); + } + + /** Creates or saves the given tag */ + public boolean saveTag(AbstractTagModel tag) throws SQLException { + boolean saveSucessful; + + if(tag.getTagIdentifier() == null) { + long newRow = tagDatabase.insert(tagsTable, AbstractTagModel.NAME, + tag.getMergedValues()); + tag.setTagIdentifier(new TagIdentifier(newRow)); + + saveSucessful = newRow >= 0; + } else { + long id = tag.getTagIdentifier().getId(); + saveSucessful = tagDatabase.update(tagsTable, tag.getSetValues(), + KEY_ROWID + "=" + id, null) > 0; + } + + return saveSucessful; + } + + /** Returns a TaskModelForView corresponding to the given Tag Name */ + public TagModelForView fetchTagFromName(String name) throws SQLException { + Cursor cursor = tagDatabase.query(true, tagsTable, + TagModelForView.FIELD_LIST, + AbstractTagModel.NAME + " = ?", new String[] {name}, null, null, null, null); + + try { + if (cursor != null && cursor.getCount() > 0) { + cursor.moveToFirst(); + TagModelForView model = new TagModelForView(cursor); + return model; + } + return null; + } finally { + if(cursor != null) + cursor.close(); + } + } + + /** Returns a TaskModelForView corresponding to the given TagIdentifier */ + public TagModelForView fetchTagForView(TagIdentifier tagId) throws SQLException { + long id = tagId.getId(); + Cursor cursor = tagDatabase.query(true, tagsTable, + TagModelForView.FIELD_LIST, + KEY_ROWID + "=" + id, null, null, null, null, null); + + try { + if (cursor != null) { + cursor.moveToFirst(); + TagModelForView model = new TagModelForView(cursor); + return model; + } + + throw new SQLException("Returned empty set!"); + } finally { + if(cursor != null) + cursor.close(); + } + } + + /** Deletes the tag and removes tag/task mappings */ + public boolean deleteTag( TagIdentifier tagId) + throws SQLException{ + if(tagToTaskMapDatabase.delete(tagTaskTable, + TagToTaskMapping.TAG + " = " + tagId.idAsString(), null) < 0) + return false; + + int res = tagDatabase.delete(tagsTable, + KEY_ROWID + " = " + tagId.idAsString(), null); + + // notify modification + TasksProvider.notifyDatabaseModification(); + + return res > 0; + } + + // --- single tag to task operations + + /** Remove the given tag from the task */ + public boolean removeTag(TaskIdentifier taskId, TagIdentifier tagId) + throws SQLException{ + + int res = tagToTaskMapDatabase.delete(tagTaskTable, + String.format("%s = ? AND %s = ?", + TagToTaskMapping.TAG, TagToTaskMapping.TASK), + new String[] { tagId.idAsString(), taskId.idAsString() }); + + // notify modification + TasksProvider.notifyDatabaseModification(); + + return res > 0; + } + + /** Add the given tag to the task */ + public boolean addTag(TaskIdentifier taskId, TagIdentifier tagId) + throws SQLException { + ContentValues values = new ContentValues(); + values.put(TagToTaskMapping.TAG, tagId.getId()); + values.put(TagToTaskMapping.TASK, taskId.getId()); + + long res = tagToTaskMapDatabase.insert(tagTaskTable, TagToTaskMapping.TAG, + values); + + // notify modification + TasksProvider.notifyDatabaseModification(); + + return res >= 0; + } + + // --- boilerplate + + /** + * Constructor - takes the context to allow the database to be + * opened/created + */ + public TagController(Context context) { + super(context); + } + + /** + * Open the notes database. If it cannot be opened, try to create a new + * instance of the database. If it cannot be created, throw an exception to + * signal the failure + * + * @return this (self reference, allowing this to be chained in an + * initialization call) + * @throws SQLException if the database could be neither opened or created + */ + @Override + public synchronized void open() throws SQLException { + tagToTaskMapDatabase = new TagToTaskMappingDatabaseHelper(context, + tagTaskTable, tagTaskTable).getWritableDatabase(); + tagDatabase = new TagModelDatabaseHelper(context, + tagsTable, tagsTable).getWritableDatabase(); + } + + /** Closes database resource */ + @Override + public void close() { + if(tagDatabase != null) + tagDatabase.close(); + if(tagToTaskMapDatabase != null) + tagToTaskMapDatabase.close(); + } +} diff --git a/astrid/src-legacy/com/timsu/astrid/data/tag/TagIdentifier.java b/astrid/src-legacy/com/timsu/astrid/data/tag/TagIdentifier.java new file mode 100644 index 000000000..4308d09f5 --- /dev/null +++ b/astrid/src-legacy/com/timsu/astrid/data/tag/TagIdentifier.java @@ -0,0 +1,31 @@ +/* + * ASTRID: Android's Simple Task Recording Dashboard + * + * Copyright (c) 2009 Tim Su + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package com.timsu.astrid.data.tag; + +import com.timsu.astrid.data.Identifier; + + +public class TagIdentifier extends Identifier { + + public TagIdentifier(long id) { + super(id); + } + +} diff --git a/astrid/src-legacy/com/timsu/astrid/data/tag/TagModelForView.java b/astrid/src-legacy/com/timsu/astrid/data/tag/TagModelForView.java new file mode 100644 index 000000000..560b5560b --- /dev/null +++ b/astrid/src-legacy/com/timsu/astrid/data/tag/TagModelForView.java @@ -0,0 +1,102 @@ +/* + * ASTRID: Android's Simple Task Recording Dashboard + * + * Copyright (c) 2009 Tim Su + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package com.timsu.astrid.data.tag; + +import android.database.Cursor; + +import com.timsu.astrid.data.AbstractController; + + +/** Tag model for viewing purposes. Contains task name */ +public class TagModelForView extends AbstractTagModel { + + static String[] FIELD_LIST = new String[] { + AbstractController.KEY_ROWID, + NAME, + }; + + // negative number, should not conflict with database row #'s + public static final TagIdentifier UNTAGGED_IDENTIFIER = new TagIdentifier(Long.MIN_VALUE); + public static final String UNTAGGED_DEFAULT_NAME = "[untagged]"; + private static TagModelForView UNTAGGED_TASKS = new TagModelForView(UNTAGGED_DEFAULT_NAME); + + public static final String HIDDEN_FROM_MAIN_LIST_PREFIX = "_"; + + /** + * Returns a TagModelForView object to represent "Untagged" tasks, + * whose Identifier is defined by the static final UNTAGGED_IDENTIFIER. + * + * Pass in a string to show the "Untagged" name in the desired language. + * @param untaggedLabel + * @return + */ + public static TagModelForView getUntaggedModel(String untaggedLabel) { + UNTAGGED_TASKS = new TagModelForView(untaggedLabel); + UNTAGGED_TASKS.setTagIdentifier(UNTAGGED_IDENTIFIER); + return UNTAGGED_TASKS; + } + + /** + * Returns the default/last-used TagModelForView representing "Untagged" + * tasks. Set the localized name using getUntaggedModel(String...) + */ + public static TagModelForView getUntaggedModel() { + UNTAGGED_TASKS.setTagIdentifier(UNTAGGED_IDENTIFIER); + return UNTAGGED_TASKS; + } + + + // --- constructors + + /** Constructor for creating a new model */ + TagModelForView(String name) { + super(); + setName(name); + } + + /** Constructor for getting an existing model */ + TagModelForView(Cursor cursor) { + super(cursor); + getName(); + } + + // --- getters and setters + + @Override + public String getName() { + return super.getName(); + } + + @Override + public String toString() { + return getName(); + } + + public boolean shouldHideFromMainList() { + return getName().startsWith(HIDDEN_FROM_MAIN_LIST_PREFIX); + } + + public void toggleHideFromMainList() { + if(shouldHideFromMainList()) + setName(getName().substring(HIDDEN_FROM_MAIN_LIST_PREFIX.length())); + else + setName(HIDDEN_FROM_MAIN_LIST_PREFIX + getName()); + } +} diff --git a/astrid/src-legacy/com/timsu/astrid/data/tag/TagToTaskMapping.java b/astrid/src-legacy/com/timsu/astrid/data/tag/TagToTaskMapping.java new file mode 100644 index 000000000..1a9fee375 --- /dev/null +++ b/astrid/src-legacy/com/timsu/astrid/data/tag/TagToTaskMapping.java @@ -0,0 +1,131 @@ +/* + * ASTRID: Android's Simple Task Recording Dashboard + * + * Copyright (c) 2009 Tim Su + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package com.timsu.astrid.data.tag; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.util.Log; + +import com.timsu.astrid.data.AbstractController; +import com.timsu.astrid.data.AbstractModel; +import com.timsu.astrid.data.task.TaskIdentifier; + + +/** A single tag on a task */ +public class TagToTaskMapping extends AbstractModel { + + /** Version number of this model */ + static final int VERSION = 2; + + // field names + + public static final String TASK = "task"; + public static final String TAG = "tag"; + + /** Default values container */ + private static final ContentValues defaultValues = new ContentValues(); + + @Override + public ContentValues getDefaultValues() { + return defaultValues; + } + + static String[] FIELD_LIST = new String[] { + AbstractController.KEY_ROWID, + TASK, + TAG, + }; + + // --- database helper + + /** Database Helper manages creating new tables and updating old ones */ + static class TagToTaskMappingDatabaseHelper extends SQLiteOpenHelper { + String tableName; + Context context; + + TagToTaskMappingDatabaseHelper(Context context, String databaseName, String tableName) { + super(context, databaseName, null, VERSION); + this.tableName = tableName; + this.context = context; + } + + @Override + public synchronized void onCreate(SQLiteDatabase db) { + String sql = new StringBuilder(). + append("CREATE TABLE IF NOT EXISTS ").append(tableName).append(" ("). + append(AbstractController.KEY_ROWID).append(" integer primary key autoincrement, "). + append(TASK).append(" integer not null,"). + append(TAG).append(" integer not null,"). + append("unique (").append(TASK).append(",").append(TAG).append(")"). + append(");").toString(); + db.execSQL(sql); + } + + @Override + public synchronized void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + Log.w(getClass().getSimpleName(), "Upgrading database from version " + + oldVersion + " to " + newVersion + "."); + + switch(oldVersion) { + default: + // we don't know how to handle it... show an error + Log.e(getClass().getSimpleName(), "Unsupported migration from " + oldVersion + " to " + newVersion); + } + } + } + + + // --- constructor pass-through + + TagToTaskMapping(TaskIdentifier task, TagIdentifier tag) { + super(); + setTask(task); + setTag(tag); + } + + TagToTaskMapping(Cursor cursor) { + super(cursor); + } + + // --- getters and setters: expose them as you see fit + + public boolean isNew() { + return getCursor() == null; + } + + public TaskIdentifier getTask() { + return new TaskIdentifier(retrieveInteger(TASK)); + } + + public TagIdentifier getTag() { + return new TagIdentifier(retrieveInteger(TAG)); + } + + private void setTask(TaskIdentifier task) { + setValues.put(TASK, task.getId()); + } + + private void setTag(TagIdentifier tag) { + setValues.put(TAG, tag.getId()); + } +} diff --git a/astrid/src-legacy/com/timsu/astrid/data/task/AbstractTaskModel.java b/astrid/src-legacy/com/timsu/astrid/data/task/AbstractTaskModel.java new file mode 100644 index 000000000..05be526f7 --- /dev/null +++ b/astrid/src-legacy/com/timsu/astrid/data/task/AbstractTaskModel.java @@ -0,0 +1,628 @@ +/* + * ASTRID: Android's Simple Task Recording Dashboard + * + * Copyright (c) 2009 Tim Su + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package com.timsu.astrid.data.task; + +import java.util.Date; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.util.Log; + +import com.timsu.astrid.R; +import com.timsu.astrid.data.AbstractController; +import com.timsu.astrid.data.AbstractModel; +import com.timsu.astrid.data.enums.Importance; +import com.timsu.astrid.data.enums.RepeatInterval; + + +/** Abstract model of a task. Subclasses implement the getters and setters + * they are interested in. + * + * @author timsu + * + */ +public abstract class AbstractTaskModel extends AbstractModel { + + /** Version number of this model */ + static final int VERSION = 8; + + public static final int COMPLETE_PERCENTAGE = 100; + + // field names + + public static final String NAME = "name"; + public static final String NOTES = "notes"; + public static final String PROGRESS_PERCENTAGE = "progressPercentage"; + public static final String IMPORTANCE = "importance"; + public static final String ESTIMATED_SECONDS = "estimatedSeconds"; + public static final String ELAPSED_SECONDS = "elapsedSeconds"; + public static final String TIMER_START = "timerStart"; + public static final String DEFINITE_DUE_DATE = "definiteDueDate"; + public static final String PREFERRED_DUE_DATE = "preferredDueDate"; + public static final String HIDDEN_UNTIL = "hiddenUntil"; + public static final String POSTPONE_COUNT = "postponeCount"; + public static final String NOTIFICATIONS = "notifications"; + public static final String NOTIFICATION_FLAGS = "notificationFlags"; + public static final String LAST_NOTIFIED = "lastNotified"; + public static final String REPEAT = "repeat"; + public static final String CREATION_DATE = "creationDate"; + public static final String COMPLETION_DATE = "completionDate"; + public static final String CALENDAR_URI = "calendarUri"; + public static final String FLAGS = "flags"; + + // reserved fields --- + public static final String BLOCKING_ON = "blockingOn"; + + // notification flags + public static final int NOTIFY_BEFORE_DEADLINE = 1 << 0; + public static final int NOTIFY_AT_DEADLINE = 1 << 1; + public static final int NOTIFY_AFTER_DEADLINE = 1 << 2; + public static final int NOTIFY_NONSTOP = 1 << 3; + + // other flags + public static final int FLAG_SYNC_ON_COMPLETE = 1 << 0; + + /** Number of bits to shift repeat value by */ + public static final int REPEAT_VALUE_OFFSET = 3; + + /** Default values container */ + private static final ContentValues defaultValues = new ContentValues(); + + static { + defaultValues.put(NAME, ""); + defaultValues.put(NOTES, ""); + defaultValues.put(PROGRESS_PERCENTAGE, 0); + defaultValues.put(IMPORTANCE, Importance.DEFAULT.ordinal()); + defaultValues.put(ESTIMATED_SECONDS, 0); + defaultValues.put(ELAPSED_SECONDS, 0); + defaultValues.put(TIMER_START, 0); + defaultValues.put(DEFINITE_DUE_DATE, 0); + defaultValues.put(PREFERRED_DUE_DATE, 0); + defaultValues.put(HIDDEN_UNTIL, 0); + defaultValues.put(BLOCKING_ON, 0); + defaultValues.put(POSTPONE_COUNT, 0); + defaultValues.put(NOTIFICATIONS, 0); + defaultValues.put(NOTIFICATION_FLAGS, NOTIFY_AT_DEADLINE); + defaultValues.put(LAST_NOTIFIED, 0); + defaultValues.put(REPEAT, 0); + defaultValues.put(COMPLETION_DATE, 0); + defaultValues.put(CALENDAR_URI, (String)null); + defaultValues.put(FLAGS, 0); + } + + // --- database helper + + /** Database Helper manages creating new tables and updating old ones */ + public static class TaskModelDatabaseHelper extends SQLiteOpenHelper { + String tableName; + Context context; + + public TaskModelDatabaseHelper(Context context, String databaseName, String tableName) { + super(context, databaseName, null, VERSION); + this.tableName = tableName; + this.context = context; + } + + @Override + public synchronized void onCreate(SQLiteDatabase db) { + String sql = new StringBuilder(). + append("CREATE TABLE IF NOT EXISTS ").append(tableName).append(" ("). + append(AbstractController.KEY_ROWID).append(" integer primary key autoincrement, "). + append(NAME).append(" text not null,"). + append(NOTES).append(" text not null,"). + append(PROGRESS_PERCENTAGE).append(" integer not null,"). + append(IMPORTANCE).append(" integer not null,"). + append(ESTIMATED_SECONDS).append(" integer,"). + append(ELAPSED_SECONDS).append(" integer,"). + append(TIMER_START).append(" integer,"). + append(DEFINITE_DUE_DATE).append(" integer,"). + append(PREFERRED_DUE_DATE).append(" integer,"). + append(HIDDEN_UNTIL).append(" integer,"). + append(BLOCKING_ON).append(" integer,"). + append(POSTPONE_COUNT).append(" integer,"). + append(NOTIFICATIONS).append(" integer,"). + append(NOTIFICATION_FLAGS).append(" integer,"). + append(LAST_NOTIFIED).append(" integer,"). + append(REPEAT).append(" integer,"). + append(FLAGS).append(" integer,"). + append(CREATION_DATE).append(" integer,"). + append(COMPLETION_DATE).append(" integer,"). + append(CALENDAR_URI).append(" text"). + append(");").toString(); + db.execSQL(sql); + } + + @Override + @SuppressWarnings("fallthrough") + public synchronized void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + Log.w(getClass().getSimpleName(), "Upgrading database from version " + + oldVersion + " to " + newVersion + "."); + String sql; + + // note: we execute sql statements in their own try block to be more + // graceful if an upgrade dies halfway or something + switch(oldVersion) { + case 1: + sql = new StringBuilder().append("ALTER TABLE "). + append(tableName).append(" ADD COLUMN "). + append(LAST_NOTIFIED).append(" integer").toString(); + try { + db.execSQL(sql); + } catch (Exception e) { + Log.e("astrid", "Error updating table!", e); + } + sql = new StringBuilder().append("ALTER TABLE "). + append(tableName).append(" ADD COLUMN "). + append(NOTIFICATION_FLAGS).append(" integer").toString(); + try { + db.execSQL(sql); + } catch (Exception e) { + Log.e("astrid", "Error updating table!", e); + } + + case 2: + sql = new StringBuilder().append("ALTER TABLE "). + append(tableName).append(" ADD COLUMN "). + append(REPEAT).append(" integer").toString(); + try { + db.execSQL(sql); + } catch (Exception e) { + Log.e("astrid", "Error updating table!", e); + } + + case 3: + sql = new StringBuilder().append("ALTER TABLE "). + append(tableName).append(" ADD COLUMN "). + append(CALENDAR_URI).append(" text").toString(); + try { + db.execSQL(sql); + } catch (Exception e) { + Log.e("astrid", "Error updating table!", e); + } + + case 4: + sql = new StringBuilder().append("ALTER TABLE "). + append(tableName).append(" ADD COLUMN "). + append(POSTPONE_COUNT).append(" integer").toString(); + try { + db.execSQL(sql); + } catch (Exception e) { + Log.e("astrid", "Error updating table!", e); + } + + case 5: + case 6: + // apparently some people didn't get the flags column + // from version 5 to version 6, so we try again + + sql = new StringBuilder().append("ALTER TABLE "). + append(tableName).append(" ADD COLUMN "). + append(FLAGS).append(" integer").toString(); + try { + db.execSQL(sql); + } catch (Exception e) { + Log.e("astrid", "Error updating table!", e); + } + + case 7: + // not a real change, but make sure that columns that are null + // are converted into zeros, which was my previous assumption + + for(String column : new String[] { + ESTIMATED_SECONDS, + ELAPSED_SECONDS, + TIMER_START, + DEFINITE_DUE_DATE, + PREFERRED_DUE_DATE, + HIDDEN_UNTIL, + POSTPONE_COUNT, + LAST_NOTIFIED, + REPEAT, + CREATION_DATE, + COMPLETION_DATE }) { + sql = String.format("UPDATE %s SET %s = 0 WHERE %s ISNULL", + tableName, column, column); + try { + db.execSQL(sql); + } catch (Exception e) { + Log.e("astrid", "Error updating table!", e); + } + } + + // --- break point + + break; + + default: + // we don't know how to handle it... show an error + Log.e(getClass().getSimpleName(), "Unsupported migration from " + oldVersion + " to " + newVersion); + } + } + } + + // --- utility methods + + /** Gets task color. Requires definiteDueDate and importance */ + protected int getTaskColorResource(Context context) { + if(getDefiniteDueDate() != null && getDefiniteDueDate().getTime() < + System.currentTimeMillis()) { + return R.color.task_list_overdue; + } else { + return R.color.task_list_normal; + } + } + + /** Checks whether task is done. Requires progressPercentage */ + protected boolean isTaskCompleted() { + return getProgressPercentage() >= COMPLETE_PERCENTAGE; + } + + /** Stops the timer & increments elapsed time. Requires timerStart and + * elapsedSeconds */ + protected void stopTimerAndUpdateElapsedTime() { + if(getTimerStart() == null) + return; + + long start = getTimerStart().getTime(); + setTimerStart(null); + long secondsElapsed = (System.currentTimeMillis() - start)/1000; + setElapsedSeconds((int) (getElapsedSeconds() + secondsElapsed)); + } + + protected void prefetchData(String[] fields) { + for(String field : fields) { + if(field.equals(NAME)) + getName(); + else if(field.equals(NOTES)) + getNotes(); + else if(field.equals(PROGRESS_PERCENTAGE)) + getProgressPercentage(); + else if(field.equals(IMPORTANCE)) + getImportance(); + else if(field.equals(ESTIMATED_SECONDS)) + getEstimatedSeconds(); + else if(field.equals(ELAPSED_SECONDS)) + getElapsedSeconds(); + else if(field.equals(TIMER_START)) + getTimerStart(); + else if(field.equals(DEFINITE_DUE_DATE)) + getDefiniteDueDate(); + else if(field.equals(PREFERRED_DUE_DATE)) + getPreferredDueDate(); + else if(field.equals(HIDDEN_UNTIL)) + getHiddenUntil(); + else if(field.equals(BLOCKING_ON)) + getBlockingOn(); + else if(field.equals(POSTPONE_COUNT)) + getPostponeCount(); + else if(field.equals(NOTIFICATIONS)) + getNotificationIntervalSeconds(); + else if(field.equals(CREATION_DATE)) + getCreationDate(); + else if(field.equals(COMPLETION_DATE)) + getCompletionDate(); + else if(field.equals(NOTIFICATION_FLAGS)) + getNotificationFlags(); + else if(field.equals(LAST_NOTIFIED)) + getLastNotificationDate(); + else if(field.equals(REPEAT)) + getRepeat(); + else if(field.equals(FLAGS)) + getFlags(); + } + } + + // --- helper classes + + public static class RepeatInfo { + private final RepeatInterval interval; + private final int value; + + public RepeatInfo(RepeatInterval repeatInterval, int value) { + this.interval = repeatInterval; + this.value = value; + } + + public Date shiftDate(Date input) { + Date newDate = (Date)input.clone(); + interval.offsetDateBy(newDate, value); + return newDate; + } + + public RepeatInterval getInterval() { + return interval; + } + + public int getValue() { + return value; + } + + public static int toSingleField(RepeatInfo repeatInfo) { + int repeat; + if(repeatInfo == null) + repeat = 0; + else + repeat = (repeatInfo.value << REPEAT_VALUE_OFFSET) + + repeatInfo.interval.ordinal(); + return repeat; + } + + public static RepeatInfo fromSingleField(int repeat) { + if(repeat == 0) + return null; + int value = repeat >> REPEAT_VALUE_OFFSET; + RepeatInterval interval = RepeatInterval.values() + [repeat - (value << REPEAT_VALUE_OFFSET)]; + + return new RepeatInfo(interval, value); + } + + } + + // --- task identifier + + private TaskIdentifier identifier = null; + + public TaskIdentifier getTaskIdentifier() { + return identifier; + } + + void setTaskIdentifier(TaskIdentifier identifier) { + this.identifier = identifier; + } + + // --- constructors and abstract methods + + AbstractTaskModel() { + super(); + } + + /** Read identifier from database */ + AbstractTaskModel(Cursor cursor) { + super(cursor); + + Integer id = retrieveInteger(AbstractController.KEY_ROWID); + setTaskIdentifier(new TaskIdentifier(id)); + } + + /** Get identifier from argument */ + AbstractTaskModel(TaskIdentifier identifier, Cursor cursor) { + super(cursor); + + setTaskIdentifier(identifier); + } + + @Override + public ContentValues getDefaultValues() { + return defaultValues; + } + + // --- getters and setters: expose them as you see fit + + protected String getName() { + return retrieveString(NAME); + } + + protected String getNotes() { + return retrieveString(NOTES); + } + + protected int getProgressPercentage() { + return retrieveInteger(PROGRESS_PERCENTAGE); + } + + protected Importance getImportance() { + Integer value = retrieveInteger(IMPORTANCE); + if(value == null) + return null; + return Importance.values()[value]; + } + + protected Integer getEstimatedSeconds() { + return retrieveInteger(ESTIMATED_SECONDS); + } + + protected Integer getElapsedSeconds() { + return retrieveInteger(ELAPSED_SECONDS); + } + + protected Date getTimerStart() { + return retrieveDate(TIMER_START); + } + + protected Date getDefiniteDueDate() { + return retrieveDate(DEFINITE_DUE_DATE); + } + + protected Date getPreferredDueDate() { + return retrieveDate(PREFERRED_DUE_DATE); + } + + protected Date getHiddenUntil() { + return retrieveDate(HIDDEN_UNTIL); + } + + protected boolean isHidden() { + if(getHiddenUntil() == null) + return false; + return getHiddenUntil().getTime() > System.currentTimeMillis(); + } + + protected Date getCreationDate() { + return retrieveDate(CREATION_DATE); + } + + protected Date getCompletionDate() { + return retrieveDate(COMPLETION_DATE); + } + + protected TaskIdentifier getBlockingOn() { + Long value = retrieveLong(BLOCKING_ON); + if(value == null) + return null; + return new TaskIdentifier(value); + } + + protected Integer getPostponeCount() { + return retrieveInteger(POSTPONE_COUNT); + } + + protected Integer getNotificationIntervalSeconds() { + return retrieveInteger(NOTIFICATIONS); + } + + protected int getNotificationFlags() { + return retrieveInteger(NOTIFICATION_FLAGS); + } + + protected Date getLastNotificationDate() { + return retrieveDate(LAST_NOTIFIED); + } + + protected RepeatInfo getRepeat() { + int repeat = retrieveInteger(REPEAT); + if(repeat == 0) + return null; + int value = repeat >> REPEAT_VALUE_OFFSET; + RepeatInterval interval = RepeatInterval.values() + [repeat - (value << REPEAT_VALUE_OFFSET)]; + + return new RepeatInfo(interval, value); + } + + protected String getCalendarUri() { + String uri = retrieveString(CALENDAR_URI); + if(uri != null && uri.length() == 0) + return null; + else + return uri; + } + + protected int getFlags() { + return retrieveInteger(FLAGS); + } + + // --- setters + + protected void setName(String name) { + putIfChangedFromDatabase(NAME, name); + } + + protected void setNotes(String notes) { + putIfChangedFromDatabase(NOTES, notes); + } + + protected void setProgressPercentage(int progressPercentage) { + putIfChangedFromDatabase(PROGRESS_PERCENTAGE, progressPercentage); + + if(getProgressPercentage() != progressPercentage && + progressPercentage == COMPLETE_PERCENTAGE) + setCompletionDate(new Date()); + } + + protected void setImportance(Importance importance) { + putIfChangedFromDatabase(IMPORTANCE, importance.ordinal()); + } + + protected void setEstimatedSeconds(Integer estimatedSeconds) { + putIfChangedFromDatabase(ESTIMATED_SECONDS, estimatedSeconds); + } + + protected void setElapsedSeconds(int elapsedSeconds) { + putIfChangedFromDatabase(ELAPSED_SECONDS, elapsedSeconds); + } + + protected void setTimerStart(Date timerStart) { + putDate(TIMER_START, timerStart); + } + + protected void setDefiniteDueDate(Date definiteDueDate) { + putDate(DEFINITE_DUE_DATE, definiteDueDate); + } + + protected void setPreferredDueDate(Date preferredDueDate) { + putDate(PREFERRED_DUE_DATE, preferredDueDate); + } + + protected void setHiddenUntil(Date hiddenUntil) { + putDate(HIDDEN_UNTIL, hiddenUntil); + } + + protected void setBlockingOn(TaskIdentifier blockingOn) { + if(blockingOn == null || blockingOn.equals(getTaskIdentifier())) + putIfChangedFromDatabase(BLOCKING_ON, (Integer)null); + else + putIfChangedFromDatabase(BLOCKING_ON, blockingOn.getId()); + } + + protected void setPostponeCount(int postponeCount) { + putIfChangedFromDatabase(POSTPONE_COUNT, postponeCount); + } + + protected void setCreationDate(Date creationDate) { + putDate(CREATION_DATE, creationDate); + } + + protected void setCompletionDate(Date completionDate) { + putDate(COMPLETION_DATE, completionDate); + } + + protected void setNotificationIntervalSeconds(Integer intervalInSeconds) { + putIfChangedFromDatabase(NOTIFICATIONS, intervalInSeconds); + } + + protected void setNotificationFlags(int flags) { + putIfChangedFromDatabase(NOTIFICATION_FLAGS, flags); + } + + protected void setLastNotificationTime(Date date) { + putDate(LAST_NOTIFIED, date); + } + + protected void setRepeat(RepeatInfo repeatInfo) { + int repeat; + if(repeatInfo == null) + repeat = 0; + else + repeat = (repeatInfo.value << REPEAT_VALUE_OFFSET) + + repeatInfo.interval.ordinal(); + putIfChangedFromDatabase(REPEAT, repeat); + } + + protected void setCalendarUri(String uri) { + putIfChangedFromDatabase(CALENDAR_URI, uri); + } + + protected void setFlags(int flags) { + putIfChangedFromDatabase(FLAGS, flags); + } + + // --- utility methods + + protected void putDate(String fieldName, Date date) { + if(date == null) + putIfChangedFromDatabase(fieldName, 0); + else + putIfChangedFromDatabase(fieldName, date.getTime()); + } +} diff --git a/astrid/src-legacy/com/timsu/astrid/data/task/TaskController.java b/astrid/src-legacy/com/timsu/astrid/data/task/TaskController.java new file mode 100644 index 000000000..62e290677 --- /dev/null +++ b/astrid/src-legacy/com/timsu/astrid/data/task/TaskController.java @@ -0,0 +1,656 @@ +/* + * ASTRID: Android's Simple Task Recording Dashboard + * + * Copyright (c) 2009 Tim Su + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package com.timsu.astrid.data.task; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashSet; +import java.util.List; + +import android.app.Activity; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.database.SQLException; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.net.Uri; +import android.util.Log; + +import com.timsu.astrid.data.AbstractController; +import com.timsu.astrid.data.alerts.AlertController; +import com.timsu.astrid.data.sync.SyncDataController; +import com.timsu.astrid.data.task.AbstractTaskModel.RepeatInfo; +import com.timsu.astrid.data.task.AbstractTaskModel.TaskModelDatabaseHelper; +import com.timsu.astrid.provider.TasksProvider; +import com.todoroo.astrid.widget.TasksWidget.UpdateService; + +/** + * Controller for task-related operations + * + * @author timsu + * + */ +public class TaskController extends AbstractController { + + private SQLiteDatabase database; + + // --- task list operations + + /** Return a list of all active tasks with notifications */ + public HashSet getTasksWithNotifications() { + HashSet list = new HashSet(); + Cursor cursor = database.query(tasksTable, TaskModelForNotify.FIELD_LIST, + String.format("%s < %d AND (%s != 0 OR %s != 0)", + AbstractTaskModel.PROGRESS_PERCENTAGE, + AbstractTaskModel.COMPLETE_PERCENTAGE, + AbstractTaskModel.NOTIFICATIONS, + AbstractTaskModel.NOTIFICATION_FLAGS), null, null, null, null, null); + + try { + if(cursor.getCount() == 0) + return list; + do { + cursor.moveToNext(); + list.add(new TaskModelForNotify(cursor)); + } while(!cursor.isLast()); + + return list; + } finally { + cursor.close(); + } + } + + /** Return a list of all active tasks with deadlines */ + public ArrayList getTasksWithDeadlines() { + ArrayList list = new ArrayList(); + Cursor cursor = database.query(tasksTable, TaskModelForNotify.FIELD_LIST, + String.format("%s < %d AND (%s != 0 OR %s != 0)", + AbstractTaskModel.PROGRESS_PERCENTAGE, + AbstractTaskModel.COMPLETE_PERCENTAGE, + AbstractTaskModel.DEFINITE_DUE_DATE, + AbstractTaskModel.PREFERRED_DUE_DATE), null, null, null, null, null); + + try { + if(cursor.getCount() == 0) + return list; + + do { + cursor.moveToNext(); + list.add(new TaskModelForNotify(cursor)); + } while(!cursor.isLast()); + + return list; + } finally { + cursor.close(); + } + } + + /** Return a list of all of the tasks with progress < COMPLETE_PERCENTAGE */ + public Cursor getActiveTaskListCursor() { + return database.query(tasksTable, TaskModelForList.FIELD_LIST, + AbstractTaskModel.PROGRESS_PERCENTAGE + " < " + + AbstractTaskModel.COMPLETE_PERCENTAGE, null, null, null, + null, null); + } + + /** Return a list of all of the tasks matching selection */ + public Cursor getMatchingTasksForProvider(String selection, + String[] selectionArgs) { + return database.query(tasksTable, TaskModelForProvider.FIELD_LIST, + selection, selectionArgs, null, null, + null, null); + } + + /** Return a list of all tasks */ + public Cursor getAllTaskListCursor() { + return database.query(tasksTable, TaskModelForList.FIELD_LIST, + null, null, null, null, null, null); + } + + /** Return a list of all tasks */ + public Cursor getBackupTaskListCursor() { + return database.query(tasksTable, TaskModelForXml.FIELD_LIST, + AbstractTaskModel.PROGRESS_PERCENTAGE + " < " + + AbstractTaskModel.COMPLETE_PERCENTAGE, null, null, null, + null, null); + } + + /** Delete all completed tasks with date < older than date */ + public int deleteCompletedTasksOlderThan(Date olderThanDate) { + return database.delete(tasksTable, String.format("`%s` >= '%d' AND `%s` <= '%d'", + AbstractTaskModel.PROGRESS_PERCENTAGE, AbstractTaskModel.COMPLETE_PERCENTAGE, + AbstractTaskModel.COMPLETION_DATE, olderThanDate.getTime()), null); + } + + /** Create a list of tasks from the db cursor given */ + public ArrayList createTaskListFromCursor(Cursor cursor) { + ArrayList list = new ArrayList(); + + if(cursor.getCount() == 0) + return list; + + do { + cursor.moveToNext(); + list.add(new TaskModelForList(cursor)); + } while(!cursor.isLast()); + + return list; + } + + /** Helper method to take a cursor pointing to a list of id's and generate + * a hashset */ + private HashSet createTaskIdentifierSet(Cursor cursor) { + HashSet list = new HashSet(); + try { + if(cursor.getCount() == 0) + return list; + + do { + cursor.moveToNext(); + list.add(new TaskIdentifier(cursor.getInt( + cursor.getColumnIndexOrThrow(KEY_ROWID)))); + } while(!cursor.isLast()); + + return list; + } finally { + cursor.close(); + } + } + + /** Get identifiers for all tasks */ + public HashSet getAllTaskIdentifiers() { + Cursor cursor = database.query(tasksTable, new String[] { KEY_ROWID }, + null, null, null, null, null, null); + return createTaskIdentifierSet(cursor); + } + + /** Get identifiers for all non-completed tasks */ + public HashSet getActiveTaskIdentifiers() { + Cursor cursor = database.query(tasksTable, new String[] { KEY_ROWID }, + AbstractTaskModel.PROGRESS_PERCENTAGE + " < " + + AbstractTaskModel.COMPLETE_PERCENTAGE, null, null, null, null, null); + return createTaskIdentifierSet(cursor); + } + + /** Get identifiers for all non-completed, non-hidden tasks */ + public HashSet getActiveVisibleTaskIdentifiers() { + Cursor cursor = database.query(tasksTable, new String[] { KEY_ROWID }, + AbstractTaskModel.PROGRESS_PERCENTAGE + " < " + + AbstractTaskModel.COMPLETE_PERCENTAGE + " AND (" + + AbstractTaskModel.HIDDEN_UNTIL + " ISNULL OR " + AbstractTaskModel.HIDDEN_UNTIL + " < " + + System.currentTimeMillis() + ")", null, null, null, null, null); + return createTaskIdentifierSet(cursor); + } + + + /** Create a weighted list of tasks from the db cursor given */ + public Cursor getTaskListCursorById(List idList) { + + StringBuilder where = new StringBuilder(); + for(int i = 0; i < idList.size(); i++) { + where.append(KEY_ROWID); + where.append("="); + where.append(idList.get(i).idAsString()); + if(i < idList.size()-1) + where.append(" OR "); + } + + // hack for empty arrays + if(idList.size() == 0) + where.append("0"); + + return database.query(true, tasksTable, + TaskModelForList.FIELD_LIST, where.toString(), null, null, + null, null, null); + } + + // --- single task operations + + /** Delete the given task */ + public boolean deleteTask(TaskIdentifier taskId) { + if(taskId == null) + throw new UnsupportedOperationException("Cannot delete uncreated task!"); + long id = taskId.getId(); + cleanupTask(taskId, false); + + // notify modification + TasksProvider.notifyDatabaseModification(); + + return database.delete(tasksTable, KEY_ROWID + "=" + id, null) > 0; + } + + /** Saves the given task to the database. Returns true on success. + * + * @param duringSync set to true when save is part of a synchronize + */ + public boolean saveTask(AbstractTaskModel task, boolean duringSync) { + boolean saveSucessful; + + if(task.getTaskIdentifier() == null) { + long newRow = database.insert(tasksTable, AbstractTaskModel.NAME, + task.getMergedValues()); + task.setTaskIdentifier(new TaskIdentifier(newRow)); + + saveSucessful = newRow >= 0; + } else { + long id = task.getTaskIdentifier().getId(); + ContentValues values = task.getSetValues(); + + if(values.size() == 0) // nothing changed + return true; + + onTaskSave(task, values, duringSync); + + saveSucessful = database.update(tasksTable, values, + KEY_ROWID + "=" + id, null) > 0; + + // task was completed + if(values.containsKey(AbstractTaskModel.PROGRESS_PERCENTAGE) && + values.getAsInteger(AbstractTaskModel.PROGRESS_PERCENTAGE) + == AbstractTaskModel.COMPLETE_PERCENTAGE) { + onTaskCompleted(task, values, duringSync); + } + + SyncDataController.taskUpdated(context, task); + } + + // notify widget that something changed + if(saveSucessful) { + Intent intent = new Intent(context, UpdateService.class); + context.startService(intent); + } + + // notify modification + TasksProvider.notifyDatabaseModification(); + + return saveSucessful; + } + + /** + * Called when the task is saved. Perform some processing on the task. + * + * @param task + * @param values + */ + private void onTaskSave(AbstractTaskModel task, ContentValues values, boolean duringSync) { + // save task completed date + if(values.containsKey(AbstractTaskModel.PROGRESS_PERCENTAGE) && + values.getAsInteger(AbstractTaskModel.PROGRESS_PERCENTAGE) + == AbstractTaskModel.COMPLETE_PERCENTAGE) { + values.put(AbstractTaskModel.COMPLETION_DATE, System.currentTimeMillis()); + } + + // task timer was updated, update notification bar + if(values.containsKey(AbstractTaskModel.TIMER_START)) { + // show notification bar if timer was started +// if(values.getAsLong(AbstractTaskModel.TIMER_START) != 0) { +// ReminderService.showTimingNotification(context, +// task.getTaskIdentifier(), task.getName()); +// } else { +// ReminderService.clearAllNotifications(context, task.getTaskIdentifier()); +// } + } + + // due date was updated, update calendar event + if((values.containsKey(AbstractTaskModel.DEFINITE_DUE_DATE) || + values.containsKey(AbstractTaskModel.PREFERRED_DUE_DATE)) && + !values.containsKey(AbstractTaskModel.CALENDAR_URI)) { + try { + Cursor cursor = fetchTaskCursor(task.getTaskIdentifier(), + new String[] { AbstractTaskModel.CALENDAR_URI }); + cursor.moveToFirst(); + String uriAsString = cursor.getString(0); + cursor.close(); + if(uriAsString != null && uriAsString.length() > 0) { + ContentResolver cr = context.getContentResolver(); + Uri uri = Uri.parse(uriAsString); + + Integer estimated = null; + if(values.containsKey(AbstractTaskModel.ESTIMATED_SECONDS)) + estimated = values.getAsInteger(AbstractTaskModel.ESTIMATED_SECONDS); + else { // read from event + Cursor event = cr.query(uri, new String[] {"dtstart", "dtend"}, + null, null, null); + event.moveToFirst(); + estimated = (event.getInt(1) - event.getInt(0))/1000; + } + + // create new start and end date for this event + ContentValues newValues = new ContentValues(); + /*TaskEditActivity.createCalendarStartEndTimes(task.getPreferredDueDate(), + task.getDefiniteDueDate(), estimated, newValues); TODO */ + cr.update(uri, newValues, null, null); + } + } catch (Exception e) { + // ignore calendar event - event could be deleted or whatever + Log.e("astrid", "Error moving calendar event", e); + } + } + } + + + /** + * Called when this task is set to completed. + * + * @param task task to process + * @param values mutable map of values to save + */ + private void onTaskCompleted(AbstractTaskModel task, ContentValues values, boolean duringSync) { + Cursor cursor = fetchTaskCursor(task.getTaskIdentifier(), + TaskModelForHandlers.FIELD_LIST); + TaskModelForHandlers model = new TaskModelForHandlers(cursor, values); + + // handle repeat + RepeatInfo repeatInfo = model.getRepeat(); + if(repeatInfo != null) { + model.repeatTaskBy(context, this, repeatInfo); + database.update(tasksTable, values, KEY_ROWID + "=" + + task.getTaskIdentifier().getId(), null); + } + + // handle sync-on-complete + if((model.getFlags() & TaskModelForHandlers.FLAG_SYNC_ON_COMPLETE) > 0 && + !duringSync) { +// Synchronizer synchronizer = new Synchronizer(model.getTaskIdentifier()); +// synchronizer.synchronize(context, new SynchronizerListener() { +// public void onSynchronizerFinished(int numServicesSynced) { +//// TaskListSubActivity.shouldRefreshTaskList = true; +// } +// }); + } + + cursor.close(); + cleanupTask(task.getTaskIdentifier(), repeatInfo != null); + } + + /** Clean up state from a task. Called when deleting or completing it */ + private void cleanupTask(TaskIdentifier taskId, boolean isRepeating) { + // delete notifications & alarms +// ReminderService.deleteAlarm(context, null, taskId.getId()); + + // delete calendar event if not repeating + if(!isRepeating) { + try { + Cursor cursor = fetchTaskCursor(taskId, new String[] { + AbstractTaskModel.CALENDAR_URI }); + cursor.moveToFirst(); + String uri = cursor.getString(0); + cursor.close(); + if(uri != null && uri.length() > 0) { + ContentResolver cr = context.getContentResolver(); + cr.delete(Uri.parse(uri), null, null); + ContentValues values = new ContentValues(); + values.put(AbstractTaskModel.CALENDAR_URI, (String)null); + database.update(tasksTable, values, KEY_ROWID + "=" + + taskId.getId(), null); + } + } catch (Exception e) { + Log.e("astrid", "Error deleting calendar event", e); + } + } + } + + /** Set last notification date */ + public boolean setLastNotificationTime(TaskIdentifier taskId, Date date) { + ContentValues values = new ContentValues(); + values.put(AbstractTaskModel.LAST_NOTIFIED, date.getTime()); + return database.update(tasksTable, values, + KEY_ROWID + "=" + taskId.getId(), null) > 0; + } + + // --- fetching different models + + /** Creates a new task and returns the task identifier */ + public TaskModelForEdit createNewTaskForEdit() { + TaskModelForEdit task = new TaskModelForEdit(); + task.setTaskIdentifier(null); + + return task; + } + + /** Returns a TaskModelForEdit corresponding to the given TaskIdentifier */ + public TaskModelForEdit fetchTaskForEdit(Activity activity, TaskIdentifier + taskId) throws SQLException { + Cursor cursor = fetchTaskCursor(taskId, TaskModelForEdit.FIELD_LIST); + if(cursor == null) + return null; + activity.startManagingCursor(cursor); + TaskModelForEdit model = new TaskModelForEdit(taskId, cursor); + return model; + } + + /** Returns a TaskModelForList corresponding to the given TaskIdentifier */ + public TaskModelForList fetchTaskForList(TaskIdentifier taskId) throws SQLException { + Cursor cursor = fetchTaskCursor(taskId, TaskModelForList.FIELD_LIST); + if(cursor == null) + return null; + TaskModelForList model = new TaskModelForList(cursor); + cursor.close(); + return model; + } + + /** Returns a TaskModelForXml corresponding to the given TaskIdentifier */ + public TaskModelForXml fetchTaskForXml(TaskIdentifier taskId) throws SQLException { + Cursor cursor = fetchTaskCursor(taskId, TaskModelForXml.FIELD_LIST); + if(cursor == null) + return null; + TaskModelForXml model = new TaskModelForXml(cursor); + cursor.close(); + return model; + } + + /* Attempts to return a TaskModelForXml for the given name and creation date */ + public TaskModelForXml fetchTaskForXml(String name, Date creationDate) { + Cursor cursor; + try { + cursor = fetchTaskCursor(name, creationDate.getTime(), + TaskModelForXml.FIELD_LIST); + } catch (SQLException e) { + return null; + } + if (cursor == null || cursor.getCount() == 0) { + return null; + } + TaskModelForXml model = new TaskModelForXml(cursor); + cursor.close(); + return model; + } + + /** Returns a TaskModelForReminder corresponding to the given TaskIdentifier */ + public TaskModelForReminder fetchTaskForReminder(TaskIdentifier taskId) throws SQLException { + Cursor cursor = fetchTaskCursor(taskId, TaskModelForReminder.FIELD_LIST); + TaskModelForReminder model = new TaskModelForReminder(cursor); + cursor.close(); + return model; + } + + /** Returns a TaskModelForSync corresponding to the given TaskIdentifier */ + public TaskModelForSync fetchTaskForSync(TaskIdentifier taskId) throws SQLException { + Cursor cursor = fetchTaskCursor(taskId, TaskModelForSync.FIELD_LIST); + TaskModelForSync model = new TaskModelForSync(cursor); + cursor.close(); + return model; + } + + /** Returns a TaskModelForView by name */ + public TaskModelForSync searchForTaskForSync(String name) throws SQLException { + Cursor cursor = database.query(true, tasksTable, TaskModelForSync.FIELD_LIST, + AbstractTaskModel.NAME + " = ? AND " + + AbstractTaskModel.PROGRESS_PERCENTAGE + " < "+ + AbstractTaskModel.COMPLETE_PERCENTAGE, + new String[] { name }, null, null, null, null); + try { + if (cursor == null || cursor.getCount() == 0) + return null; + cursor.moveToFirst(); + TaskModelForSync model = new TaskModelForSync(cursor); + return model; + } finally { + if(cursor != null) + cursor.close(); + } + } + + /** Returns a TaskModelForView corresponding to the given TaskIdentifier */ + public TaskModelForNotify fetchTaskForNotify(TaskIdentifier taskId) throws SQLException { + Cursor cursor = fetchTaskCursor(taskId, TaskModelForNotify.FIELD_LIST); + TaskModelForNotify model = new TaskModelForNotify(cursor); + cursor.close(); + return model; + } + + /** Moves cursor to the task. + * Don't forget to close the cursor when you're done. */ + private Cursor fetchTaskCursor(TaskIdentifier taskId, String[] fieldList) { + long id = taskId.getId(); + Cursor cursor = database.query(true, tasksTable, fieldList, + KEY_ROWID + "=" + id, null, null, null, null, null); + if (cursor == null) + throw new SQLException("Returned empty set!"); + + cursor.moveToFirst(); + return cursor; + } + + /** Returns null if unsuccessful, otherwise moves cursor to the task. + * Don't forget to close the cursor when you're done. */ + private Cursor fetchTaskCursor(String name, long creationDate, String[] fieldList) { + // truncate millis + final String where = AbstractTaskModel.NAME + " = ? AND " + + AbstractTaskModel.CREATION_DATE + " LIKE ?"; + + String approximateCreationDate = (creationDate / 1000) + "%"; + Cursor cursor = database.query(true, tasksTable, fieldList, + where, new String[] {name, approximateCreationDate}, null, null, null, null); + if (cursor == null) + throw new SQLException("Returned empty set!"); + + if (cursor.moveToFirst()) { + return cursor; + } + cursor.close(); + return null; + } + // --- methods supporting individual features + + /** Returns a TaskModelForView corresponding to the given TaskIdentifier */ + public int fetchTaskPostponeCount(TaskIdentifier taskId) throws SQLException { + Cursor cursor = fetchTaskCursor(taskId, new String[] {AbstractTaskModel.POSTPONE_COUNT}); + try { + if (cursor == null || cursor.getCount() == 0) + return 0; + cursor.moveToFirst(); + return cursor.getInt(0); + } catch (Exception e) { + return 0; + } finally { + if(cursor != null) + cursor.close(); + } + } + + /** Updates the alarm for the task identified by the given id */ + public void updateAlarmForTask(TaskIdentifier taskId) throws SQLException { + TaskModelForNotify task = fetchTaskForNotify(taskId); + AlertController alertController = new AlertController(context); + alertController.open(); +// ReminderService.updateAlarm(context, this, alertController, task); + alertController.close(); + } + + public ArrayList getTasksForWidget(String limit) { + + Cursor cursor = database.query(tasksTable, TaskModelForWidget.FIELD_LIST, + AbstractTaskModel.PROGRESS_PERCENTAGE + " < " + + AbstractTaskModel.COMPLETE_PERCENTAGE + " AND (" + + AbstractTaskModel.HIDDEN_UNTIL + " ISNULL OR " + AbstractTaskModel.HIDDEN_UNTIL + " < " + + System.currentTimeMillis() + ")", null, null, null, + AbstractTaskModel.IMPORTANCE + " * " + (5 * 24 * 3600 * 1000L) + + " + CASE WHEN MAX(pdd, ddd) = 0 THEN " + + (System.currentTimeMillis() + (7 * 24 * 3600 * 1000L)) + + " ELSE (CASE WHEN pdd = 0 THEN ddd ELSE pdd END) END ASC", limit); + + try { + ArrayList list = new ArrayList(); + for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) + list.add(new TaskModelForWidget(cursor)); + return list; + } finally { + cursor.close(); + } + } + + public ArrayList getTasksForProvider(String limit) { + + Cursor cursor = database.query(tasksTable, TaskModelForProvider.FIELD_LIST, + AbstractTaskModel.PROGRESS_PERCENTAGE + " < " + + AbstractTaskModel.COMPLETE_PERCENTAGE + " AND (" + + AbstractTaskModel.HIDDEN_UNTIL + " ISNULL OR " + AbstractTaskModel.HIDDEN_UNTIL + " < " + + System.currentTimeMillis() + ")", null, null, null, + AbstractTaskModel.IMPORTANCE + " * " + (5 * 24 * 3600 * 1000L) + + " + CASE WHEN MAX(pdd, ddd) = 0 THEN " + + (System.currentTimeMillis() + (7 * 24 * 3600 * 1000L)) + + " ELSE (CASE WHEN pdd = 0 THEN ddd ELSE pdd END) END ASC", limit); + + try { + ArrayList list = new ArrayList(); + for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) + list.add(new TaskModelForProvider(cursor)); + return list; + } finally { + cursor.close(); + } + } + + // --- boilerplate + + /** + * Constructor - takes the context to allow the database to be + * opened/created + */ + public TaskController(Context context) { + super(context); + } + + /** + * Open the notes database. If it cannot be opened, try to create a new + * instance of the database. If it cannot be created, throw an exception to + * signal the failure + * + * @return this (self reference, allowing this to be chained in an + * initialization call) + * @throws SQLException if the database could be neither opened or created + */ + @Override + public synchronized void open() throws SQLException { + SQLiteOpenHelper databaseHelper = new TaskModelDatabaseHelper( + context, tasksTable, tasksTable); + database = databaseHelper.getWritableDatabase(); + } + + /** Closes database resource */ + @Override + public void close() { + database.close(); + } +} diff --git a/astrid/src-legacy/com/timsu/astrid/data/task/TaskIdentifier.java b/astrid/src-legacy/com/timsu/astrid/data/task/TaskIdentifier.java new file mode 100644 index 000000000..3bdb06195 --- /dev/null +++ b/astrid/src-legacy/com/timsu/astrid/data/task/TaskIdentifier.java @@ -0,0 +1,30 @@ +/* + * ASTRID: Android's Simple Task Recording Dashboard + * + * Copyright (c) 2009 Tim Su + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package com.timsu.astrid.data.task; + +import com.timsu.astrid.data.Identifier; + + +public class TaskIdentifier extends Identifier { + + public TaskIdentifier(long id) { + super(id); + } +} diff --git a/astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForEdit.java b/astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForEdit.java new file mode 100644 index 000000000..914c70e97 --- /dev/null +++ b/astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForEdit.java @@ -0,0 +1,208 @@ +/* + * ASTRID: Android's Simple Task Recording Dashboard + * + * Copyright (c) 2009 Tim Su + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package com.timsu.astrid.data.task; + +import java.util.Date; + +import android.database.Cursor; + +import com.timsu.astrid.data.enums.Importance; + + + +/** Fields that you would want to edit in the TaskModel */ +public class TaskModelForEdit extends AbstractTaskModel { + + static String[] FIELD_LIST = new String[] { + NAME, + IMPORTANCE, + ESTIMATED_SECONDS, + ELAPSED_SECONDS, + DEFINITE_DUE_DATE, + PREFERRED_DUE_DATE, + HIDDEN_UNTIL, + BLOCKING_ON, + NOTIFICATIONS, + NOTIFICATION_FLAGS, + LAST_NOTIFIED, + PROGRESS_PERCENTAGE, + NOTES, + REPEAT, + CALENDAR_URI, + }; + + // --- constructors + + public TaskModelForEdit() { + super(); + setCreationDate(new Date()); + } + + public TaskModelForEdit(TaskIdentifier identifier, Cursor cursor) { + super(identifier, cursor); + } + + // --- getters and setters + + @Override + public boolean isTaskCompleted() { + return super.isTaskCompleted(); + } + + @Override + public Integer getNotificationIntervalSeconds() { + return super.getNotificationIntervalSeconds(); + } + + @Override + public void setNotificationIntervalSeconds(Integer intervalInSeconds) { + super.setNotificationIntervalSeconds(intervalInSeconds); + } + + @Override + public Date getDefiniteDueDate() { + return super.getDefiniteDueDate(); + } + + @Override + public Integer getEstimatedSeconds() { + return super.getEstimatedSeconds(); + } + + @Override + public Integer getElapsedSeconds() { + return super.getElapsedSeconds(); + } + + @Override + public Date getHiddenUntil() { + return super.getHiddenUntil(); + } + + @Override + public Importance getImportance() { + return super.getImportance(); + } + + @Override + public String getName() { + return super.getName(); + } + + @Override + public String getNotes() { + return super.getNotes(); + } + + @Override + public Date getPreferredDueDate() { + return super.getPreferredDueDate(); + } + + @Override + public int getProgressPercentage() { + return super.getProgressPercentage(); + } + + @Override + public TaskIdentifier getBlockingOn() { + return super.getBlockingOn(); + } + + @Override + public int getNotificationFlags() { + return super.getNotificationFlags(); + } + + @Override + public Date getLastNotificationDate() { + return super.getLastNotificationDate(); + } + + @Override + public RepeatInfo getRepeat() { + return super.getRepeat(); + } + + @Override + public String getCalendarUri() { + return super.getCalendarUri(); + } + + @Override + public void setDefiniteDueDate(Date definiteDueDate) { + super.setDefiniteDueDate(definiteDueDate); + } + + @Override + public void setEstimatedSeconds(Integer estimatedSeconds) { + super.setEstimatedSeconds(estimatedSeconds); + } + + @Override + public void setElapsedSeconds(int elapsedSeconds) { + super.setElapsedSeconds(elapsedSeconds); + } + + @Override + public void setHiddenUntil(Date hiddenUntil) { + super.setHiddenUntil(hiddenUntil); + } + + @Override + public void setImportance(Importance importance) { + super.setImportance(importance); + } + + @Override + public void setName(String name) { + super.setName(name); + } + + @Override + public void setNotes(String notes) { + super.setNotes(notes); + } + + @Override + public void setPreferredDueDate(Date preferredDueDate) { + super.setPreferredDueDate(preferredDueDate); + } + + @Override + public void setBlockingOn(TaskIdentifier blockingOn) { + super.setBlockingOn(blockingOn); + } + + @Override + public void setNotificationFlags(int flags) { + super.setNotificationFlags(flags); + } + + @Override + public void setRepeat(RepeatInfo taskRepeat) { + super.setRepeat(taskRepeat); + } + + @Override + public void setCalendarUri(String uri) { + super.setCalendarUri(uri); + } +} diff --git a/astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForHandlers.java b/astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForHandlers.java new file mode 100644 index 000000000..b0a88756a --- /dev/null +++ b/astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForHandlers.java @@ -0,0 +1,170 @@ +/* + * ASTRID: Android's Simple Task Recording Dashboard + * + * Copyright (c) 2009 Tim Su + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package com.timsu.astrid.data.task; + +import java.util.Date; +import java.util.List; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; + +import com.timsu.astrid.data.AbstractController; +import com.timsu.astrid.data.alerts.AlertController; + + + +/** Fields that you would want to read or edit in the onTaskSave and onTaskComplete + * event handlers */ +public class TaskModelForHandlers extends AbstractTaskModel { + + static String[] FIELD_LIST = new String[] { + AbstractController.KEY_ROWID, + REPEAT, + DEFINITE_DUE_DATE, + PREFERRED_DUE_DATE, + HIDDEN_UNTIL, + PROGRESS_PERCENTAGE, + ESTIMATED_SECONDS, + LAST_NOTIFIED, + NOTIFICATIONS, + NOTIFICATION_FLAGS, + FLAGS, + }; + + /** + * This method updates the task to reflect a new repeat iteration. It moves + * back the due dates and updates other task properties accordingly. + * + * @param context + * @param taskController + * @param repeatInfo + */ + public void repeatTaskBy(Context context, TaskController taskController, + RepeatInfo repeatInfo) { + + // move dates back + if(getDefiniteDueDate() != null) + setDefiniteDueDate(repeatInfo.shiftDate(getDefiniteDueDate())); + if(getHiddenUntil() != null) + setHiddenUntil(repeatInfo.shiftDate(getHiddenUntil())); + if(getPreferredDueDate() != null) + setPreferredDueDate(repeatInfo.shiftDate(getPreferredDueDate())); + setProgressPercentage(0); + + // set elapsed time to 0... yes, we're losing data + setElapsedSeconds(0); + + // if no deadlines set, create one (so users don't get confused) + if(getDefiniteDueDate() == null && getPreferredDueDate() == null) + setPreferredDueDate(repeatInfo.shiftDate(new Date())); + + // shift fixed alerts + AlertController alertController = new AlertController(context); + alertController.open(); + List alerts = alertController.getTaskAlerts(getTaskIdentifier()); + alertController.removeAlerts(getTaskIdentifier()); + for(int i = 0; i < alerts.size(); i++) { + Date newAlert = repeatInfo.shiftDate(alerts.get(i)); + alertController.addAlert(getTaskIdentifier(), newAlert); + alerts.set(i, newAlert); + } + + // reset periodic alerts + setLastNotificationTime(null); + +// ReminderService.updateAlarm(context, taskController, alertController, this); + alertController.close(); + } + + // --- constructors + + public TaskModelForHandlers(Cursor cursor, ContentValues setValues) { + super(cursor); + this.setValues = setValues; + } + + // --- getters and setters + + @Override + public RepeatInfo getRepeat() { + return super.getRepeat(); + } + + @Override + public Integer getNotificationIntervalSeconds() { + return super.getNotificationIntervalSeconds(); + } + + @Override + public boolean isTaskCompleted() { + return super.isTaskCompleted(); + } + + @Override + public Date getDefiniteDueDate() { + return super.getDefiniteDueDate(); + } + + @Override + public Integer getEstimatedSeconds() { + return super.getEstimatedSeconds(); + } + + @Override + public Date getHiddenUntil() { + return super.getHiddenUntil(); + } + + @Override + public Date getPreferredDueDate() { + return super.getPreferredDueDate(); + } + @Override + public int getNotificationFlags() { + return super.getNotificationFlags(); + } + + @Override + public Date getLastNotificationDate() { + return super.getLastNotificationDate(); + } + + @Override + public int getFlags() { + return super.getFlags(); + } + + @Override + public void setDefiniteDueDate(Date definiteDueDate) { + super.setDefiniteDueDate(definiteDueDate); + } + + @Override + public void setPreferredDueDate(Date preferredDueDate) { + super.setPreferredDueDate(preferredDueDate); + } + + @Override + public void setHiddenUntil(Date hiddenUntil) { + super.setHiddenUntil(hiddenUntil); + } + +} diff --git a/astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForList.java b/astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForList.java new file mode 100644 index 000000000..6ad03d20a --- /dev/null +++ b/astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForList.java @@ -0,0 +1,267 @@ +/* + * ASTRID: Android's Simple Task Recording Dashboard + * + * Copyright (c) 2009 Tim Su + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package com.timsu.astrid.data.task; + +import java.util.Date; +import java.util.HashMap; + +import android.content.Context; +import android.database.Cursor; + +import com.timsu.astrid.data.AbstractController; +import com.timsu.astrid.data.enums.Importance; + + + +/** Fields that you would want to edit in the TaskModel */ +public class TaskModelForList extends AbstractTaskModel { + + static String[] FIELD_LIST = new String[] { + AbstractController.KEY_ROWID, + NAME, + IMPORTANCE, + ELAPSED_SECONDS, + ESTIMATED_SECONDS, + TIMER_START, + DEFINITE_DUE_DATE, + PREFERRED_DUE_DATE, + NOTIFICATIONS, + PROGRESS_PERCENTAGE, + COMPLETION_DATE, + CREATION_DATE, + HIDDEN_UNTIL, + NOTES, + REPEAT, + FLAGS, + }; + + // pre-load the cache for our column keys + static { + HashMap indexCache = new HashMap(); + columnIndexCache.put(TaskModelForList.class, indexCache); + for(int i = 0; i < FIELD_LIST.length; i++) + indexCache.put(FIELD_LIST[i], i); + } + + /** Get the weighted score for this task. Smaller is more important */ + public int getTaskWeight() { + int weight = 0; + + // bubble tasks with timers to the top + if(getTimerStart() != null) + weight -= 10000; + + // importance + weight += getImportance().ordinal() * 80; + + // looming absolute deadline + if(getDefiniteDueDate() != null) { + int hoursLeft = (int) ((getDefiniteDueDate().getTime() - + System.currentTimeMillis())/1000/3600); + if(hoursLeft < 5*24) + weight += (hoursLeft - 5*24); + weight -= 20; + } + + // looming preferred deadline + if(getPreferredDueDate() != null) { + int hoursLeft = (int) ((getPreferredDueDate().getTime() - + System.currentTimeMillis())/1000/3600); + if(hoursLeft < 5*24) + weight += (hoursLeft - 5*24)/2; + weight -= 10; + } + + // bubble completed tasks to the bottom + if(isTaskCompleted()) { + if(getCompletionDate() == null) + weight += 1e6; + else + weight = (int)Math.max(10000 + (System.currentTimeMillis() - + getCompletionDate().getTime()) / 1000, 10000); + return weight; + } + + return weight; + } + + @Override + public boolean isHidden() { + return super.isHidden(); + } + + /** map of cached display labels */ + private final HashMap displayLabels = new HashMap(); + + public String getCachedLabel(int key) { + return displayLabels.get(key); + } + public void putCachedLabel(int key, String value) { + displayLabels.put(key, value); + } + public void clearCache() { + displayLabels.clear(); + } + + // --- constructors + + public TaskModelForList(Cursor cursor) { + super(cursor); + + prefetchData(FIELD_LIST); + } + + // --- exposed getters and setters + + @Override + public boolean isTaskCompleted() { + return super.isTaskCompleted(); + } + + @Override + public int getTaskColorResource(Context context) { + return super.getTaskColorResource(context); + } + + @Override + public Integer getElapsedSeconds() { + return super.getElapsedSeconds(); + } + + public static int getCompletedPercentage() { + return COMPLETE_PERCENTAGE; + } + + @Override + public Date getDefiniteDueDate() { + return super.getDefiniteDueDate(); + } + + @Override + public Integer getEstimatedSeconds() { + return super.getEstimatedSeconds(); + } + + @Override + public Date getHiddenUntil() { + return super.getHiddenUntil(); + } + + @Override + public Importance getImportance() { + return super.getImportance(); + } + + @Override + public String getName() { + return super.getName(); + } + + @Override + public Date getPreferredDueDate() { + return super.getPreferredDueDate(); + } + + @Override + public int getProgressPercentage() { + return super.getProgressPercentage(); + } + + @Override + public Date getTimerStart() { + return super.getTimerStart(); + } + + @Override + public Date getCompletionDate() { + return super.getCompletionDate(); + } + + @Override + public String getNotes() { + return super.getNotes(); + } + + @Override + public Integer getNotificationIntervalSeconds() { + return super.getNotificationIntervalSeconds(); + } + + @Override + public RepeatInfo getRepeat() { + return super.getRepeat(); + } + + @Override + public Date getCreationDate() { + return super.getCreationDate(); + } + + @Override + public int getFlags() { + return super.getFlags(); + } + + // --- setters + + @Override + public void setProgressPercentage(int progressPercentage) { + super.setProgressPercentage(progressPercentage); + } + + @Override + public void setTimerStart(Date timerStart) { + super.setTimerStart(timerStart); + } + + @Override + public void stopTimerAndUpdateElapsedTime() { + super.stopTimerAndUpdateElapsedTime(); + } + + public static String getNameField() { + return NAME; + } + + @Override + public void setPreferredDueDate(Date preferredDueDate) { + super.setPreferredDueDate(preferredDueDate); + } + + @Override + public void setDefiniteDueDate(Date definiteDueDate) { + super.setDefiniteDueDate(definiteDueDate); + } + + @Override + public void setImportance(Importance importance) { + super.setImportance(importance); + } + + @Override + public void setHiddenUntil(Date hiddenUntil) { + super.setHiddenUntil(hiddenUntil); + } + + @Override + public void setPostponeCount(int postponeCount) { + super.setPostponeCount(postponeCount); + } +} diff --git a/astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForNotify.java b/astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForNotify.java new file mode 100644 index 000000000..54b40c64c --- /dev/null +++ b/astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForNotify.java @@ -0,0 +1,101 @@ +/* + * ASTRID: Android's Simple Task Recording Dashboard + * + * Copyright (c) 2009 Tim Su + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package com.timsu.astrid.data.task; + +import java.util.Date; + +import android.database.Cursor; + +import com.timsu.astrid.data.AbstractController; + + + +/** Fields that you would want to see in the TaskView activity */ +public class TaskModelForNotify extends AbstractTaskModel { + + static String[] FIELD_LIST = new String[] { + AbstractController.KEY_ROWID, + ESTIMATED_SECONDS, + NOTIFICATIONS, + NOTIFICATION_FLAGS, + LAST_NOTIFIED, + HIDDEN_UNTIL, + PROGRESS_PERCENTAGE, + DEFINITE_DUE_DATE, + PREFERRED_DUE_DATE, + }; + + // --- constructors + + public TaskModelForNotify(Cursor cursor) { + super(cursor); + + prefetchData(FIELD_LIST); + } + + // --- getters + + @Override + public Integer getEstimatedSeconds() { + return super.getEstimatedSeconds(); + } + + @Override + public boolean isTaskCompleted() { + return super.isTaskCompleted(); + } + + @Override + public Integer getNotificationIntervalSeconds() { + return super.getNotificationIntervalSeconds(); + } + + @Override + public Date getHiddenUntil() { + return super.getHiddenUntil(); + } + + @Override + public Date getDefiniteDueDate() { + return super.getDefiniteDueDate(); + } + + @Override + public Date getPreferredDueDate() { + return super.getPreferredDueDate(); + } + + @Override + public int getNotificationFlags() { + return super.getNotificationFlags(); + } + + @Override + public Date getLastNotificationDate() { + return super.getLastNotificationDate(); + } + + // --- setters + + @Override + public void setLastNotificationTime(Date date) { + super.setLastNotificationTime(date); + } +} diff --git a/astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForProvider.java b/astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForProvider.java new file mode 100644 index 000000000..5b3d90b53 --- /dev/null +++ b/astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForProvider.java @@ -0,0 +1,78 @@ +/* + * ASTRID: Android's Simple Task Recording Dashboard + * + * Copyright (c) 2009 Francois DESLANDES + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package com.timsu.astrid.data.task; + +import java.util.Date; + +import android.content.ContentValues; +import android.database.Cursor; + +import com.timsu.astrid.data.AbstractController; +import com.timsu.astrid.data.enums.Importance; + + + +/** Fields that you would want to see in the TaskView activity */ +public class TaskModelForProvider extends AbstractTaskModel { + + static String[] FIELD_LIST = new String[] { + AbstractController.KEY_ROWID, + NAME, + IMPORTANCE, + PREFERRED_DUE_DATE, + DEFINITE_DUE_DATE, + "COALESCE(" + PREFERRED_DUE_DATE + ", 0) as pdd", + "COALESCE(" + DEFINITE_DUE_DATE + ", 0) as ddd" + }; + + // --- constructors + + public TaskModelForProvider(Cursor cursor) { + super(cursor); + + prefetchData(FIELD_LIST); + } + + // --- getters + + @Override + public String getName() { + return super.getName(); + } + + @Override + public Importance getImportance() { + return super.getImportance(); + } + + @Override + public Date getPreferredDueDate() { + return super.getPreferredDueDate(); + } + + @Override + public Date getDefiniteDueDate() { + return super.getDefiniteDueDate(); + } + + public void update(ContentValues newValues) { + setValues.putAll(newValues); + } +} diff --git a/astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForReminder.java b/astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForReminder.java new file mode 100644 index 000000000..26c93cdc1 --- /dev/null +++ b/astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForReminder.java @@ -0,0 +1,83 @@ +/* + * ASTRID: Android's Simple Task Recording Dashboard + * + * Copyright (c) 2009 Tim Su + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package com.timsu.astrid.data.task; + +import java.util.Date; + +import android.database.Cursor; + +import com.timsu.astrid.data.AbstractController; + + + +/** Fields that you would want to see in the TaskView activity */ +public class TaskModelForReminder extends AbstractTaskModel { + + static String[] FIELD_LIST = new String[] { + AbstractController.KEY_ROWID, + NAME, + NOTIFICATION_FLAGS, + HIDDEN_UNTIL, + TIMER_START, + PROGRESS_PERCENTAGE, + }; + + // --- constructors + + public TaskModelForReminder(Cursor cursor) { + super(cursor); + + prefetchData(FIELD_LIST); + } + + // --- getters + + @Override + public String getName() { + return super.getName(); + } + + @Override + public Date getTimerStart() { + return super.getTimerStart(); + } + + @Override + public boolean isTaskCompleted() { + return super.isTaskCompleted(); + } + + @Override + public Date getHiddenUntil() { + return super.getHiddenUntil(); + } + + @Override + public int getNotificationFlags() { + return super.getNotificationFlags(); + } + + // --- setters + + @Override + public void setLastNotificationTime(Date date) { + super.setLastNotificationTime(date); + } +} diff --git a/astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForSync.java b/astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForSync.java new file mode 100644 index 000000000..3a3c54d9b --- /dev/null +++ b/astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForSync.java @@ -0,0 +1,236 @@ +/* + * ASTRID: Android's Simple Task Recording Dashboard + * + * Copyright (c) 2009 Tim Su + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package com.timsu.astrid.data.task; + +import java.util.Date; + +import android.database.Cursor; + +import com.timsu.astrid.data.AbstractController; +import com.timsu.astrid.data.enums.Importance; + + + +/** Fields that you would want to synchronize in the TaskModel */ +public class TaskModelForSync extends AbstractTaskModel { + + static String[] FIELD_LIST = new String[] { + AbstractController.KEY_ROWID, + NAME, + IMPORTANCE, + ESTIMATED_SECONDS, + ELAPSED_SECONDS, + DEFINITE_DUE_DATE, + PREFERRED_DUE_DATE, + HIDDEN_UNTIL, + BLOCKING_ON, + PROGRESS_PERCENTAGE, + CREATION_DATE, + COMPLETION_DATE, + NOTES, + REPEAT, + LAST_NOTIFIED, + NOTIFICATIONS, + NOTIFICATION_FLAGS, + FLAGS, + }; + + // --- constructors + + public TaskModelForSync() { + super(); + setCreationDate(new Date()); + } + + public TaskModelForSync(Cursor cursor) { + super(cursor); + prefetchData(FIELD_LIST); + } + + // --- getters and setters + + @Override + public boolean isTaskCompleted() { + return super.isTaskCompleted(); + } + + @Override + public Date getDefiniteDueDate() { + return super.getDefiniteDueDate(); + } + + @Override + public Integer getEstimatedSeconds() { + return super.getEstimatedSeconds(); + } + + @Override + public int getProgressPercentage() { + return super.getProgressPercentage(); + } + + @Override + public Date getCreationDate() { + return super.getCreationDate(); + } + + @Override + public Date getCompletionDate() { + return super.getCompletionDate(); + } + + @Override + public Integer getElapsedSeconds() { + return super.getElapsedSeconds(); + } + + @Override + public Date getHiddenUntil() { + return super.getHiddenUntil(); + } + + @Override + public Importance getImportance() { + return super.getImportance(); + } + + @Override + public String getName() { + return super.getName(); + } + + @Override + public String getNotes() { + return super.getNotes(); + } + + @Override + public Date getPreferredDueDate() { + return super.getPreferredDueDate(); + } + + @Override + public TaskIdentifier getBlockingOn() { + return super.getBlockingOn(); + } + + @Override + public RepeatInfo getRepeat() { + return super.getRepeat(); + } + + @Override + public Integer getNotificationIntervalSeconds() { + return super.getNotificationIntervalSeconds(); + } + + @Override + public int getNotificationFlags() { + return super.getNotificationFlags(); + } + + @Override + public Date getLastNotificationDate() { + return super.getLastNotificationDate(); + } + + @Override + public int getFlags() { + return super.getFlags(); + } + + // --- setters + + @Override + public void setDefiniteDueDate(Date definiteDueDate) { + super.setDefiniteDueDate(definiteDueDate); + } + + @Override + public void setEstimatedSeconds(Integer estimatedSeconds) { + super.setEstimatedSeconds(estimatedSeconds); + } + + @Override + public void setElapsedSeconds(int elapsedSeconds) { + super.setElapsedSeconds(elapsedSeconds); + } + + @Override + public void setHiddenUntil(Date hiddenUntil) { + super.setHiddenUntil(hiddenUntil); + } + + @Override + public void setImportance(Importance importance) { + super.setImportance(importance); + } + + @Override + public void setName(String name) { + super.setName(name); + } + + @Override + public void setNotes(String notes) { + super.setNotes(notes); + } + + @Override + public void setPreferredDueDate(Date preferredDueDate) { + super.setPreferredDueDate(preferredDueDate); + } + + @Override + public void setBlockingOn(TaskIdentifier blockingOn) { + super.setBlockingOn(blockingOn); + } + + @Override + public void setRepeat(RepeatInfo taskRepeat) { + super.setRepeat(taskRepeat); + } + + @Override + public void setCompletionDate(Date completionDate) { + super.setCompletionDate(completionDate); + } + + @Override + public void setCreationDate(Date creationDate) { + super.setCreationDate(creationDate); + } + + @Override + public void setProgressPercentage(int progressPercentage) { + super.setProgressPercentage(progressPercentage); + } + + @Override + public void setNotificationIntervalSeconds(Integer intervalInSeconds) { + super.setNotificationIntervalSeconds(intervalInSeconds); + } + + @Override + public void setFlags(int flags) { + super.setFlags(flags); + } +} + diff --git a/astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForWidget.java b/astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForWidget.java new file mode 100644 index 000000000..61cffecf1 --- /dev/null +++ b/astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForWidget.java @@ -0,0 +1,73 @@ +/* + * ASTRID: Android's Simple Task Recording Dashboard + * + * Copyright (c) 2009 Tim Su + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package com.timsu.astrid.data.task; + +import java.util.Date; + +import android.database.Cursor; + +import com.timsu.astrid.data.AbstractController; +import com.timsu.astrid.data.enums.Importance; + + + +/** Fields that you would want to see in the TaskView activity */ +public class TaskModelForWidget extends AbstractTaskModel { + + static String[] FIELD_LIST = new String[] { + AbstractController.KEY_ROWID, + NAME, + IMPORTANCE, + PREFERRED_DUE_DATE, + DEFINITE_DUE_DATE, + "COALESCE(" + PREFERRED_DUE_DATE + ", 0) as pdd", + "COALESCE(" + DEFINITE_DUE_DATE + ", 0) as ddd" + }; + + // --- constructors + + public TaskModelForWidget(Cursor cursor) { + super(cursor); + + prefetchData(FIELD_LIST); + } + + // --- getters + + @Override + public String getName() { + return super.getName(); + } + + @Override + public Importance getImportance() { + return super.getImportance(); + } + + @Override + public Date getPreferredDueDate() { + return super.getPreferredDueDate(); + } + + @Override + public Date getDefiniteDueDate() { + return super.getDefiniteDueDate(); + } +} diff --git a/astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForXml.java b/astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForXml.java new file mode 100644 index 000000000..7aed15157 --- /dev/null +++ b/astrid/src-legacy/com/timsu/astrid/data/task/TaskModelForXml.java @@ -0,0 +1,218 @@ +package com.timsu.astrid.data.task; + +import java.util.Date; +import java.util.HashMap; + +import android.database.Cursor; +import android.util.Log; + +import com.timsu.astrid.R; +import com.timsu.astrid.data.AbstractController; +import com.timsu.astrid.data.enums.Importance; +import com.timsu.astrid.data.enums.RepeatInterval; +import com.todoroo.astrid.backup.BackupDateUtilities; + +public class TaskModelForXml extends AbstractTaskModel { + + static String[] FIELD_LIST = new String[] { + AbstractController.KEY_ROWID, + NAME, + IMPORTANCE, + ELAPSED_SECONDS, + ESTIMATED_SECONDS, + TIMER_START, + DEFINITE_DUE_DATE, + PREFERRED_DUE_DATE, + NOTIFICATIONS, + PROGRESS_PERCENTAGE, + COMPLETION_DATE, + CREATION_DATE, + HIDDEN_UNTIL, + NOTES, + REPEAT, + FLAGS, + POSTPONE_COUNT, + BLOCKING_ON, + LAST_NOTIFIED, + NOTIFICATION_FLAGS, + CALENDAR_URI, + }; + private final HashMap taskAttributesMap; + public static final String REPEAT_VALUE = "repeat_value"; + public static final String REPEAT_INTERVAL = "repeat_interval"; + + + private RepeatInterval repeatInterval = null; + private Integer repeatValue = null; + + // --- constructors + + public TaskModelForXml() { + super(); + setCreationDate(new Date()); + taskAttributesMap = new HashMap(FIELD_LIST.length); + } + + public TaskModelForXml(Cursor cursor) { + super(cursor); + prefetchData(FIELD_LIST); + taskAttributesMap = new HashMap(FIELD_LIST.length); + } + + /* Safely add a value from a date field (in case of null values) to the + taskAttributesMap. + */ + private void safePutDate(String field, Date value) { + if (value != null) { + taskAttributesMap.put(field, BackupDateUtilities.getIso8601String(value)); + } + } + + // --- getters and setters + + @Override + public Date getCreationDate() { + return super.getCreationDate(); + } + + /* Build a HashMap of task fields and associated values. + */ + public HashMap getTaskAttributes() { + taskAttributesMap.put(AbstractController.KEY_ROWID, getTaskIdentifier().idAsString()); + taskAttributesMap.put(NAME, getName()); + taskAttributesMap.put(IMPORTANCE, getImportance().toString()); + taskAttributesMap.put(ELAPSED_SECONDS, getElapsedSeconds().toString()); + taskAttributesMap.put(ESTIMATED_SECONDS, getEstimatedSeconds().toString()); + safePutDate(TIMER_START, getTimerStart()); + safePutDate(DEFINITE_DUE_DATE, getDefiniteDueDate()); + safePutDate(PREFERRED_DUE_DATE, getPreferredDueDate()); + taskAttributesMap.put(NOTIFICATIONS, getNotificationIntervalSeconds().toString()); + taskAttributesMap.put(PROGRESS_PERCENTAGE, Integer.toString(getProgressPercentage())); + safePutDate(COMPLETION_DATE, getCompletionDate()); + safePutDate(CREATION_DATE, getCreationDate()); + safePutDate(HIDDEN_UNTIL, getHiddenUntil()); + taskAttributesMap.put(NOTES, getNotes()); + RepeatInfo repeat = getRepeat(); + if (repeat != null) { + taskAttributesMap.put(REPEAT_VALUE, Integer.toString(repeat.getValue())); + taskAttributesMap.put(REPEAT_INTERVAL, repeat.getInterval().toString()); + } + taskAttributesMap.put(FLAGS, Integer.toString(getFlags())); + taskAttributesMap.put(POSTPONE_COUNT, getPostponeCount().toString()); + taskAttributesMap.put(BLOCKING_ON, Long.toString(getBlockingOn().getId())); + safePutDate(LAST_NOTIFIED, getLastNotificationDate()); + taskAttributesMap.put(NOTIFICATION_FLAGS, Integer.toString(getNotificationFlags())); + String calendarUri = getCalendarUri(); + if (calendarUri != null) { + taskAttributesMap.put(CALENDAR_URI, calendarUri); + } + return taskAttributesMap; + } + + // --- setters + + public boolean setField(String field, String value) { + boolean success = true; + if(field.equals(NAME)) { + setName(value); + } + else if(field.equals(NOTES)) { + setNotes(value); + } + else if(field.equals(PROGRESS_PERCENTAGE)) { + setProgressPercentage(Integer.parseInt(value)); + } + else if(field.equals(IMPORTANCE)) { + setImportance(Importance.valueOf(value)); + } + else if(field.equals(ESTIMATED_SECONDS)) { + setEstimatedSeconds(Integer.parseInt(value)); + } + else if(field.equals(ELAPSED_SECONDS)) { + setElapsedSeconds(Integer.parseInt(value)); + } + else if(field.equals(TIMER_START)) { + setTimerStart(BackupDateUtilities.getDateFromIso8601String(value)); + } + else if(field.equals(DEFINITE_DUE_DATE)) { + setDefiniteDueDate(BackupDateUtilities.getDateFromIso8601String(value)); + } + else if(field.equals(PREFERRED_DUE_DATE)) { + setPreferredDueDate(BackupDateUtilities.getDateFromIso8601String(value)); + } + else if(field.equals(HIDDEN_UNTIL)) { + setHiddenUntil(BackupDateUtilities.getDateFromIso8601String(value)); + } + else if(field.equals(BLOCKING_ON)) { + setBlockingOn(new TaskIdentifier(Long.parseLong(value))); + } + else if(field.equals(POSTPONE_COUNT)) { + setPostponeCount(Integer.parseInt(value)); + } + else if(field.equals(NOTIFICATIONS)) { + setNotificationIntervalSeconds(Integer.parseInt(value)); + } + else if(field.equals(CREATION_DATE)) { + setCreationDate(BackupDateUtilities.getDateFromIso8601String(value)); + } + else if(field.equals(COMPLETION_DATE)) { + setCompletionDate(BackupDateUtilities.getDateFromIso8601String(value)); + } + else if(field.equals(NOTIFICATION_FLAGS)) { + setNotificationFlags(Integer.parseInt(value)); + } + else if(field.equals(LAST_NOTIFIED)) { + setLastNotificationTime(BackupDateUtilities.getDateFromIso8601String(value)); + } + else if(field.equals(REPEAT_INTERVAL)) { + try { + setRepeatInterval(RepeatInterval.valueOf(value)); + } catch (Exception e) { + RepeatInterval repeatInterval; + switch (Integer.parseInt(value)) { + case R.string.repeat_days: + repeatInterval = RepeatInterval.DAYS; + break; + case R.string.repeat_weeks: + repeatInterval = RepeatInterval.WEEKS; + break; + case R.string.repeat_months: + repeatInterval = RepeatInterval.MONTHS; + break; + case R.string.repeat_hours: + repeatInterval = RepeatInterval.HOURS; + break; + default: + Log.e("XmlImport", "Unable to set repeat interval"); + repeatInterval = RepeatInterval.DAYS; + break; + } + setRepeatInterval(repeatInterval); + } + } + else if(field.equals(REPEAT_VALUE)) { + setRepeatValue(Integer.parseInt(value)); + } + else if(field.equals(FLAGS)) { + setFlags(Integer.parseInt(value)); + } + else { + success = false; + } + return success; + } + + public void setRepeatInterval(RepeatInterval repeatInterval) { + this.repeatInterval = repeatInterval; + if (repeatValue != null) { + setRepeat(new RepeatInfo(repeatInterval, repeatValue)); + } + } + + public void setRepeatValue(Integer repeatValue) { + this.repeatValue = repeatValue; + if (repeatInterval != null) { + setRepeat(new RepeatInfo(repeatInterval, repeatValue)); + } + } +} diff --git a/astrid/src-legacy/com/timsu/astrid/provider/TasksProvider.java b/astrid/src-legacy/com/timsu/astrid/provider/TasksProvider.java index 3111d980d..d8ca37d32 100644 --- a/astrid/src-legacy/com/timsu/astrid/provider/TasksProvider.java +++ b/astrid/src-legacy/com/timsu/astrid/provider/TasksProvider.java @@ -12,11 +12,11 @@ import android.database.MatrixCursor; import android.net.Uri; import android.util.Log; -import com.timsu.astrid.data.TaskController; -import com.timsu.astrid.data.TaskModelForProvider; import com.timsu.astrid.data.tag.TagController; import com.timsu.astrid.data.tag.TagIdentifier; import com.timsu.astrid.data.tag.TagModelForView; +import com.timsu.astrid.data.task.TaskController; +import com.timsu.astrid.data.task.TaskModelForProvider; import com.todoroo.astrid.service.AstridDependencyInjector; public class TasksProvider extends ContentProvider { diff --git a/astrid/src-legacy/com/timsu/astrid/utilities/LegacyTasksXmlExporter.java b/astrid/src-legacy/com/timsu/astrid/utilities/LegacyTasksXmlExporter.java index 1cedf1137..642cbd5b2 100644 --- a/astrid/src-legacy/com/timsu/astrid/utilities/LegacyTasksXmlExporter.java +++ b/astrid/src-legacy/com/timsu/astrid/utilities/LegacyTasksXmlExporter.java @@ -19,17 +19,19 @@ import android.util.Xml; import android.widget.Toast; import com.timsu.astrid.R; -import com.timsu.astrid.data.TaskController; -import com.timsu.astrid.data.TaskIdentifier; -import com.timsu.astrid.data.TaskModelForXml; import com.timsu.astrid.data.alerts.AlertController; import com.timsu.astrid.data.sync.SyncDataController; import com.timsu.astrid.data.sync.SyncMapping; import com.timsu.astrid.data.tag.TagController; import com.timsu.astrid.data.tag.TagIdentifier; import com.timsu.astrid.data.tag.TagModelForView; +import com.timsu.astrid.data.task.TaskController; +import com.timsu.astrid.data.task.TaskIdentifier; +import com.timsu.astrid.data.task.TaskModelForXml; import com.todoroo.astrid.backup.BackupDateUtilities; +@SuppressWarnings("nls") +@Deprecated public class LegacyTasksXmlExporter { private TaskController taskController; @@ -60,6 +62,9 @@ public class LegacyTasksXmlExporter { public static final int FILENAME_DATE_BEGIN_INDEX = 5; public static final int FILENAME_DATE_END_INDEX = 11; + /** last version before 3.0, used for XML header */ + private static final int LEGACY_VERSION = 137; + public LegacyTasksXmlExporter(boolean isService) { this.isService = isService; this.exportCount = 0; @@ -139,7 +144,7 @@ public class LegacyTasksXmlExporter { xml.startTag(null, ASTRID_TAG); xml.attribute(null, ASTRID_ATTR_VERSION, - Integer.toString(Preferences.getCurrentVersion(ctx))); + Integer.toString(LEGACY_VERSION)); openControllers(); initTagMap(); @@ -182,10 +187,6 @@ public class LegacyTasksXmlExporter { } public void exportTasks(File directory) { - if (isService && !Preferences.isBackupEnabled(ctx)) { - // Automatic backups are disabled. - return; - } if (setupFile(directory)) { Thread thread = new Thread(doBackgroundExport); thread.start();