Search in sources :

Example 21 with ConfirmModSchemaException

use of com.ichi2.anki.exception.ConfirmModSchemaException in project Anki-Android by ankidroid.

the class ImportTest method csvManualBasicExample.

@Test
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
public void csvManualBasicExample() throws IOException, ConfirmModSchemaException {
    String file = Shared.getTestFilePath(getTestContext(), "text-anki-manual-csv-single-line.txt");
    addFieldToCurrentModel("Third");
    TextImporter i = new TextImporter(mTestCol, file);
    i.setAllowHtml(true);
    i.initMapping();
    i.run();
    Note n = mTestCol.getNote(mTestCol.getDb().queryLongScalar("select id from notes"));
    assertThat(Arrays.asList(n.getFields()), contains("foo bar", "bar baz", "baz quux"));
}
Also used : Note(com.ichi2.libanki.Note) TextImporter(com.ichi2.libanki.importer.TextImporter) Test(org.junit.Test) InstrumentedTest(com.ichi2.anki.tests.InstrumentedTest) SdkSuppress(androidx.test.filters.SdkSuppress)

Example 22 with ConfirmModSchemaException

use of com.ichi2.anki.exception.ConfirmModSchemaException in project Anki-Android by ankidroid.

the class ImportTest method testCsv2.

@Test
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
public void testCsv2() throws IOException, ConfirmModSchemaException {
    ModelManager mm = mTestCol.getModels();
    Model m = mm.current();
    JSONObject f = mm.newField("Three");
    mm.addField(m, f);
    mm.save(m);
    Note n = mTestCol.newNote();
    n.setField(0, "1");
    n.setField(1, "2");
    n.setField(2, "3");
    mTestCol.addNote(n);
    // an update with unmapped fields should not clobber those fields
    String file = Shared.getTestFilePath(getTestContext(), "text-update.txt");
    TextImporter i = new TextImporter(mTestCol, file);
    i.initMapping();
    i.run();
    n.load();
    List<String> fields = Arrays.asList(n.getFields());
    assertThat(fields, contains("1", "x", "3"));
}
Also used : JSONObject(com.ichi2.utils.JSONObject) Note(com.ichi2.libanki.Note) Model(com.ichi2.libanki.Model) ModelManager(com.ichi2.libanki.ModelManager) TextImporter(com.ichi2.libanki.importer.TextImporter) Test(org.junit.Test) InstrumentedTest(com.ichi2.anki.tests.InstrumentedTest) SdkSuppress(androidx.test.filters.SdkSuppress)

Example 23 with ConfirmModSchemaException

use of com.ichi2.anki.exception.ConfirmModSchemaException in project Anki-Android by ankidroid.

the class Collection method changeSchedulerVer.

public void changeSchedulerVer(Integer ver) throws ConfirmModSchemaException {
    if (ver == schedVer()) {
        return;
    }
    if (!fSupportedSchedulerVersions.contains(ver)) {
        throw new RuntimeException("Unsupported scheduler version");
    }
    modSchema();
    @SuppressLint("VisibleForTests") SchedV2 v2Sched = new SchedV2(this);
    clearUndo();
    if (ver == 1) {
        v2Sched.moveToV1();
    } else {
        v2Sched.moveToV2();
    }
    set_config("schedVer", ver);
    _loadScheduler();
}
Also used : SuppressLint(android.annotation.SuppressLint) SchedV2(com.ichi2.libanki.sched.SchedV2)

Example 24 with ConfirmModSchemaException

use of com.ichi2.anki.exception.ConfirmModSchemaException in project Anki-Android by ankidroid.

the class CardContentProvider method insert.

