Search in sources :

Example 56 with ConfirmModSchemaException

use of com.ichi2.anki.exception.ConfirmModSchemaException in project Anki-Android by ankidroid.

the class ContentProviderTest method testInsertAndUpdateModel.

/**
 * Check that inserting a new model works as expected
 */
@Test
public void testInsertAndUpdateModel() {
    final ContentResolver cr = getContentResolver();
    ContentValues cv = new ContentValues();
    // Insert a new model
    cv.put(FlashCardsContract.Model.NAME, TEST_MODEL_NAME);
    cv.put(FlashCardsContract.Model.FIELD_NAMES, Utils.joinFields(TEST_MODEL_FIELDS));
    cv.put(FlashCardsContract.Model.NUM_CARDS, TEST_MODEL_CARDS.length);
    Uri modelUri = cr.insert(FlashCardsContract.Model.CONTENT_URI, cv);
    assertNotNull("Check inserted model isn't null", modelUri);
    assertNotNull("Check last path segment exists", modelUri.getLastPathSegment());
    long mid = Long.parseLong(modelUri.getLastPathSegment());
    Collection col = reopenCol();
    try {
        JSONObject model = col.getModels().get(mid);
        assertNotNull("Check model", model);
        assertEquals("Check model name", TEST_MODEL_NAME, model.getString("name"));
        assertEquals("Check templates length", TEST_MODEL_CARDS.length, model.getJSONArray("tmpls").length());
        assertEquals("Check field length", TEST_MODEL_FIELDS.length, model.getJSONArray("flds").length());
        JSONArray fields = model.getJSONArray("flds");
        for (int i = 0; i < fields.length(); i++) {
            assertEquals("Check name of fields", TEST_MODEL_FIELDS[i], fields.getJSONObject(i).getString("name"));
        }
        // Test updating the model CSS (to test updating MODELS_ID Uri)
        cv = new ContentValues();
        cv.put(FlashCardsContract.Model.CSS, TEST_MODEL_CSS);
        assertThat(cr.update(modelUri, cv, null, null), is(greaterThan(0)));
        col = reopenCol();
        model = col.getModels().get(mid);
        assertNotNull("Check model", model);
        assertEquals("Check css", TEST_MODEL_CSS, model.getString("css"));
        // Update each of the templates in model (to test updating MODELS_ID_TEMPLATES_ID Uri)
        for (int i = 0; i < TEST_MODEL_CARDS.length; i++) {
            cv = new ContentValues();
            cv.put(FlashCardsContract.CardTemplate.NAME, TEST_MODEL_CARDS[i]);
            cv.put(FlashCardsContract.CardTemplate.QUESTION_FORMAT, TEST_MODEL_QFMT[i]);
            cv.put(FlashCardsContract.CardTemplate.ANSWER_FORMAT, TEST_MODEL_AFMT[i]);
            cv.put(FlashCardsContract.CardTemplate.BROWSER_QUESTION_FORMAT, TEST_MODEL_QFMT[i]);
            cv.put(FlashCardsContract.CardTemplate.BROWSER_ANSWER_FORMAT, TEST_MODEL_AFMT[i]);
            Uri tmplUri = Uri.withAppendedPath(Uri.withAppendedPath(modelUri, "templates"), Integer.toString(i));
            assertThat("Update rows", cr.update(tmplUri, cv, null, null), is(greaterThan(0)));
            col = reopenCol();
            model = col.getModels().get(mid);
            assertNotNull("Check model", model);
            JSONObject template = model.getJSONArray("tmpls").getJSONObject(i);
            assertEquals("Check template name", TEST_MODEL_CARDS[i], template.getString("name"));
            assertEquals("Check qfmt", TEST_MODEL_QFMT[i], template.getString("qfmt"));
            assertEquals("Check afmt", TEST_MODEL_AFMT[i], template.getString("afmt"));
            assertEquals("Check bqfmt", TEST_MODEL_QFMT[i], template.getString("bqfmt"));
            assertEquals("Check bafmt", TEST_MODEL_AFMT[i], template.getString("bafmt"));
        }
    } finally {
        // Delete the model (this will force a full-sync)
        col.modSchemaNoCheck();
        try {
            Model model = col.getModels().get(mid);
            assertNotNull("Check model", model);
            col.getModels().rem(model);
        } catch (ConfirmModSchemaException e) {
        // This will never happen
        }
    }
}
Also used : ContentValues(android.content.ContentValues) JSONObject(com.ichi2.utils.JSONObject) JSONArray(com.ichi2.utils.JSONArray) Model(com.ichi2.libanki.Model) Collection(com.ichi2.libanki.Collection) ConfirmModSchemaException(com.ichi2.anki.exception.ConfirmModSchemaException) Uri(android.net.Uri) ContentResolver(android.content.ContentResolver) Test(org.junit.Test)

