# HG changeset patch # User Chris Cannam # Date 1192029482 0 # Node ID 4e030ebb6b3606dd7f167a0e588aa05d140660b0 # Parent d3477f673fb45fb8aadd3b9221b4da8995eef27b * 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. diff -r d3477f673fb4 -r 4e030ebb6b36 main/MainWindow.cpp --- 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("File open failed

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("File open failed

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("File open failed

Layer file %1 could not be opened.").arg(path)); return; + } else if (status == FileOpenWrongMode) { + QMessageBox::critical(this, tr("Failed to open file"), + tr("Audio required

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(pane->getSelectedLayer()); + if (!il) { + for (int i = pane->getLayerCount()-1; i >= 0; --i) { + il = dynamic_cast(pane->getLayer(i)); + if (il) break; + } + } + if (!il) { + il = dynamic_cast + (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("No audio available

Could not open an audio device for playback.

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("File open failed

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("File open failed

File \"%1\" could not be opened").arg(path)); + } else if (status == FileOpenWrongMode) { + QMessageBox::critical(this, tr("Failed to open file"), + tr("Audio required

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("Open failed

URL \"%1\" could not be opened").arg(text)); + } else if (status == FileOpenWrongMode) { + QMessageBox::critical(this, tr("Failed to open location"), + tr("Audio required

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("Open failed

File or URL \"%1\" could not be opened").arg(path)); + } else if (status == FileOpenWrongMode) { + QMessageBox::critical(this, tr("Failed to open location"), + tr("Audio required

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("Download failed

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("Download failed

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("Download failed

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("Open failed

Dropped URL \"%1\" could not be opened").arg(*i)); + } else if (status == FileOpenWrongMode) { + QMessageBox::critical(this, tr("Failed to open dropped URL"), + tr("Audio required

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("Session modified

The current session has been modified.
Do you want to save it?
"), 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("Save failed

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("Save failed

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("Save failed

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("Wrong sample rate

The sample rate of this audio file (%1 Hz) does not match\nthe current playback rate (%2 Hz).

The file will play at the wrong speed and pitch.

Change the Resample mismatching files on import option under File -> Preferences 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("Overloaded

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("Layer generation failed

Failed to generate a derived layer.

The layer transform \"%1\" failed.

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("Layer generation failed

Failed to regenerate derived layer \"%1\".

The layer transform \"%2\" failed to run.

This may mean that the layer used a plugin that is not currently available.") .arg(layerName).arg(transformName), QMessageBox::Ok); } diff -r d3477f673fb4 -r 4e030ebb6b36 main/MainWindow.h --- a/main/MainWindow.h Wed Oct 10 10:22:34 2007 +0000 +++ b/main/MainWindow.h Wed Oct 10 15:18:02 2007 +0000 @@ -75,13 +75,15 @@ enum FileOpenStatus { FileOpenSucceeded, FileOpenFailed, - FileOpenCancelled + FileOpenCancelled, + FileOpenWrongMode // attempted to open layer when no main model present }; FileOpenStatus openSomeFile(QString path, AudioFileOpenMode = AskUser); FileOpenStatus openAudioFile(QString path, AudioFileOpenMode = AskUser); FileOpenStatus openPlaylistFile(QString path, AudioFileOpenMode = AskUser); FileOpenStatus openLayerFile(QString path); + FileOpenStatus openImageFile(QString path); FileOpenStatus openSessionFile(QString path); FileOpenStatus openURL(QUrl url, AudioFileOpenMode = AskUser); FileOpenStatus openURL(QString url, AudioFileOpenMode = AskUser); @@ -239,6 +241,9 @@ void propertyStacksResized(); + void paneDropAccepted(Pane *, QStringList); + void paneDropAccepted(Pane *, QString); + void setupRecentFilesMenu(); void setupRecentTransformsMenu(); @@ -430,6 +435,7 @@ FileOpenStatus openPlaylistFile(QString path, QString location, AudioFileOpenMode = AskUser); FileOpenStatus openLayerFile(QString path, QString location); + FileOpenStatus openImageFile(QString path, QString location); FileOpenStatus openSessionFile(QString path, QString location); QString getOpenFileName(FileFinder::FileType type);