@Override
public Uri insert(@NonNull Uri uri, ContentValues values) {
    if (!hasReadWritePermission() && shouldEnforceQueryOrInsertSecurity()) {
        throwSecurityException("insert", uri);
    }
    Collection col = CollectionHelper.getInstance().getCol(mContext);
    if (col == null) {
        throw new IllegalStateException(COL_NULL_ERROR_MSG);
    }
    col.log(getLogMessage("insert", uri));
    // Find out what data the user is requesting
    int match = sUriMatcher.match(uri);
    switch(match) {
        case NOTES:
            {
                /* Insert new note with specified fields and tags
                 */
                Long modelId = values.getAsLong(FlashCardsContract.Note.MID);
                String flds = values.getAsString(FlashCardsContract.Note.FLDS);
                String tags = values.getAsString(FlashCardsContract.Note.TAGS);
                Models.AllowEmpty allowEmpty = Models.AllowEmpty.fromBoolean(values.getAsBoolean(FlashCardsContract.Note.ALLOW_EMPTY));
                // Create empty note
                com.ichi2.libanki.Note newNote = new com.ichi2.libanki.Note(col, col.getModels().get(modelId));
                // Set fields
                String[] fldsArray = Utils.splitFields(flds);
                // Check that correct number of flds specified
                if (fldsArray.length != newNote.getFields().length) {
                    throw new IllegalArgumentException("Incorrect flds argument : " + flds);
                }
                for (int idx = 0; idx < fldsArray.length; idx++) {
                    newNote.setField(idx, fldsArray[idx]);
                }
                // Set tags
                if (tags != null) {
                    newNote.setTagsFromStr(tags);
                }
                // Add to collection
                col.addNote(newNote, allowEmpty);
                col.save();
                return Uri.withAppendedPath(FlashCardsContract.Note.CONTENT_URI, Long.toString(newNote.getId()));
            }
        case NOTES_ID:
            // Note ID is generated automatically by libanki
            throw new IllegalArgumentException("Not possible to insert note with specific ID");
        case NOTES_ID_CARDS:
        case NOTES_ID_CARDS_ORD:
            // Cards are generated automatically by libanki
            throw new IllegalArgumentException("Not possible to insert cards directly (only through NOTES)");
        case MODELS:
            // Get input arguments
            String modelName = values.getAsString(FlashCardsContract.Model.NAME);
            String css = values.getAsString(FlashCardsContract.Model.CSS);
            Long did = values.getAsLong(FlashCardsContract.Model.DECK_ID);
            String fieldNames = values.getAsString(FlashCardsContract.Model.FIELD_NAMES);
            Integer numCards = values.getAsInteger(FlashCardsContract.Model.NUM_CARDS);
            Integer sortf = values.getAsInteger(FlashCardsContract.Model.SORT_FIELD_INDEX);
            Integer type = values.getAsInteger(FlashCardsContract.Model.TYPE);
            String latexPost = values.getAsString(FlashCardsContract.Model.LATEX_POST);
            String latexPre = values.getAsString(FlashCardsContract.Model.LATEX_PRE);
            // Throw exception if required fields empty
            if (modelName == null || fieldNames == null || numCards == null) {
                throw new IllegalArgumentException("Model name, field_names, and num_cards can't be empty");
            }
            if (did != null && col.getDecks().isDyn(did)) {
                throw new IllegalArgumentException("Cannot set a filtered deck as default deck for a model");
            }
            // Create a new model
            ModelManager mm = col.getModels();
            Model newModel = mm.newModel(modelName);
            try {
                // Add the fields
                String[] allFields = Utils.splitFields(fieldNames);
                for (String f : allFields) {
                    mm.addFieldInNewModel(newModel, mm.newField(f));
                }
                // Add some empty card templates
                for (int idx = 0; idx < numCards; idx++) {
                    String card_name = mContext.getResources().getString(R.string.card_n_name, idx + 1);
                    JSONObject t = Models.newTemplate(card_name);
                    t.put("qfmt", String.format("{{%s}}", allFields[0]));
                    String answerField = allFields[0];
                    if (allFields.length > 1) {
                        answerField = allFields[1];
                    }
                    t.put("afmt", String.format("{{FrontSide}}\\n\\n<hr id=answer>\\n\\n{{%s}}", answerField));
                    mm.addTemplateInNewModel(newModel, t);
                }
                // Add the CSS if specified
                if (css != null) {
                    newModel.put("css", css);
                }
                // Add the did if specified
                if (did != null) {
                    newModel.put("did", did);
                }
                if (sortf != null && sortf < allFields.length) {
                    newModel.put("sortf", sortf);
                }
                if (type != null) {
                    newModel.put("type", type);
                }
                if (latexPost != null) {
                    newModel.put("latexPost", latexPost);
                }
                if (latexPre != null) {
                    newModel.put("latexPre", latexPre);
                }
                // Add the model to collection (from this point on edits will require a full-sync)
                mm.add(newModel);
                col.save();
                // Get the mid and return a URI
                String mid = Long.toString(newModel.getLong("id"));
                return Uri.withAppendedPath(FlashCardsContract.Model.CONTENT_URI, mid);
            } catch (JSONException e) {
                Timber.e(e, "Could not set a field of new model %s", modelName);
                return null;
            }
        case MODELS_ID:
            // Model ID is generated automatically by libanki
            throw new IllegalArgumentException("Not possible to insert model with specific ID");
        case MODELS_ID_TEMPLATES:
            {
                ModelManager models = col.getModels();
                Long mid = getModelIdFromUri(uri, col);
                Model existingModel = models.get(mid);
                if (existingModel == null) {
                    throw new IllegalArgumentException("model missing: " + mid);
                }
                String name = values.getAsString(CardTemplate.NAME);
                String qfmt = values.getAsString(CardTemplate.QUESTION_FORMAT);
                String afmt = values.getAsString(CardTemplate.ANSWER_FORMAT);
                String bqfmt = values.getAsString(CardTemplate.BROWSER_QUESTION_FORMAT);
                String bafmt = values.getAsString(CardTemplate.BROWSER_ANSWER_FORMAT);
                try {
                    JSONObject t = Models.newTemplate(name);
                    t.put("qfmt", qfmt);
                    t.put("afmt", afmt);
                    t.put("bqfmt", bqfmt);
                    t.put("bafmt", bafmt);
                    models.addTemplate(existingModel, t);
                    models.save(existingModel);
                    col.save();
                    return ContentUris.withAppendedId(uri, t.getInt("ord"));
                } catch (ConfirmModSchemaException e) {
                    throw new IllegalArgumentException("Unable to add template without user requesting/accepting full-sync", e);
                } catch (JSONException e) {
                    throw new IllegalArgumentException("Unable to get ord from new template", e);
                }
            }
        case MODELS_ID_TEMPLATES_ID:
            throw new IllegalArgumentException("Not possible to insert template with specific ORD");
        case MODELS_ID_FIELDS:
            {
                ModelManager models = col.getModels();
                long mid = getModelIdFromUri(uri, col);
                Model existingModel = models.get(mid);
                if (existingModel == null) {
                    throw new IllegalArgumentException("model missing: " + mid);
                }
                String name = values.getAsString(FlashCardsContract.Model.FIELD_NAME);
                if (name == null) {
                    throw new IllegalArgumentException("field name missing for model: " + mid);
                }
                JSONObject field = models.newField(name);
                try {
                    models.addField(existingModel, field);
                    col.save();
                    JSONArray flds = existingModel.getJSONArray("flds");
                    return ContentUris.withAppendedId(uri, flds.length() - 1);
                } catch (ConfirmModSchemaException e) {
                    throw new IllegalArgumentException("Unable to insert field: " + name, e);
                } catch (JSONException e) {
                    throw new IllegalArgumentException("Unable to get newly created field: " + name, e);
                }
            }
        case SCHEDULE:
            // Doesn't make sense to insert an object into the schedule table
            throw new IllegalArgumentException("Not possible to perform insert operation on schedule");
        case DECKS:
            // Insert new deck with specified name
            String deckName = values.getAsString(FlashCardsContract.Deck.DECK_NAME);
            did = col.getDecks().id_for_name(deckName);
            if (did != null) {
                throw new IllegalArgumentException("Deck name already exists: " + deckName);
            }
            if (!Decks.isValidDeckName(deckName)) {
                throw new IllegalArgumentException("Invalid deck name '" + deckName + "'");
            }
            try {
                did = col.getDecks().id(deckName);
            } catch (DeckRenameException filteredSubdeck) {
                throw new IllegalArgumentException(filteredSubdeck.getMessage());
            }
            Deck deck = col.getDecks().get(did);
            if (deck != null) {
                try {
                    String deckDesc = values.getAsString(FlashCardsContract.Deck.DECK_DESC);
                    if (deckDesc != null) {
                        deck.put("desc", deckDesc);
                    }
                } catch (JSONException e) {
                    Timber.e(e, "Could not set a field of new deck %s", deckName);
                    return null;
                }
            }
            col.getDecks().flush();
            return Uri.withAppendedPath(FlashCardsContract.Deck.CONTENT_ALL_URI, Long.toString(did));
        case DECK_SELECTED:
            // Can't have more than one selected deck
            throw new IllegalArgumentException("Selected deck can only be queried and updated");
        case DECKS_ID:
            // Deck ID is generated automatically by libanki
            throw new IllegalArgumentException("Not possible to insert deck with specific ID");
        case MEDIA:
            // contentvalue should have data and preferredFileName values
            return insertMediaFile(values, col);
        default:
            // Unknown URI type
            throw new IllegalArgumentException("uri " + uri + " is not supported");
    }
}
Also used : Note(com.ichi2.libanki.Note) JSONArray(com.ichi2.utils.JSONArray) JSONException(com.ichi2.utils.JSONException) Deck(com.ichi2.libanki.Deck) ModelManager(com.ichi2.libanki.ModelManager) DeckRenameException(com.ichi2.libanki.backend.exception.DeckRenameException) JSONObject(com.ichi2.utils.JSONObject) Note(com.ichi2.libanki.Note) Model(com.ichi2.libanki.Model) Collection(com.ichi2.libanki.Collection) ConfirmModSchemaException(com.ichi2.anki.exception.ConfirmModSchemaException)

