annotate main/main.cpp @ 2152:60d78294ea3a

Oookay... Travis's Trusty image is now too old for the bundled hg to be able to connect to Bitbucket after the latter switched off TLS 1.0 and 1.1 support this month. So we must either use a newer image, or find another workaround. Let's try the newer image first, since we'd probably be using that already if it had existed when we set this up
author Chris Cannam
date Thu, 06 Dec 2018 09:36:08 +0000
parents ed3f1b5094ad
children 0f5ff52655ec
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 Sonic Visualiser
Chris@0 5 An audio file viewer and annotation editor.
Chris@0 6 Centre for Digital Music, Queen Mary, University of London.
Chris@77 7 This file copyright 2006 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@953 17 #include "SVSplash.h"
Chris@0 18
Chris@1 19 #include "system/System.h"
Chris@1 20 #include "system/Init.h"
Chris@0 21 #include "base/TempDirectory.h"
Chris@0 22 #include "base/PropertyContainer.h"
Chris@0 23 #include "base/Preferences.h"
Chris@908 24 #include "data/fileio/FileSource.h"
Chris@120 25 #include "widgets/TipDialog.h"
Chris@763 26 #include "widgets/InteractiveFileFinder.h"
Chris@1837 27 #include "framework/TransformUserConfigurator.h"
Chris@315 28 #include "transform/TransformFactory.h"
Chris@1837 29 #include "plugin/PluginScan.h"
Chris@1837 30 #include "plugin/PluginPathSetter.h"
Chris@0 31
Chris@0 32 #include <QMetaType>
Chris@0 33 #include <QApplication>
Chris@0 34 #include <QDesktopWidget>
Chris@0 35 #include <QMessageBox>
Chris@0 36 #include <QTranslator>
Chris@0 37 #include <QLocale>
Chris@5 38 #include <QSettings>
Chris@7 39 #include <QIcon>
Chris@11 40 #include <QSessionManager>
Chris@165 41 #include <QDir>
Chris@252 42 #include <QTimer>
Chris@331 43 #include <QPainter>
dan@365 44 #include <QFileOpenEvent>
Chris@331 45
Chris@0 46 #include <iostream>
Chris@0 47 #include <signal.h>
Chris@0 48
Chris@2053 49 #include "../version.h"
Chris@2053 50
Chris@215 51 #ifdef HAVE_FFTW3F
Chris@215 52 #include <fftw3.h>
Chris@215 53 #endif
Chris@215 54
Chris@127 55 /*! \mainpage Sonic Visualiser
Chris@127 56
Chris@127 57 \section interesting Summary of interesting classes
Chris@127 58
Chris@127 59 - Data models: Model and subclasses, e.g. WaveFileModel
Chris@127 60
Chris@127 61 - Graphical layers: Layer and subclasses, displayed on View and its
Chris@127 62 subclass widgets.
Chris@127 63
Chris@127 64 - Main window class, document class, and file parser: MainWindow,
Chris@127 65 Document, SVFileReader
Chris@127 66
Chris@127 67 - Turning one model (e.g. audio) into another (e.g. more audio, or a
Chris@244 68 curve extracted from it): Transform, encapsulating the data that need
Chris@244 69 to be stored to be able to reproduce a given transformation;
Chris@244 70 TransformFactory, for discovering the available types of transform;
Chris@244 71 ModelTransformerFactory, ModelTransformer and subclasses, providing
Chris@244 72 the mechanisms for applying transforms to data models
Chris@127 73
Chris@127 74 - Creating the plugins used by transforms: RealTimePluginFactory,
Chris@129 75 FeatureExtractionPluginFactory. See also the API documentation for
Chris@129 76 Vamp feature extraction plugins at
Chris@129 77 http://www.vamp-plugins.org/code-doc/.
Chris@127 78
Chris@127 79 - File reading and writing code: AudioFileReader and subclasses,
Chris@127 80 WavFileWriter, DataFileReader, SVFileReader
Chris@127 81
Chris@127 82 - FFT calculation and cacheing: FFTModel, FFTDataServer
Chris@127 83
Chris@127 84 - Widgets that show groups of editable properties: PropertyBox for
Chris@127 85 layer properties (contained in a PropertyStack), PluginParameterBox
Chris@127 86 for plugins (contained in a PluginParameterDialog)
Chris@127 87
Chris@127 88 - Audio playback: AudioCallbackPlaySource and subclasses,
Chris@127 89 AudioCallbackPlayTarget and subclasses, AudioGenerator
Chris@127 90
Chris@127 91 \section model Data sources: the Model hierarchy
Chris@127 92
Chris@127 93 A Model is something containing, or knowing how to obtain, data.
Chris@127 94
Chris@127 95 For example, WaveFileModel is a model that knows how to get data
Chris@127 96 from an audio file; SparseTimeValueModel is a model containing
Chris@127 97 editable "curve" data.
Chris@127 98
Chris@127 99 Models typically subclass one of a number of abstract subclasses of
Chris@127 100 Model. For example, WaveFileModel subclasses DenseTimeValueModel,
Chris@127 101 which describes an interface for models that have a value at each
Chris@127 102 time point for a given sampling resolution. (Note that
Chris@127 103 WaveFileModel does not actually read the files itself: it uses
Chris@127 104 AudioFileReader classes for that. It just makes data from the
Chris@127 105 files available in a Model.) SparseTimeValueModel uses the
Chris@127 106 SparseModel template class, which provides most of the
Chris@127 107 implementation for models that contain a series of points of some
Chris@127 108 sort -- also used by NoteModel, TextModel, and
Chris@127 109 SparseOneDimensionalModel.
Chris@127 110
Chris@127 111 Everything that goes on the screen originates from a model, via a
Chris@127 112 layer (see below). The models are contained in a Document object.
Chris@127 113 There is no containment hierarchy or ordering of models in the
Chris@127 114 document. One model is the main model, which defines the sample
Chris@127 115 rate for playback.
Chris@127 116
Chris@127 117 A model may also be marked as a "derived" model, which means it was
Chris@127 118 generated from another model using some transform (feature
Chris@127 119 extraction or effect plugin, etc) -- the idea being that they can
Chris@127 120 be re-generated using the same transform if a new source model is
Chris@127 121 loaded.
Chris@127 122
Chris@127 123 \section layer Things that can display data: the Layer hierarchy
Chris@127 124
Chris@127 125 A Layer is something that knows how to draw parts of a model onto a
Chris@127 126 timeline.
Chris@127 127
Chris@127 128 For example, WaveformLayer is a layer which draws waveforms, based
Chris@127 129 on WaveFileModel; TimeValueLayer draws curves, based on
Chris@127 130 SparseTimeValueModel; SpectrogramLayer draws spectrograms, based on
Chris@127 131 WaveFileModel (via FFTModel).
Chris@127 132
Chris@127 133 The most basic functions of a layer are: to draw itself onto a
Chris@127 134 Pane, against a timeline on the x axis; and to permit user
Chris@127 135 interaction. If you were thinking of adding the capability to
Chris@127 136 display a new sort of something, then you would want to add a new
Chris@127 137 layer type. (You may also need a new model type, depending on
Chris@127 138 whether any existing model can capture the data you need.)
Chris@127 139 Depending on the sort of data in question, there are various
Chris@127 140 existing layers that might be appropriate to start from -- for
Chris@127 141 example, a layer that displays images that the user has imported
Chris@127 142 and associated with particular times might have something in common
Chris@127 143 with the existing TextLayer which displays pieces of text that are
Chris@127 144 associated with particular times.
Chris@127 145
Chris@127 146 Although layers are visual objects, they are contained in the
Chris@127 147 Document in Sonic Visualiser rather than being managed together
Chris@127 148 with display widgets. The Sonic Visualiser file format has
Chris@127 149 separate data and layout sections, and the layers are defined in
Chris@127 150 the data section and then referred to in the layout section which
Chris@127 151 determines which layers may go on which panes (see Pane below).
Chris@127 152
Chris@127 153 Once a layer class is defined, some basic data about it needs to be
Chris@127 154 set up in the LayerFactory class, and then it will appear in the
Chris@127 155 menus and so on on the main window.
Chris@127 156
Chris@127 157 \section view Widgets that are used to show layers: The View hierarchy
Chris@127 158
Chris@127 159 A View is a widget that displays a stack of layers. The most
Chris@127 160 important subclass is Pane, the widget that is used to show most of
Chris@127 161 the data in the main window of Sonic Visualiser.
Chris@127 162
Chris@127 163 All a pane really does is contain a set of layers and get them to
Chris@127 164 render themselves (one on top of the other, with the topmost layer
Chris@127 165 being the one that is currently interacted with), cache the
Chris@127 166 results, negotiate user interaction with them, and so on. This is
Chris@127 167 generally fiddly, if not especially interesting. Panes are
Chris@127 168 strictly layout objects and are not stored in the Document class;
Chris@127 169 instead the MainWindow contains a PaneStack widget (the widget that
Chris@127 170 takes up most of Sonic Visualiser's main window) which contains a
Chris@127 171 set of panes stacked vertically.
Chris@127 172
Chris@127 173 Another View subclass is Overview, which is the widget that
Chris@127 174 contains that green waveform showing the entire file at the bottom
Chris@127 175 of the window.
Chris@127 176
Chris@127 177 */
Chris@127 178
Chris@0 179 static QMutex cleanupMutex;
Chris@589 180 static bool cleanedUp = false;
Chris@0 181
Chris@0 182 static void
Chris@0 183 signalHandler(int /* signal */)
Chris@0 184 {
Chris@0 185 // Avoid this happening more than once across threads
Chris@0 186
Chris@665 187 cerr << "signalHandler: cleaning up and exiting" << endl;
Chris@0 188 cleanupMutex.lock();
Chris@589 189 if (!cleanedUp) {
Chris@589 190 TempDirectory::getInstance()->cleanup();
Chris@589 191 cleanedUp = true;
Chris@589 192 }
Chris@589 193 cleanupMutex.unlock();
Chris@589 194 exit(0);
Chris@0 195 }
Chris@0 196
Chris@11 197 class SVApplication : public QApplication
Chris@11 198 {
Chris@11 199 public:
Chris@296 200 SVApplication(int &argc, char **argv) :
Chris@11 201 QApplication(argc, argv),
dan@365 202 m_readyForFiles(false),
dan@365 203 m_filepathQueue(QStringList()),
dan@365 204 m_mainWindow(0)
Chris@509 205 {
Chris@509 206 }
Chris@11 207 virtual ~SVApplication() { }
Chris@11 208
Chris@11 209 void setMainWindow(MainWindow *mw) { m_mainWindow = mw; }
Chris@11 210 void releaseMainWindow() { m_mainWindow = 0; }
Chris@11 211
Chris@11 212 virtual void commitData(QSessionManager &manager) {
Chris@11 213 if (!m_mainWindow) return;
Chris@11 214 bool mayAskUser = manager.allowsInteraction();
Chris@11 215 bool success = m_mainWindow->commitData(mayAskUser);
Chris@11 216 manager.release();
Chris@11 217 if (!success) manager.cancel();
Chris@11 218 }
Chris@11 219
Chris@953 220 void handleFilepathArgument(QString path, SVSplash *splash);
dan@362 221
dan@365 222 bool m_readyForFiles;
dan@365 223 QStringList m_filepathQueue;
dan@362 224
Chris@11 225 protected:
Chris@11 226 MainWindow *m_mainWindow;
dan@365 227 bool event(QEvent *);
Chris@11 228 };
Chris@11 229
Chris@0 230 int
Chris@0 231 main(int argc, char **argv)
Chris@0 232 {
Chris@2058 233 if (argc == 2 && (QString(argv[1]) == "--version" ||
Chris@2058 234 QString(argv[1]) == "-v")) {
Chris@2058 235 cerr << SV_VERSION << endl;
Chris@2058 236 exit(0);
Chris@2058 237 }
Chris@2058 238
Chris@376 239 svSystemSpecificInitialisation();
Chris@376 240
Chris@316 241 #ifdef Q_WS_X11
Chris@317 242 #if QT_VERSION >= 0x040500
Chris@342 243 // QApplication::setGraphicsSystem("raster");
Chris@316 244 #endif
Chris@316 245 #endif
Chris@316 246
Chris@678 247 #ifdef Q_OS_MAC
Chris@678 248 if (QSysInfo::MacintoshVersion > QSysInfo::MV_10_8) {
Chris@678 249 // Fix for OS/X 10.9 font problem
Chris@678 250 QFont::insertSubstitution(".Lucida Grande UI", "Lucida Grande");
Chris@678 251 }
Chris@678 252 #endif
Chris@678 253
Chris@11 254 SVApplication application(argc, argv);
Chris@0 255
Chris@46 256 QStringList args = application.arguments();
Chris@46 257
Chris@0 258 signal(SIGINT, signalHandler);
Chris@0 259 signal(SIGTERM, signalHandler);
Chris@0 260
Chris@640 261 #ifndef Q_OS_WIN32
Chris@0 262 signal(SIGHUP, signalHandler);
Chris@0 263 signal(SIGQUIT, signalHandler);
Chris@0 264 #endif
Chris@0 265
Chris@46 266 bool audioOutput = true;
Chris@70 267 bool oscSupport = true;
Chris@70 268
Chris@133 269 if (args.contains("--help") || args.contains("-h") || args.contains("-?")) {
Chris@665 270 cerr << QApplication::tr(
Chris@665 271 "\nSonic Visualiser is a program for viewing and exploring audio data\nfor semantic music 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 --no-osc: Do not provide an Open Sound Control port for remote control\n <file>: One or more Sonic Visualiser (.sv) and audio files may be provided.\n").arg(argv[0]) << endl;
Chris@70 272 exit(2);
Chris@70 273 }
Chris@70 274
Chris@46 275 if (args.contains("--no-audio")) audioOutput = false;
Chris@70 276 if (args.contains("--no-osc")) oscSupport = false;
Chris@46 277
Chris@6 278 QApplication::setOrganizationName("sonic-visualiser");
Chris@5 279 QApplication::setOrganizationDomain("sonicvisualiser.org");
Chris@213 280 QApplication::setApplicationName(QApplication::tr("Sonic Visualiser"));
Chris@141 281
Chris@952 282 QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
Chris@952 283
Chris@953 284 SVSplash *splash = 0;
Chris@231 285
Chris@231 286 QSettings settings;
Chris@237 287
Chris@237 288 settings.beginGroup("Preferences");
Chris@1274 289 // Default to using Piper server; can change in preferences
Chris@1274 290 if (!settings.contains("run-vamp-plugins-in-process")) {
Chris@1274 291 settings.setValue("run-vamp-plugins-in-process", false);
Chris@1274 292 }
Chris@1274 293 settings.endGroup();
Chris@1274 294
Chris@1274 295 settings.beginGroup("Preferences");
Chris@237 296 if (settings.value("show-splash", true).toBool()) {
Chris@953 297 splash = new SVSplash();
Chris@283 298 splash->show();
Chris@283 299 QTimer::singleShot(5000, splash, SLOT(hide()));
Chris@231 300 application.processEvents();
Chris@231 301 }
Chris@237 302 settings.endGroup();
Chris@231 303
Chris@278 304 settings.beginGroup("RDF");
Chris@278 305 if (!settings.contains("rdf-indices")) {
Chris@278 306 QStringList list;
Chris@278 307 list << "http://www.vamp-plugins.org/rdf/plugins/index.txt";
Chris@278 308 settings.setValue("rdf-indices", list);
Chris@278 309 }
Chris@278 310 settings.endGroup();
Chris@278 311
Chris@1838 312 PluginPathSetter::initialiseEnvironmentVariables();
Chris@1837 313
Chris@141 314 QIcon icon;
Chris@141 315 int sizes[] = { 16, 22, 24, 32, 48, 64, 128 };
Chris@730 316 for (int i = 0; i < int(sizeof(sizes)/sizeof(sizes[0])); ++i) {
Chris@141 317 icon.addFile(QString(":icons/sv-%1x%2.png").arg(sizes[i]).arg(sizes[i]));
Chris@141 318 }
Chris@141 319 QApplication::setWindowIcon(icon);
Chris@7 320
Chris@0 321 QString language = QLocale::system().name();
Chris@1469 322 SVDEBUG << "System language is: " << language << endl;
Chris@0 323
Chris@658 324 settings.beginGroup("Preferences");
Chris@1469 325 QString prefLanguage = settings.value("locale", language).toString();
Chris@1469 326 if (prefLanguage != QString()) language = prefLanguage;
Chris@658 327 settings.endGroup();
Chris@658 328
Chris@0 329 QTranslator qtTranslator;
Chris@0 330 QString qtTrName = QString("qt_%1").arg(language);
Chris@438 331 SVDEBUG << "Loading " << qtTrName << "... ";
Chris@165 332 bool success = false;
Chris@165 333 if (!(success = qtTranslator.load(qtTrName))) {
Chris@165 334 QString qtDir = getenv("QTDIR");
Chris@165 335 if (qtDir != "") {
Chris@165 336 success = qtTranslator.load
Chris@165 337 (qtTrName, QDir(qtDir).filePath("translations"));
Chris@165 338 }
Chris@165 339 }
Chris@165 340 if (!success) {
Chris@438 341 SVDEBUG << "Failed\nFailed to load Qt translation for locale" << endl;
Chris@253 342 } else {
Chris@665 343 cerr << "Done" << endl;
Chris@165 344 }
Chris@0 345 application.installTranslator(&qtTranslator);
Chris@0 346
Chris@0 347 QTranslator svTranslator;
Chris@0 348 QString svTrName = QString("sonic-visualiser_%1").arg(language);
Chris@438 349 SVDEBUG << "Loading " << svTrName << "... ";
Chris@0 350 svTranslator.load(svTrName, ":i18n");
Chris@438 351 SVDEBUG << "Done" << endl;
Chris@0 352 application.installTranslator(&svTranslator);
Chris@0 353
Chris@187 354 StoreStartupLocale();
Chris@187 355
Chris@1144 356 // Make known-plugins query as early as possible after showing
Chris@1307 357 // splash screen.
Chris@1307 358 PluginScan::getInstance()->scan();
Chris@1144 359
Chris@1412 360 // Permit these types to be used as args in queued signal calls
Chris@0 361 qRegisterMetaType<PropertyContainer::PropertyName>("PropertyContainer::PropertyName");
Chris@1412 362 qRegisterMetaType<ZoomLevel>("ZoomLevel");
Chris@0 363
Chris@1045 364 MainWindow::SoundOptions options = MainWindow::WithEverything;
Chris@1045 365 if (!audioOutput) options = 0;
Chris@1045 366
Chris@1045 367 MainWindow *gui = new MainWindow(options, oscSupport);
Chris@222 368 application.setMainWindow(gui);
Chris@763 369 InteractiveFileFinder::setParentWidget(gui);
Chris@763 370 TransformUserConfigurator::setParentWidget(gui);
Chris@283 371 if (splash) {
Chris@283 372 QObject::connect(gui, SIGNAL(hideSplash()), splash, SLOT(hide()));
Chris@953 373 QObject::connect(gui, SIGNAL(hideSplash(QWidget *)),
Chris@953 374 splash, SLOT(finishSplash(QWidget *)));
Chris@283 375 }
Chris@0 376
Chris@0 377 QDesktopWidget *desktop = QApplication::desktop();
Chris@0 378 QRect available = desktop->availableGeometry();
Chris@0 379
Chris@378 380 int width = (available.width() * 2) / 3;
Chris@0 381 int height = available.height() / 2;
Chris@378 382 if (height < 450) height = (available.height() * 2) / 3;
Chris@0 383 if (width > height * 2) width = height * 2;
Chris@0 384
Chris@237 385 settings.beginGroup("MainWindow");
Chris@624 386
Chris@5 387 QSize size = settings.value("size", QSize(width, height)).toSize();
Chris@319 388 gui->resizeConstrained(size);
Chris@624 389
Chris@5 390 if (settings.contains("position")) {
Chris@297 391 QRect prevrect(settings.value("position").toPoint(), size);
Chris@297 392 if (!(available & prevrect).isEmpty()) {
Chris@297 393 gui->move(prevrect.topLeft());
Chris@297 394 }
Chris@5 395 }
Chris@624 396
Chris@624 397 if (settings.value("maximised", false).toBool()) {
Chris@624 398 gui->setWindowState(Qt::WindowMaximized);
Chris@624 399 }
Chris@624 400
Chris@5 401 settings.endGroup();
Chris@5 402
Chris@222 403 gui->show();
Chris@64 404
Chris@118 405 // The MainWindow class seems to have trouble dealing with this if
Chris@118 406 // it tries to adapt to this preference before the constructor is
Chris@118 407 // complete. As a lazy hack, apply it explicitly from here
Chris@222 408 gui->preferenceChanged("Property Box Layout");
Chris@118 409
dan@365 410 application.m_readyForFiles = true; // Ready to receive files from e.g. Apple Events
dan@365 411
Chris@54 412 for (QStringList::iterator i = args.begin(); i != args.end(); ++i) {
Chris@54 413
Chris@54 414 if (i == args.begin()) continue;
Chris@54 415 if (i->startsWith('-')) continue;
Chris@54 416
Chris@54 417 QString path = *i;
Chris@54 418
dan@365 419 application.handleFilepathArgument(path, splash);
dan@365 420 }
dan@365 421
dan@365 422 for (QStringList::iterator i = application.m_filepathQueue.begin(); i != application.m_filepathQueue.end(); ++i) {
dan@365 423 QString path = *i;
dan@365 424 application.handleFilepathArgument(path, splash);
Chris@180 425 }
Chris@180 426
Chris@215 427 #ifdef HAVE_FFTW3F
Chris@215 428 settings.beginGroup("FFTWisdom");
Chris@215 429 QString wisdom = settings.value("wisdom").toString();
Chris@215 430 if (wisdom != "") {
Chris@215 431 fftwf_import_wisdom_from_string(wisdom.toLocal8Bit().data());
Chris@215 432 }
Chris@267 433 #ifdef HAVE_FFTW3
Chris@267 434 wisdom = settings.value("wisdom_d").toString();
Chris@267 435 if (wisdom != "") {
Chris@267 436 fftw_import_wisdom_from_string(wisdom.toLocal8Bit().data());
Chris@267 437 }
Chris@267 438 #endif
Chris@215 439 settings.endGroup();
Chris@215 440 #endif
Chris@180 441
Chris@0 442 int rv = application.exec();
Chris@0 443
Chris@298 444 gui->hide();
Chris@298 445
Chris@0 446 cleanupMutex.lock();
Chris@332 447
Chris@589 448 if (!cleanedUp) {
Chris@589 449 TransformFactory::deleteInstance();
Chris@589 450 TempDirectory::getInstance()->cleanup();
Chris@589 451 cleanedUp = true;
Chris@589 452 }
Chris@589 453
Chris@11 454 application.releaseMainWindow();
Chris@5 455
Chris@215 456 #ifdef HAVE_FFTW3F
Chris@267 457 settings.beginGroup("FFTWisdom");
Chris@215 458 char *cwisdom = fftwf_export_wisdom_to_string();
Chris@215 459 if (cwisdom) {
Chris@215 460 settings.setValue("wisdom", cwisdom);
Chris@332 461 free(cwisdom);
Chris@215 462 }
Chris@267 463 #ifdef HAVE_FFTW3
Chris@267 464 cwisdom = fftw_export_wisdom_to_string();
Chris@267 465 if (cwisdom) {
Chris@267 466 settings.setValue("wisdom_d", cwisdom);
Chris@332 467 free(cwisdom);
Chris@267 468 }
Chris@267 469 #endif
Chris@267 470 settings.endGroup();
Chris@215 471 #endif
Chris@215 472
Chris@908 473 FileSource::debugReport();
Chris@908 474
Chris@222 475 delete gui;
Chris@222 476
Chris@573 477 cleanupMutex.unlock();
Chris@573 478
Chris@0 479 return rv;
Chris@0 480 }
dan@365 481
dan@365 482 bool SVApplication::event(QEvent *event){
Chris@730 483
Chris@730 484 // Avoid warnings/errors with -Wextra because we aren't explicitly
Chris@730 485 // handling all event types (-Wall is OK with this because of the
Chris@730 486 // default but the stricter level insists)
Chris@730 487 #pragma GCC diagnostic ignored "-Wswitch-enum"
Chris@730 488
dan@365 489 QString thePath;
Chris@730 490
dan@365 491 switch (event->type()) {
dan@365 492 case QEvent::FileOpen:
dan@365 493 thePath = static_cast<QFileOpenEvent *>(event)->file();
dan@365 494 if(m_readyForFiles)
dan@365 495 handleFilepathArgument(thePath, NULL);
dan@365 496 else
dan@365 497 m_filepathQueue.append(thePath);
dan@365 498 return true;
dan@365 499 default:
dan@365 500 return QApplication::event(event);
dan@365 501 }
dan@365 502 }
dan@365 503
dan@365 504 /** Application-global handler for filepaths passed in, e.g. as command-line arguments or apple events */
Chris@953 505 void SVApplication::handleFilepathArgument(QString path, SVSplash *splash){
dan@365 506 static bool haveSession = false;
dan@365 507 static bool haveMainModel = false;
dan@365 508 static bool havePriorCommandLineModel = false;
dan@365 509
dan@365 510 MainWindow::FileOpenStatus status = MainWindow::FileOpenFailed;
dan@365 511
Chris@603 512 #ifdef Q_OS_WIN32
Chris@603 513 path.replace("\\", "/");
Chris@603 514 #endif
Chris@603 515
dan@365 516 if (path.endsWith("sv")) {
dan@365 517 if (!haveSession) {
Chris@738 518 status = m_mainWindow->openSessionPath(path);
dan@365 519 if (status == MainWindow::FileOpenSucceeded) {
dan@365 520 haveSession = true;
dan@365 521 haveMainModel = true;
dan@365 522 }
dan@365 523 } else {
Chris@665 524 cerr << "WARNING: Ignoring additional session file argument \"" << path << "\"" << endl;
dan@365 525 status = MainWindow::FileOpenSucceeded;
dan@365 526 }
dan@365 527 }
dan@365 528 if (status != MainWindow::FileOpenSucceeded) {
dan@365 529 if (!haveMainModel) {
Chris@844 530 status = m_mainWindow->openPath(path, MainWindow::ReplaceSession);
dan@365 531 if (status == MainWindow::FileOpenSucceeded) {
dan@365 532 haveMainModel = true;
dan@365 533 }
dan@365 534 } else {
dan@365 535 if (haveSession && !havePriorCommandLineModel) {
Chris@844 536 status = m_mainWindow->openPath(path, MainWindow::AskUser);
dan@365 537 if (status == MainWindow::FileOpenSucceeded) {
dan@365 538 havePriorCommandLineModel = true;
dan@365 539 }
dan@365 540 } else {
Chris@844 541 status = m_mainWindow->openPath(path, MainWindow::CreateAdditionalModel);
dan@365 542 }
dan@365 543 }
dan@365 544 }
dan@365 545 if (status == MainWindow::FileOpenFailed) {
dan@365 546 if (splash) splash->hide();
dan@365 547 QMessageBox::critical
dan@365 548 (m_mainWindow, QMessageBox::tr("Failed to open file"),
dan@365 549 QMessageBox::tr("File or URL \"%1\" could not be opened").arg(path));
dan@365 550 } else if (status == MainWindow::FileOpenWrongMode) {
dan@365 551 if (splash) splash->hide();
dan@365 552 QMessageBox::critical
dan@365 553 (m_mainWindow, QMessageBox::tr("Failed to open file"),
dan@365 554 QMessageBox::tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
dan@365 555 }
dan@365 556 }