Search in sources :

Example 1 with DeckRenameException

use of com.ichi2.libanki.backend.exception.DeckRenameException in project AnkiChinaAndroid by ankichinateam.

the class DecksTest method test_rename.

@Test
public void test_rename() throws DeckRenameException {
    Collection col = getCol();
    long id = col.getDecks().id("hello::world");
    // should be able to rename into a completely different branch, creating
    // parents as necessary
    col.getDecks().rename(col.getDecks().get(id), "foo::bar");
    List<String> names = col.getDecks().allSortedNames();
    assertTrue(names.contains("foo"));
    assertTrue(names.contains("foo::bar"));
    assertFalse(names.contains("hello::world"));
    // create another col
    id = col.getDecks().id("tmp");
    /* TODO: do we want to follow upstream here ?
         // automatically adjusted if a duplicate name
         col.getDecks().rename(col.getDecks().get(id), "FOO");
         names =  col.getDecks().allSortedNames();
         assertThat(names, containsString("FOO+"));
         
          */
    // when renaming, the children should be renamed too
    col.getDecks().id("one::two::three");
    id = col.getDecks().id("one");
    col.getDecks().rename(col.getDecks().get(id), "yo");
    names = col.getDecks().allSortedNames();
    for (String n : new String[] { "yo", "yo::two", "yo::two::three" }) {
        assertTrue(names.contains(n));
    }
    // over filtered
    long filteredId = col.getDecks().newDyn("filtered");
    Deck filtered = col.getDecks().get(filteredId);
    long childId = col.getDecks().id("child");
    Deck child = col.getDecks().get(childId);
    assertThrows(DeckRenameException.class, () -> col.getDecks().rename(child, "filtered::child"));
    assertThrows(DeckRenameException.class, () -> col.getDecks().rename(child, "FILTERED::child"));
}
Also used : Matchers.containsString(org.hamcrest.Matchers.containsString) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test)

Example 2 with DeckRenameException

use of com.ichi2.libanki.backend.exception.DeckRenameException in project Anki-Android by ankidroid.

the class FilteredDeckUtil method createFilteredDeck.

public static long createFilteredDeck(Collection col, String name, String search) {
    long filteredDid = 0;
    try {
        filteredDid = col.getDecks().newDyn(name);
    } catch (DeckRenameException filteredAncestor) {
        throw new RuntimeException(filteredAncestor);
    }
    DeckConfig conf = col.getDecks().confForDid(filteredDid);
    conf.getJSONArray("terms").getJSONArray(0).put(0, search);
    col.getDecks().save(conf);
    return filteredDid;
}
Also used : DeckRenameException(com.ichi2.libanki.backend.exception.DeckRenameException) DeckConfig(com.ichi2.libanki.DeckConfig)

Example 3 with DeckRenameException

use of com.ichi2.libanki.backend.exception.DeckRenameException 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 4 with DeckRenameException

use of com.ichi2.libanki.backend.exception.DeckRenameException in project AnkiChinaAndroid by ankichinateam.

the class AnkiActivity method renameDeckDialog.