Example 57 with ConfirmModSchemaException

use of com.ichi2.anki.exception.ConfirmModSchemaException in project Anki-Android by ankidroid.

the class Anki2Importer method _importCards.

/**
 * Cards
 * ***********************************************************
 */
private void _importCards() {
    if (mMustResetLearning) {
        try {
            mSrc.changeSchedulerVer(2);
        } catch (ConfirmModSchemaException e) {
            throw new RuntimeException("Changing the scheduler of an import should not cause schema modification", e);
        }
    }
    // build map of guid -> (ord -> cid) and used id cache
    /*
         * Since we can't use a tuple as a key in Java, we resort to indexing twice with nested maps.
         * Python: (guid, ord) -> cid
         * Java: guid -> ord -> cid
         */
    int nbCard = mDst.cardCount();
    Map<String, Map<Integer, Long>> cardsByGuid = HashUtil.HashMapInit(nbCard);
    Set<Long> existing = HashUtil.HashSetInit(nbCard);
    try (Cursor cur = mDst.getDb().query("select f.guid, c.ord, c.id from cards c, notes f " + "where c.nid = f.id")) {
        while (cur.moveToNext()) {
            String guid = cur.getString(0);
            int ord = cur.getInt(1);
            long cid = cur.getLong(2);
            existing.add(cid);
            if (cardsByGuid.containsKey(guid)) {
                cardsByGuid.get(guid).put(ord, cid);
            } else {
                // The size is at most the number of card type in the note type.
                Map<Integer, Long> map = new HashMap<>();
                map.put(ord, cid);
                cardsByGuid.put(guid, map);
            }
        }
    }
    // loop through src
    int nbCardsToImport = mSrc.cardCount();
    List<Object[]> cards = new ArrayList<>(nbCardsToImport);
    int totalCardCount = 0;
    final int thresExecCards = 1000;
    List<Object[]> revlog = new ArrayList<>(mSrc.getSched().logCount());
    int totalRevlogCount = 0;
    final int thresExecRevlog = 1000;
    int usn = mDst.usn();
    long aheadBy = mSrc.getSched().getToday() - mDst.getSched().getToday();
    mDst.getDb().getDatabase().beginTransaction();
    try (Cursor cur = mSrc.getDb().query("select f.guid, c.id, c.did, c.ord, c.type, c.queue, c.due, c.ivl, c.factor, c.reps, c.lapses, c.left, c.odue, c.odid, c.flags, c.data from cards c, notes f " + "where c.nid = f.id")) {
        // Counters for progress updates
        int total = cur.getCount();
        boolean largeCollection = total > 200;
        int onePercent = total / 100;
        int i = 0;
        while (cur.moveToNext()) {
            String guid = cur.getString(0);
            long cid = cur.getLong(1);
            // To keep track of card id in source
            long scid = cid;
            long did = cur.getLong(2);
            int ord = cur.getInt(3);
            @Consts.CARD_TYPE int type = cur.getInt(4);
            @Consts.CARD_QUEUE int queue = cur.getInt(5);
            long due = cur.getLong(6);
            long ivl = cur.getLong(7);
            long factor = cur.getLong(8);
            int reps = cur.getInt(9);
            int lapses = cur.getInt(10);
            int left = cur.getInt(11);
            long odue = cur.getLong(12);
            long odid = cur.getLong(13);
            int flags = cur.getInt(14);
            String data = cur.getString(15);
            if (mIgnoredGuids.contains(guid)) {
                continue;
            }
            // does the card's note exist in dst col?
            if (!mNotes.containsKey(guid)) {
                continue;
            }
            NoteTriple dnid = mNotes.get(guid);
            // does the card already exist in the dst col?
            if (cardsByGuid.containsKey(guid) && cardsByGuid.get(guid).containsKey(ord)) {
                // fixme: in future, could update if newer mod time
                continue;
            }
            // ensure the card id is unique
            while (existing.contains(cid)) {
                cid += 999;
            }
            existing.add(cid);
            // update cid, nid, etc
            long nid = mNotes.get(guid).mNid;
            did = _did(did);
            long mod = mCol.getTime().intTime();
            // review cards have a due date relative to collection
            if (queue == QUEUE_TYPE_REV || queue == QUEUE_TYPE_DAY_LEARN_RELEARN || type == CARD_TYPE_REV) {
                due -= aheadBy;
            }
            // odue needs updating too
            if (odue != 0) {
                odue -= aheadBy;
            }
            // if odid true, convert card from filtered to normal
            if (odid != 0) {
                // odid
                odid = 0;
                // odue
                due = odue;
                odue = 0;
                // queue
                if (type == CARD_TYPE_LRN) {
                    // type
                    queue = QUEUE_TYPE_NEW;
                } else {
                    queue = type;
                }
                // type
                if (type == CARD_TYPE_LRN) {
                    type = CARD_TYPE_NEW;
                }
            }
            cards.add(new Object[] { cid, nid, did, ord, mod, usn, type, queue, due, ivl, factor, reps, lapses, left, odue, odid, flags, data });
            // we need to import revlog, rewriting card ids and bumping usn
            try (Cursor cur2 = mSrc.getDb().query("select * from revlog where cid = " + scid)) {
                while (cur2.moveToNext()) {
                    Object[] rev = new Object[] { cur2.getLong(0), cur2.getLong(1), cur2.getInt(2), cur2.getInt(3), cur2.getLong(4), cur2.getLong(5), cur2.getLong(6), cur2.getLong(7), cur2.getInt(8) };
                    rev[1] = cid;
                    rev[2] = mDst.usn();
                    revlog.add(rev);
                }
            }
            i++;
            // apply card changes partially
            if (cards.size() >= thresExecCards) {
                totalCardCount += cards.size();
                insertCards(cards);
                cards.clear();
                Timber.d("add cards: %d", totalCardCount);
            }
            // apply revlog changes partially
            if (revlog.size() >= thresExecRevlog) {
                totalRevlogCount += revlog.size();
                insertRevlog(revlog);
                revlog.clear();
                Timber.d("add revlog: %d", totalRevlogCount);
            }
            if (total != 0 && (!largeCollection || i % onePercent == 0)) {
                publishProgress(100, i * 100 / total, 0);
            }
        }
        publishProgress(100, 100, 0);
        // count total values
        totalCardCount += cards.size();
        totalRevlogCount += revlog.size();
        Timber.d("add cards total:  %d", totalCardCount);
        Timber.d("add revlog total: %d", totalRevlogCount);
        // apply (for last chunk)
        insertCards(cards);
        cards.clear();
        insertRevlog(revlog);
        revlog.clear();
        mLog.add(getRes().getString(R.string.import_complete_count, totalCardCount));
        mDst.getDb().getDatabase().setTransactionSuccessful();
    } finally {
        DB.safeEndInTransaction(mDst.getDb());
    }
}
Also used : HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Cursor(android.database.Cursor) ConfirmModSchemaException(com.ichi2.anki.exception.ConfirmModSchemaException) HashMap(java.util.HashMap) Map(java.util.Map)

