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.
xiaomi/SqlNote.java

350 lines
16 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)
*
* 遵循 Apache 许可证 2.0 版(“许可证”);
* 除非遵守许可证,否则不得使用此文件。
* 你可以在以下网址获取许可证副本:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 除非适用法律要求或书面同意,
* 根据许可证分发的软件按“原样”分发,
* 不附带任何明示或暗示的保证或条件。
* 请参阅许可证,了解具体的权限和限制。
*/
package net.micode.notes.gtask.data;
import android.appwidget.AppWidgetManager; // 用于管理应用小部件的类
import android.content.ContentResolver; // 用于与 ContentProvider 进行交互的类
import android.content.ContentValues; // 用于存储一组键值对,通常用于插入或更新数据库记录
import android.content.Context; // 提供对应用程序环境的全局信息访问
import android.database.Cursor; // 用于遍历查询结果集的类
import android.net.Uri; // 用于表示统一资源标识符
import android.util.Log; // 用于记录日志信息的类
import net.micode.notes.data.Notes; // 导入与笔记相关的类
import net.micode.notes.data.Notes.DataColumns; // 导入数据列相关的接口
import net.micode.notes.data.Notes.NoteColumns; // 导入笔记列相关的接口
import net.micode.notes.gtask.exception.ActionFailureException; // 导入自定义的异常类
import net.micode.notes.tool.GTaskStringUtils; // 导入与 GTask 字符串处理相关的工具类
import net.micode.notes.tool.ResourceParser; // 导入资源解析工具类
import org.json.JSONArray; // 用于处理 JSON 数组的类
import org.json.JSONException; // 用于处理 JSON 异常的类
import org.json.JSONObject; // 用于处理 JSON 对象的类
import java.util.ArrayList; // 用于处理动态数组的类
// SqlNote 类用于处理与 SQLite 数据库中笔记相关的操作
public class SqlNote {
// 用于日志记录的标签,使用类的简单名称
private static final String TAG = SqlNote.class.getSimpleName();
// 定义无效的 ID 值
private static final int INVALID_ID = -99999;
// 定义查询笔记时使用的投影列
public static final String[] PROJECTION_NOTE = new String[] {
NoteColumns.ID, // 笔记的唯一标识
NoteColumns.ALERTED_DATE, // 提醒日期
NoteColumns.BG_COLOR_ID, // 背景颜色 ID
NoteColumns.CREATED_DATE, // 创建日期
NoteColumns.HAS_ATTACHMENT, // 是否有附件
NoteColumns.MODIFIED_DATE, // 修改日期
NoteColumns.NOTES_COUNT, // 子笔记数量
NoteColumns.PARENT_ID, // 父笔记 ID
NoteColumns.SNIPPET, // 摘要
NoteColumns.TYPE, // 笔记类型
NoteColumns.WIDGET_ID, // 小部件 ID
NoteColumns.WIDGET_TYPE, // 小部件类型
NoteColumns.SYNC_ID, // 同步 ID
NoteColumns.LOCAL_MODIFIED, // 本地修改标识
NoteColumns.ORIGIN_PARENT_ID, // 原始父笔记 ID
NoteColumns.GTASK_ID, // GTask ID
NoteColumns.VERSION // 版本号
};
// 定义投影列中笔记 ID 所在的索引
public static final int ID_COLUMN = 0;
// 定义投影列中提醒日期所在的索引
public static final int ALERTED_DATE_COLUMN = 1;
// 定义投影列中背景颜色 ID 所在的索引
public static final int BG_COLOR_ID_COLUMN = 2;
// 定义投影列中创建日期所在的索引
public static final int CREATED_DATE_COLUMN = 3;
// 定义投影列中是否有附件所在的索引
public static final int HAS_ATTACHMENT_COLUMN = 4;
// 定义投影列中修改日期所在的索引
public static final int MODIFIED_DATE_COLUMN = 5;
// 定义投影列中子笔记数量所在的索引
public static final int NOTES_COUNT_COLUMN = 6;
// 定义投影列中父笔记 ID 所在的索引
public static final int PARENT_ID_COLUMN = 7;
// 定义投影列中摘要所在的索引
public static final int SNIPPET_COLUMN = 8;
// 定义投影列中笔记类型所在的索引
public static final int TYPE_COLUMN = 9;
// 定义投影列中小部件 ID 所在的索引
public static final int WIDGET_ID_COLUMN = 10;
// 定义投影列中小部件类型所在的索引
public static final int WIDGET_TYPE_COLUMN = 11;
// 定义投影列中同步 ID 所在的索引
public static final int SYNC_ID_COLUMN = 12;
// 定义投影列中本地修改标识所在的索引
public static final int LOCAL_MODIFIED_COLUMN = 13;
// 定义投影列中原始父笔记 ID 所在的索引
public static final int ORIGIN_PARENT_ID_COLUMN = 14;
// 定义投影列中 GTask ID 所在的索引
public static final int GTASK_ID_COLUMN = 15;
// 定义投影列中版本号所在的索引
public static final int VERSION_COLUMN = 16;
// 应用程序上下文
private Context mContext;
// 用于与 ContentProvider 进行交互的 ContentResolver 对象
private ContentResolver mContentResolver;
// 表示是否为创建操作的标志
private boolean mIsCreate;
// 笔记的 ID
private long mId;
// 提醒日期
private long mAlertDate;
// 背景颜色 ID
private int mBgColorId;
// 创建日期
private long mCreatedDate;
// 是否有附件
private int mHasAttachment;
// 修改日期
private long mModifiedDate;
// 父笔记 ID
private long mParentId;
// 摘要
private String mSnippet;
// 笔记类型
private int mType;
// 小部件 ID
private int mWidgetId;
// 小部件类型
private int mWidgetType;
// 原始父笔记 ID
private long mOriginParent;
// 版本号
private long mVersion;
// 用于存储笔记差异的 ContentValues 对象
private ContentValues mDiffNoteValues;
// 用于存储笔记关联数据的列表
private ArrayList<SqlData> mDataList;
// 构造函数,用于创建一个新的 SqlNote 对象,通常用于创建新的笔记记录
public SqlNote(Context context) {
mContext = context;
mContentResolver = context.getContentResolver();
mIsCreate = true;
mId = INVALID_ID;
mAlertDate = 0;
mBgColorId = ResourceParser.getDefaultBgId(context); // 获取默认背景颜色 ID
mCreatedDate = System.currentTimeMillis(); // 设置当前时间为创建日期
mHasAttachment = 0;
mModifiedDate = System.currentTimeMillis(); // 设置当前时间为修改日期
mParentId = 0;
mSnippet = "";
mType = Notes.TYPE_NOTE; // 默认笔记类型为普通笔记
mWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID; // 无效的小部件 ID
mWidgetType = Notes.TYPE_WIDGET_INVALIDE; // 无效的小部件类型
mOriginParent = 0;
mVersion = 0;
mDiffNoteValues = new ContentValues();
mDataList = new ArrayList<SqlData>();
}
// 构造函数,用于从 Cursor 中加载数据,通常用于从数据库中读取已有的笔记记录
public SqlNote(Context context, Cursor c) {
mContext = context;
mContentResolver = context.getContentResolver();
mIsCreate = false;
loadFromCursor(c);
mDataList = new ArrayList<SqlData>();
if (mType == Notes.TYPE_NOTE)
loadDataContent(); // 如果是普通笔记,加载关联数据
mDiffNoteValues = new ContentValues();
}
// 构造函数,根据给定的笔记 ID 从数据库加载数据
public SqlNote(Context context, long id) {
mContext = context;
mContentResolver = context.getContentResolver();
mIsCreate = false;
loadFromCursor(id);
mDataList = new ArrayList<SqlData>();
if (mType == Notes.TYPE_NOTE)
loadDataContent();
mDiffNoteValues = new ContentValues();
}
// 根据笔记 ID 从数据库查询并加载数据的私有方法
private void loadFromCursor(long id) {
Cursor c = null;
try {
// 使用 ContentResolver 查询指定 ID 的笔记
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, PROJECTION_NOTE, "(_id=?)",
new String[] {
String.valueOf(id)
}, null);
if (c!= null) {
c.moveToNext();
loadFromCursor(c); // 调用另一个 loadFromCursor 方法处理查询结果
} else {
Log.w(TAG, "loadFromCursor: cursor = null"); // 如果查询结果为空,记录警告日志
}
} finally {
if (c!= null)
c.close(); // 关闭 Cursor释放资源
}
}
// 从 Cursor 中加载笔记数据的私有方法
private void loadFromCursor(Cursor c) {
mId = c.getLong(ID_COLUMN);
mAlertDate = c.getLong(ALERTED_DATE_COLUMN);
mBgColorId = c.getInt(BG_COLOR_ID_COLUMN);
mCreatedDate = c.getLong(CREATED_DATE_COLUMN);
mHasAttachment = c.getInt(HAS_ATTACHMENT_COLUMN);
mModifiedDate = c.getLong(MODIFIED_DATE_COLUMN);
mParentId = c.getLong(PARENT_ID_COLUMN);
mSnippet = c.getString(SNIPPET_COLUMN);
mType = c.getInt(TYPE_COLUMN);
mWidgetId = c.getInt(WIDGET_ID_COLUMN);
mWidgetType = c.getInt(WIDGET_TYPE_COLUMN);
mVersion = c.getLong(VERSION_COLUMN);
}
// 加载笔记关联数据的私有方法
private void loadDataContent() {
Cursor c = null;
mDataList.clear(); // 清空原有的数据列表
try {
// 使用 ContentResolver 查询与当前笔记关联的数据
c = mContentResolver.query(Notes.CONTENT_DATA_URI, SqlData.PROJECTION_DATA,
"(note_id=?)", new String[] {
String.valueOf(mId)
}, null);
if (c!= null) {
if (c.getCount() == 0) {
Log.w(TAG, "it seems that the note has not data"); // 如果没有关联数据,记录警告日志
return;
}
while (c.moveToNext()) {
SqlData data = new SqlData(mContext, c); // 根据查询结果创建 SqlData 对象
mDataList.add(data); // 将创建的 SqlData 对象添加到列表中
}
} else {
Log.w(TAG, "loadDataContent: cursor = null"); // 如果查询结果为空,记录警告日志
}
} finally {
if (c!= null)
c.close(); // 关闭 Cursor释放资源
}
}
// 根据 JSON 对象设置笔记内容的方法
public boolean setContent(JSONObject js) {
try {
// 从 JSON 对象中获取笔记部分的内容
JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) {
Log.w(TAG, "cannot set system folder"); // 如果是系统文件夹,记录警告日志
} else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_FOLDER) {
// 对于文件夹,只能更新摘要和类型
String snippet = note.has(NoteColumns.SNIPPET)? note
.getString(NoteColumns.SNIPPET) : "";
if (mIsCreate ||!mSnippet.equals(snippet)) {
mDiffNoteValues.put(NoteColumns.SNIPPET, snippet); // 将摘要差异放入 ContentValues
}
mSnippet = snippet;
int type = note.has(NoteColumns.TYPE)? note.getInt(NoteColumns.TYPE)
: Notes.TYPE_NOTE;
if (mIsCreate || mType!= type) {
mDiffNoteValues.put(NoteColumns.TYPE, type); // 将类型差异放入 ContentValues
}
mType = type;
} else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_NOTE) {
JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
long id = note.has(NoteColumns.ID)? note.getLong(NoteColumns.ID) : INVALID_ID;
if (mIsCreate || mId!= id) {
mDiffNoteValues.put(NoteColumns.ID, id); // 将 ID 差异放入 ContentValues
}
mId = id;
long alertDate = note.has(NoteColumns.ALERTED_DATE)? note
.getLong(NoteColumns.ALERTED_DATE) : 0;
if (mIsCreate || mAlertDate!= alertDate) {
mDiffNoteValues.put(NoteColumns.ALERTED_DATE, alertDate); // 将提醒日期差异放入 ContentValues
}
mAlertDate = alertDate;
int bgColorId = note.has(NoteColumns.BG_COLOR_ID)? note
.getInt(NoteColumns.BG_COLOR_ID) : ResourceParser.getDefaultBgId(mContext);
if (mIsCreate || mBgColorId!= bgColorId) {
mDiffNoteValues.put(NoteColumns.BG_COLOR_ID, bgColorId); // 将背景颜色 ID 差异放入 ContentValues
}
mBgColorId = bgColorId;
long createDate = note.has(NoteColumns.CREATED_DATE)? note
.getLong(NoteColumns.CREATED_DATE) : System.currentTimeMillis();
if (mIsCreate || mCreatedDate!= createDate) {
mDiffNoteValues.put(NoteColumns.CREATED_DATE, createDate); // 将创建日期差异放入 ContentValues
}
mCreatedDate = createDate;
int hasAttachment = note.has(NoteColumns.HAS_ATTACHMENT)? note
.getInt(NoteColumns.HAS_ATTACHMENT) : 0;
if (mIsCreate || mHasAttachment!= hasAttachment) {
mDiffNoteValues.put(NoteColumns.HAS_ATTACHMENT, hasAttachment); // 将是否有附件差异放入 ContentValues
}
mHasAttachment = hasAttachment;
long modifiedDate = note.has(NoteColumns.MODIFIED_DATE)? note
.getLong(NoteColumns.MODIFIED_DATE) : System.currentTimeMillis();
if (mIsCreate || mModifiedDate!= modifiedDate) {
mDiffNoteValues.put(NoteColumns.MODIFIED_DATE, modifiedDate); // 将修改日期差异放入 ContentValues
}
mModifiedDate = modifiedDate;
long parentId = note.has(NoteColumns.PARENT_ID)? note
.getLong(NoteColumns.PARENT_ID) : 0;
if (mIsCreate || mParentId!= parentId) {
mDiffNoteValues.put(NoteColumns.PARENT_ID, parentId); // 将父笔记 ID 差异放入 ContentValues
}
mParentId = parentId;
String snippet = note.has(NoteColumns.SNIPPET)? note
.getString(NoteColumns.SNIPPET) : "";
if (mIsCreate ||!mSnippet.equals(snippet)) {
mDiffNoteValues.put(NoteColumns.SNIPPET, snippet); // 将摘要差异放入 ContentValues
}
mSnippet = snippet;
int type = note.has(NoteColumns.TYPE)? note.getInt(NoteColumns.TYPE)
: Notes.TYPE_NOTE;
if (mIsCreate || mType!= type) {
mDiffNoteValues.put(NoteColumns.TYPE, type); // 将笔记类型差异放入 ContentValues
}
mType = type;
int widgetId = note.has(NoteColumns.WIDGET_ID)? note.getInt(NoteColumns.WIDGET_ID)
: AppWidgetManager.INVALID_APPWIDGET_ID;
if (mIsCreate || mWidgetId!= widgetId) {
mDiffNoteValues.put(NoteColumns.WIDGET_ID, widgetId); // 将小部件 ID 差异放入 ContentValues
}
mWidgetId = widgetId;
int widgetType = note.has(NoteColumns.WIDGET_TYPE)? note
.getInt(NoteColumns.WIDGET_TYPE) : Notes.TYPE_WIDGET_INVALIDE;
if (mIsCreate || mWidgetType!= widgetType) {
mDiffNoteValues.put(NoteColumns.WIDGET_TYPE, widgetType); // 将小部件类型差异放入 ContentValues
}
mWidgetType = widgetType;
long originParent = note.has(NoteColumns.ORIGIN_PARENT_ID