Search in sources :

Example 51 with CHANGED

use of com.ichi2.anki.CardBrowser.Column.CHANGED in project Anki-Android by ankidroid.

the class CardContentProvider method query.

@Override
public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String order) {
    if (!hasReadWritePermission() && shouldEnforceQueryOrInsertSecurity()) {
        throwSecurityException("query", uri);
    }
    Collection col = CollectionHelper.getInstance().getCol(mContext);
    if (col == null) {
        throw new IllegalStateException(COL_NULL_ERROR_MSG);
    }
    Timber.d(getLogMessage("query", uri));
    // Find out what data the user is requesting
    int match = sUriMatcher.match(uri);
    switch(match) {
        case NOTES_V2:
            {
                /* Search for notes using direct SQL query */
                String[] proj = sanitizeNoteProjection(projection);
                String sql = SQLiteQueryBuilder.buildQueryString(false, "notes", proj, selection, null, null, order, null);
                // Needed for varargs of query
                return col.getDb().query(sql, (Object[]) selectionArgs);
            }
        case NOTES:
            {
                /* Search for notes using the libanki browser syntax */
                String[] proj = sanitizeNoteProjection(projection);
                String query = (selection != null) ? selection : "";
                List<Long> noteIds = col.findNotes(query);
                if ((noteIds != null) && (!noteIds.isEmpty())) {
                    String sel = String.format("id in (%s)", TextUtils.join(",", noteIds));
                    String sql = SQLiteQueryBuilder.buildQueryString(false, "notes", proj, sel, null, null, order, null);
                    return col.getDb().getDatabase().query(sql);
                } else {
                    return null;
                }
            }
        case NOTES_ID:
            {
                /* Direct access note with specific ID*/
                String noteId = uri.getPathSegments().get(1);
                String[] proj = sanitizeNoteProjection(projection);
                String sql = SQLiteQueryBuilder.buildQueryString(false, "notes", proj, "id=?", null, null, order, null);
                return col.getDb().query(sql, noteId);
            }
        case NOTES_ID_CARDS:
            {
                Note currentNote = getNoteFromUri(uri, col);
                String[] columns = ((projection != null) ? projection : FlashCardsContract.Card.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, 1);
                for (Card currentCard : currentNote.cards()) {
                    addCardToCursor(currentCard, rv, col, columns);
                }
                return rv;
            }
        case NOTES_ID_CARDS_ORD:
            {
                Card currentCard = getCardFromUri(uri, col);
                String[] columns = ((projection != null) ? projection : FlashCardsContract.Card.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, 1);
                addCardToCursor(currentCard, rv, col, columns);
                return rv;
            }
        case MODELS:
            {
                ModelManager models = col.getModels();
                String[] columns = ((projection != null) ? projection : FlashCardsContract.Model.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, 1);
                for (Long modelId : models.getModels().keySet()) {
                    addModelToCursor(modelId, models, rv, columns);
                }
                return rv;
            }
        case MODELS_ID:
            {
                long modelId = getModelIdFromUri(uri, col);
                String[] columns = ((projection != null) ? projection : FlashCardsContract.Model.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, 1);
                addModelToCursor(modelId, col.getModels(), rv, columns);
                return rv;
            }
        case MODELS_ID_TEMPLATES:
            {
                /* Direct access model templates */
                ModelManager models = col.getModels();
                Model currentModel = models.get(getModelIdFromUri(uri, col));
                String[] columns = ((projection != null) ? projection : CardTemplate.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, 1);
                try {
                    JSONArray templates = currentModel.getJSONArray("tmpls");
                    for (int idx = 0; idx < templates.length(); idx++) {
                        JSONObject template = templates.getJSONObject(idx);
                        addTemplateToCursor(template, currentModel, idx + 1, models, rv, columns);
                    }
                } catch (JSONException e) {
                    throw new IllegalArgumentException("Model is malformed", e);
                }
                return rv;
            }
        case MODELS_ID_TEMPLATES_ID:
            {
                /* Direct access model template with specific ID */
                ModelManager models = col.getModels();
                int ord = Integer.parseInt(uri.getLastPathSegment());
                Model currentModel = models.get(getModelIdFromUri(uri, col));
                String[] columns = ((projection != null) ? projection : CardTemplate.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, 1);
                try {
                    JSONObject template = getTemplateFromUri(uri, col);
                    addTemplateToCursor(template, currentModel, ord + 1, models, rv, columns);
                } catch (JSONException e) {
                    throw new IllegalArgumentException("Model is malformed", e);
                }
                return rv;
            }
        case SCHEDULE:
            {
                String[] columns = ((projection != null) ? projection : FlashCardsContract.ReviewInfo.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, 1);
                long selectedDeckBeforeQuery = col.getDecks().selected();
                long deckIdOfTemporarilySelectedDeck = -1;
                // the number of scheduled cards to return
                int limit = 1;
                int selectionArgIndex = 0;
                // parsing the selection arguments
                if (selection != null) {
                    // split selection to get arguments like "limit=?"
                    String[] args = selection.split(",");
                    for (String arg : args) {
                        // split arguments into key ("limit") and value ("?")
                        String[] keyAndValue = arg.split("=");
                        try {
                            // check if value is a placeholder ("?"), if so replace with the next value of selectionArgs
                            String value = "?".equals(keyAndValue[1].trim()) ? selectionArgs[selectionArgIndex++] : keyAndValue[1];
                            if ("limit".equals(keyAndValue[0].trim())) {
                                limit = Integer.parseInt(value);
                            } else if ("deckID".equals(keyAndValue[0].trim())) {
                                deckIdOfTemporarilySelectedDeck = Long.parseLong(value);
                                if (!selectDeckWithCheck(col, deckIdOfTemporarilySelectedDeck)) {
                                    // if the provided deckID is wrong, return empty cursor.
                                    return rv;
                                }
                            }
                        } catch (NumberFormatException nfe) {
                            Timber.w(nfe);
                        }
                    }
                }
                // retrieve the number of cards provided by the selection parameter "limit"
                col.getSched().deferReset();
                for (int k = 0; k < limit; k++) {
                    Card currentCard = col.getSched().getCard();
                    if (currentCard == null) {
                        break;
                    }
                    int buttonCount = col.getSched().answerButtons(currentCard);
                    JSONArray buttonTexts = new JSONArray();
                    for (int i = 0; i < buttonCount; i++) {
                        buttonTexts.put(col.getSched().nextIvlStr(mContext, currentCard, i + 1));
                    }
                    addReviewInfoToCursor(currentCard, buttonTexts, buttonCount, rv, col, columns);
                }
                if (deckIdOfTemporarilySelectedDeck != -1) {
                    // if the selected deck was changed
                    // change the selected deck back to the one it was before the query
                    col.getDecks().select(selectedDeckBeforeQuery);
                }
                return rv;
            }
        case DECKS:
            {
                List<DeckDueTreeNode> allDecks = col.getSched().deckDueList();
                String[] columns = ((projection != null) ? projection : FlashCardsContract.Deck.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, allDecks.size());
                for (DeckDueTreeNode deck : allDecks) {
                    long id = deck.getDid();
                    String name = deck.getFullDeckName();
                    addDeckToCursor(id, name, getDeckCountsFromDueTreeNode(deck), rv, col, columns);
                }
                return rv;
            }
        case DECKS_ID:
            {
                /* Direct access deck */
                String[] columns = ((projection != null) ? projection : FlashCardsContract.Deck.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, 1);
                List<DeckDueTreeNode> allDecks = col.getSched().deckDueList();
                long deckId = Long.parseLong(uri.getPathSegments().get(1));
                for (DeckDueTreeNode deck : allDecks) {
                    if (deck.getDid() == deckId) {
                        addDeckToCursor(deckId, deck.getFullDeckName(), getDeckCountsFromDueTreeNode(deck), rv, col, columns);
                        return rv;
                    }
                }
                return rv;
            }
        case DECK_SELECTED:
            {
                long id = col.getDecks().selected();
                String name = col.getDecks().name(id);
                String[] columns = ((projection != null) ? projection : FlashCardsContract.Deck.DEFAULT_PROJECTION);
                MatrixCursor rv = new MatrixCursor(columns, 1);
                JSONArray counts = new JSONArray(Collections.singletonList(col.getSched().counts()));
                addDeckToCursor(id, name, counts, rv, col, columns);
                return rv;
            }
        default:
            // Unknown URI type
            throw new IllegalArgumentException("uri " + uri + " is not supported");
    }
}
Also used : JSONArray(com.ichi2.utils.JSONArray) JSONException(com.ichi2.utils.JSONException) ModelManager(com.ichi2.libanki.ModelManager) MatrixCursor(android.database.MatrixCursor) Card(com.ichi2.libanki.Card) DeckDueTreeNode(com.ichi2.libanki.sched.DeckDueTreeNode) JSONObject(com.ichi2.utils.JSONObject) Note(com.ichi2.libanki.Note) Model(com.ichi2.libanki.Model) Collection(com.ichi2.libanki.Collection) List(java.util.List) ArrayList(java.util.ArrayList)

