Mercurial > hg > tony
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 |