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 }