Example 52 with CHANGED

use of com.ichi2.anki.CardBrowser.Column.CHANGED in project Anki-Android by ankidroid.

the class CardContentProvider method addModelToCursor.

private void addModelToCursor(Long modelId, ModelManager models, MatrixCursor rv, String[] columns) {
    Model jsonObject = models.get(modelId);
    MatrixCursor.RowBuilder rb = rv.newRow();
    try {
        for (String column : columns) {
            switch(column) {
                case FlashCardsContract.Model._ID:
                    rb.add(modelId);
                    break;
                case FlashCardsContract.Model.NAME:
                    rb.add(jsonObject.getString("name"));
                    break;
                case FlashCardsContract.Model.FIELD_NAMES:
                    JSONArray flds = jsonObject.getJSONArray("flds");
                    String[] allFlds = new String[flds.length()];
                    for (int idx = 0; idx < flds.length(); idx++) {
                        allFlds[idx] = flds.getJSONObject(idx).optString("name", "");
                    }
                    rb.add(Utils.joinFields(allFlds));
                    break;
                case FlashCardsContract.Model.NUM_CARDS:
                    rb.add(jsonObject.getJSONArray("tmpls").length());
                    break;
                case FlashCardsContract.Model.CSS:
                    rb.add(jsonObject.getString("css"));
                    break;
                case FlashCardsContract.Model.DECK_ID:
                    // #6378 - Anki Desktop changed schema temporarily to allow null
                    rb.add(jsonObject.optLong("did", Consts.DEFAULT_DECK_ID));
                    break;
                case FlashCardsContract.Model.SORT_FIELD_INDEX:
                    rb.add(jsonObject.getLong("sortf"));
                    break;
                case FlashCardsContract.Model.TYPE:
                    rb.add(jsonObject.getLong("type"));
                    break;
                case FlashCardsContract.Model.LATEX_POST:
                    rb.add(jsonObject.getString("latexPost"));
                    break;
                case FlashCardsContract.Model.LATEX_PRE:
                    rb.add(jsonObject.getString("latexPre"));
                    break;
                case FlashCardsContract.Model.NOTE_COUNT:
                    rb.add(models.useCount(jsonObject));
                    break;
                default:
                    throw new UnsupportedOperationException("Queue \"" + column + "\" is unknown");
            }
        }
    } catch (JSONException e) {
        Timber.e(e, "Error parsing JSONArray");
        throw new IllegalArgumentException("Model " + modelId + " is malformed", e);
    }
}
Also used : Model(com.ichi2.libanki.Model) JSONArray(com.ichi2.utils.JSONArray) JSONException(com.ichi2.utils.JSONException) MatrixCursor(android.database.MatrixCursor)

