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.
qw1-notes/java/net/micode/notes/gtask/data/TaskList.java

443 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中的一个任务列表
* 负责管理任务列表的创建、更新、同步等操作
* 维护任务列表中的子任务集合及其顺序
*/
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;
}
/**
* 生成创建任务列表的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");
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 {
// 从JSON中提取任务列表ID
if (js.has(GTaskStringUtils.GTASK_JSON_ID)) {
setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID));
}
// 从JSON中提取任务列表最后修改时间
if (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) {
setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED));
}
// 从JSON中提取任务列表名称
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);
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 同步操作类型(无操作、更新本地、更新远程等)
*/
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 {
// 本地有修改
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));
}
/**
* 根据GID查找子任务
* @param gid 任务的GID
* @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);
}
/**
* 根据GID获取子任务
* @param gid 任务的GID
* @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;
}
}