From 06f57a27efc285dc0a2b2a19fe4fd91f493517b3 Mon Sep 17 00:00:00 2001 From: Sam Bosley Date: Mon, 10 Sep 2012 14:30:35 -0700 Subject: [PATCH] Record entries in the tag and tasks outstanding table when models change --- .../todoroo/andlib/data/AbstractDatabase.java | 17 ++++ .../com/todoroo/andlib/data/DatabaseDao.java | 78 +++++++++++++++++-- .../todoroo/astrid/data/OutstandingEntry.java | 10 +++ api/src/com/todoroo/astrid/data/TagData.java | 3 + api/src/com/todoroo/astrid/data/Task.java | 3 + .../astrid/actfm/EditPeopleControlSet.java | 4 +- .../com/todoroo/astrid/dao/TagDataDao.java | 11 +++ .../src/com/todoroo/astrid/dao/TaskDao.java | 14 ++++ 8 files changed, 132 insertions(+), 8 deletions(-) diff --git a/api/src/com/todoroo/andlib/data/AbstractDatabase.java b/api/src/com/todoroo/andlib/data/AbstractDatabase.java index e7c00205b..f24952551 100644 --- a/api/src/com/todoroo/andlib/data/AbstractDatabase.java +++ b/api/src/com/todoroo/andlib/data/AbstractDatabase.java @@ -5,6 +5,7 @@ */ package com.todoroo.andlib.data; +import java.lang.reflect.Field; import java.util.ArrayList; import android.content.ContentValues; @@ -131,6 +132,22 @@ abstract public class AbstractDatabase { throw new UnsupportedOperationException("Unknown model class " + modelType); //$NON-NLS-1$ } + public final Table getOutstandingTable(Class modelType) { + try { + Field f = modelType.getDeclaredField("OUTSTANDING_MODEL"); + Class outstandingModelType = (Class) f.get(null); + return getTable(outstandingModelType); + } catch (NoSuchFieldException n) { + // + } catch (IllegalAccessException i) { + // + } catch (ClassCastException c) { + throw new RuntimeException("Outstanding model class for type " + modelType + " could not be cast"); + } + + return null; + } + protected synchronized final void initializeHelper() { if(helper == null) { if(ContextManager.getContext() == null) diff --git a/api/src/com/todoroo/andlib/data/DatabaseDao.java b/api/src/com/todoroo/andlib/data/DatabaseDao.java index 8d5ee1891..b1ec7fdd1 100644 --- a/api/src/com/todoroo/andlib/data/DatabaseDao.java +++ b/api/src/com/todoroo/andlib/data/DatabaseDao.java @@ -8,15 +8,21 @@ package com.todoroo.andlib.data; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; import android.content.ContentValues; import android.database.Cursor; +import android.database.sqlite.SQLiteTransactionListener; import android.util.Log; import com.todoroo.andlib.service.Autowired; import com.todoroo.andlib.service.DependencyInjectionService; import com.todoroo.andlib.sql.Criterion; import com.todoroo.andlib.sql.Query; +import com.todoroo.andlib.utility.DateUtilities; +import com.todoroo.astrid.data.OutstandingEntry; @@ -34,6 +40,8 @@ public class DatabaseDao { private Table table; + private Table outstandingTable; + private AbstractDatabase database; @Autowired @@ -67,6 +75,7 @@ public class DatabaseDao { return; this.database = database; table = database.getTable(modelClass); + outstandingTable = database.getOutstandingTable(modelClass); } // --- listeners @@ -254,13 +263,70 @@ public class DatabaseDao { ContentValues values = item.getSetValues(); if(values == null || values.size() == 0) // nothing changed return true; - boolean result = database.update(table.name, values, - AbstractModel.ID_PROPERTY.eq(item.getId()).toString(), null) > 0; - if(result) { - onModelUpdated(item); - item.markSaved(); + boolean recordOutstanding = (outstandingTable != null); + final AtomicBoolean result = new AtomicBoolean(false); + + if (recordOutstanding) { // begin transaction + database.getDatabase().beginTransactionWithListener(new SQLiteTransactionListener() { + @Override + public void onRollback() { + result.set(false); + } + @Override + public void onCommit() {/**/} + @Override + public void onBegin() {/**/} + }); } - return result; + try { + result.set(database.update(table.name, values, + AbstractModel.ID_PROPERTY.eq(item.getId()).toString(), null) > 0); + if(result.get()) { + if (recordOutstanding) + createOutstandingEntries(item.getId(), values); // Create entries for setValues in outstanding table + onModelUpdated(item); + item.markSaved(); + } + } finally { + if (recordOutstanding) // commit transaction + database.getDatabase().endTransaction(); + } + return result.get(); + } + + private boolean createOutstandingEntries(long modelId, ContentValues modelSetValues) { + Set> entries = modelSetValues.valueSet(); + long now = DateUtilities.now(); + for (Entry entry : entries) { + if (entry.getValue() != null && recordOutstandingEntry(entry.getKey())) { + AbstractModel m; + try { + m = outstandingTable.modelClass.newInstance(); + } catch (IllegalAccessException e) { + return false; + } catch (InstantiationException e2) { + return false; + } + m.setValue(OutstandingEntry.ENTITY_ID_PROPERTY, modelId); + m.setValue(OutstandingEntry.COLUMN_STRING_PROPERTY, entry.getKey()); + m.setValue(OutstandingEntry.VALUE_STRING_PROPERTY, entry.getValue().toString()); + m.setValue(OutstandingEntry.CREATED_AT_PROPERTY, now); + database.insert(outstandingTable.name, null, m.getSetValues()); + } + } + database.getDatabase().setTransactionSuccessful(); + return true; + } + + /** + * Returns true if an entry in the outstanding table should be recorded for this + * column. Subclasses can override to return false for insignificant columns + * (e.g. Task.DETAILS, last modified, etc.) + * @param columnName + * @return + */ + protected boolean recordOutstandingEntry(String columnName) { + return true; } /** diff --git a/api/src/com/todoroo/astrid/data/OutstandingEntry.java b/api/src/com/todoroo/astrid/data/OutstandingEntry.java index 1fe1a4e39..698e293f0 100644 --- a/api/src/com/todoroo/astrid/data/OutstandingEntry.java +++ b/api/src/com/todoroo/astrid/data/OutstandingEntry.java @@ -1,16 +1,26 @@ package com.todoroo.astrid.data; import com.todoroo.andlib.data.AbstractModel; +import com.todoroo.andlib.data.Property.LongProperty; +import com.todoroo.andlib.data.Property.StringProperty; @SuppressWarnings("nls") public abstract class OutstandingEntry extends AbstractModel { public static final String ENTITY_ID_PROPERTY_NAME = "entityId"; + public static final LongProperty ENTITY_ID_PROPERTY = new LongProperty(null, ENTITY_ID_PROPERTY_NAME); + public static final String COLUMN_STRING_PROPERTY_NAME = "columnString"; + public static final StringProperty COLUMN_STRING_PROPERTY = new StringProperty(null, COLUMN_STRING_PROPERTY_NAME); + public static final String VALUE_STRING_PROPERTY_NAME = "valueString"; + public static final StringProperty VALUE_STRING_PROPERTY = new StringProperty(null, VALUE_STRING_PROPERTY_NAME); + public static final String CREATED_AT_PROPERTY_NAME = "createdAt"; + public static final LongProperty CREATED_AT_PROPERTY = new LongProperty(null, CREATED_AT_PROPERTY_NAME); + } diff --git a/api/src/com/todoroo/astrid/data/TagData.java b/api/src/com/todoroo/astrid/data/TagData.java index 150e99bce..e577300e6 100644 --- a/api/src/com/todoroo/astrid/data/TagData.java +++ b/api/src/com/todoroo/astrid/data/TagData.java @@ -32,6 +32,9 @@ public final class TagData extends RemoteModel { /** table for this model */ public static final Table TABLE = new Table("tagdata", TagData.class); + /** model class for entries in the outstanding table */ + public static final Class OUTSTANDING_MODEL = TagOutstanding.class; + /** content uri for this model */ public static final Uri CONTENT_URI = Uri.parse("content://" + AstridApiConstants.PACKAGE + "/" + TABLE.name); diff --git a/api/src/com/todoroo/astrid/data/Task.java b/api/src/com/todoroo/astrid/data/Task.java index 51de6e8cc..4cc7c9efd 100644 --- a/api/src/com/todoroo/astrid/data/Task.java +++ b/api/src/com/todoroo/astrid/data/Task.java @@ -37,6 +37,9 @@ public final class Task extends RemoteModel { /** table for this model */ public static final Table TABLE = new Table("tasks", Task.class); + /** model class for entries in the outstanding table */ + public static final Class OUTSTANDING_MODEL = TaskOutstanding.class; + /** content uri for this model */ public static final Uri CONTENT_URI = Uri.parse("content://" + AstridApiConstants.PACKAGE + "/" + TABLE.name); diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/EditPeopleControlSet.java b/astrid/plugin-src/com/todoroo/astrid/actfm/EditPeopleControlSet.java index eafe4c02a..ef15cd054 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/EditPeopleControlSet.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/EditPeopleControlSet.java @@ -730,7 +730,7 @@ public class EditPeopleControlSet extends PopupControlSet { dirty = task.getValue(Task.USER_ID) == Task.USER_ID_SELF ? dirty : true; task.setValue(Task.USER_ID, Task.USER_ID_SELF); if(!TextUtils.isEmpty(task.getValue(Task.USER))) - task.setValue(Task.USER, ""); + task.setValue(Task.USER, "{}"); assignedToMe = true; } else if(userJson.optLong("id") == Task.USER_ID_UNASSIGNED) { @@ -764,7 +764,7 @@ public class EditPeopleControlSet extends PopupControlSet { JSONObject sharedWith = sharedWithContainer.parseSharedWithAndTags(activity, false); EditText message = (EditText) getSharedWithView().findViewById(R.id.message); - if (!TextUtils.isEmpty(message.getText())) + if (!TextUtils.isEmpty(message.getText()) && sharedWith.has("p")) sharedWith.put("message", message.getText().toString()); if(cbFacebook.isChecked()) diff --git a/astrid/src/com/todoroo/astrid/dao/TagDataDao.java b/astrid/src/com/todoroo/astrid/dao/TagDataDao.java index 5e86332e6..89de28b67 100644 --- a/astrid/src/com/todoroo/astrid/dao/TagDataDao.java +++ b/astrid/src/com/todoroo/astrid/dao/TagDataDao.java @@ -9,6 +9,7 @@ import com.todoroo.andlib.data.DatabaseDao; import com.todoroo.andlib.service.Autowired; import com.todoroo.andlib.service.DependencyInjectionService; import com.todoroo.andlib.sql.Criterion; +import com.todoroo.andlib.utility.AndroidUtilities; import com.todoroo.astrid.data.TagData; /** @@ -28,6 +29,16 @@ public class TagDataDao extends DatabaseDao { setDatabase(database); } + private static final String[] IGNORE_OUTSTANDING_COLUMNS = new String[] { + TagData.MODIFICATION_DATE.name, + TagData.UUID.name + }; + + @Override + protected boolean recordOutstandingEntry(String columnName) { + return AndroidUtilities.indexOf(IGNORE_OUTSTANDING_COLUMNS, columnName) < 0; + } + // --- SQL clause generators /** diff --git a/astrid/src/com/todoroo/astrid/dao/TaskDao.java b/astrid/src/com/todoroo/astrid/dao/TaskDao.java index 79eaaceba..3c7faa945 100644 --- a/astrid/src/com/todoroo/astrid/dao/TaskDao.java +++ b/astrid/src/com/todoroo/astrid/dao/TaskDao.java @@ -21,6 +21,7 @@ import com.todoroo.andlib.sql.Criterion; import com.todoroo.andlib.sql.Field; import com.todoroo.andlib.sql.Functions; import com.todoroo.andlib.sql.Query; +import com.todoroo.andlib.utility.AndroidUtilities; import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.Preferences; import com.todoroo.astrid.api.AstridApiConstants; @@ -315,6 +316,19 @@ public class TaskDao extends DatabaseDao { Task.RECURRENCE }; + private static final String[] IGNORE_OUTSTANDING_COLUMNS = new String[] { + Task.MODIFICATION_DATE.name, + Task.DETAILS.name, + Task.DETAILS_DATE.name, + Task.CALENDAR_URI.name, + Task.UUID.name + }; + + @Override + protected boolean recordOutstandingEntry(String columnName) { + return AndroidUtilities.indexOf(IGNORE_OUTSTANDING_COLUMNS, columnName) < 0; + } + public void saveExistingWithSqlConstraintCheck(Task item) { try { saveExisting(item);