Example 53 with CHANGED

use of com.ichi2.anki.CardBrowser.Column.CHANGED in project Anki-Android by ankidroid.

the class ImportTest method testAnki2DiffmodelTemplates.

@Test
public void testAnki2DiffmodelTemplates() throws IOException, JSONException, ImportExportException {
    // different from the above as this one tests only the template text being
    // changed, not the number of cards/fields
    // import the first version of the model
    String tmp = Shared.getTestFilePath(getTestContext(), "diffmodeltemplates-1.apkg");
    AnkiPackageImporter imp = new AnkiPackageImporter(mTestCol, tmp);
    imp.setDupeOnSchemaChange(true);
    imp.run();
    // then the version with updated template
    tmp = Shared.getTestFilePath(getTestContext(), "diffmodeltemplates-2.apkg");
    imp = new AnkiPackageImporter(mTestCol, tmp);
    imp.setDupeOnSchemaChange(true);
    imp.run();
    // collection should contain the note we imported
    assertEquals(1, mTestCol.noteCount());
    // the front template should contain the text added in the 2nd package
    Long tcid = mTestCol.findCards("").get(0);
    Note tnote = mTestCol.getCard(tcid).note();
    assertTrue(mTestCol.findTemplates(tnote).get(0).getString("qfmt").contains("Changed Front Template"));
}
Also used : AnkiPackageImporter(com.ichi2.libanki.importer.AnkiPackageImporter) Note(com.ichi2.libanki.Note) Test(org.junit.Test) InstrumentedTest(com.ichi2.anki.tests.InstrumentedTest)

