Showing the changes to plugins/JSAPIExample/src/JSAPIExample.cpp (1 of 1 file). Show all
Unified · Split
| @@ -28,222 +28,223 @@ · 27 unmodified lines | |||
| 28 | // NOTE: replace this with your own namespace when starting a new plugin (to avoid .so/.dll symbol clashes) | 28 | // NOTE: replace this with your own namespace when starting a new plugin (to avoid .so/.dll symbol clashes) |
| 29 | namespace REPLACE_ME_WITH_UNIQUE_NAME { | 29 | namespace REPLACE_ME_WITH_UNIQUE_NAME { |
| 30 | 30 | ||
| 31 | static constexpr auto JSAPI_SEMANTIC_VERSION = "0.0.1"; | 31 | static constexpr auto JSAPI_SEMANTIC_VERSION = "0.0.1"; |
| 32 | static constexpr auto JSAPI_EXPORT_NAME = "JSAPIExample"; | 32 | static constexpr auto JSAPI_EXPORT_NAME = "JSAPIExample"; |
| 33 | 33 | ||
| 34 | QLoggingCategory logger{ "jsapiexample" }; | 34 | QLoggingCategory logger { "jsapiexample" }; |
| 35 | 35 | ||
| 36 | inline QVariant raiseScriptingError(QScriptContext* context, const QString& message, const QVariant& returnValue = QVariant()) { | 36 | inline QVariant raiseScriptingError(QScriptContext* context, const QString& message, const QVariant& returnValue = QVariant()) { |
| 37 | if (context) { | 37 | if (context) { |
| 38 | // when a QScriptContext is available throw an actual JS Exception (which can be caught using try/catch on JS side) | 38 | // when a QScriptContext is available throw an actual JS Exception (which can be caught using try/catch on JS side) |
| 39 | context->throwError(message); | 39 | context->throwError(message); |
| 40 | } else { | 40 | } else { |
| 41 | // otherwise just log the error | 41 | // otherwise just log the error |
| 42 | qCWarning(logger) << "error:" << message; | 42 | qCWarning(logger) << "error:" << message; |
| 43 | } | ||
| 44 | return returnValue; | ||
| 45 | } | ||
| 46 | |||
| 47 | QObject* createScopedSettings(const QString& scope, QObject* parent, QString& error); | ||
| 48 | |||
| 49 | class JSAPIExample : public QObject, public QScriptable { | ||
| 50 | Q_OBJECT | ||
| 51 | Q_PLUGIN_METADATA(IID "JSAPIExample" FILE "plugin.json") | ||
| 52 | Q_PROPERTY(QString version MEMBER _version CONSTANT) | ||
| 53 | public: | ||
| 54 | JSAPIExample() { | ||
| 55 | setObjectName(JSAPI_EXPORT_NAME); | ||
| 56 | auto scriptInit = DependencyManager::get<ScriptInitializers>(); | ||
| 57 | if (!scriptInit) { | ||
| 58 | qCWarning(logger) << "COULD NOT INITIALIZE (ScriptInitializers unavailable)" << qApp << this; | ||
| 59 | return; | ||
| 60 | } | 43 | } |
| 61 | qCWarning(logger) << "registering w/ScriptInitializerMixin..." << scriptInit.data(); | 44 | return returnValue; |
| 62 | scriptInit->registerScriptInitializer([this](QScriptEngine* engine) { | ||
| 63 | auto value = engine->newQObject(this, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater); | ||
| 64 | engine->globalObject().setProperty(objectName(), value); | ||
| 65 | // qCDebug(logger) << "setGlobalInstance" << objectName() << engine->property("fileName"); | ||
| 66 | }); | ||
| 67 | // qCInfo(logger) << "plugin loaded" << qApp << toString() << QThread::currentThread(); | ||
| 68 | } | 45 | } |
| 69 | 46 | ||
| 70 | // NOTES: everything within the "public slots:" section below will be available from JS via overall plugin QObject | 47 | QObject* createScopedSettings(const QString& scope, QObject* parent, QString& error); |
| 71 | // also, to demonstrate future-proofing JS API code, QVariant's are used throughout most of these examples -- | 48 | |
| 72 | // which still makes them very Qt-specific, but avoids depending directly on deprecated QtScript/QScriptValue APIs. | 49 | class JSAPIExample : public QObject, public QScriptable { |
| 73 | // (as such this plugin class and its methods remain forward-compatible with other engines like QML's QJSEngine) | 50 | Q_OBJECT |
| 74 | 51 | Q_PLUGIN_METADATA(IID "JSAPIExample" FILE "plugin.json") | |
| 75 | public slots: | 52 | Q_PROPERTY(QString version MEMBER _version CONSTANT) |
| 76 | // pretty-printed representation for logging eg: print(JSAPIExample) | 53 | public: |
| 77 | // (note: Qt script engines automatically look for a ".toString" method on native classes when coercing values to strings) | 54 | JSAPIExample() { |
| 78 | QString toString() const { return QString("[%1 version=%2]").arg(objectName()).arg(_version); } | 55 | setObjectName(JSAPI_EXPORT_NAME); |
| 79 | 56 | auto scriptInit = DependencyManager::get<ScriptInitializers>(); | |
| 80 | /**jsdoc | 57 | if (!scriptInit) { |
| 81 | * Returns current microseconds (usecs) since Epoch. note: 1000usecs == 1ms | 58 | qCWarning(logger) << "COULD NOT INITIALIZE (ScriptInitializers unavailable)" << qApp << this; |
| 82 | * @example <caption>Measure current setTimeout accuracy.</caption> | 59 | return; |
| 83 | * var expected = 1000; | 60 | } |
| 84 | * var start = JSAPIExample.now(); | 61 | qCWarning(logger) << "registering w/ScriptInitializerMixin..." << scriptInit.data(); |
| 85 | * Script.setTimeout(function () { | 62 | scriptInit->registerScriptInitializer([this](QScriptEngine* engine) { |
| 86 | * var elapsed = (JSAPIExample.now() - start)/1000; | 63 | auto value = engine->newQObject(this, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater); |
| 87 | * print("expected (ms):", expected, "actual (ms):", elapsed); | 64 | engine->globalObject().setProperty(objectName(), value); |
| 88 | * }, expected); | 65 | // qCDebug(logger) << "setGlobalInstance" << objectName() << engine->property("fileName"); |
| 89 | */ | 66 | }); |
| 90 | QVariant now() const { return usecTimestampNow(); } | 67 | // qCInfo(logger) << "plugin loaded" << qApp << toString() << QThread::currentThread(); |
| 91 | |||
| 92 | /**jsdoc | ||
| 93 | * Example of returning a JS Object key-value map | ||
| 94 | * @example <caption>"zip" a list of keys and corresponding values to form key-value map</caption> | ||
| 95 | * print(JSON.stringify(JSAPIExample.zip(["a","b"], [1,2])); // { "a": 1, "b": 2 } | ||
| 96 | */ | ||
| 97 | QVariant zip(const QStringList& keys, const QVariantList& values) const { | ||
| 98 | QVariantMap out; | ||
| 99 | for (int i = 0; i < keys.size(); i++) { | ||
| 100 | out[keys[i]] = i < values.size() ? values[i] : QVariant(); | ||
| 101 | } | 68 | } |
| 102 | return out; | ||
| 103 | } | ||
| 104 | 69 | ||
| 105 | /**jsdoc | 70 | // NOTES: everything within the "public slots:" section below will be available from JS via overall plugin QObject |
| 106 | * Example of returning a JS Array result | 71 | // also, to demonstrate future-proofing JS API code, QVariant's are used throughout most of these examples -- |
| 107 | * @example <caption>emulate Object.values(keyValues)</caption> | 72 | // which still makes them very Qt-specific, but avoids depending directly on deprecated QtScript/QScriptValue APIs. |
| 108 | * print(JSON.stringify(JSAPIExample.values({ "a": 1, "b": 2 }))); // [1,2] | 73 | // (as such this plugin class and its methods remain forward-compatible with other engines like QML's QJSEngine) |
| 109 | */ | 74 | |
| 110 | QVariant values(const QVariantMap& keyValues) const { | 75 | public slots: |
| 111 | QVariantList values = keyValues.values(); | 76 | // pretty-printed representation for logging eg: print(JSAPIExample) |
| 112 | return values; | 77 | // (note: Qt script engines automatically look for a ".toString" method on native classes when coercing values to strings) |
| 113 | } | 78 | QString toString() const { return QString("[%1 version=%2]").arg(objectName()).arg(_version); } |
| 79 | |||
| 80 | /**jsdoc | ||
| 81 | * Returns current microseconds (usecs) since Epoch. note: 1000usecs == 1ms | ||
| 82 | * @example <caption>Measure current setTimeout accuracy.</caption> | ||
| 83 | * var expected = 1000; | ||
| 84 | * var start = JSAPIExample.now(); | ||
| 85 | * Script.setTimeout(function () { | ||
| 86 | * var elapsed = (JSAPIExample.now() - start)/1000; | ||
| 87 | * print("expected (ms):", expected, "actual (ms):", elapsed); | ||
| 88 | * }, expected); | ||
| 89 | */ | ||
| 90 | QVariant now() const { return usecTimestampNow(); } | ||
| 91 | |||
| 92 | /**jsdoc | ||
| 93 | * Example of returning a JS Object key-value map | ||
| 94 | * @example <caption>"zip" a list of keys and corresponding values to form key-value map</caption> | ||
| 95 | * print(JSON.stringify(JSAPIExample.zip(["a","b"], [1,2])); // { "a": 1, "b": 2 } | ||
| 96 | */ | ||
| 97 | QVariant zip(const QStringList& keys, const QVariantList& values) const { | ||
| 98 | QVariantMap out; | ||
| 99 | for (int i = 0; i < keys.size(); i++) { | ||
| 100 | out[keys[i]] = i < values.size() ? values[i] : QVariant(); | ||
| 101 | } | ||
| 102 | return out; | ||
| 103 | } | ||
| 114 | 104 | ||
| 115 | /**jsdoc | 105 | /**jsdoc |
| 116 | * Another example of returning JS Array data | 106 | * Example of returning a JS Array result |
| 117 | * @example <caption>generate an integer sequence (inclusive of [from, to])</caption> | 107 | * @example <caption>emulate Object.values(keyValues)</caption> |
| 118 | * print(JSON.stringify(JSAPIExample.seq(1,5)));// [1,2,3,4,5] | 108 | * print(JSON.stringify(JSAPIExample.values({ "a": 1, "b": 2 }))); // [1,2] |
| 119 | */ | 109 | */ |
| 120 | QVariant seq(int from, int to) const { | 110 | QVariant values(const QVariantMap& keyValues) const { |
| 121 | QVariantList out; | 111 | QVariantList values = keyValues.values(); |
| 122 | for (int i = from; i <= to; i++) { | 112 | return values; |
| 123 | out.append(i); | ||
| 124 | } | 113 | } |
| 125 | return out; | ||
| 126 | } | ||
| 127 | 114 | ||
| 128 | /**jsdoc | 115 | /**jsdoc |
| 129 | * Example of returning arbitrary binary data from C++ (resulting in a JS ArrayBuffer) | 116 | * Another example of returning JS Array data |
| 130 | * see also: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer#Examples | 117 | * @example <caption>generate an integer sequence (inclusive of [from, to])</caption> |
| 131 | * @example <caption>return compressed/decompressed versions of the input data</caption> | 118 | * print(JSON.stringify(JSAPIExample.seq(1,5)));// [1,2,3,4,5] |
| 132 | * var data = "testing 1 2 3"; | 119 | */ |
| 133 | * var z = JSAPIExample.qCompressString(data); // z will be an ArrayBuffer | 120 | QVariant seq(int from, int to) const { |
| 134 | * var u = JSAPIExample.qUncompressString(z); // u will be a String value | 121 | QVariantList out; |
| 135 | * print(JSON.stringify({ input: data, compressed: z.byteLength, output: u, uncompressed: u.length })); | 122 | for (int i = from; i <= to; i++) { |
| 136 | */ | 123 | out.append(i); |
| 137 | QVariant qCompressString(const QString& jsString, int compress_level = -1) const { | 124 | } |
| 138 | QByteArray arrayBuffer = qCompress(jsString.toUtf8(), compress_level); | 125 | return out; |
| 139 | return arrayBuffer; | 126 | } |
| 140 | } | 127 | |
| 141 | QVariant qUncompressString(const QByteArray& arrayBuffer) const { | 128 | /**jsdoc |
| 142 | QString jsString = QString::fromUtf8(qUncompress(arrayBuffer)); | 129 | * Example of returning arbitrary binary data from C++ (resulting in a JS ArrayBuffer) |
| 143 | return jsString; | 130 | * see also: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer#Examples |
| 144 | } | 131 | * @example <caption>return compressed/decompressed versions of the input data</caption> |
| 132 | * var data = "testing 1 2 3"; | ||
| 133 | * var z = JSAPIExample.qCompressString(data); // z will be an ArrayBuffer | ||
| 134 | * var u = JSAPIExample.qUncompressString(z); // u will be a String value | ||
| 135 | * print(JSON.stringify({ input: data, compressed: z.byteLength, output: u, uncompressed: u.length })); | ||
| 136 | */ | ||
| 137 | QVariant qCompressString(const QString& jsString, int compress_level = -1) const { | ||
| 138 | QByteArray arrayBuffer = qCompress(jsString.toUtf8(), compress_level); | ||
| 139 | return arrayBuffer; | ||
| 140 | } | ||
| 141 | QVariant qUncompressString(const QByteArray& arrayBuffer) const { | ||
| 142 | QString jsString = QString::fromUtf8(qUncompress(arrayBuffer)); | ||
| 143 | return jsString; | ||
| 144 | } | ||
| 145 | |||
| 146 | /** | ||
| 147 | * Example of exposing a custom "managed" C++ QObject to JS | ||
| 148 | * The lifecycle of the created QObject* instance becomes managed by the invoking QScriptEngine -- | ||
| 149 | * it will be automatically cleaned up once no longer reachable from any JS variables/closures. | ||
| 150 | * @example <caption>access persistent settings stored in separate .json files</caption> | ||
| 151 | * var settings = JSAPIExample.getScopedSettings("example"); | ||
| 152 | * print("example settings stored in:", settings.fileName()); | ||
| 153 | * print("(before) example::timestamp", settings.getValue("timestamp")); | ||
| 154 | * settings.setValue("timestamp", Date.now()); | ||
| 155 | * print("(after) example::timestamp", settings.getValue("timestamp")); | ||
| 156 | * print("all example::* keys", settings.allKeys()); | ||
| 157 | * settings = null; // optional best pratice; allows the object to be reclaimed ASAP by the JS garbage collector | ||
| 158 | */ | ||
| 159 | QScriptValue getScopedSettings(const QString& scope) { | ||
| 160 | auto engine = QScriptable::engine(); | ||
| 161 | if (!engine) { | ||
| 162 | return QScriptValue::NullValue; | ||
| 163 | } | ||
| 164 | QString error; | ||
| 165 | auto cppValue = createScopedSettings(scope, engine, error); | ||
| 166 | if (!cppValue) { | ||
| 167 | raiseScriptingError(context(), "error creating scoped settings instance: " + error); | ||
| 168 | return QScriptValue::NullValue; | ||
| 169 | } | ||
| 170 | return engine->newQObject(cppValue, QScriptEngine::ScriptOwnership, QScriptEngine::ExcludeDeleteLater); | ||
| 171 | } | ||
| 145 | 172 | ||
| 146 | /** | 173 | private: |
| 147 | * Example of exposing a custom "managed" C++ QObject to JS | 174 | const QString _version { JSAPI_SEMANTIC_VERSION }; |
| 148 | * The lifecycle of the created QObject* instance becomes managed by the invoking QScriptEngine -- | 175 | }; |
| 149 | * it will be automatically cleaned up once no longer reachable from any JS variables/closures. | 176 | |
| 150 | * @example <caption>access persistent settings stored in separate .json files</caption> | 177 | // JSSettingsHelper wraps a scoped (prefixed/separate) QSettings and exposes a subset of QSetting APIs as slots |
| 151 | * var settings = JSAPIExample.getScopedSettings("example"); | 178 | class JSSettingsHelper : public QObject { |
| 152 | * print("example settings stored in:", settings.fileName()); | 179 | Q_OBJECT |
| 153 | * print("(before) example::timestamp", settings.getValue("timestamp")); | 180 | public: |
| 154 | * settings.setValue("timestamp", Date.now()); | 181 | JSSettingsHelper(const QString& scope, QObject* parent = nullptr); |
| 155 | * print("(after) example::timestamp", settings.getValue("timestamp")); | 182 | ~JSSettingsHelper(); |
| 156 | * print("all example::* keys", settings.allKeys()); | 183 | operator bool() const; |
| 157 | * settings = null; // optional best pratice; allows the object to be reclaimed ASAP by the JS garbage collector | 184 | public slots: |
| 158 | */ | 185 | QString fileName() const; |
| 159 | QScriptValue getScopedSettings(const QString& scope) { | 186 | QString toString() const; |
| 160 | auto engine = QScriptable::engine(); | 187 | QVariant getValue(const QString& key, const QVariant& defaultValue = QVariant()); |
| 161 | if (!engine) | 188 | bool setValue(const QString& key, const QVariant& value); |
| 162 | return QScriptValue::NullValue; | 189 | QStringList allKeys() const; |
| 163 | QString error; | 190 | protected: |
| 164 | auto cppValue = createScopedSettings(scope, engine, error); | 191 | QString _scope; |
| 165 | if (!cppValue) { | 192 | QString _fileName; |
| 166 | raiseScriptingError(context(), "error creating scoped settings instance: " + error); | 193 | QSharedPointer<QSettings> _settings; |
| 167 | return QScriptValue::NullValue; | 194 | QString getLocalSettingsPath(const QString& scope) const; |
| 195 | }; | ||
| 196 | |||
| 197 | // verifies the requested scope is sensible and creates/returns a scoped JSSettingsHelper instance | ||
| 198 | QObject* createScopedSettings(const QString& scope, QObject* parent, QString& error) { | ||
| 199 | const QRegExp VALID_SETTINGS_SCOPE { "[-_A-Za-z0-9]{1,64}" }; | ||
| 200 | if (!VALID_SETTINGS_SCOPE.exactMatch(scope)) { | ||
| 201 | error = QString("invalid scope (expected alphanumeric <= 64 chars not '%1')").arg(scope); | ||
| 202 | return nullptr; | ||
| 168 | } | 203 | } |
| 169 | return engine->newQObject(cppValue, QScriptEngine::ScriptOwnership, QScriptEngine::ExcludeDeleteLater); | 204 | return new JSSettingsHelper(scope, parent); |
| 170 | } | 205 | } |
| 171 | 206 | ||
| 172 | private: | 207 | // -------------------------------------------------- |
| 173 | const QString _version{ JSAPI_SEMANTIC_VERSION }; | 208 | // ----- inline JSSettingsHelper implementation ----- |
| 174 | }; | 209 | JSSettingsHelper::operator bool() const { |
| 175 | 210 | return (bool)_settings; | |
| 176 | // JSSettingsHelper wraps a scoped (prefixed/separate) QSettings and exposes a subset of QSetting APIs as slots | ||
| 177 | class JSSettingsHelper : public QObject { | ||
| 178 | Q_OBJECT | ||
| 179 | public: | ||
| 180 | JSSettingsHelper(const QString& scope, QObject* parent = nullptr); | ||
| 181 | ~JSSettingsHelper(); | ||
| 182 | operator bool() const; | ||
| 183 | public slots: | ||
| 184 | QString fileName() const; | ||
| 185 | QString toString() const; | ||
| 186 | QVariant getValue(const QString& key, const QVariant& defaultValue = QVariant()); | ||
| 187 | bool setValue(const QString& key, const QVariant& value); | ||
| 188 | QStringList allKeys() const; | ||
| 189 | protected: | ||
| 190 | QString _scope; | ||
| 191 | QString _fileName; | ||
| 192 | QSharedPointer<QSettings> _settings; | ||
| 193 | QString getLocalSettingsPath(const QString& scope) const; | ||
| 194 | }; | ||
| 195 | |||
| 196 | // verifies the requested scope is sensible and creates/returns a scoped JSSettingsHelper instance | ||
| 197 | QObject* createScopedSettings(const QString& scope, QObject* parent, QString& error) { | ||
| 198 | const QRegExp VALID_SETTINGS_SCOPE{ "[-_A-Za-z0-9]{1,64}" }; | ||
| 199 | if (!VALID_SETTINGS_SCOPE.exactMatch(scope)) { | ||
| 200 | error = QString("invalid scope (expected alphanumeric <= 64 chars not '%1')").arg(scope); | ||
| 201 | return nullptr; | ||
| 202 | } | 211 | } |
| 203 | return new JSSettingsHelper(scope, parent); | 212 | JSSettingsHelper::JSSettingsHelper(const QString& scope, QObject* parent) : |
| 204 | } | 213 | QObject(parent), _scope(scope), _fileName(getLocalSettingsPath(scope)), |
| 205 | 214 | _settings(_fileName.isEmpty() ? nullptr : new QSettings(_fileName, JSON_FORMAT)) { | |
| 206 | // -------------------------------------------------- | 215 | } |
| 207 | // ----- inline JSSettingsHelper implementation ----- | 216 | JSSettingsHelper::~JSSettingsHelper() { |
| 208 | JSSettingsHelper::operator bool() const { | 217 | qCDebug(logger) << "~JSSettingsHelper" << _scope << _fileName << this; |
| 209 | return (bool)_settings; | 218 | } |
| 210 | } | 219 | QString JSSettingsHelper::fileName() const { |
| 211 | JSSettingsHelper::JSSettingsHelper(const QString& scope, QObject* parent) : | 220 | return _settings ? _settings->fileName() : ""; |
| 212 | QObject(parent), _scope(scope), _fileName(getLocalSettingsPath(scope)), | 221 | } |
| 213 | _settings(_fileName.isEmpty() ? nullptr : new QSettings(_fileName, JSON_FORMAT)) { | 222 | QString JSSettingsHelper::toString() const { |
| 214 | } | 223 | return QString("[JSSettingsHelper scope=%1 valid=%2]").arg(_scope).arg((bool)_settings); |
| 215 | JSSettingsHelper::~JSSettingsHelper() { | 224 | } |
| 216 | qCDebug(logger) << "~JSSettingsHelper" << _scope << _fileName << this; | 225 | QVariant JSSettingsHelper::getValue(const QString& key, const QVariant& defaultValue) { |
| 217 | } | 226 | return _settings ? _settings->value(key, defaultValue) : defaultValue; |
| 218 | QString JSSettingsHelper::fileName() const { | 227 | } |
| 219 | return _settings ? _settings->fileName() : ""; | 228 | bool JSSettingsHelper::setValue(const QString& key, const QVariant& value) { |
| 220 | } | 229 | if (_settings) { |
| 221 | QString JSSettingsHelper::toString() const { | 230 | if (value.isValid()) { |
| 222 | return QString("[JSSettingsHelper scope=%1 valid=%2]").arg(_scope).arg((bool)_settings); | 231 | _settings->setValue(key, value); |
| 223 | } | 232 | } else { |
| 224 | QVariant JSSettingsHelper::getValue(const QString& key, const QVariant& defaultValue) { | 233 | _settings->remove(key); |
| 225 | return _settings ? _settings->value(key, defaultValue) : defaultValue; | 234 | } |
| 226 | } | 235 | return true; |
| 227 | bool JSSettingsHelper::setValue(const QString& key, const QVariant& value) { | ||
| 228 | if (_settings) { | ||
| 229 | if (value.isValid()) { | ||
| 230 | _settings->setValue(key, value); | ||
| 231 | } else { | ||
| 232 | _settings->remove(key); | ||
| 233 | } | 236 | } |
| 234 | return true; | 237 | return false; |
| 238 | } | ||
| 239 | QStringList JSSettingsHelper::allKeys() const { | ||
| 240 | return _settings ? _settings->allKeys() : QStringList{}; | ||
| 241 | } | ||
| 242 | QString JSSettingsHelper::getLocalSettingsPath(const QString& scope) const { | ||
| 243 | // generate a prefixed filename (relative to the main application's Interface.json file) | ||
| 244 | const QString fileName = QString("jsapi_%1.json").arg(scope); | ||
| 245 | return QFileInfo(::settingsFilename()).dir().filePath(fileName); | ||
| 235 | } | 246 | } |
| 236 | return false; | 247 | // ----- /inline JSSettingsHelper implementation ----- |
| 237 | } | ||
| 238 | QStringList JSSettingsHelper::allKeys() const { | ||
| 239 | return _settings ? _settings->allKeys() : QStringList{}; | ||
| 240 | } | ||
| 241 | QString JSSettingsHelper::getLocalSettingsPath(const QString& scope) const { | ||
| 242 | // generate a prefixed filename (relative to the main application's Interface.json file) | ||
| 243 | const QString fileName = QString("jsapi_%1.json").arg(scope); | ||
| 244 | return QFileInfo(::settingsFilename()).dir().filePath(fileName); | ||
| 245 | } | ||
| 246 | // ----- /inline JSSettingsHelper implementation ----- | ||
| 247 | 248 | ||
| 248 | } // namespace REPLACE_ME_WITH_UNIQUE_NAME | 249 | } // namespace REPLACE_ME_WITH_UNIQUE_NAME |
| 249 | 250 | ||