| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2016 The Qt Company Ltd. | 
| 4 | ** Contact: https://www.qt.io/licensing/ | 
| 5 | ** | 
| 6 | ** This file is part of the Qt Virtual Keyboard module of the Qt Toolkit. | 
| 7 | ** | 
| 8 | ** $QT_BEGIN_LICENSE:GPL$ | 
| 9 | ** Commercial License Usage | 
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in | 
| 11 | ** accordance with the commercial license agreement provided with the | 
| 12 | ** Software or, alternatively, in accordance with the terms contained in | 
| 13 | ** a written agreement between you and The Qt Company. For licensing terms | 
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further | 
| 15 | ** information use the contact form at https://www.qt.io/contact-us. | 
| 16 | ** | 
| 17 | ** GNU General Public License Usage | 
| 18 | ** Alternatively, this file may be used under the terms of the GNU | 
| 19 | ** General Public License version 3 or (at your option) any later version | 
| 20 | ** approved by the KDE Free Qt Foundation. The licenses are as published by | 
| 21 | ** the Free Software Foundation and appearing in the file LICENSE.GPL3 | 
| 22 | ** included in the packaging of this file. Please review the following | 
| 23 | ** information to ensure the GNU General Public License requirements will | 
| 24 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. | 
| 25 | ** | 
| 26 | ** $QT_END_LICENSE$ | 
| 27 | ** | 
| 28 | ****************************************************************************/ | 
| 29 |  | 
| 30 | #include <QtVirtualKeyboard/private/virtualkeyboardsettings_p.h> | 
| 31 | #include <QtVirtualKeyboard/private/settings_p.h> | 
| 32 | #include <QtVirtualKeyboard/private/virtualkeyboarddebug_p.h> | 
| 33 | #include <QQmlEngine> | 
| 34 | #include <QFileInfo> | 
| 35 | #include <QDir> | 
| 36 | #include <QRegularExpression> | 
| 37 | #include <QtCore/private/qobject_p.h> | 
| 38 |  | 
| 39 | QT_BEGIN_NAMESPACE | 
| 40 | namespace QtVirtualKeyboard { | 
| 41 |  | 
| 42 | class VirtualKeyboardSettingsPrivate : public QObjectPrivate | 
| 43 | { | 
| 44 | public: | 
| 45 |     VirtualKeyboardSettingsPrivate() : | 
| 46 |         QObjectPrivate(), | 
| 47 |         engine() | 
| 48 |     {} | 
| 49 |  | 
| 50 |     QString buildStyleImportPath(const QString &path, const QString &name) const | 
| 51 |     { | 
| 52 |         QString importPath(path + name + QLatin1String("/style.qml" )); | 
| 53 |         if (!importPath.startsWith(s: QLatin1String("qrc:" ))) { | 
| 54 |             QUrl url = QUrl::fromLocalFile(localfile: importPath); | 
| 55 |             importPath = url.toString(); | 
| 56 |         } | 
| 57 |         return importPath; | 
| 58 |     } | 
| 59 |  | 
| 60 |     QString buildStyleFilePath(const QString &path, const QString &name) const | 
| 61 |     { | 
| 62 |         QString filePath(path); | 
| 63 |         if (filePath.startsWith(s: QLatin1String("qrc:" ))) | 
| 64 |             filePath.remove(i: 0, len: 3); | 
| 65 |         return filePath + name + QLatin1String("/style.qml" ); | 
| 66 |     } | 
| 67 |  | 
| 68 |     QString styleImportPath(const QString &name) const | 
| 69 |     { | 
| 70 |         if (name.isEmpty()) | 
| 71 |             return QString(); | 
| 72 |  | 
| 73 |         QStringList styleImportPathList; | 
| 74 |         styleImportPathList << QLatin1String("qrc:/QtQuick/VirtualKeyboard/content/styles/" ); | 
| 75 |         const QStringList importPathList = engine->importPathList(); | 
| 76 |         // Add QML import path (Note: the QML base dir is usually the last entry in the list) | 
| 77 |         for (int i = importPathList.size() - 1; i >= 0; --i) { | 
| 78 |             const QString stylesPath = importPathList.at(i) | 
| 79 |                 + QLatin1String("/QtQuick/VirtualKeyboard/Styles/" ); | 
| 80 |             styleImportPathList += stylesPath; | 
| 81 |         } | 
| 82 |  | 
| 83 |         for (const QString &styleImportPath : qAsConst(t&: styleImportPathList)) { | 
| 84 |             QString filePath = buildStyleFilePath(path: styleImportPath, name); | 
| 85 |             bool pathExist = false; | 
| 86 |             pathExist = QFileInfo::exists(file: filePath); | 
| 87 |             if (pathExist) | 
| 88 |                 return buildStyleImportPath(path: styleImportPath, name); | 
| 89 |         } | 
| 90 |         return QString(); | 
| 91 |     } | 
| 92 |  | 
| 93 |     QPointer<QQmlEngine> engine; | 
| 94 |     WordCandidateListSettings wordCandidateListSettings; | 
| 95 | }; | 
| 96 |  | 
| 97 | /*! | 
| 98 |     \qmlmodule QtQuick.VirtualKeyboard.Settings 2.\QtMinorVersion | 
| 99 |     \title Qt Quick Virtual Keyboard Settings QML Types | 
| 100 |     \ingroup qmlmodules | 
| 101 |  | 
| 102 |     \brief Provides settings for Qt Virtual Keyboard. | 
| 103 |  | 
| 104 |     The QML types can be imported into your application using the following | 
| 105 |     import statements in your .qml file: | 
| 106 |  | 
| 107 |     \qml \QtMinorVersion | 
| 108 |     import QtQuick.VirtualKeyboard.Settings 2.\1 | 
| 109 |     \endqml | 
| 110 | */ | 
| 111 |  | 
| 112 | /*! | 
| 113 |     \qmltype VirtualKeyboardSettings | 
| 114 |     \inqmlmodule QtQuick.VirtualKeyboard.Settings | 
| 115 |     \ingroup qtvirtualkeyboard-settings-qml | 
| 116 |     \since QtQuick.VirtualKeyboard 1.2 | 
| 117 |     \brief Provides settings for virtual keyboard. | 
| 118 |  | 
| 119 |     This type provides a VirtualKeyboardSettings singleton instance, | 
| 120 |     which can be used to configure the virtual keyboard settings. | 
| 121 |  | 
| 122 |     Please note that the settings have only effect in the current | 
| 123 |     application's lifetime, that is, configuration changes are not | 
| 124 |     permanent. | 
| 125 |  | 
| 126 |     For example, to change the keyboard style in application: | 
| 127 |  | 
| 128 |     \code | 
| 129 |         Component.onCompleted: VirtualKeyboardSettings.styleName = "retro" | 
| 130 |     \endcode | 
| 131 | */ | 
| 132 |  | 
| 133 | /*! | 
| 134 |     \internal | 
| 135 | */ | 
| 136 | QObject *VirtualKeyboardSettings::registerSettingsModule(QQmlEngine *engine, QJSEngine *jsEngine) | 
| 137 | { | 
| 138 |     Q_UNUSED(jsEngine); | 
| 139 |     return new VirtualKeyboardSettings(engine); | 
| 140 | } | 
| 141 |  | 
| 142 | /*! | 
| 143 |     \class QtVirtualKeyboard::VirtualKeyboardSettings | 
| 144 |     \internal | 
| 145 | */ | 
| 146 |  | 
| 147 | /*! | 
| 148 |     \internal | 
| 149 | */ | 
| 150 | VirtualKeyboardSettings::VirtualKeyboardSettings(QQmlEngine *engine) : | 
| 151 |     QObject(*new VirtualKeyboardSettingsPrivate()) | 
| 152 | { | 
| 153 |     Q_D(VirtualKeyboardSettings); | 
| 154 |     d->engine = engine; | 
| 155 |     Settings *settings = Settings::instance(); | 
| 156 |     if (settings->styleName().isEmpty()) | 
| 157 |         resetStyle(); | 
| 158 |     if (settings->layoutPath().isEmpty()) | 
| 159 |         resetLayoutPath(); | 
| 160 |     connect(asender: settings, SIGNAL(styleChanged()), SIGNAL(styleChanged())); | 
| 161 |     connect(asender: settings, SIGNAL(styleNameChanged()), SIGNAL(styleNameChanged())); | 
| 162 |     connect(asender: settings, SIGNAL(localeChanged()), SIGNAL(localeChanged())); | 
| 163 |     connect(asender: settings, SIGNAL(availableLocalesChanged()), SIGNAL(availableLocalesChanged())); | 
| 164 |     connect(asender: settings, SIGNAL(activeLocalesChanged()), SIGNAL(activeLocalesChanged())); | 
| 165 |     connect(asender: settings, SIGNAL(layoutPathChanged()), SIGNAL(layoutPathChanged())); | 
| 166 |     connect(sender: settings, SIGNAL(wclAutoHideDelayChanged()), receiver: &d->wordCandidateListSettings, SIGNAL(autoHideDelayChanged())); | 
| 167 |     connect(sender: settings, SIGNAL(wclAlwaysVisibleChanged()), receiver: &d->wordCandidateListSettings, SIGNAL(alwaysVisibleChanged())); | 
| 168 |     connect(sender: settings, SIGNAL(wclAutoCommitWordChanged()), receiver: &d->wordCandidateListSettings, SIGNAL(autoCommitWordChanged())); | 
| 169 |     connect(asender: settings, SIGNAL(fullScreenModeChanged()), SIGNAL(fullScreenModeChanged())); | 
| 170 | } | 
| 171 |  | 
| 172 | /*! | 
| 173 |     \internal | 
| 174 | */ | 
| 175 | QString VirtualKeyboardSettings::style() const | 
| 176 | { | 
| 177 |     return Settings::instance()->style(); | 
| 178 | } | 
| 179 |  | 
| 180 | /*! | 
| 181 |     \internal | 
| 182 | */ | 
| 183 | QString VirtualKeyboardSettings::styleName() const | 
| 184 | { | 
| 185 |     return Settings::instance()->styleName(); | 
| 186 | } | 
| 187 |  | 
| 188 | /*! | 
| 189 |     \internal | 
| 190 | */ | 
| 191 | void VirtualKeyboardSettings::setStyleName(const QString &styleName) | 
| 192 | { | 
| 193 |     Q_D(VirtualKeyboardSettings); | 
| 194 |     Settings *settings = Settings::instance(); | 
| 195 |     QString style = d->styleImportPath(name: styleName); | 
| 196 |     if (style.isEmpty()) { | 
| 197 |         qWarning() << "WARNING: Cannot find style"  << styleName << "- fallback:"  << settings->styleName(); | 
| 198 |         return; | 
| 199 |     } | 
| 200 |     settings->setStyleName(styleName); | 
| 201 |     settings->setStyle(style); | 
| 202 | } | 
| 203 |  | 
| 204 | /*! | 
| 205 |     \internal | 
| 206 | */ | 
| 207 | QUrl VirtualKeyboardSettings::layoutPath() const | 
| 208 | { | 
| 209 |     return Settings::instance()->layoutPath(); | 
| 210 | } | 
| 211 |  | 
| 212 | /*! | 
| 213 |     \internal | 
| 214 | */ | 
| 215 | void VirtualKeyboardSettings::setLayoutPath(const QUrl &layoutPath) | 
| 216 | { | 
| 217 |     Settings *settings = Settings::instance(); | 
| 218 |     QDir layoutDirectory(layoutPath.toLocalFile()); | 
| 219 |     if (!layoutDirectory.exists()) { | 
| 220 |         qWarning() << "WARNING: Cannot find layout path"  << layoutPath; | 
| 221 |         return; | 
| 222 |     } | 
| 223 |     settings->setLayoutPath(layoutPath); | 
| 224 | } | 
| 225 |  | 
| 226 | void VirtualKeyboardSettings::resetLayoutPath() | 
| 227 | { | 
| 228 |     Settings *settings = Settings::instance(); | 
| 229 |     QUrl layoutPath(QLatin1String(QT_VIRTUALKEYBOARD_DEFAULT_LAYOUTS_DIR)); | 
| 230 |     const QString customLayoutPath(QDir::fromNativeSeparators(pathName: qEnvironmentVariable(varName: "QT_VIRTUALKEYBOARD_LAYOUT_PATH" ))); | 
| 231 |     if (!customLayoutPath.isEmpty()) { | 
| 232 |         bool found = false; | 
| 233 |         QDir customLayoutDirectory(customLayoutPath); | 
| 234 |         if (customLayoutDirectory.exists()) { | 
| 235 |             found = true; | 
| 236 |             layoutPath = QUrl::fromLocalFile(localfile: customLayoutPath); | 
| 237 |         } else { | 
| 238 |             customLayoutDirectory = QDir(QUrl(customLayoutPath).toLocalFile()); | 
| 239 |             if (customLayoutDirectory.exists()) { | 
| 240 |                 found = true; | 
| 241 |                 layoutPath = QUrl(customLayoutPath); | 
| 242 |             } | 
| 243 |         } | 
| 244 |         if (!found) { | 
| 245 |             qWarning() << "WARNING: Cannot assign custom layout path"  << customLayoutPath << "- fallback:"  << layoutPath; | 
| 246 |         } | 
| 247 |     } | 
| 248 |     settings->setLayoutPath(layoutPath); | 
| 249 | } | 
| 250 |  | 
| 251 | QString VirtualKeyboardSettings::locale() const | 
| 252 | { | 
| 253 |     return Settings::instance()->locale(); | 
| 254 | } | 
| 255 |  | 
| 256 | void VirtualKeyboardSettings::setLocale(const QString &locale) | 
| 257 | { | 
| 258 |     Settings::instance()->setLocale(locale); | 
| 259 | } | 
| 260 |  | 
| 261 | QStringList VirtualKeyboardSettings::availableLocales() const | 
| 262 | { | 
| 263 |     return Settings::instance()->availableLocales(); | 
| 264 | } | 
| 265 |  | 
| 266 | void VirtualKeyboardSettings::setActiveLocales(const QStringList &activeLocales) | 
| 267 | { | 
| 268 |     Settings::instance()->setActiveLocales(activeLocales); | 
| 269 | } | 
| 270 |  | 
| 271 | QStringList VirtualKeyboardSettings::activeLocales() const | 
| 272 | { | 
| 273 |     return Settings::instance()->activeLocales(); | 
| 274 | } | 
| 275 |  | 
| 276 | WordCandidateListSettings *VirtualKeyboardSettings::wordCandidateList() const | 
| 277 | { | 
| 278 |     Q_D(const VirtualKeyboardSettings); | 
| 279 |     return const_cast<WordCandidateListSettings *>(&d->wordCandidateListSettings); | 
| 280 | } | 
| 281 |  | 
| 282 | bool VirtualKeyboardSettings::fullScreenMode() const | 
| 283 | { | 
| 284 |     return Settings::instance()->fullScreenMode(); | 
| 285 | } | 
| 286 |  | 
| 287 | void VirtualKeyboardSettings::setFullScreenMode(bool fullScreenMode) | 
| 288 | { | 
| 289 |     return Settings::instance()->setFullScreenMode(fullScreenMode); | 
| 290 | } | 
| 291 |  | 
| 292 | void VirtualKeyboardSettings::resetStyle() | 
| 293 | { | 
| 294 |     Q_D(VirtualKeyboardSettings); | 
| 295 |     Settings *settings = Settings::instance(); | 
| 296 |     QString styleName = QLatin1String(QT_VIRTUALKEYBOARD_DEFAULT_STYLE); | 
| 297 |     QString style = d->styleImportPath(name: styleName); | 
| 298 |     QString customStyleName = QString::fromLatin1(str: qgetenv(varName: "QT_VIRTUALKEYBOARD_STYLE" )); | 
| 299 |     if (!customStyleName.isEmpty()) { | 
| 300 |         bool found = false; | 
| 301 |         QRegularExpression styleNameValidator(QLatin1String("\\A(?:\\w+)\\z" )); | 
| 302 |         QRegularExpressionMatch match = styleNameValidator.match(subject: customStyleName); | 
| 303 |         if (match.hasMatch()) { | 
| 304 |             QString customStyle = d->styleImportPath(name: customStyleName); | 
| 305 |             if (!customStyle.isEmpty()) { | 
| 306 |                 styleName = customStyleName; | 
| 307 |                 style = customStyle; | 
| 308 |                 found = true; | 
| 309 |             } | 
| 310 |         } | 
| 311 |         if (!found) { | 
| 312 |             qWarning() << "WARNING: Cannot find style"  << customStyleName << "- fallback:"  << styleName; | 
| 313 |         } | 
| 314 |     } | 
| 315 |     if (!style.isEmpty()) { | 
| 316 |         settings->setStyleName(styleName); | 
| 317 |         settings->setStyle(style); | 
| 318 |     } | 
| 319 | } | 
| 320 |  | 
| 321 | /*! | 
| 322 |     \qmlproperty string VirtualKeyboardSettings::style | 
| 323 |     \internal | 
| 324 | */ | 
| 325 |  | 
| 326 | /*! | 
| 327 |     \qmlproperty string VirtualKeyboardSettings::styleName | 
| 328 |  | 
| 329 |     This property provides the current style. Application can change | 
| 330 |     the keyboard style by setting the styleName to different value. | 
| 331 |  | 
| 332 |     The system wide keyboard style can be affected by setting | 
| 333 |     the QT_VIRTUALKEYBOARD_STYLE environment variable. | 
| 334 | */ | 
| 335 |  | 
| 336 | /*! | 
| 337 |     \qmlproperty string VirtualKeyboardSettings::locale | 
| 338 |     \since QtQuick.VirtualKeyboard.Settings 2.0 | 
| 339 |  | 
| 340 |     This property provides the default locale for the keyboard. | 
| 341 |  | 
| 342 |     When the locale is not specified, the default system locale is used instead. | 
| 343 |  | 
| 344 |     If the keyboard locale is different from the new default locale, keyboard | 
| 345 |     language is changed immediately to reflect the new locale. If the locale setting | 
| 346 |     is incorrect, or it is not in the list of supported locales, it is ignored and | 
| 347 |     the default setting is used instead. | 
| 348 |  | 
| 349 |     A locale is supported if it is included in the list of availableLocales. | 
| 350 | */ | 
| 351 |  | 
| 352 | /*! | 
| 353 |     \qmlproperty list<string> VirtualKeyboardSettings::availableLocales | 
| 354 |     \since QtQuick.VirtualKeyboard.Settings 2.0 | 
| 355 |     \readonly | 
| 356 |  | 
| 357 |     This property contains a list of languages supported by the virtual keyboard. | 
| 358 |  | 
| 359 |     This list is read-only and depends on the build-time configuration of the | 
| 360 |     virtual keyboard. | 
| 361 | */ | 
| 362 |  | 
| 363 | /*! | 
| 364 |     \qmlproperty list<string> VirtualKeyboardSettings::activeLocales | 
| 365 |     \since QtQuick.VirtualKeyboard.Settings 2.0 | 
| 366 |  | 
| 367 |     This property contains a list of activated languages of the virtual keyboard. | 
| 368 |  | 
| 369 |     The list of active languages is a subset of the available languages, and can be | 
| 370 |     used to limit the list of available languages in the application lifetime. | 
| 371 | */ | 
| 372 |  | 
| 373 | /*! | 
| 374 |     \qmlproperty bool VirtualKeyboardSettings::fullScreenMode | 
| 375 |     \since QtQuick.VirtualKeyboard.Settings 2.2 | 
| 376 |  | 
| 377 |     This property enables the fullscreen mode for the virtual keyboard. | 
| 378 |  | 
| 379 |     In fullscreen mode, the virtual keyboard replicates the contents of the | 
| 380 |     focused input field to the fullscreen input field located at the top of the | 
| 381 |     keyboard. | 
| 382 |  | 
| 383 |     For example, to activate the fullscreen mode when the screen aspect ratio | 
| 384 |     is greater than 16:9: | 
| 385 |  | 
| 386 |     \code | 
| 387 |         Binding { | 
| 388 |             target: VirtualKeyboardSettings | 
| 389 |             property: "fullScreenMode" | 
| 390 |             value: (Screen.width / Screen.height) > (16.0 / 9.0) | 
| 391 |         } | 
| 392 |     \endcode | 
| 393 | */ | 
| 394 |  | 
| 395 | /*! | 
| 396 |     \since QtQuick.VirtualKeyboard.Settings 2.2 | 
| 397 |     \qmlpropertygroup QtQuick.VirtualKeyboard::VirtualKeyboardSettings::wordCandidateList | 
| 398 |     \qmlproperty int QtQuick.VirtualKeyboard::VirtualKeyboardSettings::wordCandidateList.autoHideDelay | 
| 399 |     \qmlproperty bool QtQuick.VirtualKeyboard::VirtualKeyboardSettings::wordCandidateList.alwaysVisible | 
| 400 |  | 
| 401 |     \table | 
| 402 |     \header | 
| 403 |         \li Name | 
| 404 |         \li Description | 
| 405 |     \row | 
| 406 |         \li autoHideDelay | 
| 407 |         \li This property defines the delay, in milliseconds, after which the | 
| 408 |             word candidate list is hidden if empty. | 
| 409 |  | 
| 410 |             If the value is \c 0, the list is immediately hidden when cleared. | 
| 411 |  | 
| 412 |             If the value is \c -1, the list is visible until input focus | 
| 413 |             changes, or the input panel is hidden. | 
| 414 |  | 
| 415 |             The default value is \c 5000 milliseconds. | 
| 416 |     \row | 
| 417 |         \li alwaysVisible | 
| 418 |         \li This property defines whether the word candidate list should always | 
| 419 |             remain visible. | 
| 420 |  | 
| 421 |             The default value is \c false. | 
| 422 |     \row | 
| 423 |         \li autoCommitWord | 
| 424 |         \li This property enables the automatic commit feature that is activated | 
| 425 |             when the word candidate list is narrowed down to a single candidate. | 
| 426 |  | 
| 427 |             The automatic commit feature takes effect when the word candidate | 
| 428 |             list initially contains multiple words and is reduced to single word | 
| 429 |             after additional input. This word will be selected and committed | 
| 430 |             automatically without user interaction. | 
| 431 |  | 
| 432 |             This property is set to \c false by default. | 
| 433 |     \endtable | 
| 434 | */ | 
| 435 |  | 
| 436 | WordCandidateListSettings::WordCandidateListSettings(QObject *parent) : | 
| 437 |     QObject(parent) | 
| 438 | { | 
| 439 | } | 
| 440 |  | 
| 441 | int WordCandidateListSettings::autoHideDelay() const | 
| 442 | { | 
| 443 |     return Settings::instance()->wclAutoHideDelay(); | 
| 444 | } | 
| 445 |  | 
| 446 | void WordCandidateListSettings::setAutoHideDelay(int autoHideDelay) | 
| 447 | { | 
| 448 |     Settings::instance()->setWclAutoHideDelay(autoHideDelay); | 
| 449 | } | 
| 450 |  | 
| 451 | bool WordCandidateListSettings::alwaysVisible() const | 
| 452 | { | 
| 453 |     return Settings::instance()->wclAlwaysVisible(); | 
| 454 | } | 
| 455 |  | 
| 456 | void WordCandidateListSettings::setAlwaysVisible(bool alwaysVisible) | 
| 457 | { | 
| 458 |     Settings::instance()->setWclAlwaysVisible(alwaysVisible); | 
| 459 | } | 
| 460 |  | 
| 461 | bool WordCandidateListSettings::autoCommitWord() const | 
| 462 | { | 
| 463 |     return Settings::instance()->wclAutoCommitWord(); | 
| 464 | } | 
| 465 |  | 
| 466 | void WordCandidateListSettings::setAutoCommitWord(bool autoCommitWord) | 
| 467 | { | 
| 468 |     Settings::instance()->setWclAutoCommitWord(autoCommitWord); | 
| 469 | } | 
| 470 |  | 
| 471 | } // namespace QtVirtualKeyboard | 
| 472 | QT_END_NAMESPACE | 
| 473 |  |