Search in sources :

Example 61 with DeckConfig

use of com.ichi2.libanki.DeckConfig in project AnkiChinaAndroid by ankichinateam.

the class SchedV2 method _deckRevLimitSingle.

/**
 * Maximal number of rev card still to see today in deck d. It's computed as:
 * the number of rev card to see by day according to the deck optinos
 * minus the number of rev cards seen today in deck d or a descendant
 * plus the number of extra cards to see today in deck d, a parent or a descendant.
 *
 * Respects the limits of its ancestor, either given as parentLimit, or through direct computation.
 */
private int _deckRevLimitSingle(@Nullable Deck d, Integer parentLimit) {
    // invalid deck selected?
    if (d == null) {
        return 0;
    }
    if (d.getInt("dyn") != 0) {
        return mDynReportLimit;
    }
    long did = d.getLong("id");
    @NonNull DeckConfig c = mCol.getDecks().confForDid(did);
    int lim = Math.max(0, c.getJSONObject("rev").getInt("perDay") - d.getJSONArray("revToday").getInt(1));
    // So currentCard does not have to be taken into consideration in this method
    if (currentCardIsInQueueWithDeck(Consts.QUEUE_TYPE_REV, did)) {
        lim--;
    }
    if (parentLimit != null) {
        return Math.min(parentLimit, lim);
    } else if (!d.getString("name").contains("::")) {
        return lim;
    } else {
        for (@NonNull Deck parent : mCol.getDecks().parents(did)) {
            // pass in dummy parentLimit so we don't do parent lookup again
            lim = Math.min(lim, _deckRevLimitSingle(parent, lim));
        }
        return lim;
    }
}
Also used : NonNull(androidx.annotation.NonNull) Deck(com.ichi2.libanki.Deck) DeckConfig(com.ichi2.libanki.DeckConfig)

Example 62 with DeckConfig

use of com.ichi2.libanki.DeckConfig in project AnkiChinaAndroid by ankichinateam.

the class ZipFile method exportInto.

/**
 * Export source database into new destination database Note: The following python syntax isn't supported in
 * Android: for row in mSrc.db.execute("select * from cards where id in "+ids2str(cids)): therefore we use a
 * different method for copying tables
 *
 * @param path String path to destination database
 * @throws JSONException
 * @throws IOException
 */
