Java tutorial
/**************************************************************************************** * Copyright (c) 2011 Norbert Nagold <norbert.nagold@gmail.com> * * Copyright (c) 2014 Houssam Salem <houssam.salem.au@gmail.com> * * * * This program is free software; you can redistribute it and/or modify it under * * the terms of the GNU General Public License as published by the Free Software * * Foundation; either version 3 of the License, or (at your option) any later * * version. * * * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * * PARTICULAR PURPOSE. See the GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License along with * * this program. If not, see <http://www.gnu.org/licenses/>. * ****************************************************************************************/ package com.ichi2.libanki; import android.database.Cursor; import android.util.Pair; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; public class Note implements Cloneable { private Collection mCol; private long mId; private String mGuId; private JSONObject mModel; private long mMid; private List<String> mTags; private String[] mFields; private int mFlags; private String mData; private Map<String, Pair<Integer, JSONObject>> mFMap; private long mScm; private int mUsn; private long mMod; private boolean mNewlyAdded; public Note(Collection col, Long id) { this(col, null, id); } public Note(Collection col, JSONObject model) { this(col, model, null); } public Note(Collection col, JSONObject model, Long id) { assert !(model != null && id != null); mCol = col; if (id != null) { mId = id; load(); } else { mId = Utils.timestampID(mCol.getDb(), "notes"); mGuId = Utils.guid64(); mModel = model; try { mMid = model.getLong("id"); mTags = new ArrayList<String>(); mFields = new String[model.getJSONArray("flds").length()]; Arrays.fill(mFields, ""); } catch (JSONException e) { throw new RuntimeException(e); } mFlags = 0; mData = ""; mFMap = mCol.getModels().fieldMap(mModel); mScm = mCol.getScm(); } } public void load() { Cursor cursor = null; try { cursor = mCol.getDb().getDatabase().rawQuery( "SELECT guid, mid, mod, usn, tags, flds, flags, data FROM notes WHERE id = " + mId, null); if (!cursor.moveToFirst()) { throw new RuntimeException("Notes.load(): No result from query for note " + mId); } mGuId = cursor.getString(0); mMid = cursor.getLong(1); mMod = cursor.getLong(2); mUsn = cursor.getInt(3); mTags = mCol.getTags().split(cursor.getString(4)); mFields = Utils.splitFields(cursor.getString(5)); mFlags = cursor.getInt(6); mData = cursor.getString(7); mModel = mCol.getModels().get(mMid); mFMap = mCol.getModels().fieldMap(mModel); mScm = mCol.getScm(); } finally { if (cursor != null) { cursor.close(); } } } /* * If fields or tags have changed, write changes to disk. */ public void flush() { flush(null); } public void flush(Long mod) { flush(mod, true); } public void flush(Long mod, boolean changeUsn) { assert mScm == mCol.getScm(); _preFlush(); if (changeUsn) { mUsn = mCol.usn(); } String sfld = Utils.stripHTMLMedia(mFields[mCol.getModels().sortIdx(mModel)]); String tags = stringTags(); String fields = joinedFields(); if (mod == null && mCol.getDb().queryScalar(String.format(Locale.US, "select 1 from notes where id = ? and tags = ? and flds = ?", mId, tags, fields)) > 0) { return; } long csum = Utils.fieldChecksum(mFields[0]); mMod = mod != null ? mod : Utils.intNow(); mCol.getDb().execute("insert or replace into notes values (?,?,?,?,?,?,?,?,?,?,?)", new Object[] { mId, mGuId, mMid, mMod, mUsn, tags, fields, sfld, csum, mFlags, mData }); mCol.getTags().register(mTags); _postFlush(); } public String joinedFields() { return Utils.joinFields(mFields); } public ArrayList<Card> cards() { ArrayList<Card> cards = new ArrayList<Card>(); Cursor cur = null; try { cur = mCol.getDb().getDatabase().rawQuery("SELECT id FROM cards WHERE nid = " + mId + " ORDER BY ord", null); while (cur.moveToNext()) { cards.add(mCol.getCard(cur.getLong(0))); } } finally { if (cur != null) { cur.close(); } } return cards; } public JSONObject model() { return mModel; } /** * Dict interface * *********************************************************** */ public String[] keys() { return (String[]) mFMap.keySet().toArray(); } public String[] values() { return mFields; } public String[][] items() { // TODO: Revisit this method. The field order returned differs from Anki. // The items here are only used in the note editor, so it's a low priority. String[][] result = new String[mFMap.size()][2]; for (String fname : mFMap.keySet()) { int i = mFMap.get(fname).first; result[i][0] = fname; result[i][1] = mFields[i]; } return result; } private int _fieldOrd(String key) { return mFMap.get(key).first; } public String getitem(String key) { return mFields[_fieldOrd(key)]; } public void setitem(String key, String value) { mFields[_fieldOrd(key)] = value; } public boolean contains(String key) { return mFMap.containsKey(key); } /** * Tags * *********************************************************** */ public boolean hasTag(String tag) { return mCol.getTags().inList(tag, mTags); } public String stringTags() { return mCol.getTags().join(mCol.getTags().canonify(mTags)); } public void setTagsFromStr(String str) { mTags = mCol.getTags().split(str); } public void delTag(String tag) { List<String> rem = new LinkedList<String>(); for (String t : mTags) { if (t.equalsIgnoreCase(tag)) { rem.add(t); } } for (String r : rem) { mTags.remove(r); } } /* * duplicates will be stripped on save */ public void addTag(String tag) { mTags.add(tag); } /** * Unique/duplicate check * *********************************************************** */ /** * * @return 1 if first is empty; 2 if first is a duplicate, null otherwise. */ public Integer dupeOrEmpty() { String val = mFields[0]; if (val.trim().length() == 0) { return 1; } long csum = Utils.fieldChecksum(val); // find any matching csums and compare for (String flds : mCol.getDb().queryColumn(String.class, "SELECT flds FROM notes WHERE csum = " + csum + " AND id != " + (mId != 0 ? mId : 0) + " AND mid = " + mMid, 0)) { if (Utils.stripHTMLMedia(Utils.splitFields(flds)[0]).equals(Utils.stripHTMLMedia(mFields[0]))) { return 2; } } return null; } /** * Flushing cloze notes * *********************************************************** */ /* * have we been added yet? */ private void _preFlush() { mNewlyAdded = mCol.getDb().queryScalar("SELECT 1 FROM cards WHERE nid = " + mId) == 0; } /* * generate missing cards */ private void _postFlush() { if (!mNewlyAdded) { mCol.genCards(new long[] { mId }); } } /* * *********************************************************** * The methods below are not in LibAnki. * *********************************************************** */ public long getMid() { return mMid; } /** * @return the mId */ public long getId() { // TODO: Conflicting method name and return value. Reconsider. return mId; } public Collection getCol() { return mCol; } public String getSFld() { return mCol.getDb().queryString("SELECT sfld FROM notes WHERE id = " + mId); } public String[] getFields() { return mFields; } public void setField(int index, String value) { mFields[index] = value; } public long getMod() { return mMod; } public Note clone() { try { return (Note) super.clone(); } catch (CloneNotSupportedException e) { throw new RuntimeException(e); } } public List<String> getTags() { return mTags; } }