Mercurial > hg > sonic-visualiser
changeset 200:1871581e4da9
* Split MainWindow out into MainWindowBase (pane stack management, basic file
I/O etc) and MainWindow (widget structure, menus and actions etc)
author | Chris Cannam |
---|---|
date | Mon, 22 Oct 2007 14:24:31 +0000 |
parents | 6e1d4d500092 |
children | de783e8ee5f0 |
files | main/MainWindow.cpp main/MainWindow.h main/MainWindowBase.cpp main/MainWindowBase.h main/main.cpp sv.pro |
diffstat | 6 files changed, 2515 insertions(+), 2187 deletions(-) [+] |
line wrap: on
line diff
--- a/main/MainWindow.cpp Mon Oct 22 09:45:35 2007 +0000 +++ b/main/MainWindow.cpp Mon Oct 22 14:24:31 2007 +0000 @@ -4,7 +4,7 @@ Sonic Visualiser An audio file viewer and annotation editor. Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam and QMUL. + This file copyright 2006-2007 Chris Cannam and QMUL. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -70,9 +70,6 @@ #include "base/ColourDatabase.h" #include "osc/OSCQueue.h" -//!!! -#include "data/model/AggregateWaveModel.h" - // For version information #include "vamp/vamp.h" #include "vamp-sdk/PluginBase.h" @@ -115,17 +112,8 @@ MainWindow::MainWindow(bool withAudioOutput, bool withOSCSupport) : - m_document(0), - m_paneStack(0), - m_viewManager(0), + MainWindowBase(withAudioOutput, withOSCSupport), m_overview(0), - m_timeRulerLayer(0), - m_audioOutput(withAudioOutput), - m_playSource(0), - m_playTarget(0), - m_oscQueue(withOSCSupport ? new OSCQueue() : 0), - m_recentFiles("RecentFiles", 20), - m_recentTransforms("RecentTransforms", 20), m_mainMenusCreated(false), m_paneMenu(0), m_layerMenu(0), @@ -141,10 +129,6 @@ m_rightButtonPlaybackMenu(0), m_ffwdAction(0), m_rwdAction(0), - m_documentModified(false), - m_openingAudioFile(false), - m_abandoning(false), - m_labeller(0), m_preferencesDialog(0), m_layerTreeView(0), m_keyReference(new KeyReference()) @@ -170,29 +154,10 @@ cdb->setUseDarkBackground(cdb->addColour(QColor(225, 74, 255), tr("Bright Purple")), true); cdb->setUseDarkBackground(cdb->addColour(QColor(255, 188, 80), tr("Bright Orange")), true); - connect(CommandHistory::getInstance(), SIGNAL(commandExecuted()), - this, SLOT(documentModified())); - connect(CommandHistory::getInstance(), SIGNAL(documentRestored()), - this, SLOT(documentRestored())); - QFrame *frame = new QFrame; setCentralWidget(frame); QGridLayout *layout = new QGridLayout; - - m_viewManager = new ViewManager(); - connect(m_viewManager, SIGNAL(selectionChanged()), - this, SLOT(updateMenuStates())); - connect(m_viewManager, SIGNAL(inProgressSelectionChanged()), - this, SLOT(inProgressSelectionChanged())); - - Preferences::BackgroundMode mode = - Preferences::getInstance()->getBackgroundMode(); - m_initialDarkBackground = m_viewManager->getGlobalDarkBackground(); - if (mode != Preferences::BackgroundFromTheme) { - m_viewManager->setGlobalDarkBackground - (mode == Preferences::DarkBackground); - } m_descriptionLabel = new QLabel; @@ -201,22 +166,6 @@ scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); scroll->setFrameShape(QFrame::NoFrame); - m_paneStack = new PaneStack(scroll, m_viewManager); - connect(m_paneStack, SIGNAL(currentPaneChanged(Pane *)), - this, SLOT(currentPaneChanged(Pane *))); - connect(m_paneStack, SIGNAL(currentLayerChanged(Pane *, Layer *)), - this, SLOT(currentLayerChanged(Pane *, Layer *))); - connect(m_paneStack, SIGNAL(rightButtonMenuRequested(Pane *, QPoint)), - this, SLOT(rightButtonMenuRequested(Pane *, QPoint))); - connect(m_paneStack, SIGNAL(propertyStacksResized()), - 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); m_overview = new Overview(frame); @@ -242,14 +191,7 @@ } else { m_panLayer->setBaseColour (ColourDatabase::getInstance()->getColourIndex(tr("Green"))); - } - - m_playSource = new AudioCallbackPlaySource(m_viewManager); - - connect(m_playSource, SIGNAL(sampleRateMismatch(size_t, size_t, bool)), - this, SLOT(sampleRateMismatch(size_t, size_t, bool))); - connect(m_playSource, SIGNAL(audioOverloadPluginDisabled()), - this, SLOT(audioOverloadPluginDisabled())); + } m_fader = new Fader(frame, false); connect(m_fader, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget())); @@ -318,45 +260,6 @@ frame->setLayout(layout); - connect(m_viewManager, SIGNAL(outputLevelsChanged(float, float)), - this, SLOT(outputLevelsChanged(float, float))); - - connect(m_viewManager, SIGNAL(playbackFrameChanged(unsigned long)), - this, SLOT(playbackFrameChanged(unsigned long))); - - connect(m_viewManager, SIGNAL(globalCentreFrameChanged(unsigned long)), - this, SLOT(globalCentreFrameChanged(unsigned long))); - - connect(m_viewManager, SIGNAL(viewCentreFrameChanged(View *, unsigned long)), - this, SLOT(viewCentreFrameChanged(View *, unsigned long))); - - connect(m_viewManager, SIGNAL(viewZoomLevelChanged(View *, unsigned long, bool)), - this, SLOT(viewZoomLevelChanged(View *, unsigned long, bool))); - - connect(Preferences::getInstance(), - SIGNAL(propertyChanged(PropertyContainer::PropertyName)), - this, - SLOT(preferenceChanged(PropertyContainer::PropertyName))); - -// preferenceChanged("Property Box Layout"); - - if (m_oscQueue && m_oscQueue->isOK()) { - connect(m_oscQueue, SIGNAL(messagesAvailable()), this, SLOT(pollOSC())); - QTimer *oscTimer = new QTimer(this); - connect(oscTimer, SIGNAL(timeout()), this, SLOT(pollOSC())); - oscTimer->start(1000); - } - - Labeller::ValueType labellerType = Labeller::ValueFromTwoLevelCounter; - settings.beginGroup("MainWindow"); - labellerType = (Labeller::ValueType) - settings.value("labellertype", (int)labellerType).toInt(); - int cycle = settings.value("labellercycle", 4).toInt(); - settings.endGroup(); - - m_labeller = new Labeller(labellerType); - m_labeller->setCounterCycleSize(cycle); - setupMenus(); setupToolbars(); setupHelpMenu(); @@ -368,81 +271,12 @@ MainWindow::~MainWindow() { -// std::cerr << "MainWindow::~MainWindow()" << std::endl; - - if (!m_abandoning) { - closeSession(); - } - delete m_playTarget; - delete m_playSource; - delete m_viewManager; - delete m_oscQueue; delete m_keyReference; delete m_preferencesDialog; delete m_layerTreeView; Profiles::getInstance()->dump(); } -QString -MainWindow::getOpenFileName(FileFinder::FileType type) -{ - FileFinder *ff = FileFinder::getInstance(); - switch (type) { - case FileFinder::SessionFile: - return ff->getOpenFileName(type, m_sessionFile); - case FileFinder::AudioFile: - return ff->getOpenFileName(type, m_audioFile); - case FileFinder::LayerFile: - return ff->getOpenFileName(type, m_sessionFile); - case FileFinder::LayerFileNoMidi: - return ff->getOpenFileName(type, m_sessionFile); - case FileFinder::SessionOrAudioFile: - return ff->getOpenFileName(type, m_sessionFile); - case FileFinder::ImageFile: - return ff->getOpenFileName(type, m_sessionFile); - case FileFinder::AnyFile: - if (getMainModel() != 0 && - m_paneStack != 0 && - m_paneStack->getCurrentPane() != 0) { // can import a layer - return ff->getOpenFileName(FileFinder::AnyFile, m_sessionFile); - } else { - return ff->getOpenFileName(FileFinder::SessionOrAudioFile, - m_sessionFile); - } - } - return ""; -} - -QString -MainWindow::getSaveFileName(FileFinder::FileType type) -{ - FileFinder *ff = FileFinder::getInstance(); - switch (type) { - case FileFinder::SessionFile: - return ff->getSaveFileName(type, m_sessionFile); - case FileFinder::AudioFile: - return ff->getSaveFileName(type, m_audioFile); - case FileFinder::LayerFile: - return ff->getSaveFileName(type, m_sessionFile); - case FileFinder::LayerFileNoMidi: - return ff->getSaveFileName(type, m_sessionFile); - case FileFinder::SessionOrAudioFile: - return ff->getSaveFileName(type, m_sessionFile); - case FileFinder::ImageFile: - return ff->getSaveFileName(type, m_sessionFile); - case FileFinder::AnyFile: - return ff->getSaveFileName(type, m_sessionFile); - } - return ""; -} - -void -MainWindow::registerLastOpenedFilePath(FileFinder::FileType type, QString path) -{ - FileFinder *ff = FileFinder::getInstance(); - ff->registerLastOpenedFilePath(type, path); -} - void MainWindow::setupMenus() { @@ -777,7 +611,7 @@ QActionGroup *cycleGroup = new QActionGroup(this); int cycles[] = { 2, 3, 4, 5, 6, 7, 8, 10, 12, 16 }; - for (int i = 0; i < sizeof(cycles)/sizeof(cycles[0]); ++i) { + for (int i = 0; i < int(sizeof(cycles)/sizeof(cycles[0])); ++i) { action = new QAction(QString("%1").arg(cycles[i]), this); connect(action, SIGNAL(triggered()), this, SLOT(setInstantsCounterCycle())); action->setCheckable(true); @@ -1909,6 +1743,8 @@ void MainWindow::updateMenuStates() { + MainWindowBase::updateMenuStates(); + Pane *currentPane = 0; Layer *currentLayer = 0; @@ -1920,10 +1756,6 @@ bool haveCurrentLayer = (haveCurrentPane && (currentLayer != 0)); - bool haveMainModel = - (getMainModel() != 0); - bool havePlayTarget = - (m_playTarget != 0); bool haveSelection = (m_viewManager && !m_viewManager->getSelections().empty()); @@ -1936,40 +1768,11 @@ bool haveCurrentTimeValueLayer = (haveCurrentLayer && dynamic_cast<TimeValueLayer *>(currentLayer)); - bool haveCurrentColour3DPlot = - (haveCurrentLayer && - dynamic_cast<Colour3DPlotLayer *>(currentLayer)); - bool haveClipboardContents = - (m_viewManager && - !m_viewManager->getClipboard().empty()); - - emit canAddPane(haveMainModel); - emit canDeleteCurrentPane(haveCurrentPane); - emit canZoom(haveMainModel && haveCurrentPane); - emit canScroll(haveMainModel && haveCurrentPane); - emit canAddLayer(haveMainModel && haveCurrentPane); - emit canImportMoreAudio(haveMainModel); - emit canImportLayer(haveMainModel && haveCurrentPane); - emit canExportAudio(haveMainModel); - emit canExportLayer(haveMainModel && - (haveCurrentEditableLayer || haveCurrentColour3DPlot)); - emit canExportImage(haveMainModel && haveCurrentPane); - emit canDeleteCurrentLayer(haveCurrentLayer); - emit canRenameLayer(haveCurrentLayer); - emit canEditLayer(haveCurrentEditableLayer); - emit canMeasureLayer(haveCurrentLayer); - emit canSelect(haveMainModel && haveCurrentPane); - emit canPlay(havePlayTarget); - emit canFfwd(true); - emit canRewind(true); - emit canPaste(haveCurrentEditableLayer && haveClipboardContents); - emit canInsertInstant(haveCurrentPane); - emit canInsertInstantsAtBoundaries(haveCurrentPane && haveSelection); - emit canRenumberInstants(haveCurrentTimeInstantsLayer && haveSelection); - emit canPlaySelection(haveMainModel && havePlayTarget && haveSelection); - emit canClearSelection(haveSelection); - emit canEditSelection(haveSelection && haveCurrentEditableLayer); - emit canSave(m_sessionFile != "" && m_documentModified); + + emit canChangePlaybackSpeed(true); + int v = m_playSpeed->value(); + emit canSpeedUpPlayback(v < m_playSpeed->maximum()); + emit canSlowDownPlayback(v > m_playSpeed->minimum()); if (m_viewManager && (m_viewManager->getToolMode() == ViewManager::MeasureMode)) { @@ -1982,11 +1785,6 @@ m_deleteSelectedAction->setStatusTip(tr("Delete items in current selection from the current layer")); } - emit canChangePlaybackSpeed(true); - int v = m_playSpeed->value(); - emit canSpeedUpPlayback(v < m_playSpeed->maximum()); - emit canSlowDownPlayback(v > m_playSpeed->minimum()); - if (m_ffwdAction && m_rwdAction) { if (haveCurrentTimeInstantsLayer) { m_ffwdAction->setText(tr("Fast Forward to Next Instant")); @@ -2038,124 +1836,15 @@ void MainWindow::documentModified() { -// std::cerr << "MainWindow::documentModified" << std::endl; - - if (!m_documentModified) { - setWindowTitle(tr("%1 (modified)").arg(windowTitle())); - } - - m_documentModified = true; - updateMenuStates(); + //!!! + MainWindowBase::documentModified(); } void MainWindow::documentRestored() { -// std::cerr << "MainWindow::documentRestored" << std::endl; - - if (m_documentModified) { - QString wt(windowTitle()); - wt.replace(tr(" (modified)"), ""); - setWindowTitle(wt); - } - - m_documentModified = false; - updateMenuStates(); -} - -void -MainWindow::playLoopToggled() -{ - QAction *action = dynamic_cast<QAction *>(sender()); - - if (action) { - m_viewManager->setPlayLoopMode(action->isChecked()); - } else { - m_viewManager->setPlayLoopMode(!m_viewManager->getPlayLoopMode()); - } -} - -void -MainWindow::playSelectionToggled() -{ - QAction *action = dynamic_cast<QAction *>(sender()); - - if (action) { - m_viewManager->setPlaySelectionMode(action->isChecked()); - } else { - m_viewManager->setPlaySelectionMode(!m_viewManager->getPlaySelectionMode()); - } -} - -void -MainWindow::playSoloToggled() -{ - QAction *action = dynamic_cast<QAction *>(sender()); - - if (action) { - m_viewManager->setPlaySoloMode(action->isChecked()); - } else { - m_viewManager->setPlaySoloMode(!m_viewManager->getPlaySoloMode()); - } - - if (m_viewManager->getPlaySoloMode()) { - currentPaneChanged(m_paneStack->getCurrentPane()); - } else { - m_viewManager->setPlaybackModel(0); - if (m_playSource) { - m_playSource->clearSoloModelSet(); - } - } -} - -void -MainWindow::currentPaneChanged(Pane *p) -{ - updateMenuStates(); - updateVisibleRangeDisplay(p); - - if (!p) return; - - if (!(m_viewManager && - m_playSource && - m_viewManager->getPlaySoloMode())) { - if (m_viewManager) m_viewManager->setPlaybackModel(0); - return; - } - - Model *prevPlaybackModel = m_viewManager->getPlaybackModel(); - - View::ModelSet soloModels = p->getModels(); - - for (View::ModelSet::iterator mi = soloModels.begin(); - mi != soloModels.end(); ++mi) { - if (dynamic_cast<RangeSummarisableTimeValueModel *>(*mi)) { - m_viewManager->setPlaybackModel(*mi); - } - } - - RangeSummarisableTimeValueModel *a = - dynamic_cast<RangeSummarisableTimeValueModel *>(prevPlaybackModel); - RangeSummarisableTimeValueModel *b = - dynamic_cast<RangeSummarisableTimeValueModel *>(m_viewManager-> - getPlaybackModel()); - - m_playSource->setSoloModelSet(soloModels); - - if (a && b && (a != b)) { - int frame = m_playSource->getCurrentPlayingFrame(); - //!!! I don't really believe that these functions are the right way around - int rframe = a->alignFromReference(frame); - int bframe = b->alignToReference(rframe); - if (m_playSource->isPlaying()) m_playSource->play(bframe); - } -} - -void -MainWindow::currentLayerChanged(Pane *p, Layer *) -{ - updateMenuStates(); - updateVisibleRangeDisplay(p); + //!!! + MainWindowBase::documentRestored(); } void @@ -2195,331 +1884,6 @@ //} void -MainWindow::selectAll() -{ - if (!getMainModel()) return; - m_viewManager->setSelection(Selection(getMainModel()->getStartFrame(), - getMainModel()->getEndFrame())); -} - -void -MainWindow::selectToStart() -{ - if (!getMainModel()) return; - m_viewManager->setSelection(Selection(getMainModel()->getStartFrame(), - m_viewManager->getGlobalCentreFrame())); -} - -void -MainWindow::selectToEnd() -{ - if (!getMainModel()) return; - m_viewManager->setSelection(Selection(m_viewManager->getGlobalCentreFrame(), - getMainModel()->getEndFrame())); -} - -void -MainWindow::selectVisible() -{ - Model *model = getMainModel(); - if (!model) return; - - Pane *currentPane = m_paneStack->getCurrentPane(); - if (!currentPane) return; - - size_t startFrame, endFrame; - - if (currentPane->getStartFrame() < 0) startFrame = 0; - else startFrame = currentPane->getStartFrame(); - - if (currentPane->getEndFrame() > model->getEndFrame()) endFrame = model->getEndFrame(); - else endFrame = currentPane->getEndFrame(); - - m_viewManager->setSelection(Selection(startFrame, endFrame)); -} - -void -MainWindow::clearSelection() -{ - m_viewManager->clearSelections(); -} - -void -MainWindow::cut() -{ - Pane *currentPane = m_paneStack->getCurrentPane(); - if (!currentPane) return; - - Layer *layer = currentPane->getSelectedLayer(); - if (!layer) return; - - Clipboard &clipboard = m_viewManager->getClipboard(); - clipboard.clear(); - - MultiSelection::SelectionList selections = m_viewManager->getSelections(); - - CommandHistory::getInstance()->startCompoundOperation(tr("Cut"), true); - - for (MultiSelection::SelectionList::iterator i = selections.begin(); - i != selections.end(); ++i) { - layer->copy(*i, clipboard); - layer->deleteSelection(*i); - } - - CommandHistory::getInstance()->endCompoundOperation(); -} - -void -MainWindow::copy() -{ - Pane *currentPane = m_paneStack->getCurrentPane(); - if (!currentPane) return; - - Layer *layer = currentPane->getSelectedLayer(); - if (!layer) return; - - Clipboard &clipboard = m_viewManager->getClipboard(); - clipboard.clear(); - - MultiSelection::SelectionList selections = m_viewManager->getSelections(); - - for (MultiSelection::SelectionList::iterator i = selections.begin(); - i != selections.end(); ++i) { - layer->copy(*i, clipboard); - } -} - -void -MainWindow::paste() -{ - Pane *currentPane = m_paneStack->getCurrentPane(); - if (!currentPane) return; - - //!!! if we have no current layer, we should create one of the most - // appropriate type - - Layer *layer = currentPane->getSelectedLayer(); - if (!layer) return; - - Clipboard &clipboard = m_viewManager->getClipboard(); - Clipboard::PointList contents = clipboard.getPoints(); -/* - long minFrame = 0; - bool have = false; - for (int i = 0; i < contents.size(); ++i) { - if (!contents[i].haveFrame()) continue; - if (!have || contents[i].getFrame() < minFrame) { - minFrame = contents[i].getFrame(); - have = true; - } - } - - long frameOffset = long(m_viewManager->getGlobalCentreFrame()) - minFrame; - - layer->paste(clipboard, frameOffset); -*/ - layer->paste(clipboard, 0, true); -} - -void -MainWindow::deleteSelected() -{ - if (m_paneStack->getCurrentPane() && - m_paneStack->getCurrentPane()->getSelectedLayer()) { - - Layer *layer = m_paneStack->getCurrentPane()->getSelectedLayer(); - - if (m_viewManager && - (m_viewManager->getToolMode() == ViewManager::MeasureMode)) { - - layer->deleteCurrentMeasureRect(); - - } else { - - MultiSelection::SelectionList selections = - m_viewManager->getSelections(); - - for (MultiSelection::SelectionList::iterator i = selections.begin(); - i != selections.end(); ++i) { - layer->deleteSelection(*i); - } - } - } -} - -void -MainWindow::insertInstant() -{ - int frame = m_viewManager->getPlaybackFrame(); - insertInstantAt(frame); -} - -void -MainWindow::insertInstantsAtBoundaries() -{ - MultiSelection::SelectionList selections = m_viewManager->getSelections(); - for (MultiSelection::SelectionList::iterator i = selections.begin(); - i != selections.end(); ++i) { - size_t start = i->getStartFrame(); - size_t end = i->getEndFrame(); - if (start != end) { - insertInstantAt(i->getStartFrame()); - insertInstantAt(i->getEndFrame()); - } - } -} - -void -MainWindow::insertInstantAt(size_t frame) -{ - Pane *pane = m_paneStack->getCurrentPane(); - if (!pane) { - return; - } - - Layer *layer = dynamic_cast<TimeInstantLayer *> - (pane->getSelectedLayer()); - - if (!layer) { - for (int i = pane->getLayerCount(); i > 0; --i) { - layer = dynamic_cast<TimeInstantLayer *>(pane->getLayer(i - 1)); - if (layer) break; - } - - if (!layer) { - CommandHistory::getInstance()->startCompoundOperation - (tr("Add Point"), true); - layer = m_document->createEmptyLayer(LayerFactory::TimeInstants); - if (layer) { - m_document->addLayerToView(pane, layer); - m_paneStack->setCurrentLayer(pane, layer); - } - CommandHistory::getInstance()->endCompoundOperation(); - } - } - - if (layer) { - - Model *model = layer->getModel(); - SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *> - (model); - - if (sodm) { - SparseOneDimensionalModel::Point point(frame, ""); - - SparseOneDimensionalModel::Point prevPoint(0); - bool havePrevPoint = false; - - SparseOneDimensionalModel::EditCommand *command = - new SparseOneDimensionalModel::EditCommand(sodm, tr("Add Point")); - - if (m_labeller->actingOnPrevPoint()) { - - SparseOneDimensionalModel::PointList prevPoints = - sodm->getPreviousPoints(frame); - - if (!prevPoints.empty()) { - prevPoint = *prevPoints.begin(); - havePrevPoint = true; - } - } - - if (m_labeller) { - - m_labeller->setSampleRate(sodm->getSampleRate()); - - if (havePrevPoint) { - command->deletePoint(prevPoint); - } - - m_labeller->label<SparseOneDimensionalModel::Point> - (point, havePrevPoint ? &prevPoint : 0); - - if (havePrevPoint) { - command->addPoint(prevPoint); - } - } - - command->addPoint(point); - - command->setName(tr("Add Point at %1 s") - .arg(RealTime::frame2RealTime - (frame, - sodm->getSampleRate()) - .toText(false).c_str())); - - command->finish(); - } - } -} - -void -MainWindow::setInstantsNumbering() -{ - QAction *a = dynamic_cast<QAction *>(sender()); - if (!a) return; - - int type = m_numberingActions[a]; - - if (m_labeller) m_labeller->setType(Labeller::ValueType(type)); - - QSettings settings; - settings.beginGroup("MainWindow"); - settings.setValue("labellertype", type); - settings.endGroup(); -} - -void -MainWindow::setInstantsCounterCycle() -{ - QAction *a = dynamic_cast<QAction *>(sender()); - if (!a) return; - - int cycle = a->text().toInt(); - if (cycle == 0) return; - - if (m_labeller) m_labeller->setCounterCycleSize(cycle); - - QSettings settings; - settings.beginGroup("MainWindow"); - settings.setValue("labellercycle", cycle); - settings.endGroup(); -} - -void -MainWindow::resetInstantsCounters() -{ - LabelCounterInputDialog dialog(m_labeller, this); - dialog.exec(); -} - -void -MainWindow::renumberInstants() -{ - Pane *pane = m_paneStack->getCurrentPane(); - if (!pane) return; - - Layer *layer = dynamic_cast<TimeInstantLayer *>(pane->getSelectedLayer()); - if (!layer) return; - - MultiSelection ms(m_viewManager->getSelection()); - - Model *model = layer->getModel(); - SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *> - (model); - if (!sodm) return; - - if (!m_labeller) return; - - Labeller labeller(*m_labeller); - labeller.setSampleRate(sodm->getSampleRate()); - - // This uses a command - - labeller.labelAll<SparseOneDimensionalModel::Point>(*sodm, &ms); -} - -void MainWindow::importAudio() { QString path = getOpenFileName(FileFinder::AudioFile); @@ -2857,498 +2221,6 @@ delete image; } -MainWindow::FileOpenStatus -MainWindow::open(QString fileOrUrl, AudioFileOpenMode mode) -{ - return open(FileSource(fileOrUrl), mode); -} - -MainWindow::FileOpenStatus -MainWindow::open(FileSource source, AudioFileOpenMode mode) -{ - FileOpenStatus status; - - if (!source.isAvailable()) return FileOpenFailed; - source.waitForData(); - - bool canImportLayer = (getMainModel() != 0 && - m_paneStack != 0 && - m_paneStack->getCurrentPane() != 0); - - if ((status = openAudio(source, mode)) != FileOpenFailed) { - return status; - } else if ((status = openSession(source)) != FileOpenFailed) { - return status; - } else if ((status = openPlaylist(source, mode)) != FileOpenFailed) { - return status; - } else if (!canImportLayer) { - return FileOpenWrongMode; - } else if ((status = openImage(source)) != FileOpenFailed) { - return status; - } else if ((status = openLayer(source)) != FileOpenFailed) { - return status; - } else { - return FileOpenFailed; - } -} - -MainWindow::FileOpenStatus -MainWindow::openAudio(FileSource source, AudioFileOpenMode mode) -{ - std::cerr << "MainWindow::openAudio(" << source.getLocation().toStdString() << ")" << std::endl; - - if (!source.isAvailable()) return FileOpenFailed; - source.waitForData(); - - m_openingAudioFile = true; - - size_t rate = 0; - - if (Preferences::getInstance()->getResampleOnLoad()) { - rate = m_playSource->getSourceSampleRate(); - } - - WaveFileModel *newModel = new WaveFileModel(source, rate); - - if (!newModel->isOK()) { - delete newModel; - m_openingAudioFile = false; - return FileOpenFailed; - } - - std::cerr << "mode = " << mode << std::endl; - - if (mode == AskUser) { - if (getMainModel()) { - - static bool prevSetAsMain = true; - bool setAsMain = true; - - QStringList items; - items << tr("Replace the existing main waveform") - << tr("Load this file into a new waveform pane"); - - bool ok = false; - QString item = ListInputDialog::getItem - (this, tr("Select target for import"), - tr("You already have an audio waveform loaded.\nWhat would you like to do with the new audio file?"), - items, prevSetAsMain ? 0 : 1, &ok); - - if (!ok || item.isEmpty()) { - delete newModel; - m_openingAudioFile = false; - return FileOpenCancelled; - } - - setAsMain = (item == items[0]); - prevSetAsMain = setAsMain; - - if (setAsMain) mode = ReplaceMainModel; - else mode = CreateAdditionalModel; - - } else { - mode = ReplaceMainModel; - } - } - - if (mode == ReplaceCurrentPane) { - - Pane *pane = m_paneStack->getCurrentPane(); - if (pane) { - if (getMainModel()) { - View::ModelSet models(pane->getModels()); - if (models.find(getMainModel()) != models.end()) { - mode = ReplaceMainModel; - } - } else { - mode = ReplaceMainModel; - } - } else { - mode = CreateAdditionalModel; - } - } - - if (mode == CreateAdditionalModel && !getMainModel()) { - mode = ReplaceMainModel; - } - - if (mode == ReplaceMainModel) { - - Model *prevMain = getMainModel(); - if (prevMain) { - m_playSource->removeModel(prevMain); - PlayParameterRepository::getInstance()->removeModel(prevMain); - } - PlayParameterRepository::getInstance()->addModel(newModel); - - m_document->setMainModel(newModel); - setupMenus(); - - if (m_sessionFile == "") { - setWindowTitle(tr("Sonic Visualiser: %1") - .arg(source.getLocation())); - CommandHistory::getInstance()->clear(); - CommandHistory::getInstance()->documentSaved(); - m_documentModified = false; - } else { - setWindowTitle(tr("Sonic Visualiser: %1 [%2]") - .arg(QFileInfo(m_sessionFile).fileName()) - .arg(source.getLocation())); - if (m_documentModified) { - m_documentModified = false; - documentModified(); // so as to restore "(modified)" window title - } - } - - if (!source.isRemote()) m_audioFile = source.getLocalFilename(); - - } else if (mode == CreateAdditionalModel) { - - CommandHistory::getInstance()->startCompoundOperation - (tr("Import \"%1\"").arg(source.getLocation()), true); - - m_document->addImportedModel(newModel); - - AddPaneCommand *command = new AddPaneCommand(this); - CommandHistory::getInstance()->addCommand(command); - - Pane *pane = command->getPane(); - - if (!m_timeRulerLayer) { - m_timeRulerLayer = m_document->createMainModelLayer - (LayerFactory::TimeRuler); - } - - m_document->addLayerToView(pane, m_timeRulerLayer); - - Layer *newLayer = m_document->createImportedLayer(newModel); - - if (newLayer) { - m_document->addLayerToView(pane, newLayer); - } - - CommandHistory::getInstance()->endCompoundOperation(); - - } else if (mode == ReplaceCurrentPane) { - - // We know there is a current pane, otherwise we would have - // reset the mode to CreateAdditionalModel above; and we know - // the current pane does not contain the main model, otherwise - // we would have reset it to ReplaceMainModel. But we don't - // know whether the pane contains a waveform model at all. - - Pane *pane = m_paneStack->getCurrentPane(); - Layer *replace = 0; - - for (int i = 0; i < pane->getLayerCount(); ++i) { - Layer *layer = pane->getLayer(i); - if (dynamic_cast<WaveformLayer *>(layer)) { - replace = layer; - break; - } - } - - CommandHistory::getInstance()->startCompoundOperation - (tr("Import \"%1\"").arg(source.getLocation()), true); - - m_document->addImportedModel(newModel); - - if (replace) { - m_document->removeLayerFromView(pane, replace); - } - - Layer *newLayer = m_document->createImportedLayer(newModel); - - if (newLayer) { - m_document->addLayerToView(pane, newLayer); - } - - CommandHistory::getInstance()->endCompoundOperation(); - } - - updateMenuStates(); - m_recentFiles.addFile(source.getLocation()); - if (!source.isRemote()) { - // for file dialog - registerLastOpenedFilePath(FileFinder::AudioFile, - source.getLocalFilename()); - } - m_openingAudioFile = false; - - currentPaneChanged(m_paneStack->getCurrentPane()); - - return FileOpenSucceeded; -} - -MainWindow::FileOpenStatus -MainWindow::openPlaylist(FileSource source, AudioFileOpenMode mode) -{ - std::set<QString> extensions; - PlaylistFileReader::getSupportedExtensions(extensions); - QString extension = source.getExtension(); - if (extensions.find(extension) == extensions.end()) return FileOpenFailed; - - if (!source.isAvailable()) return FileOpenFailed; - source.waitForData(); - - PlaylistFileReader reader(source.getLocalFilename()); - if (!reader.isOK()) return FileOpenFailed; - - PlaylistFileReader::Playlist playlist = reader.load(); - - bool someSuccess = false; - - for (PlaylistFileReader::Playlist::const_iterator i = playlist.begin(); - i != playlist.end(); ++i) { - - FileOpenStatus status = openAudio(*i, mode); - - if (status == FileOpenCancelled) { - return FileOpenCancelled; - } - - if (status == FileOpenSucceeded) { - someSuccess = true; - mode = CreateAdditionalModel; - } - } - - if (someSuccess) return FileOpenSucceeded; - else return FileOpenFailed; -} - -MainWindow::FileOpenStatus -MainWindow::openLayer(FileSource source) -{ - Pane *pane = m_paneStack->getCurrentPane(); - - if (!pane) { - // shouldn't happen, as the menu action should have been disabled - std::cerr << "WARNING: MainWindow::openLayer: no current pane" << std::endl; - return FileOpenWrongMode; - } - - if (!getMainModel()) { - // shouldn't happen, as the menu action should have been disabled - std::cerr << "WARNING: MainWindow::openLayer: No main model -- hence no default sample rate available" << std::endl; - return FileOpenWrongMode; - } - - if (!source.isAvailable()) return FileOpenFailed; - source.waitForData(); - - QString path = source.getLocalFilename(); - - if (source.getExtension() == "svl" || source.getExtension() == "xml") { - - PaneCallback callback(this); - QFile file(path); - - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - std::cerr << "ERROR: MainWindow::openLayer(" - << source.getLocation().toStdString() - << "): Failed to open file for reading" << std::endl; - return FileOpenFailed; - } - - SVFileReader reader(m_document, callback, source.getLocation()); - reader.setCurrentPane(pane); - - QXmlInputSource inputSource(&file); - reader.parse(inputSource); - - if (!reader.isOK()) { - std::cerr << "ERROR: MainWindow::openLayer(" - << source.getLocation().toStdString() - << "): Failed to read XML file: " - << reader.getErrorString().toStdString() << std::endl; - return FileOpenFailed; - } - - m_recentFiles.addFile(source.getLocation()); - - if (!source.isRemote()) { - registerLastOpenedFilePath(FileFinder::LayerFile, path); // for file dialog - } - - } else { - - try { - - Model *model = DataFileReaderFactory::load - (path, getMainModel()->getSampleRate()); - - if (model) { - - std::cerr << "MainWindow::openLayer: Have model" << std::endl; - - Layer *newLayer = m_document->createImportedLayer(model); - - if (newLayer) { - - m_document->addLayerToView(pane, newLayer); - m_recentFiles.addFile(source.getLocation()); - - if (!source.isRemote()) { - registerLastOpenedFilePath - (FileFinder::LayerFile, - path); // for file dialog - } - - return FileOpenSucceeded; - } - } - } catch (DataFileReaderFactory::Exception e) { - if (e == DataFileReaderFactory::ImportCancelled) { - return FileOpenCancelled; - } - } - } - - source.setLeaveLocalFile(true); - return FileOpenFailed; -} - -MainWindow::FileOpenStatus -MainWindow::openImage(FileSource source) -{ - Pane *pane = m_paneStack->getCurrentPane(); - - if (!pane) { - // shouldn't happen, as the menu action should have been disabled - std::cerr << "WARNING: MainWindow::openImage: 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 << "openImage: trying location \"" << source.getLocation().toStdString() << "\" in image layer" << std::endl; - - if (!il->addImage(m_viewManager->getGlobalCentreFrame(), source.getLocation())) { - 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; -} - -MainWindow::FileOpenStatus -MainWindow::openSession(FileSource source) -{ - if (!source.isAvailable()) return FileOpenFailed; - if (source.getExtension() != "sv") return FileOpenFailed; - source.waitForData(); - - BZipFileDevice bzFile(source.getLocalFilename()); - if (!bzFile.open(QIODevice::ReadOnly)) return FileOpenFailed; - - if (!checkSaveModified()) return FileOpenCancelled; - - QString error; - closeSession(); - createDocument(); - - PaneCallback callback(this); - m_viewManager->clearSelections(); - - SVFileReader reader(m_document, callback, source.getLocation()); - QXmlInputSource inputSource(&bzFile); - reader.parse(inputSource); - - if (!reader.isOK()) { - error = tr("SV XML file read error:\n%1").arg(reader.getErrorString()); - } - - bzFile.close(); - - bool ok = (error == ""); - - if (ok) { - - setWindowTitle(tr("Sonic Visualiser: %1") - .arg(source.getLocation())); - - if (!source.isRemote()) m_sessionFile = source.getLocalFilename(); - - setupMenus(); - CommandHistory::getInstance()->clear(); - CommandHistory::getInstance()->documentSaved(); - m_documentModified = false; - updateMenuStates(); - - m_recentFiles.addFile(source.getLocation()); - - if (!source.isRemote()) { - // for file dialog - registerLastOpenedFilePath(FileFinder::SessionFile, - source.getLocalFilename()); - } - - } else { - setWindowTitle(tr("Sonic Visualiser")); - } - - return ok ? FileOpenSucceeded : FileOpenFailed; -} - -void -MainWindow::createPlayTarget() -{ - if (m_playTarget) return; - - m_playTarget = AudioTargetFactory::createCallbackTarget(m_playSource); - if (!m_playTarget) { - QMessageBox::warning - (this, tr("Couldn't open audio device"), - 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)), - m_playTarget, SLOT(setOutputGain(float))); -} - -WaveFileModel * -MainWindow::getMainModel() -{ - if (!m_document) return 0; - return m_document->getMainModel(); -} - -const WaveFileModel * -MainWindow::getMainModel() const -{ - if (!m_document) return 0; - return m_document->getMainModel(); -} - void MainWindow::newSession() { @@ -3381,33 +2253,6 @@ } void -MainWindow::createDocument() -{ - m_document = new Document; - - connect(m_document, SIGNAL(layerAdded(Layer *)), - this, SLOT(layerAdded(Layer *))); - connect(m_document, SIGNAL(layerRemoved(Layer *)), - this, SLOT(layerRemoved(Layer *))); - connect(m_document, SIGNAL(layerAboutToBeDeleted(Layer *)), - this, SLOT(layerAboutToBeDeleted(Layer *))); - connect(m_document, SIGNAL(layerInAView(Layer *, bool)), - this, SLOT(layerInAView(Layer *, bool))); - - connect(m_document, SIGNAL(modelAdded(Model *)), - this, SLOT(modelAdded(Model *))); - connect(m_document, SIGNAL(mainModelChanged(WaveFileModel *)), - this, SLOT(mainModelChanged(WaveFileModel *))); - connect(m_document, SIGNAL(modelAboutToBeDeleted(Model *)), - this, SLOT(modelAboutToBeDeleted(Model *))); - - connect(m_document, SIGNAL(modelGenerationFailed(QString)), - this, SLOT(modelGenerationFailed(QString))); - connect(m_document, SIGNAL(modelRegenerationFailed(QString, QString)), - this, SLOT(modelRegenerationFailed(QString, QString))); -} - -void MainWindow::closeSession() { if (!checkSaveModified()) return; @@ -3465,7 +2310,7 @@ if (path.isEmpty()) return; - if (openSession(path) == FileOpenFailed) { + if (openSessionFile(path) == FileOpenFailed) { QMessageBox::critical(this, tr("Failed to open file"), tr("<b>File open failed</b><p>Session file \"%1\" could not be opened").arg(path)); } @@ -3550,6 +2395,24 @@ } void +MainWindow::paneAdded(Pane *pane) +{ + if (m_overview) m_overview->registerView(pane); +} + +void +MainWindow::paneHidden(Pane *pane) +{ + if (m_overview) m_overview->unregisterView(pane); +} + +void +MainWindow::paneAboutToBeDeleted(Pane *pane) +{ + if (m_overview) m_overview->unregisterView(pane); +} + +void MainWindow::paneDropAccepted(Pane *pane, QStringList uriList) { if (pane) m_paneStack->setCurrentPane(pane); @@ -3624,6 +2487,8 @@ delete m_layerTreeView; } + closeSession(); + e->accept(); return; } @@ -3751,239 +2616,12 @@ } } -bool -MainWindow::saveSessionFile(QString path) -{ - BZipFileDevice bzFile(path); - if (!bzFile.open(QIODevice::WriteOnly)) { - std::cerr << "Failed to open session file \"" << path.toStdString() - << "\" for writing: " - << bzFile.errorString().toStdString() << std::endl; - return false; - } - - QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); - - QTextStream out(&bzFile); - toXml(out); - out.flush(); - - QApplication::restoreOverrideCursor(); - - if (!bzFile.isOK()) { - QMessageBox::critical(this, tr("Failed to write file"), - tr("<b>Save failed</b><p>Failed to write to file \"%1\": %2") - .arg(path).arg(bzFile.errorString())); - bzFile.close(); - return false; - } - - bzFile.close(); - return true; -} - -void -MainWindow::toXml(QTextStream &out) -{ - QString indent(" "); - - out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; - out << "<!DOCTYPE sonic-visualiser>\n"; - out << "<sv>\n"; - - m_document->toXml(out, "", ""); - - out << "<display>\n"; - - out << QString(" <window width=\"%1\" height=\"%2\"/>\n") - .arg(width()).arg(height()); - - for (int i = 0; i < m_paneStack->getPaneCount(); ++i) { - - Pane *pane = m_paneStack->getPane(i); - - if (pane) { - pane->toXml(out, indent); - } - } - - out << "</display>\n"; - - m_viewManager->getSelection().toXml(out); - - out << "</sv>\n"; -} - -Pane * -MainWindow::addPaneToStack() -{ - AddPaneCommand *command = new AddPaneCommand(this); - CommandHistory::getInstance()->addCommand(command); - return command->getPane(); -} - -void -MainWindow::zoomIn() -{ - Pane *currentPane = m_paneStack->getCurrentPane(); - if (currentPane) currentPane->zoom(true); -} - -void -MainWindow::zoomOut() -{ - Pane *currentPane = m_paneStack->getCurrentPane(); - if (currentPane) currentPane->zoom(false); -} - -void -MainWindow::zoomToFit() -{ - Pane *currentPane = m_paneStack->getCurrentPane(); - if (!currentPane) return; - - Model *model = getMainModel(); - if (!model) return; - - size_t start = model->getStartFrame(); - size_t end = model->getEndFrame(); - size_t pixels = currentPane->width(); - - size_t sw = currentPane->getVerticalScaleWidth(); - if (pixels > sw * 2) pixels -= sw * 2; - else pixels = 1; - if (pixels > 4) pixels -= 4; - - size_t zoomLevel = (end - start) / pixels; - - currentPane->setZoomLevel(zoomLevel); - currentPane->setCentreFrame((start + end) / 2); -} - -void -MainWindow::zoomDefault() -{ - Pane *currentPane = m_paneStack->getCurrentPane(); - if (currentPane) currentPane->setZoomLevel(1024); -} - -void -MainWindow::scrollLeft() -{ - Pane *currentPane = m_paneStack->getCurrentPane(); - if (currentPane) currentPane->scroll(false, false); -} - -void -MainWindow::jumpLeft() -{ - Pane *currentPane = m_paneStack->getCurrentPane(); - if (currentPane) currentPane->scroll(false, true); -} - -void -MainWindow::scrollRight() -{ - Pane *currentPane = m_paneStack->getCurrentPane(); - if (currentPane) currentPane->scroll(true, false); -} - -void -MainWindow::jumpRight() -{ - Pane *currentPane = m_paneStack->getCurrentPane(); - if (currentPane) currentPane->scroll(true, true); -} - -void -MainWindow::showNoOverlays() -{ - m_viewManager->setOverlayMode(ViewManager::NoOverlays); -} - -void -MainWindow::showMinimalOverlays() -{ - m_viewManager->setOverlayMode(ViewManager::MinimalOverlays); -} - -void -MainWindow::showStandardOverlays() -{ - m_viewManager->setOverlayMode(ViewManager::StandardOverlays); -} - -void -MainWindow::showAllOverlays() -{ - m_viewManager->setOverlayMode(ViewManager::AllOverlays); -} - -void -MainWindow::toggleZoomWheels() -{ - if (m_viewManager->getZoomWheelsEnabled()) { - m_viewManager->setZoomWheelsEnabled(false); - } else { - m_viewManager->setZoomWheelsEnabled(true); - } -} - -void -MainWindow::togglePropertyBoxes() -{ - if (m_paneStack->getLayoutStyle() == PaneStack::NoPropertyStacks) { - if (Preferences::getInstance()->getPropertyBoxLayout() == - Preferences::VerticallyStacked) { - m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout); - } else { - m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout); - } - } else { - m_paneStack->setLayoutStyle(PaneStack::NoPropertyStacks); - } -} - -void -MainWindow::toggleStatusBar() -{ - QSettings settings; - settings.beginGroup("MainWindow"); - bool sb = settings.value("showstatusbar", true).toBool(); - - if (sb) { - statusBar()->hide(); - } else { - statusBar()->show(); - } - - settings.setValue("showstatusbar", !sb); - - settings.endGroup(); -} - void MainWindow::preferenceChanged(PropertyContainer::PropertyName name) { - if (name == "Property Box Layout") { - if (m_paneStack->getLayoutStyle() != PaneStack::NoPropertyStacks) { - if (Preferences::getInstance()->getPropertyBoxLayout() == - Preferences::VerticallyStacked) { - m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout); - } else { - m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout); - } - } - } else if (name == "Background Mode" && m_viewManager) { - Preferences::BackgroundMode mode = - Preferences::getInstance()->getBackgroundMode(); - if (mode == Preferences::BackgroundFromTheme) { - m_viewManager->setGlobalDarkBackground(m_initialDarkBackground); - } else if (mode == Preferences::DarkBackground) { - m_viewManager->setGlobalDarkBackground(true); - } else { - m_viewManager->setGlobalDarkBackground(false); - } + MainWindowBase::preferenceChanged(name); + + if (name == "Background Mode" && m_viewManager) { if (m_viewManager->getGlobalDarkBackground()) { m_panLayer->setBaseColour (ColourDatabase::getInstance()->getColourIndex(tr("Bright Green"))); @@ -3991,171 +2629,7 @@ m_panLayer->setBaseColour (ColourDatabase::getInstance()->getColourIndex(tr("Green"))); } - } -} - -void -MainWindow::play() -{ - if (m_playSource->isPlaying()) { - stop(); - } else { - playbackFrameChanged(m_viewManager->getPlaybackFrame()); - m_playSource->play(m_viewManager->getPlaybackFrame()); - } -} - -void -MainWindow::ffwd() -{ - if (!getMainModel()) return; - - int frame = m_viewManager->getPlaybackFrame(); - ++frame; - - Layer *layer = getSnapLayer(); - size_t sr = getMainModel()->getSampleRate(); - - if (!layer) { - - frame = RealTime::realTime2Frame - (RealTime::frame2RealTime(frame, sr) + RealTime(2, 0), sr); - if (frame > int(getMainModel()->getEndFrame())) { - frame = getMainModel()->getEndFrame(); - } - - } else { - - size_t resolution = 0; - if (!layer->snapToFeatureFrame(m_paneStack->getCurrentPane(), - frame, resolution, Layer::SnapRight)) { - frame = getMainModel()->getEndFrame(); - } - } - - if (frame < 0) frame = 0; - - if (m_viewManager->getPlaySelectionMode()) { - frame = m_viewManager->constrainFrameToSelection(size_t(frame)); - } - - m_viewManager->setPlaybackFrame(frame); -} - -void -MainWindow::ffwdEnd() -{ - if (!getMainModel()) return; - - size_t frame = getMainModel()->getEndFrame(); - - if (m_viewManager->getPlaySelectionMode()) { - frame = m_viewManager->constrainFrameToSelection(frame); - } - - m_viewManager->setPlaybackFrame(frame); -} - -void -MainWindow::rewind() -{ - if (!getMainModel()) return; - - int frame = m_viewManager->getPlaybackFrame(); - if (frame > 0) --frame; - - Layer *layer = getSnapLayer(); - size_t sr = getMainModel()->getSampleRate(); - - // when rewinding during playback, we want to allow a period - // following a rewind target point at which the rewind will go to - // the prior point instead of the immediately neighbouring one - if (m_playSource && m_playSource->isPlaying()) { - RealTime ct = RealTime::frame2RealTime(frame, sr); - ct = ct - RealTime::fromSeconds(0.25); - if (ct < RealTime::zeroTime) ct = RealTime::zeroTime; -// std::cerr << "rewind: frame " << frame << " -> "; - frame = RealTime::realTime2Frame(ct, sr); -// std::cerr << frame << std::endl; - } - - if (!layer) { - - frame = RealTime::realTime2Frame - (RealTime::frame2RealTime(frame, sr) - RealTime(2, 0), sr); - if (frame < int(getMainModel()->getStartFrame())) { - frame = getMainModel()->getStartFrame(); - } - - } else { - - size_t resolution = 0; - if (!layer->snapToFeatureFrame(m_paneStack->getCurrentPane(), - frame, resolution, Layer::SnapLeft)) { - frame = getMainModel()->getStartFrame(); - } - } - - if (frame < 0) frame = 0; - - if (m_viewManager->getPlaySelectionMode()) { - frame = m_viewManager->constrainFrameToSelection(size_t(frame)); - } - - m_viewManager->setPlaybackFrame(frame); -} - -void -MainWindow::rewindStart() -{ - if (!getMainModel()) return; - - size_t frame = getMainModel()->getStartFrame(); - - if (m_viewManager->getPlaySelectionMode()) { - frame = m_viewManager->constrainFrameToSelection(frame); - } - - m_viewManager->setPlaybackFrame(frame); -} - -Layer * -MainWindow::getSnapLayer() const -{ - Pane *pane = m_paneStack->getCurrentPane(); - if (!pane) return 0; - - Layer *layer = pane->getSelectedLayer(); - - if (!dynamic_cast<TimeInstantLayer *>(layer) && - !dynamic_cast<TimeValueLayer *>(layer) && - !dynamic_cast<TimeRulerLayer *>(layer)) { - - layer = 0; - - for (int i = pane->getLayerCount(); i > 0; --i) { - Layer *l = pane->getLayer(i-1); - if (dynamic_cast<TimeRulerLayer *>(l)) { - layer = l; - break; - } - } - } - - return layer; -} - -void -MainWindow::stop() -{ - m_playSource->stop(); - - if (m_paneStack && m_paneStack->getCurrentPane()) { - updateVisibleRangeDisplay(m_paneStack->getCurrentPane()); - } else { - m_myStatusMessage = ""; - statusBar()->showMessage(""); - } + } } void @@ -4253,92 +2727,6 @@ updateMenuStates(); } -MainWindow::AddPaneCommand::AddPaneCommand(MainWindow *mw) : - m_mw(mw), - m_pane(0), - m_prevCurrentPane(0), - m_added(false) -{ -} - -MainWindow::AddPaneCommand::~AddPaneCommand() -{ - if (m_pane && !m_added) { - m_mw->m_paneStack->deletePane(m_pane); - } -} - -QString -MainWindow::AddPaneCommand::getName() const -{ - return tr("Add Pane"); -} - -void -MainWindow::AddPaneCommand::execute() -{ - if (!m_pane) { - m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane(); - m_pane = m_mw->m_paneStack->addPane(); - - connect(m_pane, SIGNAL(contextHelpChanged(const QString &)), - m_mw, SLOT(contextHelpChanged(const QString &))); - } else { - m_mw->m_paneStack->showPane(m_pane); - } - - m_mw->m_paneStack->setCurrentPane(m_pane); - m_mw->m_overview->registerView(m_pane); - m_added = true; -} - -void -MainWindow::AddPaneCommand::unexecute() -{ - m_mw->m_paneStack->hidePane(m_pane); - m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane); - m_mw->m_overview->unregisterView(m_pane); - m_added = false; -} - -MainWindow::RemovePaneCommand::RemovePaneCommand(MainWindow *mw, Pane *pane) : - m_mw(mw), - m_pane(pane), - m_added(true) -{ -} - -MainWindow::RemovePaneCommand::~RemovePaneCommand() -{ - if (m_pane && !m_added) { - m_mw->m_paneStack->deletePane(m_pane); - } -} - -QString -MainWindow::RemovePaneCommand::getName() const -{ - return tr("Remove Pane"); -} - -void -MainWindow::RemovePaneCommand::execute() -{ - m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane(); - m_mw->m_paneStack->hidePane(m_pane); - m_mw->m_overview->unregisterView(m_pane); - m_added = false; -} - -void -MainWindow::RemovePaneCommand::unexecute() -{ - m_mw->m_paneStack->showPane(m_pane); - m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane); - m_mw->m_overview->registerView(m_pane); - m_added = true; -} - void MainWindow::addLayer() { @@ -4478,45 +2866,6 @@ } void -MainWindow::deleteCurrentPane() -{ - CommandHistory::getInstance()->startCompoundOperation - (tr("Delete Pane"), true); - - Pane *pane = m_paneStack->getCurrentPane(); - if (pane) { - while (pane->getLayerCount() > 0) { - Layer *layer = pane->getLayer(0); - if (layer) { - m_document->removeLayerFromView(pane, layer); - } else { - break; - } - } - - RemovePaneCommand *command = new RemovePaneCommand(this, pane); - CommandHistory::getInstance()->addCommand(command); - } - - CommandHistory::getInstance()->endCompoundOperation(); - - updateMenuStates(); -} - -void -MainWindow::deleteCurrentLayer() -{ - Pane *pane = m_paneStack->getCurrentPane(); - if (pane) { - Layer *layer = pane->getSelectedLayer(); - if (layer) { - m_document->removeLayerFromView(pane, layer); - } - } - updateMenuStates(); -} - -void MainWindow::renameCurrentLayer() { Pane *pane = m_paneStack->getCurrentPane(); @@ -4614,68 +2963,6 @@ } void -MainWindow::playbackFrameChanged(unsigned long frame) -{ - if (!(m_playSource && m_playSource->isPlaying()) || !getMainModel()) return; - - RealTime now = RealTime::frame2RealTime - (frame, getMainModel()->getSampleRate()); - - if (now.sec == m_lastPlayStatusSec) return; - - RealTime then = RealTime::frame2RealTime - (m_playSource->getPlayEndFrame(), getMainModel()->getSampleRate()); - - QString nowStr; - QString thenStr; - QString remainingStr; - - if (then.sec > 10) { - nowStr = now.toSecText().c_str(); - thenStr = then.toSecText().c_str(); - remainingStr = (then - now).toSecText().c_str(); - m_lastPlayStatusSec = now.sec; - } else { - nowStr = now.toText(true).c_str(); - thenStr = then.toText(true).c_str(); - remainingStr = (then - now).toText(true).c_str(); - } - - m_myStatusMessage = tr("Playing: %1 of %2 (%3 remaining)") - .arg(nowStr).arg(thenStr).arg(remainingStr); - - statusBar()->showMessage(m_myStatusMessage); -} - -void -MainWindow::globalCentreFrameChanged(unsigned long ) -{ - if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return; - Pane *p = 0; - if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return; - if (!p->getFollowGlobalPan()) return; - updateVisibleRangeDisplay(p); -} - -void -MainWindow::viewCentreFrameChanged(View *v, unsigned long ) -{ - if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return; - Pane *p = 0; - if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return; - if (v == p) updateVisibleRangeDisplay(p); -} - -void -MainWindow::viewZoomLevelChanged(View *v, unsigned long , bool ) -{ - if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return; - Pane *p = 0; - if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return; - if (v == p) updateVisibleRangeDisplay(p); -} - -void MainWindow::updateVisibleRangeDisplay(Pane *p) const { if (!getMainModel() || !p) { @@ -4756,68 +3043,23 @@ } void -MainWindow::layerAdded(Layer *) +MainWindow::layerRemoved(Layer *layer) { -// std::cerr << "MainWindow::layerAdded(" << layer << ")" << std::endl; -// setupExistingLayersMenu(); - updateMenuStates(); -} - -void -MainWindow::layerRemoved(Layer *) -{ -// std::cerr << "MainWindow::layerRemoved(" << layer << ")" << std::endl; setupExistingLayersMenus(); - updateMenuStates(); -} - -void -MainWindow::layerAboutToBeDeleted(Layer *layer) -{ -// std::cerr << "MainWindow::layerAboutToBeDeleted(" << layer << ")" << std::endl; - if (layer == m_timeRulerLayer) { -// std::cerr << "(this is the time ruler layer)" << std::endl; - m_timeRulerLayer = 0; - } + MainWindowBase::layerRemoved(layer); } void MainWindow::layerInAView(Layer *layer, bool inAView) { -// std::cerr << "MainWindow::layerInAView(" << layer << "," << inAView << ")" << std::endl; - - // Check whether we need to add or remove model from play source - Model *model = layer->getModel(); - if (model) { - if (inAView) { - m_playSource->addModel(model); - } else { - bool found = false; - for (int i = 0; i < m_paneStack->getPaneCount(); ++i) { - Pane *pane = m_paneStack->getPane(i); - if (!pane) continue; - for (int j = 0; j < pane->getLayerCount(); ++j) { - Layer *pl = pane->getLayer(j); - if (pl && pl->getModel() == model) { - found = true; - break; - } - } - if (found) break; - } - if (!found) m_playSource->removeModel(model); - } - } - setupExistingLayersMenus(); - updateMenuStates(); + MainWindowBase::layerInAView(layer, inAView); } void MainWindow::modelAdded(Model *model) { -// std::cerr << "MainWindow::modelAdded(" << model << ")" << std::endl; - m_playSource->addModel(model); + MainWindowBase::modelAdded(model); if (dynamic_cast<DenseTimeValueModel *>(model)) { setupPaneAndLayerMenus(); } @@ -4826,22 +3068,54 @@ void MainWindow::mainModelChanged(WaveFileModel *model) { -// std::cerr << "MainWindow::mainModelChanged(" << model << ")" << std::endl; - updateDescriptionLabel(); m_panLayer->setModel(model); - if (model) m_viewManager->setMainModelSampleRate(model->getSampleRate()); - if (model && !m_playTarget && m_audioOutput) createPlayTarget(); + + MainWindowBase::mainModelChanged(model); + + if (m_playTarget) { + connect(m_fader, SIGNAL(valueChanged(float)), + m_playTarget, SLOT(setOutputGain(float))); + } } void -MainWindow::modelAboutToBeDeleted(Model *model) +MainWindow::setInstantsNumbering() { -// std::cerr << "MainWindow::modelAboutToBeDeleted(" << model << ")" << std::endl; - if (model == m_viewManager->getPlaybackModel()) { - m_viewManager->setPlaybackModel(0); - } - m_playSource->removeModel(model); - FFTDataServer::modelAboutToBeDeleted(model); + QAction *a = dynamic_cast<QAction *>(sender()); + if (!a) return; + + int type = m_numberingActions[a]; + + if (m_labeller) m_labeller->setType(Labeller::ValueType(type)); + + QSettings settings; + settings.beginGroup("MainWindow"); + settings.setValue("labellertype", type); + settings.endGroup(); +} + +void +MainWindow::setInstantsCounterCycle() +{ + QAction *a = dynamic_cast<QAction *>(sender()); + if (!a) return; + + int cycle = a->text().toInt(); + if (cycle == 0) return; + + if (m_labeller) m_labeller->setCounterCycleSize(cycle); + + QSettings settings; + settings.beginGroup("MainWindow"); + settings.setValue("labellercycle", cycle); + settings.endGroup(); +} + +void +MainWindow::resetInstantsCounters() +{ + LabelCounterInputDialog dialog(m_labeller, this); + dialog.exec(); } void @@ -4875,19 +3149,6 @@ } void -MainWindow::propertyStacksResized() -{ -/* - std::cerr << "MainWindow::propertyStacksResized" << std::endl; - Pane *pane = m_paneStack->getCurrentPane(); - if (pane && m_overview) { - std::cerr << "Fixed width: " << pane->width() << std::endl; - m_overview->setFixedWidth(pane->width()); - } -*/ -} - -void MainWindow::showLayerTree() { if (!m_layerTreeView.isNull()) { @@ -4907,23 +3168,6 @@ } void -MainWindow::pollOSC() -{ - if (!m_oscQueue || m_oscQueue->isEmpty()) return; - std::cerr << "MainWindow::pollOSC: have " << m_oscQueue->getMessagesAvailable() << " messages" << std::endl; - - if (m_openingAudioFile) return; - - OSCMessage message = m_oscQueue->readMessage(); - - if (message.getTarget() != 0) { - return; //!!! for now -- this class is target 0, others not handled yet - } - - handleOSCMessage(message); -} - -void MainWindow::handleOSCMessage(const OSCMessage &message) { std::cerr << "MainWindow::handleOSCMessage: thread id = " @@ -5457,24 +3701,6 @@ } void -MainWindow::inProgressSelectionChanged() -{ - Pane *currentPane = 0; - if (m_paneStack) currentPane = m_paneStack->getCurrentPane(); - if (currentPane) updateVisibleRangeDisplay(currentPane); -} - -void -MainWindow::contextHelpChanged(const QString &s) -{ - if (s == "" && m_myStatusMessage != "") { - statusBar()->showMessage(m_myStatusMessage); - return; - } - statusBar()->showMessage(s); -} - -void MainWindow::website() { openHelpUrl(tr("http://www.sonicvisualiser.org/")); @@ -5487,46 +3713,6 @@ } void -MainWindow::openHelpUrl(QString url) -{ - // This method mostly lifted from Qt Assistant source code - - QProcess *process = new QProcess(this); - connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater())); - - QStringList args; - -#ifdef Q_OS_MAC - args.append(url); - process->start("open", args); -#else -#ifdef Q_OS_WIN32 - - QString pf(getenv("ProgramFiles")); - QString command = pf + QString("\\Internet Explorer\\IEXPLORE.EXE"); - - args.append(url); - process->start(command, args); - -#else -#ifdef Q_WS_X11 - if (!qgetenv("KDE_FULL_SESSION").isEmpty()) { - args.append("exec"); - args.append(url); - process->start("kfmclient", args); - } else if (!qgetenv("BROWSER").isEmpty()) { - args.append(url); - process->start(qgetenv("BROWSER"), args); - } else { - args.append(url); - process->start("firefox", args); - } -#endif -#endif -#endif -} - -void MainWindow::about() { bool debug = false;
--- a/main/MainWindow.h Mon Oct 22 09:45:35 2007 +0000 +++ b/main/MainWindow.h Mon Oct 22 14:24:31 2007 +0000 @@ -4,7 +4,7 @@ Sonic Visualiser An audio file viewer and annotation editor. Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam and QMUL. + This file copyright 2006-2007 Chris Cannam and QMUL. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -19,9 +19,10 @@ #include <QFrame> #include <QString> #include <QUrl> -#include <QMainWindow> #include <QPointer> +#include "MainWindowBase.h" + #include "base/Command.h" #include "view/ViewManager.h" #include "base/PropertyContainer.h" @@ -58,7 +59,7 @@ class Labeller; -class MainWindow : public QMainWindow +class MainWindow : public MainWindowBase { Q_OBJECT @@ -66,228 +67,102 @@ MainWindow(bool withAudioOutput = true, bool withOSCSupport = true); virtual ~MainWindow(); - - enum AudioFileOpenMode { - ReplaceMainModel, - CreateAdditionalModel, - ReplaceCurrentPane, - AskUser - }; - - enum FileOpenStatus { - FileOpenSucceeded, - FileOpenFailed, - FileOpenCancelled, - FileOpenWrongMode // attempted to open layer when no main model present - }; - - FileOpenStatus open(QString fileOrUrl, AudioFileOpenMode = AskUser); - FileOpenStatus open(FileSource source, AudioFileOpenMode = AskUser); - - FileOpenStatus openAudio(FileSource source, AudioFileOpenMode = AskUser); - FileOpenStatus openPlaylist(FileSource source, AudioFileOpenMode = AskUser); - FileOpenStatus openLayer(FileSource source); - FileOpenStatus openImage(FileSource source); - FileOpenStatus openSession(FileSource source); - - bool saveSessionFile(QString path); - bool commitData(bool mayAskUser); // on session shutdown signals: - // Used to toggle the availability of menu actions - void canAddPane(bool); - void canDeleteCurrentPane(bool); - void canAddLayer(bool); - void canImportMoreAudio(bool); - void canImportLayer(bool); - void canExportAudio(bool); - void canExportLayer(bool); - void canExportImage(bool); - void canRenameLayer(bool); - void canEditLayer(bool); - void canMeasureLayer(bool); - void canSelect(bool); - void canClearSelection(bool); - void canEditSelection(bool); - void canDeleteSelection(bool); - void canPaste(bool); - void canInsertInstant(bool); - void canInsertInstantsAtBoundaries(bool); - void canRenumberInstants(bool); - void canDeleteCurrentLayer(bool); - void canZoom(bool); - void canScroll(bool); - void canPlay(bool); - void canFfwd(bool); - void canRewind(bool); - void canPlaySelection(bool); - void canSpeedUpPlayback(bool); - void canSlowDownPlayback(bool); - void canChangePlaybackSpeed(bool); - void canSave(bool); public slots: - void preferenceChanged(PropertyContainer::PropertyName); + virtual void preferenceChanged(PropertyContainer::PropertyName); + virtual bool commitData(bool mayAskUser); protected slots: - void openSession(); - void importAudio(); - void importMoreAudio(); - void openSomething(); - void openLocation(); - void openRecentFile(); - void exportAudio(); - void importLayer(); - void exportLayer(); - void exportImage(); - void saveSession(); - void saveSessionAs(); - void newSession(); - void closeSession(); - void preferences(); + virtual void openSession(); + virtual void importAudio(); + virtual void importMoreAudio(); + virtual void openSomething(); + virtual void openLocation(); + virtual void openRecentFile(); + virtual void exportAudio(); + virtual void importLayer(); + virtual void exportLayer(); + virtual void exportImage(); + virtual void saveSession(); + virtual void saveSessionAs(); + virtual void newSession(); + virtual void closeSession(); + virtual void preferences(); - void zoomIn(); - void zoomOut(); - void zoomToFit(); - void zoomDefault(); - void scrollLeft(); - void scrollRight(); - void jumpLeft(); - void jumpRight(); + virtual void sampleRateMismatch(size_t, size_t, bool); + virtual void audioOverloadPluginDisabled(); - void showNoOverlays(); - void showMinimalOverlays(); - void showStandardOverlays(); - void showAllOverlays(); + virtual void toolNavigateSelected(); + virtual void toolSelectSelected(); + virtual void toolEditSelected(); + virtual void toolDrawSelected(); + virtual void toolMeasureSelected(); - void toggleZoomWheels(); - void togglePropertyBoxes(); - void toggleStatusBar(); + virtual void documentModified(); + virtual void documentRestored(); - void play(); - void ffwd(); - void ffwdEnd(); - void rewind(); - void rewindStart(); - void stop(); + virtual void updateMenuStates(); + virtual void updateDescriptionLabel(); - void addPane(); - void addLayer(); - void deleteCurrentPane(); - void renameCurrentLayer(); - void deleteCurrentLayer(); + virtual void setInstantsNumbering(); + virtual void setInstantsCounterCycle(); + virtual void resetInstantsCounters(); - void playLoopToggled(); - void playSelectionToggled(); - void playSoloToggled(); - void playSpeedChanged(int); - void playSharpenToggled(); - void playMonoToggled(); - void speedUpPlayback(); - void slowDownPlayback(); - void restoreNormalPlayback(); - void sampleRateMismatch(size_t, size_t, bool); - void audioOverloadPluginDisabled(); + virtual void modelGenerationFailed(QString); + virtual void modelRegenerationFailed(QString, QString); - void playbackFrameChanged(unsigned long); - void globalCentreFrameChanged(unsigned long); - void viewCentreFrameChanged(View *, unsigned long); - void viewZoomLevelChanged(View *, unsigned long, bool); - void outputLevelsChanged(float, float); + virtual void rightButtonMenuRequested(Pane *, QPoint point); - void currentPaneChanged(Pane *); - void currentLayerChanged(Pane *, Layer *); + virtual void addPane(); + virtual void addLayer(); + virtual void renameCurrentLayer(); - void toolNavigateSelected(); - void toolSelectSelected(); - void toolEditSelected(); - void toolDrawSelected(); - void toolMeasureSelected(); + virtual void paneAdded(Pane *); + virtual void paneHidden(Pane *); + virtual void paneAboutToBeDeleted(Pane *); + virtual void paneDropAccepted(Pane *, QStringList); + virtual void paneDropAccepted(Pane *, QString); - void selectAll(); - void selectToStart(); - void selectToEnd(); - void selectVisible(); - void clearSelection(); - void cut(); - void copy(); - void paste(); - void deleteSelected(); - void insertInstant(); - void insertInstantAt(size_t); - void insertInstantsAtBoundaries(); - void setInstantsNumbering(); - void setInstantsCounterCycle(); - void resetInstantsCounters(); - void renumberInstants(); + virtual void setupRecentFilesMenu(); + virtual void setupRecentTransformsMenu(); - void documentModified(); - void documentRestored(); + virtual void playSpeedChanged(int); + virtual void playSharpenToggled(); + virtual void playMonoToggled(); - void updateMenuStates(); - void updateDescriptionLabel(); + virtual void speedUpPlayback(); + virtual void slowDownPlayback(); + virtual void restoreNormalPlayback(); - void layerAdded(Layer *); - void layerRemoved(Layer *); - void layerAboutToBeDeleted(Layer *); - void layerInAView(Layer *, bool); + virtual void outputLevelsChanged(float, float); - void mainModelChanged(WaveFileModel *); - void modelAdded(Model *); - void modelAboutToBeDeleted(Model *); + virtual void layerRemoved(Layer *); + virtual void layerInAView(Layer *, bool); - void modelGenerationFailed(QString); - void modelRegenerationFailed(QString, QString); + virtual void mainModelChanged(WaveFileModel *); + virtual void modelAdded(Model *); - void rightButtonMenuRequested(Pane *, QPoint point); + virtual void showLayerTree(); - void propertyStacksResized(); + virtual void mouseEnteredWidget(); + virtual void mouseLeftWidget(); - void paneDropAccepted(Pane *, QStringList); - void paneDropAccepted(Pane *, QString); + virtual void handleOSCMessage(const OSCMessage &); - void setupRecentFilesMenu(); - void setupRecentTransformsMenu(); - - void showLayerTree(); - - void pollOSC(); - void handleOSCMessage(const OSCMessage &); - - void mouseEnteredWidget(); - void mouseLeftWidget(); - void contextHelpChanged(const QString &); - void inProgressSelectionChanged(); - - void website(); - void help(); - void about(); - void keyReference(); + virtual void website(); + virtual void help(); + virtual void about(); + virtual void keyReference(); protected: - QString m_sessionFile; - QString m_audioFile; - Document *m_document; - - QLabel *m_descriptionLabel; - PaneStack *m_paneStack; - ViewManager *m_viewManager; Overview *m_overview; Fader *m_fader; AudioDial *m_playSpeed; QPushButton *m_playSharpen; QPushButton *m_playMono; WaveformLayer *m_panLayer; - Layer *m_timeRulerLayer; - - bool m_audioOutput; - AudioCallbackPlaySource *m_playSource; - AudioCallbackPlayTarget *m_playTarget; - - OSCQueue *m_oscQueue; - - RecentFiles m_recentFiles; - RecentFiles m_recentTransforms; bool m_mainMenusCreated; QMenu *m_paneMenu; @@ -307,26 +182,11 @@ QAction *m_ffwdAction; QAction *m_rwdAction; - bool m_documentModified; - bool m_openingAudioFile; - bool m_abandoning; - - Labeller *m_labeller; - - int m_lastPlayStatusSec; - mutable QString m_myStatusMessage; - QPointer<PreferencesDialog> m_preferencesDialog; QPointer<QTreeView> m_layerTreeView; - bool m_initialDarkBackground; - KeyReference *m_keyReference; - WaveFileModel *getMainModel(); - const WaveFileModel *getMainModel() const; - void createDocument(); - struct PaneConfiguration { PaneConfiguration(LayerFactory::LayerType _layer = LayerFactory::TimeRuler, @@ -360,87 +220,22 @@ typedef std::map<QAction *, int> NumberingActionMap; NumberingActionMap m_numberingActions; - void setupMenus(); - void setupFileMenu(); - void setupEditMenu(); - void setupViewMenu(); - void setupPaneAndLayerMenus(); - void setupTransformsMenu(); - void setupHelpMenu(); - void setupExistingLayersMenus(); - void setupToolbars(); + virtual void setupMenus(); + virtual void setupFileMenu(); + virtual void setupEditMenu(); + virtual void setupViewMenu(); + virtual void setupPaneAndLayerMenus(); + virtual void setupTransformsMenu(); + virtual void setupHelpMenu(); + virtual void setupExistingLayersMenus(); + virtual void setupToolbars(); - Pane *addPaneToStack(); - - void addPane(const PaneConfiguration &configuration, QString text); - - Layer *getSnapLayer() const; - - class PaneCallback : public SVFileReaderPaneCallback - { - public: - PaneCallback(MainWindow *mw) : m_mw(mw) { } - virtual Pane *addPane() { return m_mw->addPaneToStack(); } - virtual void setWindowSize(int width, int height) { - m_mw->resize(width, height); - } - virtual void addSelection(int start, int end) { - m_mw->m_viewManager->addSelection(Selection(start, end)); - } - protected: - MainWindow *m_mw; - }; - - class AddPaneCommand : public Command - { - public: - AddPaneCommand(MainWindow *mw); - virtual ~AddPaneCommand(); - - virtual void execute(); - virtual void unexecute(); - virtual QString getName() const; - - Pane *getPane() { return m_pane; } - - protected: - MainWindow *m_mw; - Pane *m_pane; // Main window owns this, but I determine its lifespan - Pane *m_prevCurrentPane; // I don't own this - bool m_added; - }; - - class RemovePaneCommand : public Command - { - public: - RemovePaneCommand(MainWindow *mw, Pane *pane); - virtual ~RemovePaneCommand(); - - virtual void execute(); - virtual void unexecute(); - virtual QString getName() const; - - protected: - MainWindow *m_mw; - Pane *m_pane; // Main window owns this, but I determine its lifespan - Pane *m_prevCurrentPane; // I don't own this - bool m_added; - }; + virtual void addPane(const PaneConfiguration &configuration, QString text); virtual void closeEvent(QCloseEvent *e); - bool checkSaveModified(); - - QString getOpenFileName(FileFinder::FileType type); - QString getSaveFileName(FileFinder::FileType type); - void registerLastOpenedFilePath(FileFinder::FileType type, QString path); - - void createPlayTarget(); - - void openHelpUrl(QString url); - - void updateVisibleRangeDisplay(Pane *p) const; - - void toXml(QTextStream &stream); + virtual bool checkSaveModified(); + + virtual void updateVisibleRangeDisplay(Pane *p) const; };
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main/MainWindowBase.cpp Mon Oct 22 14:24:31 2007 +0000 @@ -0,0 +1,2006 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2006-2007 Chris Cannam and QMUL. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#include "MainWindowBase.h" +#include "document/Document.h" + + +#include "view/Pane.h" +#include "view/PaneStack.h" +#include "data/model/WaveFileModel.h" +#include "data/model/SparseOneDimensionalModel.h" +#include "data/model/NoteModel.h" +#include "data/model/Labeller.h" +#include "view/ViewManager.h" + +#include "layer/WaveformLayer.h" +#include "layer/TimeRulerLayer.h" +#include "layer/TimeInstantLayer.h" +#include "layer/TimeValueLayer.h" +#include "layer/Colour3DPlotLayer.h" +#include "layer/SliceLayer.h" +#include "layer/SliceableLayer.h" +#include "layer/ImageLayer.h" + +#include "widgets/ListInputDialog.h" + +#include "audioio/AudioCallbackPlaySource.h" +#include "audioio/AudioCallbackPlayTarget.h" +#include "audioio/AudioTargetFactory.h" +#include "audioio/PlaySpeedRangeMapper.h" +#include "data/fileio/DataFileReaderFactory.h" +#include "data/fileio/PlaylistFileReader.h" +#include "data/fileio/WavFileWriter.h" +#include "data/fileio/CSVFileWriter.h" +#include "data/fileio/MIDIFileWriter.h" +#include "data/fileio/BZipFileDevice.h" +#include "data/fileio/FileSource.h" + +#include "data/fft/FFTDataServer.h" + +#include "base/RecentFiles.h" + +#include "base/PlayParameterRepository.h" +#include "base/XmlExportable.h" +#include "base/CommandHistory.h" +#include "base/Profiler.h" +#include "base/Preferences.h" + +#include "osc/OSCQueue.h" + +#include <QApplication> +#include <QMessageBox> +#include <QGridLayout> +#include <QLabel> +#include <QAction> +#include <QMenuBar> +#include <QToolBar> +#include <QInputDialog> +#include <QStatusBar> +#include <QTreeView> +#include <QFile> +#include <QFileInfo> +#include <QDir> +#include <QTextStream> +#include <QProcess> +#include <QShortcut> +#include <QSettings> +#include <QDateTime> +#include <QProcess> +#include <QCheckBox> +#include <QRegExp> +#include <QScrollArea> + +#include <iostream> +#include <cstdio> +#include <errno.h> + +using std::cerr; +using std::endl; + +using std::vector; +using std::map; +using std::set; + + +MainWindowBase::MainWindowBase(bool withAudioOutput, bool withOSCSupport) : + m_document(0), + m_paneStack(0), + m_viewManager(0), + m_timeRulerLayer(0), + m_audioOutput(withAudioOutput), + m_playSource(0), + m_playTarget(0), + m_oscQueue(withOSCSupport ? new OSCQueue() : 0), + m_recentFiles("RecentFiles", 20), + m_recentTransforms("RecentTransforms", 20), + m_documentModified(false), + m_openingAudioFile(false), + m_abandoning(false), + m_labeller(0) +{ + connect(CommandHistory::getInstance(), SIGNAL(commandExecuted()), + this, SLOT(documentModified())); + connect(CommandHistory::getInstance(), SIGNAL(documentRestored()), + this, SLOT(documentRestored())); + + m_viewManager = new ViewManager(); + connect(m_viewManager, SIGNAL(selectionChanged()), + this, SLOT(updateMenuStates())); + connect(m_viewManager, SIGNAL(inProgressSelectionChanged()), + this, SLOT(inProgressSelectionChanged())); + + Preferences::BackgroundMode mode = + Preferences::getInstance()->getBackgroundMode(); + m_initialDarkBackground = m_viewManager->getGlobalDarkBackground(); + if (mode != Preferences::BackgroundFromTheme) { + m_viewManager->setGlobalDarkBackground + (mode == Preferences::DarkBackground); + } + + m_paneStack = new PaneStack(0, m_viewManager); + connect(m_paneStack, SIGNAL(currentPaneChanged(Pane *)), + this, SLOT(currentPaneChanged(Pane *))); + connect(m_paneStack, SIGNAL(currentLayerChanged(Pane *, Layer *)), + this, SLOT(currentLayerChanged(Pane *, Layer *))); + connect(m_paneStack, SIGNAL(rightButtonMenuRequested(Pane *, QPoint)), + this, SLOT(rightButtonMenuRequested(Pane *, QPoint))); + connect(m_paneStack, SIGNAL(contextHelpChanged(const QString &)), + this, SLOT(contextHelpChanged(const QString &))); + connect(m_paneStack, SIGNAL(paneAdded(Pane *)), + this, SLOT(paneAdded(Pane *))); + connect(m_paneStack, SIGNAL(paneHidden(Pane *)), + this, SLOT(paneHidden(Pane *))); + connect(m_paneStack, SIGNAL(paneAboutToBeDeleted(Pane *)), + this, SLOT(paneAboutToBeDeleted(Pane *))); + connect(m_paneStack, SIGNAL(dropAccepted(Pane *, QStringList)), + this, SLOT(paneDropAccepted(Pane *, QStringList))); + connect(m_paneStack, SIGNAL(dropAccepted(Pane *, QString)), + this, SLOT(paneDropAccepted(Pane *, QString))); + + m_playSource = new AudioCallbackPlaySource(m_viewManager); + + connect(m_playSource, SIGNAL(sampleRateMismatch(size_t, size_t, bool)), + this, SLOT(sampleRateMismatch(size_t, size_t, bool))); + connect(m_playSource, SIGNAL(audioOverloadPluginDisabled()), + this, SLOT(audioOverloadPluginDisabled())); + + connect(m_viewManager, SIGNAL(outputLevelsChanged(float, float)), + this, SLOT(outputLevelsChanged(float, float))); + + connect(m_viewManager, SIGNAL(playbackFrameChanged(unsigned long)), + this, SLOT(playbackFrameChanged(unsigned long))); + + connect(m_viewManager, SIGNAL(globalCentreFrameChanged(unsigned long)), + this, SLOT(globalCentreFrameChanged(unsigned long))); + + connect(m_viewManager, SIGNAL(viewCentreFrameChanged(View *, unsigned long)), + this, SLOT(viewCentreFrameChanged(View *, unsigned long))); + + connect(m_viewManager, SIGNAL(viewZoomLevelChanged(View *, unsigned long, bool)), + this, SLOT(viewZoomLevelChanged(View *, unsigned long, bool))); + + connect(Preferences::getInstance(), + SIGNAL(propertyChanged(PropertyContainer::PropertyName)), + this, + SLOT(preferenceChanged(PropertyContainer::PropertyName))); + + if (m_oscQueue && m_oscQueue->isOK()) { + connect(m_oscQueue, SIGNAL(messagesAvailable()), this, SLOT(pollOSC())); + QTimer *oscTimer = new QTimer(this); + connect(oscTimer, SIGNAL(timeout()), this, SLOT(pollOSC())); + oscTimer->start(1000); + } + + Labeller::ValueType labellerType = Labeller::ValueFromTwoLevelCounter; + QSettings settings; + settings.beginGroup("MainWindow"); + labellerType = (Labeller::ValueType) + settings.value("labellertype", (int)labellerType).toInt(); + int cycle = settings.value("labellercycle", 4).toInt(); + settings.endGroup(); + + m_labeller = new Labeller(labellerType); + m_labeller->setCounterCycleSize(cycle); +} + +MainWindowBase::~MainWindowBase() +{ + delete m_playTarget; + delete m_playSource; + delete m_viewManager; + delete m_oscQueue; + Profiles::getInstance()->dump(); +} + +QString +MainWindowBase::getOpenFileName(FileFinder::FileType type) +{ + FileFinder *ff = FileFinder::getInstance(); + switch (type) { + case FileFinder::SessionFile: + return ff->getOpenFileName(type, m_sessionFile); + case FileFinder::AudioFile: + return ff->getOpenFileName(type, m_audioFile); + case FileFinder::LayerFile: + return ff->getOpenFileName(type, m_sessionFile); + case FileFinder::LayerFileNoMidi: + return ff->getOpenFileName(type, m_sessionFile); + case FileFinder::SessionOrAudioFile: + return ff->getOpenFileName(type, m_sessionFile); + case FileFinder::ImageFile: + return ff->getOpenFileName(type, m_sessionFile); + case FileFinder::AnyFile: + if (getMainModel() != 0 && + m_paneStack != 0 && + m_paneStack->getCurrentPane() != 0) { // can import a layer + return ff->getOpenFileName(FileFinder::AnyFile, m_sessionFile); + } else { + return ff->getOpenFileName(FileFinder::SessionOrAudioFile, + m_sessionFile); + } + } + return ""; +} + +QString +MainWindowBase::getSaveFileName(FileFinder::FileType type) +{ + FileFinder *ff = FileFinder::getInstance(); + switch (type) { + case FileFinder::SessionFile: + return ff->getSaveFileName(type, m_sessionFile); + case FileFinder::AudioFile: + return ff->getSaveFileName(type, m_audioFile); + case FileFinder::LayerFile: + return ff->getSaveFileName(type, m_sessionFile); + case FileFinder::LayerFileNoMidi: + return ff->getSaveFileName(type, m_sessionFile); + case FileFinder::SessionOrAudioFile: + return ff->getSaveFileName(type, m_sessionFile); + case FileFinder::ImageFile: + return ff->getSaveFileName(type, m_sessionFile); + case FileFinder::AnyFile: + return ff->getSaveFileName(type, m_sessionFile); + } + return ""; +} + +void +MainWindowBase::registerLastOpenedFilePath(FileFinder::FileType type, QString path) +{ + FileFinder *ff = FileFinder::getInstance(); + ff->registerLastOpenedFilePath(type, path); +} + +void +MainWindowBase::updateMenuStates() +{ + Pane *currentPane = 0; + Layer *currentLayer = 0; + + if (m_paneStack) currentPane = m_paneStack->getCurrentPane(); + if (currentPane) currentLayer = currentPane->getSelectedLayer(); + + bool haveCurrentPane = + (currentPane != 0); + bool haveCurrentLayer = + (haveCurrentPane && + (currentLayer != 0)); + bool haveMainModel = + (getMainModel() != 0); + bool havePlayTarget = + (m_playTarget != 0); + bool haveSelection = + (m_viewManager && + !m_viewManager->getSelections().empty()); + bool haveCurrentEditableLayer = + (haveCurrentLayer && + currentLayer->isLayerEditable()); + bool haveCurrentTimeInstantsLayer = + (haveCurrentLayer && + dynamic_cast<TimeInstantLayer *>(currentLayer)); + bool haveCurrentColour3DPlot = + (haveCurrentLayer && + dynamic_cast<Colour3DPlotLayer *>(currentLayer)); + bool haveClipboardContents = + (m_viewManager && + !m_viewManager->getClipboard().empty()); + + emit canAddPane(haveMainModel); + emit canDeleteCurrentPane(haveCurrentPane); + emit canZoom(haveMainModel && haveCurrentPane); + emit canScroll(haveMainModel && haveCurrentPane); + emit canAddLayer(haveMainModel && haveCurrentPane); + emit canImportMoreAudio(haveMainModel); + emit canImportLayer(haveMainModel && haveCurrentPane); + emit canExportAudio(haveMainModel); + emit canExportLayer(haveMainModel && + (haveCurrentEditableLayer || haveCurrentColour3DPlot)); + emit canExportImage(haveMainModel && haveCurrentPane); + emit canDeleteCurrentLayer(haveCurrentLayer); + emit canRenameLayer(haveCurrentLayer); + emit canEditLayer(haveCurrentEditableLayer); + emit canMeasureLayer(haveCurrentLayer); + emit canSelect(haveMainModel && haveCurrentPane); + emit canPlay(havePlayTarget); + emit canFfwd(true); + emit canRewind(true); + emit canPaste(haveCurrentEditableLayer && haveClipboardContents); + emit canInsertInstant(haveCurrentPane); + emit canInsertInstantsAtBoundaries(haveCurrentPane && haveSelection); + emit canRenumberInstants(haveCurrentTimeInstantsLayer && haveSelection); + emit canPlaySelection(haveMainModel && havePlayTarget && haveSelection); + emit canClearSelection(haveSelection); + emit canEditSelection(haveSelection && haveCurrentEditableLayer); + emit canSave(m_sessionFile != "" && m_documentModified); +} + +void +MainWindowBase::documentModified() +{ +// std::cerr << "MainWindowBase::documentModified" << std::endl; + + if (!m_documentModified) { + //!!! this in subclass implementation? + setWindowTitle(tr("%1 (modified)").arg(windowTitle())); + } + + m_documentModified = true; + updateMenuStates(); +} + +void +MainWindowBase::documentRestored() +{ +// std::cerr << "MainWindowBase::documentRestored" << std::endl; + + if (m_documentModified) { + //!!! this in subclass implementation? + QString wt(windowTitle()); + wt.replace(tr(" (modified)"), ""); + setWindowTitle(wt); + } + + m_documentModified = false; + updateMenuStates(); +} + +void +MainWindowBase::playLoopToggled() +{ + QAction *action = dynamic_cast<QAction *>(sender()); + + if (action) { + m_viewManager->setPlayLoopMode(action->isChecked()); + } else { + m_viewManager->setPlayLoopMode(!m_viewManager->getPlayLoopMode()); + } +} + +void +MainWindowBase::playSelectionToggled() +{ + QAction *action = dynamic_cast<QAction *>(sender()); + + if (action) { + m_viewManager->setPlaySelectionMode(action->isChecked()); + } else { + m_viewManager->setPlaySelectionMode(!m_viewManager->getPlaySelectionMode()); + } +} + +void +MainWindowBase::playSoloToggled() +{ + QAction *action = dynamic_cast<QAction *>(sender()); + + if (action) { + m_viewManager->setPlaySoloMode(action->isChecked()); + } else { + m_viewManager->setPlaySoloMode(!m_viewManager->getPlaySoloMode()); + } + + if (m_viewManager->getPlaySoloMode()) { + currentPaneChanged(m_paneStack->getCurrentPane()); + } else { + m_viewManager->setPlaybackModel(0); + if (m_playSource) { + m_playSource->clearSoloModelSet(); + } + } +} + +void +MainWindowBase::currentPaneChanged(Pane *p) +{ + updateMenuStates(); + updateVisibleRangeDisplay(p); + + if (!p) return; + + if (!(m_viewManager && + m_playSource && + m_viewManager->getPlaySoloMode())) { + if (m_viewManager) m_viewManager->setPlaybackModel(0); + return; + } + + Model *prevPlaybackModel = m_viewManager->getPlaybackModel(); + + View::ModelSet soloModels = p->getModels(); + + for (View::ModelSet::iterator mi = soloModels.begin(); + mi != soloModels.end(); ++mi) { + if (dynamic_cast<RangeSummarisableTimeValueModel *>(*mi)) { + m_viewManager->setPlaybackModel(*mi); + } + } + + RangeSummarisableTimeValueModel *a = + dynamic_cast<RangeSummarisableTimeValueModel *>(prevPlaybackModel); + RangeSummarisableTimeValueModel *b = + dynamic_cast<RangeSummarisableTimeValueModel *>(m_viewManager-> + getPlaybackModel()); + + m_playSource->setSoloModelSet(soloModels); + + if (a && b && (a != b)) { + int frame = m_playSource->getCurrentPlayingFrame(); + //!!! I don't really believe that these functions are the right way around + int rframe = a->alignFromReference(frame); + int bframe = b->alignToReference(rframe); + if (m_playSource->isPlaying()) m_playSource->play(bframe); + } +} + +void +MainWindowBase::currentLayerChanged(Pane *p, Layer *) +{ + updateMenuStates(); + updateVisibleRangeDisplay(p); +} + +void +MainWindowBase::selectAll() +{ + if (!getMainModel()) return; + m_viewManager->setSelection(Selection(getMainModel()->getStartFrame(), + getMainModel()->getEndFrame())); +} + +void +MainWindowBase::selectToStart() +{ + if (!getMainModel()) return; + m_viewManager->setSelection(Selection(getMainModel()->getStartFrame(), + m_viewManager->getGlobalCentreFrame())); +} + +void +MainWindowBase::selectToEnd() +{ + if (!getMainModel()) return; + m_viewManager->setSelection(Selection(m_viewManager->getGlobalCentreFrame(), + getMainModel()->getEndFrame())); +} + +void +MainWindowBase::selectVisible() +{ + Model *model = getMainModel(); + if (!model) return; + + Pane *currentPane = m_paneStack->getCurrentPane(); + if (!currentPane) return; + + size_t startFrame, endFrame; + + if (currentPane->getStartFrame() < 0) startFrame = 0; + else startFrame = currentPane->getStartFrame(); + + if (currentPane->getEndFrame() > model->getEndFrame()) endFrame = model->getEndFrame(); + else endFrame = currentPane->getEndFrame(); + + m_viewManager->setSelection(Selection(startFrame, endFrame)); +} + +void +MainWindowBase::clearSelection() +{ + m_viewManager->clearSelections(); +} + +void +MainWindowBase::cut() +{ + Pane *currentPane = m_paneStack->getCurrentPane(); + if (!currentPane) return; + + Layer *layer = currentPane->getSelectedLayer(); + if (!layer) return; + + Clipboard &clipboard = m_viewManager->getClipboard(); + clipboard.clear(); + + MultiSelection::SelectionList selections = m_viewManager->getSelections(); + + CommandHistory::getInstance()->startCompoundOperation(tr("Cut"), true); + + for (MultiSelection::SelectionList::iterator i = selections.begin(); + i != selections.end(); ++i) { + layer->copy(*i, clipboard); + layer->deleteSelection(*i); + } + + CommandHistory::getInstance()->endCompoundOperation(); +} + +void +MainWindowBase::copy() +{ + Pane *currentPane = m_paneStack->getCurrentPane(); + if (!currentPane) return; + + Layer *layer = currentPane->getSelectedLayer(); + if (!layer) return; + + Clipboard &clipboard = m_viewManager->getClipboard(); + clipboard.clear(); + + MultiSelection::SelectionList selections = m_viewManager->getSelections(); + + for (MultiSelection::SelectionList::iterator i = selections.begin(); + i != selections.end(); ++i) { + layer->copy(*i, clipboard); + } +} + +void +MainWindowBase::paste() +{ + Pane *currentPane = m_paneStack->getCurrentPane(); + if (!currentPane) return; + + //!!! if we have no current layer, we should create one of the most + // appropriate type + + Layer *layer = currentPane->getSelectedLayer(); + if (!layer) return; + + Clipboard &clipboard = m_viewManager->getClipboard(); + Clipboard::PointList contents = clipboard.getPoints(); +/* + long minFrame = 0; + bool have = false; + for (int i = 0; i < contents.size(); ++i) { + if (!contents[i].haveFrame()) continue; + if (!have || contents[i].getFrame() < minFrame) { + minFrame = contents[i].getFrame(); + have = true; + } + } + + long frameOffset = long(m_viewManager->getGlobalCentreFrame()) - minFrame; + + layer->paste(clipboard, frameOffset); +*/ + layer->paste(clipboard, 0, true); +} + +void +MainWindowBase::deleteSelected() +{ + if (m_paneStack->getCurrentPane() && + m_paneStack->getCurrentPane()->getSelectedLayer()) { + + Layer *layer = m_paneStack->getCurrentPane()->getSelectedLayer(); + + if (m_viewManager && + (m_viewManager->getToolMode() == ViewManager::MeasureMode)) { + + layer->deleteCurrentMeasureRect(); + + } else { + + MultiSelection::SelectionList selections = + m_viewManager->getSelections(); + + for (MultiSelection::SelectionList::iterator i = selections.begin(); + i != selections.end(); ++i) { + layer->deleteSelection(*i); + } + } + } +} + +void +MainWindowBase::insertInstant() +{ + int frame = m_viewManager->getPlaybackFrame(); + insertInstantAt(frame); +} + +void +MainWindowBase::insertInstantsAtBoundaries() +{ + MultiSelection::SelectionList selections = m_viewManager->getSelections(); + for (MultiSelection::SelectionList::iterator i = selections.begin(); + i != selections.end(); ++i) { + size_t start = i->getStartFrame(); + size_t end = i->getEndFrame(); + if (start != end) { + insertInstantAt(i->getStartFrame()); + insertInstantAt(i->getEndFrame()); + } + } +} + +void +MainWindowBase::insertInstantAt(size_t frame) +{ + Pane *pane = m_paneStack->getCurrentPane(); + if (!pane) { + return; + } + + Layer *layer = dynamic_cast<TimeInstantLayer *> + (pane->getSelectedLayer()); + + if (!layer) { + for (int i = pane->getLayerCount(); i > 0; --i) { + layer = dynamic_cast<TimeInstantLayer *>(pane->getLayer(i - 1)); + if (layer) break; + } + + if (!layer) { + CommandHistory::getInstance()->startCompoundOperation + (tr("Add Point"), true); + layer = m_document->createEmptyLayer(LayerFactory::TimeInstants); + if (layer) { + m_document->addLayerToView(pane, layer); + m_paneStack->setCurrentLayer(pane, layer); + } + CommandHistory::getInstance()->endCompoundOperation(); + } + } + + if (layer) { + + Model *model = layer->getModel(); + SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *> + (model); + + if (sodm) { + SparseOneDimensionalModel::Point point(frame, ""); + + SparseOneDimensionalModel::Point prevPoint(0); + bool havePrevPoint = false; + + SparseOneDimensionalModel::EditCommand *command = + new SparseOneDimensionalModel::EditCommand(sodm, tr("Add Point")); + + if (m_labeller->actingOnPrevPoint()) { + + SparseOneDimensionalModel::PointList prevPoints = + sodm->getPreviousPoints(frame); + + if (!prevPoints.empty()) { + prevPoint = *prevPoints.begin(); + havePrevPoint = true; + } + } + + if (m_labeller) { + + m_labeller->setSampleRate(sodm->getSampleRate()); + + if (havePrevPoint) { + command->deletePoint(prevPoint); + } + + m_labeller->label<SparseOneDimensionalModel::Point> + (point, havePrevPoint ? &prevPoint : 0); + + if (havePrevPoint) { + command->addPoint(prevPoint); + } + } + + command->addPoint(point); + + command->setName(tr("Add Point at %1 s") + .arg(RealTime::frame2RealTime + (frame, + sodm->getSampleRate()) + .toText(false).c_str())); + + command->finish(); + } + } +} + +void +MainWindowBase::renumberInstants() +{ + Pane *pane = m_paneStack->getCurrentPane(); + if (!pane) return; + + Layer *layer = dynamic_cast<TimeInstantLayer *>(pane->getSelectedLayer()); + if (!layer) return; + + MultiSelection ms(m_viewManager->getSelection()); + + Model *model = layer->getModel(); + SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *> + (model); + if (!sodm) return; + + if (!m_labeller) return; + + Labeller labeller(*m_labeller); + labeller.setSampleRate(sodm->getSampleRate()); + + // This uses a command + + labeller.labelAll<SparseOneDimensionalModel::Point>(*sodm, &ms); +} + +MainWindowBase::FileOpenStatus +MainWindowBase::open(QString fileOrUrl, AudioFileOpenMode mode) +{ + return open(FileSource(fileOrUrl), mode); +} + +MainWindowBase::FileOpenStatus +MainWindowBase::open(FileSource source, AudioFileOpenMode mode) +{ + FileOpenStatus status; + + if (!source.isAvailable()) return FileOpenFailed; + source.waitForData(); + + bool canImportLayer = (getMainModel() != 0 && + m_paneStack != 0 && + m_paneStack->getCurrentPane() != 0); + + if ((status = openAudio(source, mode)) != FileOpenFailed) { + return status; + } else if ((status = openSession(source)) != FileOpenFailed) { + return status; + } else if ((status = openPlaylist(source, mode)) != FileOpenFailed) { + return status; + } else if (!canImportLayer) { + return FileOpenWrongMode; + } else if ((status = openImage(source)) != FileOpenFailed) { + return status; + } else if ((status = openLayer(source)) != FileOpenFailed) { + return status; + } else { + return FileOpenFailed; + } +} + +MainWindowBase::FileOpenStatus +MainWindowBase::openAudio(FileSource source, AudioFileOpenMode mode) +{ + std::cerr << "MainWindowBase::openAudio(" << source.getLocation().toStdString() << ")" << std::endl; + + if (!source.isAvailable()) return FileOpenFailed; + source.waitForData(); + + m_openingAudioFile = true; + + size_t rate = 0; + + if (Preferences::getInstance()->getResampleOnLoad()) { + rate = m_playSource->getSourceSampleRate(); + } + + WaveFileModel *newModel = new WaveFileModel(source, rate); + + if (!newModel->isOK()) { + delete newModel; + m_openingAudioFile = false; + return FileOpenFailed; + } + + std::cerr << "mode = " << mode << std::endl; + + if (mode == AskUser) { + if (getMainModel()) { + + static bool prevSetAsMain = true; + bool setAsMain = true; + + QStringList items; + items << tr("Replace the existing main waveform") + << tr("Load this file into a new waveform pane"); + + bool ok = false; + QString item = ListInputDialog::getItem + (this, tr("Select target for import"), + tr("You already have an audio waveform loaded.\nWhat would you like to do with the new audio file?"), + items, prevSetAsMain ? 0 : 1, &ok); + + if (!ok || item.isEmpty()) { + delete newModel; + m_openingAudioFile = false; + return FileOpenCancelled; + } + + setAsMain = (item == items[0]); + prevSetAsMain = setAsMain; + + if (setAsMain) mode = ReplaceMainModel; + else mode = CreateAdditionalModel; + + } else { + mode = ReplaceMainModel; + } + } + + if (mode == ReplaceCurrentPane) { + + Pane *pane = m_paneStack->getCurrentPane(); + if (pane) { + if (getMainModel()) { + View::ModelSet models(pane->getModels()); + if (models.find(getMainModel()) != models.end()) { + mode = ReplaceMainModel; + } + } else { + mode = ReplaceMainModel; + } + } else { + mode = CreateAdditionalModel; + } + } + + if (mode == CreateAdditionalModel && !getMainModel()) { + mode = ReplaceMainModel; + } + + if (mode == ReplaceMainModel) { + + Model *prevMain = getMainModel(); + if (prevMain) { + m_playSource->removeModel(prevMain); + PlayParameterRepository::getInstance()->removeModel(prevMain); + } + PlayParameterRepository::getInstance()->addModel(newModel); + + m_document->setMainModel(newModel); + + setupMenus(); + + if (m_sessionFile == "") { + //!!! shouldn't be dealing directly with title from here -- call a method + setWindowTitle(tr("Sonic Visualiser: %1") + .arg(source.getLocation())); + CommandHistory::getInstance()->clear(); + CommandHistory::getInstance()->documentSaved(); + m_documentModified = false; + } else { + setWindowTitle(tr("Sonic Visualiser: %1 [%2]") + .arg(QFileInfo(m_sessionFile).fileName()) + .arg(source.getLocation())); + if (m_documentModified) { + m_documentModified = false; + documentModified(); // so as to restore "(modified)" window title + } + } + + if (!source.isRemote()) m_audioFile = source.getLocalFilename(); + + } else if (mode == CreateAdditionalModel) { + + CommandHistory::getInstance()->startCompoundOperation + (tr("Import \"%1\"").arg(source.getLocation()), true); + + m_document->addImportedModel(newModel); + + AddPaneCommand *command = new AddPaneCommand(this); + CommandHistory::getInstance()->addCommand(command); + + Pane *pane = command->getPane(); + + if (!m_timeRulerLayer) { + m_timeRulerLayer = m_document->createMainModelLayer + (LayerFactory::TimeRuler); + } + + m_document->addLayerToView(pane, m_timeRulerLayer); + + Layer *newLayer = m_document->createImportedLayer(newModel); + + if (newLayer) { + m_document->addLayerToView(pane, newLayer); + } + + CommandHistory::getInstance()->endCompoundOperation(); + + } else if (mode == ReplaceCurrentPane) { + + // We know there is a current pane, otherwise we would have + // reset the mode to CreateAdditionalModel above; and we know + // the current pane does not contain the main model, otherwise + // we would have reset it to ReplaceMainModel. But we don't + // know whether the pane contains a waveform model at all. + + Pane *pane = m_paneStack->getCurrentPane(); + Layer *replace = 0; + + for (int i = 0; i < pane->getLayerCount(); ++i) { + Layer *layer = pane->getLayer(i); + if (dynamic_cast<WaveformLayer *>(layer)) { + replace = layer; + break; + } + } + + CommandHistory::getInstance()->startCompoundOperation + (tr("Import \"%1\"").arg(source.getLocation()), true); + + m_document->addImportedModel(newModel); + + if (replace) { + m_document->removeLayerFromView(pane, replace); + } + + Layer *newLayer = m_document->createImportedLayer(newModel); + + if (newLayer) { + m_document->addLayerToView(pane, newLayer); + } + + CommandHistory::getInstance()->endCompoundOperation(); + } + + updateMenuStates(); + m_recentFiles.addFile(source.getLocation()); + if (!source.isRemote()) { + // for file dialog + registerLastOpenedFilePath(FileFinder::AudioFile, + source.getLocalFilename()); + } + m_openingAudioFile = false; + + currentPaneChanged(m_paneStack->getCurrentPane()); + + return FileOpenSucceeded; +} + +MainWindowBase::FileOpenStatus +MainWindowBase::openPlaylist(FileSource source, AudioFileOpenMode mode) +{ + std::set<QString> extensions; + PlaylistFileReader::getSupportedExtensions(extensions); + QString extension = source.getExtension(); + if (extensions.find(extension) == extensions.end()) return FileOpenFailed; + + if (!source.isAvailable()) return FileOpenFailed; + source.waitForData(); + + PlaylistFileReader reader(source.getLocalFilename()); + if (!reader.isOK()) return FileOpenFailed; + + PlaylistFileReader::Playlist playlist = reader.load(); + + bool someSuccess = false; + + for (PlaylistFileReader::Playlist::const_iterator i = playlist.begin(); + i != playlist.end(); ++i) { + + FileOpenStatus status = openAudio(*i, mode); + + if (status == FileOpenCancelled) { + return FileOpenCancelled; + } + + if (status == FileOpenSucceeded) { + someSuccess = true; + mode = CreateAdditionalModel; + } + } + + if (someSuccess) return FileOpenSucceeded; + else return FileOpenFailed; +} + +MainWindowBase::FileOpenStatus +MainWindowBase::openLayer(FileSource source) +{ + Pane *pane = m_paneStack->getCurrentPane(); + + if (!pane) { + // shouldn't happen, as the menu action should have been disabled + std::cerr << "WARNING: MainWindowBase::openLayer: no current pane" << std::endl; + return FileOpenWrongMode; + } + + if (!getMainModel()) { + // shouldn't happen, as the menu action should have been disabled + std::cerr << "WARNING: MainWindowBase::openLayer: No main model -- hence no default sample rate available" << std::endl; + return FileOpenWrongMode; + } + + if (!source.isAvailable()) return FileOpenFailed; + source.waitForData(); + + QString path = source.getLocalFilename(); + + if (source.getExtension() == "svl" || source.getExtension() == "xml") { + + PaneCallback callback(this); + QFile file(path); + + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + std::cerr << "ERROR: MainWindowBase::openLayer(" + << source.getLocation().toStdString() + << "): Failed to open file for reading" << std::endl; + return FileOpenFailed; + } + + SVFileReader reader(m_document, callback, source.getLocation()); + reader.setCurrentPane(pane); + + QXmlInputSource inputSource(&file); + reader.parse(inputSource); + + if (!reader.isOK()) { + std::cerr << "ERROR: MainWindowBase::openLayer(" + << source.getLocation().toStdString() + << "): Failed to read XML file: " + << reader.getErrorString().toStdString() << std::endl; + return FileOpenFailed; + } + + m_recentFiles.addFile(source.getLocation()); + + if (!source.isRemote()) { + registerLastOpenedFilePath(FileFinder::LayerFile, path); // for file dialog + } + + } else { + + try { + + Model *model = DataFileReaderFactory::load + (path, getMainModel()->getSampleRate()); + + if (model) { + + std::cerr << "MainWindowBase::openLayer: Have model" << std::endl; + + Layer *newLayer = m_document->createImportedLayer(model); + + if (newLayer) { + + m_document->addLayerToView(pane, newLayer); + m_recentFiles.addFile(source.getLocation()); + + if (!source.isRemote()) { + registerLastOpenedFilePath + (FileFinder::LayerFile, + path); // for file dialog + } + + return FileOpenSucceeded; + } + } + } catch (DataFileReaderFactory::Exception e) { + if (e == DataFileReaderFactory::ImportCancelled) { + return FileOpenCancelled; + } + } + } + + source.setLeaveLocalFile(true); + return FileOpenFailed; +} + +MainWindowBase::FileOpenStatus +MainWindowBase::openImage(FileSource source) +{ + Pane *pane = m_paneStack->getCurrentPane(); + + if (!pane) { + // shouldn't happen, as the menu action should have been disabled + std::cerr << "WARNING: MainWindowBase::openImage: 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 << "openImage: trying location \"" << source.getLocation().toStdString() << "\" in image layer" << std::endl; + + if (!il->addImage(m_viewManager->getGlobalCentreFrame(), source.getLocation())) { + 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; +} + +MainWindowBase::FileOpenStatus +MainWindowBase::openSessionFile(QString fileOrUrl) +{ + return openSession(FileSource(fileOrUrl)); +} + +MainWindowBase::FileOpenStatus +MainWindowBase::openSession(FileSource source) +{ + if (!source.isAvailable()) return FileOpenFailed; + if (source.getExtension() != "sv") return FileOpenFailed; + source.waitForData(); + + BZipFileDevice bzFile(source.getLocalFilename()); + if (!bzFile.open(QIODevice::ReadOnly)) return FileOpenFailed; + + if (!checkSaveModified()) return FileOpenCancelled; + + QString error; + closeSession(); + createDocument(); + + PaneCallback callback(this); + m_viewManager->clearSelections(); + + SVFileReader reader(m_document, callback, source.getLocation()); + QXmlInputSource inputSource(&bzFile); + reader.parse(inputSource); + + if (!reader.isOK()) { + error = tr("SV XML file read error:\n%1").arg(reader.getErrorString()); + } + + bzFile.close(); + + bool ok = (error == ""); + + if (ok) { + + setWindowTitle(tr("Sonic Visualiser: %1") + .arg(source.getLocation())); + + if (!source.isRemote()) m_sessionFile = source.getLocalFilename(); + + setupMenus(); + + CommandHistory::getInstance()->clear(); + CommandHistory::getInstance()->documentSaved(); + m_documentModified = false; + updateMenuStates(); + + m_recentFiles.addFile(source.getLocation()); + + if (!source.isRemote()) { + // for file dialog + registerLastOpenedFilePath(FileFinder::SessionFile, + source.getLocalFilename()); + } + + } else { + setWindowTitle(tr("Sonic Visualiser")); + } + + return ok ? FileOpenSucceeded : FileOpenFailed; +} + +void +MainWindowBase::createPlayTarget() +{ + if (m_playTarget) return; + + m_playTarget = AudioTargetFactory::createCallbackTarget(m_playSource); + if (!m_playTarget) { + QMessageBox::warning + (this, tr("Couldn't open audio device"), + 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); + } +} + +WaveFileModel * +MainWindowBase::getMainModel() +{ + if (!m_document) return 0; + return m_document->getMainModel(); +} + +const WaveFileModel * +MainWindowBase::getMainModel() const +{ + if (!m_document) return 0; + return m_document->getMainModel(); +} + +void +MainWindowBase::createDocument() +{ + m_document = new Document; + + connect(m_document, SIGNAL(layerAdded(Layer *)), + this, SLOT(layerAdded(Layer *))); + connect(m_document, SIGNAL(layerRemoved(Layer *)), + this, SLOT(layerRemoved(Layer *))); + connect(m_document, SIGNAL(layerAboutToBeDeleted(Layer *)), + this, SLOT(layerAboutToBeDeleted(Layer *))); + connect(m_document, SIGNAL(layerInAView(Layer *, bool)), + this, SLOT(layerInAView(Layer *, bool))); + + connect(m_document, SIGNAL(modelAdded(Model *)), + this, SLOT(modelAdded(Model *))); + connect(m_document, SIGNAL(mainModelChanged(WaveFileModel *)), + this, SLOT(mainModelChanged(WaveFileModel *))); + connect(m_document, SIGNAL(modelAboutToBeDeleted(Model *)), + this, SLOT(modelAboutToBeDeleted(Model *))); + + connect(m_document, SIGNAL(modelGenerationFailed(QString)), + this, SLOT(modelGenerationFailed(QString))); + connect(m_document, SIGNAL(modelRegenerationFailed(QString, QString)), + this, SLOT(modelRegenerationFailed(QString, QString))); +} + +bool +MainWindowBase::saveSessionFile(QString path) +{ + BZipFileDevice bzFile(path); + if (!bzFile.open(QIODevice::WriteOnly)) { + std::cerr << "Failed to open session file \"" << path.toStdString() + << "\" for writing: " + << bzFile.errorString().toStdString() << std::endl; + return false; + } + + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + + QTextStream out(&bzFile); + toXml(out); + out.flush(); + + QApplication::restoreOverrideCursor(); + + if (!bzFile.isOK()) { + QMessageBox::critical(this, tr("Failed to write file"), + tr("<b>Save failed</b><p>Failed to write to file \"%1\": %2") + .arg(path).arg(bzFile.errorString())); + bzFile.close(); + return false; + } + + bzFile.close(); + return true; +} + +void +MainWindowBase::toXml(QTextStream &out) +{ + QString indent(" "); + + out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; + out << "<!DOCTYPE sonic-visualiser>\n"; + out << "<sv>\n"; + + m_document->toXml(out, "", ""); + + out << "<display>\n"; + + out << QString(" <window width=\"%1\" height=\"%2\"/>\n") + .arg(width()).arg(height()); + + for (int i = 0; i < m_paneStack->getPaneCount(); ++i) { + + Pane *pane = m_paneStack->getPane(i); + + if (pane) { + pane->toXml(out, indent); + } + } + + out << "</display>\n"; + + m_viewManager->getSelection().toXml(out); + + out << "</sv>\n"; +} + +Pane * +MainWindowBase::addPaneToStack() +{ + AddPaneCommand *command = new AddPaneCommand(this); + CommandHistory::getInstance()->addCommand(command); + return command->getPane(); +} + +void +MainWindowBase::zoomIn() +{ + Pane *currentPane = m_paneStack->getCurrentPane(); + if (currentPane) currentPane->zoom(true); +} + +void +MainWindowBase::zoomOut() +{ + Pane *currentPane = m_paneStack->getCurrentPane(); + if (currentPane) currentPane->zoom(false); +} + +void +MainWindowBase::zoomToFit() +{ + Pane *currentPane = m_paneStack->getCurrentPane(); + if (!currentPane) return; + + Model *model = getMainModel(); + if (!model) return; + + size_t start = model->getStartFrame(); + size_t end = model->getEndFrame(); + size_t pixels = currentPane->width(); + + size_t sw = currentPane->getVerticalScaleWidth(); + if (pixels > sw * 2) pixels -= sw * 2; + else pixels = 1; + if (pixels > 4) pixels -= 4; + + size_t zoomLevel = (end - start) / pixels; + + currentPane->setZoomLevel(zoomLevel); + currentPane->setCentreFrame((start + end) / 2); +} + +void +MainWindowBase::zoomDefault() +{ + Pane *currentPane = m_paneStack->getCurrentPane(); + if (currentPane) currentPane->setZoomLevel(1024); +} + +void +MainWindowBase::scrollLeft() +{ + Pane *currentPane = m_paneStack->getCurrentPane(); + if (currentPane) currentPane->scroll(false, false); +} + +void +MainWindowBase::jumpLeft() +{ + Pane *currentPane = m_paneStack->getCurrentPane(); + if (currentPane) currentPane->scroll(false, true); +} + +void +MainWindowBase::scrollRight() +{ + Pane *currentPane = m_paneStack->getCurrentPane(); + if (currentPane) currentPane->scroll(true, false); +} + +void +MainWindowBase::jumpRight() +{ + Pane *currentPane = m_paneStack->getCurrentPane(); + if (currentPane) currentPane->scroll(true, true); +} + +void +MainWindowBase::showNoOverlays() +{ + m_viewManager->setOverlayMode(ViewManager::NoOverlays); +} + +void +MainWindowBase::showMinimalOverlays() +{ + m_viewManager->setOverlayMode(ViewManager::MinimalOverlays); +} + +void +MainWindowBase::showStandardOverlays() +{ + m_viewManager->setOverlayMode(ViewManager::StandardOverlays); +} + +void +MainWindowBase::showAllOverlays() +{ + m_viewManager->setOverlayMode(ViewManager::AllOverlays); +} + +void +MainWindowBase::toggleZoomWheels() +{ + if (m_viewManager->getZoomWheelsEnabled()) { + m_viewManager->setZoomWheelsEnabled(false); + } else { + m_viewManager->setZoomWheelsEnabled(true); + } +} + +void +MainWindowBase::togglePropertyBoxes() +{ + if (m_paneStack->getLayoutStyle() == PaneStack::NoPropertyStacks) { + if (Preferences::getInstance()->getPropertyBoxLayout() == + Preferences::VerticallyStacked) { + m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout); + } else { + m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout); + } + } else { + m_paneStack->setLayoutStyle(PaneStack::NoPropertyStacks); + } +} + +void +MainWindowBase::toggleStatusBar() +{ + QSettings settings; + settings.beginGroup("MainWindow"); + bool sb = settings.value("showstatusbar", true).toBool(); + + if (sb) { + statusBar()->hide(); + } else { + statusBar()->show(); + } + + settings.setValue("showstatusbar", !sb); + + settings.endGroup(); +} + +void +MainWindowBase::preferenceChanged(PropertyContainer::PropertyName name) +{ + if (name == "Property Box Layout") { + if (m_paneStack->getLayoutStyle() != PaneStack::NoPropertyStacks) { + if (Preferences::getInstance()->getPropertyBoxLayout() == + Preferences::VerticallyStacked) { + m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout); + } else { + m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout); + } + } + } else if (name == "Background Mode" && m_viewManager) { + Preferences::BackgroundMode mode = + Preferences::getInstance()->getBackgroundMode(); + if (mode == Preferences::BackgroundFromTheme) { + m_viewManager->setGlobalDarkBackground(m_initialDarkBackground); + } else if (mode == Preferences::DarkBackground) { + m_viewManager->setGlobalDarkBackground(true); + } else { + m_viewManager->setGlobalDarkBackground(false); + } + } +} + +void +MainWindowBase::play() +{ + if (m_playSource->isPlaying()) { + stop(); + } else { + playbackFrameChanged(m_viewManager->getPlaybackFrame()); + m_playSource->play(m_viewManager->getPlaybackFrame()); + } +} + +void +MainWindowBase::ffwd() +{ + if (!getMainModel()) return; + + int frame = m_viewManager->getPlaybackFrame(); + ++frame; + + Layer *layer = getSnapLayer(); + size_t sr = getMainModel()->getSampleRate(); + + if (!layer) { + + frame = RealTime::realTime2Frame + (RealTime::frame2RealTime(frame, sr) + RealTime(2, 0), sr); + if (frame > int(getMainModel()->getEndFrame())) { + frame = getMainModel()->getEndFrame(); + } + + } else { + + size_t resolution = 0; + if (!layer->snapToFeatureFrame(m_paneStack->getCurrentPane(), + frame, resolution, Layer::SnapRight)) { + frame = getMainModel()->getEndFrame(); + } + } + + if (frame < 0) frame = 0; + + if (m_viewManager->getPlaySelectionMode()) { + frame = m_viewManager->constrainFrameToSelection(size_t(frame)); + } + + m_viewManager->setPlaybackFrame(frame); +} + +void +MainWindowBase::ffwdEnd() +{ + if (!getMainModel()) return; + + size_t frame = getMainModel()->getEndFrame(); + + if (m_viewManager->getPlaySelectionMode()) { + frame = m_viewManager->constrainFrameToSelection(frame); + } + + m_viewManager->setPlaybackFrame(frame); +} + +void +MainWindowBase::rewind() +{ + if (!getMainModel()) return; + + int frame = m_viewManager->getPlaybackFrame(); + if (frame > 0) --frame; + + Layer *layer = getSnapLayer(); + size_t sr = getMainModel()->getSampleRate(); + + // when rewinding during playback, we want to allow a period + // following a rewind target point at which the rewind will go to + // the prior point instead of the immediately neighbouring one + if (m_playSource && m_playSource->isPlaying()) { + RealTime ct = RealTime::frame2RealTime(frame, sr); + ct = ct - RealTime::fromSeconds(0.25); + if (ct < RealTime::zeroTime) ct = RealTime::zeroTime; +// std::cerr << "rewind: frame " << frame << " -> "; + frame = RealTime::realTime2Frame(ct, sr); +// std::cerr << frame << std::endl; + } + + if (!layer) { + + frame = RealTime::realTime2Frame + (RealTime::frame2RealTime(frame, sr) - RealTime(2, 0), sr); + if (frame < int(getMainModel()->getStartFrame())) { + frame = getMainModel()->getStartFrame(); + } + + } else { + + size_t resolution = 0; + if (!layer->snapToFeatureFrame(m_paneStack->getCurrentPane(), + frame, resolution, Layer::SnapLeft)) { + frame = getMainModel()->getStartFrame(); + } + } + + if (frame < 0) frame = 0; + + if (m_viewManager->getPlaySelectionMode()) { + frame = m_viewManager->constrainFrameToSelection(size_t(frame)); + } + + m_viewManager->setPlaybackFrame(frame); +} + +void +MainWindowBase::rewindStart() +{ + if (!getMainModel()) return; + + size_t frame = getMainModel()->getStartFrame(); + + if (m_viewManager->getPlaySelectionMode()) { + frame = m_viewManager->constrainFrameToSelection(frame); + } + + m_viewManager->setPlaybackFrame(frame); +} + +Layer * +MainWindowBase::getSnapLayer() const +{ + Pane *pane = m_paneStack->getCurrentPane(); + if (!pane) return 0; + + Layer *layer = pane->getSelectedLayer(); + + if (!dynamic_cast<TimeInstantLayer *>(layer) && + !dynamic_cast<TimeValueLayer *>(layer) && + !dynamic_cast<TimeRulerLayer *>(layer)) { + + layer = 0; + + for (int i = pane->getLayerCount(); i > 0; --i) { + Layer *l = pane->getLayer(i-1); + if (dynamic_cast<TimeRulerLayer *>(l)) { + layer = l; + break; + } + } + } + + return layer; +} + +void +MainWindowBase::stop() +{ + m_playSource->stop(); + + if (m_paneStack && m_paneStack->getCurrentPane()) { + updateVisibleRangeDisplay(m_paneStack->getCurrentPane()); + } else { + m_myStatusMessage = ""; + statusBar()->showMessage(""); + } +} + +MainWindowBase::AddPaneCommand::AddPaneCommand(MainWindowBase *mw) : + m_mw(mw), + m_pane(0), + m_prevCurrentPane(0), + m_added(false) +{ +} + +MainWindowBase::AddPaneCommand::~AddPaneCommand() +{ + if (m_pane && !m_added) { + m_mw->m_paneStack->deletePane(m_pane); + } +} + +QString +MainWindowBase::AddPaneCommand::getName() const +{ + return tr("Add Pane"); +} + +void +MainWindowBase::AddPaneCommand::execute() +{ + if (!m_pane) { + m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane(); + m_pane = m_mw->m_paneStack->addPane(); + + connect(m_pane, SIGNAL(contextHelpChanged(const QString &)), + m_mw, SLOT(contextHelpChanged(const QString &))); + } else { + m_mw->m_paneStack->showPane(m_pane); + } + + m_mw->m_paneStack->setCurrentPane(m_pane); + m_added = true; +} + +void +MainWindowBase::AddPaneCommand::unexecute() +{ + m_mw->m_paneStack->hidePane(m_pane); + m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane); + m_added = false; +} + +MainWindowBase::RemovePaneCommand::RemovePaneCommand(MainWindowBase *mw, Pane *pane) : + m_mw(mw), + m_pane(pane), + m_added(true) +{ +} + +MainWindowBase::RemovePaneCommand::~RemovePaneCommand() +{ + if (m_pane && !m_added) { + m_mw->m_paneStack->deletePane(m_pane); + } +} + +QString +MainWindowBase::RemovePaneCommand::getName() const +{ + return tr("Remove Pane"); +} + +void +MainWindowBase::RemovePaneCommand::execute() +{ + m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane(); + m_mw->m_paneStack->hidePane(m_pane); + m_added = false; +} + +void +MainWindowBase::RemovePaneCommand::unexecute() +{ + m_mw->m_paneStack->showPane(m_pane); + m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane); + m_added = true; +} + +void +MainWindowBase::deleteCurrentPane() +{ + CommandHistory::getInstance()->startCompoundOperation + (tr("Delete Pane"), true); + + Pane *pane = m_paneStack->getCurrentPane(); + if (pane) { + while (pane->getLayerCount() > 0) { + Layer *layer = pane->getLayer(0); + if (layer) { + m_document->removeLayerFromView(pane, layer); + } else { + break; + } + } + + RemovePaneCommand *command = new RemovePaneCommand(this, pane); + CommandHistory::getInstance()->addCommand(command); + } + + CommandHistory::getInstance()->endCompoundOperation(); + + updateMenuStates(); +} + +void +MainWindowBase::deleteCurrentLayer() +{ + Pane *pane = m_paneStack->getCurrentPane(); + if (pane) { + Layer *layer = pane->getSelectedLayer(); + if (layer) { + m_document->removeLayerFromView(pane, layer); + } + } + updateMenuStates(); +} + +void +MainWindowBase::playbackFrameChanged(unsigned long frame) +{ + if (!(m_playSource && m_playSource->isPlaying()) || !getMainModel()) return; + + RealTime now = RealTime::frame2RealTime + (frame, getMainModel()->getSampleRate()); + + if (now.sec == m_lastPlayStatusSec) return; + + RealTime then = RealTime::frame2RealTime + (m_playSource->getPlayEndFrame(), getMainModel()->getSampleRate()); + + QString nowStr; + QString thenStr; + QString remainingStr; + + if (then.sec > 10) { + nowStr = now.toSecText().c_str(); + thenStr = then.toSecText().c_str(); + remainingStr = (then - now).toSecText().c_str(); + m_lastPlayStatusSec = now.sec; + } else { + nowStr = now.toText(true).c_str(); + thenStr = then.toText(true).c_str(); + remainingStr = (then - now).toText(true).c_str(); + } + + m_myStatusMessage = tr("Playing: %1 of %2 (%3 remaining)") + .arg(nowStr).arg(thenStr).arg(remainingStr); + + statusBar()->showMessage(m_myStatusMessage); +} + +void +MainWindowBase::globalCentreFrameChanged(unsigned long ) +{ + if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return; + Pane *p = 0; + if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return; + if (!p->getFollowGlobalPan()) return; + updateVisibleRangeDisplay(p); +} + +void +MainWindowBase::viewCentreFrameChanged(View *v, unsigned long ) +{ + if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return; + Pane *p = 0; + if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return; + if (v == p) updateVisibleRangeDisplay(p); +} + +void +MainWindowBase::viewZoomLevelChanged(View *v, unsigned long , bool ) +{ + if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return; + Pane *p = 0; + if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return; + if (v == p) updateVisibleRangeDisplay(p); +} + +void +MainWindowBase::layerAdded(Layer *) +{ +// std::cerr << "MainWindowBase::layerAdded(" << layer << ")" << std::endl; + updateMenuStates(); +} + +void +MainWindowBase::layerRemoved(Layer *) +{ +// std::cerr << "MainWindowBase::layerRemoved(" << layer << ")" << std::endl; + updateMenuStates(); +} + +void +MainWindowBase::layerAboutToBeDeleted(Layer *layer) +{ +// std::cerr << "MainWindowBase::layerAboutToBeDeleted(" << layer << ")" << std::endl; + if (layer == m_timeRulerLayer) { +// std::cerr << "(this is the time ruler layer)" << std::endl; + m_timeRulerLayer = 0; + } +} + +void +MainWindowBase::layerInAView(Layer *layer, bool inAView) +{ +// std::cerr << "MainWindowBase::layerInAView(" << layer << "," << inAView << ")" << std::endl; + + // Check whether we need to add or remove model from play source + Model *model = layer->getModel(); + if (model) { + if (inAView) { + m_playSource->addModel(model); + } else { + bool found = false; + for (int i = 0; i < m_paneStack->getPaneCount(); ++i) { + Pane *pane = m_paneStack->getPane(i); + if (!pane) continue; + for (int j = 0; j < pane->getLayerCount(); ++j) { + Layer *pl = pane->getLayer(j); + if (pl && pl->getModel() == model) { + found = true; + break; + } + } + if (found) break; + } + if (!found) m_playSource->removeModel(model); + } + } + + updateMenuStates(); +} + +void +MainWindowBase::modelAdded(Model *model) +{ +// std::cerr << "MainWindowBase::modelAdded(" << model << ")" << std::endl; + m_playSource->addModel(model); +} + +void +MainWindowBase::mainModelChanged(WaveFileModel *model) +{ +// std::cerr << "MainWindowBase::mainModelChanged(" << model << ")" << std::endl; + updateDescriptionLabel(); + if (model) m_viewManager->setMainModelSampleRate(model->getSampleRate()); + if (model && !m_playTarget && m_audioOutput) createPlayTarget(); +} + +void +MainWindowBase::modelAboutToBeDeleted(Model *model) +{ +// std::cerr << "MainWindowBase::modelAboutToBeDeleted(" << model << ")" << std::endl; + if (model == m_viewManager->getPlaybackModel()) { + m_viewManager->setPlaybackModel(0); + } + m_playSource->removeModel(model); + FFTDataServer::modelAboutToBeDeleted(model); +} + +void +MainWindowBase::pollOSC() +{ + if (!m_oscQueue || m_oscQueue->isEmpty()) return; + std::cerr << "MainWindowBase::pollOSC: have " << m_oscQueue->getMessagesAvailable() << " messages" << std::endl; + + if (m_openingAudioFile) return; + + OSCMessage message = m_oscQueue->readMessage(); + + if (message.getTarget() != 0) { + return; //!!! for now -- this class is target 0, others not handled yet + } + + handleOSCMessage(message); +} + +void +MainWindowBase::inProgressSelectionChanged() +{ + Pane *currentPane = 0; + if (m_paneStack) currentPane = m_paneStack->getCurrentPane(); + if (currentPane) updateVisibleRangeDisplay(currentPane); +} + +void +MainWindowBase::contextHelpChanged(const QString &s) +{ + if (s == "" && m_myStatusMessage != "") { + statusBar()->showMessage(m_myStatusMessage); + return; + } + statusBar()->showMessage(s); +} + +void +MainWindowBase::openHelpUrl(QString url) +{ + // This method mostly lifted from Qt Assistant source code + + QProcess *process = new QProcess(this); + connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater())); + + QStringList args; + +#ifdef Q_OS_MAC + args.append(url); + process->start("open", args); +#else +#ifdef Q_OS_WIN32 + + QString pf(getenv("ProgramFiles")); + QString command = pf + QString("\\Internet Explorer\\IEXPLORE.EXE"); + + args.append(url); + process->start(command, args); + +#else +#ifdef Q_WS_X11 + if (!qgetenv("KDE_FULL_SESSION").isEmpty()) { + args.append("exec"); + args.append(url); + process->start("kfmclient", args); + } else if (!qgetenv("BROWSER").isEmpty()) { + args.append(url); + process->start(qgetenv("BROWSER"), args); + } else { + args.append(url); + process->start("firefox", args); + } +#endif +#endif +#endif +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main/MainWindowBase.h Mon Oct 22 14:24:31 2007 +0000 @@ -0,0 +1,339 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Sonic Visualiser + An audio file viewer and annotation editor. + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2006-2007 Chris Cannam and QMUL. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _MAIN_WINDOW_BASE_H_ +#define _MAIN_WINDOW_BASE_H_ + +#include <QFrame> +#include <QString> +#include <QUrl> +#include <QMainWindow> +#include <QPointer> + +#include "base/Command.h" +#include "view/ViewManager.h" +#include "base/PropertyContainer.h" +#include "base/RecentFiles.h" +#include "layer/LayerFactory.h" +#include "transform/Transform.h" +#include "document/SVFileReader.h" +#include "data/fileio/FileFinder.h" +#include "data/fileio/FileSource.h" +#include <map> + +class Document; +class PaneStack; +class Pane; +class View; +class Fader; +class Overview; +class Layer; +class WaveformLayer; +class WaveFileModel; +class AudioCallbackPlaySource; +class AudioCallbackPlayTarget; +class CommandHistory; +class QMenu; +class AudioDial; +class QLabel; +class QCheckBox; +class PreferencesDialog; +class QTreeView; +class QPushButton; +class OSCQueue; +class OSCMessage; +class KeyReference; +class Labeller; + +/** + * The base class for the SV main window. This includes everything to + * do with general document and pane stack management, but nothing + * that involves user interaction -- this doesn't create the widget or + * menu structures or editing tools, and if a function needs to open a + * dialog, it shouldn't be in here. This permits "variations on SV" + * to use different subclasses retaining the same general structure. + */ + +class MainWindowBase : public QMainWindow +{ + Q_OBJECT + +public: + MainWindowBase(bool withAudioOutput, bool withOSCSupport); + virtual ~MainWindowBase(); + + enum AudioFileOpenMode { + ReplaceMainModel, + CreateAdditionalModel, + ReplaceCurrentPane, + AskUser + }; + + enum FileOpenStatus { + FileOpenSucceeded, + FileOpenFailed, + FileOpenCancelled, + FileOpenWrongMode // attempted to open layer when no main model present + }; + + virtual FileOpenStatus open(QString fileOrUrl, AudioFileOpenMode = AskUser); + virtual FileOpenStatus open(FileSource source, AudioFileOpenMode = AskUser); + + virtual FileOpenStatus openAudio(FileSource source, AudioFileOpenMode = AskUser); + virtual FileOpenStatus openPlaylist(FileSource source, AudioFileOpenMode = AskUser); + virtual FileOpenStatus openLayer(FileSource source); + virtual FileOpenStatus openImage(FileSource source); + + virtual FileOpenStatus openSessionFile(QString fileOrUrl); + virtual FileOpenStatus openSession(FileSource source); + + virtual bool saveSessionFile(QString path); + +signals: + // Used to toggle the availability of menu actions + void canAddPane(bool); + void canDeleteCurrentPane(bool); + void canAddLayer(bool); + void canImportMoreAudio(bool); + void canImportLayer(bool); + void canExportAudio(bool); + void canExportLayer(bool); + void canExportImage(bool); + void canRenameLayer(bool); + void canEditLayer(bool); + void canMeasureLayer(bool); + void canSelect(bool); + void canClearSelection(bool); + void canEditSelection(bool); + void canDeleteSelection(bool); + void canPaste(bool); + void canInsertInstant(bool); + void canInsertInstantsAtBoundaries(bool); + void canRenumberInstants(bool); + void canDeleteCurrentLayer(bool); + void canZoom(bool); + void canScroll(bool); + void canPlay(bool); + void canFfwd(bool); + void canRewind(bool); + void canPlaySelection(bool); + void canSpeedUpPlayback(bool); + void canSlowDownPlayback(bool); + void canChangePlaybackSpeed(bool); + void canSave(bool); + +public slots: + virtual void preferenceChanged(PropertyContainer::PropertyName); + +protected slots: + virtual void zoomIn(); + virtual void zoomOut(); + virtual void zoomToFit(); + virtual void zoomDefault(); + virtual void scrollLeft(); + virtual void scrollRight(); + virtual void jumpLeft(); + virtual void jumpRight(); + + virtual void showNoOverlays(); + virtual void showMinimalOverlays(); + virtual void showStandardOverlays(); + virtual void showAllOverlays(); + + virtual void toggleZoomWheels(); + virtual void togglePropertyBoxes(); + virtual void toggleStatusBar(); + + virtual void play(); + virtual void ffwd(); + virtual void ffwdEnd(); + virtual void rewind(); + virtual void rewindStart(); + virtual void stop(); + + virtual void deleteCurrentPane(); + virtual void deleteCurrentLayer(); + + virtual void playLoopToggled(); + virtual void playSelectionToggled(); + virtual void playSoloToggled(); + + virtual void sampleRateMismatch(size_t, size_t, bool) = 0; + virtual void audioOverloadPluginDisabled() = 0; + + virtual void playbackFrameChanged(unsigned long); + virtual void globalCentreFrameChanged(unsigned long); + virtual void viewCentreFrameChanged(View *, unsigned long); + virtual void viewZoomLevelChanged(View *, unsigned long, bool); + virtual void outputLevelsChanged(float, float) = 0; + + virtual void currentPaneChanged(Pane *); + virtual void currentLayerChanged(Pane *, Layer *); + + virtual void selectAll(); + virtual void selectToStart(); + virtual void selectToEnd(); + virtual void selectVisible(); + virtual void clearSelection(); + + virtual void cut(); + virtual void copy(); + virtual void paste(); + virtual void deleteSelected(); + + virtual void insertInstant(); + virtual void insertInstantAt(size_t); + virtual void insertInstantsAtBoundaries(); + virtual void renumberInstants(); + + virtual void documentModified(); + virtual void documentRestored(); + + virtual void layerAdded(Layer *); + virtual void layerRemoved(Layer *); + virtual void layerAboutToBeDeleted(Layer *); + virtual void layerInAView(Layer *, bool); + + virtual void mainModelChanged(WaveFileModel *); + virtual void modelAdded(Model *); + virtual void modelAboutToBeDeleted(Model *); + + virtual void updateMenuStates(); + virtual void updateDescriptionLabel() = 0; + + virtual void modelGenerationFailed(QString) = 0; + virtual void modelRegenerationFailed(QString, QString) = 0; + + virtual void rightButtonMenuRequested(Pane *, QPoint point) = 0; + + virtual void paneAdded(Pane *) = 0; + virtual void paneHidden(Pane *) = 0; + virtual void paneAboutToBeDeleted(Pane *) = 0; + virtual void paneDropAccepted(Pane *, QStringList) = 0; + virtual void paneDropAccepted(Pane *, QString) = 0; + + virtual void pollOSC(); + virtual void handleOSCMessage(const OSCMessage &) = 0; + + virtual void contextHelpChanged(const QString &); + virtual void inProgressSelectionChanged(); + + virtual void closeSession() = 0; + +protected: + QString m_sessionFile; + QString m_audioFile; + Document *m_document; + + QLabel *m_descriptionLabel; + PaneStack *m_paneStack; + ViewManager *m_viewManager; + Layer *m_timeRulerLayer; + + bool m_audioOutput; + AudioCallbackPlaySource *m_playSource; + AudioCallbackPlayTarget *m_playTarget; + + OSCQueue *m_oscQueue; + + RecentFiles m_recentFiles; + RecentFiles m_recentTransforms; + + bool m_documentModified; + bool m_openingAudioFile; + bool m_abandoning; + + Labeller *m_labeller; + + int m_lastPlayStatusSec; + mutable QString m_myStatusMessage; + + bool m_initialDarkBackground; + + WaveFileModel *getMainModel(); + const WaveFileModel *getMainModel() const; + void createDocument(); + + Pane *addPaneToStack(); + Layer *getSnapLayer() const; + + class PaneCallback : public SVFileReaderPaneCallback + { + public: + PaneCallback(MainWindowBase *mw) : m_mw(mw) { } + virtual Pane *addPane() { return m_mw->addPaneToStack(); } + virtual void setWindowSize(int width, int height) { + m_mw->resize(width, height); + } + virtual void addSelection(int start, int end) { + m_mw->m_viewManager->addSelection(Selection(start, end)); + } + protected: + MainWindowBase *m_mw; + }; + + class AddPaneCommand : public Command + { + public: + AddPaneCommand(MainWindowBase *mw); + virtual ~AddPaneCommand(); + + virtual void execute(); + virtual void unexecute(); + virtual QString getName() const; + + Pane *getPane() { return m_pane; } + + protected: + MainWindowBase *m_mw; + Pane *m_pane; // Main window owns this, but I determine its lifespan + Pane *m_prevCurrentPane; // I don't own this + bool m_added; + }; + + class RemovePaneCommand : public Command + { + public: + RemovePaneCommand(MainWindowBase *mw, Pane *pane); + virtual ~RemovePaneCommand(); + + virtual void execute(); + virtual void unexecute(); + virtual QString getName() const; + + protected: + MainWindowBase *m_mw; + Pane *m_pane; // Main window owns this, but I determine its lifespan + Pane *m_prevCurrentPane; // I don't own this + bool m_added; + }; + + virtual bool checkSaveModified() = 0; + + virtual QString getOpenFileName(FileFinder::FileType type); + virtual QString getSaveFileName(FileFinder::FileType type); + virtual void registerLastOpenedFilePath(FileFinder::FileType type, QString path); + + virtual void createPlayTarget(); + virtual void openHelpUrl(QString url); + + virtual void setupMenus() = 0; + virtual void updateVisibleRangeDisplay(Pane *p) const = 0; + + virtual void toXml(QTextStream &stream); +}; + + +#endif
--- a/main/main.cpp Mon Oct 22 09:45:35 2007 +0000 +++ b/main/main.cpp Mon Oct 22 14:24:31 2007 +0000 @@ -304,7 +304,7 @@ if (path.endsWith("sv")) { if (!haveSession) { - status = gui.openSession(path); + status = gui.openSessionFile(path); if (status == MainWindow::FileOpenSucceeded) { haveSession = true; haveMainModel = true;
--- a/sv.pro Mon Oct 22 09:45:35 2007 +0000 +++ b/sv.pro Mon Oct 22 14:24:31 2007 +0000 @@ -43,6 +43,7 @@ document/Document.h \ document/SVFileReader.h \ main/MainWindow.h \ + main/MainWindowBase.h \ main/PreferencesDialog.h \ osc/OSCMessage.h \ osc/OSCQueue.h \ @@ -64,6 +65,7 @@ document/SVFileReader.cpp \ main/main.cpp \ main/MainWindow.cpp \ + main/MainWindowBase.cpp \ main/PreferencesDialog.cpp \ osc/OSCMessage.cpp \ osc/OSCQueue.cpp \