public void exportInto(String path, Context context) throws JSONException, IOException, ImportExportException {
    // create a new collection at the target
    new File(path).delete();
    Collection dst = Storage.Collection(context, path);
    mSrc = mCol;
    // find cards
    Long[] cids = cardIds();
    // attach dst to src so we can copy data between them. This isn't done in original libanki as Python more
    // flexible
    dst.close();
    Timber.d("Attach DB");
    mSrc.getDb().getDatabase().execSQL("ATTACH '" + path + "' AS DST_DB");
    // copy cards, noting used nids (as unique set)
    Timber.d("Copy cards");
    mSrc.getDb().getDatabase().execSQL("INSERT INTO DST_DB.cards select * from cards where id in " + Utils.ids2str(cids));
    Set<Long> nids = new HashSet<>(mSrc.getDb().queryLongList("select nid from cards where id in " + Utils.ids2str(cids)));
    // notes
    Timber.d("Copy notes");
    ArrayList<Long> uniqueNids = new ArrayList<>(nids);
    String strnids = Utils.ids2str(uniqueNids);
    mSrc.getDb().getDatabase().execSQL("INSERT INTO DST_DB.notes select * from notes where id in " + strnids);
    // remove system tags if not exporting scheduling info
    if (!mIncludeSched) {
        Timber.d("Stripping system tags from list");
        ArrayList<String> srcTags = mSrc.getDb().queryStringList("select tags from notes where id in " + strnids);
        ArrayList<Object[]> args = new ArrayList<>(srcTags.size());
        Object[] arg = new Object[2];
        for (int row = 0; row < srcTags.size(); row++) {
            arg[0] = removeSystemTags(srcTags.get(row));
            arg[1] = uniqueNids.get(row);
            args.add(row, arg);
        }
        mSrc.getDb().executeMany("UPDATE DST_DB.notes set tags=? where id=?", args);
    }
    // models used by the notes
    Timber.d("Finding models used by notes");
    ArrayList<Long> mids = mSrc.getDb().queryLongList("select distinct mid from DST_DB.notes where id in " + strnids);
    // card history and revlog
    if (mIncludeSched) {
        Timber.d("Copy history and revlog");
        mSrc.getDb().getDatabase().execSQL("insert into DST_DB.revlog select * from revlog where cid in " + Utils.ids2str(cids));
        // reopen collection to destination database (different from original python code)
        mSrc.getDb().getDatabase().execSQL("DETACH DST_DB");
        dst.reopen();
    } else {
        Timber.d("Detaching destination db and reopening");
        // first reopen collection to destination database (different from original python code)
        mSrc.getDb().getDatabase().execSQL("DETACH DST_DB");
        dst.reopen();
        // then need to reset card state
        Timber.d("Resetting cards");
        dst.getSched().resetCards(cids);
    }
    // models - start with zero
    Timber.d("Copy models");
    for (Model m : mSrc.getModels().all()) {
        if (mids.contains(m.getLong("id"))) {
            Timber.d("Copy models:%s", m.getLong("id"));
            dst.getModels().update(m);
        }
    }
    for (Model m : dst.getModels().all()) {
        Timber.d("check dst model:%s", m.getLong("id"));
    }
    // decks
    Timber.d("Copy decks");
    ArrayList<Long> dids = new ArrayList<>();
    if (mDid != null) {
        dids.add(mDid);
        for (Long x : mSrc.getDecks().children(mDid).values()) {
            dids.add(x);
        }
    }
    JSONObject dconfs = new JSONObject();
    for (Deck d : mSrc.getDecks().all()) {
        if ("1".equals(d.getString("id"))) {
            continue;
        }
        if (mDid != null && !dids.contains(d.getLong("id"))) {
            continue;
        }
        if (d.getInt("dyn") != 1 && d.getLong("conf") != 1L) {
            if (mIncludeSched) {
                dconfs.put(Long.toString(d.getLong("conf")), true);
            }
        }
        Deck destinationDeck = d.deepClone();
        if (!mIncludeSched) {
            // scheduling not included, so reset deck settings to default
            destinationDeck.put("conf", 1);
        }
        dst.getDecks().update(destinationDeck);
    }
    // copy used deck confs
    Timber.d("Copy deck options");
    for (DeckConfig dc : mSrc.getDecks().allConf()) {
        if (dconfs.has(dc.getString("id"))) {
            dst.getDecks().updateConf(dc);
        }
    }
    // find used media
    Timber.d("Find used media");
    JSONObject media = new JSONObject();
    mMediaDir = mSrc.getMedia().dir();
    if (mIncludeMedia) {
        ArrayList<Long> mid = mSrc.getDb().queryLongList("select mid from notes where id in " + strnids);
        ArrayList<String> flds = mSrc.getDb().queryStringList("select flds from notes where id in " + strnids);
        for (int idx = 0; idx < mid.size(); idx++) {
            for (String file : mSrc.getMedia().filesInStr(mid.get(idx), flds.get(idx))) {
                // skip files in subdirs
                if (file.contains(File.separator)) {
                    continue;
                }
                media.put(file, true);
            }
        }
        if (mMediaDir != null) {
            for (File f : new File(mMediaDir).listFiles()) {
                if (f.isDirectory()) {
                    continue;
                }
                String fname = f.getName();
                if (fname.startsWith("_")) {
                    // Loop through every model that will be exported, and check if it contains a reference to f
                    for (JSONObject model : mSrc.getModels().all()) {
                        if (_modelHasMedia(model, fname)) {
                            media.put(fname, true);
                            break;
                        }
                    }
                }
            }
        }
    }
    JSONArray keys = media.names();
    if (keys != null) {
        for (int i = 0; i < keys.length(); i++) {
            mMediaFiles.add(keys.getString(i));
        }
    }
    Timber.d("Cleanup");
    dst.setCrt(mSrc.getCrt());
    // todo: tags?
    mCount = dst.cardCount();
    dst.setMod();
    postExport();
    dst.close();
}
Also used : ArrayList(java.util.ArrayList) JSONArray(com.ichi2.utils.JSONArray) JSONObject(com.ichi2.utils.JSONObject) JSONObject(com.ichi2.utils.JSONObject) File(java.io.File) HashSet(java.util.HashSet)

Example 63 with DeckConfig

use of com.ichi2.libanki.DeckConfig in project AnkiChinaAndroid by ankichinateam.

the class Storage method _upgrade.

