|
|
|
@ -1,8 +1,6 @@
|
|
|
|
|
package com.todoroo.astrid.gtasks;
|
|
|
|
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.Stack;
|
|
|
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
|
|
|
import java.util.concurrent.atomic.AtomicLong;
|
|
|
|
|
|
|
|
|
@ -25,6 +23,7 @@ public class GtasksTaskListUpdater {
|
|
|
|
|
|
|
|
|
|
final HashMap<Long, Long> parents = new HashMap<Long, Long>();
|
|
|
|
|
final HashMap<Long, Long> siblings = new HashMap<Long, Long>();
|
|
|
|
|
|
|
|
|
|
final HashMap<Long, String> localToRemoteIdMap =
|
|
|
|
|
new HashMap<Long, String>();
|
|
|
|
|
|
|
|
|
@ -32,54 +31,113 @@ public class GtasksTaskListUpdater {
|
|
|
|
|
DependencyInjectionService.getInstance().inject(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- used during normal ui operations
|
|
|
|
|
|
|
|
|
|
public void debugPrint(String listId) {
|
|
|
|
|
StoreObject list = gtasksListService.getList(listId);
|
|
|
|
|
if(list == GtasksListService.LIST_NOT_FOUND_OBJECT)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
iterateThroughList(list, new ListIterator() {
|
|
|
|
|
public void processTask(long taskId, Metadata metadata) {
|
|
|
|
|
System.err.format("%d: indent:%d, parent:%d\n", taskId, //$NON-NLS-1$
|
|
|
|
|
metadata.getValue(GtasksMetadata.INDENT),
|
|
|
|
|
metadata.getValue(GtasksMetadata.PARENT_TASK));
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Indent a task and all its children
|
|
|
|
|
*/
|
|
|
|
|
public void indent(String listId, final long targetTaskId, final int delta) {
|
|
|
|
|
StoreObject list = gtasksListService.getList(listId);
|
|
|
|
|
if(list == GtasksListService.LIST_NOT_FOUND_OBJECT)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
updateParentSiblingMapsFor(list);
|
|
|
|
|
|
|
|
|
|
final AtomicInteger targetTaskIndent = new AtomicInteger(-1);
|
|
|
|
|
final AtomicInteger previousIndent = new AtomicInteger(-1);
|
|
|
|
|
final AtomicLong previousTask = new AtomicLong(-1);
|
|
|
|
|
|
|
|
|
|
iterateThroughList(list, new ListIterator() {
|
|
|
|
|
@Override
|
|
|
|
|
public void processTask(long taskId, Metadata metadata) {
|
|
|
|
|
int indent = metadata.getValue(GtasksMetadata.INDENT);
|
|
|
|
|
|
|
|
|
|
if(targetTaskId == taskId) {
|
|
|
|
|
// if indenting is warranted, indent me and my children
|
|
|
|
|
if(indent + delta <= previousIndent.get() + 1 && indent + delta >= 0) {
|
|
|
|
|
targetTaskIndent.set(indent);
|
|
|
|
|
metadata.setValue(GtasksMetadata.INDENT, indent + delta);
|
|
|
|
|
if(delta > 0)
|
|
|
|
|
metadata.setValue(GtasksMetadata.PARENT_TASK, previousTask.get());
|
|
|
|
|
else if(parents.containsKey(taskId))
|
|
|
|
|
metadata.setValue(GtasksMetadata.PARENT_TASK,
|
|
|
|
|
parents.get(parents.get(taskId)));
|
|
|
|
|
else
|
|
|
|
|
metadata.setValue(GtasksMetadata.PARENT_TASK, Task.NO_ID);
|
|
|
|
|
PluginServices.getMetadataService().save(metadata);
|
|
|
|
|
}
|
|
|
|
|
} else if(targetTaskIndent.get() > -1) {
|
|
|
|
|
// found first task that is not beneath target
|
|
|
|
|
if(indent <= targetTaskIndent.get())
|
|
|
|
|
targetTaskIndent.set(-1);
|
|
|
|
|
else {
|
|
|
|
|
metadata.setValue(GtasksMetadata.INDENT, indent + delta);
|
|
|
|
|
PluginServices.getMetadataService().save(metadata);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
previousIndent.set(indent);
|
|
|
|
|
previousTask.set(taskId);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- used during synchronization
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Update order, parent, and indentation fields for all tasks in all lists
|
|
|
|
|
*/
|
|
|
|
|
public void updateAllMetadata() {
|
|
|
|
|
for(StoreObject list : gtasksListService.getLists()) {
|
|
|
|
|
correctMetadataForList(list.getValue(GtasksList.REMOTE_ID));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Update order and parent fields for all tasks in the given list
|
|
|
|
|
* Update order, parent, and indentation fields for all tasks in the given list
|
|
|
|
|
* @param listId
|
|
|
|
|
*/
|
|
|
|
|
public void updateMetadataForList(String listId) {
|
|
|
|
|
public void correctMetadataForList(String listId) {
|
|
|
|
|
StoreObject list = gtasksListService.getList(listId);
|
|
|
|
|
if(list == GtasksListService.LIST_NOT_FOUND_OBJECT)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
final ArrayList<Long> ids = new ArrayList<Long>();
|
|
|
|
|
final Stack<Long> taskHierarchyStack = new Stack<Long>();
|
|
|
|
|
updateParentSiblingMapsFor(list);
|
|
|
|
|
|
|
|
|
|
final AtomicInteger order = new AtomicInteger(0);
|
|
|
|
|
final AtomicInteger previousIndent = new AtomicInteger(-1);
|
|
|
|
|
|
|
|
|
|
iterateThroughList(list, new ListIterator() {
|
|
|
|
|
@Override
|
|
|
|
|
public void processTask(long taskId) {
|
|
|
|
|
ids.add(taskId);
|
|
|
|
|
Metadata metadata = gtasksMetadataService.getTaskMetadata(taskId);
|
|
|
|
|
if(metadata == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
public void processTask(long taskId, Metadata metadata) {
|
|
|
|
|
metadata.setValue(GtasksMetadata.ORDER, order.getAndAdd(1));
|
|
|
|
|
int indent = metadata.getValue(GtasksMetadata.INDENT);
|
|
|
|
|
if(indent > previousIndent.get() + 1)
|
|
|
|
|
indent = previousIndent.get() + 1;
|
|
|
|
|
metadata.setValue(GtasksMetadata.INDENT, indent);
|
|
|
|
|
|
|
|
|
|
for(int i = indent; i <= previousIndent.get(); i++) {
|
|
|
|
|
if(!taskHierarchyStack.isEmpty())
|
|
|
|
|
taskHierarchyStack.pop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(indent > 0) {
|
|
|
|
|
if(taskHierarchyStack.isEmpty()) {
|
|
|
|
|
metadata.setValue(GtasksMetadata.PARENT_TASK, 0L);
|
|
|
|
|
metadata.setValue(GtasksMetadata.INDENT, 0);
|
|
|
|
|
} else
|
|
|
|
|
metadata.setValue(GtasksMetadata.PARENT_TASK, taskHierarchyStack.peek());
|
|
|
|
|
} else {
|
|
|
|
|
metadata.setValue(GtasksMetadata.PARENT_TASK, 0L);
|
|
|
|
|
}
|
|
|
|
|
long parent = parents.get(taskId);
|
|
|
|
|
metadata.setValue(GtasksMetadata.PARENT_TASK, parent);
|
|
|
|
|
|
|
|
|
|
PluginServices.getMetadataService().save(metadata);
|
|
|
|
|
taskHierarchyStack.push(taskId);
|
|
|
|
|
previousIndent.set(indent);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
PluginServices.getTaskService().clearDetails(Task.ID.in(ids.toArray(new Long[ids.size()])));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -87,44 +145,50 @@ public class GtasksTaskListUpdater {
|
|
|
|
|
*/
|
|
|
|
|
public void createParentSiblingMaps() {
|
|
|
|
|
for(StoreObject list : gtasksListService.getLists()) {
|
|
|
|
|
final AtomicLong previousTask = new AtomicLong(-1L);
|
|
|
|
|
final AtomicInteger previousIndent = new AtomicInteger(-1);
|
|
|
|
|
|
|
|
|
|
iterateThroughList(list, new ListIterator() {
|
|
|
|
|
@Override
|
|
|
|
|
public void processTask(long taskId) {
|
|
|
|
|
Metadata metadata = gtasksMetadataService.getTaskMetadata(taskId);
|
|
|
|
|
if(metadata == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
int indent = metadata.getValue(GtasksMetadata.INDENT);
|
|
|
|
|
|
|
|
|
|
long parent, sibling;
|
|
|
|
|
if(indent > previousIndent.get()) {
|
|
|
|
|
parent = previousTask.get();
|
|
|
|
|
sibling = -1L;
|
|
|
|
|
} else if(indent == previousIndent.get()) {
|
|
|
|
|
sibling = previousTask.get();
|
|
|
|
|
parent = parents.get(sibling);
|
|
|
|
|
} else {
|
|
|
|
|
// move up once for each indent
|
|
|
|
|
sibling = previousTask.get();
|
|
|
|
|
for(int i = indent; i < previousIndent.get(); i++)
|
|
|
|
|
sibling = parents.get(sibling);
|
|
|
|
|
parent = parents.get(sibling);
|
|
|
|
|
}
|
|
|
|
|
parents.put(taskId, parent);
|
|
|
|
|
siblings.put(taskId, sibling);
|
|
|
|
|
updateParentSiblingMapsFor(list);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
previousTask.set(taskId);
|
|
|
|
|
previousIndent.set(indent);
|
|
|
|
|
if(!TextUtils.isEmpty(metadata.getValue(GtasksMetadata.ID)))
|
|
|
|
|
localToRemoteIdMap.put(taskId, metadata.getValue(GtasksMetadata.ID));
|
|
|
|
|
private void updateParentSiblingMapsFor(StoreObject list) {
|
|
|
|
|
final AtomicLong previousTask = new AtomicLong(-1L);
|
|
|
|
|
final AtomicInteger previousIndent = new AtomicInteger(-1);
|
|
|
|
|
|
|
|
|
|
iterateThroughList(list, new ListIterator() {
|
|
|
|
|
@Override
|
|
|
|
|
public void processTask(long taskId, Metadata metadata) {
|
|
|
|
|
int indent = metadata.getValue(GtasksMetadata.INDENT);
|
|
|
|
|
|
|
|
|
|
long parent, sibling;
|
|
|
|
|
if(indent > previousIndent.get()) {
|
|
|
|
|
parent = previousTask.get();
|
|
|
|
|
sibling = -1L;
|
|
|
|
|
} else if(indent == previousIndent.get()) {
|
|
|
|
|
sibling = previousTask.get();
|
|
|
|
|
parent = parents.get(sibling);
|
|
|
|
|
} else {
|
|
|
|
|
// move up once for each indent
|
|
|
|
|
sibling = previousTask.get();
|
|
|
|
|
for(int i = indent; i < previousIndent.get(); i++)
|
|
|
|
|
sibling = parents.get(sibling);
|
|
|
|
|
parent = parents.get(sibling);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
parents.put(taskId, parent);
|
|
|
|
|
siblings.put(taskId, sibling);
|
|
|
|
|
|
|
|
|
|
previousTask.set(taskId);
|
|
|
|
|
previousIndent.set(indent);
|
|
|
|
|
if(!TextUtils.isEmpty(metadata.getValue(GtasksMetadata.ID)))
|
|
|
|
|
localToRemoteIdMap.put(taskId, metadata.getValue(GtasksMetadata.ID));
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Must be called after creating parent and sibling maps. Updates a
|
|
|
|
|
* task container's parent and sibling fields.
|
|
|
|
|
*
|
|
|
|
|
* @param container
|
|
|
|
|
*/
|
|
|
|
|
public void updateParentAndSibling(GtasksTaskContainer container) {
|
|
|
|
|
long taskId = container.task.getId();
|
|
|
|
|
if(parents.containsKey(taskId)) {
|
|
|
|
@ -146,7 +210,7 @@ public class GtasksTaskListUpdater {
|
|
|
|
|
// --- private helpers
|
|
|
|
|
|
|
|
|
|
private interface ListIterator {
|
|
|
|
|
public void processTask(long taskId);
|
|
|
|
|
public void processTask(long taskId, Metadata metadata);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void iterateThroughList(StoreObject list, ListIterator iterator) {
|
|
|
|
@ -155,12 +219,16 @@ public class GtasksTaskListUpdater {
|
|
|
|
|
try {
|
|
|
|
|
for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
|
|
|
|
|
long taskId = cursor.getLong(0);
|
|
|
|
|
iterator.processTask(taskId);
|
|
|
|
|
Metadata metadata = gtasksMetadataService.getTaskMetadata(taskId);
|
|
|
|
|
if(metadata == null)
|
|
|
|
|
continue;
|
|
|
|
|
iterator.processTask(taskId, metadata);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} finally {
|
|
|
|
|
cursor.close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|