Example 25 with ConfirmModSchemaException

use of com.ichi2.anki.exception.ConfirmModSchemaException in project Anki-Android by ankidroid.

the class Models method remTemplate.

/**
 * {@inheritDoc}
 */
@Override
public void remTemplate(Model m, JSONObject template) throws ConfirmModSchemaException {
    if (m.getJSONArray("tmpls").length() <= 1) {
        return;
    }
    // find cards using this template
    JSONArray tmpls = m.getJSONArray("tmpls");
    int ord = -1;
    for (int i = 0; i < tmpls.length(); ++i) {
        if (tmpls.getJSONObject(i).equals(template)) {
            ord = i;
            break;
        }
    }
    if (ord == -1) {
        throw new IllegalArgumentException("Invalid template proposed for delete");
    }
    // the code in "isRemTemplateSafe" was in place here in libanki. It is extracted to a method for reuse
    List<Long> cids = getCardIdsForModel(m.getLong("id"), new int[] { ord });
    if (cids == null) {
        Timber.d("remTemplate getCardIdsForModel determined it was unsafe to delete the template");
        return;
    }
    // ok to proceed; remove cards
    Timber.d("remTemplate proceeding to delete the template and %d cards", cids.size());
    mCol.modSchema();
    mCol.remCards(cids);
    // shift ordinals
    mCol.getDb().execute("update cards set ord = ord - 1, usn = ?, mod = ? where nid in (select id from notes where mid = ?) and ord > ?", mCol.usn(), mCol.getTime().intTime(), m.getLong("id"), ord);
    tmpls = m.getJSONArray("tmpls");
    JSONArray tmpls2 = new JSONArray();
    for (int i = 0; i < tmpls.length(); ++i) {
        if (template.equals(tmpls.getJSONObject(i))) {
            continue;
        }
        tmpls2.put(tmpls.getJSONObject(i));
    }
    m.put("tmpls", tmpls2);
    _updateTemplOrds(m);
    save(m);
    Timber.d("remTemplate done working");
}
Also used : JSONArray(com.ichi2.utils.JSONArray)

Aggregations

JSONObject (com.ichi2.utils.JSONObject)39 ConfirmModSchemaException (com.ichi2.anki.exception.ConfirmModSchemaException)26 JSONArray (com.ichi2.utils.JSONArray)23 Test (org.junit.Test)22 RobolectricTest (com.ichi2.anki.RobolectricTest)14 ConfirmationDialog (com.ichi2.anki.dialogs.ConfirmationDialog)12 Collection (com.ichi2.libanki.Collection)12 Model (com.ichi2.libanki.Model)12 Note (com.ichi2.libanki.Note)8 ArrayList (java.util.ArrayList)8 JSONException (com.ichi2.utils.JSONException)6 HashMap (java.util.HashMap)5 SdkSuppress (androidx.test.filters.SdkSuppress)4 TaskData (com.ichi2.async.TaskData)4 ModelManager (com.ichi2.libanki.ModelManager)4 TextImporter (com.ichi2.libanki.importer.TextImporter)4 Matchers.containsString (org.hamcrest.Matchers.containsString)4 Cursor (android.database.Cursor)3 Uri (android.net.Uri)3 Bundle (android.os.Bundle)3