private static void _upgrade(Collection col, int ver) {
    try {
        if (ver < 3) {
            // new deck properties
            for (Deck d : col.getDecks().all()) {
                d.put("dyn", 0);
                d.put("collapsed", false);
                col.getDecks().save(d);
            }
        }
        if (ver < 4) {
            col.modSchemaNoCheck();
            ArrayList<Model> clozes = new ArrayList<>();
            for (Model m : col.getModels().all()) {
                if (!m.getJSONArray("tmpls").getJSONObject(0).getString("qfmt").contains("{{cloze:")) {
                    m.put("type", Consts.MODEL_STD);
                } else {
                    clozes.add(m);
                }
            }
            for (Model m : clozes) {
                try {
                    _upgradeClozeModel(col, m);
                } catch (ConfirmModSchemaException e) {
                    // Will never be reached as we already set modSchemaNoCheck()
                    throw new RuntimeException(e);
                }
            }
            col.getDb().execute("UPDATE col SET ver = 4");
        }
        if (ver < 5) {
            col.getDb().execute("UPDATE cards SET odue = 0 WHERE queue = 2");
            col.getDb().execute("UPDATE col SET ver = 5");
        }
        if (ver < 6) {
            col.modSchemaNoCheck();
            for (Model m : col.getModels().all()) {
                m.put("css", new JSONObject(Models.defaultModel).getString("css"));
                JSONArray ar = m.getJSONArray("tmpls");
                for (int i = 0; i < ar.length(); i++) {
                    JSONObject t = ar.getJSONObject(i);
                    if (!t.has("css")) {
                        continue;
                    }
                    m.put("css", m.getString("css") + "\n" + t.getString("css").replace(".card ", ".card" + t.getInt("ord") + 1));
                    t.remove("css");
                }
                col.getModels().save(m);
            }
            col.getDb().execute("UPDATE col SET ver = 6");
        }
        if (ver < 7) {
            col.modSchemaNoCheck();
            col.getDb().execute("UPDATE cards SET odue = 0 WHERE (type = " + Consts.CARD_TYPE_LRN + " OR queue = 2) AND NOT odid");
            col.getDb().execute("UPDATE col SET ver = 7");
        }
        if (ver < 8) {
            col.modSchemaNoCheck();
            col.getDb().execute("UPDATE cards SET due = due / 1000 WHERE due > 4294967296");
            col.getDb().execute("UPDATE col SET ver = 8");
        }
        if (ver < 9) {
            col.getDb().execute("UPDATE col SET ver = 9");
        }
        if (ver < 10) {
            col.getDb().execute("UPDATE cards SET left = left + left * 1000 WHERE queue = " + Consts.QUEUE_TYPE_LRN);
            col.getDb().execute("UPDATE col SET ver = 10");
        }
        if (ver < 11) {
            col.modSchemaNoCheck();
            for (Deck d : col.getDecks().all()) {
                if (d.getInt("dyn") != 0) {
                    int order = d.getInt("order");
                    // failed order was removed
                    if (order >= 5) {
                        order -= 1;
                    }
                    JSONArray terms = new JSONArray(Arrays.asList(d.getString("search"), d.getInt("limit"), order));
                    d.put("terms", new JSONArray());
                    d.getJSONArray("terms").put(0, terms);
                    d.remove("search");
                    d.remove("limit");
                    d.remove("order");
                    d.put("resched", true);
                    d.put("return", true);
                } else {
                    if (!d.has("extendNew")) {
                        d.put("extendNew", 10);
                        d.put("extendRev", 50);
                    }
                }
                col.getDecks().save(d);
            }
            for (DeckConfig c : col.getDecks().allConf()) {
                JSONObject r = c.getJSONObject("rev");
                r.put("ivlFct", r.optDouble("ivlFct", 1));
                if (r.has("ivlfct")) {
                    r.remove("ivlfct");
                }
                r.put("maxIvl", 36500);
                col.getDecks().save(c);
            }
            for (Model m : col.getModels().all()) {
                JSONArray tmpls = m.getJSONArray("tmpls");
                for (int ti = 0; ti < tmpls.length(); ++ti) {
                    JSONObject t = tmpls.getJSONObject(ti);
                    t.put("bqfmt", "");
                    t.put("bafmt", "");
                }
                col.getModels().save(m);
            }
            col.getDb().execute("update col set ver = 11");
        }
    // if (ver < 12) {
    // col.getDb().execute("create table if not exists synclog (" + "    id             integer not null,"
    // + "    type             integer not null,"+ "    mod             integer not null" + ")");
    // col.getDb().execute("update col set ver = 12");
    // _updateIndices(col.getDb());
    // }
    } catch (JSONException e) {
        throw new RuntimeException(e);
    }
}
Also used : JSONObject(com.ichi2.utils.JSONObject) ArrayList(java.util.ArrayList) JSONArray(com.ichi2.utils.JSONArray) ConfirmModSchemaException(com.ichi2.anki.exception.ConfirmModSchemaException) JSONException(com.ichi2.utils.JSONException)

Example 64 with DeckConfig

use of com.ichi2.libanki.DeckConfig in project AnkiChinaAndroid by ankichinateam.

the class AbstractSchedTest method undoAndRedo.

