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.
rass/gtask/data/Task.java

376 lines
19 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.text.TextUtils;
import android.util.Log;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.DataConstants;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.gtask.exception.ActionFailureException;
import net.micode.notes.tool.GTaskStringUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
// Task类继承自Node类代表一个任务相关的实体包含任务的各种属性以及与任务相关的操作方法
// 例如创建、更新任务的JSON表示从不同来源的JSON数据设置任务内容获取任务的本地JSON表示等功能。
public class Task extends Node {
// 用于在日志输出中标识该类的标签,取类的简单名称,方便在日志里区分该类相关的记录
private static final String TAG = Task.class.getSimpleName();
// 标记任务是否已完成初始化为false表示任务默认未完成可通过相应方法进行设置和获取
private boolean mCompleted;
// 存储任务的备注信息初始化为null可按需设置和获取
private String mNotes;
// 用于存储任务的元信息以JSONObject形式存在初始化为null可通过相关方法设置和获取
private JSONObject mMetaInfo;
// 指向当前任务的前一个兄弟任务在同一父任务下的顺序关系初始化为null可通过方法进行关联设置
private Task mPriorSibling;
// 指向当前任务的父任务是TaskList类型初始化为null可通过方法设置关联
private TaskList mParent;
// 默认构造函数调用父类的构造函数通过super()),并初始化任务相关的成员变量默认值
public Task() {
super();
mCompleted = false;
mNotes = null;
mPriorSibling = null;
mParent = null;
mMetaInfo = null;
}
// 生成用于创建任务的JSON对象的方法按照特定的格式和要求构建包含任务创建相关信息的JSON对象若JSON构建过程出现异常则抛出异常
public JSONObject getCreateAction(int actionId) {
JSONObject js = new JSONObject();
try {
// 设置action_type字段表示操作类型为创建任务对应的值从GTaskStringUtils中获取
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE);
// 设置action_id字段传入给定的actionId作为该创建操作的唯一标识符
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);
// 设置index字段通过调用父任务mParent的getChildTaskIndex方法获取当前任务在父任务中的索引位置
js.put(GTaskStringUtils.GTASK_JSON_INDEX, mParent.getChildTaskIndex(this));
// 构建表示任务实体信息的JSONObject包含任务的名称、创建者ID这里设为"null",可能需根据实际情况调整)、实体类型等关键信息
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_TASK);
// 如果任务有备注信息不为null则将备注信息添加到任务实体信息中
if (getNotes()!= null) {
entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes());
}
// 将包含任务实体信息的JSONObject添加到外层的js对象中对应键为GTaskStringUtils.GTASK_JSON_ENTITY_DELTA
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);
// 设置parent_id字段使用父任务mParent的唯一标识符通过getGid方法获取来指定父任务ID
js.put(GTaskStringUtils.GTASK_JSON_PARENT_ID, mParent.getGid());
// 设置dest_parent_type字段指定目标父类型这里设为组类型对应的值从GTaskStringUtils中获取
js.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT_TYPE,
GTaskStringUtils.GTASK_JSON_TYPE_GROUP);
// 设置list_id字段同样使用父任务的唯一标识符可能表示任务所属的列表ID具体含义取决于业务逻辑
js.put(GTaskStringUtils.GTASK_JSON_LIST_ID, mParent.getGid());
// 如果存在前一个兄弟任务mPriorSibling不为null设置prior_sibling_id字段使用兄弟任务的唯一标识符来指定顺序关系
if (mPriorSibling!= null) {
js.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, mPriorSibling.getGid());
}
} catch (JSONException e) {
// 如果在构建JSON对象过程中出现异常记录错误日志打印异常堆栈信息并抛出表示创建任务JSON对象失败的异常
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("fail to generate task-create jsonobject");
}
return js;
}
// 生成用于更新任务的JSON对象的方法按照特定格式构建包含任务更新相关信息的JSON对象若JSON构建出现异常则抛出异常
public JSONObject getUpdateAction(int actionId) {
JSONObject js = new JSONObject();
try {
// 设置action_type字段表示操作类型为更新任务对应的值从GTaskStringUtils中获取
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE);
// 设置action_id字段传入给定的actionId作为该更新操作的唯一标识符
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);
// 设置id字段使用任务自身的唯一标识符通过getGid方法获取来指定要更新的任务ID
js.put(GTaskStringUtils.GTASK_JSON_ID, getGid());
// 构建表示任务实体信息更新部分的JSONObject包含任务的名称、备注信息以及是否已删除等关键更新信息
JSONObject entity = new JSONObject();
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());
if (getNotes()!= null) {
entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes());
}
entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted());
// 将包含任务实体更新信息的JSONObject添加到外层的js对象中对应键为GTaskStringUtils.GTASK_JSON_ENTITY_DELTA
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);
} catch (JSONException e) {
// 如果在构建JSON对象过程中出现异常记录错误日志打印异常堆栈信息并抛出表示更新任务JSON对象失败的异常
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("fail to generate task-update jsonobject");
}
return js;
}
// 从远程传来的JSON对象中设置任务内容的方法根据JSON对象中包含的不同字段信息来更新任务的对应属性若JSON解析出现异常则抛出异常
public void setContentByRemoteJSON(JSONObject js) {
if (js!= null) {
try {
// 如果JSON对象中包含任务ID字段GTaskStringUtils.GTASK_JSON_ID则设置任务的唯一标识符通过setGid方法
if (js.has(GTaskStringUtils.GTASK_JSON_ID)) {
setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID));
}
// 如果JSON对象中包含最后修改时间字段GTaskStringUtils.GTASK_JSON_LAST_MODIFIED则设置任务的最后修改时间通过setLastModified方法
if (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) {
setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED));
}
// 如果JSON对象中包含任务名称字段GTaskStringUtils.GTASK_JSON_NAME则设置任务的名称通过setName方法
if (js.has(GTaskStringUtils.GTASK_JSON_NAME)) {
setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME));
}
// 如果JSON对象中包含任务备注字段GTaskStringUtils.GTASK_JSON_NOTES则设置任务的备注信息通过setNotes方法
if (js.has(GTaskStringUtils.GTASK_JSON_NOTES)) {
setNotes(js.getString(GTaskStringUtils.GTASK_JSON_NOTES));
}
// 如果JSON对象中包含任务是否已删除字段GTaskStringUtils.GTASK_JSON_DELETED则设置任务的删除状态通过setDeleted方法
if (js.has(GTaskStringUtils.GTASK_JSON_DELETED)) {
setDeleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_DELETED));
}
// 如果JSON对象中包含任务是否已完成字段GTaskStringUtils.GTASK_JSON_COMPLETED则设置任务的完成状态通过setCompleted方法
if (js.has(GTaskStringUtils.GTASK_JSON_COMPLETED)) {
setCompleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_COMPLETED));
}
} catch (JSONException e) {
// 如果在解析JSON对象设置任务内容过程中出现异常记录错误日志打印异常堆栈信息并抛出表示从JSON对象获取任务内容失败的异常
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("fail to get task content from jsonobject");
}
}
}
// 从本地的JSON对象中设置任务内容的方法根据本地JSON格式特点包含特定的头部信息等提取相关信息来设置任务名称若格式不符合要求会记录相应日志
public void setContentByLocalJSON(JSONObject js) {
if (js == null ||!js.has(GTaskStringUtils.META_HEAD_NOTE)
||!js.has(GTaskStringUtils.META_HEAD_DATA)) {
Log.w(TAG, "setContentByLocalJSON: nothing is avaiable");
}
try {
JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
if (note.getInt(NoteColumns.TYPE)!= Notes.TYPE_NOTE) {
Log.e(TAG, "invalid type");
return;
}
for (int i = 0; i < dataArray.length(); i++) {
JSONObject data = dataArray.getJSONObject(i);
if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) {
setName(data.getString(DataColumns.CONTENT));
break;
}
}
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
}
}
// 根据任务当前内容生成用于本地表示的JSON对象的方法根据任务是否有元信息mMetaInfo分情况构建不同结构的JSON对象若JSON构建出现异常则返回null
public JSONObject getLocalJSONFromContent() {
String name = getName();
try {
if (mMetaInfo == null) {
// 如果任务是新从网络创建的没有元信息并且任务名称为空记录警告日志并返回null
if (name == null) {
Log.w(TAG, "the note seems to be an empty one");
return null;
}
JSONObject js = new JSONObject();
JSONObject note = new JSONObject();
JSONArray dataArray = new JSONArray();
JSONObject data = new JSONObject();
data.put(DataColumns.CONTENT, name);
dataArray.put(data);
js.put(GTaskStringUtils.META_HEAD_DATA, dataArray);
note.put(NoteColumns.TYPE, Notes.TYPE_NOTE);
js.put(GTaskStringUtils.META_HEAD_NOTE, note);
return js;
} else {
// 如果任务是已同步过的有元信息则从元信息中提取相关内容更新任务名称对应的部分数据然后返回元信息作为本地JSON表示
JSONObject note = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
JSONArray dataArray = mMetaInfo.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
for (int i = 0; i < dataArray.length(); i++) {
JSONObject data = dataArray.getJSONObject(i);
if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) {
data.put(DataColumns.CONTENT, getName());
break;
}
}
note.put(NoteColumns.TYPE, Notes.TYPE_NOTE);
return mMetaInfo;
}
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
return null;
}
}
// 设置任务的元信息的方法根据传入的MetaData对象其中包含任务相关的笔记信息等来构建任务的元信息JSONObject若解析出现异常则将元信息设为null
public void setMetaInfo(MetaData metaData) {
if (metaData!= null && metaData.getNotes()!= null) {
try {
mMetaInfo = new JSONObject(metaData.getNotes());
} catch (JSONException e) {
Log.w(TAG, e.toString());
mMetaInfo = null;
}
}
}
// 根据数据库游标Cursor以及任务当前状态判断同步操作类型的方法通过比较数据库中的记录和任务的相关属性如ID、修改时间、Gtask ID等来确定需要执行的同步动作若出现异常则返回表示错误的同步动作类型
public int getSyncAction(Cursor c) {
try {
JSONObject noteInfo = null;
if (mMetaInfo!= null && mMetaInfo.has(GTaskStringUtils.META_HEAD_NOTE)) {
noteInfo = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
}
if (noteInfo == null) {
Log.w(TAG, "it seems that note meta has been deleted");
return SYNC_ACTION_UPDATE_REMOTE;
}
if (!noteInfo.has(NoteColumns.ID)) {
Log.w(TAG, "remote note id seems to be deleted");
return SYNC_ACTION_UPDATE_LOCAL;
}
// 验证数据库中的笔记ID与任务元信息中的笔记ID是否匹配不匹配则返回更新本地的同步动作类型
if (c.getLong(SqlNote.ID_COLUMN)!= noteInfo.getLong(NoteColumns.ID)) {
Log.w(TAG, "note id doesn't match");
return SYNC_ACTION_UPDATE_LOCAL;
}
if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) {
// 如果本地没有更新本地修改标记为0
if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {
// 两边都没有更新,返回无需同步的动作类型
return SYNC_ACTION_NONE;
} else {
// 应用远程数据到本地,返回更新本地的同步动作类型
return SYNC_ACTION_UPDATE_LOCAL;
}
} else {
// 验证Gtask 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_CONFLICT;
}
}
} catch (Exception e) {
Log.e(TAG, e.toString());
e.printStackTrace();
}
return SYNC_ACTION_ERROR;
}
// 判断任务是否值得保存的方法根据任务是否有元信息或者任务名称、备注信息是否非空去除空格后长度大于0来确定任务是否有保存的价值返回布尔值结果
public boolean isWorthSaving() {
return mMetaInfo!= null || (getName()!= null && getName().trim().length() > 0)
|| (getNotes()!= null && getNotes().trim().length() > 0);
}
// 设置任务完成状态的方法传入布尔值参数来更新任务的完成状态mCompleted成员变量
public void setCompleted(boolean completed) {
this.mCompleted = completed;
}
// 设置任务备注信息的方法传入字符串参数来更新任务的备注信息mNotes成员变量
public void setNotes(String notes) {
this.mNotes = notes;
}
// 设置任务前一个兄弟任务的方法传入Task类型的参数来更新任务的前一个兄弟任务关联mPriorSibling成员变量
public void setPriorSibling(Task priorSibling) {
this.mPriorSibling = priorSibling;
}
// 设置任务父任务的方法传入TaskList类型的参数来更新任务的父任务关联mParent成员变量
public void setParent(TaskList parent) {
this.mParent = parent;
}
// 获取任务完成状态的方法,返回任务
public boolean getCompleted() {
return this.mCompleted;
}
public String getNotes() {
return this.mNotes;
}
public Task getPriorSibling() {
return this.mPriorSibling;
}
public TaskList getParent() {
return this.mParent;
}
}