File indexing completed on 2024-12-22 04:28:23
0001 /* 0002 SPDX-FileCopyrightText: 2023-2024 Laurent Montel <montel.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "voskenginelanguagewidget.h" 0008 #include "libvoskspeechtotext_debug.h" 0009 #include "voskspeechtotextmodel.h" 0010 #include "voskspeechtotextproxymodel.h" 0011 0012 #include <KLocalizedString> 0013 #include <KMessageBox> 0014 #include <QLabel> 0015 #include <QLineEdit> 0016 #include <QProgressBar> 0017 #include <QPushButton> 0018 #include <QTreeView> 0019 #include <QVBoxLayout> 0020 0021 #if QT_VERSION < QT_VERSION_CHECK(6, 4, 0) 0022 #include <TextAddonsWidgets/LineEditCatchReturnKey> 0023 #else 0024 #include <KLineEditEventHandler> 0025 #endif 0026 0027 VoskEngineLanguageWidget::VoskEngineLanguageWidget(QWidget *parent) 0028 : QWidget{parent} 0029 , mTreeView(new QTreeView(this)) 0030 , mSearchLineEdit(new QLineEdit(this)) 0031 , mVoskSpeechToTextModel(new VoskSpeechToTextModel(this)) 0032 , mVoskSpeechToTextProxyModel(new VoskSpeechToTextProxyModel(this)) 0033 , mProgressBar(new QProgressBar(this)) 0034 , mProgressBarLabel(new QLabel(this)) 0035 , mProgressBarWidget(new QWidget(this)) 0036 { 0037 auto mainLayout = new QVBoxLayout(this); 0038 mainLayout->setObjectName(QStringLiteral("mainLayout")); 0039 mainLayout->setContentsMargins({}); 0040 0041 auto hboxLayout = new QHBoxLayout; 0042 hboxLayout->setObjectName(QStringLiteral("hboxLayout")); 0043 hboxLayout->setContentsMargins({}); 0044 mainLayout->addLayout(hboxLayout); 0045 0046 auto vboxLayout = new QVBoxLayout; 0047 vboxLayout->setObjectName(QStringLiteral("vboxLayout")); 0048 vboxLayout->setContentsMargins({}); 0049 0050 mSearchLineEdit->setObjectName(QStringLiteral("mSearchLineEdit")); 0051 vboxLayout->addWidget(mSearchLineEdit); 0052 mSearchLineEdit->setPlaceholderText(i18n("Search...")); 0053 mSearchLineEdit->setClearButtonEnabled(true); 0054 0055 #if QT_VERSION < QT_VERSION_CHECK(6, 4, 0) 0056 new TextAddonsWidgets::LineEditCatchReturnKey(mSearchLineEdit, this); 0057 #else 0058 KLineEditEventHandler::catchReturnKey(mSearchLineEdit); 0059 #endif 0060 0061 mTreeView->setObjectName(QStringLiteral("mTreeView")); 0062 connect(ManagerModelVoskSpeechToText::self(), &ManagerModelVoskSpeechToText::errorText, this, &VoskEngineLanguageWidget::slotError); 0063 connect(ManagerModelVoskSpeechToText::self(), &ManagerModelVoskSpeechToText::progress, this, &VoskEngineLanguageWidget::slotProgressInfo); 0064 connect(ManagerModelVoskSpeechToText::self(), 0065 &ManagerModelVoskSpeechToText::extractDone, 0066 mVoskSpeechToTextModel, 0067 &VoskSpeechToTextModel::updateInstalledLanguage); 0068 connect(ManagerModelVoskSpeechToText::self(), &ManagerModelVoskSpeechToText::downLoadModelListDone, this, &VoskEngineLanguageWidget::updateListModel); 0069 0070 // TODO store list on local. 0071 if (ManagerModelVoskSpeechToText::self()->needDownloadModelList()) { 0072 ManagerModelVoskSpeechToText::self()->downloadListModels(); 0073 } else { 0074 mVoskSpeechToTextModel->setSpeechToTextInfos(ManagerModelVoskSpeechToText::self()->speechToTextInfos()); 0075 } 0076 0077 mVoskSpeechToTextProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); 0078 mVoskSpeechToTextProxyModel->setSourceModel(mVoskSpeechToTextModel); 0079 mTreeView->setModel(mVoskSpeechToTextProxyModel); 0080 mTreeView->setRootIsDecorated(false); 0081 mTreeView->setSortingEnabled(true); 0082 vboxLayout->addWidget(mTreeView); 0083 0084 hboxLayout->addLayout(vboxLayout); 0085 0086 auto buttonLayout = new QVBoxLayout; 0087 buttonLayout->setObjectName(QStringLiteral("buttonLayout")); 0088 hboxLayout->addLayout(buttonLayout); 0089 0090 auto downLoadLanguage = new QPushButton(QIcon::fromTheme(QStringLiteral("download-symbolic")), i18n("Download"), this); 0091 downLoadLanguage->setObjectName(QStringLiteral("downLoadLanguage")); 0092 buttonLayout->addWidget(downLoadLanguage); 0093 connect(downLoadLanguage, &QPushButton::clicked, this, [this]() { 0094 const auto currentlySelectedIndex = mVoskSpeechToTextProxyModel->mapToSource(mTreeView->selectionModel()->currentIndex()); 0095 const QModelIndex modelIndex = mVoskSpeechToTextModel->index(currentlySelectedIndex.row(), VoskSpeechToTextModel::Url); 0096 const QModelIndex modelIndexCheckSum = mVoskSpeechToTextModel->index(currentlySelectedIndex.row(), VoskSpeechToTextModel::CheckSum); 0097 const QModelIndex modelIndexName = mVoskSpeechToTextModel->index(currentlySelectedIndex.row(), VoskSpeechToTextModel::Name); 0098 const QModelIndex modelIndexVersion = mVoskSpeechToTextModel->index(currentlySelectedIndex.row(), VoskSpeechToTextModel::AvailableVersion); 0099 0100 const QString url = modelIndex.data().toString(); 0101 const QString checkSum = modelIndexCheckSum.data().toString(); 0102 qCDebug(LIBVOSKSPEECHTOTEXT_LOG) << " url " << url << " checksum " << checkSum; 0103 VoskDownloadLanguageJob::DownloadLanguageInfo info; 0104 info.checksum = modelIndexCheckSum.data().toString(); 0105 info.url = QUrl(modelIndex.data().toString()); 0106 info.name = modelIndexName.data().toString(); 0107 info.version = modelIndexVersion.data().toString(); 0108 slotDownLoad(info); 0109 }); 0110 0111 auto deleteLanguage = new QPushButton(QIcon::fromTheme(QStringLiteral("edit-delete")), i18n("Delete"), this); 0112 deleteLanguage->setObjectName(QStringLiteral("downLoadLanguage")); 0113 buttonLayout->addWidget(deleteLanguage); 0114 0115 auto updateListLanguage = new QPushButton(i18n("Update List"), this); 0116 updateListLanguage->setToolTip(i18n("Update list of languages from network")); 0117 updateListLanguage->setObjectName(QStringLiteral("updateListLanguage")); 0118 buttonLayout->addWidget(updateListLanguage); 0119 buttonLayout->addStretch(1); // spacer 0120 connect(updateListLanguage, &QPushButton::clicked, this, &VoskEngineLanguageWidget::slotUpdateListLanguage); 0121 0122 connect(mSearchLineEdit, &QLineEdit::textChanged, this, &VoskEngineLanguageWidget::slotTextChanged); 0123 0124 auto progressBarLayout = new QHBoxLayout; 0125 progressBarLayout->setObjectName(QStringLiteral("progressBarLayout")); 0126 0127 mProgressBarLabel->setObjectName(QStringLiteral("mProgressBarLabel")); 0128 progressBarLayout->addWidget(mProgressBarLabel); 0129 0130 mProgressBar->setObjectName(QStringLiteral("mProgressBar")); 0131 progressBarLayout->addWidget(mProgressBar); 0132 0133 mProgressBarWidget->setObjectName(QStringLiteral("mProgressBarWidget")); 0134 mProgressBarWidget->setLayout(progressBarLayout); 0135 0136 mainLayout->addWidget(mProgressBarWidget); 0137 mProgressBarWidget->setVisible(false); 0138 0139 mTreeView->setColumnHidden(VoskSpeechToTextModel::Url, true); 0140 mTreeView->setColumnHidden(VoskSpeechToTextModel::CheckSum, true); 0141 mTreeView->setColumnHidden(VoskSpeechToTextModel::Identifier, true); 0142 mTreeView->setColumnHidden(VoskSpeechToTextModel::NeedToUpdateLanguage, true); 0143 mTreeView->setColumnHidden(VoskSpeechToTextModel::Name, true); 0144 mTreeView->setColumnHidden(VoskSpeechToTextModel::SizeByte, true); 0145 auto updateButton = [this, downLoadLanguage, deleteLanguage]() { 0146 const bool hasSelectedItem = mTreeView->currentIndex().isValid(); 0147 const auto currentlySelectedIndex = mVoskSpeechToTextProxyModel->mapToSource(mTreeView->selectionModel()->currentIndex()); 0148 const QModelIndex modelIndex = mVoskSpeechToTextModel->index(currentlySelectedIndex.row(), VoskSpeechToTextModel::Installed); 0149 const QModelIndex modelIndexNeedToUpdate = mVoskSpeechToTextModel->index(currentlySelectedIndex.row(), VoskSpeechToTextModel::NeedToUpdateLanguage); 0150 const bool isInstalled = modelIndex.data().toBool(); 0151 const bool needToUpdate = modelIndexNeedToUpdate.data().toBool(); 0152 0153 if (needToUpdate) { 0154 downLoadLanguage->setEnabled(hasSelectedItem && needToUpdate); 0155 } else { 0156 downLoadLanguage->setEnabled(hasSelectedItem && !isInstalled); 0157 } 0158 deleteLanguage->setEnabled(hasSelectedItem && isInstalled); 0159 }; 0160 0161 connect(deleteLanguage, &QPushButton::clicked, this, [this, updateButton]() { 0162 const auto currentlySelectedIndex = mVoskSpeechToTextProxyModel->mapToSource(mTreeView->selectionModel()->currentIndex()); 0163 const QModelIndex modelIndex = mVoskSpeechToTextModel->index(currentlySelectedIndex.row(), VoskSpeechToTextModel::Name); 0164 const QString identifier = modelIndex.data().toString(); 0165 slotDelete(identifier); 0166 updateButton(); 0167 }); 0168 0169 connect(mTreeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, [updateButton]() { 0170 updateButton(); 0171 }); 0172 downLoadLanguage->setEnabled(false); 0173 deleteLanguage->setEnabled(false); 0174 } 0175 0176 VoskEngineLanguageWidget::~VoskEngineLanguageWidget() = default; 0177 0178 void VoskEngineLanguageWidget::slotProgressInfo(const ManagerModelVoskSpeechToText::ProgressInfo &info) 0179 { 0180 if (info.bytesReceived != info.bytesTotal) { 0181 mProgressBarWidget->setVisible(true); 0182 } else { 0183 mProgressBarWidget->setVisible(false); 0184 } 0185 mProgressBarLabel->setText(info.languageName); 0186 mProgressBar->setRange(0, 100); 0187 mProgressBar->setValue((info.bytesReceived * 100) / info.bytesTotal); 0188 } 0189 0190 void VoskEngineLanguageWidget::slotError(const QString &str) 0191 { 0192 KMessageBox::error(this, i18n("Error: %1", str), i18n("Vosk")); 0193 } 0194 0195 void VoskEngineLanguageWidget::slotTextChanged(const QString &str) 0196 { 0197 mVoskSpeechToTextProxyModel->setSearchString(str); 0198 } 0199 0200 void VoskEngineLanguageWidget::slotDownLoad(const VoskDownloadLanguageJob::DownloadLanguageInfo &info) 0201 { 0202 ManagerModelVoskSpeechToText::self()->downloadLanguage(info); 0203 } 0204 0205 void VoskEngineLanguageWidget::slotDelete(const QString &name) 0206 { 0207 mVoskSpeechToTextModel->removeLanguage(name); 0208 } 0209 0210 void VoskEngineLanguageWidget::slotUpdateListLanguage() 0211 { 0212 ManagerModelVoskSpeechToText::self()->downloadListModels(); 0213 } 0214 0215 void VoskEngineLanguageWidget::updateListModel() 0216 { 0217 mVoskSpeechToTextModel->setSpeechToTextInfos(ManagerModelVoskSpeechToText::self()->speechToTextInfos()); 0218 } 0219 0220 #include "moc_voskenginelanguagewidget.cpp"