public void renameDeckDialog(final long did) {
    final Resources res = getResources();
    mDialogEditText = new EditText(this);
    mDialogEditText.setSingleLine();
    final String currentName = getCol().getDecks().name(did);
    mDialogEditText.setText(currentName);
    mDialogEditText.setSelection(mDialogEditText.getText().length());
    new MaterialDialog.Builder(this).title(res.getString(R.string.rename_deck)).customView(mDialogEditText, true).positiveText(res.getString(R.string.rename)).negativeText(res.getString(R.string.dialog_cancel)).onPositive((dialog, which) -> {
        String newName = mDialogEditText.getText().toString().replaceAll("\"", "");
        Collection col = getCol();
        if (!Decks.isValidDeckName(newName)) {
            Timber.i("renameDeckDialog not renaming deck to invalid name '%s'", newName);
            UIUtils.showThemedToast(this, getString(R.string.invalid_deck_name), false);
        } else if (!newName.equals(currentName)) {
            try {
                col.getDecks().rename(col.getDecks().get(did), newName);
            } catch (DeckRenameException e) {
                // We get a localized string from libanki to explain the error
                UIUtils.showThemedToast(this, e.getLocalizedMessage(res), false);
            }
        }
        dismissAllDialogFragments();
        try {
            refreshDeckListUI(true);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }).onNegative((dialog, which) -> dismissAllDialogFragments()).build().show();
}
Also used : EditText(android.widget.EditText) Bundle(android.os.Bundle) ParcelFileDescriptor(android.os.ParcelFileDescriptor) ProgressBar(android.widget.ProgressBar) NonNull(androidx.annotation.NonNull) Uri(android.net.Uri) ShareCompat(androidx.core.app.ShareCompat) DialogHandler(com.ichi2.anki.dialogs.DialogHandler) DELETE_DECK(com.ichi2.async.CollectionTask.TASK_TYPE.DELETE_DECK) AppCompatActivity(androidx.appcompat.app.AppCompatActivity) Decks(com.ichi2.libanki.Decks) NO_SPECIFIC_STATUS_BAR_COLOR(com.ichi2.themes.Themes.NO_SPECIFIC_STATUS_BAR_COLOR) Fragment(androidx.fragment.app.Fragment) JSONException(com.ichi2.utils.JSONException) ContextCompat(androidx.core.content.ContextCompat) TargetApi(android.annotation.TargetApi) CustomTabActivityHelper(com.ichi2.compat.customtabs.CustomTabActivityHelper) JSONObject(com.ichi2.utils.JSONObject) CustomTabsFallback(com.ichi2.compat.customtabs.CustomTabsFallback) BE_VIP(com.ichi2.anki.DeckPicker.BE_VIP) Nullable(androidx.annotation.Nullable) Consts(com.ichi2.libanki.Consts) OKHttpUtil(com.ichi2.utils.OKHttpUtil) MobclickAgent(com.umeng.analytics.MobclickAgent) CompatHelper(com.ichi2.compat.CompatHelper) SelfStudyActivity.saveLastDeckId(com.ichi2.anki.SelfStudyActivity.saveLastDeckId) IMPORT(com.ichi2.async.CollectionTask.TASK_TYPE.IMPORT) DialogFragment(androidx.fragment.app.DialogFragment) DeckPickerConfirmDeleteDeckDialog(com.ichi2.anki.dialogs.DeckPickerConfirmDeleteDeckDialog) NotificationCompat(androidx.core.app.NotificationCompat) BitmapFactory(android.graphics.BitmapFactory) IMPORT_REPLACE(com.ichi2.async.CollectionTask.TASK_TYPE.IMPORT_REPLACE) ArrayList(java.util.ArrayList) NO_WRITEABLE_PERMISSION(com.ichi2.anki.MyAccount.NO_WRITEABLE_PERMISSION) Toast(android.widget.Toast) SimpleMessageDialog(com.ichi2.anki.dialogs.SimpleMessageDialog) Connection(com.ichi2.async.Connection) Response(okhttp3.Response) Call(okhttp3.Call) FragmentManager(androidx.fragment.app.FragmentManager) FileOutputStream(java.io.FileOutputStream) IOException(java.io.IOException) CustomTabsHelper(com.ichi2.compat.customtabs.CustomTabsHelper) File(java.io.File) SharedPreferences(android.content.SharedPreferences) TypedValue(android.util.TypedValue) TreeMap(java.util.TreeMap) CustomStudyDialog(com.ichi2.anki.dialogs.CustomStudyDialog) ImportUtils(com.ichi2.utils.ImportUtils) TAB_MAIN_STATE(com.ichi2.anki.SelfStudyActivity.TAB_MAIN_STATE) ActivityTransitionAnimation(com.ichi2.anim.ActivityTransitionAnimation) EditText(android.widget.EditText) AsyncDialogFragment(com.ichi2.anki.dialogs.AsyncDialogFragment) WindowManager(android.view.WindowManager) UsageAnalytics(com.ichi2.anki.analytics.UsageAnalytics) ExportDialog(com.ichi2.anki.dialogs.ExportDialog) PendingIntent(android.app.PendingIntent) CustomTabsIntent(androidx.browser.customtabs.CustomTabsIntent) AnkiChinaSyncer(com.ichi2.libanki.sync.AnkiChinaSyncer) FormBody(okhttp3.FormBody) TimeUtils(com.ichi2.libanki.utils.TimeUtils) View(android.view.View) TaskData(com.ichi2.async.TaskData) Animation(android.view.animation.Animation) REQUEST_BROWSE_CARDS(com.ichi2.anki.DeckPicker.REQUEST_BROWSE_CARDS) NotificationManager(android.app.NotificationManager) FragmentTransaction(androidx.fragment.app.FragmentTransaction) DatabaseErrorDialog(com.ichi2.anki.dialogs.DatabaseErrorDialog) Timber(timber.log.Timber) LayoutParams(android.view.ViewGroup.LayoutParams) CollectionLoader(com.ichi2.async.CollectionLoader) List(java.util.List) REBUILD_CRAM(com.ichi2.async.CollectionTask.TASK_TYPE.REBUILD_CRAM) ActivityNotFoundException(android.content.ActivityNotFoundException) FileProvider(androidx.core.content.FileProvider) Toolbar(androidx.appcompat.widget.Toolbar) TaskListenerWithContext(com.ichi2.async.TaskListenerWithContext) MaterialDialog(com.afollestad.materialdialogs.MaterialDialog) DeckRenameException(com.ichi2.anki.exception.DeckRenameException) Context(android.content.Context) TaskListener(com.ichi2.async.TaskListener) EXPORT_APKG(com.ichi2.async.CollectionTask.TASK_TYPE.EXPORT_APKG) ImportDialog(com.ichi2.anki.dialogs.ImportDialog) Intent(android.content.Intent) REFRESH_LOGIN_STATE_AND_TURN_TO_VIP_HTML(com.ichi2.anki.DeckPicker.REFRESH_LOGIN_STATE_AND_TURN_TO_VIP_HTML) CONFIRM_PRIVATE_STRATEGY(com.ichi2.anki.DeckPicker.CONFIRM_PRIVATE_STRATEGY) Collection(com.ichi2.libanki.Collection) AudioManager(android.media.AudioManager) MenuItem(android.view.MenuItem) RequestBody(okhttp3.RequestBody) EMPTY_CRAM(com.ichi2.async.CollectionTask.TASK_TYPE.EMPTY_CRAM) Model(com.ichi2.libanki.Model) Build(android.os.Build) Utils(com.ichi2.libanki.Utils) TOKEN_IS_EXPIRED(com.ichi2.anki.MyAccount.TOKEN_IS_EXPIRED) Iterator(java.util.Iterator) CollectionTask(com.ichi2.async.CollectionTask) Themes(com.ichi2.themes.Themes) Color(android.graphics.Color) AdaptionUtil(com.ichi2.utils.AdaptionUtil) Activity(android.app.Activity) CustomStyleDialog(com.ichi2.ui.CustomStyleDialog) Resources(android.content.res.Resources) DeckRenameException(com.ichi2.anki.exception.DeckRenameException) Collection(com.ichi2.libanki.Collection) Resources(android.content.res.Resources) JSONException(com.ichi2.utils.JSONException) IOException(java.io.IOException) ActivityNotFoundException(android.content.ActivityNotFoundException) DeckRenameException(com.ichi2.anki.exception.DeckRenameException)

Aggregations

DeckRenameException (com.ichi2.libanki.backend.exception.DeckRenameException)2 TargetApi (android.annotation.TargetApi)1 Activity (android.app.Activity)1 NotificationManager (android.app.NotificationManager)1 PendingIntent (android.app.PendingIntent)1 ActivityNotFoundException (android.content.ActivityNotFoundException)1 Context (android.content.Context)1 Intent (android.content.Intent)1 SharedPreferences (android.content.SharedPreferences)1 Resources (android.content.res.Resources)1 BitmapFactory (android.graphics.BitmapFactory)1 Color (android.graphics.Color)1 AudioManager (android.media.AudioManager)1 Uri (android.net.Uri)1 Build (android.os.Build)1 Bundle (android.os.Bundle)1 ParcelFileDescriptor (android.os.ParcelFileDescriptor)1 TypedValue (android.util.TypedValue)1 MenuItem (android.view.MenuItem)1 View (android.view.View)1