protected void undoAndRedo(boolean preload) {
    Collection col = getCol();
    DeckConfig conf = col.getDecks().confForDid(1);
    conf.getJSONObject("new").put("delays", new JSONArray(new double[] { 1, 3, 5, 10 }));
    col.getConf().put("collapseTime", 20 * 60);
    AbstractSched sched = col.getSched();
    Note note = addNoteUsingBasicModel("foo", "bar");
    col.reset();
    Card card = sched.getCard();
    assertNotNull(card);
    assertArrayEquals(new int[] { 1, 0, 0 }, sched.counts(card));
    if (preload) {
        sched.preloadNextCard();
    }
    sched.answerCard(card, sched.getGoodNewButton());
    card = sched.getCard();
    assertNotNull(card);
    assertArrayEquals(new int[] { 0, (schedVersion == 1) ? 3 : 1, 0 }, sched.counts(card));
    if (preload) {
        sched.preloadNextCard();
    }
    sched.answerCard(card, sched.getGoodNewButton());
    card = sched.getCard();
    assertNotNull(card);
    assertArrayEquals(new int[] { 0, (schedVersion == 1) ? 2 : 1, 0 }, sched.counts(card));
    if (preload) {
        sched.preloadNextCard();
    }
    assertNotNull(card);
    card = nonTaskUndo(col);
    assertNotNull(card);
    assertArrayEquals(new int[] { 0, (schedVersion == 1) ? 3 : 1, 0 }, sched.counts(card));
    sched.count();
    if (preload) {
        sched.preloadNextCard();
    }
    sched.answerCard(card, sched.getGoodNewButton());
    card = sched.getCard();
    assertNotNull(card);
    if (preload) {
        sched.preloadNextCard();
    }
    assertArrayEquals(new int[] { 0, (schedVersion == 1) ? 2 : 1, 0 }, sched.counts(card));
    assertNotNull(card);
}
Also used : Note(com.ichi2.libanki.Note) JSONArray(com.ichi2.utils.JSONArray) Collection(com.ichi2.libanki.Collection) DeckConfig(com.ichi2.libanki.DeckConfig) Card(com.ichi2.libanki.Card)

Example 65 with DeckConfig

use of com.ichi2.libanki.DeckConfig in project AnkiChinaAndroid by ankichinateam.

the class AbstractSchedTest method siblingCorrectlyBuried.

@Test
public void siblingCorrectlyBuried() {
    // #6903
    Collection col = getCol();
    AbstractSched sched = col.getSched();
    Models models = col.getModels();
    DeckConfig dconf = col.getDecks().getConf(1);
    dconf.getJSONObject("new").put("bury", true);
    final int nbNote = 2;
    Note[] notes = new Note[nbNote];
    for (int i = 0; i < nbNote; i++) {
        Note note = addNoteUsingBasicAndReversedModel("front", "back");
        notes[i] = note;
    }
    col.reset();
    for (int i = 0; i < nbNote; i++) {
        Card card = sched.getCard();
        assertArrayEquals(new int[] { nbNote * 2 - i, 0, 0 }, sched.counts(card));
        assertEquals(notes[i].firstCard().getId(), card.getId());
        assertEquals(Consts.QUEUE_TYPE_NEW, card.getQueue());
        sched.answerCard(card, sched.answerButtons(card));
    }
    Card card = sched.getCard();
    assertNull(card);
}
Also used : Note(com.ichi2.libanki.Note) Collection(com.ichi2.libanki.Collection) Models(com.ichi2.libanki.Models) DeckConfig(com.ichi2.libanki.DeckConfig) Card(com.ichi2.libanki.Card) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test)

Aggregations

DeckConfig (com.ichi2.libanki.DeckConfig)85 Collection (com.ichi2.libanki.Collection)57 Card (com.ichi2.libanki.Card)50 Test (org.junit.Test)49 RobolectricTest (com.ichi2.anki.RobolectricTest)48 Note (com.ichi2.libanki.Note)47 JSONArray (com.ichi2.utils.JSONArray)42 JSONObject (com.ichi2.utils.JSONObject)27 Deck (com.ichi2.libanki.Deck)14 NonNull (androidx.annotation.NonNull)12 Cursor (android.database.Cursor)5 JSONException (com.ichi2.utils.JSONException)5 ArrayList (java.util.ArrayList)5 Model (com.ichi2.libanki.Model)4 HashMap (java.util.HashMap)4 SuppressLint (android.annotation.SuppressLint)3 Map (java.util.Map)3 TreeMap (java.util.TreeMap)3 ContentValues (android.content.ContentValues)2 Intent (android.content.Intent)2