soundeditor/qatsh/MainWindow.cpp

506 lines
13 KiB
C++

// MainWindow class implementation
//
// QATSH Copyright 2009 Jean-Philippe MEURET <jpmeuret@free.fr>
#include <iostream>
#include <QtCore/QSettings>
#include <QtCore/QFileInfo>
#include <QtCore/QModelIndex>
#include <QtGui/QCloseEvent>
#include <QtGui/QVBoxLayout>
#include <QtGui/QMessageBox>
#include <QtGui/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());
}