506 lines
13 KiB
C++
506 lines
13 KiB
C++
// MainWindow class implementation
|
|
//
|
|
// QATSH Copyright 2009 Jean-Philippe MEURET <jpmeuret@free.fr>
|
|
|
|
#include <iostream>
|
|
|
|
#include <QSettings>
|
|
#include <QFileInfo>
|
|
#include <QModelIndex>
|
|
|
|
#include <QCloseEvent>
|
|
#include <QVBoxLayout>
|
|
#include <QMessageBox>
|
|
#include <QFileDialog>
|
|
|
|
#include "IATSAnalysis.h"
|
|
#include "DocumentWindow.h"
|
|
#include "PreferencesDialog.h"
|
|
#include "AnalysisParamsDialog.h"
|
|
|
|
#include "MainWindow.h"
|
|
#include "ui_MainWindow.h"
|
|
|
|
|
|
// Constructors / Destructor ===============================================
|
|
MainWindow::MainWindow(QWidget *parent)
|
|
: QMainWindow(parent)
|
|
{
|
|
init();
|
|
}
|
|
|
|
MainWindow::MainWindow(const QString &qsFileName, QWidget *parent)
|
|
: QMainWindow(parent)
|
|
{
|
|
init();
|
|
if (QFileInfo(qsFileName).suffix().toLower() == "ats")
|
|
loadFile(qsFileName);
|
|
else
|
|
analyseFile(qsFileName);
|
|
}
|
|
|
|
MainWindow::MainWindow(const QString &qsFileName, IATSAnalysis* pAnalysis, QWidget *parent)
|
|
: QMainWindow(parent)
|
|
{
|
|
init();
|
|
analyseFile(qsFileName, pAnalysis);
|
|
}
|
|
|
|
void MainWindow::init()
|
|
{
|
|
_pui = new Ui::MainWindow;
|
|
_pui->setupUi(this);
|
|
|
|
setAttribute(Qt::WA_DeleteOnClose);
|
|
|
|
_pqwDocWin = 0;
|
|
|
|
_bIsUntitled = true;
|
|
|
|
setWindowTitle(QString("%1 %2").arg(qApp->applicationName()).arg(qApp->applicationVersion()));
|
|
resize(QSize(640, 480));
|
|
|
|
// Connect actions to local slots.
|
|
connect(_pui->qaNewFile, SIGNAL(triggered()), this, SLOT(newFile()));
|
|
connect(_pui->qaOpenFile, SIGNAL(triggered()), this, SLOT(openFile()));
|
|
connect(_pui->qaSaveFile, SIGNAL(triggered()), this, SLOT(saveFile()));
|
|
connect(_pui->qaSaveFileAs, SIGNAL(triggered()), this, SLOT(saveFileAs()));
|
|
connect(_pui->qaFileProperties, SIGNAL(triggered()), this, SLOT(showFileProperties()));
|
|
|
|
connect(_pui->qaPreferences, SIGNAL(triggered()), this, SLOT(preferences()));
|
|
|
|
connect(_pui->qaReAnalyse, SIGNAL(triggered()), this, SLOT(showAnalysisTool()));
|
|
connect(_pui->qaReSynthesize, SIGNAL(triggered()), this, SLOT(showSynthesisTool()));
|
|
connect(_pui->qaPlaySynthSound, SIGNAL(triggered()), this, SLOT(startPlayingSynthesisResult()));
|
|
connect(_pui->qaWinPartials, SIGNAL(triggered()), this, SLOT(showPartialsSpectrogram()));
|
|
connect(_pui->qaWinResidual, SIGNAL(triggered()), this, SLOT(showResidualsSpectrogram()));
|
|
|
|
connect(_pui->qaZoomIn, SIGNAL(triggered()), this, SLOT(zoomIn()));
|
|
connect(_pui->qaZoomOut, SIGNAL(triggered()), this, SLOT(zoomOut()));
|
|
connect(_pui->qaZoomAll, SIGNAL(triggered()), this, SLOT(zoomAll()));
|
|
connect(_pui->qaZoomSel, SIGNAL(triggered()), this, SLOT(zoomSelection()));
|
|
|
|
connect(_pui->qaAbout, SIGNAL(triggered()), this, SLOT(about()));
|
|
|
|
// Setup action list for enableAction() member function.
|
|
_qlActions << _pui->qaNewFile << _pui->qaOpenFile << _pui->qaSaveFile
|
|
<< _pui->qaSaveFileAs << _pui->qaFileProperties << _pui->qaPreferences
|
|
<< _pui->qaReAnalyse << _pui->qaReSynthesize
|
|
<< _pui->qaWinPartials << _pui->qaWinResidual << _pui->qaAbout;
|
|
|
|
// Disable some actions for the moment.
|
|
enableAction(eSaveFile, false);
|
|
enableAction(eSaveFileAs, false);
|
|
enableAction(eFileProperties, false);
|
|
enableAction(eReAnalyse, false);
|
|
enableAction(eReSynthesize, false);
|
|
enableAction(eWinPartials, false);
|
|
enableAction(eWinResidual, false);
|
|
}
|
|
|
|
MainWindow::~MainWindow()
|
|
{
|
|
delete _pui;
|
|
}
|
|
|
|
// Private slots ===========================================================
|
|
void MainWindow::enableAction(EActionId eActionId, bool bEnable)
|
|
{
|
|
if (eActionId >= 0 && eActionId < eActionNumber)
|
|
_qlActions[eActionId]->setEnabled(bEnable);
|
|
}
|
|
|
|
void MainWindow::newFile()
|
|
{
|
|
const QString qsFileName =
|
|
QFileDialog::getOpenFileName(this, tr("Choose a sound file"),
|
|
"", // TODO: get from settings
|
|
tr("Sound files "
|
|
"(*.wav *.aif* *.au *.caf *.raw *.flac *.w64 "
|
|
"*.voc *.snd *.sf *.pcm *.iff *.svx *.nist *.sph)"));
|
|
if (!qsFileName.isEmpty())
|
|
analyseFile(qsFileName);
|
|
}
|
|
|
|
void MainWindow::openFile()
|
|
{
|
|
const QString qsFileName = QFileDialog::getOpenFileName(this, tr("Choose an ATS File"),
|
|
"", // TODO: get path from settings
|
|
tr("ATS files (*.ats)"));
|
|
|
|
if (!qsFileName.isEmpty())
|
|
{
|
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
|
|
|
if (!_pqwDocWin)
|
|
{
|
|
loadFile(qsFileName);
|
|
}
|
|
else
|
|
{
|
|
MainWindow *pqmwNew = new MainWindow(qsFileName, (QWidget*)0);
|
|
if (pqmwNew->isUntitled())
|
|
delete pqmwNew;
|
|
else
|
|
{
|
|
pqmwNew->move(x() + 40, y() + 40);
|
|
pqmwNew->show();
|
|
}
|
|
}
|
|
|
|
QApplication::restoreOverrideCursor();
|
|
}
|
|
}
|
|
|
|
bool MainWindow::saveFile()
|
|
{
|
|
if (isUntitled()) {
|
|
return saveFileAs();
|
|
} else if (isWindowModified()) {
|
|
return storeFile(_qsCurFileName);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool MainWindow::saveFileAs()
|
|
{
|
|
const QString qsFileName =
|
|
QFileDialog::getSaveFileName(this, tr("Save ATS file as"), _qsCurFileName);
|
|
|
|
if (qsFileName.isEmpty())
|
|
return false;
|
|
|
|
return storeFile(qsFileName);
|
|
}
|
|
|
|
void MainWindow::preferences()
|
|
{
|
|
PreferencesDialog prefsDlg(this);
|
|
prefsDlg.exec();
|
|
}
|
|
|
|
void MainWindow::showFileProperties()
|
|
{
|
|
if (_pqwDocWin)
|
|
_pqwDocWin->showFileProperties();
|
|
}
|
|
|
|
void MainWindow::showAnalysisTool()
|
|
{
|
|
if (_pqwDocWin)
|
|
{
|
|
if (_pui->qaReAnalyse->isChecked())
|
|
{
|
|
_pqwDocWin->showAnalysisTool();
|
|
_pui->qaReSynthesize->setChecked(false);
|
|
}
|
|
else
|
|
_pqwDocWin->showSelectionEditionTool();
|
|
}
|
|
}
|
|
|
|
void MainWindow::showSynthesisTool()
|
|
{
|
|
if (_pqwDocWin)
|
|
{
|
|
if (_pui->qaReSynthesize->isChecked())
|
|
{
|
|
_pqwDocWin->showSynthesisTool();
|
|
_pui->qaReAnalyse->setChecked(false);
|
|
}
|
|
else
|
|
_pqwDocWin->showSelectionEditionTool();
|
|
}
|
|
}
|
|
|
|
void MainWindow::startPlayingSynthesisResult()
|
|
{
|
|
if (_pqwDocWin)
|
|
_pqwDocWin->onStartPlayingSynthesisResult();
|
|
}
|
|
|
|
void MainWindow::showSelectionEditionTool()
|
|
{
|
|
if (_pqwDocWin)
|
|
{
|
|
_pui->qaReAnalyse->setChecked(false);
|
|
_pui->qaReSynthesize->setChecked(false);
|
|
_pqwDocWin->showSelectionEditionTool();
|
|
}
|
|
}
|
|
|
|
void MainWindow::showPartialsSpectrogram()
|
|
{
|
|
if (_pqwDocWin)
|
|
{
|
|
if (_pui->qaWinPartials->isChecked())
|
|
{
|
|
_pqwDocWin->showGraphicalView(DocumentWindow::ePartialsSpectrogram);
|
|
_pui->qaWinResidual->setChecked(false);
|
|
}
|
|
else
|
|
// Inhibit user uncheck : he must click on qaWinResidual to do that
|
|
_pui->qaWinPartials->setChecked(true);
|
|
}
|
|
}
|
|
|
|
void MainWindow::showResidualsSpectrogram()
|
|
{
|
|
if (_pqwDocWin)
|
|
{
|
|
if (_pui->qaWinResidual->isChecked())
|
|
{
|
|
_pqwDocWin->showGraphicalView(DocumentWindow::eResidualsSpectrogram);
|
|
_pui->qaWinPartials->setChecked(false);
|
|
}
|
|
else
|
|
// Inhibit user uncheck : he must click on qaWinPartials to do that
|
|
_pui->qaWinResidual->setChecked(true);
|
|
}
|
|
}
|
|
|
|
void MainWindow::zoomIn()
|
|
{
|
|
if (_pqwDocWin)
|
|
_pqwDocWin->zoomIn();
|
|
}
|
|
|
|
void MainWindow::zoomOut()
|
|
{
|
|
if (_pqwDocWin)
|
|
_pqwDocWin->zoomOut();
|
|
}
|
|
|
|
void MainWindow::zoomAll()
|
|
{
|
|
if (_pqwDocWin)
|
|
_pqwDocWin->zoomAll();
|
|
}
|
|
|
|
void MainWindow::zoomSelection()
|
|
{
|
|
if (_pqwDocWin)
|
|
_pqwDocWin->zoomSelection();
|
|
}
|
|
|
|
void MainWindow::undo()
|
|
{
|
|
statusBar()->showMessage(tr("Invoked Edit|Undo"));
|
|
}
|
|
|
|
void MainWindow::redo()
|
|
{
|
|
statusBar()->showMessage(tr("Invoked Edit|Redo"));
|
|
}
|
|
|
|
void MainWindow::about()
|
|
{
|
|
statusBar()->showMessage(tr("Invoked Help|About"));
|
|
QMessageBox::about(this, tr("About %1").arg(qApp->applicationName()),
|
|
tr("<b>%1 %2</b>\n\nA Qt 4 GUI for ATSA\n\n"
|
|
"Copyright 2009 Jean-Philippe Meuret <jpmeuret@free.fr>\n\n"
|
|
"Based on ATSA library and heavily inspired from WATSH\n"
|
|
"by Oscar Pablo Di Liscia / Pete Moss / Juan Pampin\n"
|
|
"<http://www-ccrma.stanford.edu/~juan/ATS.html>")
|
|
.arg(qApp->applicationName()).arg(qApp->applicationVersion()));
|
|
}
|
|
|
|
// Private member functions ===============================================
|
|
|
|
bool MainWindow::isUntitled() const
|
|
{
|
|
return _bIsUntitled;
|
|
}
|
|
|
|
bool MainWindow::maybeSave()
|
|
{
|
|
if (isWindowModified())
|
|
{
|
|
QMessageBox::StandardButton ret;
|
|
ret = QMessageBox::warning(this, qApp->applicationName(),
|
|
tr("The document has been modified.\n"
|
|
"Do you want to save your changes ?"),
|
|
QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
|
|
if (ret == QMessageBox::Save)
|
|
return saveFile();
|
|
else if (ret == QMessageBox::Cancel)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void MainWindow::setCurrentFile(const QString &qsFileName)
|
|
{
|
|
static int nNoNameDocNum = 1;
|
|
|
|
_bIsUntitled = qsFileName.isEmpty();
|
|
|
|
if (_bIsUntitled)
|
|
_qsCurFileName = tr("NoName%1.ats").arg(nNoNameDocNum++);
|
|
else
|
|
_qsCurFileName = QFileInfo(qsFileName).canonicalFilePath();
|
|
|
|
setWindowTitle(tr("%1[*] - %2 %3").arg(simpleFileName(_qsCurFileName))
|
|
.arg(qApp->applicationName()).arg(qApp->applicationVersion()));
|
|
//setWindowModified(_bIsUntitled);
|
|
}
|
|
|
|
QString MainWindow::simpleFileName(const QString &qsFullFileName)
|
|
{
|
|
return QFileInfo(qsFullFileName).fileName();
|
|
}
|
|
|
|
void MainWindow::layoutDocumentWindow(DocumentWindow* pqwDocWin)
|
|
{
|
|
QVBoxLayout* qvblMainLayout = new QVBoxLayout(_pui->qwCentralWidget);
|
|
|
|
qvblMainLayout->setObjectName(QString::fromUtf8("qvblMainLayout"));
|
|
qvblMainLayout->setContentsMargins(2, 2, 2, 2);
|
|
|
|
qvblMainLayout->addWidget(pqwDocWin);
|
|
}
|
|
|
|
void MainWindow::analyseFile(const QString& qsFileName)
|
|
{
|
|
AnalysisParamsDialog anaParDlg(this);
|
|
if (anaParDlg.exec() == QDialog::Accepted)
|
|
{
|
|
if (!_pqwDocWin)
|
|
{
|
|
analyseFile(qsFileName, anaParDlg.analysisParams());
|
|
}
|
|
else
|
|
{
|
|
MainWindow *pqmwNew = new MainWindow(qsFileName, anaParDlg.analysisParams(), 0);
|
|
pqmwNew->move(x() + 40, y() + 40);
|
|
pqmwNew->show();
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::analyseFile(const QString &qsFileName, IATSAnalysis* pAnalysis)
|
|
{
|
|
layoutDocumentWindow(_pqwDocWin = new DocumentWindow(this));
|
|
|
|
statusBar()->showMessage(tr("Analysing file ..."));
|
|
|
|
if (_pqwDocWin->analyseFile(qsFileName, pAnalysis))
|
|
{
|
|
_pqwDocWin->show();
|
|
setCurrentFile("");
|
|
statusBar()->showMessage(tr("Analysis done"), 2000);
|
|
}
|
|
else
|
|
{
|
|
delete _pqwDocWin;
|
|
_pqwDocWin = 0;
|
|
statusBar()->showMessage(tr("Analysis failed"), 2000);
|
|
QMessageBox::warning(this, qApp->applicationName(),
|
|
tr("Analysis failed for file %1.").arg(qsFileName));
|
|
}
|
|
}
|
|
|
|
void MainWindow::loadFile(const QString &qsFileName)
|
|
{
|
|
layoutDocumentWindow(_pqwDocWin = new DocumentWindow(this));
|
|
|
|
statusBar()->showMessage(tr("Loading file ..."));
|
|
|
|
if (_pqwDocWin->loadFile(qsFileName))
|
|
{
|
|
_pqwDocWin->show();
|
|
setCurrentFile(qsFileName);
|
|
statusBar()->showMessage(tr("File loaded"), 2000);
|
|
}
|
|
else
|
|
{
|
|
delete _pqwDocWin;
|
|
_pqwDocWin = 0;
|
|
statusBar()->showMessage(tr("Failed to load file"), 2000);
|
|
QMessageBox::warning(this, qApp->applicationName(),
|
|
tr("Could not load file %1.").arg(qsFileName));
|
|
}
|
|
}
|
|
|
|
bool MainWindow::storeFile(const QString &qsFileName)
|
|
{
|
|
bool bSavedOld = true;
|
|
|
|
statusBar()->showMessage(tr("Saving file ..."));
|
|
|
|
// Save old version of target file if present.
|
|
QFile qfOut(qsFileName);
|
|
if (qfOut.exists())
|
|
{
|
|
QFile qfOldOut(qsFileName+"~");
|
|
if (qfOldOut.exists())
|
|
bSavedOld = qfOldOut.remove();
|
|
if (bSavedOld)
|
|
bSavedOld = qfOut.rename(qfOldOut.fileName());
|
|
if (!bSavedOld)
|
|
QMessageBox::warning(this, qApp->applicationName(),
|
|
tr("Failed to save old %1 ;\ngiving up.").arg(qsFileName));
|
|
}
|
|
|
|
bool bStored = bSavedOld;
|
|
if (bSavedOld)
|
|
{
|
|
// Try and store data to the target file.
|
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
|
|
|
bStored = _pqwDocWin->storeFile(qsFileName);
|
|
|
|
QApplication::restoreOverrideCursor();
|
|
|
|
if (bStored)
|
|
{
|
|
setCurrentFile(qsFileName);
|
|
}
|
|
else
|
|
{
|
|
QMessageBox::warning(this, qApp->applicationName(),
|
|
tr("Could not write file %1 ;\n"
|
|
"reverting to old version if any.").arg(qsFileName));
|
|
|
|
// If storing the new data failed, revert to old target file version.
|
|
QFile qfOut(qsFileName);
|
|
if (qfOut.exists())
|
|
{
|
|
bool bRestoredOld = qfOut.remove();
|
|
QFile qfOldOut(qsFileName+"~");
|
|
if (bRestoredOld && qfOldOut.exists())
|
|
bRestoredOld = qfOldOut.rename(qfOut.fileName());
|
|
if (!bRestoredOld)
|
|
QMessageBox::warning(this, qApp->applicationName(),
|
|
tr("Failed to revert %1 to saved version.").arg(qsFileName));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bStored)
|
|
{
|
|
statusBar()->showMessage(tr("File saved"), 2000);
|
|
setWindowModified(false);
|
|
}
|
|
else
|
|
{
|
|
statusBar()->showMessage(tr("Failed to save file"), 2000);
|
|
}
|
|
|
|
return bStored;
|
|
}
|
|
|
|
void MainWindow::closeEvent(QCloseEvent *pqEvent)
|
|
{
|
|
// Ask user to save anything necessary if any.
|
|
if (maybeSave())
|
|
pqEvent->accept();
|
|
else
|
|
pqEvent->ignore();
|
|
|
|
// Save window size if something loaded/analysed.
|
|
QSettings qSettings;
|
|
if (_pqwDocWin)
|
|
qSettings.setValue("Window/Size", size());
|
|
}
|