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.
text123/TaskList.java

521 lines
23 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类继承自Node类用于表示任务列表包含任务列表的各种属性和操作方法
public class TaskList extends Node {
// 用于日志记录的标签,方便在日志中定位该类相关的信息
private static final String TAG = TaskList.class.getSimpleName();
// 任务列表在某个集合中的索引
private int mIndex;
// 存储任务列表中的所有任务
private ArrayList<Task> mChildren;
// 无参构造函数用于创建一个新的TaskList对象
public TaskList() {
// 调用父类的无参构造函数,进行必要的初始化
super();
// 初始化任务列表中的任务集合
mChildren = new ArrayList<Task>();
// 初始化任务列表的索引为1
mIndex = 1;
}
// 获取用于创建任务列表的JSONObject的方法actionId用于标识操作ID
public JSONObject getCreateAction(int actionId) {
// 创建一个新的JSONObject对象用于存储创建任务列表的相关信息
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中可能用于在特定集合中定位该任务列表
// 创建一个JSONObject对象用于存储任务列表的实体变更信息
JSONObject entity = new JSONObject();
// 开始构建任务列表的实体信息,这些信息描述了任务列表本身的属性
// 设置任务列表的名称
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());
// 获取当前任务列表的名称并放入实体信息中,任务列表名称是一个重要标识
// 设置任务列表的创建者ID为"null"
entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null");
// 这里将创建者ID设置为"null",可能表示在当前逻辑中,创建者信息暂未明确或不重要
// 设置任务列表的类型为组类型
entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE,
GTaskStringUtils.GTASK_JSON_TYPE_GROUP);
// 明确任务列表的类型为组类型,这有助于在后续处理中正确识别和处理任务列表
// 将实体变更信息添加到创建任务列表的JSONObject中
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);
// 将包含任务列表详细信息的entity对象作为实体变更信息添加到js中
} catch (JSONException e) {
// 如果在创建JSONObject过程中发生JSON异常
Log.e(TAG, e.toString());
// 记录错误日志,包含异常信息,方便开发人员定位和解决问题
e.printStackTrace();
// 打印异常堆栈信息,提供更详细的错误信息,帮助开发人员了解异常发生的位置和原因
// 抛出自定义的ActionFailureException异常提示生成创建任务列表的JSONObject失败
throw new ActionFailureException("fail to generate tasklist-create jsonobject");
}
// 返回包含创建任务列表相关信息的JSONObject
return js;
}
// 获取用于更新任务列表的JSONObject的方法actionId用于标识操作ID
public JSONObject getUpdateAction(int actionId) {
// 创建一个新的JSONObject对象用于存储更新任务列表的相关信息
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());
// 将当前任务列表的全局唯一标识符Gid放入JSONObject中
// 使得接收方能够准确知道要更新的是哪个具体的任务列表
// 创建一个JSONObject对象用于存储任务列表的实体变更信息
JSONObject entity = new JSONObject();
// 构建用于描述任务列表更新内容的实体对象
// 设置任务列表的名称
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());
// 将任务列表的名称放入实体变更信息中,因为任务列表的名称可能会在更新中改变
// 设置任务列表是否被删除的标志
entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted());
// 将任务列表的删除状态添加到实体变更信息中,表明任务列表是否已被标记为删除
// 这对于更新操作中处理任务列表的删除情况非常重要
// 将实体变更信息添加到更新任务列表的JSONObject中
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);
// 将包含任务列表更新细节的entity对象作为实体变更部分添加到js中
// 完成更新任务列表所需信息的组装
} catch (JSONException e) {
// 如果在创建JSONObject过程中发生JSON异常
Log.e(TAG, e.toString());
// 记录详细的错误信息,方便开发人员定位问题所在
e.printStackTrace();
// 打印异常堆栈跟踪信息,帮助开发人员深入了解异常发生的具体过程和位置
// 抛出自定义的ActionFailureException异常提示生成更新任务列表的JSONObject失败
throw new ActionFailureException("fail to generate tasklist-update jsonobject");
}
// 返回包含更新任务列表相关信息的JSONObject
return js;
}
// 根据远程JSON数据设置任务列表内容的方法
public void setContentByRemoteJSON(JSONObject js) {
// 如果传入的JSONObject不为null
if (js!= null) {
try {
// 如果JSON数据中包含任务列表的ID
if (js.has(GTaskStringUtils.GTASK_JSON_ID)) {
// 设置任务列表的全局唯一标识符Gid
setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID));
}
// 通过这种方式将远程数据中的任务列表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) {
// 如果在解析JSON数据过程中发生JSON异常
Log.e(TAG, e.toString());
// 记录错误日志,包含异常信息,方便开发人员定位问题
e.printStackTrace();
// 打印异常堆栈信息,帮助开发人员了解异常发生的具体位置和原因
// 抛出自定义的ActionFailureException异常提示从JSONObject获取任务列表内容失败
throw new ActionFailureException("fail to get tasklist content from jsonobject");
}
}
}
// 根据本地JSON数据设置任务列表内容的方法
public void setContentByLocalJSON(JSONObject js) {
// 如果传入的JSONObject为null或者不包含GTaskStringUtils.META_HEAD_NOTE字段
if (js == null ||!js.has(GTaskStringUtils.META_HEAD_NOTE)) {
// 记录警告日志,提示没有可用信息
Log.w(TAG, "setContentByLocalJSON: nothing is avaiable");
} else {
try {
// 从传入的JSONObject中获取包含笔记信息的JSONObject
JSONObject folder = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
// 获取笔记类型
int type = folder.getInt(NoteColumns.TYPE);
// 如果笔记类型是普通文件夹类型
if (type == Notes.TYPE_FOLDER) {
// 从文件夹信息中获取摘要信息
String name = folder.getString(NoteColumns.SNIPPET);
// 设置任务列表的名称,添加特定前缀
setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + name);
}
// 如果笔记类型是系统文件夹类型
else if (type == Notes.TYPE_SYSTEM) {
// 获取文件夹的ID
long id = folder.getLong(NoteColumns.ID);
// 如果ID是根文件夹的ID
if (id == Notes.ID_ROOT_FOLDER) {
// 设置任务列表的名称,添加特定前缀和默认根文件夹名称
setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT);
}
// 如果ID是通话记录文件夹的ID
else if (id == Notes.ID_CALL_RECORD_FOLDER) {
// 设置任务列表的名称,添加特定前缀和通话记录文件夹名称
setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_CALL_NOTE);
}
// 如果是其他未知的系统文件夹ID
else {
// 记录错误日志,提示无效的系统文件夹
Log.e(TAG, "invalid system folder");
}
}
// 如果是其他不识别的类型
else {
// 记录错误日志,提示类型错误
Log.e(TAG, "error type");
}
} catch (JSONException e) {
// 如果在解析JSONObject过程中发生异常
Log.e(TAG, e.toString());
// 打印异常堆栈信息,方便调试
e.printStackTrace();
}
}
}
// 从任务列表内容生成本地JSON数据的方法
public JSONObject getLocalJSONFromContent() {
try {
// 创建一个新的JSONObject对象用于存储本地JSON数据
JSONObject js = new JSONObject();
// 创建一个新的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对象的SNIPPET字段
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);
}
// 将包含文件夹信息的folder对象放入js对象的META_HEAD_NOTE字段
js.put(GTaskStringUtils.META_HEAD_NOTE, folder);
// 返回生成的包含本地JSON数据的js对象
return js;
} catch (JSONException e) {
// 如果在创建JSONObject过程中发生异常
Log.e(TAG, e.toString());
// 打印异常堆栈信息,方便调试
e.printStackTrace();
// 返回null表示生成失败
return null;
}
}
p// 获取任务列表同步操作类型的方法,根据数据库游标和任务列表自身状态判断同步操作类型
public int getSyncAction(Cursor c) {
try {
// 如果本地修改标记为0说明没有本地更新
if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) {
// 如果数据库中的同步ID与任务列表的最后修改时间相同
if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {
// 说明本地和远程都没有更新,返回无需同步操作的类型
return SYNC_ACTION_NONE;
} else {
// 否则,说明远程有更新,需要将远程数据应用到本地,返回更新本地的同步操作类型
return SYNC_ACTION_UPDATE_LOCAL;
}
} else {
// 验证数据库中的GTask ID与任务列表的GTask ID是否匹配
if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) {
// 如果不匹配记录错误日志提示GTask ID不匹配
Log.e(TAG, "gtask id doesn't match");
// 返回表示同步操作出现错误的类型
return SYNC_ACTION_ERROR;
}
// 如果数据库中的同步ID与任务列表的最后修改时间相同
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;
}
// 获取任务列表中子任务数量的方法
public int getChildTaskCount() {
// 返回任务列表中存储的子任务的数量
return mChildren.size();
}
// 向任务列表中添加子任务的方法,不指定插入位置,将子任务添加到列表末尾
public boolean addChildTask(Task task) {
// 初始化返回值为false
boolean ret = false;
// 检查传入的任务是否为null并且任务列表中不包含该任务
if (task!= null &&!mChildren.contains(task)) {
// 将任务添加到任务列表中并将返回结果赋值给ret
ret = mChildren.add(task);
// 如果添加成功
if (ret) {
// 设置任务的前一个兄弟任务和所属的任务列表
// 如果任务列表为空则前一个兄弟任务为null否则为任务列表中最后一个任务
task.setPriorSibling(mChildren.isEmpty()? null : mChildren.get(mChildren.size() - 1));
// 设置任务所属的任务列表为当前任务列表
task.setParent(this);
}
}
// 返回添加操作的结果
return ret;
}
// 向任务列表中指定位置添加子任务的方法
public boolean addChildTask(Task task, int index) {
// 检查插入位置是否合法索引不能小于0且不能大于任务列表的大小
if (index < 0 || index > mChildren.size()) {
// 如果索引不合法记录错误日志并返回false
Log.e(TAG, "add child task: invalid index");
return false;
}
// 获取任务在任务列表中的位置
int pos = mChildren.indexOf(task);
// 检查传入的任务是否为null且任务列表中不包含该任务
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);
// 如果后一个任务不为null设置后一个任务的前一个兄弟任务为新插入的任务
if (afterTask!= null)
afterTask.setPriorSibling(task);
}
// 无论任务是否成功插入都返回true
// 这里返回true可能是因为方法设计上认为只要索引合法就算任务已存在也算操作成功
return true;
}
// 从任务列表中移除子任务的方法
public boolean removeChildTask(Task task) {
// 初始化返回值为false
boolean ret = false;
// 获取任务在任务列表中的位置
int index = mChildren.indexOf(task);
// 如果任务在任务列表中存在
if (index!= -1) {
// 从任务列表中移除该任务并将返回结果赋值给ret
ret = mChildren.remove(task);
// 如果移除成功
if (ret) {
// 重置被移除任务的前一个兄弟任务和所属的任务列表
task.setPriorSibling(null);
task.setParent(null);
// 更新任务列表中的任务关系
if (index!= mChildren.size()) {
// 设置移除任务位置后的任务的前一个兄弟任务
// 如果移除的是第一个任务则其后一个任务的前一个兄弟任务为null否则为移除任务的前一个任务
mChildren.get(index).setPriorSibling(index == 0? null : mChildren.get(index - 1));
}
}
}
// 返回移除操作的结果
return ret;
}
// 将子任务移动到任务列表中指定位置的方法
public boolean moveChildTask(Task task, int index) {
// 检查目标索引是否在合法范围内索引不能小于0且不能大于或等于任务列表的大小
if (index < 0 || index >= mChildren.size()) {
// 如果索引不合法记录错误日志并返回false
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;
}
// 如果任务当前位置与目标位置相同无需移动直接返回true
if (pos == index)
return true;
// 通过先移除任务,再在指定位置添加任务来实现移动
// 只有当移除和添加操作都成功时才返回true
return (removeChildTask(task) && addChildTask(task, index));
}
// 根据任务的全局唯一标识符Gid在任务列表中查找子任务的方法
public Task findChildTaskByGid(String gid) {
// 遍历任务列表中的所有子任务
for (int i = 0; i < mChildren.size(); i++) {
// 获取当前索引对应的子任务
Task t = mChildren.get(i);
// 如果当前子任务的Gid与传入的Gid相等
if (t.getGid().equals(gid)) {
// 返回找到的子任务
return t;
}
}
// 如果遍历完整个列表都没有找到匹配的子任务返回null
return null;
}
// 获取指定子任务在任务列表中的索引的方法
public int getChildTaskIndex(Task task) {
// 使用indexOf方法获取任务在任务列表中的索引位置
return mChildren.indexOf(task);
}
// 根据索引获取任务列表中对应子任务的方法
public Task getChildTaskByIndex(int index) {
// 检查索引是否在合法范围内索引不能小于0且不能大于或等于任务列表的大小
if (index < 0 || index >= mChildren.size()) {
// 如果索引不合法记录错误日志并返回null
Log.e(TAG, "getTaskByIndex: invalid index");
return null;
}
// 返回指定索引位置的子任务
return mChildren.get(index);
}
// 根据任务的全局唯一标识符Gid在任务列表中查找子任务的方法
// 该方法名称似乎有误应为getChildTaskByGid与已有功能重复
public Task getChilTaskByGid(String gid) {
// 遍历任务列表中的所有子任务
for (Task task : mChildren) {
// 如果当前子任务的Gid与传入的Gid相等
if (task.getGid().equals(gid))
// 返回找到的子任务
return task;
}
// 如果遍历完整个列表都没有找到匹配的子任务返回null
return null;
}
// 获取任务列表中所有子任务的方法
public ArrayList<Task> getChildTaskList() {
// 直接返回存储子任务的mChildren列表
return this.mChildren;
}
// 设置任务列表索引的方法
public void setIndex(int index) {
// 将任务列表的索引设置为传入的index值
this.mIndex = index;
}
// 获取任务列表索引的方法
public int getIndex() {
// 返回任务列表的索引值
return this.mIndex;
}}