File indexing completed on 2024-04-28 15:52:00

0001 /*
0002     SPDX-FileCopyrightText: 2008 Pino Toscano <pino@kde.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "tts.h"
0008 
0009 #include <QSet>
0010 
0011 #include <KLocalizedString>
0012 
0013 #include "settings.h"
0014 
0015 /* Private storage. */
0016 class OkularTTS::Private
0017 {
0018 public:
0019     explicit Private(OkularTTS *qq)
0020         : q(qq)
0021         , speech(new QTextToSpeech(Okular::Settings::ttsEngine()))
0022     {
0023         const QVector<QVoice> voices = speech->availableVoices();
0024         QString voiceName = Okular::Settings::ttsVoice();
0025         for (const QVoice &voice : voices) {
0026             if (voice.name() == voiceName) {
0027                 speech->setVoice(voice);
0028             }
0029         }
0030     }
0031 
0032     ~Private()
0033     {
0034         delete speech;
0035         speech = nullptr;
0036     }
0037 
0038     OkularTTS *q;
0039     QTextToSpeech *speech;
0040     // Which speech engine was used when above object was created.
0041     // When the setting changes, we need to stop speaking and recreate.
0042     QString speechEngine;
0043     Q_DISABLE_COPY(Private)
0044 };
0045 
0046 OkularTTS::OkularTTS(QObject *parent)
0047     : QObject(parent)
0048     , d(new Private(this))
0049 {
0050     // Initialize speechEngine so we can reinitialize if it changes.
0051     d->speechEngine = Okular::Settings::ttsEngine();
0052     connect(d->speech, &QTextToSpeech::stateChanged, this, &OkularTTS::slotSpeechStateChanged);
0053     connect(Okular::Settings::self(), &KCoreConfigSkeleton::configChanged, this, &OkularTTS::slotConfigChanged);
0054 }
0055 
0056 OkularTTS::~OkularTTS()
0057 {
0058     delete d;
0059 }
0060 
0061 void OkularTTS::say(const QString &text)
0062 {
0063     if (text.isEmpty()) {
0064         return;
0065     }
0066 
0067     d->speech->say(text);
0068 }
0069 
0070 void OkularTTS::stopAllSpeechs()
0071 {
0072     if (!d->speech) {
0073         return;
0074     }
0075 
0076     d->speech->stop();
0077 }
0078 
0079 void OkularTTS::pauseResumeSpeech()
0080 {
0081     if (!d->speech) {
0082         return;
0083     }
0084 
0085     if (d->speech->state() == QTextToSpeech::Speaking) {
0086         d->speech->pause();
0087     } else {
0088         d->speech->resume();
0089     }
0090 }
0091 
0092 void OkularTTS::slotSpeechStateChanged(QTextToSpeech::State state)
0093 {
0094     if (state == QTextToSpeech::Speaking) {
0095         Q_EMIT isSpeaking(true);
0096         Q_EMIT canPauseOrResume(true);
0097     } else {
0098         Q_EMIT isSpeaking(false);
0099         if (state == QTextToSpeech::Paused) {
0100             Q_EMIT canPauseOrResume(true);
0101         } else {
0102             Q_EMIT canPauseOrResume(false);
0103         }
0104     }
0105 }
0106 
0107 void OkularTTS::slotConfigChanged()
0108 {
0109     const QString engine = Okular::Settings::ttsEngine();
0110     const QString voiceName = Okular::Settings::ttsVoice();
0111     if (engine != d->speechEngine) {
0112         d->speech->stop();
0113         delete d->speech;
0114         d->speech = new QTextToSpeech(engine);
0115         connect(d->speech, &QTextToSpeech::stateChanged, this, &OkularTTS::slotSpeechStateChanged);
0116         d->speechEngine = engine;
0117     }
0118 
0119     const QVector<QVoice> voices = d->speech->availableVoices();
0120     for (const QVoice &voice : voices) {
0121         if (voice.name() == voiceName) {
0122             d->speech->setVoice(voice);
0123             break;
0124         }
0125     }
0126 }