use of com.ichi2.anki.CardBrowser.Column.TAGS 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();
}
use of com.ichi2.anki.CardBrowser.Column.TAGS in project Anki-Android by ankidroid.
the class Tags method flush.
public void flush() {
if (mChanged) {
JSONObject tags = new JSONObject();
for (Map.Entry<String, Integer> t : mTags.entrySet()) {
tags.put(t.getKey(), t.getValue());
}
ContentValues val = new ContentValues();
val.put("tags", Utils.jsonToString(tags));
// TODO: the database update call here sets mod = true. Verify if this is intended.
mCol.getDb().update("col", val);
mChanged = false;
}
}
use of com.ichi2.anki.CardBrowser.Column.TAGS in project Anki-Android by ankidroid.
the class Tags method load.
public void load(@NonNull String json) {
JSONObject tags = new JSONObject(json);
for (String t : tags) {
mTags.put(t, tags.getInt(t));
}
mChanged = false;
}
use of com.ichi2.anki.CardBrowser.Column.TAGS in project Anki-Android by ankidroid.
the class NoteEditor method saveNote.
@VisibleForTesting
void saveNote() {
final Resources res = getResources();
if (mSelectedTags == null) {
mSelectedTags = new ArrayList<>(0);
}
saveToggleStickyMap();
// treat add new note and edit existing note independently
if (mAddNote) {
// DEFECT: This does not block addition if cloze transpositions are in non-cloze fields.
if (isClozeType() && !hasClozeDeletions()) {
displayErrorSavingNote();
return;
}
// load all of the fields into the note
for (FieldEditText f : mEditFields) {
updateField(f);
}
// Save deck to model
mEditorNote.model().put("did", mCurrentDid);
// Save tags to model
mEditorNote.setTagsFromStr(tagsAsString(mSelectedTags));
JSONArray tags = new JSONArray();
for (String t : mSelectedTags) {
tags.put(t);
}
getCol().getModels().current().put("tags", tags);
getCol().getModels().setChanged();
mReloadRequired = true;
TaskManager.launchCollectionTask(new CollectionTask.AddNote(mEditorNote), saveNoteHandler());
updateFieldsFromStickyText();
} else {
// Check whether note type has been changed
final Model newModel = getCurrentlySelectedModel();
final Model oldModel = (mCurrentEditedCard == null) ? null : mCurrentEditedCard.model();
if (!newModel.equals(oldModel)) {
mReloadRequired = true;
if (mModelChangeCardMap.size() < mEditorNote.numberOfCards() || mModelChangeCardMap.containsValue(null)) {
// If cards will be lost via the new mapping then show a confirmation dialog before proceeding with the change
ConfirmationDialog dialog = new ConfirmationDialog();
dialog.setArgs(res.getString(R.string.confirm_map_cards_to_nothing));
Runnable confirm = () -> {
// Bypass the check once the user confirms
changeNoteTypeWithErrorHandling(oldModel, newModel);
};
dialog.setConfirm(confirm);
showDialogFragment(dialog);
} else {
// Otherwise go straight to changing note type
changeNoteTypeWithErrorHandling(oldModel, newModel);
}
return;
}
// Regular changes in note content
boolean modified = false;
// changed did? this has to be done first as remFromDyn() involves a direct write to the database
if (mCurrentEditedCard != null && mCurrentEditedCard.getDid() != mCurrentDid) {
mReloadRequired = true;
// remove card from filtered deck first (if relevant)
getCol().getSched().remFromDyn(new long[] { mCurrentEditedCard.getId() });
// refresh the card object to reflect the database changes in remFromDyn()
mCurrentEditedCard.load();
// also reload the note object
mEditorNote = mCurrentEditedCard.note();
// then set the card ID to the new deck
mCurrentEditedCard.setDid(mCurrentDid);
modified = true;
}
// now load any changes to the fields from the form
for (FieldEditText f : mEditFields) {
modified = modified | updateField(f);
}
// added tag?
for (String t : mSelectedTags) {
modified = modified || !mEditorNote.hasTag(t);
}
// removed tag?
modified = modified || mEditorNote.getTags().size() > mSelectedTags.size();
if (modified) {
mEditorNote.setTagsFromStr(tagsAsString(mSelectedTags));
mChanged = true;
}
closeNoteEditor();
}
}
use of com.ichi2.anki.CardBrowser.Column.TAGS in project Anki-Android by ankidroid.
the class NoteEditor method showTagsDialog.
private void showTagsDialog() {
if (mSelectedTags == null) {
mSelectedTags = new ArrayList<>(0);
}
ArrayList<String> tags = new ArrayList<>(getCol().getTags().all());
ArrayList<String> selTags = new ArrayList<>(mSelectedTags);
TagsDialog dialog = mTagsDialogFactory.newTagsDialog().withArguments(TagsDialog.DialogType.EDIT_TAGS, selTags, tags);
showDialogFragment(dialog);
}
Aggregations