/**************************************************************************** ** qspdsay - un entorno gráfico al comando spd-say **--------------------------------------------------------------------------- ** qspdsay - main.cpp, qspdsay.cpp, qspdsay.h, qspdsay.qrc, qspdsay.ui **=========================================================================== ** FJA - neocipres@gmail.com Julio de 2011 (12/07/2012) **=========================================================================== ** This file may be used under the terms of the GNU General Public ** License version 3.0 as published by the Free Software Foundation ** and appearing in the file LICENSE.GPL included in the packaging of ** this file. Please review the following information to ensure GNU ** General Public Licensing requirements will be met: ** ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ****************************************************************************/ #include "qspdsay.h" #include "ui_qspdsay.h" #include <QMessageBox> #include <QFileDialog> #include <QTextStream> #include <QKeyEvent> #include <QSettings> qspdsay::qspdsay(QWidget *parent) : QMainWindow(parent), ui(new Ui::qspdsay) { ui->setupUi(this); comando = "spd-say"; acfg = "/home/paco/.speech-dispatcher/conf/speechd.conf"; QString argsI = QString::null; argsI.append("-l "+ui->cBLengua->currentText()); argsI.append(" -t "+ui->cBLector->currentText()); ui->lEArgumentos->setText(argsI); proc = new QProcess(ui->centralWidget); connect(ui->actionAcerca_de_Qt, SIGNAL(triggered()), qApp, SLOT(aboutQt())); connect(ui->actionAcerca_de_qspdsay, SIGNAL(triggered()), this, SLOT(acercade())); connect(ui->pBAceptar, SIGNAL(clicked()), this, SLOT(aceptar())); connect(ui->pBStop, SIGNAL(clicked()), this, SLOT(stopLeer())); connect(ui->actionAyuda_spd_say, SIGNAL(triggered()), this, SLOT(ayuda())); connect(ui->cBLengua, SIGNAL(currentIndexChanged(QString )), this, SLOT(modificaLengua(QString ))); connect(ui->cBLector, SIGNAL(currentIndexChanged(QString )), this, SLOT(modificaLector(QString ))); connect(ui->hSRate, SIGNAL(valueChanged(int)), this, SLOT(modificaRate(int ))); connect(ui->actionAbrir_Archivo, SIGNAL(triggered()), this, SLOT(abrirA())); connect(ui->actionGuardar_Archivo, SIGNAL(triggered()), this, SLOT(guardarAcomo())); connect(ui->actionGuardar, SIGNAL(triggered()), this, SLOT(guardarA())); connect(ui->actionCerrar, SIGNAL(triggered()), this, SLOT(cerrarA())); connect(ui->actionVer_speechd_conf, SIGNAL(triggered()), this, SLOT(verConf())); connect(proc, SIGNAL(readyReadStandardOutput()), this, SLOT(readFromStdout())); connect(proc, SIGNAL(readyReadStandardError()), this, SLOT(readFromStderr())); connect(proc, SIGNAL(error(QProcess::ProcessError )), this, SLOT(tipoError(QProcess::ProcessError ))); for (int i = 0; i < MaxRecentFiles; ++i) { recentFileActs[i] = new QAction(this); recentFileActs[i]->setVisible(false); connect(recentFileActs[i], SIGNAL(triggered()), this, SLOT(openRecentFile())); } crearMenu(); readSettings(); } qspdsay::~qspdsay() { //writeSettings(); delete ui; } void qspdsay::crearMenu() { ui->menuArchivo->addSeparator(); for (int i = 0; i < MaxRecentFiles; ++i) ui->menuArchivo->addAction(recentFileActs[i]); updateRecentFileActions(); } void qspdsay::acercade() { QString separador = QString::null; separador.fill('=', 40); QString nomAp = "<p><b><BIG><BIG>qspdsay</BIG></BIG></b></p>"; QString desAp1 = "<p><b>"+QString::fromUtf8("Entorno gráfico al comando spd-say")+"</b></p>"; QString desAp2 = "<p>"+QString::fromUtf8("<br><b>spd-say</b> es un comando que forma parte del proyecto <a href= http://devel.freebsoft.org/speechd>speech-dispatcher</a>, el cual proporciona una capa independiente del dispositivo para la síntesis de voz.")+"</p>"; QString teclas = QString::null; teclas.append(QString::fromUtf8("<p>F1 -> Inicia el proceso de lectura</p>" )); QString autor = "<p><b>FJA</b> - neocipres@gmail.com</p>"; QString version = QString::fromUtf8("<p>Versión: 0.9.9</p>"); QString modificado = "<p>Julio de 2011 - Modificado el 12 de Jul/2012</p>"; QString licencia = QString::fromUtf8("<p>Distribuido de acuerdo a los términos de la <a href= http://www.viti.es/gnu/licenses/gpl.html>licencia GNU/GPL</a></p>"); QString gnu = "<p><a href= http://www.gnu.org/home.es.html>Proyecto GNU</a></p>"; QMessageBox::about(ui->centralWidget, "Acerca de ...",nomAp+desAp1+desAp2+teclas+separador+autor+modificado+separador+version+licencia+gnu); } void qspdsay::aceptar() { QString cmd = comando; QStringList args = (QStringList() << ui->lEArgumentos->text().split(" ")); if (ui->rBLinea->isChecked()) { QString linea = leeLinea(); args << linea; } if (ui->rBBloque->isChecked()) { QString bloque = leeBloque(); args << bloque; } if (ui->rBTextoC->isChecked()) { args << ui->tEEditor->toPlainText(); } ejecutar(cmd, args); } void qspdsay::stopLeer() { cerrarA(); ui->rBLinea->setChecked(true); aceptar(); } void qspdsay::ejecutar(QString cmd, QStringList args) { ui->tESalida->clear(); if (proc->state() == 0) proc->start(cmd, args, QIODevice::ReadOnly); else ui->statusBar->showMessage(QString("El proceso %1 no puede ejecutarse, hay otro proceso corriendo.").arg(cmd), 5000); } void qspdsay::readFromStdout() { QByteArray datos = proc->readAllStandardOutput(); QString linea = QString::null; linea.append(QString::fromUtf8(datos)); ui->tESalida->append(linea); } void qspdsay::readFromStderr() { QByteArray datos = proc->readAllStandardError(); QString linea = QString::null; ui->tESalida->append("<b>"+linea+"</b>"); } void qspdsay::tipoError(QProcess::ProcessError error) { QString cadE; switch (error) { case QProcess::FailedToStart: cadE = QString::fromUtf8("El proceso %1 ha fallado al iniciarse.\nPuede que no exista, o no se tengan los permisos suficientes").arg(comando); break; case QProcess::Crashed: cadE = QString::fromUtf8("Después de un inicio correcto,\nel proceso %1 se ha roto.").arg(comando); break; case QProcess::Timedout: cadE = "The last waitFor...() function timed out. The state of QProcess is unchanged, and you can try calling waitFor...() again."; break; case QProcess::WriteError: cadE = "An error occurred when attempting to write to the process.\nFor example, the process may not be running, or it may have closed its input channel."; break; case QProcess::ReadError: cadE = "An error occurred when attempting to read from the process.\nFor example, the process may not be running."; break; case QProcess::UnknownError: cadE = QString::fromUtf8("Un error desconocido en el proceso %1.").arg(comando); break; } QMessageBox::warning( ui->centralWidget, tr("Error - spd-say"), tr("Error: ")+QString::number(error)+". "+cadE, tr("Aceptar") ); } void qspdsay::ayuda() { QStringList args; args << "-h"; ejecutar("spd-say", args); } void qspdsay::modificaLengua(QString ) { modificarArgs(); } void qspdsay::modificaLector(QString ) { modificarArgs(); } void qspdsay::modificaRate(int ) { modificarArgs(); } void qspdsay::modificarArgs() { QString args; ui->lEArgumentos->clear(); args.append("-l "+ui->cBLengua->currentText()); args.append(" -t "+ui->cBLector->currentText()); if (ui->hSRate->value() != 0) args.append(" -r "+QString::number(ui->hSRate->value())); ui->lEArgumentos->setText(args); } QString qspdsay::leeLinea() { c = ui->tEEditor->textCursor(); c.select(QTextCursor::LineUnderCursor); // QTextCursor::BlockUnderCursor QString linea = c.selectedText(); c.movePosition(QTextCursor::Down); // QTextCursor::NextBlock ui->tEEditor->setTextCursor(c); return linea; } QString qspdsay::leeBloque() { c = ui->tEEditor->textCursor(); c.select(QTextCursor::BlockUnderCursor); QString bloque = c.selectedText(); c.movePosition(QTextCursor::NextBlock); ui->tEEditor->setTextCursor(c); return bloque; } void qspdsay::abrirA() { QString nomF = QFileDialog::getOpenFileName(this, tr("Abrir archivo de texto a voz"), QDir::homePath(), tr("Archivos de voz (*.voz);;Archivos de texto (*.txt)")); if ( !nomF.isEmpty () ) { loadFile(nomF); } } void qspdsay::loadFile(const QString &nomF) { QFile fichero(nomF); if (!fichero.open( QFile::ReadOnly | QFile::Text )) { QString aviso = tr("No se puede abrir el archivo:\n\n %1\n\n%2").arg(nomF).arg(fichero.errorString()); QMessageBox::critical(ui->centralWidget, "Error al abrir", aviso, "Aceptar"); return; } QTextStream ts(&fichero); ui->tEEditor->clear(); ui->tEEditor->setText(ts.readAll()); setCurrentFile(nomF); ui->statusBar->showMessage(tr("Archivo cargado"), 3000); } bool qspdsay::txtNoMod() { if (ui->tEEditor->document()->isModified()) { int ret = QMessageBox::warning(this, tr("archivo modificado"), QString::fromUtf8("El documento ha sido modificado.\n" "¿Quiere salvar los cambios?"), QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape); if (ret == QMessageBox::Yes) return guardarA(); else if (ret == QMessageBox::Cancel) return false; } return true; } bool qspdsay::guardarA() { if (curFile.isEmpty()) return guardarAcomo(); else saveFile(curFile); return true; } bool qspdsay::guardarAcomo() { QString nomF = QFileDialog::getSaveFileName(this, tr("Guardar archivo"), QDir::homePath(), tr("Archivos de voz (*.voz);;Archivos de texto (*.txt)")); if (nomF.isEmpty()) return false; //if (!nomF.contains(".voz")) {nomF.append(".voz");} saveFile(nomF); return true; } void qspdsay::saveFile(const QString &nomF) { QFile fichero(nomF); if ( !fichero.open(QFile::WriteOnly | QFile::Text) ){ QString aviso = tr("No se puede grabar el archivo:\n\n %1\n\n%2").arg(nomF).arg(fichero.errorString()); QMessageBox::critical(ui->centralWidget, "Error al grabar", aviso, "Aceptar"); return; } QTextStream ts(&fichero); ts << ui->tEEditor->toPlainText(); fichero.close(); QApplication::restoreOverrideCursor(); setCurrentFile(nomF); ui->statusBar->showMessage("Archivo de voz: "+nomF+" guardado", 5000); } void qspdsay::cerrarA() { curFile = ""; ui->tEEditor->clear(); } void qspdsay::verConf() { QFile fichero(acfg); if ( !fichero.open( QFile::ReadOnly | QFile::Text ) ){ ui->statusBar->showMessage("No se puede abrir: "+acfg, 5000); return; } QTextStream ts(&fichero); ui->tESalida->clear(); ui->tESalida->setText(ts.readAll()); } void qspdsay::keyPressEvent(QKeyEvent *event) { int tecla = event->key(); switch (tecla) { case Qt::Key_F1: aceptar(); break; } } void qspdsay::closeEvent(QCloseEvent* event) { if (txtNoMod()) { writeSettings(); event->accept(); } else { event->ignore(); } } void qspdsay::openRecentFile() { QAction *action = qobject_cast<QAction *>(sender()); if (action) loadFile(action->data().toString()); } QString qspdsay::strippedName(const QString &fullFileName) { return QFileInfo(fullFileName).fileName(); } void qspdsay::updateRecentFileActions() { QSettings settings; QStringList files = settings.value("recentFileList").toStringList(); int numRecentFiles = qMin(files.size(), (int)MaxRecentFiles); for (int i = 0; i < numRecentFiles; ++i) { QString text = tr("&%1 %2").arg(i + 1).arg(strippedName(files[i])); recentFileActs[i]->setText(text); recentFileActs[i]->setData(files[i]); recentFileActs[i]->setVisible(true); } for (int j = numRecentFiles; j < MaxRecentFiles; ++j) recentFileActs[j]->setVisible(false); //separatorAct->setVisible(numRecentFiles > 0); } void qspdsay::setCurrentFile(const QString &fileName) { curFile = fileName; setWindowFilePath(curFile); QSettings settings; QStringList files = settings.value("recentFileList").toStringList(); files.removeAll(fileName); files.prepend(fileName); while (files.size() > MaxRecentFiles) files.removeLast(); settings.setValue("recentFileList", files); foreach (QWidget *widget, QApplication::topLevelWidgets()) { qspdsay *mainWin = qobject_cast<qspdsay *>(widget); if (mainWin) mainWin->updateRecentFileActions(); } } void qspdsay::readSettings() { QSettings settings; QPoint pos = settings.value("pos", QPoint(20, 20)).toPoint(); QSize size = settings.value("size", QSize(800, 600)).toSize(); QByteArray state = settings.value("state", QByteArray()).toByteArray(); QString ua = settings.value("ua", "").toString(); restoreState(state); resize(size); move(pos); if (!ua.isEmpty()) loadFile(ua); } void qspdsay::writeSettings() { /* Save postion/size of main window y el último archivo abierto */ QSettings settings; settings.setValue("pos", pos()); settings.setValue("size", size()); settings.setValue("state", saveState()); settings.setValue("ua", curFile); }