Fixed subtasks type parsing and conversion between local and remote trees. Should have the correct helpers now when we start syncing subtasks under sync v2

pull/14/head
Sam Bosley 13 years ago
parent 95af2428ef
commit ac0a1eda07

@ -15,6 +15,7 @@ import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.Autowired; import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService; import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.astrid.api.Filter; import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.service.TaskService; import com.todoroo.astrid.service.TaskService;
@ -34,12 +35,14 @@ public abstract class AstridOrderedListUpdater<LIST> {
public static class Node { public static class Node {
public long taskId; public long taskId;
public String uuid; // For parsing and syncing -- not used elsewhere
public Node parent; public Node parent;
public int indent; public int indent;
public final ArrayList<Node> children = new ArrayList<Node>(); public final ArrayList<Node> children = new ArrayList<Node>();
public Node(long taskId, Node parent, int indent) { public Node(long taskId, Node parent, int indent) {
this.taskId = taskId; this.taskId = taskId;
this.uuid = RemoteModel.NO_UUID;
this.parent = parent; this.parent = parent;
this.indent = indent; this.indent = indent;
} }
@ -364,28 +367,41 @@ public abstract class AstridOrderedListUpdater<LIST> {
} }
public static Node buildTreeModel(String serializedTree, JSONTreeModelBuilder callback) { public static Node buildTreeModel(String serializedTree, JSONTreeModelBuilder callback) {
return buildTreeModel(serializedTree, callback, false);
}
public static Node buildTreeModel(String serializedTree, JSONTreeModelBuilder callback, boolean useUuid) {
Node root = new Node(-1, null, -1); Node root = new Node(-1, null, -1);
try { try {
JSONArray tree = new JSONArray(serializedTree); JSONArray tree = new JSONArray(serializedTree);
recursivelyBuildChildren(root, tree, callback); recursivelyBuildChildren(root, tree, callback, useUuid);
} catch (JSONException e) { } catch (JSONException e) {
Log.e("OrderedListUpdater", "Error building tree model", e); //$NON-NLS-1$//$NON-NLS-2$ Log.e("OrderedListUpdater", "Error building tree model", e); //$NON-NLS-1$//$NON-NLS-2$
} }
return root; return root;
} }
private static void recursivelyBuildChildren(Node node, JSONArray children, JSONTreeModelBuilder callback) throws JSONException { private static void recursivelyBuildChildren(Node node, JSONArray children, JSONTreeModelBuilder callback, boolean useUuid) throws JSONException {
for (int i = 1; i < children.length(); i++) { for (int i = 1; i < children.length(); i++) {
JSONArray subarray = children.optJSONArray(i); JSONArray subarray = children.optJSONArray(i);
Long id; Long id = 0L;
if (subarray == null) String uuid = RemoteModel.NO_UUID;
id = children.getLong(i); if (!useUuid) {
else if (subarray == null)
id = subarray.getLong(0); id = children.getLong(i);
else
id = subarray.getLong(0);
} else {
if (subarray == null)
uuid = children.getString(i);
else
uuid = subarray.getString(0);
}
Node child = new Node(id, node, node.indent + 1); Node child = new Node(id, node, node.indent + 1);
if (useUuid)
child.uuid = uuid;
if (subarray != null) if (subarray != null)
recursivelyBuildChildren(child, subarray, callback); recursivelyBuildChildren(child, subarray, callback, useUuid);
node.children.add(child); node.children.add(child);
if (callback != null) if (callback != null)
callback.afterAddNode(child); callback.afterAddNode(child);
@ -393,30 +409,37 @@ public abstract class AstridOrderedListUpdater<LIST> {
} }
protected String serializeTree() { protected String serializeTree() {
return serializeTree(treeRoot); return serializeTree(treeRoot, false);
} }
public static String serializeTree(Node root) { public static String serializeTree(Node root) {
return serializeTree(root, false);
}
public static String serializeTree(Node root, boolean useUuid) {
JSONArray tree = new JSONArray(); JSONArray tree = new JSONArray();
if (root == null) { if (root == null) {
return tree.toString(); return tree.toString();
} }
try { try {
recursivelySerialize(root, tree); recursivelySerialize(root, tree, useUuid);
} catch (JSONException e) { } catch (JSONException e) {
Log.e("OrderedListUpdater", "Error serializing tree model", e); //$NON-NLS-1$//$NON-NLS-2$ Log.e("OrderedListUpdater", "Error serializing tree model", e); //$NON-NLS-1$//$NON-NLS-2$
} }
return tree.toString(); return tree.toString();
} }
private static void recursivelySerialize(Node node, JSONArray serializeTo) throws JSONException { private static void recursivelySerialize(Node node, JSONArray serializeTo, boolean useUuid) throws JSONException {
ArrayList<Node> children = node.children; ArrayList<Node> children = node.children;
serializeTo.put(node.taskId); if (useUuid)
serializeTo.put(node.uuid);
else
serializeTo.put(node.taskId);
for (Node child : children) { for (Node child : children) {
if (child.children.size() > 0) { if (child.children.size() > 0) {
JSONArray branch = new JSONArray(); JSONArray branch = new JSONArray();
recursivelySerialize(child, branch); recursivelySerialize(child, branch, useUuid);
serializeTo.put(branch); serializeTo.put(branch);
} else { } else {
serializeTo.put(child.taskId); serializeTo.put(child.taskId);

@ -7,6 +7,7 @@ import android.content.SharedPreferences;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.TodorooCursor; import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.ContextManager; import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.sql.Criterion; import com.todoroo.andlib.sql.Criterion;
@ -20,6 +21,7 @@ import com.todoroo.astrid.core.CustomFilterExposer;
import com.todoroo.astrid.core.PluginServices; import com.todoroo.astrid.core.PluginServices;
import com.todoroo.astrid.core.SortHelper; import com.todoroo.astrid.core.SortHelper;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria; import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.subtasks.AstridOrderedListUpdater.Node; import com.todoroo.astrid.subtasks.AstridOrderedListUpdater.Node;
@ -107,68 +109,87 @@ public class SubtasksHelper {
return ids.toArray(new Long[ids.size()]); return ids.toArray(new Long[ids.size()]);
} }
@SuppressWarnings("nls")
public static String[] getStringIdArray(String serializedTree) {
ArrayList<String> ids = new ArrayList<String>();
String[] values = serializedTree.split("[\\[\\],\\s]"); // Split on [ ] , or whitespace chars
for (String idString : values) {
if (!TextUtils.isEmpty(idString))
ids.add(idString);
}
return ids.toArray(new String[ids.size()]);
}
/**
* Takes a subtasks string containing local ids and remaps it to one containing UUIDs
* @param localTree
* @return
*/
public static String convertTreeToRemoteIds(String localTree) { public static String convertTreeToRemoteIds(String localTree) {
return convertIdTree(localTree, true); Long[] localIds = getIdArray(localTree);
HashMap<Long, String> idMap = getIdMap(localIds, Task.ID, Task.UUID);
idMap.put(-1L, "-1"); //$NON-NLS-1$
Node tree = AstridOrderedListUpdater.buildTreeModel(localTree, null);
remapLocalTreeToRemote(tree, idMap);
return AstridOrderedListUpdater.serializeTree(tree, true);
} }
public static String convertTreeToLocalIds(String remoteTree) { private static void remapLocalTreeToRemote(Node root, HashMap<Long, String> idMap) {
return convertIdTree(remoteTree, false); ArrayList<Node> children = root.children;
for (int i = 0; i < children.size(); i++) {
Node child = children.get(i);
String uuid = idMap.get(child.taskId);
if (!RemoteModel.isValidUuid(uuid)) {
children.remove(i);
children.addAll(i, child.children);
i--;
} else {
child.uuid = uuid;
remapLocalTreeToRemote(child, idMap);
}
}
} }
private static String convertIdTree(String treeString, boolean localToRemote) { /**
Long[] ids = getIdArray(treeString); * Takes a subtasks string containing UUIDs and remaps it to one containing local ids
HashMap<Long, Long> idMap = buildIdMap(ids, localToRemote); * @param remoteTree
idMap.put(-1L, -1L); * @return
*/
public static String convertTreeToLocalIds(String remoteTree) {
String[] uuids = getStringIdArray(remoteTree);
HashMap<String, Long> idMap = getIdMap(uuids, Task.UUID, Task.ID);
idMap.put("-1", -1L); //$NON-NLS-1$
Node tree = AstridOrderedListUpdater.buildTreeModel(treeString, null); Node tree = AstridOrderedListUpdater.buildTreeModel(remoteTree, null, true);
remapTree(tree, idMap); remapRemoteTreeToLocal(tree, idMap);
return AstridOrderedListUpdater.serializeTree(tree); return AstridOrderedListUpdater.serializeTree(tree);
} }
private static void remapTree(Node root, HashMap<Long, Long> idMap) { private static void remapRemoteTreeToLocal(Node root, HashMap<String, Long> idMap) {
ArrayList<Node> children = root.children; ArrayList<Node> children = root.children;
for (int i = 0; i < children.size(); i++) { for (int i = 0; i < children.size(); i++) {
Node child = children.get(i); Node child = children.get(i);
Long remoteId = idMap.get(child.taskId); Long localId = idMap.get(child.uuid);
if (remoteId == null || remoteId <= 0) { if (localId == null || localId <= 0) {
children.remove(i); children.remove(i);
children.addAll(i, child.children); children.addAll(i, child.children);
i--; i--;
} else { } else {
child.taskId = remoteId; child.taskId = localId;
remapTree(child, idMap); remapRemoteTreeToLocal(child, idMap);
} }
} }
} }
private static HashMap<Long, Long> buildIdMap(Long[] localIds, boolean localToRemote) { // If localToRemote is true, keys are local ids. If false. keys are remtoe ids private static <A, B> HashMap<A, B> getIdMap(A[] keys, Property<A> keyProperty, Property<B> valueProperty) {
HashMap<Long, Long> map = new HashMap<Long, Long>(); HashMap<A, B> map = new HashMap<A, B>();
Criterion criterion; TodorooCursor<Task> tasks = PluginServices.getTaskService().query(Query.select(keyProperty, valueProperty).where(keyProperty.in(keys)));
if (localToRemote)
criterion = Task.ID.in(localIds);
else
criterion = Task.UUID.in(localIds);
TodorooCursor<Task> tasks = PluginServices.getTaskService().query(Query.select(Task.ID, Task.UUID).where(criterion));
try { try {
Task t = new Task();
for (tasks.moveToFirst(); !tasks.isAfterLast(); tasks.moveToNext()) { for (tasks.moveToFirst(); !tasks.isAfterLast(); tasks.moveToNext()) {
t.clear(); A key = tasks.get(keyProperty);
t.readFromCursor(tasks); B value = tasks.get(valueProperty);
map.put(key, value);
if (t.containsNonNullValue(Task.UUID)) {
Long key;
Long value;
if (localToRemote) {
key = t.getId();
value = Long.parseLong(t.getValue(Task.UUID));
} else {
key = Long.parseLong(t.getValue(Task.UUID));
value = t.getId();
}
map.put(key, value);
}
} }
} finally { } finally {
tasks.close(); tasks.close();

@ -110,7 +110,7 @@ public class SubtasksMetadataMigration {
Node newNode = new Node(item.getValue(Metadata.TASK), parent, parent.indent + 1); Node newNode = new Node(item.getValue(Metadata.TASK), parent, parent.indent + 1);
parent.children.add(newNode); parent.children.add(newNode);
} }
return AstridOrderedListUpdater.serializeTree(root); return AstridOrderedListUpdater.serializeTree(root, false);
} }
private Node findNextParentForIndent(Node root, int indent) { private Node findNextParentForIndent(Node root, int indent) {

Loading…
Cancel
Save