Mercurial > hg > sonic-visualiser
comparison main/main.cpp @ 365:174ca518546f macness
Use QFileOpenEvent instead of native mac AppleEvent stuff: does the same job, better, neater
author | Dan Stowell <dan.stowell@eecs.qmul.ac.uk> |
---|---|
date | Mon, 11 Oct 2010 15:47:12 +0100 |
parents | 43205eda54bd |
children | d0c5831d6528 61111a6a229f |
comparison
equal
deleted
inserted
replaced
364:4e16d48c693d | 365:174ca518546f |
---|---|
20 #include "base/TempDirectory.h" | 20 #include "base/TempDirectory.h" |
21 #include "base/PropertyContainer.h" | 21 #include "base/PropertyContainer.h" |
22 #include "base/Preferences.h" | 22 #include "base/Preferences.h" |
23 #include "widgets/TipDialog.h" | 23 #include "widgets/TipDialog.h" |
24 #include "transform/TransformFactory.h" | 24 #include "transform/TransformFactory.h" |
25 | |
26 #ifdef Q_WS_MAC | |
27 #include <ApplicationServices/ApplicationServices.h> | |
28 #include <Carbon/Carbon.h> | |
29 #endif | |
30 | 25 |
31 #include <QMetaType> | 26 #include <QMetaType> |
32 #include <QApplication> | 27 #include <QApplication> |
33 #include <QDesktopWidget> | 28 #include <QDesktopWidget> |
34 #include <QMessageBox> | 29 #include <QMessageBox> |
39 #include <QSessionManager> | 34 #include <QSessionManager> |
40 #include <QDir> | 35 #include <QDir> |
41 #include <QSplashScreen> | 36 #include <QSplashScreen> |
42 #include <QTimer> | 37 #include <QTimer> |
43 #include <QPainter> | 38 #include <QPainter> |
39 #include <QFileOpenEvent> | |
44 | 40 |
45 #include "../version.h" | 41 #include "../version.h" |
46 | 42 |
47 #include <iostream> | 43 #include <iostream> |
48 #include <signal.h> | 44 #include <signal.h> |
174 of the window. | 170 of the window. |
175 | 171 |
176 */ | 172 */ |
177 | 173 |
178 static QMutex cleanupMutex; | 174 static QMutex cleanupMutex; |
179 static MainWindow *gui; | |
180 | 175 |
181 static void | 176 static void |
182 signalHandler(int /* signal */) | 177 signalHandler(int /* signal */) |
183 { | 178 { |
184 // Avoid this happening more than once across threads | 179 // Avoid this happening more than once across threads |
192 class SVApplication : public QApplication | 187 class SVApplication : public QApplication |
193 { | 188 { |
194 public: | 189 public: |
195 SVApplication(int &argc, char **argv) : | 190 SVApplication(int &argc, char **argv) : |
196 QApplication(argc, argv), | 191 QApplication(argc, argv), |
197 m_mainWindow(0) { } | 192 m_readyForFiles(false), |
193 m_filepathQueue(QStringList()), | |
194 m_mainWindow(0) | |
195 { } | |
198 virtual ~SVApplication() { } | 196 virtual ~SVApplication() { } |
199 | 197 |
200 void setMainWindow(MainWindow *mw) { m_mainWindow = mw; } | 198 void setMainWindow(MainWindow *mw) { m_mainWindow = mw; } |
201 void releaseMainWindow() { m_mainWindow = 0; } | 199 void releaseMainWindow() { m_mainWindow = 0; } |
202 | 200 |
206 bool success = m_mainWindow->commitData(mayAskUser); | 204 bool success = m_mainWindow->commitData(mayAskUser); |
207 manager.release(); | 205 manager.release(); |
208 if (!success) manager.cancel(); | 206 if (!success) manager.cancel(); |
209 } | 207 } |
210 | 208 |
211 /** Application-global handler for filepaths passed in, e.g. as command-line arguments or apple events */ | 209 void handleFilepathArgument(QString path, QSplashScreen *splash); |
212 static void handleFilepathArgument(QString path, QSplashScreen *splash){ | 210 |
213 static bool haveSession = false; | 211 bool m_readyForFiles; |
214 static bool haveMainModel = false; | 212 QStringList m_filepathQueue; |
215 static bool havePriorCommandLineModel = false; | |
216 | |
217 MainWindow::FileOpenStatus status = MainWindow::FileOpenFailed; | |
218 | |
219 if (path.endsWith("sv")) { | |
220 if (!haveSession) { | |
221 status = gui->openSessionFile(path); | |
222 if (status == MainWindow::FileOpenSucceeded) { | |
223 haveSession = true; | |
224 haveMainModel = true; | |
225 } | |
226 } else { | |
227 std::cerr << "WARNING: Ignoring additional session file argument \"" << path.toStdString() << "\"" << std::endl; | |
228 status = MainWindow::FileOpenSucceeded; | |
229 } | |
230 } | |
231 if (status != MainWindow::FileOpenSucceeded) { | |
232 if (!haveMainModel) { | |
233 status = gui->open(path, MainWindow::ReplaceMainModel); | |
234 if (status == MainWindow::FileOpenSucceeded) { | |
235 haveMainModel = true; | |
236 } | |
237 } else { | |
238 if (haveSession && !havePriorCommandLineModel) { | |
239 status = gui->open(path, MainWindow::AskUser); | |
240 if (status == MainWindow::FileOpenSucceeded) { | |
241 havePriorCommandLineModel = true; | |
242 } | |
243 } else { | |
244 status = gui->open(path, MainWindow::CreateAdditionalModel); | |
245 } | |
246 } | |
247 } | |
248 if (status == MainWindow::FileOpenFailed) { | |
249 if (splash) splash->hide(); | |
250 QMessageBox::critical | |
251 (gui, QMessageBox::tr("Failed to open file"), | |
252 QMessageBox::tr("File or URL \"%1\" could not be opened").arg(path)); | |
253 } else if (status == MainWindow::FileOpenWrongMode) { | |
254 if (splash) splash->hide(); | |
255 QMessageBox::critical | |
256 (gui, QMessageBox::tr("Failed to open file"), | |
257 QMessageBox::tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data")); | |
258 } | |
259 } | |
260 | |
261 #ifdef Q_WS_MAC | |
262 static pascal OSErr HandleOpenDocAE (const AppleEvent * theAppleEvent, AppleEvent * /* reply */, SInt32 /* handlerRefcon */) { | |
263 AEDescList docList; | |
264 FSRef theFSRef; | |
265 long count = 0; | |
266 OSErr err; | |
267 | |
268 err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeAEList, &docList); | |
269 err = AECountItems(&docList, &count); | |
270 if(count == 0){ | |
271 std::cerr << "SV warning: received apple open-documents event with no documents (count==0)" << std::endl; | |
272 AEDisposeDesc(&docList); | |
273 return noErr; | |
274 } | |
275 // NB we could be passed a list of files - however, SV on Mac currently can only open one at a time, so we simply open the first. | |
276 | |
277 err = AEGetNthPtr(&docList, 1, typeFSRef, NULL, NULL, &theFSRef, sizeof(theFSRef), NULL); | |
278 | |
279 // Call routine to open document with current reference. | |
280 if(err == noErr){ | |
281 char uPath[1024]; | |
282 FSRefMakePath(&theFSRef, (UInt8*)uPath, 1023); | |
283 std::cerr << "SV received Apple Event request to open " << uPath << std::endl; | |
284 handleFilepathArgument(uPath, NULL); | |
285 } | |
286 | |
287 AEDisposeDesc(&docList); | |
288 return noErr; | |
289 } | |
290 static OSErr InstallMacOSEventHandlers(void) | |
291 { | |
292 OSErr err; | |
293 err = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, NewAEEventHandlerUPP(HandleOpenDocAE), 0, false); | |
294 std::cerr << "HandleOpenDocAE installed. " << err << std::endl; | |
295 return err; | |
296 } | |
297 #endif // Q_WS_MAC | |
298 | 213 |
299 protected: | 214 protected: |
300 MainWindow *m_mainWindow; | 215 MainWindow *m_mainWindow; |
216 bool event(QEvent *); | |
217 | |
301 }; | 218 }; |
302 | 219 |
303 int | 220 int |
304 main(int argc, char **argv) | 221 main(int argc, char **argv) |
305 { | 222 { |
407 | 324 |
408 // Permit size_t and PropertyName to be used as args in queued signal calls | 325 // Permit size_t and PropertyName to be used as args in queued signal calls |
409 qRegisterMetaType<size_t>("size_t"); | 326 qRegisterMetaType<size_t>("size_t"); |
410 qRegisterMetaType<PropertyContainer::PropertyName>("PropertyContainer::PropertyName"); | 327 qRegisterMetaType<PropertyContainer::PropertyName>("PropertyContainer::PropertyName"); |
411 | 328 |
412 gui = new MainWindow(audioOutput, oscSupport); | 329 MainWindow *gui = new MainWindow(audioOutput, oscSupport); |
413 application.setMainWindow(gui); | 330 application.setMainWindow(gui); |
414 if (splash) { | 331 if (splash) { |
415 QObject::connect(gui, SIGNAL(hideSplash()), splash, SLOT(hide())); | 332 QObject::connect(gui, SIGNAL(hideSplash()), splash, SLOT(hide())); |
416 } | 333 } |
417 | 334 |
432 gui->move(prevrect.topLeft()); | 349 gui->move(prevrect.topLeft()); |
433 } | 350 } |
434 } | 351 } |
435 settings.endGroup(); | 352 settings.endGroup(); |
436 | 353 |
437 #ifdef Q_WS_MAC | |
438 application.InstallMacOSEventHandlers(); | |
439 #endif // Q_WS_MAC | |
440 | |
441 gui->show(); | 354 gui->show(); |
442 | 355 |
443 // The MainWindow class seems to have trouble dealing with this if | 356 // The MainWindow class seems to have trouble dealing with this if |
444 // it tries to adapt to this preference before the constructor is | 357 // it tries to adapt to this preference before the constructor is |
445 // complete. As a lazy hack, apply it explicitly from here | 358 // complete. As a lazy hack, apply it explicitly from here |
446 gui->preferenceChanged("Property Box Layout"); | 359 gui->preferenceChanged("Property Box Layout"); |
447 | 360 |
361 application.m_readyForFiles = true; // Ready to receive files from e.g. Apple Events | |
362 | |
448 for (QStringList::iterator i = args.begin(); i != args.end(); ++i) { | 363 for (QStringList::iterator i = args.begin(); i != args.end(); ++i) { |
449 | 364 |
450 if (i == args.begin()) continue; | 365 if (i == args.begin()) continue; |
451 if (i->startsWith('-')) continue; | 366 if (i->startsWith('-')) continue; |
452 | 367 |
453 QString path = *i; | 368 QString path = *i; |
454 | 369 |
455 SVApplication::handleFilepathArgument(path, splash); | 370 application.handleFilepathArgument(path, splash); |
371 } | |
372 | |
373 for (QStringList::iterator i = application.m_filepathQueue.begin(); i != application.m_filepathQueue.end(); ++i) { | |
374 QString path = *i; | |
375 application.handleFilepathArgument(path, splash); | |
456 } | 376 } |
457 | 377 |
458 #ifdef HAVE_FFTW3F | 378 #ifdef HAVE_FFTW3F |
459 settings.beginGroup("FFTWisdom"); | 379 settings.beginGroup("FFTWisdom"); |
460 QString wisdom = settings.value("wisdom").toString(); | 380 QString wisdom = settings.value("wisdom").toString(); |
508 | 428 |
509 delete gui; | 429 delete gui; |
510 | 430 |
511 return rv; | 431 return rv; |
512 } | 432 } |
433 | |
434 bool SVApplication::event(QEvent *event){ | |
435 QString thePath; | |
436 switch (event->type()) { | |
437 case QEvent::FileOpen: | |
438 thePath = static_cast<QFileOpenEvent *>(event)->file(); | |
439 if(m_readyForFiles) | |
440 handleFilepathArgument(thePath, NULL); | |
441 else | |
442 m_filepathQueue.append(thePath); | |
443 return true; | |
444 default: | |
445 return QApplication::event(event); | |
446 } | |
447 } | |
448 | |
449 /** Application-global handler for filepaths passed in, e.g. as command-line arguments or apple events */ | |
450 void SVApplication::handleFilepathArgument(QString path, QSplashScreen *splash){ | |
451 static bool haveSession = false; | |
452 static bool haveMainModel = false; | |
453 static bool havePriorCommandLineModel = false; | |
454 | |
455 MainWindow::FileOpenStatus status = MainWindow::FileOpenFailed; | |
456 | |
457 if (path.endsWith("sv")) { | |
458 if (!haveSession) { | |
459 status = m_mainWindow->openSessionFile(path); | |
460 if (status == MainWindow::FileOpenSucceeded) { | |
461 haveSession = true; | |
462 haveMainModel = true; | |
463 } | |
464 } else { | |
465 std::cerr << "WARNING: Ignoring additional session file argument \"" << path.toStdString() << "\"" << std::endl; | |
466 status = MainWindow::FileOpenSucceeded; | |
467 } | |
468 } | |
469 if (status != MainWindow::FileOpenSucceeded) { | |
470 if (!haveMainModel) { | |
471 status = m_mainWindow->open(path, MainWindow::ReplaceMainModel); | |
472 if (status == MainWindow::FileOpenSucceeded) { | |
473 haveMainModel = true; | |
474 } | |
475 } else { | |
476 if (haveSession && !havePriorCommandLineModel) { | |
477 status = m_mainWindow->open(path, MainWindow::AskUser); | |
478 if (status == MainWindow::FileOpenSucceeded) { | |
479 havePriorCommandLineModel = true; | |
480 } | |
481 } else { | |
482 status = m_mainWindow->open(path, MainWindow::CreateAdditionalModel); | |
483 } | |
484 } | |
485 } | |
486 if (status == MainWindow::FileOpenFailed) { | |
487 if (splash) splash->hide(); | |
488 QMessageBox::critical | |
489 (m_mainWindow, QMessageBox::tr("Failed to open file"), | |
490 QMessageBox::tr("File or URL \"%1\" could not be opened").arg(path)); | |
491 } else if (status == MainWindow::FileOpenWrongMode) { | |
492 if (splash) splash->hide(); | |
493 QMessageBox::critical | |
494 (m_mainWindow, QMessageBox::tr("Failed to open file"), | |
495 QMessageBox::tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data")); | |
496 } | |
497 } |