annotate 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
rev   line source
Chris@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@0 4 Tony
Chris@0 5 An intonation analysis and annotation tool
Chris@0 6 Centre for Digital Music, Queen Mary, University of London.
Chris@0 7 This file copyright 2006-2012 Chris Cannam and QMUL.
Chris@0 8
Chris@0 9 This program is free software; you can redistribute it and/or
Chris@0 10 modify it under the terms of the GNU General Public License as
Chris@0 11 published by the Free Software Foundation; either version 2 of the
Chris@0 12 License, or (at your option) any later version. See the file
Chris@0 13 COPYING included with this distribution for more information.
Chris@0 14 */
Chris@0 15
Chris@0 16 #include "MainWindow.h"
Chris@0 17
Chris@0 18 #include "system/System.h"
Chris@0 19 #include "system/Init.h"
Chris@0 20 #include "base/TempDirectory.h"
Chris@0 21 #include "base/PropertyContainer.h"
Chris@0 22 #include "base/Preferences.h"
Chris@0 23 #include "widgets/TipDialog.h"
Chris@0 24
Chris@0 25 #include <QMetaType>
Chris@0 26 #include <QApplication>
Chris@0 27 #include <QDesktopWidget>
Chris@0 28 #include <QMessageBox>
Chris@0 29 #include <QTranslator>
Chris@0 30 #include <QLocale>
Chris@0 31 #include <QSettings>
Chris@0 32 #include <QIcon>
Chris@0 33 #include <QSessionManager>
Chris@0 34 #include <QSplashScreen>
Chris@0 35 #include <QFileOpenEvent>
Chris@0 36 #include <QDir>
Chris@0 37
Chris@0 38 #include <iostream>
Chris@0 39 #include <signal.h>
Chris@0 40
Chris@0 41 static QMutex cleanupMutex;
Chris@0 42
Chris@0 43 static void
Chris@0 44 signalHandler(int /* signal */)
Chris@0 45 {
Chris@0 46 // Avoid this happening more than once across threads
Chris@0 47
Chris@0 48 cleanupMutex.lock();
Chris@0 49 std::cerr << "signalHandler: cleaning up and exiting" << std::endl;
Chris@0 50 TempDirectory::getInstance()->cleanup();
Chris@0 51 exit(0); // without releasing mutex
Chris@0 52 }
Chris@0 53
Chris@0 54 class TonyApplication : public QApplication
Chris@0 55 {
Chris@0 56 public:
Chris@0 57 TonyApplication(int argc, char **argv) :
Chris@0 58 QApplication(argc, argv),
Chris@0 59 m_mainWindow(0),
Chris@0 60 m_readyForFiles(false)
Chris@0 61 {
Chris@0 62 #ifdef Q_OS_MAC
Chris@0 63 // Override the Qt plugin load path. The default contains the
Chris@0 64 // Qt installation location as well as the application
Chris@0 65 // directory, but we don't ever want to load plugins from
Chris@0 66 // outside the app bundle because we don't know for sure what
Chris@0 67 // (potentially different) versions of the Qt framework
Chris@0 68 // libraries they may have dyld dependencies on.
Chris@0 69 QString apploc(applicationFilePath());
Chris@0 70 apploc.truncate(apploc.lastIndexOf(QLatin1Char('/')));
Chris@0 71 apploc = QDir(apploc).canonicalPath();
Chris@0 72 if (QFile::exists(apploc)) {
Chris@0 73 setLibraryPaths(QStringList() << apploc);
Chris@0 74 } else {
Chris@0 75 setLibraryPaths(QStringList());
Chris@0 76 }
Chris@0 77 #endif
Chris@0 78 }
Chris@0 79 virtual ~TonyApplication() {
Chris@0 80 }
Chris@0 81
Chris@0 82 void setMainWindow(MainWindow *mw) { m_mainWindow = mw; }
Chris@0 83 void releaseMainWindow() { m_mainWindow = 0; }
Chris@0 84
Chris@0 85 virtual void commitData(QSessionManager &manager) {
Chris@0 86 if (!m_mainWindow) return;
Chris@0 87 bool mayAskUser = manager.allowsInteraction();
Chris@0 88 bool success = m_mainWindow->commitData(mayAskUser);
Chris@0 89 manager.release();
Chris@0 90 if (!success) manager.cancel();
Chris@0 91 }
Chris@0 92
Chris@0 93 void readyForFiles() {
Chris@0 94 m_readyForFiles = true;
Chris@0 95 }
Chris@0 96
Chris@0 97 void handleFilepathArgument(QString path, QSplashScreen *splash);
Chris@0 98
Chris@0 99 void handleQueuedPaths(QSplashScreen *splash) {
Chris@0 100 foreach (QString f, m_filepathQueue) {
Chris@0 101 handleFilepathArgument(f, splash);
Chris@0 102 }
Chris@0 103 }
Chris@0 104
Chris@0 105 protected:
Chris@0 106 MainWindow *m_mainWindow;
Chris@0 107
Chris@0 108 bool m_readyForFiles;
Chris@0 109 QStringList m_filepathQueue;
Chris@0 110
Chris@0 111 virtual bool event(QEvent *event) {
Chris@0 112 switch (event->type()) {
Chris@0 113 case QEvent::FileOpen:
Chris@0 114 {
Chris@0 115 QString path = static_cast<QFileOpenEvent *>(event)->file();
Chris@0 116 if (m_readyForFiles) {
Chris@0 117 handleFilepathArgument(path, NULL);
Chris@0 118 } else {
Chris@0 119 m_filepathQueue.append(path);
Chris@0 120 }
Chris@0 121 return true;
Chris@0 122 }
Chris@0 123 default:
Chris@0 124 return QApplication::event(event);
Chris@0 125 }
Chris@0 126 }
Chris@0 127 };
Chris@0 128
Chris@0 129 int
Chris@0 130 main(int argc, char **argv)
Chris@0 131 {
Chris@0 132 svSystemSpecificInitialisation();
Chris@0 133
Chris@0 134 TonyApplication application(argc, argv);
Chris@0 135
Chris@0 136 QStringList args = application.arguments();
Chris@0 137
Chris@0 138 signal(SIGINT, signalHandler);
Chris@0 139 signal(SIGTERM, signalHandler);
Chris@0 140
Chris@0 141 #ifndef Q_WS_WIN32
Chris@0 142 signal(SIGHUP, signalHandler);
Chris@0 143 signal(SIGQUIT, signalHandler);
Chris@0 144 #endif
Chris@0 145
Chris@0 146 bool audioOutput = true;
Chris@0 147
Chris@0 148 if (args.contains("--help") || args.contains("-h") || args.contains("-?")) {
Chris@0 149 std::cerr << QApplication::tr(
Chris@0 150 "\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;
Chris@0 151 exit(2);
Chris@0 152 }
Chris@0 153
Chris@0 154 if (args.contains("--no-audio")) audioOutput = false;
Chris@0 155
Chris@0 156 QApplication::setOrganizationName("QMUL");
Chris@0 157 QApplication::setOrganizationDomain("qmul.ac.uk");
Chris@0 158 QApplication::setApplicationName("Tony");
Chris@0 159
Chris@0 160 QSplashScreen *splash = 0;
Chris@0 161 // If we had a splash screen, we would show it here
Chris@0 162
Chris@0 163 QIcon icon;
Chris@0 164 int sizes[] = { 16, 22, 24, 32, 48, 64, 128 };
Chris@0 165 for (size_t i = 0; i < sizeof(sizes)/sizeof(sizes[0]); ++i) {
Chris@0 166 icon.addFile(QString(":icons/tony-%1x%2.png").arg(sizes[i]).arg(sizes[i]));
Chris@0 167 }
Chris@0 168 QApplication::setWindowIcon(icon);
Chris@0 169
Chris@0 170 QString language = QLocale::system().name();
Chris@0 171
Chris@0 172 QTranslator qtTranslator;
Chris@0 173 QString qtTrName = QString("qt_%1").arg(language);
Chris@0 174 std::cerr << "Loading " << qtTrName.toStdString() << "..." << std::endl;
Chris@0 175 bool success = false;
Chris@0 176 if (!(success = qtTranslator.load(qtTrName))) {
Chris@0 177 QString qtDir = getenv("QTDIR");
Chris@0 178 if (qtDir != "") {
Chris@0 179 success = qtTranslator.load
Chris@0 180 (qtTrName, QDir(qtDir).filePath("translations"));
Chris@0 181 }
Chris@0 182 }
Chris@0 183 if (!success) {
Chris@0 184 std::cerr << "Failed to load Qt translation for locale" << std::endl;
Chris@0 185 }
Chris@0 186 application.installTranslator(&qtTranslator);
Chris@0 187
Chris@0 188 StoreStartupLocale();
Chris@0 189
Chris@0 190 // Permit size_t and PropertyName to be used as args in queued signal calls
Chris@0 191 qRegisterMetaType<size_t>("size_t");
Chris@0 192 qRegisterMetaType<PropertyContainer::PropertyName>("PropertyContainer::PropertyName");
Chris@0 193
Chris@0 194 MainWindow *gui = new MainWindow(audioOutput, false); // no osc support
Chris@0 195 application.setMainWindow(gui);
Chris@0 196 if (splash) {
Chris@0 197 QObject::connect(gui, SIGNAL(hideSplash()), splash, SLOT(hide()));
Chris@0 198 }
Chris@0 199
Chris@0 200 QDesktopWidget *desktop = QApplication::desktop();
Chris@0 201 QRect available = desktop->availableGeometry();
Chris@0 202
Chris@0 203 int width = (available.width() * 2) / 3;
Chris@0 204 int height = available.height() / 2;
Chris@0 205 if (height < 450) height = (available.height() * 2) / 3;
Chris@0 206 if (width > height * 2) width = height * 2;
Chris@0 207
Chris@0 208 QSettings settings;
Chris@0 209 settings.beginGroup("MainWindow");
Chris@0 210 QSize size = settings.value("size", QSize(width, height)).toSize();
Chris@0 211 gui->resizeConstrained(size);
Chris@0 212 if (settings.contains("position")) {
Chris@0 213 QRect prevrect(settings.value("position").toPoint(), size);
Chris@0 214 if (!(available & prevrect).isEmpty()) {
Chris@0 215 gui->move(prevrect.topLeft());
Chris@0 216 }
Chris@0 217 }
Chris@0 218 settings.endGroup();
Chris@0 219
Chris@0 220 gui->show();
Chris@0 221
Chris@0 222 application.readyForFiles();
Chris@0 223
Chris@0 224 for (QStringList::iterator i = args.begin(); i != args.end(); ++i) {
Chris@0 225
Chris@0 226 if (i == args.begin()) continue;
Chris@0 227 if (i->startsWith('-')) continue;
Chris@0 228
Chris@0 229 QString path = *i;
Chris@0 230
Chris@0 231 application.handleFilepathArgument(path, splash);
Chris@0 232 }
Chris@0 233
Chris@0 234 application.handleQueuedPaths(splash);
Chris@0 235
Chris@0 236 if (splash) splash->finish(gui);
Chris@0 237 delete splash;
Chris@0 238
Chris@0 239 int rv = application.exec();
Chris@0 240
Chris@0 241 gui->hide();
Chris@0 242
Chris@0 243 cleanupMutex.lock();
Chris@0 244 TempDirectory::getInstance()->cleanup();
Chris@0 245 application.releaseMainWindow();
Chris@0 246
Chris@0 247 delete gui;
Chris@0 248
Chris@0 249 return rv;
Chris@0 250 }
Chris@0 251
Chris@0 252 /** Application-global handler for filepaths passed in, e.g. as
Chris@0 253 * command-line arguments or apple events */
Chris@0 254
Chris@0 255 void TonyApplication::handleFilepathArgument(QString path,
Chris@0 256 QSplashScreen *splash)
Chris@0 257 {
Chris@0 258 static bool haveSession = false;
Chris@0 259 static bool haveMainModel = false;
Chris@0 260 static bool havePriorCommandLineModel = false;
Chris@0 261
Chris@0 262 MainWindow::FileOpenStatus status = MainWindow::FileOpenFailed;
Chris@0 263
Chris@0 264 if (path.endsWith("ton")) {
Chris@0 265 if (!haveSession) {
Chris@0 266 status = m_mainWindow->openSessionFile(path);
Chris@0 267 if (status == MainWindow::FileOpenSucceeded) {
Chris@0 268 haveSession = true;
Chris@0 269 haveMainModel = true;
Chris@0 270 }
Chris@0 271 } else {
Chris@0 272 std::cerr << "WARNING: Ignoring additional session file argument \"" << path << "\"" << std::endl;
Chris@0 273 status = MainWindow::FileOpenSucceeded;
Chris@0 274 }
Chris@0 275 }
Chris@0 276 if (status != MainWindow::FileOpenSucceeded) {
Chris@0 277 if (!haveMainModel) {
Chris@0 278 status = m_mainWindow->open(path, MainWindow::ReplaceSession);
Chris@0 279 if (status == MainWindow::FileOpenSucceeded) {
Chris@0 280 haveMainModel = true;
Chris@0 281 }
Chris@0 282 } else {
Chris@0 283 if (haveSession && !havePriorCommandLineModel) {
Chris@0 284 status = m_mainWindow->open(path, MainWindow::AskUser);
Chris@0 285 if (status == MainWindow::FileOpenSucceeded) {
Chris@0 286 havePriorCommandLineModel = true;
Chris@0 287 }
Chris@0 288 } else {
Chris@0 289 status = m_mainWindow->open(path, MainWindow::CreateAdditionalModel);
Chris@0 290 }
Chris@0 291 }
Chris@0 292 }
Chris@0 293 if (status == MainWindow::FileOpenFailed) {
Chris@0 294 if (splash) splash->hide();
Chris@0 295 QMessageBox::critical
Chris@0 296 (m_mainWindow, QMessageBox::tr("Failed to open file"),
Chris@0 297 QMessageBox::tr("File or URL \"%1\" could not be opened").arg(path));
Chris@0 298 } else if (status == MainWindow::FileOpenWrongMode) {
Chris@0 299 if (splash) splash->hide();
Chris@0 300 QMessageBox::critical
Chris@0 301 (m_mainWindow, QMessageBox::tr("Failed to open file"),
Chris@0 302 QMessageBox::tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
Chris@0 303 }
Chris@0 304 }
Chris@0 305