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
}
}
}
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());
}
}
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);
}
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));
}
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);
}
Aggregations