main.cpp

Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2006 Chris Cannam and QMUL.
00008     
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 #include "MainWindow.h"
00017 
00018 #include "system/System.h"
00019 #include "system/Init.h"
00020 #include "base/TempDirectory.h"
00021 #include "base/PropertyContainer.h"
00022 #include "base/Preferences.h"
00023 #include "widgets/TipDialog.h"
00024 
00025 #include <QMetaType>
00026 #include <QApplication>
00027 #include <QDesktopWidget>
00028 #include <QMessageBox>
00029 #include <QTranslator>
00030 #include <QLocale>
00031 #include <QSettings>
00032 #include <QIcon>
00033 #include <QSessionManager>
00034 #include <QDir>
00035 #include <QSplashScreen>
00036 
00037 #include <iostream>
00038 #include <signal.h>
00039 
00040 #ifdef HAVE_FFTW3F
00041 #include <fftw3.h>
00042 #endif
00043 
00168 static QMutex cleanupMutex;
00169 
00170 static void
00171 signalHandler(int /* signal */)
00172 {
00173     // Avoid this happening more than once across threads
00174 
00175     cleanupMutex.lock();
00176     std::cerr << "signalHandler: cleaning up and exiting" << std::endl;
00177     TempDirectory::getInstance()->cleanup();
00178     exit(0); // without releasing mutex
00179 }
00180 
00181 class SVApplication : public QApplication
00182 {
00183 public:
00184     SVApplication(int argc, char **argv) :
00185         QApplication(argc, argv),
00186         m_mainWindow(0) { }
00187     virtual ~SVApplication() { }
00188 
00189     void setMainWindow(MainWindow *mw) { m_mainWindow = mw; }
00190     void releaseMainWindow() { m_mainWindow = 0; }
00191 
00192     virtual void commitData(QSessionManager &manager) {
00193         if (!m_mainWindow) return;
00194         bool mayAskUser = manager.allowsInteraction();
00195         bool success = m_mainWindow->commitData(mayAskUser);
00196         manager.release();
00197         if (!success) manager.cancel();
00198     }
00199 
00200 protected:
00201     MainWindow *m_mainWindow;
00202 };
00203 
00204 int
00205 main(int argc, char **argv)
00206 {
00207     SVApplication application(argc, argv);
00208 
00209     QStringList args = application.arguments();
00210 
00211     signal(SIGINT,  signalHandler);
00212     signal(SIGTERM, signalHandler);
00213 
00214 #ifndef Q_WS_WIN32
00215     signal(SIGHUP,  signalHandler);
00216     signal(SIGQUIT, signalHandler);
00217 #endif
00218 
00219     svSystemSpecificInitialisation();
00220 
00221     bool audioOutput = true;
00222     bool oscSupport = true;
00223 
00224     if (args.contains("--help") || args.contains("-h") || args.contains("-?")) {
00225         std::cerr << QApplication::tr(
00226             "\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]).toStdString() << std::endl;
00227         exit(2);
00228     }
00229 
00230     if (args.contains("--no-audio")) audioOutput = false;
00231     if (args.contains("--no-osc")) oscSupport = false;
00232 
00233     QApplication::setOrganizationName("sonic-visualiser");
00234     QApplication::setOrganizationDomain("sonicvisualiser.org");
00235     QApplication::setApplicationName(QApplication::tr("Sonic Visualiser"));
00236 
00237     QPixmap pixmap(":/icons/sv-splash.png");
00238     QSplashScreen splash(pixmap);
00239 
00240     QSettings settings;
00241 
00242     settings.beginGroup("Preferences");
00243     if (settings.value("show-splash", true).toBool()) {
00244         splash.show();
00245         application.processEvents();
00246     }
00247     settings.endGroup();
00248 
00249     QIcon icon;
00250     int sizes[] = { 16, 22, 24, 32, 48, 64, 128 };
00251     for (int i = 0; i < sizeof(sizes)/sizeof(sizes[0]); ++i) {
00252         icon.addFile(QString(":icons/sv-%1x%2.png").arg(sizes[i]).arg(sizes[i]));
00253     }
00254     QApplication::setWindowIcon(icon);
00255 
00256     QString language = QLocale::system().name();
00257 
00258     QTranslator qtTranslator;
00259     QString qtTrName = QString("qt_%1").arg(language);
00260     std::cerr << "Loading " << qtTrName.toStdString() << "..." << std::endl;
00261     bool success = false;
00262     if (!(success = qtTranslator.load(qtTrName))) {
00263         QString qtDir = getenv("QTDIR");
00264         if (qtDir != "") {
00265             success = qtTranslator.load
00266                 (qtTrName, QDir(qtDir).filePath("translations"));
00267         }
00268     }
00269     if (!success) {
00270         std::cerr << "Failed to load Qt translation for locale" << std::endl;
00271     }
00272     application.installTranslator(&qtTranslator);
00273 
00274     QTranslator svTranslator;
00275     QString svTrName = QString("sonic-visualiser_%1").arg(language);
00276     std::cerr << "Loading " << svTrName.toStdString() << "..." << std::endl;
00277     svTranslator.load(svTrName, ":i18n");
00278     application.installTranslator(&svTranslator);
00279 
00280     StoreStartupLocale();
00281 
00282     // Permit size_t and PropertyName to be used as args in queued signal calls
00283     qRegisterMetaType<size_t>("size_t");
00284     qRegisterMetaType<PropertyContainer::PropertyName>("PropertyContainer::PropertyName");
00285 
00286     MainWindow *gui = new MainWindow(audioOutput, oscSupport);
00287     application.setMainWindow(gui);
00288 
00289     QDesktopWidget *desktop = QApplication::desktop();
00290     QRect available = desktop->availableGeometry();
00291 
00292     int width = available.width() * 2 / 3;
00293     int height = available.height() / 2;
00294     if (height < 450) height = available.height() * 2 / 3;
00295     if (width > height * 2) width = height * 2;
00296 
00297     settings.beginGroup("MainWindow");
00298     QSize size = settings.value("size", QSize(width, height)).toSize();
00299     gui->resize(size);
00300     if (settings.contains("position")) {
00301         gui->move(settings.value("position").toPoint());
00302     }
00303     settings.endGroup();
00304     
00305     gui->show();
00306 
00307     // The MainWindow class seems to have trouble dealing with this if
00308     // it tries to adapt to this preference before the constructor is
00309     // complete.  As a lazy hack, apply it explicitly from here
00310     gui->preferenceChanged("Property Box Layout");
00311 
00312     bool haveSession = false;
00313     bool haveMainModel = false;
00314     bool havePriorCommandLineModel = false;
00315 
00316     for (QStringList::iterator i = args.begin(); i != args.end(); ++i) {
00317 
00318         MainWindow::FileOpenStatus status = MainWindow::FileOpenFailed;
00319 
00320         if (i == args.begin()) continue;
00321         if (i->startsWith('-')) continue;
00322 
00323         QString path = *i;
00324 
00325         if (path.endsWith("sv")) {
00326             if (!haveSession) {
00327                 status = gui->openSessionFile(path);
00328                 if (status == MainWindow::FileOpenSucceeded) {
00329                     haveSession = true;
00330                     haveMainModel = true;
00331                 }
00332             } else {
00333                 std::cerr << "WARNING: Ignoring additional session file argument \"" << path.toStdString() << "\"" << std::endl;
00334                 status = MainWindow::FileOpenSucceeded;
00335             }
00336         }
00337         if (status != MainWindow::FileOpenSucceeded) {
00338             if (!haveMainModel) {
00339                 status = gui->open(path, MainWindow::ReplaceMainModel);
00340                 if (status == MainWindow::FileOpenSucceeded) {
00341                     haveMainModel = true;
00342                 }
00343             } else {
00344                 if (haveSession && !havePriorCommandLineModel) {
00345                     status = gui->open(path, MainWindow::AskUser);
00346                     if (status == MainWindow::FileOpenSucceeded) {
00347                         havePriorCommandLineModel = true;
00348                     }
00349                 } else {
00350                     status = gui->open(path, MainWindow::CreateAdditionalModel);
00351                 }
00352             }
00353         }
00354         if (status == MainWindow::FileOpenFailed) {
00355             QMessageBox::critical
00356                 (gui, QMessageBox::tr("Failed to open file"),
00357                  QMessageBox::tr("File or URL \"%1\" could not be opened").arg(path));
00358         }
00359     }
00360     
00361 #ifdef HAVE_FFTW3F
00362     settings.beginGroup("FFTWisdom");
00363     QString wisdom = settings.value("wisdom").toString();
00364     if (wisdom != "") {
00365         fftwf_import_wisdom_from_string(wisdom.toLocal8Bit().data());
00366     }
00367     settings.endGroup();
00368 #endif
00369 
00370     splash.finish(gui);
00371 
00372 /*
00373     TipDialog tipDialog;
00374     if (tipDialog.isOK()) {
00375         tipDialog.exec();
00376     }
00377 */
00378     int rv = application.exec();
00379     std::cerr << "application.exec() returned " << rv << std::endl;
00380 
00381     cleanupMutex.lock();
00382     TempDirectory::getInstance()->cleanup();
00383 
00384     application.releaseMainWindow();
00385 
00386 #ifdef HAVE_FFTW3F
00387     char *cwisdom = fftwf_export_wisdom_to_string();
00388     if (cwisdom) {
00389         settings.beginGroup("FFTWisdom");
00390         settings.setValue("wisdom", cwisdom);
00391         settings.endGroup();
00392         fftwf_free(cwisdom);
00393     }
00394 #endif
00395 
00396     delete gui;
00397 
00398     return rv;
00399 }

Generated on Wed Feb 20 15:45:26 2008 for SonicVisualiser by  doxygen 1.5.1