Mercurial > hg > tony
diff src/main.cpp @ 0:158f40a613a5
Initial import of material from SV and Vect. This builds and runs, but does not yet have the layout we need
author | Chris Cannam |
---|---|
date | Fri, 16 Nov 2012 11:48:16 +0000 |
parents | |
children | ab10f175b4cb |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main.cpp Fri Nov 16 11:48:16 2012 +0000 @@ -0,0 +1,305 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Tony + An intonation analysis and annotation tool + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2006-2012 Chris Cannam and QMUL. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#include "MainWindow.h" + +#include "system/System.h" +#include "system/Init.h" +#include "base/TempDirectory.h" +#include "base/PropertyContainer.h" +#include "base/Preferences.h" +#include "widgets/TipDialog.h" + +#include <QMetaType> +#include <QApplication> +#include <QDesktopWidget> +#include <QMessageBox> +#include <QTranslator> +#include <QLocale> +#include <QSettings> +#include <QIcon> +#include <QSessionManager> +#include <QSplashScreen> +#include <QFileOpenEvent> +#include <QDir> + +#include <iostream> +#include <signal.h> + +static QMutex cleanupMutex; + +static void +signalHandler(int /* signal */) +{ + // Avoid this happening more than once across threads + + cleanupMutex.lock(); + std::cerr << "signalHandler: cleaning up and exiting" << std::endl; + TempDirectory::getInstance()->cleanup(); + exit(0); // without releasing mutex +} + +class TonyApplication : public QApplication +{ +public: + TonyApplication(int argc, char **argv) : + QApplication(argc, argv), + m_mainWindow(0), + m_readyForFiles(false) + { +#ifdef Q_OS_MAC + // Override the Qt plugin load path. The default contains the + // Qt installation location as well as the application + // directory, but we don't ever want to load plugins from + // outside the app bundle because we don't know for sure what + // (potentially different) versions of the Qt framework + // libraries they may have dyld dependencies on. + QString apploc(applicationFilePath()); + apploc.truncate(apploc.lastIndexOf(QLatin1Char('/'))); + apploc = QDir(apploc).canonicalPath(); + if (QFile::exists(apploc)) { + setLibraryPaths(QStringList() << apploc); + } else { + setLibraryPaths(QStringList()); + } +#endif + } + virtual ~TonyApplication() { + } + + void setMainWindow(MainWindow *mw) { m_mainWindow = mw; } + void releaseMainWindow() { m_mainWindow = 0; } + + virtual void commitData(QSessionManager &manager) { + if (!m_mainWindow) return; + bool mayAskUser = manager.allowsInteraction(); + bool success = m_mainWindow->commitData(mayAskUser); + manager.release(); + if (!success) manager.cancel(); + } + + void readyForFiles() { + m_readyForFiles = true; + } + + void handleFilepathArgument(QString path, QSplashScreen *splash); + + void handleQueuedPaths(QSplashScreen *splash) { + foreach (QString f, m_filepathQueue) { + handleFilepathArgument(f, splash); + } + } + +protected: + MainWindow *m_mainWindow; + + bool m_readyForFiles; + QStringList m_filepathQueue; + + virtual bool event(QEvent *event) { + switch (event->type()) { + case QEvent::FileOpen: + { + QString path = static_cast<QFileOpenEvent *>(event)->file(); + if (m_readyForFiles) { + handleFilepathArgument(path, NULL); + } else { + m_filepathQueue.append(path); + } + return true; + } + default: + return QApplication::event(event); + } + } +}; + +int +main(int argc, char **argv) +{ + svSystemSpecificInitialisation(); + + TonyApplication application(argc, argv); + + QStringList args = application.arguments(); + + signal(SIGINT, signalHandler); + signal(SIGTERM, signalHandler); + +#ifndef Q_WS_WIN32 + signal(SIGHUP, signalHandler); + signal(SIGQUIT, signalHandler); +#endif + + bool audioOutput = true; + + if (args.contains("--help") || args.contains("-h") || args.contains("-?")) { + std::cerr << QApplication::tr( + "\nTony is a program for interactive note and pitch analysis and annotation.\n\nUsage:\n\n %1 [--no-audio] [--no-osc] [<file> ...]\n\n --no-audio: Do not attempt to open an audio output device\n <file>: One or more Tony (.ton) and audio files may be provided.\n").arg(argv[0]).toStdString() << std::endl; + exit(2); + } + + if (args.contains("--no-audio")) audioOutput = false; + + QApplication::setOrganizationName("QMUL"); + QApplication::setOrganizationDomain("qmul.ac.uk"); + QApplication::setApplicationName("Tony"); + + QSplashScreen *splash = 0; + // If we had a splash screen, we would show it here + + QIcon icon; + int sizes[] = { 16, 22, 24, 32, 48, 64, 128 }; + for (size_t i = 0; i < sizeof(sizes)/sizeof(sizes[0]); ++i) { + icon.addFile(QString(":icons/tony-%1x%2.png").arg(sizes[i]).arg(sizes[i])); + } + QApplication::setWindowIcon(icon); + + QString language = QLocale::system().name(); + + QTranslator qtTranslator; + QString qtTrName = QString("qt_%1").arg(language); + std::cerr << "Loading " << qtTrName.toStdString() << "..." << std::endl; + bool success = false; + if (!(success = qtTranslator.load(qtTrName))) { + QString qtDir = getenv("QTDIR"); + if (qtDir != "") { + success = qtTranslator.load + (qtTrName, QDir(qtDir).filePath("translations")); + } + } + if (!success) { + std::cerr << "Failed to load Qt translation for locale" << std::endl; + } + application.installTranslator(&qtTranslator); + + StoreStartupLocale(); + + // Permit size_t and PropertyName to be used as args in queued signal calls + qRegisterMetaType<size_t>("size_t"); + qRegisterMetaType<PropertyContainer::PropertyName>("PropertyContainer::PropertyName"); + + MainWindow *gui = new MainWindow(audioOutput, false); // no osc support + application.setMainWindow(gui); + if (splash) { + QObject::connect(gui, SIGNAL(hideSplash()), splash, SLOT(hide())); + } + + QDesktopWidget *desktop = QApplication::desktop(); + QRect available = desktop->availableGeometry(); + + int width = (available.width() * 2) / 3; + int height = available.height() / 2; + if (height < 450) height = (available.height() * 2) / 3; + if (width > height * 2) width = height * 2; + + QSettings settings; + settings.beginGroup("MainWindow"); + QSize size = settings.value("size", QSize(width, height)).toSize(); + gui->resizeConstrained(size); + if (settings.contains("position")) { + QRect prevrect(settings.value("position").toPoint(), size); + if (!(available & prevrect).isEmpty()) { + gui->move(prevrect.topLeft()); + } + } + settings.endGroup(); + + gui->show(); + + application.readyForFiles(); + + for (QStringList::iterator i = args.begin(); i != args.end(); ++i) { + + if (i == args.begin()) continue; + if (i->startsWith('-')) continue; + + QString path = *i; + + application.handleFilepathArgument(path, splash); + } + + application.handleQueuedPaths(splash); + + if (splash) splash->finish(gui); + delete splash; + + int rv = application.exec(); + + gui->hide(); + + cleanupMutex.lock(); + TempDirectory::getInstance()->cleanup(); + application.releaseMainWindow(); + + delete gui; + + return rv; +} + +/** Application-global handler for filepaths passed in, e.g. as + * command-line arguments or apple events */ + +void TonyApplication::handleFilepathArgument(QString path, + QSplashScreen *splash) +{ + static bool haveSession = false; + static bool haveMainModel = false; + static bool havePriorCommandLineModel = false; + + MainWindow::FileOpenStatus status = MainWindow::FileOpenFailed; + + if (path.endsWith("ton")) { + if (!haveSession) { + status = m_mainWindow->openSessionFile(path); + if (status == MainWindow::FileOpenSucceeded) { + haveSession = true; + haveMainModel = true; + } + } else { + std::cerr << "WARNING: Ignoring additional session file argument \"" << path << "\"" << std::endl; + status = MainWindow::FileOpenSucceeded; + } + } + if (status != MainWindow::FileOpenSucceeded) { + if (!haveMainModel) { + status = m_mainWindow->open(path, MainWindow::ReplaceSession); + if (status == MainWindow::FileOpenSucceeded) { + haveMainModel = true; + } + } else { + if (haveSession && !havePriorCommandLineModel) { + status = m_mainWindow->open(path, MainWindow::AskUser); + if (status == MainWindow::FileOpenSucceeded) { + havePriorCommandLineModel = true; + } + } else { + status = m_mainWindow->open(path, MainWindow::CreateAdditionalModel); + } + } + } + if (status == MainWindow::FileOpenFailed) { + if (splash) splash->hide(); + QMessageBox::critical + (m_mainWindow, QMessageBox::tr("Failed to open file"), + QMessageBox::tr("File or URL \"%1\" could not be opened").arg(path)); + } else if (status == MainWindow::FileOpenWrongMode) { + if (splash) splash->hide(); + QMessageBox::critical + (m_mainWindow, QMessageBox::tr("Failed to open file"), + QMessageBox::tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data")); + } +} +