KTextAddons

voskenginelanguagewidget.cpp
1/*
2 SPDX-FileCopyrightText: 2023-2025 Laurent Montel <montel@kde.org>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "voskenginelanguagewidget.h"
8#include "libvoskspeechtotext_debug.h"
9#include "voskspeechtotextmodel.h"
10#include "voskspeechtotextproxymodel.h"
11
12#include <KLocalizedString>
13#include <KMessageBox>
14#include <QLabel>
15#include <QLineEdit>
16#include <QProgressBar>
17#include <QPushButton>
18#include <QTreeView>
19#include <QVBoxLayout>
20
21#include <KLineEditEventHandler>
22
23VoskEngineLanguageWidget::VoskEngineLanguageWidget(QWidget *parent)
24 : QWidget{parent}
25 , mTreeView(new QTreeView(this))
26 , mSearchLineEdit(new QLineEdit(this))
27 , mVoskSpeechToTextModel(new VoskSpeechToTextModel(this))
28 , mVoskSpeechToTextProxyModel(new VoskSpeechToTextProxyModel(this))
29 , mProgressBar(new QProgressBar(this))
30 , mProgressBarLabel(new QLabel(this))
31 , mProgressBarWidget(new QWidget(this))
32{
33 auto mainLayout = new QVBoxLayout(this);
34 mainLayout->setObjectName(QStringLiteral("mainLayout"));
35 mainLayout->setContentsMargins({});
36
37 auto hboxLayout = new QHBoxLayout;
38 hboxLayout->setObjectName(QStringLiteral("hboxLayout"));
39 hboxLayout->setContentsMargins({});
40 mainLayout->addLayout(hboxLayout);
41
42 auto vboxLayout = new QVBoxLayout;
43 vboxLayout->setObjectName(QStringLiteral("vboxLayout"));
44 vboxLayout->setContentsMargins({});
45
46 mSearchLineEdit->setObjectName(QStringLiteral("mSearchLineEdit"));
47 vboxLayout->addWidget(mSearchLineEdit);
48 mSearchLineEdit->setPlaceholderText(i18nc("@info:placeholder", "Search…"));
49 mSearchLineEdit->setClearButtonEnabled(true);
50
52
53 mTreeView->setObjectName(QStringLiteral("mTreeView"));
54 connect(ManagerModelVoskSpeechToText::self(), &ManagerModelVoskSpeechToText::errorText, this, &VoskEngineLanguageWidget::slotError);
55 connect(ManagerModelVoskSpeechToText::self(), &ManagerModelVoskSpeechToText::progress, this, &VoskEngineLanguageWidget::slotProgressInfo);
56 connect(ManagerModelVoskSpeechToText::self(),
57 &ManagerModelVoskSpeechToText::extractDone,
58 mVoskSpeechToTextModel,
59 &VoskSpeechToTextModel::updateInstalledLanguage);
60 connect(ManagerModelVoskSpeechToText::self(), &ManagerModelVoskSpeechToText::downLoadModelListDone, this, &VoskEngineLanguageWidget::updateListModel);
61
62 // TODO store list on local.
63 if (ManagerModelVoskSpeechToText::self()->needDownloadModelList()) {
64 ManagerModelVoskSpeechToText::self()->downloadListModels();
65 } else {
66 mVoskSpeechToTextModel->setSpeechToTextInfos(ManagerModelVoskSpeechToText::self()->speechToTextInfos());
67 }
68
69 mVoskSpeechToTextProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
70 mVoskSpeechToTextProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
71 mVoskSpeechToTextProxyModel->setSourceModel(mVoskSpeechToTextModel);
72 mTreeView->setModel(mVoskSpeechToTextProxyModel);
73 mTreeView->setRootIsDecorated(false);
74 mTreeView->setSortingEnabled(true);
75 vboxLayout->addWidget(mTreeView);
76
77 hboxLayout->addLayout(vboxLayout);
78
79 auto buttonLayout = new QVBoxLayout;
80 buttonLayout->setObjectName(QStringLiteral("buttonLayout"));
81 hboxLayout->addLayout(buttonLayout);
82
83 auto downLoadLanguage = new QPushButton(QIcon::fromTheme(QStringLiteral("download-symbolic")), i18n("Download"), this);
84 downLoadLanguage->setObjectName(QStringLiteral("downLoadLanguage"));
85 buttonLayout->addWidget(downLoadLanguage);
86 connect(downLoadLanguage, &QPushButton::clicked, this, [this]() {
87 const auto currentlySelectedIndex = mVoskSpeechToTextProxyModel->mapToSource(mTreeView->selectionModel()->currentIndex());
88 const QModelIndex modelIndex = mVoskSpeechToTextModel->index(currentlySelectedIndex.row(), VoskSpeechToTextModel::Url);
89 const QModelIndex modelIndexCheckSum = mVoskSpeechToTextModel->index(currentlySelectedIndex.row(), VoskSpeechToTextModel::CheckSum);
90 const QModelIndex modelIndexName = mVoskSpeechToTextModel->index(currentlySelectedIndex.row(), VoskSpeechToTextModel::Name);
91 const QModelIndex modelIndexVersion = mVoskSpeechToTextModel->index(currentlySelectedIndex.row(), VoskSpeechToTextModel::AvailableVersion);
92
93 const QString url = modelIndex.data().toString();
94 const QString checkSum = modelIndexCheckSum.data().toString();
95 qCDebug(LIBVOSKSPEECHTOTEXT_LOG) << " url " << url << " checksum " << checkSum;
96 VoskDownloadLanguageJob::DownloadLanguageInfo info;
97 info.checksum = modelIndexCheckSum.data().toString();
98 info.url = QUrl(modelIndex.data().toString());
99 info.name = modelIndexName.data().toString();
100 info.version = modelIndexVersion.data().toString();
101 slotDownLoad(info);
102 });
103
104 auto deleteLanguage = new QPushButton(QIcon::fromTheme(QStringLiteral("edit-delete")), i18n("Delete"), this);
105 deleteLanguage->setObjectName(QStringLiteral("downLoadLanguage"));
106 buttonLayout->addWidget(deleteLanguage);
107
108 auto updateListLanguage = new QPushButton(i18nc("@action:button", "Update List"), this);
109 updateListLanguage->setToolTip(i18nc("@info:tooltip", "Update list of languages from network"));
110 updateListLanguage->setObjectName(QStringLiteral("updateListLanguage"));
111 buttonLayout->addWidget(updateListLanguage);
112 buttonLayout->addStretch(1); // spacer
113 connect(updateListLanguage, &QPushButton::clicked, this, &VoskEngineLanguageWidget::slotUpdateListLanguage);
114
115 connect(mSearchLineEdit, &QLineEdit::textChanged, this, &VoskEngineLanguageWidget::slotTextChanged);
116
117 auto progressBarLayout = new QHBoxLayout;
118 progressBarLayout->setObjectName(QStringLiteral("progressBarLayout"));
119
120 mProgressBarLabel->setObjectName(QStringLiteral("mProgressBarLabel"));
121 progressBarLayout->addWidget(mProgressBarLabel);
122
123 mProgressBar->setObjectName(QStringLiteral("mProgressBar"));
124 progressBarLayout->addWidget(mProgressBar);
125
126 mProgressBarWidget->setObjectName(QStringLiteral("mProgressBarWidget"));
127 mProgressBarWidget->setLayout(progressBarLayout);
128
129 mainLayout->addWidget(mProgressBarWidget);
130 mProgressBarWidget->setVisible(false);
131
132 mTreeView->setColumnHidden(VoskSpeechToTextModel::Url, true);
133 mTreeView->setColumnHidden(VoskSpeechToTextModel::CheckSum, true);
134 mTreeView->setColumnHidden(VoskSpeechToTextModel::Identifier, true);
135 mTreeView->setColumnHidden(VoskSpeechToTextModel::NeedToUpdateLanguage, true);
136 mTreeView->setColumnHidden(VoskSpeechToTextModel::Name, true);
137 mTreeView->setColumnHidden(VoskSpeechToTextModel::SizeByte, true);
138 auto updateButton = [this, downLoadLanguage, deleteLanguage]() {
139 const bool hasSelectedItem = mTreeView->currentIndex().isValid();
140 const auto currentlySelectedIndex = mVoskSpeechToTextProxyModel->mapToSource(mTreeView->selectionModel()->currentIndex());
141 const QModelIndex modelIndex = mVoskSpeechToTextModel->index(currentlySelectedIndex.row(), VoskSpeechToTextModel::Installed);
142 const QModelIndex modelIndexNeedToUpdate = mVoskSpeechToTextModel->index(currentlySelectedIndex.row(), VoskSpeechToTextModel::NeedToUpdateLanguage);
143 const bool isInstalled = modelIndex.data().toBool();
144 const bool needToUpdate = modelIndexNeedToUpdate.data().toBool();
145
146 if (needToUpdate) {
147 downLoadLanguage->setEnabled(hasSelectedItem && needToUpdate);
148 } else {
149 downLoadLanguage->setEnabled(hasSelectedItem && !isInstalled);
150 }
151 deleteLanguage->setEnabled(hasSelectedItem && isInstalled);
152 };
153
154 connect(deleteLanguage, &QPushButton::clicked, this, [this, updateButton]() {
155 const auto currentlySelectedIndex = mVoskSpeechToTextProxyModel->mapToSource(mTreeView->selectionModel()->currentIndex());
156 const QModelIndex modelIndex = mVoskSpeechToTextModel->index(currentlySelectedIndex.row(), VoskSpeechToTextModel::Name);
157 const QString identifier = modelIndex.data().toString();
158 slotDelete(identifier);
159 updateButton();
160 });
161
162 connect(mTreeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, [updateButton]() {
163 updateButton();
164 });
165 downLoadLanguage->setEnabled(false);
166 deleteLanguage->setEnabled(false);
167}
168
169VoskEngineLanguageWidget::~VoskEngineLanguageWidget() = default;
170
171void VoskEngineLanguageWidget::slotProgressInfo(const ManagerModelVoskSpeechToText::ProgressInfo &info)
172{
173 if (info.bytesReceived != info.bytesTotal) {
174 mProgressBarWidget->setVisible(true);
175 } else {
176 mProgressBarWidget->setVisible(false);
177 }
178 mProgressBarLabel->setText(info.languageName);
179 mProgressBar->setRange(0, 100);
180 mProgressBar->setValue((info.bytesReceived * 100) / info.bytesTotal);
181}
182
183void VoskEngineLanguageWidget::slotError(const QString &str)
184{
185 KMessageBox::error(this, i18n("Error: %1", str), i18n("Vosk"));
186}
187
188void VoskEngineLanguageWidget::slotTextChanged(const QString &str)
189{
190 mVoskSpeechToTextProxyModel->setSearchString(str);
191}
192
193void VoskEngineLanguageWidget::slotDownLoad(const VoskDownloadLanguageJob::DownloadLanguageInfo &info)
194{
195 ManagerModelVoskSpeechToText::self()->downloadLanguage(info);
196}
197
198void VoskEngineLanguageWidget::slotDelete(const QString &name)
199{
200 mVoskSpeechToTextModel->removeLanguage(name);
201}
202
203void VoskEngineLanguageWidget::slotUpdateListLanguage()
204{
205 ManagerModelVoskSpeechToText::self()->downloadListModels();
206}
207
208void VoskEngineLanguageWidget::updateListModel()
209{
210 mVoskSpeechToTextModel->setSpeechToTextInfos(ManagerModelVoskSpeechToText::self()->speechToTextInfos());
211}
212
213#include "moc_voskenginelanguagewidget.cpp"
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
void catchReturnKey(QObject *lineEdit)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
void clicked(bool checked)
QIcon fromTheme(const QString &name)
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
void textChanged(const QString &text)
QVariant data(int role) const const
void setObjectName(QAnyStringView name)
CaseInsensitive
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
bool toBool() const const
QString toString() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Apr 25 2025 12:06:14 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.