1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qdeclarativetexttospeech_p.h"
5#include "qvoiceselectorattached_p.h"
6
7#include <QtCore/qregularexpression.h>
8
9QT_BEGIN_NAMESPACE
10
11using namespace Qt::StringLiterals;
12
13/*!
14 \internal
15
16 Constructor that delays the initialization of the text-to-speech
17 engine until the QML engine sets the engine.
18*/
19QDeclarativeTextToSpeech::QDeclarativeTextToSpeech(QObject *parent)
20 : QTextToSpeech(u"none"_s, parent)
21{}
22
23/*!
24 Intercept the calls to QTextToSpeech::engine/setEngine so that we can
25 delay the setting of the engine until the component is completely parsed.
26*/
27QString QDeclarativeTextToSpeech::engine() const
28{
29 if (!m_engine.isEmpty())
30 return m_engine;
31 return QTextToSpeech::engine();
32}
33
34void QDeclarativeTextToSpeech::setEngine(const QString &engine)
35{
36 if (m_engine == engine)
37 return;
38
39 m_engine = engine;
40 if (m_complete)
41 QTextToSpeech::setEngine(engine: m_engine, params: m_engineParameters);
42 emit engineChanged(m_engine);
43}
44
45/*!
46 \qmlproperty map TextToSpeech::engineParameters
47 \brief This property holds engine-specific parameters.
48
49 \sa engine
50*/
51QVariantMap QDeclarativeTextToSpeech::engineParameters() const
52{
53 return m_engineParameters;
54}
55
56void QDeclarativeTextToSpeech::setEngineParameters(const QVariantMap &parameters)
57{
58 if (m_engineParameters == parameters)
59 return;
60
61 m_engineParameters = parameters;
62 // if changed after initialization, then we need to recreate the engine
63 if (m_complete)
64 QTextToSpeech::setEngine(engine: QTextToSpeech::engine(), params: m_engineParameters);
65 emit engineParametersChanged();
66}
67
68void QDeclarativeTextToSpeech::classBegin()
69{
70}
71
72void QDeclarativeTextToSpeech::componentComplete()
73{
74 m_complete = true;
75 QTextToSpeech::setEngine(engine: m_engine, params: m_engineParameters);
76 selectVoice();
77}
78
79void QDeclarativeTextToSpeech::selectVoice()
80{
81 if (!m_complete || !m_voiceSelector)
82 return;
83
84 if (state() != QTextToSpeech::Ready) {
85 // for asynchronously initialized engines we have to wait for it to be ready
86 connect(sender: this, signal: &QTextToSpeech::stateChanged, context: this, slot: &QDeclarativeTextToSpeech::selectVoice,
87 type: Qt::SingleShotConnection);
88 } else {
89 auto voices = findVoices(criteria: m_voiceSelector->selectionCriteria());
90 if (!voices.isEmpty())
91 setVoice(voices.first());
92 }
93}
94
95
96QList<QVoice> QDeclarativeTextToSpeech::findVoices(const QVariantMap &criteria) const
97{
98 const QLocale *plocale = nullptr;
99 // if we limit by locale, then limit the search to the voices for that
100 if (const auto &it = criteria.find(key: QLatin1String("locale")); it != criteria.end()) {
101 if (it->metaType() == QMetaType::fromType<QLocale>())
102 plocale = static_cast<const QLocale *>(it->constData());
103 }
104 QList<QVoice> voices = allVoices(locale: plocale);
105
106 voices.removeIf(pred: [&criteria](const QVoice &voice){
107 const QMetaObject &mo = QVoice::staticMetaObject;
108 for (const auto &[key, value] : criteria.asKeyValueRange()) {
109 const int propertyIndex = mo.indexOfProperty(name: key.toUtf8().constData());
110 if (propertyIndex < 0) {
111 qWarning(msg: "QVoice doesn't have a property %s!", qPrintable(key));
112 } else {
113 const QMetaProperty prop = mo.property(index: propertyIndex);
114 const QVariant voiceValue = prop.readOnGadget(gadget: &voice);
115 if (voiceValue.metaType() == QMetaType::fromType<QLocale::Language>()) {
116 if (voiceValue.value<QLocale::Language>() != value.toLocale().language())
117 return true;
118 } else if (value.metaType() == QMetaType::fromType<QRegularExpression>()) {
119 if (!value.value<QRegularExpression>().match(subject: voiceValue.toString()).hasMatch())
120 return true;
121 } else if (voiceValue != value) {
122 return true;
123 }
124 }
125 }
126 return false;
127 });
128
129 return voices;
130}
131
132
133QT_END_NAMESPACE
134

source code of qtspeech/src/tts/qml/qdeclarativetexttospeech.cpp