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.
abc/src/Date/TaskList.java

436 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.

/*
* 版权所有 (c) 2010-2011MiCode 开源社区 (www.micode.net)
* 根据 Apache 许可证 2.0 版本("许可证")授权;
* 除非符合许可证的规定,否则不得使用本文件。
* 您可以从以下网址获取许可证副本:
* http://www.apache.org/licenses/LICENSE-2.0
* 除非适用法律要求或书面同意,本软件按"原样"分发,
* 没有任何明示或暗示的保证或条件。
* 详见许可证中规定的权限和限制。
* 这是一份标准的Apache许可证2.0版本的开源声明)
*/
// 声明当前类所在的包路径属于笔记应用的Google任务数据模块
package net.micode.notes.gtask.data;
// 导入Android数据库相关类
import android.database.Cursor; // 用于操作和遍历数据库查询结果集
import android.util.Log; // Android日志工具类
// 导入笔记应用的核心数据类
import net.micode.notes.data.Notes; // 笔记数据常量类
import net.micode.notes.data.Notes.NoteColumns; // 笔记表列名常量
// 导入异常处理类
import net.micode.notes.gtask.exception.ActionFailureException;
// 当Google任务操作失败时抛出的自定义异常
// 导入Google任务字符串处理工具类
import net.micode.notes.tool.GTaskStringUtils;
// 包含Google任务API使用的JSON键名常量
// 导入JSON处理相关类
import org.json.JSONException; // JSON解析异常类
import org.json.JSONObject; // JSON对象操作类
// 导入Java工具类
import java.util.ArrayList; // 动态数组集合
import java.util.Objects; // 对象操作工具类(判空等)
// 继承自Node基类表示Google Tasks中的任务列表
public class TaskList extends Node {
// 日志标签,使用类名作为标识
private static final String TAG = TaskList.class.getSimpleName();
// 任务列表的排序索引
private int mIndex;
// 存储子任务的动态数组
private final ArrayList<Task> mChildren;
// 构造函数
public TaskList() {
super(); // 调用父类Node的构造函数
mChildren = new ArrayList<>(); // 初始化子任务列表
mIndex = 1; // 默认索引从1开始
}
/**
* 生成创建任务列表的JSON动作
* @param actionId 动作ID用于标识操作序列
* @return 包含创建命令的JSON对象
* @throws ActionFailureException 当JSON操作失败时抛出
*/
public JSONObject getCreateAction(int actionId) {
JSONObject js = new JSONObject();
try {
// 设置动作类型为"create"
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); // 实体类型设为"group"
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); // 添加实体数据
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("生成任务列表创建JSON失败");
}
return js;
}
/**
* 生成更新任务列表的JSON动作
* @param actionId 动作ID
* @return 包含更新命令的JSON对象
*/
public JSONObject getUpdateAction(int actionId) {
JSONObject js = new JSONObject();
try {
// 设置动作类型为"update"
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("生成任务列表更新JSON失败");
}
return js;
}
/**
* 从远程JSON数据设置任务列表内容
* @param js 包含远程数据的JSON对象
* @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("从JSON解析任务列表内容失败");
}
}
}
/**
* 从本地JSON数据设置任务列表内容
* @param js 包含本地数据的JSON对象
*/
public void setContentByLocalJSON(JSONObject js) {
// 检查数据有效性
if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)) {
Log.w(TAG, "setContentByLocalJSON: 无可用数据");
return;
}
try {
JSONObject folder = Objects.requireNonNull(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); // 添加MIUI前缀
}
// 处理系统文件夹类型
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, "无效的系统文件夹");
}
} else {
Log.e(TAG, "错误的类型");
}
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
}
}
/**
* 从任务列表内容生成本地JSON格式
* @return 包含任务列表数据的JSON对象失败返回null
*/
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());
}
// 设置文件夹基本属性
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 {
// 有本地修改时验证任务ID
if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) {
Log.e(TAG, "任务ID不匹配");
return SYNC_ACTION_ERROR;
}
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.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, "添加子任务:无效的索引");
return false;
}
// 检查任务是否已存在
int pos = mChildren.indexOf(task);
if (task != null && pos == -1) {
mChildren.add(index, task);
// 更新任务链关系
Task preTask = (index != 0) ? mChildren.get(index - 1) : null;
Task afterTask = (index != mChildren.size() - 1) ? mChildren.get(index + 1) : null;
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, "移动子任务:无效的索引");
return false;
}
int pos = mChildren.indexOf(task);
if (pos == -1) {
Log.e(TAG, "移动子任务:任务不在列表中");
return false;
}
if (pos == index) {
return true; // 位置未改变
}
// 先移除再添加实现移动
return (removeChildTask(task) && addChildTask(task, index));
}
// 以下是查询方法
/**
* 通过GID查找子任务
* @param gid 要查找的任务全局ID
* @return 找到的任务对象未找到返回null
*/
public Task findChildTaskByGid(String gid) {
for (Task t : mChildren) {
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: 无效的索引");
return null;
}
return mChildren.get(index);
}
/**
* 通过GID获取子任务别名方法
* @param gid 要查找的任务全局ID
* @return 找到的任务对象未找到返回null
*/
public Task getChilTaskByGid(String gid) {
return findChildTaskByGid(gid);
}
/**
* 获取所有子任务列表
* @return 子任务ArrayList注意返回的是引用
*/
public ArrayList<Task> getChildTaskList() {
return this.mChildren;
}
// 以下是索引属性的getter/setter
/**
* 设置任务列表索引
* @param index 新的索引值
*/
public void setIndex(int index) {
this.mIndex = index;
}
/**
* 获取当前索引
* @return 当前索引值
*/
public int getIndex() {
return this.mIndex;
}
}