use of com.ichi2.anki.CardBrowser.Column.CARD in project AnkiChinaAndroid by ankichinateam.
the class Sched method _newConf.
/**
* Tools ******************************************************************** ***************************
*/
@Override
@NonNull
protected JSONObject _newConf(@NonNull Card card) {
DeckConfig conf = _cardConf(card);
// normal deck
if (card.getODid() == 0) {
return conf.getJSONObject("new");
}
// dynamic deck; override some attributes, use original deck for others
DeckConfig oconf = mCol.getDecks().confForDid(card.getODid());
JSONArray delays = conf.optJSONArray("delays");
if (delays == null) {
delays = oconf.getJSONObject("new").getJSONArray("delays");
}
JSONObject dict = new JSONObject();
// original deck
dict.put("ints", oconf.getJSONObject("new").getJSONArray("ints"));
dict.put("initialFactor", oconf.getJSONObject("new").getInt("initialFactor"));
dict.put("bury", oconf.getJSONObject("new").optBoolean("bury", true));
// overrides
dict.put("delays", delays);
dict.put("separate", conf.getBoolean("separate"));
dict.put("order", Consts.NEW_CARDS_DUE);
dict.put("perDay", mReportLimit);
return dict;
}
use of com.ichi2.anki.CardBrowser.Column.CARD in project AnkiChinaAndroid by ankichinateam.
the class SchedV2 method currentCardIsInQueueWithDeck.
protected boolean currentCardIsInQueueWithDeck(@Consts.CARD_QUEUE int queue, long did) {
// mCurrentCard may be set to null when the reviewer gets closed. So we copy it to be sure to avoid NullPointerException
Card currentCard = mCurrentCard;
List<Long> currentCardParentsDid = mCurrentCardParentsDid;
return currentCard != null && currentCard.getQueue() == queue && currentCardParentsDid != null && currentCardParentsDid.contains(did);
}
use of com.ichi2.anki.CardBrowser.Column.CARD in project AnkiChinaAndroid by ankichinateam.
the class SchedV2 method quickDeckDueTree.
/**
* Similar to deck due tree, but ignore the number of cards.
*
* It may takes a lot of time to compute the number of card, it
* requires multiple database access by deck. Ignoring this number
* lead to the creation of a tree more quickly.
*/
@Override
@NonNull
public List<DeckTreeNode> quickDeckDueTree() {
// Similar to deckDueTree, ignoring the numbers
// Similar to deckDueList
ArrayList<DeckTreeNode> data = new ArrayList<>();
for (JSONObject deck : mCol.getDecks().allSorted()) {
DeckTreeNode g = new DeckTreeNode(mCol, deck.getString("name"), deck.getLong("id"));
data.add(g);
}
return _groupChildren(data, false);
}
use of com.ichi2.anki.CardBrowser.Column.CARD in project AnkiChinaAndroid by ankichinateam.
the class Anki2Importer method _importCards.
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
mCards = new HashMap<>();
Map<Long, Boolean> existing = new HashMap<>();
Cursor cur = null;
try {
cur = mDst.getDb().getDatabase().query("select f.guid, c.ord, c.id from cards c, notes f " + "where c.nid = f.id", null);
while (cur.moveToNext()) {
String guid = cur.getString(0);
int ord = cur.getInt(1);
long cid = cur.getLong(2);
existing.put(cid, true);
if (mCards.containsKey(guid)) {
mCards.get(guid).put(ord, cid);
} else {
Map<Integer, Long> map = new HashMap<>();
map.put(ord, cid);
mCards.put(guid, map);
}
}
} finally {
if (cur != null) {
cur.close();
}
}
// loop through src
List<Object[]> cards = new ArrayList<>();
int totalCardCount = 0;
final int thresExecCards = 1000;
List<Object[]> revlog = new ArrayList<>();
int totalRevlogCount = 0;
final int thresExecRevlog = 1000;
int usn = mDst.usn();
long aheadBy = mSrc.getSched().getToday() - mDst.getSched().getToday();
try {
mDst.getDb().getDatabase().beginTransaction();
cur = mSrc.getDb().getDatabase().query("select f.guid, f.mid, c.* from cards c, notes f " + "where c.nid = f.id", null);
// Counters for progress updates
int total = cur.getCount();
boolean largeCollection = total > 200;
int onePercent = total / 100;
int i = 0;
while (cur.moveToNext()) {
Object[] card = new Object[] { cur.getString(0), cur.getLong(1), cur.getLong(2), cur.getLong(3), cur.getLong(4), cur.getInt(5), cur.getLong(6), cur.getInt(7), cur.getInt(8), cur.getInt(9), cur.getLong(10), cur.getLong(11), cur.getLong(12), cur.getInt(13), cur.getInt(14), cur.getInt(15), cur.getLong(16), cur.getLong(17), cur.getInt(18), cur.getString(19) };
String guid = (String) card[0];
if (mChangedGuids.containsKey(guid)) {
guid = mChangedGuids.get(guid);
}
if (mIgnoredGuids.containsKey(guid)) {
continue;
}
// does the card's note exist in dst col?
if (!mNotes.containsKey(guid)) {
continue;
}
Object[] dnid = mNotes.get(guid);
// does the card already exist in the dst col?
int ord = (Integer) card[5];
if (mCards.containsKey(guid) && mCards.get(guid).containsKey(ord)) {
// fixme: in future, could update if newer mod time
continue;
}
// doesn't exist. strip off note info, and save src id for later
Object[] oc = card;
card = new Object[oc.length - 2];
System.arraycopy(oc, 2, card, 0, card.length);
long scid = (Long) card[0];
// ensure the card id is unique
while (existing.containsKey(card[0])) {
card[0] = (Long) card[0] + 999;
}
existing.put((Long) card[0], true);
// update cid, nid, etc
card[1] = mNotes.get(guid)[0];
card[2] = _did((Long) card[2]);
if (mTopID < 0) {
mTopID = (long) card[2];
}
card[4] = mCol.getTime().intTime();
card[5] = usn;
// review cards have a due date relative to collection
if ((Integer) card[7] == 2 || (Integer) card[7] == 3 || (Integer) card[6] == 2) {
card[8] = (Long) card[8] - aheadBy;
}
// odue needs updating too
if (((Long) card[14]).longValue() != 0) {
card[14] = (Long) card[14] - aheadBy;
}
// if odid true, convert card from filtered to normal
if ((Long) card[15] != 0) {
// odid
card[15] = 0;
// odue
card[8] = card[14];
card[14] = 0;
// queue
if ((Integer) card[6] == 1) {
// type
card[7] = 0;
} else {
card[7] = card[6];
}
// type
if ((Integer) card[6] == 1) {
card[6] = 0;
}
}
cards.add(card);
// we need to import revlog, rewriting card ids and bumping usn
try (Cursor cur2 = mSrc.getDb().getDatabase().query("select * from revlog where cid = " + scid, null)) {
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] = card[0];
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 {
if (cur != null) {
cur.close();
}
if (mDst.getDb().getDatabase().inTransaction()) {
try {
mDst.getDb().getDatabase().endTransaction();
} catch (Exception e) {
Timber.w(e);
}
}
}
}
use of com.ichi2.anki.CardBrowser.Column.CARD in project AnkiChinaAndroid by ankichinateam.
the class NoteImporter method importNotes.
/**
* Convert each card into a note, apply attributes and add to col.
*/
public void importNotes(List<ForeignNote> notes) {
Assert.that(mappingOk());
// note whether tags are mapped
mTagsMapped = false;
for (String f : mMapping) {
if ("_tags".equals(f)) {
mTagsMapped = true;
break;
}
}
// gather checks for duplicate comparison
HashMap<Long, List<Long>> csums = new HashMap<>();
try (Cursor c = mCol.getDb().query("select csum, id from notes where mid = ?", mModel.getLong("id"))) {
while (c.moveToNext()) {
long csum = c.getLong(0);
long id = c.getLong(1);
if (csums.containsKey(csum)) {
csums.get(csum).add(id);
} else {
csums.put(csum, new ArrayList<>(Collections.singletonList(id)));
}
}
}
HashMap<String, Boolean> firsts = new HashMap<>();
int fld0index = mMapping.indexOf(mModel.getJSONArray("flds").getJSONObject(0).getString("name"));
mFMap = mCol.getModels().fieldMap(mModel);
mNextId = mCol.getTime().timestampID(mCol.getDb(), "notes");
// loop through the notes
List<Object[]> updates = new ArrayList<>();
List<String> updateLog = new ArrayList<>();
// PORT: Translations moved closer to their sources
List<Object[]> _new = new ArrayList<>();
_ids = new ArrayList<>();
_cards = new ArrayList<>();
mEmptyNotes = false;
int dupeCount = 0;
List<String> dupes = new ArrayList<>();
for (ForeignNote n : notes) {
for (int c = 0; c < n.mFields.size(); c++) {
if (!this.mAllowHTML) {
n.mFields.set(c, HtmlUtils.escape(n.mFields.get(c)));
}
n.mFields.set(c, n.mFields.get(c).trim());
if (!this.mAllowHTML) {
n.mFields.set(c, n.mFields.get(c).replace("\n", "<br>"));
}
}
String fld0 = n.mFields.get(fld0index);
long csum = fieldChecksum(fld0);
// first field must exist
if (fld0 == null || fld0.length() == 0) {
getLog().add(getString(R.string.note_importer_error_empty_first_field, TextUtils.join(" ", n.mFields)));
continue;
}
// earlier in import?
if (firsts.containsKey(fld0) && mImportMode != ADD_MODE) {
// duplicates in source file; log and ignore
getLog().add(getString(R.string.note_importer_error_appeared_twice, fld0));
continue;
}
firsts.put(fld0, true);
// already exists?
boolean found = false;
if (csums.containsKey(csum)) {
// csum is not a guarantee; have to check
for (Long id : csums.get(csum)) {
String flds = mCol.getDb().queryString("select flds from notes where id = ?", id);
String[] sflds = splitFields(flds);
if (fld0.equals(sflds[0])) {
// duplicate
found = true;
if (mImportMode == UPDATE_MODE) {
Object[] data = updateData(n, id, sflds);
if (data != null && data.length > 0) {
updates.add(data);
updateLog.add(getString(R.string.note_importer_error_first_field_matched, fld0));
dupeCount += 1;
found = true;
}
} else if (mImportMode == IGNORE_MODE) {
dupeCount += 1;
} else if (mImportMode == ADD_MODE) {
// allow duplicates in this case
if (!dupes.contains(fld0)) {
// only show message once, no matter how many
// duplicates are in the collection already
updateLog.add(getString(R.string.note_importer_error_added_duplicate_first_field, fld0));
dupes.add(fld0);
}
found = false;
}
}
}
}
// newly add
if (!found) {
Object[] data = newData(n);
if (data != null && data.length > 0) {
_new.add(data);
// note that we've seen this note once already
firsts.put(fld0, true);
}
}
}
addNew(_new);
addUpdates(updates);
// make sure to update sflds, etc
mCol.updateFieldCache(collection2Array(_ids));
// generate cards
if (!mCol.genCards(_ids).isEmpty()) {
this.getLog().add(0, getString(R.string.note_importer_empty_cards_found));
}
// apply scheduling updates
updateCards();
// we randomize or order here, to ensure that siblings
// have the same due#
long did = mCol.getDecks().selected();
DeckConfig conf = mCol.getDecks().confForDid(did);
// in order due?
if (conf.getJSONObject("new").getInt("order") == NEW_CARDS_RANDOM) {
mCol.getSched().randomizeCards(did);
}
String part1 = getQuantityString(R.plurals.note_importer_notes_added, _new.size());
String part2 = getQuantityString(R.plurals.note_importer_notes_updated, mUpdateCount);
int unchanged;
if (mImportMode == UPDATE_MODE) {
unchanged = dupeCount - mUpdateCount;
} else if (mImportMode == IGNORE_MODE) {
unchanged = dupeCount;
} else {
unchanged = 0;
}
String part3 = getQuantityString(R.plurals.note_importer_notes_unchanged, unchanged);
mLog.add(String.format("%s, %s, %s.", part1, part2, part3));
mLog.addAll(updateLog);
if (mEmptyNotes) {
mLog.add(getString(R.string.note_importer_error_empty_notes));
}
mTotal = _ids.size();
}
Aggregations