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