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"));
+    }
+}
+