MainWindowBase.cpp

Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2006-2007 Chris Cannam and QMUL.
00008     
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 #include "MainWindowBase.h"
00017 #include "Document.h"
00018 
00019 
00020 #include "view/Pane.h"
00021 #include "view/PaneStack.h"
00022 #include "data/model/WaveFileModel.h"
00023 #include "data/model/SparseOneDimensionalModel.h"
00024 #include "data/model/NoteModel.h"
00025 #include "data/model/Labeller.h"
00026 #include "view/ViewManager.h"
00027 
00028 #include "layer/WaveformLayer.h"
00029 #include "layer/TimeRulerLayer.h"
00030 #include "layer/TimeInstantLayer.h"
00031 #include "layer/TimeValueLayer.h"
00032 #include "layer/Colour3DPlotLayer.h"
00033 #include "layer/SliceLayer.h"
00034 #include "layer/SliceableLayer.h"
00035 #include "layer/ImageLayer.h"
00036 
00037 #include "widgets/ListInputDialog.h"
00038 
00039 #include "audioio/AudioCallbackPlaySource.h"
00040 #include "audioio/AudioCallbackPlayTarget.h"
00041 #include "audioio/AudioTargetFactory.h"
00042 #include "audioio/PlaySpeedRangeMapper.h"
00043 #include "data/fileio/DataFileReaderFactory.h"
00044 #include "data/fileio/PlaylistFileReader.h"
00045 #include "data/fileio/WavFileWriter.h"
00046 #include "data/fileio/CSVFileWriter.h"
00047 #include "data/fileio/MIDIFileWriter.h"
00048 #include "data/fileio/BZipFileDevice.h"
00049 #include "data/fileio/FileSource.h"
00050 
00051 #include "data/fft/FFTDataServer.h"
00052 
00053 #include "base/RecentFiles.h"
00054 
00055 #include "base/PlayParameterRepository.h"
00056 #include "base/XmlExportable.h"
00057 #include "base/CommandHistory.h"
00058 #include "base/Profiler.h"
00059 #include "base/Preferences.h"
00060 
00061 #include "data/osc/OSCQueue.h"
00062 
00063 #include <QApplication>
00064 #include <QMessageBox>
00065 #include <QGridLayout>
00066 #include <QLabel>
00067 #include <QAction>
00068 #include <QMenuBar>
00069 #include <QToolBar>
00070 #include <QInputDialog>
00071 #include <QStatusBar>
00072 #include <QTreeView>
00073 #include <QFile>
00074 #include <QFileInfo>
00075 #include <QDir>
00076 #include <QTextStream>
00077 #include <QProcess>
00078 #include <QShortcut>
00079 #include <QSettings>
00080 #include <QDateTime>
00081 #include <QProcess>
00082 #include <QCheckBox>
00083 #include <QRegExp>
00084 #include <QScrollArea>
00085 
00086 #include <iostream>
00087 #include <cstdio>
00088 #include <errno.h>
00089 
00090 using std::cerr;
00091 using std::endl;
00092 
00093 using std::vector;
00094 using std::map;
00095 using std::set;
00096 
00097 
00098 MainWindowBase::MainWindowBase(bool withAudioOutput, bool withOSCSupport) :
00099     m_document(0),
00100     m_paneStack(0),
00101     m_viewManager(0),
00102     m_timeRulerLayer(0),
00103     m_audioOutput(withAudioOutput),
00104     m_playSource(0),
00105     m_playTarget(0),
00106     m_oscQueue(withOSCSupport ? new OSCQueue() : 0),
00107     m_recentFiles("RecentFiles", 20),
00108     m_recentTransforms("RecentTransforms", 20),
00109     m_documentModified(false),
00110     m_openingAudioFile(false),
00111     m_abandoning(false),
00112     m_labeller(0)
00113 {
00114     connect(CommandHistory::getInstance(), SIGNAL(commandExecuted()),
00115             this, SLOT(documentModified()));
00116     connect(CommandHistory::getInstance(), SIGNAL(documentRestored()),
00117             this, SLOT(documentRestored()));
00118     
00119     m_viewManager = new ViewManager();
00120     connect(m_viewManager, SIGNAL(selectionChanged()),
00121             this, SLOT(updateMenuStates()));
00122     connect(m_viewManager, SIGNAL(inProgressSelectionChanged()),
00123             this, SLOT(inProgressSelectionChanged()));
00124 
00125     Preferences::BackgroundMode mode =
00126         Preferences::getInstance()->getBackgroundMode();
00127     m_initialDarkBackground = m_viewManager->getGlobalDarkBackground();
00128     if (mode != Preferences::BackgroundFromTheme) {
00129         m_viewManager->setGlobalDarkBackground
00130             (mode == Preferences::DarkBackground);
00131     }
00132 
00133     m_paneStack = new PaneStack(0, m_viewManager);
00134     connect(m_paneStack, SIGNAL(currentPaneChanged(Pane *)),
00135             this, SLOT(currentPaneChanged(Pane *)));
00136     connect(m_paneStack, SIGNAL(currentLayerChanged(Pane *, Layer *)),
00137             this, SLOT(currentLayerChanged(Pane *, Layer *)));
00138     connect(m_paneStack, SIGNAL(rightButtonMenuRequested(Pane *, QPoint)),
00139             this, SLOT(rightButtonMenuRequested(Pane *, QPoint)));
00140     connect(m_paneStack, SIGNAL(contextHelpChanged(const QString &)),
00141             this, SLOT(contextHelpChanged(const QString &)));
00142     connect(m_paneStack, SIGNAL(paneAdded(Pane *)),
00143             this, SLOT(paneAdded(Pane *)));
00144     connect(m_paneStack, SIGNAL(paneHidden(Pane *)),
00145             this, SLOT(paneHidden(Pane *)));
00146     connect(m_paneStack, SIGNAL(paneAboutToBeDeleted(Pane *)),
00147             this, SLOT(paneAboutToBeDeleted(Pane *)));
00148     connect(m_paneStack, SIGNAL(dropAccepted(Pane *, QStringList)),
00149             this, SLOT(paneDropAccepted(Pane *, QStringList)));
00150     connect(m_paneStack, SIGNAL(dropAccepted(Pane *, QString)),
00151             this, SLOT(paneDropAccepted(Pane *, QString)));
00152     connect(m_paneStack, SIGNAL(paneDeleteButtonClicked(Pane *)),
00153             this, SLOT(paneDeleteButtonClicked(Pane *)));
00154 
00155     m_playSource = new AudioCallbackPlaySource(m_viewManager,
00156                                                QApplication::applicationName());
00157 
00158     connect(m_playSource, SIGNAL(sampleRateMismatch(size_t, size_t, bool)),
00159             this,           SLOT(sampleRateMismatch(size_t, size_t, bool)));
00160     connect(m_playSource, SIGNAL(audioOverloadPluginDisabled()),
00161             this,           SLOT(audioOverloadPluginDisabled()));
00162 
00163     connect(m_viewManager, SIGNAL(outputLevelsChanged(float, float)),
00164             this, SLOT(outputLevelsChanged(float, float)));
00165 
00166     connect(m_viewManager, SIGNAL(playbackFrameChanged(unsigned long)),
00167             this, SLOT(playbackFrameChanged(unsigned long)));
00168 
00169     connect(m_viewManager, SIGNAL(globalCentreFrameChanged(unsigned long)),
00170             this, SLOT(globalCentreFrameChanged(unsigned long)));
00171 
00172     connect(m_viewManager, SIGNAL(viewCentreFrameChanged(View *, unsigned long)),
00173             this, SLOT(viewCentreFrameChanged(View *, unsigned long)));
00174 
00175     connect(m_viewManager, SIGNAL(viewZoomLevelChanged(View *, unsigned long, bool)),
00176             this, SLOT(viewZoomLevelChanged(View *, unsigned long, bool)));
00177 
00178     connect(Preferences::getInstance(),
00179             SIGNAL(propertyChanged(PropertyContainer::PropertyName)),
00180             this,
00181             SLOT(preferenceChanged(PropertyContainer::PropertyName)));
00182 
00183     if (m_oscQueue && m_oscQueue->isOK()) {
00184         connect(m_oscQueue, SIGNAL(messagesAvailable()), this, SLOT(pollOSC()));
00185         QTimer *oscTimer = new QTimer(this);
00186         connect(oscTimer, SIGNAL(timeout()), this, SLOT(pollOSC()));
00187         oscTimer->start(1000);
00188     }
00189 
00190     Labeller::ValueType labellerType = Labeller::ValueFromTwoLevelCounter;
00191     QSettings settings;
00192     settings.beginGroup("MainWindow");
00193     labellerType = (Labeller::ValueType)
00194         settings.value("labellertype", (int)labellerType).toInt();
00195     int cycle = settings.value("labellercycle", 4).toInt();
00196     settings.endGroup();
00197 
00198     m_labeller = new Labeller(labellerType);
00199     m_labeller->setCounterCycleSize(cycle);
00200 }
00201 
00202 MainWindowBase::~MainWindowBase()
00203 {
00204     if (m_playTarget) m_playTarget->shutdown();
00205 //    delete m_playTarget;
00206     delete m_playSource;
00207     delete m_viewManager;
00208     delete m_oscQueue;
00209     Profiles::getInstance()->dump();
00210 }
00211 
00212 QString
00213 MainWindowBase::getOpenFileName(FileFinder::FileType type)
00214 {
00215     FileFinder *ff = FileFinder::getInstance();
00216     switch (type) {
00217     case FileFinder::SessionFile:
00218         return ff->getOpenFileName(type, m_sessionFile);
00219     case FileFinder::AudioFile:
00220         return ff->getOpenFileName(type, m_audioFile);
00221     case FileFinder::LayerFile:
00222         return ff->getOpenFileName(type, m_sessionFile);
00223     case FileFinder::LayerFileNoMidi:
00224         return ff->getOpenFileName(type, m_sessionFile);
00225     case FileFinder::SessionOrAudioFile:
00226         return ff->getOpenFileName(type, m_sessionFile);
00227     case FileFinder::ImageFile:
00228         return ff->getOpenFileName(type, m_sessionFile);
00229     case FileFinder::AnyFile:
00230         if (getMainModel() != 0 &&
00231             m_paneStack != 0 &&
00232             m_paneStack->getCurrentPane() != 0) { // can import a layer
00233             return ff->getOpenFileName(FileFinder::AnyFile, m_sessionFile);
00234         } else {
00235             return ff->getOpenFileName(FileFinder::SessionOrAudioFile,
00236                                        m_sessionFile);
00237         }
00238     }
00239     return "";
00240 }
00241 
00242 QString
00243 MainWindowBase::getSaveFileName(FileFinder::FileType type)
00244 {
00245     FileFinder *ff = FileFinder::getInstance();
00246     switch (type) {
00247     case FileFinder::SessionFile:
00248         return ff->getSaveFileName(type, m_sessionFile);
00249     case FileFinder::AudioFile:
00250         return ff->getSaveFileName(type, m_audioFile);
00251     case FileFinder::LayerFile:
00252         return ff->getSaveFileName(type, m_sessionFile);
00253     case FileFinder::LayerFileNoMidi:
00254         return ff->getSaveFileName(type, m_sessionFile);
00255     case FileFinder::SessionOrAudioFile:
00256         return ff->getSaveFileName(type, m_sessionFile);
00257     case FileFinder::ImageFile:
00258         return ff->getSaveFileName(type, m_sessionFile);
00259     case FileFinder::AnyFile:
00260         return ff->getSaveFileName(type, m_sessionFile);
00261     }
00262     return "";
00263 }
00264 
00265 void
00266 MainWindowBase::registerLastOpenedFilePath(FileFinder::FileType type, QString path)
00267 {
00268     FileFinder *ff = FileFinder::getInstance();
00269     ff->registerLastOpenedFilePath(type, path);
00270 }
00271 
00272 void
00273 MainWindowBase::updateMenuStates()
00274 {
00275     Pane *currentPane = 0;
00276     Layer *currentLayer = 0;
00277 
00278     if (m_paneStack) currentPane = m_paneStack->getCurrentPane();
00279     if (currentPane) currentLayer = currentPane->getSelectedLayer();
00280 
00281     bool havePrevPane = false, haveNextPane = false;
00282     bool havePrevLayer = false, haveNextLayer = false;
00283 
00284     if (currentPane) {
00285         for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
00286             if (m_paneStack->getPane(i) == currentPane) {
00287                 if (i > 0) havePrevPane = true;
00288                 if (i < m_paneStack->getPaneCount()-1) haveNextPane = true;
00289                 break;
00290             }
00291         }
00292         if (currentLayer) {
00293             for (int i = 0; i < currentPane->getLayerCount(); ++i) {
00294                 if (currentPane->getLayer(i) == currentLayer) {
00295                     if (i > 0) havePrevLayer = true;
00296                     if (i < currentPane->getLayerCount()-1) haveNextLayer = true;
00297                     break;
00298                 }
00299             }
00300         }
00301     }        
00302 
00303     bool haveCurrentPane =
00304         (currentPane != 0);
00305     bool haveCurrentLayer =
00306         (haveCurrentPane &&
00307          (currentLayer != 0));
00308     bool haveMainModel =
00309         (getMainModel() != 0);
00310     bool havePlayTarget =
00311         (m_playTarget != 0);
00312     bool haveSelection = 
00313         (m_viewManager &&
00314          !m_viewManager->getSelections().empty());
00315     bool haveCurrentEditableLayer =
00316         (haveCurrentLayer &&
00317          currentLayer->isLayerEditable());
00318     bool haveCurrentTimeInstantsLayer = 
00319         (haveCurrentLayer &&
00320          dynamic_cast<TimeInstantLayer *>(currentLayer));
00321     bool haveCurrentColour3DPlot =
00322         (haveCurrentLayer &&
00323          dynamic_cast<Colour3DPlotLayer *>(currentLayer));
00324     bool haveClipboardContents =
00325         (m_viewManager &&
00326          !m_viewManager->getClipboard().empty());
00327 
00328     emit canAddPane(haveMainModel);
00329     emit canDeleteCurrentPane(haveCurrentPane);
00330     emit canZoom(haveMainModel && haveCurrentPane);
00331     emit canScroll(haveMainModel && haveCurrentPane);
00332     emit canAddLayer(haveMainModel && haveCurrentPane);
00333     emit canImportMoreAudio(haveMainModel);
00334     emit canImportLayer(haveMainModel && haveCurrentPane);
00335     emit canExportAudio(haveMainModel);
00336     emit canExportLayer(haveMainModel &&
00337                         (haveCurrentEditableLayer || haveCurrentColour3DPlot));
00338     emit canExportImage(haveMainModel && haveCurrentPane);
00339     emit canDeleteCurrentLayer(haveCurrentLayer);
00340     emit canRenameLayer(haveCurrentLayer);
00341     emit canEditLayer(haveCurrentEditableLayer);
00342     emit canMeasureLayer(haveCurrentLayer);
00343     emit canSelect(haveMainModel && haveCurrentPane);
00344     emit canPlay(havePlayTarget);
00345     emit canFfwd(true);
00346     emit canRewind(true);
00347     emit canPaste(haveClipboardContents);
00348     emit canInsertInstant(haveCurrentPane);
00349     emit canInsertInstantsAtBoundaries(haveCurrentPane && haveSelection);
00350     emit canRenumberInstants(haveCurrentTimeInstantsLayer && haveSelection);
00351     emit canPlaySelection(haveMainModel && havePlayTarget && haveSelection);
00352     emit canClearSelection(haveSelection);
00353     emit canEditSelection(haveSelection && haveCurrentEditableLayer);
00354     emit canSave(m_sessionFile != "" && m_documentModified);
00355     emit canSelectPreviousPane(havePrevPane);
00356     emit canSelectNextPane(haveNextPane);
00357     emit canSelectPreviousLayer(havePrevLayer);
00358     emit canSelectNextLayer(haveNextLayer);
00359 }
00360 
00361 void
00362 MainWindowBase::documentModified()
00363 {
00364 //    std::cerr << "MainWindowBase::documentModified" << std::endl;
00365 
00366     if (!m_documentModified) {
00368         setWindowTitle(tr("%1 (modified)").arg(windowTitle()));
00369     }
00370 
00371     m_documentModified = true;
00372     updateMenuStates();
00373 }
00374 
00375 void
00376 MainWindowBase::documentRestored()
00377 {
00378 //    std::cerr << "MainWindowBase::documentRestored" << std::endl;
00379 
00380     if (m_documentModified) {
00382         QString wt(windowTitle());
00383         wt.replace(tr(" (modified)"), "");
00384         setWindowTitle(wt);
00385     }
00386 
00387     m_documentModified = false;
00388     updateMenuStates();
00389 }
00390 
00391 void
00392 MainWindowBase::playLoopToggled()
00393 {
00394     QAction *action = dynamic_cast<QAction *>(sender());
00395     
00396     if (action) {
00397         m_viewManager->setPlayLoopMode(action->isChecked());
00398     } else {
00399         m_viewManager->setPlayLoopMode(!m_viewManager->getPlayLoopMode());
00400     }
00401 }
00402 
00403 void
00404 MainWindowBase::playSelectionToggled()
00405 {
00406     QAction *action = dynamic_cast<QAction *>(sender());
00407     
00408     if (action) {
00409         m_viewManager->setPlaySelectionMode(action->isChecked());
00410     } else {
00411         m_viewManager->setPlaySelectionMode(!m_viewManager->getPlaySelectionMode());
00412     }
00413 }
00414 
00415 void
00416 MainWindowBase::playSoloToggled()
00417 {
00418     QAction *action = dynamic_cast<QAction *>(sender());
00419     
00420     if (action) {
00421         m_viewManager->setPlaySoloMode(action->isChecked());
00422     } else {
00423         m_viewManager->setPlaySoloMode(!m_viewManager->getPlaySoloMode());
00424     }
00425 
00426     if (m_viewManager->getPlaySoloMode()) {
00427         currentPaneChanged(m_paneStack->getCurrentPane());
00428     } else {
00429         m_viewManager->setPlaybackModel(0);
00430         if (m_playSource) {
00431             m_playSource->clearSoloModelSet();
00432         }
00433     }
00434 }
00435 
00436 void
00437 MainWindowBase::currentPaneChanged(Pane *p)
00438 {
00439     updateMenuStates();
00440     updateVisibleRangeDisplay(p);
00441 
00442     if (!p) return;
00443 
00444     if (!(m_viewManager &&
00445           m_playSource &&
00446           m_viewManager->getPlaySoloMode())) {
00447         if (m_viewManager) m_viewManager->setPlaybackModel(0);
00448         return;
00449     }
00450 
00451     Model *prevPlaybackModel = m_viewManager->getPlaybackModel();
00452 
00453     // What we want here is not the currently playing frame (unless we
00454     // are about to clear out the audio playback buffers -- which may
00455     // or may not be possible, depending on the audio driver).  What
00456     // we want is the frame that was last committed to the soundcard
00457     // buffers, as the audio driver will continue playing up to that
00458     // frame before switching to whichever one we decide we want to
00459     // switch to, regardless of our efforts.
00460 
00461     int frame = m_playSource->getCurrentBufferedFrame();
00462 
00463 //    std::cerr << "currentPaneChanged: current frame (in ref model) = " << frame << std::endl;
00464 
00465     View::ModelSet soloModels = p->getModels();
00466     
00467     View::ModelSet sources;
00468     for (View::ModelSet::iterator mi = soloModels.begin();
00469          mi != soloModels.end(); ++mi) {
00470         if (*mi && (*mi)->getSourceModel()) {
00471             sources.insert((*mi)->getSourceModel());
00472         }
00473     }
00474     for (View::ModelSet::iterator mi = sources.begin();
00475          mi != sources.end(); ++mi) {
00476         soloModels.insert(*mi);
00477     }
00478 
00480     //playback model has changed, and changing it on ViewManager --
00481     //the play source should be making the setPlaybackModel call to
00482     //ViewManager
00483 
00484     for (View::ModelSet::iterator mi = soloModels.begin();
00485          mi != soloModels.end(); ++mi) {
00486         if (dynamic_cast<RangeSummarisableTimeValueModel *>(*mi)) {
00487             m_viewManager->setPlaybackModel(*mi);
00488         }
00489     }
00490     
00491     RangeSummarisableTimeValueModel *a = 
00492         dynamic_cast<RangeSummarisableTimeValueModel *>(prevPlaybackModel);
00493     RangeSummarisableTimeValueModel *b = 
00494         dynamic_cast<RangeSummarisableTimeValueModel *>(m_viewManager->
00495                                                         getPlaybackModel());
00496 
00497     m_playSource->setSoloModelSet(soloModels);
00498 
00499     if (a && b && (a != b)) {
00500         if (m_playSource->isPlaying()) m_playSource->play(frame);
00501     }
00502 }
00503 
00504 void
00505 MainWindowBase::currentLayerChanged(Pane *p, Layer *)
00506 {
00507     updateMenuStates();
00508     updateVisibleRangeDisplay(p);
00509 }
00510 
00511 void
00512 MainWindowBase::selectAll()
00513 {
00514     if (!getMainModel()) return;
00515     m_viewManager->setSelection(Selection(getMainModel()->getStartFrame(),
00516                                           getMainModel()->getEndFrame()));
00517 }
00518 
00519 void
00520 MainWindowBase::selectToStart()
00521 {
00522     if (!getMainModel()) return;
00523     m_viewManager->setSelection(Selection(getMainModel()->getStartFrame(),
00524                                           m_viewManager->getGlobalCentreFrame()));
00525 }
00526 
00527 void
00528 MainWindowBase::selectToEnd()
00529 {
00530     if (!getMainModel()) return;
00531     m_viewManager->setSelection(Selection(m_viewManager->getGlobalCentreFrame(),
00532                                           getMainModel()->getEndFrame()));
00533 }
00534 
00535 void
00536 MainWindowBase::selectVisible()
00537 {
00538     Model *model = getMainModel();
00539     if (!model) return;
00540 
00541     Pane *currentPane = m_paneStack->getCurrentPane();
00542     if (!currentPane) return;
00543 
00544     size_t startFrame, endFrame;
00545 
00546     if (currentPane->getStartFrame() < 0) startFrame = 0;
00547     else startFrame = currentPane->getStartFrame();
00548 
00549     if (currentPane->getEndFrame() > model->getEndFrame()) endFrame = model->getEndFrame();
00550     else endFrame = currentPane->getEndFrame();
00551 
00552     m_viewManager->setSelection(Selection(startFrame, endFrame));
00553 }
00554 
00555 void
00556 MainWindowBase::clearSelection()
00557 {
00558     m_viewManager->clearSelections();
00559 }
00560 
00561 void
00562 MainWindowBase::cut()
00563 {
00564     Pane *currentPane = m_paneStack->getCurrentPane();
00565     if (!currentPane) return;
00566 
00567     Layer *layer = currentPane->getSelectedLayer();
00568     if (!layer) return;
00569 
00570     Clipboard &clipboard = m_viewManager->getClipboard();
00571     clipboard.clear();
00572 
00573     MultiSelection::SelectionList selections = m_viewManager->getSelections();
00574 
00575     CommandHistory::getInstance()->startCompoundOperation(tr("Cut"), true);
00576 
00577     for (MultiSelection::SelectionList::iterator i = selections.begin();
00578          i != selections.end(); ++i) {
00579         layer->copy(currentPane, *i, clipboard);
00580         layer->deleteSelection(*i);
00581     }
00582 
00583     CommandHistory::getInstance()->endCompoundOperation();
00584 }
00585 
00586 void
00587 MainWindowBase::copy()
00588 {
00589     Pane *currentPane = m_paneStack->getCurrentPane();
00590     if (!currentPane) return;
00591 
00592     Layer *layer = currentPane->getSelectedLayer();
00593     if (!layer) return;
00594 
00595     Clipboard &clipboard = m_viewManager->getClipboard();
00596     clipboard.clear();
00597 
00598     MultiSelection::SelectionList selections = m_viewManager->getSelections();
00599 
00600     for (MultiSelection::SelectionList::iterator i = selections.begin();
00601          i != selections.end(); ++i) {
00602         layer->copy(currentPane, *i, clipboard);
00603     }
00604 }
00605 
00606 void
00607 MainWindowBase::paste()
00608 {
00609     Pane *currentPane = m_paneStack->getCurrentPane();
00610     if (!currentPane) return;
00611 
00612     Layer *layer = currentPane->getSelectedLayer();
00613 
00614     Clipboard &clipboard = m_viewManager->getClipboard();
00615 //    Clipboard::PointList contents = clipboard.getPoints();
00616 
00617     bool inCompound = false;
00618 
00619     if (!layer || !layer->isLayerEditable()) {
00620         
00621         CommandHistory::getInstance()->startCompoundOperation
00622             (tr("Paste"), true);
00623 
00624         // no suitable current layer: create one of the most
00625         // appropriate sort
00626         LayerFactory::LayerType type =
00627             LayerFactory::getInstance()->getLayerTypeForClipboardContents(clipboard);
00628         layer = m_document->createEmptyLayer(type);
00629 
00630         if (!layer) {
00631             CommandHistory::getInstance()->endCompoundOperation();
00632             return;
00633         }
00634 
00635         m_document->addLayerToView(currentPane, layer);
00636         m_paneStack->setCurrentLayer(currentPane, layer);
00637 
00638         inCompound = true;
00639     }
00640 
00641     layer->paste(currentPane, clipboard, 0, true);
00642 
00643     if (inCompound) CommandHistory::getInstance()->endCompoundOperation();
00644 }
00645 
00646 void
00647 MainWindowBase::deleteSelected()
00648 {
00649     if (m_paneStack->getCurrentPane() &&
00650         m_paneStack->getCurrentPane()->getSelectedLayer()) {
00651         
00652         Layer *layer = m_paneStack->getCurrentPane()->getSelectedLayer();
00653 
00654         if (m_viewManager && 
00655             (m_viewManager->getToolMode() == ViewManager::MeasureMode)) {
00656 
00657             layer->deleteCurrentMeasureRect();
00658 
00659         } else {
00660 
00661             MultiSelection::SelectionList selections =
00662                 m_viewManager->getSelections();
00663             
00664             for (MultiSelection::SelectionList::iterator i = selections.begin();
00665                  i != selections.end(); ++i) {
00666                 layer->deleteSelection(*i);
00667             }
00668         }
00669     }
00670 }
00671 
00672 void
00673 MainWindowBase::insertInstant()
00674 {
00675     int frame = m_viewManager->getPlaybackFrame();
00676     insertInstantAt(frame);
00677 }
00678 
00679 void
00680 MainWindowBase::insertInstantsAtBoundaries()
00681 {
00682     MultiSelection::SelectionList selections = m_viewManager->getSelections();
00683     for (MultiSelection::SelectionList::iterator i = selections.begin();
00684          i != selections.end(); ++i) {
00685         size_t start = i->getStartFrame();
00686         size_t end = i->getEndFrame();
00687         if (start != end) {
00688             insertInstantAt(i->getStartFrame());
00689             insertInstantAt(i->getEndFrame());
00690         }
00691     }
00692 }
00693 
00694 void
00695 MainWindowBase::insertInstantAt(size_t frame)
00696 {
00697     Pane *pane = m_paneStack->getCurrentPane();
00698     if (!pane) {
00699         return;
00700     }
00701 
00702     frame = pane->alignFromReference(frame);
00703 
00704     Layer *layer = dynamic_cast<TimeInstantLayer *>
00705         (pane->getSelectedLayer());
00706 
00707     if (!layer) {
00708         for (int i = pane->getLayerCount(); i > 0; --i) {
00709             layer = dynamic_cast<TimeInstantLayer *>(pane->getLayer(i - 1));
00710             if (layer) break;
00711         }
00712 
00713         if (!layer) {
00714             CommandHistory::getInstance()->startCompoundOperation
00715                 (tr("Add Point"), true);
00716             layer = m_document->createEmptyLayer(LayerFactory::TimeInstants);
00717             if (layer) {
00718                 m_document->addLayerToView(pane, layer);
00719                 m_paneStack->setCurrentLayer(pane, layer);
00720             }
00721             CommandHistory::getInstance()->endCompoundOperation();
00722         }
00723     }
00724 
00725     if (layer) {
00726     
00727         Model *model = layer->getModel();
00728         SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *>
00729             (model);
00730 
00731         if (sodm) {
00732             SparseOneDimensionalModel::Point point(frame, "");
00733 
00734             SparseOneDimensionalModel::Point prevPoint(0);
00735             bool havePrevPoint = false;
00736 
00737             SparseOneDimensionalModel::EditCommand *command =
00738                 new SparseOneDimensionalModel::EditCommand(sodm, tr("Add Point"));
00739 
00740             if (m_labeller->requiresPrevPoint()) {
00741 
00742                 SparseOneDimensionalModel::PointList prevPoints =
00743                     sodm->getPreviousPoints(frame);
00744 
00745                 if (!prevPoints.empty()) {
00746                     prevPoint = *prevPoints.begin();
00747                     havePrevPoint = true;
00748                 }
00749             }
00750 
00751             if (m_labeller) {
00752 
00753                 m_labeller->setSampleRate(sodm->getSampleRate());
00754 
00755                 if (m_labeller->actingOnPrevPoint()) {
00756                     command->deletePoint(prevPoint);
00757                 }
00758 
00759                 m_labeller->label<SparseOneDimensionalModel::Point>
00760                     (point, havePrevPoint ? &prevPoint : 0);
00761 
00762                 if (m_labeller->actingOnPrevPoint()) {
00763                     command->addPoint(prevPoint);
00764                 }
00765             }
00766             
00767             command->addPoint(point);
00768 
00769             command->setName(tr("Add Point at %1 s")
00770                              .arg(RealTime::frame2RealTime
00771                                   (frame,
00772                                    sodm->getSampleRate())
00773                                   .toText(false).c_str()));
00774 
00775             command->finish();
00776         }
00777     }
00778 }
00779 
00780 void
00781 MainWindowBase::renumberInstants()
00782 {
00783     Pane *pane = m_paneStack->getCurrentPane();
00784     if (!pane) return;
00785 
00786     Layer *layer = dynamic_cast<TimeInstantLayer *>(pane->getSelectedLayer());
00787     if (!layer) return;
00788 
00789     MultiSelection ms(m_viewManager->getSelection());
00790     
00791     Model *model = layer->getModel();
00792     SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *>
00793         (model);
00794     if (!sodm) return;
00795 
00796     if (!m_labeller) return;
00797 
00798     Labeller labeller(*m_labeller);
00799     labeller.setSampleRate(sodm->getSampleRate());
00800 
00801     // This uses a command
00802 
00803     labeller.labelAll<SparseOneDimensionalModel::Point>(*sodm, &ms);
00804 }
00805 
00806 MainWindowBase::FileOpenStatus
00807 MainWindowBase::open(QString fileOrUrl, AudioFileOpenMode mode)
00808 {
00809     return open(FileSource(fileOrUrl, FileSource::ProgressDialog), mode);
00810 }
00811 
00812 MainWindowBase::FileOpenStatus
00813 MainWindowBase::open(FileSource source, AudioFileOpenMode mode)
00814 {
00815     FileOpenStatus status;
00816 
00817     if (!source.isAvailable()) return FileOpenFailed;
00818     source.waitForData();
00819 
00820     bool canImportLayer = (getMainModel() != 0 &&
00821                            m_paneStack != 0 &&
00822                            m_paneStack->getCurrentPane() != 0);
00823 
00824     if ((status = openAudio(source, mode)) != FileOpenFailed) {
00825         return status;
00826     } else if ((status = openSession(source)) != FileOpenFailed) {
00827         return status;
00828     } else if ((status = openPlaylist(source, mode)) != FileOpenFailed) {
00829         return status;
00830     } else if (!canImportLayer) {
00831         return FileOpenWrongMode;
00832     } else if ((status = openImage(source)) != FileOpenFailed) {
00833         return status;
00834     } else if ((status = openLayer(source)) != FileOpenFailed) {
00835         return status;
00836     } else {
00837         return FileOpenFailed;
00838     }
00839 }
00840 
00841 MainWindowBase::FileOpenStatus
00842 MainWindowBase::openAudio(FileSource source, AudioFileOpenMode mode)
00843 {
00844     std::cerr << "MainWindowBase::openAudio(" << source.getLocation().toStdString() << ")" << std::endl;
00845 
00846     if (!source.isAvailable()) return FileOpenFailed;
00847     source.waitForData();
00848 
00849     m_openingAudioFile = true;
00850 
00851     size_t rate = 0;
00852 
00853     if (Preferences::getInstance()->getResampleOnLoad()) {
00854         rate = m_playSource->getSourceSampleRate();
00855     }
00856 
00857     WaveFileModel *newModel = new WaveFileModel(source, rate);
00858 
00859     if (!newModel->isOK()) {
00860         delete newModel;
00861         m_openingAudioFile = false;
00862         return FileOpenFailed;
00863     }
00864 
00865     std::cerr << "mode = " << mode << std::endl;
00866 
00867     if (mode == AskUser) {
00868         if (getMainModel()) {
00869 
00870             static bool prevSetAsMain = true;
00871             bool setAsMain = true;
00872             
00873             QStringList items;
00874             items << tr("Replace the existing main waveform")
00875                   << tr("Load this file into a new waveform pane");
00876 
00877             bool ok = false;
00878             QString item = ListInputDialog::getItem
00879                 (this, tr("Select target for import"),
00880                  tr("You already have an audio waveform loaded.\nWhat would you like to do with the new audio file?"),
00881                  items, prevSetAsMain ? 0 : 1, &ok);
00882             
00883             if (!ok || item.isEmpty()) {
00884                 delete newModel;
00885                 m_openingAudioFile = false;
00886                 return FileOpenCancelled;
00887             }
00888             
00889             setAsMain = (item == items[0]);
00890             prevSetAsMain = setAsMain;
00891 
00892             if (setAsMain) mode = ReplaceMainModel;
00893             else mode = CreateAdditionalModel;
00894 
00895         } else {
00896             mode = ReplaceMainModel;
00897         }
00898     }
00899 
00900     if (mode == ReplaceCurrentPane) {
00901 
00902         Pane *pane = m_paneStack->getCurrentPane();
00903         if (pane) {
00904             if (getMainModel()) {
00905                 View::ModelSet models(pane->getModels());
00906                 if (models.find(getMainModel()) != models.end()) {
00907                     mode = ReplaceMainModel;
00908                 }
00909             } else {
00910                 mode = ReplaceMainModel;
00911             }
00912         } else {
00913             mode = CreateAdditionalModel;
00914         }
00915     }
00916 
00917     if (mode == CreateAdditionalModel && !getMainModel()) {
00918         mode = ReplaceMainModel;
00919     }
00920 
00921     if (mode == ReplaceMainModel) {
00922 
00923         Model *prevMain = getMainModel();
00924         if (prevMain) {
00925             m_playSource->removeModel(prevMain);
00926             PlayParameterRepository::getInstance()->removeModel(prevMain);
00927         }
00928         PlayParameterRepository::getInstance()->addModel(newModel);
00929 
00930         m_document->setMainModel(newModel);
00931 
00932         setupMenus();
00933 
00934         if (m_sessionFile == "") {
00936             setWindowTitle(tr("%1: %2")
00937                            .arg(QApplication::applicationName())
00938                            .arg(source.getLocation()));
00939             CommandHistory::getInstance()->clear();
00940             CommandHistory::getInstance()->documentSaved();
00941             m_documentModified = false;
00942         } else {
00943             setWindowTitle(tr("%1: %2 [%3]")
00944                            .arg(QApplication::applicationName())
00945                            .arg(QFileInfo(m_sessionFile).fileName())
00946                            .arg(source.getLocation()));
00947             if (m_documentModified) {
00948                 m_documentModified = false;
00949                 documentModified(); // so as to restore "(modified)" window title
00950             }
00951         }
00952 
00953         if (!source.isRemote()) m_audioFile = source.getLocalFilename();
00954 
00955     } else if (mode == CreateAdditionalModel) {
00956 
00957         CommandHistory::getInstance()->startCompoundOperation
00958             (tr("Import \"%1\"").arg(source.getLocation()), true);
00959 
00960         m_document->addImportedModel(newModel);
00961 
00962         AddPaneCommand *command = new AddPaneCommand(this);
00963         CommandHistory::getInstance()->addCommand(command);
00964 
00965         Pane *pane = command->getPane();
00966 
00967         if (m_timeRulerLayer) {
00968             m_document->addLayerToView(pane, m_timeRulerLayer);
00969         }
00970 
00971         Layer *newLayer = m_document->createImportedLayer(newModel);
00972 
00973         if (newLayer) {
00974             m_document->addLayerToView(pane, newLayer);
00975         }
00976         
00977         CommandHistory::getInstance()->endCompoundOperation();
00978 
00979     } else if (mode == ReplaceCurrentPane) {
00980 
00981         // We know there is a current pane, otherwise we would have
00982         // reset the mode to CreateAdditionalModel above; and we know
00983         // the current pane does not contain the main model, otherwise
00984         // we would have reset it to ReplaceMainModel.  But we don't
00985         // know whether the pane contains a waveform model at all.
00986         
00987         Pane *pane = m_paneStack->getCurrentPane();
00988         Layer *replace = 0;
00989 
00990         for (int i = 0; i < pane->getLayerCount(); ++i) {
00991             Layer *layer = pane->getLayer(i);
00992             if (dynamic_cast<WaveformLayer *>(layer)) {
00993                 replace = layer;
00994                 break;
00995             }
00996         }
00997 
00998         CommandHistory::getInstance()->startCompoundOperation
00999             (tr("Import \"%1\"").arg(source.getLocation()), true);
01000 
01001         m_document->addImportedModel(newModel);
01002 
01003         if (replace) {
01004             m_document->removeLayerFromView(pane, replace);
01005         }
01006 
01007         Layer *newLayer = m_document->createImportedLayer(newModel);
01008 
01009         if (newLayer) {
01010             m_document->addLayerToView(pane, newLayer);
01011         }
01012         
01013         CommandHistory::getInstance()->endCompoundOperation();
01014     }
01015 
01016     updateMenuStates();
01017     m_recentFiles.addFile(source.getLocation());
01018     if (!source.isRemote()) {
01019         // for file dialog
01020         registerLastOpenedFilePath(FileFinder::AudioFile,
01021                                    source.getLocalFilename());
01022     }
01023     m_openingAudioFile = false;
01024 
01025     currentPaneChanged(m_paneStack->getCurrentPane());
01026 
01027     return FileOpenSucceeded;
01028 }
01029 
01030 MainWindowBase::FileOpenStatus
01031 MainWindowBase::openPlaylist(FileSource source, AudioFileOpenMode mode)
01032 {
01033     std::set<QString> extensions;
01034     PlaylistFileReader::getSupportedExtensions(extensions);
01035     QString extension = source.getExtension();
01036     if (extensions.find(extension) == extensions.end()) return FileOpenFailed;
01037 
01038     if (!source.isAvailable()) return FileOpenFailed;
01039     source.waitForData();
01040 
01041     PlaylistFileReader reader(source.getLocalFilename());
01042     if (!reader.isOK()) return FileOpenFailed;
01043 
01044     PlaylistFileReader::Playlist playlist = reader.load();
01045 
01046     bool someSuccess = false;
01047 
01048     for (PlaylistFileReader::Playlist::const_iterator i = playlist.begin();
01049          i != playlist.end(); ++i) {
01050 
01051         FileOpenStatus status = openAudio
01052             (FileSource(*i, FileSource::ProgressDialog), mode);
01053 
01054         if (status == FileOpenCancelled) {
01055             return FileOpenCancelled;
01056         }
01057 
01058         if (status == FileOpenSucceeded) {
01059             someSuccess = true;
01060             mode = CreateAdditionalModel;
01061         }
01062     }
01063 
01064     if (someSuccess) return FileOpenSucceeded;
01065     else return FileOpenFailed;
01066 }
01067 
01068 MainWindowBase::FileOpenStatus
01069 MainWindowBase::openLayer(FileSource source)
01070 {
01071     Pane *pane = m_paneStack->getCurrentPane();
01072     
01073     if (!pane) {
01074         // shouldn't happen, as the menu action should have been disabled
01075         std::cerr << "WARNING: MainWindowBase::openLayer: no current pane" << std::endl;
01076         return FileOpenWrongMode;
01077     }
01078 
01079     if (!getMainModel()) {
01080         // shouldn't happen, as the menu action should have been disabled
01081         std::cerr << "WARNING: MainWindowBase::openLayer: No main model -- hence no default sample rate available" << std::endl;
01082         return FileOpenWrongMode;
01083     }
01084 
01085     if (!source.isAvailable()) return FileOpenFailed;
01086     source.waitForData();
01087 
01088     QString path = source.getLocalFilename();
01089 
01090     if (source.getExtension() == "svl" || source.getExtension() == "xml") {
01091 
01092         PaneCallback callback(this);
01093         QFile file(path);
01094         
01095         if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
01096             std::cerr << "ERROR: MainWindowBase::openLayer("
01097                       << source.getLocation().toStdString()
01098                       << "): Failed to open file for reading" << std::endl;
01099             return FileOpenFailed;
01100         }
01101         
01102         SVFileReader reader(m_document, callback, source.getLocation());
01103         connect
01104             (&reader, SIGNAL(modelRegenerationFailed(QString, QString, QString)),
01105              this, SLOT(modelRegenerationFailed(QString, QString, QString)));
01106         connect
01107             (&reader, SIGNAL(modelRegenerationWarning(QString, QString, QString)),
01108              this, SLOT(modelRegenerationWarning(QString, QString, QString)));
01109         reader.setCurrentPane(pane);
01110         
01111         QXmlInputSource inputSource(&file);
01112         reader.parse(inputSource);
01113         
01114         if (!reader.isOK()) {
01115             std::cerr << "ERROR: MainWindowBase::openLayer("
01116                       << source.getLocation().toStdString()
01117                       << "): Failed to read XML file: "
01118                       << reader.getErrorString().toStdString() << std::endl;
01119             return FileOpenFailed;
01120         }
01121 
01122         m_recentFiles.addFile(source.getLocation());
01123 
01124         if (!source.isRemote()) {
01125             registerLastOpenedFilePath(FileFinder::LayerFile, path); // for file dialog
01126         }
01127 
01128         return FileOpenSucceeded;
01129 
01130     } else {
01131         
01132         try {
01133 
01134             Model *model = DataFileReaderFactory::load
01135                 (path, getMainModel()->getSampleRate());
01136         
01137             if (model) {
01138 
01139                 std::cerr << "MainWindowBase::openLayer: Have model" << std::endl;
01140 
01141                 Layer *newLayer = m_document->createImportedLayer(model);
01142 
01143                 if (newLayer) {
01144 
01145                     m_document->addLayerToView(pane, newLayer);
01146                     m_paneStack->setCurrentLayer(pane, newLayer);
01147 
01148                     m_recentFiles.addFile(source.getLocation());
01149                     
01150                     if (!source.isRemote()) {
01151                         registerLastOpenedFilePath
01152                             (FileFinder::LayerFile,
01153                              path); // for file dialog
01154                     }
01155 
01156                     return FileOpenSucceeded;
01157                 }
01158             }
01159         } catch (DataFileReaderFactory::Exception e) {
01160             if (e == DataFileReaderFactory::ImportCancelled) {
01161                 return FileOpenCancelled;
01162             }
01163         }
01164     }
01165     
01166     return FileOpenFailed;
01167 }
01168 
01169 MainWindowBase::FileOpenStatus
01170 MainWindowBase::openImage(FileSource source)
01171 {
01172     Pane *pane = m_paneStack->getCurrentPane();
01173     
01174     if (!pane) {
01175         // shouldn't happen, as the menu action should have been disabled
01176         std::cerr << "WARNING: MainWindowBase::openImage: no current pane" << std::endl;
01177         return FileOpenWrongMode;
01178     }
01179 
01180     if (!m_document->getMainModel()) {
01181         return FileOpenWrongMode;
01182     }
01183 
01184     bool newLayer = false;
01185 
01186     ImageLayer *il = dynamic_cast<ImageLayer *>(pane->getSelectedLayer());
01187     if (!il) {
01188         for (int i = pane->getLayerCount()-1; i >= 0; --i) {
01189             il = dynamic_cast<ImageLayer *>(pane->getLayer(i));
01190             if (il) break;
01191         }
01192     }
01193     if (!il) {
01194         il = dynamic_cast<ImageLayer *>
01195             (m_document->createEmptyLayer(LayerFactory::Image));
01196         if (!il) return FileOpenFailed;
01197         newLayer = true;
01198     }
01199 
01200     // We don't put the image file in Recent Files
01201 
01202     std::cerr << "openImage: trying location \"" << source.getLocation().toStdString() << "\" in image layer" << std::endl;
01203 
01204     if (!il->addImage(m_viewManager->getGlobalCentreFrame(), source.getLocation())) {
01205         if (newLayer) {
01206             m_document->deleteLayer(il); // also releases its model
01207         }
01208         return FileOpenFailed;
01209     } else {
01210         if (newLayer) {
01211             m_document->addLayerToView(pane, il);
01212         }
01213         m_paneStack->setCurrentLayer(pane, il);
01214     }
01215 
01216     return FileOpenSucceeded;
01217 }
01218 
01219 MainWindowBase::FileOpenStatus
01220 MainWindowBase::openSessionFile(QString fileOrUrl)
01221 {
01222     return openSession(FileSource(fileOrUrl, FileSource::ProgressDialog));
01223 }
01224 
01225 MainWindowBase::FileOpenStatus
01226 MainWindowBase::openSession(FileSource source)
01227 {
01228     if (!source.isAvailable()) return FileOpenFailed;
01229     if (source.getExtension() != "sv") return FileOpenFailed;
01230     source.waitForData();
01231 
01232     BZipFileDevice bzFile(source.getLocalFilename());
01233     if (!bzFile.open(QIODevice::ReadOnly)) return FileOpenFailed;
01234 
01235     if (!checkSaveModified()) return FileOpenCancelled;
01236 
01237     QString error;
01238     closeSession();
01239     createDocument();
01240 
01241     PaneCallback callback(this);
01242     m_viewManager->clearSelections();
01243 
01244     SVFileReader reader(m_document, callback, source.getLocation());
01245     connect
01246         (&reader, SIGNAL(modelRegenerationFailed(QString, QString, QString)),
01247          this, SLOT(modelRegenerationFailed(QString, QString, QString)));
01248     connect
01249         (&reader, SIGNAL(modelRegenerationWarning(QString, QString, QString)),
01250          this, SLOT(modelRegenerationWarning(QString, QString, QString)));
01251     QXmlInputSource inputSource(&bzFile);
01252     reader.parse(inputSource);
01253     
01254     if (!reader.isOK()) {
01255         error = tr("SV XML file read error:\n%1").arg(reader.getErrorString());
01256     }
01257     
01258     bzFile.close();
01259 
01260     bool ok = (error == "");
01261 
01262     if (ok) {
01263 
01264         setWindowTitle(tr("%1: %2")
01265                        .arg(QApplication::applicationName())
01266                        .arg(source.getLocation()));
01267 
01268         if (!source.isRemote()) m_sessionFile = source.getLocalFilename();
01269 
01270         setupMenus();
01271 
01272         CommandHistory::getInstance()->clear();
01273         CommandHistory::getInstance()->documentSaved();
01274         m_documentModified = false;
01275         updateMenuStates();
01276 
01277         m_recentFiles.addFile(source.getLocation());
01278 
01279         if (!source.isRemote()) {
01280             // for file dialog
01281             registerLastOpenedFilePath(FileFinder::SessionFile,
01282                                         source.getLocalFilename());
01283         }
01284 
01285     } else {
01286         setWindowTitle(QApplication::applicationName());
01287     }
01288 
01289     return ok ? FileOpenSucceeded : FileOpenFailed;
01290 }
01291 
01292 void
01293 MainWindowBase::createPlayTarget()
01294 {
01295     if (m_playTarget) return;
01296 
01297     m_playTarget = AudioTargetFactory::createCallbackTarget(m_playSource);
01298     if (!m_playTarget) {
01299         QMessageBox::warning
01300             (this, tr("Couldn't open audio device"),
01301              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."),
01302              QMessageBox::Ok);
01303     }
01304 }
01305 
01306 WaveFileModel *
01307 MainWindowBase::getMainModel()
01308 {
01309     if (!m_document) return 0;
01310     return m_document->getMainModel();
01311 }
01312 
01313 const WaveFileModel *
01314 MainWindowBase::getMainModel() const
01315 {
01316     if (!m_document) return 0;
01317     return m_document->getMainModel();
01318 }
01319 
01320 void
01321 MainWindowBase::createDocument()
01322 {
01323     m_document = new Document;
01324 
01325     connect(m_document, SIGNAL(layerAdded(Layer *)),
01326             this, SLOT(layerAdded(Layer *)));
01327     connect(m_document, SIGNAL(layerRemoved(Layer *)),
01328             this, SLOT(layerRemoved(Layer *)));
01329     connect(m_document, SIGNAL(layerAboutToBeDeleted(Layer *)),
01330             this, SLOT(layerAboutToBeDeleted(Layer *)));
01331     connect(m_document, SIGNAL(layerInAView(Layer *, bool)),
01332             this, SLOT(layerInAView(Layer *, bool)));
01333 
01334     connect(m_document, SIGNAL(modelAdded(Model *)),
01335             this, SLOT(modelAdded(Model *)));
01336     connect(m_document, SIGNAL(mainModelChanged(WaveFileModel *)),
01337             this, SLOT(mainModelChanged(WaveFileModel *)));
01338     connect(m_document, SIGNAL(modelAboutToBeDeleted(Model *)),
01339             this, SLOT(modelAboutToBeDeleted(Model *)));
01340 
01341     connect(m_document, SIGNAL(modelGenerationFailed(QString, QString)),
01342             this, SLOT(modelGenerationFailed(QString, QString)));
01343     connect(m_document, SIGNAL(modelRegenerationWarning(QString, QString, QString)),
01344             this, SLOT(modelRegenerationWarning(QString, QString, QString)));
01345     connect(m_document, SIGNAL(modelGenerationFailed(QString, QString)),
01346             this, SLOT(modelGenerationFailed(QString, QString)));
01347     connect(m_document, SIGNAL(modelRegenerationWarning(QString, QString, QString)),
01348             this, SLOT(modelRegenerationWarning(QString, QString, QString)));
01349     connect(m_document, SIGNAL(alignmentFailed(QString, QString)),
01350             this, SLOT(alignmentFailed(QString, QString)));
01351 }
01352 
01353 bool
01354 MainWindowBase::saveSessionFile(QString path)
01355 {
01356     BZipFileDevice bzFile(path);
01357     if (!bzFile.open(QIODevice::WriteOnly)) {
01358         std::cerr << "Failed to open session file \"" << path.toStdString()
01359                   << "\" for writing: "
01360                   << bzFile.errorString().toStdString() << std::endl;
01361         return false;
01362     }
01363 
01364     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
01365 
01366     QTextStream out(&bzFile);
01367     toXml(out);
01368     out.flush();
01369 
01370     QApplication::restoreOverrideCursor();
01371 
01372     if (!bzFile.isOK()) {
01373         QMessageBox::critical(this, tr("Failed to write file"),
01374                               tr("<b>Save failed</b><p>Failed to write to file \"%1\": %2")
01375                               .arg(path).arg(bzFile.errorString()));
01376         bzFile.close();
01377         return false;
01378     }
01379 
01380     bzFile.close();
01381     return true;
01382 }
01383 
01384 void
01385 MainWindowBase::toXml(QTextStream &out)
01386 {
01387     QString indent("  ");
01388 
01389     out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
01390     out << "<!DOCTYPE sonic-visualiser>\n";
01391     out << "<sv>\n";
01392 
01393     m_document->toXml(out, "", "");
01394 
01395     out << "<display>\n";
01396 
01397     out << QString("  <window width=\"%1\" height=\"%2\"/>\n")
01398         .arg(width()).arg(height());
01399 
01400     for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
01401 
01402         Pane *pane = m_paneStack->getPane(i);
01403 
01404         if (pane) {
01405             pane->toXml(out, indent);
01406         }
01407     }
01408 
01409     out << "</display>\n";
01410 
01411     m_viewManager->getSelection().toXml(out);
01412 
01413     out << "</sv>\n";
01414 }
01415 
01416 Pane *
01417 MainWindowBase::addPaneToStack()
01418 {
01419     AddPaneCommand *command = new AddPaneCommand(this);
01420     CommandHistory::getInstance()->addCommand(command);
01421     Pane *pane = command->getPane();
01422     return pane;
01423 }
01424 
01425 void
01426 MainWindowBase::zoomIn()
01427 {
01428     Pane *currentPane = m_paneStack->getCurrentPane();
01429     if (currentPane) currentPane->zoom(true);
01430 }
01431 
01432 void
01433 MainWindowBase::zoomOut()
01434 {
01435     Pane *currentPane = m_paneStack->getCurrentPane();
01436     if (currentPane) currentPane->zoom(false);
01437 }
01438 
01439 void
01440 MainWindowBase::zoomToFit()
01441 {
01442     Pane *currentPane = m_paneStack->getCurrentPane();
01443     if (!currentPane) return;
01444 
01445     Model *model = getMainModel();
01446     if (!model) return;
01447     
01448     size_t start = model->getStartFrame();
01449     size_t end = model->getEndFrame();
01450     if (m_playSource) end = std::max(end, m_playSource->getPlayEndFrame());
01451     size_t pixels = currentPane->width();
01452 
01453     size_t sw = currentPane->getVerticalScaleWidth();
01454     if (pixels > sw * 2) pixels -= sw * 2;
01455     else pixels = 1;
01456     if (pixels > 4) pixels -= 4;
01457 
01458     size_t zoomLevel = (end - start) / pixels;
01459 
01460     currentPane->setZoomLevel(zoomLevel);
01461     currentPane->setCentreFrame((start + end) / 2);
01462 }
01463 
01464 void
01465 MainWindowBase::zoomDefault()
01466 {
01467     Pane *currentPane = m_paneStack->getCurrentPane();
01468     if (currentPane) currentPane->setZoomLevel(1024);
01469 }
01470 
01471 void
01472 MainWindowBase::scrollLeft()
01473 {
01474     Pane *currentPane = m_paneStack->getCurrentPane();
01475     if (currentPane) currentPane->scroll(false, false);
01476 }
01477 
01478 void
01479 MainWindowBase::jumpLeft()
01480 {
01481     Pane *currentPane = m_paneStack->getCurrentPane();
01482     if (currentPane) currentPane->scroll(false, true);
01483 }
01484 
01485 void
01486 MainWindowBase::scrollRight()
01487 {
01488     Pane *currentPane = m_paneStack->getCurrentPane();
01489     if (currentPane) currentPane->scroll(true, false);
01490 }
01491 
01492 void
01493 MainWindowBase::jumpRight()
01494 {
01495     Pane *currentPane = m_paneStack->getCurrentPane();
01496     if (currentPane) currentPane->scroll(true, true);
01497 }
01498 
01499 void
01500 MainWindowBase::showNoOverlays()
01501 {
01502     m_viewManager->setOverlayMode(ViewManager::NoOverlays);
01503 }
01504 
01505 void
01506 MainWindowBase::showMinimalOverlays()
01507 {
01508     m_viewManager->setOverlayMode(ViewManager::MinimalOverlays);
01509 }
01510 
01511 void
01512 MainWindowBase::showStandardOverlays()
01513 {
01514     m_viewManager->setOverlayMode(ViewManager::StandardOverlays);
01515 }
01516 
01517 void
01518 MainWindowBase::showAllOverlays()
01519 {
01520     m_viewManager->setOverlayMode(ViewManager::AllOverlays);
01521 }
01522 
01523 void
01524 MainWindowBase::toggleZoomWheels()
01525 {
01526     if (m_viewManager->getZoomWheelsEnabled()) {
01527         m_viewManager->setZoomWheelsEnabled(false);
01528     } else {
01529         m_viewManager->setZoomWheelsEnabled(true);
01530     }
01531 }
01532 
01533 void
01534 MainWindowBase::togglePropertyBoxes()
01535 {
01536     if (m_paneStack->getLayoutStyle() == PaneStack::NoPropertyStacks) {
01537         if (Preferences::getInstance()->getPropertyBoxLayout() ==
01538             Preferences::VerticallyStacked) {
01539             m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout);
01540         } else {
01541             m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout);
01542         }
01543     } else {
01544         m_paneStack->setLayoutStyle(PaneStack::NoPropertyStacks);
01545     }
01546 }
01547 
01548 void
01549 MainWindowBase::toggleStatusBar()
01550 {
01551     QSettings settings;
01552     settings.beginGroup("MainWindow");
01553     bool sb = settings.value("showstatusbar", true).toBool();
01554 
01555     if (sb) {
01556         statusBar()->hide();
01557     } else {
01558         statusBar()->show();
01559     }
01560 
01561     settings.setValue("showstatusbar", !sb);
01562 
01563     settings.endGroup();
01564 }
01565 
01566 void
01567 MainWindowBase::preferenceChanged(PropertyContainer::PropertyName name)
01568 {
01569     if (name == "Property Box Layout") {
01570         if (m_paneStack->getLayoutStyle() != PaneStack::NoPropertyStacks) {
01571             if (Preferences::getInstance()->getPropertyBoxLayout() ==
01572                 Preferences::VerticallyStacked) {
01573                 m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout);
01574             } else {
01575                 m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout);
01576             }
01577         }
01578     } else if (name == "Background Mode" && m_viewManager) {
01579         Preferences::BackgroundMode mode =
01580             Preferences::getInstance()->getBackgroundMode();
01581         if (mode == Preferences::BackgroundFromTheme) {
01582             m_viewManager->setGlobalDarkBackground(m_initialDarkBackground);
01583         } else if (mode == Preferences::DarkBackground) {
01584             m_viewManager->setGlobalDarkBackground(true);
01585         } else {
01586             m_viewManager->setGlobalDarkBackground(false);
01587         }
01588     }            
01589 }
01590 
01591 void
01592 MainWindowBase::play()
01593 {
01594     if (m_playSource->isPlaying()) {
01595         stop();
01596     } else {
01597         playbackFrameChanged(m_viewManager->getPlaybackFrame());
01598         m_playSource->play(m_viewManager->getPlaybackFrame());
01599     }
01600 }
01601 
01602 void
01603 MainWindowBase::ffwd()
01604 {
01605     if (!getMainModel()) return;
01606 
01607     int frame = m_viewManager->getPlaybackFrame();
01608     ++frame;
01609 
01610     Pane *pane = m_paneStack->getCurrentPane();
01611     Layer *layer = getSnapLayer();
01612     size_t sr = getMainModel()->getSampleRate();
01613 
01614     if (!layer) {
01615 
01616         frame = RealTime::realTime2Frame
01617             (RealTime::frame2RealTime(frame, sr) + RealTime(2, 0), sr);
01618         if (frame > int(getMainModel()->getEndFrame())) {
01619             frame = getMainModel()->getEndFrame();
01620         }
01621 
01622     } else {
01623 
01624         size_t resolution = 0;
01625         if (layer->snapToFeatureFrame(m_paneStack->getCurrentPane(),
01626                                       frame, resolution, Layer::SnapRight)) {
01627             if (pane) frame = pane->alignToReference(frame);
01628         } else {
01629             frame = getMainModel()->getEndFrame();
01630         }
01631     }
01632         
01633     if (frame < 0) frame = 0;
01634 
01635     if (m_viewManager->getPlaySelectionMode()) {
01636         frame = m_viewManager->constrainFrameToSelection(size_t(frame));
01637     }
01638     
01639     m_viewManager->setPlaybackFrame(frame);
01640 }
01641 
01642 void
01643 MainWindowBase::ffwdEnd()
01644 {
01645     if (!getMainModel()) return;
01646 
01647     size_t frame = getMainModel()->getEndFrame();
01648 
01649     if (m_viewManager->getPlaySelectionMode()) {
01650         frame = m_viewManager->constrainFrameToSelection(frame);
01651     }
01652 
01653     m_viewManager->setPlaybackFrame(frame);
01654 }
01655 
01656 void
01657 MainWindowBase::rewind()
01658 {
01659     if (!getMainModel()) return;
01660 
01661     int frame = m_viewManager->getPlaybackFrame();
01662     if (frame > 0) --frame;
01663 
01664     Pane *pane = m_paneStack->getCurrentPane();
01665     Layer *layer = getSnapLayer();
01666     size_t sr = getMainModel()->getSampleRate();
01667     
01668     // when rewinding during playback, we want to allow a period
01669     // following a rewind target point at which the rewind will go to
01670     // the prior point instead of the immediately neighbouring one
01671     if (m_playSource && m_playSource->isPlaying()) {
01672         RealTime ct = RealTime::frame2RealTime(frame, sr);
01673         ct = ct - RealTime::fromSeconds(0.25);
01674         if (ct < RealTime::zeroTime) ct = RealTime::zeroTime;
01675 //        std::cerr << "rewind: frame " << frame << " -> ";
01676         frame = RealTime::realTime2Frame(ct, sr);
01677 //        std::cerr << frame << std::endl;
01678     }
01679 
01680     if (!layer) {
01681         
01682         frame = RealTime::realTime2Frame
01683             (RealTime::frame2RealTime(frame, sr) - RealTime(2, 0), sr);
01684         if (frame < int(getMainModel()->getStartFrame())) {
01685             frame = getMainModel()->getStartFrame();
01686         }
01687 
01688     } else {
01689 
01690         size_t resolution = 0;
01691         if (layer->snapToFeatureFrame(m_paneStack->getCurrentPane(),
01692                                       frame, resolution, Layer::SnapLeft)) {
01693             
01694             if (pane) frame = pane->alignToReference(frame);
01695         } else {
01696             frame = getMainModel()->getStartFrame();
01697         }
01698     }
01699 
01700     if (frame < 0) frame = 0;
01701 
01702     if (m_viewManager->getPlaySelectionMode()) {
01703         frame = m_viewManager->constrainFrameToSelection(size_t(frame));
01704     }
01705 
01706     m_viewManager->setPlaybackFrame(frame);
01707 }
01708 
01709 void
01710 MainWindowBase::rewindStart()
01711 {
01712     if (!getMainModel()) return;
01713 
01714     size_t frame = getMainModel()->getStartFrame();
01715 
01716     if (m_viewManager->getPlaySelectionMode()) {
01717         frame = m_viewManager->constrainFrameToSelection(frame);
01718     }
01719 
01720     m_viewManager->setPlaybackFrame(frame);
01721 }
01722 
01723 Layer *
01724 MainWindowBase::getSnapLayer() const
01725 {
01726     Pane *pane = m_paneStack->getCurrentPane();
01727     if (!pane) return 0;
01728 
01729     Layer *layer = pane->getSelectedLayer();
01730 
01731     if (!dynamic_cast<TimeInstantLayer *>(layer) &&
01732         !dynamic_cast<TimeValueLayer *>(layer) &&
01733         !dynamic_cast<TimeRulerLayer *>(layer)) {
01734 
01735         layer = 0;
01736 
01737         for (int i = pane->getLayerCount(); i > 0; --i) {
01738             Layer *l = pane->getLayer(i-1);
01739             if (dynamic_cast<TimeRulerLayer *>(l)) {
01740                 layer = l;
01741                 break;
01742             }
01743         }
01744     }
01745 
01746     return layer;
01747 }
01748 
01749 void
01750 MainWindowBase::stop()
01751 {
01752     m_playSource->stop();
01753 
01754     if (m_paneStack && m_paneStack->getCurrentPane()) {
01755         updateVisibleRangeDisplay(m_paneStack->getCurrentPane());
01756     } else {
01757         m_myStatusMessage = "";
01758         statusBar()->showMessage("");
01759     }
01760 }
01761 
01762 MainWindowBase::AddPaneCommand::AddPaneCommand(MainWindowBase *mw) :
01763     m_mw(mw),
01764     m_pane(0),
01765     m_prevCurrentPane(0),
01766     m_added(false)
01767 {
01768 }
01769 
01770 MainWindowBase::AddPaneCommand::~AddPaneCommand()
01771 {
01772     if (m_pane && !m_added) {
01773         m_mw->m_paneStack->deletePane(m_pane);
01774     }
01775 }
01776 
01777 QString
01778 MainWindowBase::AddPaneCommand::getName() const
01779 {
01780     return tr("Add Pane");
01781 }
01782 
01783 void
01784 MainWindowBase::AddPaneCommand::execute()
01785 {
01786     if (!m_pane) {
01787         m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane();
01788         m_pane = m_mw->m_paneStack->addPane();
01789 
01790         connect(m_pane, SIGNAL(contextHelpChanged(const QString &)),
01791                 m_mw, SLOT(contextHelpChanged(const QString &)));
01792     } else {
01793         m_mw->m_paneStack->showPane(m_pane);
01794     }
01795 
01796     m_mw->m_paneStack->setCurrentPane(m_pane);
01797     m_added = true;
01798 }
01799 
01800 void
01801 MainWindowBase::AddPaneCommand::unexecute()
01802 {
01803     m_mw->m_paneStack->hidePane(m_pane);
01804     m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane);
01805     m_added = false;
01806 }
01807 
01808 MainWindowBase::RemovePaneCommand::RemovePaneCommand(MainWindowBase *mw, Pane *pane) :
01809     m_mw(mw),
01810     m_pane(pane),
01811     m_added(true)
01812 {
01813 }
01814 
01815 MainWindowBase::RemovePaneCommand::~RemovePaneCommand()
01816 {
01817     if (m_pane && !m_added) {
01818         m_mw->m_paneStack->deletePane(m_pane);
01819     }
01820 }
01821 
01822 QString
01823 MainWindowBase::RemovePaneCommand::getName() const
01824 {
01825     return tr("Remove Pane");
01826 }
01827 
01828 void
01829 MainWindowBase::RemovePaneCommand::execute()
01830 {
01831     m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane();
01832     m_mw->m_paneStack->hidePane(m_pane);
01833     m_added = false;
01834 }
01835 
01836 void
01837 MainWindowBase::RemovePaneCommand::unexecute()
01838 {
01839     m_mw->m_paneStack->showPane(m_pane);
01840     m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane);
01841     m_added = true;
01842 }
01843 
01844 void
01845 MainWindowBase::deleteCurrentPane()
01846 {
01847     CommandHistory::getInstance()->startCompoundOperation
01848         (tr("Delete Pane"), true);
01849 
01850     Pane *pane = m_paneStack->getCurrentPane();
01851     if (pane) {
01852         while (pane->getLayerCount() > 0) {
01853             Layer *layer = pane->getLayer(0);
01854             if (layer) {
01855                 m_document->removeLayerFromView(pane, layer);
01856             } else {
01857                 break;
01858             }
01859         }
01860 
01861         RemovePaneCommand *command = new RemovePaneCommand(this, pane);
01862         CommandHistory::getInstance()->addCommand(command);
01863     }
01864 
01865     CommandHistory::getInstance()->endCompoundOperation();
01866 
01867     updateMenuStates();
01868 }
01869 
01870 void
01871 MainWindowBase::deleteCurrentLayer()
01872 {
01873     Pane *pane = m_paneStack->getCurrentPane();
01874     if (pane) {
01875         Layer *layer = pane->getSelectedLayer();
01876         if (layer) {
01877             m_document->removeLayerFromView(pane, layer);
01878         }
01879     }
01880     updateMenuStates();
01881 }
01882 
01883 void
01884 MainWindowBase::previousPane()
01885 {
01886     if (!m_paneStack) return;
01887 
01888     Pane *currentPane = m_paneStack->getCurrentPane();
01889     if (!currentPane) return;
01890 
01891     for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
01892         if (m_paneStack->getPane(i) == currentPane) {
01893             if (i == 0) return;
01894             m_paneStack->setCurrentPane(m_paneStack->getPane(i-1));
01895             updateMenuStates();
01896             return;
01897         }
01898     }
01899 }
01900 
01901 void
01902 MainWindowBase::nextPane()
01903 {
01904     if (!m_paneStack) return;
01905 
01906     Pane *currentPane = m_paneStack->getCurrentPane();
01907     if (!currentPane) return;
01908 
01909     for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
01910         if (m_paneStack->getPane(i) == currentPane) {
01911             if (i == m_paneStack->getPaneCount()-1) return;
01912             m_paneStack->setCurrentPane(m_paneStack->getPane(i+1));
01913             updateMenuStates();
01914             return;
01915         }
01916     }
01917 }
01918 
01919 void
01920 MainWindowBase::previousLayer()
01921 {
01923 
01924     if (!m_paneStack) return;
01925 
01926     Pane *currentPane = m_paneStack->getCurrentPane();
01927     if (!currentPane) return;
01928 
01929     Layer *currentLayer = currentPane->getSelectedLayer();
01930     if (!currentLayer) return;
01931 
01932     for (int i = 0; i < currentPane->getLayerCount(); ++i) {
01933         if (currentPane->getLayer(i) == currentLayer) {
01934             if (i == 0) return;
01935             m_paneStack->setCurrentLayer(currentPane,
01936                                          currentPane->getLayer(i-1));
01937             updateMenuStates();
01938             return;
01939         }
01940     }
01941 }
01942 
01943 void
01944 MainWindowBase::nextLayer()
01945 {
01947 
01948     if (!m_paneStack) return;
01949 
01950     Pane *currentPane = m_paneStack->getCurrentPane();
01951     if (!currentPane) return;
01952 
01953     Layer *currentLayer = currentPane->getSelectedLayer();
01954     if (!currentLayer) return;
01955 
01956     for (int i = 0; i < currentPane->getLayerCount(); ++i) {
01957         if (currentPane->getLayer(i) == currentLayer) {
01958             if (i == currentPane->getLayerCount()-1) return;
01959             m_paneStack->setCurrentLayer(currentPane,
01960                                          currentPane->getLayer(i+1));
01961             updateMenuStates();
01962             return;
01963         }
01964     }
01965 }
01966 
01967 void
01968 MainWindowBase::playbackFrameChanged(unsigned long frame)
01969 {
01970     if (!(m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
01971 
01972     RealTime now = RealTime::frame2RealTime
01973         (frame, getMainModel()->getSampleRate());
01974 
01975     if (now.sec == m_lastPlayStatusSec) return;
01976 
01977     RealTime then = RealTime::frame2RealTime
01978         (m_playSource->getPlayEndFrame(), getMainModel()->getSampleRate());
01979 
01980     QString nowStr;
01981     QString thenStr;
01982     QString remainingStr;
01983 
01984     if (then.sec > 10) {
01985         nowStr = now.toSecText().c_str();
01986         thenStr = then.toSecText().c_str();
01987         remainingStr = (then - now).toSecText().c_str();
01988         m_lastPlayStatusSec = now.sec;
01989     } else {
01990         nowStr = now.toText(true).c_str();
01991         thenStr = then.toText(true).c_str();
01992         remainingStr = (then - now).toText(true).c_str();
01993     }        
01994 
01995     m_myStatusMessage = tr("Playing: %1 of %2 (%3 remaining)")
01996         .arg(nowStr).arg(thenStr).arg(remainingStr);
01997 
01998     statusBar()->showMessage(m_myStatusMessage);
01999 }
02000 
02001 void
02002 MainWindowBase::globalCentreFrameChanged(unsigned long )
02003 {
02004     if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
02005     Pane *p = 0;
02006     if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
02007     if (!p->getFollowGlobalPan()) return;
02008     updateVisibleRangeDisplay(p);
02009 }
02010 
02011 void
02012 MainWindowBase::viewCentreFrameChanged(View *v, unsigned long )
02013 {
02014     if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
02015     Pane *p = 0;
02016     if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
02017     if (v == p) updateVisibleRangeDisplay(p);
02018 }
02019 
02020 void
02021 MainWindowBase::viewZoomLevelChanged(View *v, unsigned long , bool )
02022 {
02023     if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
02024     Pane *p = 0;
02025     if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
02026     if (v == p) updateVisibleRangeDisplay(p);
02027 }
02028 
02029 void
02030 MainWindowBase::layerAdded(Layer *)
02031 {
02032 //    std::cerr << "MainWindowBase::layerAdded(" << layer << ")" << std::endl;
02033     updateMenuStates();
02034 }
02035 
02036 void
02037 MainWindowBase::layerRemoved(Layer *)
02038 {
02039 //    std::cerr << "MainWindowBase::layerRemoved(" << layer << ")" << std::endl;
02040     updateMenuStates();
02041 }
02042 
02043 void
02044 MainWindowBase::layerAboutToBeDeleted(Layer *layer)
02045 {
02046 //    std::cerr << "MainWindowBase::layerAboutToBeDeleted(" << layer << ")" << std::endl;
02047     if (m_timeRulerLayer && (layer == m_timeRulerLayer)) {
02048 //      std::cerr << "(this is the time ruler layer)" << std::endl;
02049         m_timeRulerLayer = 0;
02050     }
02051 }
02052 
02053 void
02054 MainWindowBase::layerInAView(Layer *layer, bool inAView)
02055 {
02056 //    std::cerr << "MainWindowBase::layerInAView(" << layer << "," << inAView << ")" << std::endl;
02057 
02058     // Check whether we need to add or remove model from play source
02059     Model *model = layer->getModel();
02060     if (model) {
02061         if (inAView) {
02062             m_playSource->addModel(model);
02063         } else {
02064             bool found = false;
02065             for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
02066                 Pane *pane = m_paneStack->getPane(i);
02067                 if (!pane) continue;
02068                 for (int j = 0; j < pane->getLayerCount(); ++j) {
02069                     Layer *pl = pane->getLayer(j);
02070                     if (pl && pl->getModel() == model) {
02071                         found = true;
02072                         break;
02073                     }
02074                 }
02075                 if (found) break;
02076             }
02077             if (!found) m_playSource->removeModel(model);
02078         }
02079     }
02080 
02081     updateMenuStates();
02082 }
02083 
02084 void
02085 MainWindowBase::modelAdded(Model *model)
02086 {
02087 //    std::cerr << "MainWindowBase::modelAdded(" << model << ")" << std::endl;
02088     m_playSource->addModel(model);
02089 }
02090 
02091 void
02092 MainWindowBase::mainModelChanged(WaveFileModel *model)
02093 {
02094 //    std::cerr << "MainWindowBase::mainModelChanged(" << model << ")" << std::endl;
02095     updateDescriptionLabel();
02096     if (model) m_viewManager->setMainModelSampleRate(model->getSampleRate());
02097     if (model && !m_playTarget && m_audioOutput) createPlayTarget();
02098 }
02099 
02100 void
02101 MainWindowBase::modelAboutToBeDeleted(Model *model)
02102 {
02103 //    std::cerr << "MainWindowBase::modelAboutToBeDeleted(" << model << ")" << std::endl;
02104     if (model == m_viewManager->getPlaybackModel()) {
02105         m_viewManager->setPlaybackModel(0);
02106     }
02107     m_playSource->removeModel(model);
02108     FFTDataServer::modelAboutToBeDeleted(model);
02109 }
02110 
02111 void
02112 MainWindowBase::paneDeleteButtonClicked(Pane *pane)
02113 {
02114     bool found = false;
02115     for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
02116         if (m_paneStack->getPane(i) == pane) {
02117             found = true;
02118             break;
02119         }
02120     }
02121     if (!found) {
02122         std::cerr << "MainWindowBase::paneDeleteButtonClicked: Unknown pane "
02123                   << pane << std::endl;
02124         return;
02125     }
02126 
02127     CommandHistory::getInstance()->startCompoundOperation
02128         (tr("Delete Pane"), true);
02129 
02130     while (pane->getLayerCount() > 0) {
02131         Layer *layer = pane->getLayer(0);
02132         if (layer) {
02133             m_document->removeLayerFromView(pane, layer);
02134         } else {
02135             break;
02136         }
02137     }
02138 
02139     RemovePaneCommand *command = new RemovePaneCommand(this, pane);
02140     CommandHistory::getInstance()->addCommand(command);
02141 
02142     CommandHistory::getInstance()->endCompoundOperation();
02143 
02144     updateMenuStates();
02145 }
02146 
02147 void
02148 MainWindowBase::pollOSC()
02149 {
02150     if (!m_oscQueue || m_oscQueue->isEmpty()) return;
02151     std::cerr << "MainWindowBase::pollOSC: have " << m_oscQueue->getMessagesAvailable() << " messages" << std::endl;
02152 
02153     if (m_openingAudioFile) return;
02154 
02155     OSCMessage message = m_oscQueue->readMessage();
02156 
02157     if (message.getTarget() != 0) {
02158         return; 
02159     }
02160 
02161     handleOSCMessage(message);
02162 }
02163 
02164 void
02165 MainWindowBase::inProgressSelectionChanged()
02166 {
02167     Pane *currentPane = 0;
02168     if (m_paneStack) currentPane = m_paneStack->getCurrentPane();
02169     if (currentPane) updateVisibleRangeDisplay(currentPane);
02170 }
02171 
02172 void
02173 MainWindowBase::contextHelpChanged(const QString &s)
02174 {
02175     if (s == "" && m_myStatusMessage != "") {
02176         statusBar()->showMessage(m_myStatusMessage);
02177         return;
02178     }
02179     statusBar()->showMessage(s);
02180 }
02181 
02182 void
02183 MainWindowBase::openHelpUrl(QString url)
02184 {
02185     // This method mostly lifted from Qt Assistant source code
02186 
02187     QProcess *process = new QProcess(this);
02188     connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater()));
02189 
02190     QStringList args;
02191 
02192 #ifdef Q_OS_MAC
02193     args.append(url);
02194     process->start("open", args);
02195 #else
02196 #ifdef Q_OS_WIN32
02197 
02198         QString pf(getenv("ProgramFiles"));
02199         QString command = pf + QString("\\Internet Explorer\\IEXPLORE.EXE");
02200 
02201         args.append(url);
02202         process->start(command, args);
02203 
02204 #else
02205 #ifdef Q_WS_X11
02206     if (!qgetenv("KDE_FULL_SESSION").isEmpty()) {
02207         args.append("exec");
02208         args.append(url);
02209         process->start("kfmclient", args);
02210     } else if (!qgetenv("BROWSER").isEmpty()) {
02211         args.append(url);
02212         process->start(qgetenv("BROWSER"), args);
02213     } else {
02214         args.append(url);
02215         process->start("firefox", args);
02216     }
02217 #endif
02218 #endif
02219 #endif
02220 }
02221 

Generated on Wed Feb 20 15:45:26 2008 for SonicVisualiser by  doxygen 1.5.1