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.

235 lines
10 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;
public class Task extends Node {
private static final String TAG = Task.class.getSimpleName();
private boolean mCompleted; // 任务完成状态
private String mNotes; // 任务备注
private JSONObject mMetaInfo; // 元数据存储本地笔记与GTask的映射
private Task mPriorSibling; // 前一个兄弟任务(用于排序)
private TaskList mParent; // 所属任务列表
// 构造函数:初始化任务属性
public Task() {
super();
mCompleted = false;
mNotes = null;
mPriorSibling = null;
mParent = null;
mMetaInfo = null;
}
// 生成创建任务的JSON请求
public JSONObject getCreateAction(int actionId) {
JSONObject js = new JSONObject();
try {
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, "create"); // 动作类型
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); // 动作ID
js.put(GTaskStringUtils.GTASK_JSON_INDEX, mParent.getChildTaskIndex(this)); // 排序索引
// 任务实体数据
JSONObject entity = new JSONObject();
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); // 任务名称
entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE, "task"); // 实体类型
if (getNotes() != null) entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes());
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);
// 父任务列表信息
js.put(GTaskStringUtils.GTASK_JSON_PARENT_ID, mParent.getGid());
js.put(GTaskStringUtils.GTASK_JSON_LIST_ID, mParent.getGid());
// 前一个兄弟任务ID用于排序
if (mPriorSibling != null) {
js.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, mPriorSibling.getGid());
}
} catch (JSONException e) {
throw new ActionFailureException("生成创建任务JSON失败");
}
return js;
}
// 生成更新任务的JSON请求
public JSONObject getUpdateAction(int actionId) {
JSONObject js = new JSONObject();
try {
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, "update"); // 动作类型
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); // 动作ID
js.put(GTaskStringUtils.GTASK_JSON_ID, getGid()); // 任务ID
// 任务实体数据(仅更新变更字段)
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()); // 删除状态
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);
} catch (JSONException e) {
throw new ActionFailureException("生成更新任务JSON失败");
}
return js;
}
// 从远程JSONGTask数据设置任务内容
public void setContentByRemoteJSON(JSONObject js) {
if (js != null) {
try {
setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID)); // 设置GTask ID
setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)); // 最后修改时间
setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME)); // 任务名称
setNotes(js.getString(GTaskStringUtils.GTASK_JSON_NOTES)); // 任务备注
setDeleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_DELETED)); // 删除状态
setCompleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_COMPLETED)); // 完成状态
} catch (JSONException e) {
throw new ActionFailureException("解析远程JSON失败");
}
}
}
// 从本地JSON笔记数据设置任务内容
public void setContentByLocalJSON(JSONObject js) {
if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)) return;
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) return;
// 从数据列表中获取笔记内容作为任务名称
for (int i = 0; i < dataArray.length(); i++) {
JSONObject data = dataArray.getJSONObject(i);
if (data.getString(DataColumns.MIME_TYPE).equals(DataConstants.NOTE)) {
setName(data.getString(DataColumns.CONTENT));
break;
}
}
} catch (JSONException e) {
Log.e(TAG, "解析本地JSON失败", e);
}
}
// 从任务内容生成本地JSON用于存储到本地数据库
public JSONObject getLocalJSONFromContent() {
String name = getName();
try {
if (mMetaInfo == 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 {
// 已同步任务(更新元数据)
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 (data.getString(DataColumns.MIME_TYPE).equals(DataConstants.NOTE)) {
data.put(DataColumns.CONTENT, name);
break;
}
}
note.put(NoteColumns.TYPE, Notes.TYPE_NOTE);
return mMetaInfo;
}
} catch (JSONException e) {
Log.e(TAG, "生成本地JSON失败", e);
return null;
}
}
// 设置元数据本地笔记与GTask的映射
public void setMetaInfo(MetaData metaData) {
if (metaData != null && metaData.getNotes() != null) {
try {
mMetaInfo = new JSONObject(metaData.getNotes());
} catch (JSONException e) {
Log.w(TAG, "解析元数据失败", e);
mMetaInfo = null;
}
}
}
// 判断当前同步动作类型
public int getSyncAction(Cursor c) {
try {
if (mMetaInfo == null || !mMetaInfo.has(GTaskStringUtils.META_HEAD_NOTE)) {
return SYNC_ACTION_UPDATE_REMOTE; // 元数据不存在,需从远程更新
}
JSONObject noteInfo = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
// 验证笔记ID
if (c.getLong(SqlNote.ID_COLUMN) != noteInfo.getLong(NoteColumns.ID)) {
return SYNC_ACTION_UPDATE_LOCAL; // ID不匹配需更新本地
}
// 判断本地修改状态
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())) {
return SYNC_ACTION_ERROR; // GTask ID不匹配错误
}
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);
}
return SYNC_ACTION_ERROR;
}
// 判断任务是否值得保存
public boolean isWorthSaving() {
return mMetaInfo != null ||
(getName() != null && getName().trim().length() > 0) ||
(getNotes() != null && getNotes().trim().length() > 0);
}
// Getter和Setter方法
public void setCompleted(boolean completed) { this.mCompleted = completed; }
public void setNotes(String notes) { this.mNotes = notes; }
public void setPriorSibling(Task priorSibling) { this.mPriorSibling = priorSibling; }
public void setParent(TaskList parent) { this.mParent = parent; }
public boolean getCompleted() { return mCompleted; }
public String getNotes() { return mNotes; }
public Task getPriorSibling() { return mPriorSibling; }
public TaskList getParent() { return mParent; }
}