You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
MiNote/gtask/data/TaskList.java

445 lines
15 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* 遵循 Apache 许可证 2.0 版("许可证"
* 除非遵守许可证,否则不得使用此文件。
* 您可以在以下网址获取许可证副本:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 除非适用法律要求或书面同意,否则根据许可证分发的软件是按"原样"提供的,
* 不附带任何明示或暗示的保证或条件。请参阅许可证,了解管理权限和限制的具体语言。
*/
package net.micode.notes.gtask.data;
import android.database.Cursor;
import android.util.Log;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.gtask.exception.ActionFailureException;
import net.micode.notes.tool.GTaskStringUtils;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
/**
* 任务列表类(对应 Google Tasks 中的任务列表概念)
* 负责管理一组相关的任务,并与云端同步
*/
public class TaskList extends Node {
private static final String TAG = TaskList.class.getSimpleName();
private int mIndex; // 任务列表在同步队列中的索引位置
private ArrayList<Task> mChildren; // 子任务列表
/**
* 构造函数
*/
public TaskList() {
super(); // 调用父类构造函数
mChildren = new ArrayList<Task>(); // 初始化子任务列表
mIndex = 1; // 默认索引为 1
}
/**
* 生成创建任务列表的 JSON 操作对象
* @param actionId 操作 ID用于标识同步操作
* @return JSON 格式的创建操作
*/
public JSONObject getCreateAction(int actionId) {
JSONObject js = new JSONObject();
try {
// 设置操作类型为创建任务列表
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE);
// 设置操作 ID
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);
// 设置任务列表索引
js.put(GTaskStringUtils.GTASK_JSON_INDEX, mIndex);
// 设置实体变更内容
JSONObject entity = new JSONObject();
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); // 任务列表名称
entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null"); // 创建者 ID
entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE,
GTaskStringUtils.GTASK_JSON_TYPE_GROUP); // 实体类型为组
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("fail to generate tasklist-create jsonobject");
}
return js;
}
/**
* 生成更新任务列表的 JSON 操作对象
* @param actionId 操作 ID
* @return JSON 格式的更新操作
*/
public JSONObject getUpdateAction(int actionId) {
JSONObject js = new JSONObject();
try {
// 设置操作类型为更新任务列表
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE);
// 设置操作 ID
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);
// 设置任务列表 ID
js.put(GTaskStringUtils.GTASK_JSON_ID, getGid());
// 设置实体变更内容
JSONObject entity = new JSONObject();
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); // 任务列表名称
entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted()); // 是否删除
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("fail to generate tasklist-update jsonobject");
}
return js;
}
/**
* 从远程 JSON 数据设置任务列表内容(用于同步)
* @param js 包含任务列表数据的 JSON 对象
*/
public void setContentByRemoteJSON(JSONObject js) {
if (js != null) {
try {
// 设置任务列表 ID
if (js.has(GTaskStringUtils.GTASK_JSON_ID)) {
setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID));
}
// 设置最后修改时间
if (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) {
setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED));
}
// 设置任务列表名称
if (js.has(GTaskStringUtils.GTASK_JSON_NAME)) {
setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME));
}
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("fail to get tasklist content from jsonobject");
}
}
}
/**
* 从本地 JSON 数据设置任务列表内容
* @param js 包含本地便签数据的 JSON 对象
*/
public void setContentByLocalJSON(JSONObject js) {
if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)) {
Log.w(TAG, "setContentByLocalJSON: nothing is avaiable");
}
try {
JSONObject folder = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
if (folder.getInt(NoteColumns.TYPE) == Notes.TYPE_FOLDER) {
// 普通文件夹类型
String name = folder.getString(NoteColumns.SNIPPET);
// 添加小米便签前缀标识
setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + name);
} else if (folder.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) {
// 系统文件夹类型
if (folder.getLong(NoteColumns.ID) == Notes.ID_ROOT_FOLDER)
// 根文件夹命名
setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT);
else if (folder.getLong(NoteColumns.ID) == Notes.ID_CALL_RECORD_FOLDER)
// 通话记录文件夹命名
setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX
+ GTaskStringUtils.FOLDER_CALL_NOTE);
else
Log.e(TAG, "invalid system folder"); // 无效系统文件夹类型
} else {
Log.e(TAG, "error type"); // 错误类型
}
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
}
}
/**
* 将任务列表内容转换为本地 JSON 格式
* @return 本地 JSON 格式的任务列表数据
*/
public JSONObject getLocalJSONFromContent() {
try {
JSONObject js = new JSONObject();
JSONObject folder = new JSONObject();
// 处理任务列表名称(去除可能的前缀)
String folderName = getName();
if (getName().startsWith(GTaskStringUtils.MIUI_FOLDER_PREFFIX))
folderName = folderName.substring(GTaskStringUtils.MIUI_FOLDER_PREFFIX.length(),
folderName.length());
// 设置文件夹摘要(即任务列表名称)
folder.put(NoteColumns.SNIPPET, folderName);
// 根据名称判断文件夹类型(系统文件夹或普通文件夹)
if (folderName.equals(GTaskStringUtils.FOLDER_DEFAULT)
|| folderName.equals(GTaskStringUtils.FOLDER_CALL_NOTE))
folder.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
else
folder.put(NoteColumns.TYPE, Notes.TYPE_FOLDER);
// 将文件夹数据放入主 JSON 对象
js.put(GTaskStringUtils.META_HEAD_NOTE, folder);
return js;
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
return null;
}
}
/**
* 判断同步操作类型(本地与远程数据对比)
* @param c 包含本地数据的 Cursor
* @return 同步操作类型SYNC_ACTION_NONE-无操作SYNC_ACTION_UPDATE_LOCAL-更新本地SYNC_ACTION_UPDATE_REMOTE-更新远程)
*/
public int getSyncAction(Cursor c) {
try {
if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) {
// 本地没有修改
if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {
// 本地和远程都没有更新
return SYNC_ACTION_NONE;
} else {
// 应用远程数据到本地
return SYNC_ACTION_UPDATE_LOCAL;
}
} else {
// 本地有修改
// 验证 Google Tasks ID 是否匹配
if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) {
Log.e(TAG, "gtask id doesn't match");
return SYNC_ACTION_ERROR;
}
if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {
// 只有本地修改
return SYNC_ACTION_UPDATE_REMOTE;
} else {
// 文件夹冲突时,默认应用本地修改
return SYNC_ACTION_UPDATE_REMOTE;
}
}
} catch (Exception e) {
Log.e(TAG, e.toString());
e.printStackTrace();
}
return SYNC_ACTION_ERROR;
}
/**
* 获取子任务数量
* @return 子任务数量
*/
public int getChildTaskCount() {
return mChildren.size();
}
/**
* 添加子任务到任务列表末尾
* @param task 要添加的任务
* @return 是否添加成功
*/
public boolean addChildTask(Task task) {
boolean ret = false;
if (task != null && !mChildren.contains(task)) {
ret = mChildren.add(task);
if (ret) {
// 设置任务的前置兄弟任务和父任务列表
task.setPriorSibling(mChildren.isEmpty() ? null : mChildren
.get(mChildren.size() - 1));
task.setParent(this);
}
}
return ret;
}
/**
* 在指定位置添加子任务
* @param task 要添加的任务
* @param index 指定位置索引
* @return 是否添加成功
*/
public boolean addChildTask(Task task, int index) {
if (index < 0 || index > mChildren.size()) {
Log.e(TAG, "add child task: invalid index");
return false;
}
int pos = mChildren.indexOf(task);
if (task != null && pos == -1) {
mChildren.add(index, task);
// 更新任务列表中的前置兄弟关系
Task preTask = null;
Task afterTask = null;
if (index != 0)
preTask = mChildren.get(index - 1);
if (index != mChildren.size() - 1)
afterTask = mChildren.get(index + 1);
task.setPriorSibling(preTask);
if (afterTask != null)
afterTask.setPriorSibling(task);
}
return true;
}
/**
* 移除子任务
* @param task 要移除的任务
* @return 是否移除成功
*/
public boolean removeChildTask(Task task) {
boolean ret = false;
int index = mChildren.indexOf(task);
if (index != -1) {
ret = mChildren.remove(task);
if (ret) {
// 重置任务的前置兄弟和父任务列表
task.setPriorSibling(null);
task.setParent(null);
// 更新任务列表中的前置兄弟关系
if (index != mChildren.size()) {
mChildren.get(index).setPriorSibling(
index == 0 ? null : mChildren.get(index - 1));
}
}
}
return ret;
}
/**
* 移动子任务到指定位置
* @param task 要移动的任务
* @param index 目标位置索引
* @return 是否移动成功
*/
public boolean moveChildTask(Task task, int index) {
if (index < 0 || index >= mChildren.size()) {
Log.e(TAG, "move child task: invalid index");
return false;
}
int pos = mChildren.indexOf(task);
if (pos == -1) {
Log.e(TAG, "move child task: the task should in the list");
return false;
}
if (pos == index)
return true;
// 先移除再添加实现移动
return (removeChildTask(task) && addChildTask(task, index));
}
/**
* 根据 Google Tasks ID 查找子任务
* @param gid 任务的 Google Tasks ID
* @return 找到的任务,未找到则返回 null
*/
public Task findChildTaskByGid(String gid) {
for (int i = 0; i < mChildren.size(); i++) {
Task t = mChildren.get(i);
if (t.getGid().equals(gid)) {
return t;
}
}
return null;
}
/**
* 获取子任务在列表中的索引位置
* @param task 要查找的任务
* @return 任务的索引位置,未找到返回 -1
*/
public int getChildTaskIndex(Task task) {
return mChildren.indexOf(task);
}
/**
* 根据索引获取子任务
* @param index 索引位置
* @return 指定位置的任务,索引无效则返回 null
*/
public Task getChildTaskByIndex(int index) {
if (index < 0 || index >= mChildren.size()) {
Log.e(TAG, "getTaskByIndex: invalid index");
return null;
}
return mChildren.get(index);
}
/**
* 根据 Google Tasks ID 获取子任务
* @param gid 任务的 Google Tasks ID
* @return 找到的任务,未找到则返回 null
*/
public Task getChilTaskByGid(String gid) {
for (Task task : mChildren) {
if (task.getGid().equals(gid))
return task;
}
return null;
}
/**
* 获取所有子任务列表
* @return 子任务列表
*/
public ArrayList<Task> getChildTaskList() {
return this.mChildren;
}
/**
* 设置任务列表在同步队列中的索引
* @param index 索引值
*/
public void setIndex(int index) {
this.mIndex = index;
}
/**
* 获取任务列表在同步队列中的索引
* @return 索引值
*/
public int getIndex() {
return this.mIndex;
}
}