Example 58 with ConfirmModSchemaException

use of com.ichi2.anki.exception.ConfirmModSchemaException in project Anki-Android by ankidroid.

the class Models method remField.

@Override
public void remField(Model m, JSONObject field) throws ConfirmModSchemaException {
    mCol.modSchema();
    JSONArray flds = m.getJSONArray("flds");
    JSONArray flds2 = new JSONArray();
    int idx = -1;
    for (int i = 0; i < flds.length(); ++i) {
        if (field.equals(flds.getJSONObject(i))) {
            idx = i;
            continue;
        }
        flds2.put(flds.getJSONObject(i));
    }
    m.put("flds", flds2);
    int sortf = m.getInt("sortf");
    if (sortf >= m.getJSONArray("flds").length()) {
        m.put("sortf", sortf - 1);
    }
    _updateFieldOrds(m);
    _transformFields(m, new TransformFieldDelete(idx));
    if (idx == sortIdx(m)) {
        // need to rebuild
        mCol.updateFieldCache(nids(m));
    }
    renameField(m, field, null);
}
Also used : JSONArray(com.ichi2.utils.JSONArray)

Example 59 with ConfirmModSchemaException

use of com.ichi2.anki.exception.ConfirmModSchemaException in project Anki-Android by ankidroid.

the class Models method moveField.

