comparison main/MainWindow.cpp @ 193:4e030ebb6b36

* Make it possible to drop audio files, layer files, session files and images onto SV panes. Need to do a bit more work on where we expect the dropped file to go, particularly in the case of audio files -- at the moment they're always opened in new panes, but it may be better to by default replace whatever is in the target pane.
author Chris Cannam
date Wed, 10 Oct 2007 15:18:02 +0000
parents d3477f673fb4
children c851c49c79fe
comparison
equal deleted inserted replaced
192:d3477f673fb4 193:4e030ebb6b36
32 #include "layer/TimeInstantLayer.h" 32 #include "layer/TimeInstantLayer.h"
33 #include "layer/TimeValueLayer.h" 33 #include "layer/TimeValueLayer.h"
34 #include "layer/Colour3DPlotLayer.h" 34 #include "layer/Colour3DPlotLayer.h"
35 #include "layer/SliceLayer.h" 35 #include "layer/SliceLayer.h"
36 #include "layer/SliceableLayer.h" 36 #include "layer/SliceableLayer.h"
37 #include "layer/ImageLayer.h"
37 #include "widgets/Fader.h" 38 #include "widgets/Fader.h"
38 #include "view/Overview.h" 39 #include "view/Overview.h"
39 #include "widgets/PropertyBox.h" 40 #include "widgets/PropertyBox.h"
40 #include "widgets/PropertyStack.h" 41 #include "widgets/PropertyStack.h"
41 #include "widgets/AudioDial.h" 42 #include "widgets/AudioDial.h"
209 this, SLOT(rightButtonMenuRequested(Pane *, QPoint))); 210 this, SLOT(rightButtonMenuRequested(Pane *, QPoint)));
210 connect(m_paneStack, SIGNAL(propertyStacksResized()), 211 connect(m_paneStack, SIGNAL(propertyStacksResized()),
211 this, SLOT(propertyStacksResized())); 212 this, SLOT(propertyStacksResized()));
212 connect(m_paneStack, SIGNAL(contextHelpChanged(const QString &)), 213 connect(m_paneStack, SIGNAL(contextHelpChanged(const QString &)),
213 this, SLOT(contextHelpChanged(const QString &))); 214 this, SLOT(contextHelpChanged(const QString &)));
215 connect(m_paneStack, SIGNAL(dropAccepted(Pane *, QStringList)),
216 this, SLOT(paneDropAccepted(Pane *, QStringList)));
217 connect(m_paneStack, SIGNAL(dropAccepted(Pane *, QString)),
218 this, SLOT(paneDropAccepted(Pane *, QString)));
214 219
215 scroll->setWidget(m_paneStack); 220 scroll->setWidget(m_paneStack);
216 221
217 m_overview = new Overview(frame); 222 m_overview = new Overview(frame);
218 m_overview->setViewManager(m_viewManager); 223 m_overview->setViewManager(m_viewManager);
2527 QString path = getOpenFileName(FileFinder::AudioFile); 2532 QString path = getOpenFileName(FileFinder::AudioFile);
2528 2533
2529 if (path != "") { 2534 if (path != "") {
2530 if (openAudioFile(path, ReplaceMainModel) == FileOpenFailed) { 2535 if (openAudioFile(path, ReplaceMainModel) == FileOpenFailed) {
2531 QMessageBox::critical(this, tr("Failed to open file"), 2536 QMessageBox::critical(this, tr("Failed to open file"),
2532 tr("Audio file \"%1\" could not be opened").arg(path)); 2537 tr("<b>File open failed</b><p>Audio file \"%1\" could not be opened").arg(path));
2533 } 2538 }
2534 } 2539 }
2535 } 2540 }
2536 2541
2537 void 2542 void
2540 QString path = getOpenFileName(FileFinder::AudioFile); 2545 QString path = getOpenFileName(FileFinder::AudioFile);
2541 2546
2542 if (path != "") { 2547 if (path != "") {
2543 if (openAudioFile(path, CreateAdditionalModel) == FileOpenFailed) { 2548 if (openAudioFile(path, CreateAdditionalModel) == FileOpenFailed) {
2544 QMessageBox::critical(this, tr("Failed to open file"), 2549 QMessageBox::critical(this, tr("Failed to open file"),
2545 tr("Audio file \"%1\" could not be opened").arg(path)); 2550 tr("<b>File open failed</b><p>Audio file \"%1\" could not be opened").arg(path));
2546 } 2551 }
2547 } 2552 }
2548 } 2553 }
2549 2554
2550 void 2555 void
2673 2678
2674 QString path = getOpenFileName(FileFinder::LayerFile); 2679 QString path = getOpenFileName(FileFinder::LayerFile);
2675 2680
2676 if (path != "") { 2681 if (path != "") {
2677 2682
2678 if (openLayerFile(path) == FileOpenFailed) { 2683 FileOpenStatus status = openLayerFile(path);
2684
2685 if (status == FileOpenFailed) {
2679 QMessageBox::critical(this, tr("Failed to open file"), 2686 QMessageBox::critical(this, tr("Failed to open file"),
2680 tr("File %1 could not be opened.").arg(path)); 2687 tr("<b>File open failed</b><p>Layer file %1 could not be opened.").arg(path));
2681 return; 2688 return;
2689 } else if (status == FileOpenWrongMode) {
2690 QMessageBox::critical(this, tr("Failed to open file"),
2691 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
2682 } 2692 }
2683 } 2693 }
2684 } 2694 }
2685 2695
2686 MainWindow::FileOpenStatus 2696 MainWindow::FileOpenStatus
2695 Pane *pane = m_paneStack->getCurrentPane(); 2705 Pane *pane = m_paneStack->getCurrentPane();
2696 2706
2697 if (!pane) { 2707 if (!pane) {
2698 // shouldn't happen, as the menu action should have been disabled 2708 // shouldn't happen, as the menu action should have been disabled
2699 std::cerr << "WARNING: MainWindow::openLayerFile: no current pane" << std::endl; 2709 std::cerr << "WARNING: MainWindow::openLayerFile: no current pane" << std::endl;
2700 return FileOpenFailed; 2710 return FileOpenWrongMode;
2701 } 2711 }
2702 2712
2703 if (!getMainModel()) { 2713 if (!getMainModel()) {
2704 // shouldn't happen, as the menu action should have been disabled 2714 // shouldn't happen, as the menu action should have been disabled
2705 std::cerr << "WARNING: MainWindow::openLayerFile: No main model -- hence no default sample rate available" << std::endl; 2715 std::cerr << "WARNING: MainWindow::openLayerFile: No main model -- hence no default sample rate available" << std::endl;
2706 return FileOpenFailed; 2716 return FileOpenWrongMode;
2707 } 2717 }
2708 2718
2709 bool realFile = (location == path); 2719 bool realFile = (location == path);
2710 2720
2711 if (path.endsWith(".svl") || path.endsWith(".xml")) { 2721 if (path.endsWith(".svl") || path.endsWith(".xml")) {
2742 2752
2743 return FileOpenSucceeded; 2753 return FileOpenSucceeded;
2744 2754
2745 } else { 2755 } else {
2746 2756
2747 Model *model = DataFileReaderFactory::load(path, getMainModel()->getSampleRate()); 2757 try {
2758
2759 Model *model = DataFileReaderFactory::load
2760 (path, getMainModel()->getSampleRate());
2748 2761
2749 if (model) { 2762 if (model) {
2750 2763
2751 Layer *newLayer = m_document->createImportedLayer(model); 2764 Layer *newLayer = m_document->createImportedLayer(model);
2752 2765
2753 if (newLayer) { 2766 if (newLayer) {
2754 2767
2755 m_document->addLayerToView(pane, newLayer); 2768 m_document->addLayerToView(pane, newLayer);
2756 m_recentFiles.addFile(location); 2769 m_recentFiles.addFile(location);
2757 2770
2758 if (realFile) { 2771 if (realFile) {
2759 registerLastOpenedFilePath(FileFinder::LayerFile, path); // for file dialog 2772 registerLastOpenedFilePath(FileFinder::LayerFile, path); // for file dialog
2773 }
2774
2775 return FileOpenSucceeded;
2760 } 2776 }
2761
2762 return FileOpenSucceeded;
2763 } 2777 }
2778 } catch (DataFileReaderFactory::Exception e) {
2779 if (e == DataFileReaderFactory::ImportCancelled) {
2780 return FileOpenCancelled;
2781 }
2764 } 2782 }
2765 } 2783 }
2766 2784
2767 return FileOpenFailed; 2785 return FileOpenFailed;
2786 }
2787
2788 MainWindow::FileOpenStatus
2789 MainWindow::openImageFile(QString path)
2790 {
2791 return openImageFile(path, path);
2792 }
2793
2794 MainWindow::FileOpenStatus
2795 MainWindow::openImageFile(QString path, QString location)
2796 {
2797 Pane *pane = m_paneStack->getCurrentPane();
2798
2799 if (!pane) {
2800 // shouldn't happen, as the menu action should have been disabled
2801 std::cerr << "WARNING: MainWindow::openImageFile: no current pane" << std::endl;
2802 return FileOpenWrongMode;
2803 }
2804
2805 if (!m_document->getMainModel()) {
2806 return FileOpenWrongMode;
2807 }
2808
2809 bool newLayer = false;
2810
2811 ImageLayer *il = dynamic_cast<ImageLayer *>(pane->getSelectedLayer());
2812 if (!il) {
2813 for (int i = pane->getLayerCount()-1; i >= 0; --i) {
2814 il = dynamic_cast<ImageLayer *>(pane->getLayer(i));
2815 if (il) break;
2816 }
2817 }
2818 if (!il) {
2819 il = dynamic_cast<ImageLayer *>
2820 (m_document->createEmptyLayer(LayerFactory::Image));
2821 if (!il) return FileOpenFailed;
2822 newLayer = true;
2823 }
2824
2825 // We don't put the image file in Recent Files
2826
2827 std::cerr << "openImageFile: trying location \"" << location.toStdString() << "\" in image layer" << std::endl;
2828
2829 if (!il->addImage(m_viewManager->getGlobalCentreFrame(), location)) {
2830 if (newLayer) {
2831 m_document->setModel(il, 0); // releasing its model
2832 delete il;
2833 }
2834 return FileOpenFailed;
2835 } else {
2836 if (newLayer) {
2837 m_document->addLayerToView(pane, il);
2838 }
2839 m_paneStack->setCurrentLayer(pane, il);
2840 return FileOpenSucceeded;
2841 }
2768 } 2842 }
2769 2843
2770 void 2844 void
2771 MainWindow::exportLayer() 2845 MainWindow::exportLayer()
2772 { 2846 {
3123 3197
3124 m_playTarget = AudioTargetFactory::createCallbackTarget(m_playSource); 3198 m_playTarget = AudioTargetFactory::createCallbackTarget(m_playSource);
3125 if (!m_playTarget) { 3199 if (!m_playTarget) {
3126 QMessageBox::warning 3200 QMessageBox::warning
3127 (this, tr("Couldn't open audio device"), 3201 (this, tr("Couldn't open audio device"),
3128 tr("Could not open an audio device for playback.\nAudio playback will not be available during this session.\n"), 3202 tr("<b>No audio available</b><p>Could not open an audio device for playback.<p>Audio playback will not be available during this session."),
3129 QMessageBox::Ok); 3203 QMessageBox::Ok);
3130 } 3204 }
3131 connect(m_fader, SIGNAL(valueChanged(float)), 3205 connect(m_fader, SIGNAL(valueChanged(float)),
3132 m_playTarget, SLOT(setOutputGain(float))); 3206 m_playTarget, SLOT(setOutputGain(float)));
3133 } 3207 }
3262 3336
3263 if (path.isEmpty()) return; 3337 if (path.isEmpty()) return;
3264 3338
3265 if (openSessionFile(path) == FileOpenFailed) { 3339 if (openSessionFile(path) == FileOpenFailed) {
3266 QMessageBox::critical(this, tr("Failed to open file"), 3340 QMessageBox::critical(this, tr("Failed to open file"),
3267 tr("Session file \"%1\" could not be opened").arg(path)); 3341 tr("<b>File open failed</b><p>Session file \"%1\" could not be opened").arg(path));
3268 } 3342 }
3269 } 3343 }
3270 3344
3271 void 3345 void
3272 MainWindow::openSomething() 3346 MainWindow::openSomething()
3273 { 3347 {
3274 QString orig = m_audioFile; 3348 QString orig = m_audioFile;
3275 if (orig == "") orig = "."; 3349 if (orig == "") orig = ".";
3276 else orig = QFileInfo(orig).absoluteDir().canonicalPath(); 3350 else orig = QFileInfo(orig).absoluteDir().canonicalPath();
3277 3351
3278 bool canImportLayer = (getMainModel() != 0 &&
3279 m_paneStack != 0 &&
3280 m_paneStack->getCurrentPane() != 0);
3281
3282 QString path = getOpenFileName(FileFinder::AnyFile); 3352 QString path = getOpenFileName(FileFinder::AnyFile);
3283 3353
3284 if (path.isEmpty()) return; 3354 if (path.isEmpty()) return;
3285 3355
3286 if (path.endsWith(".sv")) { 3356 FileOpenStatus status = openSomeFile(path, AskUser);
3287 3357
3288 if (!checkSaveModified()) return; 3358 if (status == FileOpenFailed) {
3289 3359 QMessageBox::critical(this, tr("Failed to open file"),
3290 if (openSessionFile(path) == FileOpenFailed) { 3360 tr("<b>File open failed</b><p>File \"%1\" could not be opened").arg(path));
3291 QMessageBox::critical(this, tr("Failed to open file"), 3361 } else if (status == FileOpenWrongMode) {
3292 tr("Session file \"%1\" could not be opened").arg(path)); 3362 QMessageBox::critical(this, tr("Failed to open file"),
3293 } 3363 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
3294
3295 } else {
3296
3297 if (openPlaylistFile(path, AskUser) == FileOpenFailed) {
3298
3299 if (openAudioFile(path, AskUser) == FileOpenFailed) {
3300
3301 if (!canImportLayer || (openLayerFile(path) == FileOpenFailed)) {
3302
3303 QMessageBox::critical(this, tr("Failed to open file"),
3304 tr("File \"%1\" could not be opened").arg(path));
3305 }
3306 }
3307 }
3308 } 3364 }
3309 } 3365 }
3310 3366
3311 void 3367 void
3312 MainWindow::openLocation() 3368 MainWindow::openLocation()
3325 3381
3326 settings.setValue("lastremote", text); 3382 settings.setValue("lastremote", text);
3327 3383
3328 if (text.isEmpty()) return; 3384 if (text.isEmpty()) return;
3329 3385
3330 if (openURL(QUrl(text)) == FileOpenFailed) { 3386 FileOpenStatus status = openURL(QUrl(text));
3387
3388 if (status == FileOpenFailed) {
3331 QMessageBox::critical(this, tr("Failed to open location"), 3389 QMessageBox::critical(this, tr("Failed to open location"),
3332 tr("URL \"%1\" could not be opened").arg(text)); 3390 tr("<b>Open failed</b><p>URL \"%1\" could not be opened").arg(text));
3391 } else if (status == FileOpenWrongMode) {
3392 QMessageBox::critical(this, tr("Failed to open location"),
3393 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
3333 } 3394 }
3334 } 3395 }
3335 3396
3336 void 3397 void
3337 MainWindow::openRecentFile() 3398 MainWindow::openRecentFile()
3346 } 3407 }
3347 3408
3348 QString path = action->text(); 3409 QString path = action->text();
3349 if (path == "") return; 3410 if (path == "") return;
3350 3411
3351 QUrl url(path); 3412 FileOpenStatus status = openURL(path);
3352 if (RemoteFile::canHandleScheme(url)) { 3413
3353 openURL(url); 3414 if (status == FileOpenFailed) {
3354 return; 3415 QMessageBox::critical(this, tr("Failed to open location"),
3355 } 3416 tr("<b>Open failed</b><p>File or URL \"%1\" could not be opened").arg(path));
3356 3417 } else if (status == FileOpenWrongMode) {
3357 if (path.endsWith("sv")) { 3418 QMessageBox::critical(this, tr("Failed to open location"),
3358 3419 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
3359 if (!checkSaveModified()) return;
3360
3361 if (openSessionFile(path) == FileOpenFailed) {
3362 QMessageBox::critical(this, tr("Failed to open file"),
3363 tr("Session file \"%1\" could not be opened").arg(path));
3364 }
3365
3366 } else {
3367
3368 if (openPlaylistFile(path, AskUser) == FileOpenFailed) {
3369
3370 if (openAudioFile(path, AskUser) == FileOpenFailed) {
3371
3372 bool canImportLayer = (getMainModel() != 0 &&
3373 m_paneStack != 0 &&
3374 m_paneStack->getCurrentPane() != 0);
3375
3376 if (!canImportLayer || (openLayerFile(path) == FileOpenFailed)) {
3377
3378 QMessageBox::critical(this, tr("Failed to open file"),
3379 tr("File \"%1\" could not be opened").arg(path));
3380 }
3381 }
3382 }
3383 } 3420 }
3384 } 3421 }
3385 3422
3386 MainWindow::FileOpenStatus 3423 MainWindow::FileOpenStatus
3387 MainWindow::openURL(QUrl url, AudioFileOpenMode mode) 3424 MainWindow::openURL(QUrl url, AudioFileOpenMode mode)
3388 { 3425 {
3389 if (url.scheme().toLower() == "file") { 3426 if (url.scheme().toLower() == "file" || url.scheme() == "") {
3390 3427
3391 return openSomeFile(url.toLocalFile(), mode); 3428 return openSomeFile(url.toLocalFile(), mode);
3392 3429
3393 } else if (!RemoteFile::canHandleScheme(url)) { 3430 } else if (!RemoteFile::canHandleScheme(url)) {
3394 3431
3395 QMessageBox::critical(this, tr("Unsupported scheme in URL"), 3432 QMessageBox::critical(this, tr("Unsupported scheme in URL"),
3396 tr("The URL scheme \"%1\" is not supported") 3433 tr("<b>Download failed</b><p>The URL scheme \"%1\" is not supported")
3397 .arg(url.scheme())); 3434 .arg(url.scheme()));
3398 return FileOpenFailed; 3435 return FileOpenFailed;
3399 3436
3400 } else { 3437 } else {
3401 RemoteFile rf(url); 3438 RemoteFile rf(url);
3402 rf.wait(); 3439 rf.wait();
3403 if (!rf.isOK()) { 3440 if (!rf.isOK()) {
3404 QMessageBox::critical(this, tr("File download failed"), 3441 QMessageBox::critical(this, tr("File download failed"),
3405 tr("Failed to download URL \"%1\": %2") 3442 tr("<b>Download failed</b><p>Failed to download URL \"%1\": %2")
3406 .arg(url.toString()).arg(rf.getErrorString())); 3443 .arg(url.toString()).arg(rf.getErrorString()));
3407 return FileOpenFailed; 3444 return FileOpenFailed;
3408 } 3445 }
3409 FileOpenStatus status; 3446 FileOpenStatus status;
3410 if ((status = openSomeFile(rf.getLocalFilename(), url.toString(), 3447 if ((status = openSomeFile(rf.getLocalFilename(), url.toString(),
3422 // This function is used when we don't know whether the string is 3459 // This function is used when we don't know whether the string is
3423 // an encoded or human-readable url 3460 // an encoded or human-readable url
3424 3461
3425 QUrl url(ustr); 3462 QUrl url(ustr);
3426 3463
3427 if (url.scheme().toLower() == "file") { 3464 if (url.scheme().toLower() == "file" || url.scheme() == "") {
3428 3465
3429 return openSomeFile(url.toLocalFile(), mode); 3466 FileOpenStatus status = openSomeFile(url.toLocalFile(), mode);
3467 if (status == FileOpenFailed) {
3468 url.setEncodedUrl(ustr.toAscii());
3469 status = openSomeFile(url.toLocalFile(), mode);
3470 }
3471 return status;
3430 3472
3431 } else if (!RemoteFile::canHandleScheme(url)) { 3473 } else if (!RemoteFile::canHandleScheme(url)) {
3432 3474
3433 QMessageBox::critical(this, tr("Unsupported scheme in URL"), 3475 QMessageBox::critical(this, tr("Unsupported scheme in URL"),
3434 tr("The URL scheme \"%1\" is not supported") 3476 tr("<b>Download failed</b><p>The URL scheme \"%1\" is not supported")
3435 .arg(url.scheme())); 3477 .arg(url.scheme()));
3436 return FileOpenFailed; 3478 return FileOpenFailed;
3437 3479
3438 } else { 3480 } else {
3439 RemoteFile rf(url); 3481 RemoteFile rf(url);
3477 3519
3478 if ((status = openPlaylistFile(path, location, mode)) != FileOpenFailed) { 3520 if ((status = openPlaylistFile(path, location, mode)) != FileOpenFailed) {
3479 return status; 3521 return status;
3480 } else if ((status = openAudioFile(path, location, mode)) != FileOpenFailed) { 3522 } else if ((status = openAudioFile(path, location, mode)) != FileOpenFailed) {
3481 return status; 3523 return status;
3482 } else if ((status = openSessionFile(path, location)) != FileOpenFailed) { 3524 } else if (QFileInfo(path).suffix().toLower() == "sv" &&
3525 (status = openSessionFile(path, location)) != FileOpenFailed) {
3483 return status; 3526 return status;
3484 } else if (!canImportLayer) { 3527 } else if (!canImportLayer) {
3485 return FileOpenFailed; 3528 return FileOpenWrongMode;
3529 } else if ((status = openImageFile(path, location)) != FileOpenFailed) {
3530 return status;
3486 } else if ((status = openLayerFile(path, location)) != FileOpenFailed) { 3531 } else if ((status = openLayerFile(path, location)) != FileOpenFailed) {
3487 return status; 3532 return status;
3488 } else { 3533 } else {
3489 return FileOpenFailed; 3534 return FileOpenFailed;
3490 } 3535 }
3551 } else { 3596 } else {
3552 setWindowTitle(tr("Sonic Visualiser")); 3597 setWindowTitle(tr("Sonic Visualiser"));
3553 } 3598 }
3554 3599
3555 return ok ? FileOpenSucceeded : FileOpenFailed; 3600 return ok ? FileOpenSucceeded : FileOpenFailed;
3601 }
3602
3603 void
3604 MainWindow::paneDropAccepted(Pane *pane, QStringList uriList)
3605 {
3606 if (pane) m_paneStack->setCurrentPane(pane);
3607
3608 for (QStringList::iterator i = uriList.begin(); i != uriList.end(); ++i) {
3609
3610 FileOpenStatus status =
3611 openURL(*i, (m_document->getMainModel() ?
3612 CreateAdditionalModel : ReplaceMainModel));
3613
3614 if (status == FileOpenFailed) {
3615 QMessageBox::critical(this, tr("Failed to open dropped URL"),
3616 tr("<b>Open failed</b><p>Dropped URL \"%1\" could not be opened").arg(*i));
3617 } else if (status == FileOpenWrongMode) {
3618 QMessageBox::critical(this, tr("Failed to open dropped URL"),
3619 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
3620 }
3621 }
3622 }
3623
3624 void
3625 MainWindow::paneDropAccepted(Pane *pane, QString text)
3626 {
3627 if (pane) m_paneStack->setCurrentPane(pane);
3628
3629 QUrl testUrl(text);
3630 if (testUrl.scheme() == "file" ||
3631 testUrl.scheme() == "http" ||
3632 testUrl.scheme() == "ftp") {
3633 QStringList list;
3634 list.push_back(text);
3635 paneDropAccepted(pane, list);
3636 return;
3637 }
3638
3639 //!!! open as text -- but by importing as if a CSV, or just adding
3640 //to a text layer?
3556 } 3641 }
3557 3642
3558 void 3643 void
3559 MainWindow::closeEvent(QCloseEvent *e) 3644 MainWindow::closeEvent(QCloseEvent *e)
3560 { 3645 {
3657 if (!m_documentModified) return true; 3742 if (!m_documentModified) return true;
3658 3743
3659 int button = 3744 int button =
3660 QMessageBox::warning(this, 3745 QMessageBox::warning(this,
3661 tr("Session modified"), 3746 tr("Session modified"),
3662 tr("The current session has been modified.\nDo you want to save it?"), 3747 tr("<b>Session modified</b><p>The current session has been modified.<br>Do you want to save it?<br>"),
3663 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, 3748 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
3664 QMessageBox::Yes); 3749 QMessageBox::Yes);
3665 3750
3666 if (button == QMessageBox::Yes) { 3751 if (button == QMessageBox::Yes) {
3667 saveSession(); 3752 saveSession();
3683 MainWindow::saveSession() 3768 MainWindow::saveSession()
3684 { 3769 {
3685 if (m_sessionFile != "") { 3770 if (m_sessionFile != "") {
3686 if (!saveSessionFile(m_sessionFile)) { 3771 if (!saveSessionFile(m_sessionFile)) {
3687 QMessageBox::critical(this, tr("Failed to save file"), 3772 QMessageBox::critical(this, tr("Failed to save file"),
3688 tr("Session file \"%1\" could not be saved.").arg(m_sessionFile)); 3773 tr("<b>Save failed</b><p>Session file \"%1\" could not be saved.").arg(m_sessionFile));
3689 } else { 3774 } else {
3690 CommandHistory::getInstance()->documentSaved(); 3775 CommandHistory::getInstance()->documentSaved();
3691 documentRestored(); 3776 documentRestored();
3692 } 3777 }
3693 } else { 3778 } else {
3706 3791
3707 if (path == "") return; 3792 if (path == "") return;
3708 3793
3709 if (!saveSessionFile(path)) { 3794 if (!saveSessionFile(path)) {
3710 QMessageBox::critical(this, tr("Failed to save file"), 3795 QMessageBox::critical(this, tr("Failed to save file"),
3711 tr("Session file \"%1\" could not be saved.").arg(path)); 3796 tr("<b>Save failed</b><p>Session file \"%1\" could not be saved.").arg(path));
3712 } else { 3797 } else {
3713 setWindowTitle(tr("Sonic Visualiser: %1") 3798 setWindowTitle(tr("Sonic Visualiser: %1")
3714 .arg(QFileInfo(path).fileName())); 3799 .arg(QFileInfo(path).fileName()));
3715 m_sessionFile = path; 3800 m_sessionFile = path;
3716 CommandHistory::getInstance()->documentSaved(); 3801 CommandHistory::getInstance()->documentSaved();
3738 3823
3739 QApplication::restoreOverrideCursor(); 3824 QApplication::restoreOverrideCursor();
3740 3825
3741 if (!bzFile.isOK()) { 3826 if (!bzFile.isOK()) {
3742 QMessageBox::critical(this, tr("Failed to write file"), 3827 QMessageBox::critical(this, tr("Failed to write file"),
3743 tr("Failed to write to file \"%1\": %2") 3828 tr("<b>Save failed</b><p>Failed to write to file \"%1\": %2")
3744 .arg(path).arg(bzFile.errorString())); 3829 .arg(path).arg(bzFile.errorString()));
3745 bzFile.close(); 3830 bzFile.close();
3746 return false; 3831 return false;
3747 } 3832 }
3748 3833
4704 void 4789 void
4705 MainWindow::sampleRateMismatch(size_t requested, size_t actual, 4790 MainWindow::sampleRateMismatch(size_t requested, size_t actual,
4706 bool willResample) 4791 bool willResample)
4707 { 4792 {
4708 if (!willResample) { 4793 if (!willResample) {
4709 //!!! more helpful message needed
4710 QMessageBox::information 4794 QMessageBox::information
4711 (this, tr("Sample rate mismatch"), 4795 (this, tr("Sample rate mismatch"),
4712 tr("The sample rate of this audio file (%1 Hz) does not match\nthe current playback rate (%2 Hz).\n\nThe file will play at the wrong speed and pitch.") 4796 tr("<b>Wrong sample rate</b><p>The sample rate of this audio file (%1 Hz) does not match\nthe current playback rate (%2 Hz).<p>The file will play at the wrong speed and pitch.<p>Change the <i>Resample mismatching files on import</i> option under <i>File</i> -> <i>Preferences</i> if you want to alter this behaviour.")
4713 .arg(requested).arg(actual)); 4797 .arg(requested).arg(actual));
4714 } 4798 }
4715 4799
4716 updateDescriptionLabel(); 4800 updateDescriptionLabel();
4717 } 4801 }
4719 void 4803 void
4720 MainWindow::audioOverloadPluginDisabled() 4804 MainWindow::audioOverloadPluginDisabled()
4721 { 4805 {
4722 QMessageBox::information 4806 QMessageBox::information
4723 (this, tr("Audio processing overload"), 4807 (this, tr("Audio processing overload"),
4724 tr("Audio effects plugin auditioning has been disabled\ndue to a processing overload.")); 4808 tr("<b>Overloaded</b><p>Audio effects plugin auditioning has been disabled due to a processing overload."));
4725 } 4809 }
4726 4810
4727 void 4811 void
4728 MainWindow::layerAdded(Layer *) 4812 MainWindow::layerAdded(Layer *)
4729 { 4813 {
4817 MainWindow::modelGenerationFailed(QString transformName) 4901 MainWindow::modelGenerationFailed(QString transformName)
4818 { 4902 {
4819 QMessageBox::warning 4903 QMessageBox::warning
4820 (this, 4904 (this,
4821 tr("Failed to generate layer"), 4905 tr("Failed to generate layer"),
4822 tr("Failed to generate a derived layer.\n\nThe layer transform \"%1\" failed.\n\nThis probably means that a plugin failed to initialise, perhaps because it\nrejected the processing block size that was requested.") 4906 tr("<b>Layer generation failed</b><p>Failed to generate a derived layer.<p>The layer transform \"%1\" failed.<p>This may mean that a plugin failed to initialise, perhaps because it rejected the processing block size that was requested.")
4823 .arg(transformName), 4907 .arg(transformName),
4824 QMessageBox::Ok); 4908 QMessageBox::Ok);
4825 } 4909 }
4826 4910
4827 void 4911 void
4828 MainWindow::modelRegenerationFailed(QString layerName, QString transformName) 4912 MainWindow::modelRegenerationFailed(QString layerName, QString transformName)
4829 { 4913 {
4830 QMessageBox::warning 4914 QMessageBox::warning
4831 (this, 4915 (this,
4832 tr("Failed to regenerate layer"), 4916 tr("Failed to regenerate layer"),
4833 tr("Failed to regenerate derived layer \"%1\".\n\nThe layer transform \"%2\" failed to run.\n\nThis probably means the layer used a plugin that is not currently available.") 4917 tr("<b>Layer generation failed</b><p>Failed to regenerate derived layer \"%1\".<p>The layer transform \"%2\" failed to run.<p>This may mean that the layer used a plugin that is not currently available.")
4834 .arg(layerName).arg(transformName), 4918 .arg(layerName).arg(transformName),
4835 QMessageBox::Ok); 4919 QMessageBox::Ok);
4836 } 4920 }
4837 4921
4838 void 4922 void