com.ichi2.libanki.Note.java Source code

Java tutorial

Introduction

Here is the source code for com.ichi2.libanki.Note.java

Source

/****************************************************************************************
 * 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;
    }
}