@Override
public void moveField(Model m, JSONObject field, int idx) throws ConfirmModSchemaException {
    mCol.modSchema();
    JSONArray flds = m.getJSONArray("flds");
    ArrayList<JSONObject> l = new ArrayList<>(flds.length());
    int oldidx = -1;
    for (int i = 0; i < flds.length(); ++i) {
        l.add(flds.getJSONObject(i));
        if (field.equals(flds.getJSONObject(i))) {
            oldidx = i;
            if (idx == oldidx) {
                return;
            }
        }
    }
    // remember old sort field
    String sortf = Utils.jsonToString(m.getJSONArray("flds").getJSONObject(m.getInt("sortf")));
    // move
    l.remove(oldidx);
    l.add(idx, field);
    m.put("flds", new JSONArray(l));
    // restore sort field
    flds = m.getJSONArray("flds");
    for (int i = 0; i < flds.length(); ++i) {
        if (Utils.jsonToString(flds.getJSONObject(i)).equals(sortf)) {
            m.put("sortf", i);
            break;
        }
    }
    _updateFieldOrds(m);
    save(m);
    _transformFields(m, new TransformFieldMove(idx, oldidx));
}
Also used : JSONObject(com.ichi2.utils.JSONObject) JSONArray(com.ichi2.utils.JSONArray) ArrayList(java.util.ArrayList)

Example 60 with ConfirmModSchemaException

use of com.ichi2.anki.exception.ConfirmModSchemaException in project Anki-Android by ankidroid.

the class Models method renameField.

@Override
public void renameField(Model m, JSONObject field, String newName) throws ConfirmModSchemaException {
    mCol.modSchema();
    String pat = String.format("\\{\\{([^{}]*)([:#^/]|[^:#/^}][^:}]*?:|)%s\\}\\}", Pattern.quote(field.getString("name")));
    if (newName == null) {
        newName = "";
    }
    String repl = "{{$1$2" + newName + "}}";
    JSONArray tmpls = m.getJSONArray("tmpls");
    for (JSONObject t : tmpls.jsonObjectIterable()) {
        for (String fmt : new String[] { "qfmt", "afmt" }) {
            if (!"".equals(newName)) {
                t.put(fmt, t.getString(fmt).replaceAll(pat, repl));
            } else {
                t.put(fmt, t.getString(fmt).replaceAll(pat, ""));
            }
        }
    }
    field.put("name", newName);
    save(m);
}
Also used : JSONObject(com.ichi2.utils.JSONObject) JSONArray(com.ichi2.utils.JSONArray)

Aggregations

JSONObject (com.ichi2.utils.JSONObject)39 ConfirmModSchemaException (com.ichi2.anki.exception.ConfirmModSchemaException)26 JSONArray (com.ichi2.utils.JSONArray)23 Test (org.junit.Test)22 RobolectricTest (com.ichi2.anki.RobolectricTest)14 ConfirmationDialog (com.ichi2.anki.dialogs.ConfirmationDialog)12 Collection (com.ichi2.libanki.Collection)12 Model (com.ichi2.libanki.Model)12 Note (com.ichi2.libanki.Note)8 ArrayList (java.util.ArrayList)8 JSONException (com.ichi2.utils.JSONException)6 HashMap (java.util.HashMap)5 SdkSuppress (androidx.test.filters.SdkSuppress)4 TaskData (com.ichi2.async.TaskData)4 ModelManager (com.ichi2.libanki.ModelManager)4 TextImporter (com.ichi2.libanki.importer.TextImporter)4 Matchers.containsString (org.hamcrest.Matchers.containsString)4 Cursor (android.database.Cursor)3 Uri (android.net.Uri)3 Bundle (android.os.Bundle)3