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.

493 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.appwidget.AppWidgetManager;
import android.content.ContentResolver;
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;
import net.micode.notes.tool.ResourceParser;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
public class SqlNote {
private static final String TAG = SqlNote.class.getSimpleName(); // 用于日志记录的标签
private static final int INVALID_ID = -99999; // 无效ID常量
// 数据库列的投影
public static final String[] PROJECTION_NOTE = new String[] {
NoteColumns.ID, NoteColumns.ALERTED_DATE, NoteColumns.BG_COLOR_ID,
NoteColumns.CREATED_DATE, NoteColumns.HAS_ATTACHMENT, NoteColumns.MODIFIED_DATE,
NoteColumns.NOTES_COUNT, NoteColumns.PARENT_ID, NoteColumns.SNIPPET, NoteColumns.TYPE,
NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE, NoteColumns.SYNC_ID,
NoteColumns.LOCAL_MODIFIED, NoteColumns.ORIGIN_PARENT_ID, NoteColumns.GTASK_ID,
NoteColumns.VERSION
};
// 数据库列索引
public static final int ID_COLUMN = 0;
public static final int ALERTED_DATE_COLUMN = 1;
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;
public static final int PARENT_ID_COLUMN = 7;
public static final int SNIPPET_COLUMN = 8;
public static final int TYPE_COLUMN = 9;
public static final int WIDGET_ID_COLUMN = 10;
public static final int WIDGET_TYPE_COLUMN = 11;
public static final int SYNC_ID_COLUMN = 12;
public static final int LOCAL_MODIFIED_COLUMN = 13;
public static final int ORIGIN_PARENT_ID_COLUMN = 14;
public static final int GTASK_ID_COLUMN = 15;
public static final int VERSION_COLUMN = 16;
private Context mContext; // 上下文对象
private ContentResolver mContentResolver; // 内容解析器,用于与内容提供者交互
private boolean mIsCreate; // 标识是否为新创建的数据
private long mId; // 数据ID
private long mAlertDate; // 提醒日期
private int mBgColorId; // 背景颜色ID
private long mCreatedDate; // 创建日期
private int mHasAttachment; // 是否有附件
private long mModifiedDate; // 修改日期
private long mParentId; // 父ID
private String mSnippet; // 摘要
private int mType; // 类型
private int mWidgetId; // 小部件ID
private int mWidgetType; // 小部件类型
private long mOriginParent; // 原始父ID
private long mVersion; // 版本
private ContentValues mDiffNoteValues; // 存储数据变化的内容值
private ArrayList<SqlData> mDataList; // 存储与此笔记相关的数据列表
// 构造函数,初始化新数据
public SqlNote(Context context) {
mContext = context; // 保存上下文
mContentResolver = context.getContentResolver(); // 获取内容解析器
mIsCreate = true; // 标记为新创建
mId = INVALID_ID; // 初始化ID为无效值
mAlertDate = 0; // 初始化提醒日期为0
mBgColorId = ResourceParser.getDefaultBgId(context); // 获取默认背景颜色ID
mCreatedDate = System.currentTimeMillis(); // 获取当前时间作为创建日期
mHasAttachment = 0; // 初始化附件标志为0
mModifiedDate = System.currentTimeMillis(); // 获取当前时间作为修改日期
mParentId = 0; // 初始化父ID为0
mSnippet = ""; // 初始化摘要为空
mType = Notes.TYPE_NOTE; // 默认类型为笔记
mWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID; // 初始化小部件ID为无效值
mWidgetType = Notes.TYPE_WIDGET_INVALIDE; // 初始化小部件类型为无效值
mOriginParent = 0; // 初始化原始父ID为0
mVersion = 0; // 初始化版本为0
mDiffNoteValues = new ContentValues(); // 初始化内容值对象
mDataList = new ArrayList<SqlData>(); // 初始化数据列表
}
// 构造函数,初始化已有数据
public SqlNote(Context context, Cursor c) {
mContext = context; // 保存上下文
mContentResolver = context.getContentResolver(); // 获取内容解析器
mIsCreate = false; // 标记为已有数据
loadFromCursor(c); // 从Cursor加载数据
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); // 从ID加载数据
mDataList = new ArrayList<SqlData>(); // 初始化数据列表
if (mType == Notes.TYPE_NOTE) // 如果类型是笔记,加载数据内容
loadDataContent();
mDiffNoteValues = new ContentValues(); // 初始化内容值对象
}
// 从Cursor加载数据
private void loadFromCursor(long id) {
Cursor c = null; // 声明Cursor
try {
// 查询数据库获取笔记数据
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, PROJECTION_NOTE, "(_id=?)",
new String[] {
String.valueOf(id) // 使用ID作为查询条件
}, null);
if (c != null) {
c.moveToNext(); // 移动到结果的第一行
loadFromCursor(c); // 加载数据
} 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); // 获取数据ID
mAlertDate = c.getLong(ALERTED_DATE_COLUMN); // 获取提醒日期
mBgColorId = c.getInt(BG_COLOR_ID_COLUMN); // 获取背景颜色ID
mCreatedDate = c.getLong(CREATED_DATE_COLUMN); // 获取创建日期
mHasAttachment = c.getInt(HAS_ATTACHMENT_COLUMN); // 获取附件标志
mModifiedDate = c.getLong(MODIFIED_DATE_COLUMN); // 获取修改日期
mParentId = c.getLong(PARENT_ID_COLUMN); // 获取父ID
mSnippet = c.getString(SNIPPET_COLUMN); // 获取摘要
mType = c.getInt(TYPE_COLUMN); // 获取类型
mWidgetId = c.getInt(WIDGET_ID_COLUMN); // 获取小部件ID
mWidgetType = c.getInt(WIDGET_TYPE_COLUMN); // 获取小部件类型
mVersion = c.getLong(VERSION_COLUMN); // 获取版本
}
// 加载数据内容
private void loadDataContent() {
Cursor c = null; // 声明Cursor
mDataList.clear(); // 清空数据列表
try {
// 查询数据库获取与笔记相关的数据
c = mContentResolver.query(Notes.CONTENT_DATA_URI, SqlData.PROJECTION_DATA,
"(note_id=?)", new String[] {
String.valueOf(mId) // 使用笔记ID作为查询条件
}, 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); // 添加到数据列表
}
} else {
Log.w(TAG, "loadDataContent: cursor = null"); // 记录警告
}
} finally {
if (c != null)
c.close(); // 确保Cursor被关闭
}
}
// 设置内容从JSON对象中提取数据
public boolean setContent(JSONObject js) {
try {
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); // 更新摘要
}
mSnippet = snippet;
int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE)
: Notes.TYPE_NOTE; // 获取类型
if (mIsCreate || mType != type) {
mDiffNoteValues.put(NoteColumns.TYPE, type); // 更新类型
}
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; // 获取ID
if (mIsCreate || mId != id) {
mDiffNoteValues.put(NoteColumns.ID, id); // 更新ID
}
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); // 更新提醒日期
}
mAlertDate = alertDate;
int bgColorId = note.has(NoteColumns.BG_COLOR_ID) ? note
.getInt(NoteColumns.BG_COLOR_ID) : ResourceParser.getDefaultBgId(mContext); // 获取背景颜色ID
if (mIsCreate || mBgColorId != bgColorId) {
mDiffNoteValues.put(NoteColumns.BG_COLOR_ID, bgColorId); // 更新背景颜色ID
}
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); // 更新创建日期
}
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); // 更新附件标志
}
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); // 更新修改日期
}
mModifiedDate = modifiedDate;
long parentId = note.has(NoteColumns.PARENT_ID) ? note
.getLong(NoteColumns.PARENT_ID) : 0; // 获取父ID
if (mIsCreate || mParentId != parentId) {
mDiffNoteValues.put(NoteColumns.PARENT_ID, parentId); // 更新父ID
}
mParentId = parentId;
String snippet = note.has(NoteColumns.SNIPPET) ? note
.getString(NoteColumns.SNIPPET) : ""; // 获取摘要
if (mIsCreate || !mSnippet.equals(snippet)) {
mDiffNoteValues.put(NoteColumns.SNIPPET, snippet); // 更新摘要
}
mSnippet = snippet;
int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE)
: Notes.TYPE_NOTE; // 获取类型
if (mIsCreate || mType != type) {
mDiffNoteValues.put(NoteColumns.TYPE, type); // 更新类型
}
mType = type;
int widgetId = note.has(NoteColumns.WIDGET_ID) ? note.getInt(NoteColumns.WIDGET_ID)
: AppWidgetManager.INVALID_APPWIDGET_ID; // 获取小部件ID
if (mIsCreate || mWidgetId != widgetId) {
mDiffNoteValues.put(NoteColumns.WIDGET_ID, widgetId); // 更新小部件ID
}
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); // 更新小部件类型
}
mWidgetType = widgetType;
long originParent = note.has(NoteColumns.ORIGIN_PARENT_ID) ? note
.getLong(NoteColumns.ORIGIN_PARENT_ID) : 0; // 获取原始父ID
if (mIsCreate || mOriginParent != originParent) {
mDiffNoteValues.put(NoteColumns.ORIGIN_PARENT_ID, originParent); // 更新原始父ID
}
mOriginParent = originParent;
// 加载数据内容
for (int i = 0; i < dataArray.length(); i++) {
JSONObject data = dataArray.getJSONObject(i); // 获取数据对象
SqlData sqlData = null; // 声明SqlData对象
if (data.has(DataColumns.ID)) { // 如果数据对象有ID
long dataId = data.getLong(DataColumns.ID); // 获取数据ID
for (SqlData temp : mDataList) { // 遍历数据列表
if (dataId == temp.getId()) { // 如果找到匹配的ID
sqlData = temp; // 赋值
}
}
}
if (sqlData == null) { // 如果没有找到匹配的SqlData
sqlData = new SqlData(mContext); // 创建新的SqlData对象
mDataList.add(sqlData); // 添加到数据列表
}
sqlData.setContent(data); // 设置内容
}
}
} catch (JSONException e) {
Log.e(TAG, e.toString()); // 记录错误
e.printStackTrace(); // 打印堆栈跟踪
return false; // 返回失败
}
return true; // 返回成功
}
// 获取内容返回JSON对象
public JSONObject getContent() {
try {
JSONObject js = new JSONObject(); // 创建JSON对象
if (mIsCreate) { // 如果是新创建的
Log.e(TAG, "it seems that we haven't created this in database yet"); // 记录错误
return null; // 返回null
}
JSONObject note = new JSONObject(); // 创建笔记对象
if (mType == Notes.TYPE_NOTE) { // 如果类型是笔记
note.put(NoteColumns.ID, mId); // 添加ID
note.put(NoteColumns.ALERTED_DATE, mAlertDate); // 添加提醒日期
note.put(NoteColumns.BG_COLOR_ID, mBgColorId); // 添加背景颜色ID
note.put(NoteColumns.CREATED_DATE, mCreatedDate); // 添加创建日期
note.put(NoteColumns.HAS_ATTACHMENT, mHasAttachment); // 添加附件标志
note.put(NoteColumns.MODIFIED_DATE, mModifiedDate); // 添加修改日期
note.put(NoteColumns.PARENT_ID, mParentId); // 添加父ID
note.put(NoteColumns.SNIPPET, mSnippet); // 添加摘要
note.put(NoteColumns.TYPE, mType); // 添加类型
note.put(NoteColumns.WIDGET_ID, mWidgetId); // 添加小部件ID
note.put(NoteColumns.WIDGET_TYPE, mWidgetType); // 添加小部件类型
note.put(NoteColumns.ORIGIN_PARENT_ID, mOriginParent); // 添加原始父ID
js.put(GTaskStringUtils.META_HEAD_NOTE, note); // 将笔记对象添加到JSON对象
JSONArray dataArray = new JSONArray(); // 创建数据数组
for (SqlData sqlData : mDataList) { // 遍历数据列表
JSONObject data = sqlData.getContent(); // 获取内容
if (data != null) {
dataArray.put(data); // 添加到数据数组
}
}
js.put(GTaskStringUtils.META_HEAD_DATA, dataArray); // 将数据数组添加到JSON对象
} else if (mType == Notes.TYPE_FOLDER || mType == Notes.TYPE_SYSTEM) { // 如果是文件夹或系统
note.put(NoteColumns.ID, mId); // 添加ID
note.put(NoteColumns.TYPE, mType); // 添加类型
note.put(NoteColumns.SNIPPET, mSnippet); // 添加摘要
js.put(GTaskStringUtils.META_HEAD_NOTE, note); // 将笔记对象添加到JSON对象
}
return js; // 返回JSON对象
} catch (JSONException e) {
Log.e(TAG, e.toString()); // 记录错误
e.printStackTrace(); // 打印堆栈跟踪
}
return null; // 返回null
}
// 设置父ID
public void setParentId(long id) {
mParentId = id; // 更新父ID
mDiffNoteValues.put(NoteColumns.PARENT_ID, id); // 更新差异数据
}
// 设置GTask ID
public void setGtaskId(String gid) {
mDiffNoteValues.put(NoteColumns.GTASK_ID, gid); // 更新GTask ID
}
// 设置同步ID
public void setSyncId(long syncId) {
mDiffNoteValues.put(NoteColumns.SYNC_ID, syncId); // 更新同步ID
}
// 重置本地修改标志
public void resetLocalModified() {
mDiffNoteValues.put(NoteColumns.LOCAL_MODIFIED, 0); // 重置本地修改标志
}
// 获取数据ID
public long getId() {
return mId; // 返回数据ID
}
// 获取父ID
public long getParentId() {
return mParentId; // 返回父ID
}
// 获取摘要
public String getSnippet() {
return mSnippet; // 返回摘要
}
// 检查是否为笔记类型
public boolean isNoteType() {
return mType == Notes.TYPE_NOTE; // 返回类型是否为笔记
}
// 提交数据到数据库
public void commit(boolean validateVersion) {
if (mIsCreate) { // 如果是新创建的
if (mId == INVALID_ID && mDiffNoteValues.containsKey(NoteColumns.ID)) {
mDiffNoteValues.remove(NoteColumns.ID); // 移除无效ID
}
Uri uri = mContentResolver.insert(Notes.CONTENT_NOTE_URI, mDiffNoteValues); // 插入数据
try {
mId = Long.valueOf(uri.getPathSegments().get(1)); // 获取新插入数据的ID
} catch (NumberFormatException e) {
Log.e(TAG, "Get note id error :" + e.toString()); // 记录错误
throw new ActionFailureException("create note failed"); // 抛出异常
}
if (mId == 0) { // 如果ID为0
throw new IllegalStateException("Create thread id failed"); // 抛出异常
}
if (mType == Notes.TYPE_NOTE) { // 如果类型是笔记
for (SqlData sqlData : mDataList) {
sqlData.commit(mId, false, -1); // 提交数据
}
}
} else { // 如果是已有数据
if (mId <= 0 && mId != Notes.ID_ROOT_FOLDER && mId != Notes.ID_CALL_RECORD_FOLDER) {
Log.e(TAG, "No such note"); // 记录错误
throw new IllegalStateException("Try to update note with invalid id"); // 抛出异常
}
if (mDiffNoteValues.size() > 0) { // 如果有差异数据
mVersion++; // 增加版本
int result = 0;
if (!validateVersion) { // 如果不验证版本
result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "("
+ NoteColumns.ID + "=?)", new String[] {
String.valueOf(mId) // 使用ID作为更新条件
});
} else { // 如果验证版本
result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "("
+ NoteColumns.ID + "=?) AND (" + NoteColumns.VERSION + "<=?)",
new String[] {
String.valueOf(mId), String.valueOf(mVersion) // 使用ID和版本作为更新条件
});
}
if (result == 0) { // 如果没有更新
Log.w(TAG, "there is no update. maybe user updates note when syncing"); // 记录警告
}
}
if (mType == Notes.TYPE_NOTE) { // 如果类型是笔记
for (SqlData sqlData : mDataList) {
sqlData.commit(mId, validateVersion, mVersion); // 提交数据
}
}
}
// 刷新本地信息
loadFromCursor(mId); // 重新加载数据
if (mType == Notes.TYPE_NOTE) // 如果类型是笔记
loadDataContent(); // 加载数据内容
mDiffNoteValues.clear(); // 清空差异数据
mIsCreate = false; // 标记为非创建状态
}
}