Search in sources :

Example 46 with TAGS

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();
}
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 47 with TAGS

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;
    }
}
Also used : ContentValues(android.content.ContentValues) JSONObject(com.ichi2.utils.JSONObject) TreeMap(java.util.TreeMap) Map(java.util.Map)

Example 48 with TAGS

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;
}
Also used : JSONObject(com.ichi2.utils.JSONObject)

Example 49 with TAGS

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();
    }
}
Also used : JSONArray(com.ichi2.utils.JSONArray) Model(com.ichi2.libanki.Model) Resources(android.content.res.Resources) CollectionTask(com.ichi2.async.CollectionTask) ConfirmationDialog(com.ichi2.anki.dialogs.ConfirmationDialog) VisibleForTesting(androidx.annotation.VisibleForTesting)

Example 50 with TAGS

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);
}
Also used : ArrayList(java.util.ArrayList) TagsDialog(com.ichi2.anki.dialogs.tags.TagsDialog)

Aggregations

JSONObject (com.ichi2.utils.JSONObject)27 Note (com.ichi2.libanki.Note)18 JSONArray (com.ichi2.utils.JSONArray)18 ArrayList (java.util.ArrayList)13 Card (com.ichi2.libanki.Card)12 Collection (com.ichi2.libanki.Collection)12 Model (com.ichi2.libanki.Model)11 Map (java.util.Map)10 HashMap (java.util.HashMap)9 SuppressLint (android.annotation.SuppressLint)8 Resources (android.content.res.Resources)8 Deck (com.ichi2.libanki.Deck)8 JSONException (com.ichi2.utils.JSONException)8 JSONException (org.json.JSONException)8 Intent (android.content.Intent)7 View (android.view.View)7 TextView (android.widget.TextView)7 Pair (android.util.Pair)5 ContentValues (android.content.ContentValues)4 Uri (android.net.Uri)4