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.
XiaoMiNotes/src/gtask/data/TaskList.java

446 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)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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;
/**
* TaskList 类 - 任务列表实体类
*
* 功能代表Google Tasks中的一个任务列表对应小米便签中的文件夹
* 继承自Node抽象类可以包含多个Task子任务实现任务列表的层级管理
* 处理文件夹与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; // 默认索引为1Google Tasks的索引从1开始
}
/**
* 获取创建任务列表的JSON操作数据用于发送到Google Tasks服务器
* @param actionId 操作ID
* @return 包含创建操作数据的JSONObject
* @throws ActionFailureException 生成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操作数据用于发送到Google Tasks服务器
* @param actionId 操作ID
* @return 包含更新操作数据的JSONObject
* @throws ActionFailureException 生成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数据设置任务列表内容从Google Tasks服务器获取
* @param js 包含远程列表数据的JSONObject
* @throws ActionFailureException 解析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 包含本地文件夹数据的JSONObject
*/
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) {
// 普通文件夹使用片段作为名称并添加MIUI前缀
String name = folder.getString(NoteColumns.SNIPPET);
setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + name);
} else if (folder.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) {
// 系统文件夹根据ID设置特定的名称
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 包含本地文件夹数据的JSONObject
*/
public JSONObject getLocalJSONFromContent() {
try {
JSONObject js = new JSONObject();
JSONObject folder = new JSONObject();
// 处理文件夹名称移除MIUI前缀
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); // 其他为普通文件夹
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_*
*/
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 Task 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 添加成功返回true失败返回false
*/
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 添加成功返回true失败返回false
*/
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 移除成功返回true失败返回false
*/
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 移动成功返回true失败返回false
*/
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 Task ID查找子任务
* @param gid Google Task的全局唯一标识
* @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 Task ID获取子任务方法名有拼写错误
* @param gid Google Task的全局唯一标识
* @return 找到的任务对象未找到返回null
*/
public Task getChilTaskByGid(String gid) {
for (Task task : mChildren) {
if (task.getGid().equals(gid))
return task;
}
return null;
}
/**
* 获取所有子任务的列表
* @return 子任务列表的ArrayList
*/
public ArrayList<Task> getChildTaskList() {
return this.mChildren;
}
/**
* 设置任务列表索引
* @param index 索引值
*/
public void setIndex(int index) {
this.mIndex = index;
}
/**
* 获取任务列表索引
* @return 索引值
*/
public int getIndex() {
return this.mIndex;
}
}