Warning, /education/gcompris/src/core/Wordlist.qml is written in an unsupported language. File is not indexed.

0001 /* GCompris - Wordlist.qml
0002  *
0003  * SPDX-FileCopyrightText: 2014 Holger Kaelberer <holger.k@elberer.de>
0004  *
0005  * Authors:
0006  *   Holger Kaelberer <holger.k@elberer.de>
0007  *
0008  *   SPDX-License-Identifier: GPL-3.0-or-later
0009  */
0010 import QtQuick 2.12
0011 import GCompris 1.0
0012 import "core.js" as Core
0013 
0014 /**
0015  * A Wordlist component loads and maintains GCompris wordlists.
0016  * @ingroup components
0017  *
0018  * It loads wordlists from json-files, validates its content and exposes
0019  * wordlists and levels to activities.
0020  *
0021  * It expects and returns the following wordlist format (UTF8 encoded):
0022  *
0023  * @code
0024  * {
0025  *    "name":"default-gd",
0026  *    "description":"GĂ idhlig",
0027  *    "locale":"gd",
0028  *    "levels":[ { "level":1,
0029  *                 "speed":150,                           <-- optional
0030  *                 "fallspeed":7000,                      <-- optional
0031  *                 "sublevels":10,                        <-- optional
0032  *                 "words":["a","jim", "beam", ... ]},    <-- mandatory
0033  *               { "level":2, ... }
0034  *             ]
0035  * }
0036  * @endcode
0037  *
0038  * @inherit QtQuick.Item
0039  * @sa JsonParser
0040  */
0041 Item {
0042     id: wordlist
0043 
0044     /**
0045      * type:string
0046      * Default filename to be used if the language specific wordlist file could
0047      * not be loaded.
0048      * Default is emtpy.
0049      */
0050     property string defaultFilename: ""
0051 
0052     /**
0053      * type:bool
0054      * Whether to automatically fallback to the default filename if the
0055      * language specific wordlist file could not be loaded.
0056      * Default is true.
0057      */
0058     property bool useDefault: true
0059 
0060     /**
0061      * type:string
0062      * Name of the file to load the language specific wordlist from.
0063      * Default is empty. Can also be passed directly in loadFromFile().
0064      * If set in the QML definition, the wordlist is autoloaded onCompleted.
0065      */
0066     property string filename: ""
0067 
0068     /**
0069      * type:object
0070      * Complete Wordlist content loaded. You probably want to use one of the
0071      * convenience accessors like getLevelWordList().
0072      * Default is empty.
0073      */
0074     property var wordList: ({})
0075 
0076     /// @cond INTERNAL_DOCS
0077 
0078     property var randomWordList: []
0079     property int maxLevel: 0
0080 
0081     /// @endcond
0082 
0083     /**
0084      * Emitted if an error occurs.
0085      * @param msg Error message.
0086      */
0087     signal error(string msg);
0088 
0089     /**
0090      * Load Wordlist from JSON Object.
0091      *
0092      * @param type:object levels to load wordlist from.
0093     */
0094     function loadFromJSON(levels) {
0095         wordList = {levels: levels};
0096         maxLevel = wordList.levels.length;
0097         return wordList;
0098     }
0099 
0100     /**
0101      * Load Wordlist from file @p fname.
0102      *
0103      * @param type:string fname Filename to load wordlist from.
0104      */
0105     function loadFromFile(fname) {
0106         filename = fname;
0107         var from;
0108         maxLevel = 0
0109         wordList = parser.parseFromUrl(filename, validateWordlist);
0110         if (wordList == null) {
0111             error("Wordlist: Invalid wordlist file " + fname);
0112             if (useDefault) {
0113                 // fallback to default file:
0114                 wordList = parser.parseFromUrl(defaultFilename, validateWordlist);
0115                 if (wordList == null) {
0116                     error("Wordlist: Invalid wordlist file " + defaultFilename);
0117                     return;
0118                 }
0119                 from = "default-file " + defaultFilename;
0120             }
0121             else {
0122                 error("Wordlist: do not use default list, no list loaded");
0123                 return;
0124             }
0125         } else {
0126             from = "file " + fname;
0127         }
0128         // at this point we have valid levels
0129         maxLevel = wordList.levels.length;
0130         console.log("Wordlist: loaded " + maxLevel + " levels from " + from);
0131         return wordList;
0132     }
0133 
0134     /**
0135      * Get wordlist data for @p level
0136      *
0137      * @param type:int level Level.
0138      * @returns type:object wordlist data.
0139      */
0140     function getLevelWordList(level) {
0141         if (level > maxLevel)
0142             return null;
0143         return wordList.levels[level - 1];
0144     }
0145 
0146     /**
0147      * Get number of sub-levels in @p level.
0148      *
0149      * @param type:int level Level.
0150      * @returns type:int Number of sublevels.
0151      */
0152     function getMaxSubLevel(level) {
0153         if (level > maxLevel || level === 0) {
0154             console.log("ERROR: Wordlist.getMaxSubLevel out of range, requested level", level,
0155                         "out of expected range", 1, "-", maxLevel)
0156             return null;
0157         }
0158         return wordList.levels[level - 1].sublevels !== undefined ?
0159                     wordList.levels[level - 1].sublevels : 0;
0160     }
0161 
0162     /**
0163      * Build a random word list for @p level.
0164      *
0165      * We don't want to propose several time the same word. First call
0166      * initRandomWord(level) to create the initial shuffled list of words.
0167      * Then call getRandomWord() to get the words one at a time.
0168      * If a word was not found by the child, add it again to the list
0169      * with appendRandomWord(word)
0170      *
0171      * @param type:int level Level.
0172      */
0173     function initRandomWord(level) {
0174         randomWordList = Core.shuffle(wordList.levels[level - 1].words).slice(0)
0175     }
0176 
0177     /**
0178      * Re-add a random word to a shuffled word list.
0179      *
0180      * @param type:string word Word to append.
0181      * @sa initRandomWord
0182      */
0183     function appendRandomWord(word) {
0184         randomWordList.unshift(word)
0185     }
0186 
0187     /**
0188      * Returns the next random word from a shuffled wordlist.
0189      *
0190      * @sa initRandomWord
0191      */
0192     function getRandomWord() {
0193         return randomWordList.pop()
0194     }
0195 
0196     /// @cond INTERNAL_DOCS
0197 
0198     function validateWordlist(doc)
0199     {
0200         // minimal syntax check:
0201         var i;
0202         if (undefined === doc.levels)
0203             return false;
0204         for (i = 0; i < doc.levels.length; i++) {
0205             // check mandatory level properties only (speed, fallspeed and sublevels are optional)
0206             if (doc.levels[i].words.length < 1)
0207                 return false;
0208         }
0209         if (i < 1)
0210             return false;
0211         return true;
0212     }
0213 
0214     /// @endcond
0215 
0216     JsonParser {
0217         id: parser
0218 
0219         onError: wordlist.error(msg);
0220     }
0221 
0222     Component.onCompleted: {
0223         if (filename != "")
0224             loadFromFile(filename);
0225     }
0226 }