Example 54 with CHANGED

use of com.ichi2.anki.CardBrowser.Column.CHANGED in project Anki-Android by ankidroid.

the class NoteServiceTest method updateJsonNoteTest.

// tests if the text fields of the notes are the same after calling updateJsonNoteFromMultimediaNote
@Test
public void updateJsonNoteTest() {
    Model testModel = mTestCol.getModels().byName("Basic");
    IMultimediaEditableNote multiMediaNote = NoteService.createEmptyNote(testModel);
    multiMediaNote.getField(0).setText("foo");
    multiMediaNote.getField(1).setText("bar");
    Note basicNote = new Note(mTestCol, testModel);
    basicNote.setField(0, "this should be changed to foo");
    basicNote.setField(1, "this should be changed to bar");
    NoteService.updateJsonNoteFromMultimediaNote(multiMediaNote, basicNote);
    assertEquals(basicNote.getFields()[0], multiMediaNote.getField(0).getText());
    assertEquals(basicNote.getFields()[1], multiMediaNote.getField(1).getText());
}
Also used : Note(com.ichi2.libanki.Note) IMultimediaEditableNote(com.ichi2.anki.multimediacard.IMultimediaEditableNote) Model(com.ichi2.libanki.Model) IMultimediaEditableNote(com.ichi2.anki.multimediacard.IMultimediaEditableNote) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test)

Example 55 with CHANGED

use of com.ichi2.anki.CardBrowser.Column.CHANGED in project Anki-Android by ankidroid.

the class ReviewerNoParamTest method whiteboardPenColorChangeChangesDatabaseDark.

@Test
public void whiteboardPenColorChangeChangesDatabaseDark() {
    enableDarkMode();
    Whiteboard whiteboard = startReviewerForWhiteboard();
    whiteboard.setPenColor(ARBITRARY_PEN_COLOR_VALUE);
    WhiteboardPenColor penColor = getPenColor();
    assertThat("Dark pen color is changed", penColor.getDarkPenColor(), is(ARBITRARY_PEN_COLOR_VALUE));
}
Also used : WhiteboardPenColor(com.ichi2.anki.model.WhiteboardPenColor) Test(org.junit.Test)

Aggregations

JSONObject (com.ichi2.utils.JSONObject)19 Test (org.junit.Test)19 Note (com.ichi2.libanki.Note)16 Card (com.ichi2.libanki.Card)15 Collection (com.ichi2.libanki.Collection)15 Model (com.ichi2.libanki.Model)12 Intent (android.content.Intent)9 JSONArray (com.ichi2.utils.JSONArray)9 JSONException (com.ichi2.utils.JSONException)8 List (java.util.List)7 ShadowActivity (org.robolectric.shadows.ShadowActivity)7 ArrayList (java.util.ArrayList)6 Map (java.util.Map)6 ShadowIntent (org.robolectric.shadows.ShadowIntent)6 ConfirmModSchemaException (com.ichi2.anki.exception.ConfirmModSchemaException)5 Cursor (android.database.Cursor)4 MatrixCursor (android.database.MatrixCursor)4 TaskData (com.ichi2.async.TaskData)4 Deck (com.ichi2.libanki.Deck)4 AbstractSched (com.ichi2.libanki.sched.AbstractSched)4