Mercurial > hg > sonic-visualiser
diff 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 |
line wrap: on
line diff
--- a/main/MainWindow.cpp Wed Oct 10 10:22:34 2007 +0000 +++ b/main/MainWindow.cpp Wed Oct 10 15:18:02 2007 +0000 @@ -34,6 +34,7 @@ #include "layer/Colour3DPlotLayer.h" #include "layer/SliceLayer.h" #include "layer/SliceableLayer.h" +#include "layer/ImageLayer.h" #include "widgets/Fader.h" #include "view/Overview.h" #include "widgets/PropertyBox.h" @@ -211,6 +212,10 @@ this, SLOT(propertyStacksResized())); connect(m_paneStack, SIGNAL(contextHelpChanged(const QString &)), this, SLOT(contextHelpChanged(const QString &))); + connect(m_paneStack, SIGNAL(dropAccepted(Pane *, QStringList)), + this, SLOT(paneDropAccepted(Pane *, QStringList))); + connect(m_paneStack, SIGNAL(dropAccepted(Pane *, QString)), + this, SLOT(paneDropAccepted(Pane *, QString))); scroll->setWidget(m_paneStack); @@ -2529,7 +2534,7 @@ if (path != "") { if (openAudioFile(path, ReplaceMainModel) == FileOpenFailed) { QMessageBox::critical(this, tr("Failed to open file"), - tr("Audio file \"%1\" could not be opened").arg(path)); + tr("<b>File open failed</b><p>Audio file \"%1\" could not be opened").arg(path)); } } } @@ -2542,7 +2547,7 @@ if (path != "") { if (openAudioFile(path, CreateAdditionalModel) == FileOpenFailed) { QMessageBox::critical(this, tr("Failed to open file"), - tr("Audio file \"%1\" could not be opened").arg(path)); + tr("<b>File open failed</b><p>Audio file \"%1\" could not be opened").arg(path)); } } } @@ -2675,10 +2680,15 @@ if (path != "") { - if (openLayerFile(path) == FileOpenFailed) { + FileOpenStatus status = openLayerFile(path); + + if (status == FileOpenFailed) { QMessageBox::critical(this, tr("Failed to open file"), - tr("File %1 could not be opened.").arg(path)); + tr("<b>File open failed</b><p>Layer file %1 could not be opened.").arg(path)); return; + } else if (status == FileOpenWrongMode) { + QMessageBox::critical(this, tr("Failed to open file"), + tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data")); } } } @@ -2697,13 +2707,13 @@ if (!pane) { // shouldn't happen, as the menu action should have been disabled std::cerr << "WARNING: MainWindow::openLayerFile: no current pane" << std::endl; - return FileOpenFailed; + return FileOpenWrongMode; } if (!getMainModel()) { // shouldn't happen, as the menu action should have been disabled std::cerr << "WARNING: MainWindow::openLayerFile: No main model -- hence no default sample rate available" << std::endl; - return FileOpenFailed; + return FileOpenWrongMode; } bool realFile = (location == path); @@ -2744,22 +2754,30 @@ } else { - Model *model = DataFileReaderFactory::load(path, getMainModel()->getSampleRate()); + try { + + Model *model = DataFileReaderFactory::load + (path, getMainModel()->getSampleRate()); - if (model) { - - Layer *newLayer = m_document->createImportedLayer(model); - - if (newLayer) { - - m_document->addLayerToView(pane, newLayer); - m_recentFiles.addFile(location); - - if (realFile) { - registerLastOpenedFilePath(FileFinder::LayerFile, path); // for file dialog + if (model) { + + Layer *newLayer = m_document->createImportedLayer(model); + + if (newLayer) { + + m_document->addLayerToView(pane, newLayer); + m_recentFiles.addFile(location); + + if (realFile) { + registerLastOpenedFilePath(FileFinder::LayerFile, path); // for file dialog + } + + return FileOpenSucceeded; } - - return FileOpenSucceeded; + } + } catch (DataFileReaderFactory::Exception e) { + if (e == DataFileReaderFactory::ImportCancelled) { + return FileOpenCancelled; } } } @@ -2767,6 +2785,62 @@ return FileOpenFailed; } +MainWindow::FileOpenStatus +MainWindow::openImageFile(QString path) +{ + return openImageFile(path, path); +} + +MainWindow::FileOpenStatus +MainWindow::openImageFile(QString path, QString location) +{ + Pane *pane = m_paneStack->getCurrentPane(); + + if (!pane) { + // shouldn't happen, as the menu action should have been disabled + std::cerr << "WARNING: MainWindow::openImageFile: no current pane" << std::endl; + return FileOpenWrongMode; + } + + if (!m_document->getMainModel()) { + return FileOpenWrongMode; + } + + bool newLayer = false; + + ImageLayer *il = dynamic_cast<ImageLayer *>(pane->getSelectedLayer()); + if (!il) { + for (int i = pane->getLayerCount()-1; i >= 0; --i) { + il = dynamic_cast<ImageLayer *>(pane->getLayer(i)); + if (il) break; + } + } + if (!il) { + il = dynamic_cast<ImageLayer *> + (m_document->createEmptyLayer(LayerFactory::Image)); + if (!il) return FileOpenFailed; + newLayer = true; + } + + // We don't put the image file in Recent Files + + std::cerr << "openImageFile: trying location \"" << location.toStdString() << "\" in image layer" << std::endl; + + if (!il->addImage(m_viewManager->getGlobalCentreFrame(), location)) { + if (newLayer) { + m_document->setModel(il, 0); // releasing its model + delete il; + } + return FileOpenFailed; + } else { + if (newLayer) { + m_document->addLayerToView(pane, il); + } + m_paneStack->setCurrentLayer(pane, il); + return FileOpenSucceeded; + } +} + void MainWindow::exportLayer() { @@ -3125,7 +3199,7 @@ if (!m_playTarget) { QMessageBox::warning (this, tr("Couldn't open audio device"), - tr("Could not open an audio device for playback.\nAudio playback will not be available during this session.\n"), + 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."), QMessageBox::Ok); } connect(m_fader, SIGNAL(valueChanged(float)), @@ -3264,7 +3338,7 @@ if (openSessionFile(path) == FileOpenFailed) { QMessageBox::critical(this, tr("Failed to open file"), - tr("Session file \"%1\" could not be opened").arg(path)); + tr("<b>File open failed</b><p>Session file \"%1\" could not be opened").arg(path)); } } @@ -3275,36 +3349,18 @@ if (orig == "") orig = "."; else orig = QFileInfo(orig).absoluteDir().canonicalPath(); - bool canImportLayer = (getMainModel() != 0 && - m_paneStack != 0 && - m_paneStack->getCurrentPane() != 0); - QString path = getOpenFileName(FileFinder::AnyFile); if (path.isEmpty()) return; - if (path.endsWith(".sv")) { - - if (!checkSaveModified()) return; - - if (openSessionFile(path) == FileOpenFailed) { - QMessageBox::critical(this, tr("Failed to open file"), - tr("Session file \"%1\" could not be opened").arg(path)); - } - - } else { - - if (openPlaylistFile(path, AskUser) == FileOpenFailed) { - - if (openAudioFile(path, AskUser) == FileOpenFailed) { - - if (!canImportLayer || (openLayerFile(path) == FileOpenFailed)) { - - QMessageBox::critical(this, tr("Failed to open file"), - tr("File \"%1\" could not be opened").arg(path)); - } - } - } + FileOpenStatus status = openSomeFile(path, AskUser); + + if (status == FileOpenFailed) { + QMessageBox::critical(this, tr("Failed to open file"), + tr("<b>File open failed</b><p>File \"%1\" could not be opened").arg(path)); + } else if (status == FileOpenWrongMode) { + QMessageBox::critical(this, tr("Failed to open file"), + tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data")); } } @@ -3327,9 +3383,14 @@ if (text.isEmpty()) return; - if (openURL(QUrl(text)) == FileOpenFailed) { + FileOpenStatus status = openURL(QUrl(text)); + + if (status == FileOpenFailed) { QMessageBox::critical(this, tr("Failed to open location"), - tr("URL \"%1\" could not be opened").arg(text)); + tr("<b>Open failed</b><p>URL \"%1\" could not be opened").arg(text)); + } else if (status == FileOpenWrongMode) { + QMessageBox::critical(this, tr("Failed to open location"), + tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data")); } } @@ -3348,52 +3409,28 @@ QString path = action->text(); if (path == "") return; - QUrl url(path); - if (RemoteFile::canHandleScheme(url)) { - openURL(url); - return; - } - - if (path.endsWith("sv")) { - - if (!checkSaveModified()) return; - - if (openSessionFile(path) == FileOpenFailed) { - QMessageBox::critical(this, tr("Failed to open file"), - tr("Session file \"%1\" could not be opened").arg(path)); - } - - } else { - - if (openPlaylistFile(path, AskUser) == FileOpenFailed) { - - if (openAudioFile(path, AskUser) == FileOpenFailed) { - - bool canImportLayer = (getMainModel() != 0 && - m_paneStack != 0 && - m_paneStack->getCurrentPane() != 0); - - if (!canImportLayer || (openLayerFile(path) == FileOpenFailed)) { - - QMessageBox::critical(this, tr("Failed to open file"), - tr("File \"%1\" could not be opened").arg(path)); - } - } - } + FileOpenStatus status = openURL(path); + + if (status == FileOpenFailed) { + QMessageBox::critical(this, tr("Failed to open location"), + tr("<b>Open failed</b><p>File or URL \"%1\" could not be opened").arg(path)); + } else if (status == FileOpenWrongMode) { + QMessageBox::critical(this, tr("Failed to open location"), + tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data")); } } MainWindow::FileOpenStatus MainWindow::openURL(QUrl url, AudioFileOpenMode mode) { - if (url.scheme().toLower() == "file") { + if (url.scheme().toLower() == "file" || url.scheme() == "") { return openSomeFile(url.toLocalFile(), mode); } else if (!RemoteFile::canHandleScheme(url)) { QMessageBox::critical(this, tr("Unsupported scheme in URL"), - tr("The URL scheme \"%1\" is not supported") + tr("<b>Download failed</b><p>The URL scheme \"%1\" is not supported") .arg(url.scheme())); return FileOpenFailed; @@ -3402,7 +3439,7 @@ rf.wait(); if (!rf.isOK()) { QMessageBox::critical(this, tr("File download failed"), - tr("Failed to download URL \"%1\": %2") + tr("<b>Download failed</b><p>Failed to download URL \"%1\": %2") .arg(url.toString()).arg(rf.getErrorString())); return FileOpenFailed; } @@ -3424,14 +3461,19 @@ QUrl url(ustr); - if (url.scheme().toLower() == "file") { - - return openSomeFile(url.toLocalFile(), mode); + if (url.scheme().toLower() == "file" || url.scheme() == "") { + + FileOpenStatus status = openSomeFile(url.toLocalFile(), mode); + if (status == FileOpenFailed) { + url.setEncodedUrl(ustr.toAscii()); + status = openSomeFile(url.toLocalFile(), mode); + } + return status; } else if (!RemoteFile::canHandleScheme(url)) { QMessageBox::critical(this, tr("Unsupported scheme in URL"), - tr("The URL scheme \"%1\" is not supported") + tr("<b>Download failed</b><p>The URL scheme \"%1\" is not supported") .arg(url.scheme())); return FileOpenFailed; @@ -3479,10 +3521,13 @@ return status; } else if ((status = openAudioFile(path, location, mode)) != FileOpenFailed) { return status; - } else if ((status = openSessionFile(path, location)) != FileOpenFailed) { + } else if (QFileInfo(path).suffix().toLower() == "sv" && + (status = openSessionFile(path, location)) != FileOpenFailed) { return status; } else if (!canImportLayer) { - return FileOpenFailed; + return FileOpenWrongMode; + } else if ((status = openImageFile(path, location)) != FileOpenFailed) { + return status; } else if ((status = openLayerFile(path, location)) != FileOpenFailed) { return status; } else { @@ -3556,6 +3601,46 @@ } void +MainWindow::paneDropAccepted(Pane *pane, QStringList uriList) +{ + if (pane) m_paneStack->setCurrentPane(pane); + + for (QStringList::iterator i = uriList.begin(); i != uriList.end(); ++i) { + + FileOpenStatus status = + openURL(*i, (m_document->getMainModel() ? + CreateAdditionalModel : ReplaceMainModel)); + + if (status == FileOpenFailed) { + QMessageBox::critical(this, tr("Failed to open dropped URL"), + tr("<b>Open failed</b><p>Dropped URL \"%1\" could not be opened").arg(*i)); + } else if (status == FileOpenWrongMode) { + QMessageBox::critical(this, tr("Failed to open dropped URL"), + tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data")); + } + } +} + +void +MainWindow::paneDropAccepted(Pane *pane, QString text) +{ + if (pane) m_paneStack->setCurrentPane(pane); + + QUrl testUrl(text); + if (testUrl.scheme() == "file" || + testUrl.scheme() == "http" || + testUrl.scheme() == "ftp") { + QStringList list; + list.push_back(text); + paneDropAccepted(pane, list); + return; + } + + //!!! open as text -- but by importing as if a CSV, or just adding + //to a text layer? +} + +void MainWindow::closeEvent(QCloseEvent *e) { // std::cerr << "MainWindow::closeEvent" << std::endl; @@ -3659,7 +3744,7 @@ int button = QMessageBox::warning(this, tr("Session modified"), - tr("The current session has been modified.\nDo you want to save it?"), + tr("<b>Session modified</b><p>The current session has been modified.<br>Do you want to save it?<br>"), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Yes); @@ -3685,7 +3770,7 @@ if (m_sessionFile != "") { if (!saveSessionFile(m_sessionFile)) { QMessageBox::critical(this, tr("Failed to save file"), - tr("Session file \"%1\" could not be saved.").arg(m_sessionFile)); + tr("<b>Save failed</b><p>Session file \"%1\" could not be saved.").arg(m_sessionFile)); } else { CommandHistory::getInstance()->documentSaved(); documentRestored(); @@ -3708,7 +3793,7 @@ if (!saveSessionFile(path)) { QMessageBox::critical(this, tr("Failed to save file"), - tr("Session file \"%1\" could not be saved.").arg(path)); + tr("<b>Save failed</b><p>Session file \"%1\" could not be saved.").arg(path)); } else { setWindowTitle(tr("Sonic Visualiser: %1") .arg(QFileInfo(path).fileName())); @@ -3740,7 +3825,7 @@ if (!bzFile.isOK()) { QMessageBox::critical(this, tr("Failed to write file"), - tr("Failed to write to file \"%1\": %2") + tr("<b>Save failed</b><p>Failed to write to file \"%1\": %2") .arg(path).arg(bzFile.errorString())); bzFile.close(); return false; @@ -4706,10 +4791,9 @@ bool willResample) { if (!willResample) { - //!!! more helpful message needed QMessageBox::information (this, tr("Sample rate mismatch"), - 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.") + 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.") .arg(requested).arg(actual)); } @@ -4721,7 +4805,7 @@ { QMessageBox::information (this, tr("Audio processing overload"), - tr("Audio effects plugin auditioning has been disabled\ndue to a processing overload.")); + tr("<b>Overloaded</b><p>Audio effects plugin auditioning has been disabled due to a processing overload.")); } void @@ -4819,7 +4903,7 @@ QMessageBox::warning (this, tr("Failed to generate layer"), - 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.") + 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.") .arg(transformName), QMessageBox::Ok); } @@ -4830,7 +4914,7 @@ QMessageBox::warning (this, tr("Failed to regenerate layer"), - 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.") + 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.") .arg(layerName).arg(transformName), QMessageBox::Ok); }