| Chris@45 | 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */ | 
| Chris@45 | 2 | 
| Chris@45 | 3 /* | 
| Chris@45 | 4     Sonic Visualiser | 
| Chris@45 | 5     An audio file viewer and annotation editor. | 
| Chris@45 | 6     Centre for Digital Music, Queen Mary, University of London. | 
| Chris@45 | 7     This file copyright 2006-2007 Chris Cannam and QMUL. | 
| Chris@45 | 8 | 
| Chris@45 | 9     This program is free software; you can redistribute it and/or | 
| Chris@45 | 10     modify it under the terms of the GNU General Public License as | 
| Chris@45 | 11     published by the Free Software Foundation; either version 2 of the | 
| Chris@45 | 12     License, or (at your option) any later version.  See the file | 
| Chris@45 | 13     COPYING included with this distribution for more information. | 
| Chris@45 | 14 */ | 
| Chris@45 | 15 | 
| Chris@45 | 16 #include "MainWindowBase.h" | 
| Chris@46 | 17 #include "Document.h" | 
| Chris@45 | 18 | 
| Chris@45 | 19 | 
| Chris@45 | 20 #include "view/Pane.h" | 
| Chris@45 | 21 #include "view/PaneStack.h" | 
| Chris@45 | 22 #include "data/model/WaveFileModel.h" | 
| Chris@45 | 23 #include "data/model/SparseOneDimensionalModel.h" | 
| Chris@45 | 24 #include "data/model/NoteModel.h" | 
| Chris@45 | 25 #include "data/model/Labeller.h" | 
| Chris@124 | 26 #include "data/model/TabularModel.h" | 
| Chris@45 | 27 #include "view/ViewManager.h" | 
| Chris@45 | 28 | 
| Chris@45 | 29 #include "layer/WaveformLayer.h" | 
| Chris@45 | 30 #include "layer/TimeRulerLayer.h" | 
| Chris@45 | 31 #include "layer/TimeInstantLayer.h" | 
| Chris@45 | 32 #include "layer/TimeValueLayer.h" | 
| Chris@45 | 33 #include "layer/Colour3DPlotLayer.h" | 
| Chris@45 | 34 #include "layer/SliceLayer.h" | 
| Chris@45 | 35 #include "layer/SliceableLayer.h" | 
| Chris@45 | 36 #include "layer/ImageLayer.h" | 
| Chris@184 | 37 #include "layer/NoteLayer.h" | 
| Chris@184 | 38 #include "layer/RegionLayer.h" | 
| Chris@45 | 39 | 
| Chris@45 | 40 #include "widgets/ListInputDialog.h" | 
| Chris@105 | 41 #include "widgets/CommandHistory.h" | 
| Chris@109 | 42 #include "widgets/ProgressDialog.h" | 
| Chris@109 | 43 #include "widgets/MIDIFileImportDialog.h" | 
| Chris@109 | 44 #include "widgets/CSVFormatDialog.h" | 
| Chris@123 | 45 #include "widgets/ModelDataTableDialog.h" | 
| Chris@45 | 46 | 
| Chris@45 | 47 #include "audioio/AudioCallbackPlaySource.h" | 
| Chris@45 | 48 #include "audioio/AudioCallbackPlayTarget.h" | 
| Chris@45 | 49 #include "audioio/AudioTargetFactory.h" | 
| Chris@45 | 50 #include "audioio/PlaySpeedRangeMapper.h" | 
| Chris@45 | 51 #include "data/fileio/DataFileReaderFactory.h" | 
| Chris@45 | 52 #include "data/fileio/PlaylistFileReader.h" | 
| Chris@45 | 53 #include "data/fileio/WavFileWriter.h" | 
| Chris@45 | 54 #include "data/fileio/CSVFileWriter.h" | 
| Chris@45 | 55 #include "data/fileio/MIDIFileWriter.h" | 
| Chris@45 | 56 #include "data/fileio/BZipFileDevice.h" | 
| Chris@45 | 57 #include "data/fileio/FileSource.h" | 
| Chris@152 | 58 #include "data/fileio/AudioFileReaderFactory.h" | 
| Chris@134 | 59 #include "rdf/RDFImporter.h" | 
| Chris@45 | 60 | 
| Chris@45 | 61 #include "data/fft/FFTDataServer.h" | 
| Chris@45 | 62 | 
| Chris@45 | 63 #include "base/RecentFiles.h" | 
| Chris@45 | 64 | 
| Chris@45 | 65 #include "base/PlayParameterRepository.h" | 
| Chris@45 | 66 #include "base/XmlExportable.h" | 
| Chris@45 | 67 #include "base/Profiler.h" | 
| Chris@45 | 68 #include "base/Preferences.h" | 
| Chris@45 | 69 | 
| Chris@45 | 70 #include "data/osc/OSCQueue.h" | 
| Chris@157 | 71 #include "data/midi/MIDIInput.h" | 
| Chris@45 | 72 | 
| Chris@45 | 73 #include <QApplication> | 
| Chris@45 | 74 #include <QMessageBox> | 
| Chris@45 | 75 #include <QGridLayout> | 
| Chris@45 | 76 #include <QLabel> | 
| Chris@45 | 77 #include <QAction> | 
| Chris@45 | 78 #include <QMenuBar> | 
| Chris@45 | 79 #include <QToolBar> | 
| Chris@45 | 80 #include <QInputDialog> | 
| Chris@45 | 81 #include <QStatusBar> | 
| Chris@45 | 82 #include <QTreeView> | 
| Chris@45 | 83 #include <QFile> | 
| Chris@45 | 84 #include <QFileInfo> | 
| Chris@45 | 85 #include <QDir> | 
| Chris@45 | 86 #include <QTextStream> | 
| Chris@45 | 87 #include <QProcess> | 
| Chris@45 | 88 #include <QShortcut> | 
| Chris@45 | 89 #include <QSettings> | 
| Chris@45 | 90 #include <QDateTime> | 
| Chris@45 | 91 #include <QProcess> | 
| Chris@45 | 92 #include <QCheckBox> | 
| Chris@45 | 93 #include <QRegExp> | 
| Chris@45 | 94 #include <QScrollArea> | 
| Chris@168 | 95 #include <QDesktopWidget> | 
| Chris@45 | 96 | 
| Chris@45 | 97 #include <iostream> | 
| Chris@45 | 98 #include <cstdio> | 
| Chris@45 | 99 #include <errno.h> | 
| Chris@45 | 100 | 
| Chris@45 | 101 using std::cerr; | 
| Chris@45 | 102 using std::endl; | 
| Chris@45 | 103 | 
| Chris@45 | 104 using std::vector; | 
| Chris@45 | 105 using std::map; | 
| Chris@45 | 106 using std::set; | 
| Chris@45 | 107 | 
| Chris@45 | 108 | 
| Chris@161 | 109 MainWindowBase::MainWindowBase(bool withAudioOutput, | 
| Chris@161 | 110                                bool withOSCSupport, | 
| Chris@161 | 111                                bool withMIDIInput) : | 
| Chris@45 | 112     m_document(0), | 
| Chris@45 | 113     m_paneStack(0), | 
| Chris@45 | 114     m_viewManager(0), | 
| Chris@45 | 115     m_timeRulerLayer(0), | 
| Chris@45 | 116     m_audioOutput(withAudioOutput), | 
| Chris@45 | 117     m_playSource(0), | 
| Chris@45 | 118     m_playTarget(0), | 
| Chris@113 | 119     m_oscQueue(0), | 
| Chris@113 | 120     m_oscQueueStarter(0), | 
| Chris@157 | 121     m_midiInput(0), | 
| Chris@45 | 122     m_recentFiles("RecentFiles", 20), | 
| Chris@54 | 123     m_recentTransforms("RecentTransforms", 20), | 
| Chris@45 | 124     m_documentModified(false), | 
| Chris@45 | 125     m_openingAudioFile(false), | 
| Chris@45 | 126     m_abandoning(false), | 
| Chris@121 | 127     m_labeller(0), | 
| Chris@121 | 128     m_lastPlayStatusSec(0) | 
| Chris@45 | 129 { | 
| Chris@113 | 130     Profiler profiler("MainWindowBase::MainWindowBase"); | 
| Chris@113 | 131 | 
| Chris@45 | 132     connect(CommandHistory::getInstance(), SIGNAL(commandExecuted()), | 
| Chris@45 | 133 	    this, SLOT(documentModified())); | 
| Chris@45 | 134     connect(CommandHistory::getInstance(), SIGNAL(documentRestored()), | 
| Chris@45 | 135 	    this, SLOT(documentRestored())); | 
| Chris@45 | 136 | 
| Chris@45 | 137     m_viewManager = new ViewManager(); | 
| Chris@45 | 138     connect(m_viewManager, SIGNAL(selectionChanged()), | 
| Chris@45 | 139 	    this, SLOT(updateMenuStates())); | 
| Chris@45 | 140     connect(m_viewManager, SIGNAL(inProgressSelectionChanged()), | 
| Chris@45 | 141 	    this, SLOT(inProgressSelectionChanged())); | 
| Chris@45 | 142 | 
| Chris@105 | 143     // set a sensible default font size for views -- cannot do this | 
| Chris@105 | 144     // in Preferences, which is in base and not supposed to use QtGui | 
| Chris@105 | 145     int viewFontSize = QApplication::font().pointSize() * 0.9; | 
| Chris@105 | 146     QSettings settings; | 
| Chris@105 | 147     settings.beginGroup("Preferences"); | 
| Chris@105 | 148     viewFontSize = settings.value("view-font-size", viewFontSize).toInt(); | 
| Chris@105 | 149     settings.setValue("view-font-size", viewFontSize); | 
| Chris@105 | 150     settings.endGroup(); | 
| Chris@105 | 151 | 
| Chris@45 | 152     Preferences::BackgroundMode mode = | 
| Chris@45 | 153         Preferences::getInstance()->getBackgroundMode(); | 
| Chris@45 | 154     m_initialDarkBackground = m_viewManager->getGlobalDarkBackground(); | 
| Chris@45 | 155     if (mode != Preferences::BackgroundFromTheme) { | 
| Chris@45 | 156         m_viewManager->setGlobalDarkBackground | 
| Chris@45 | 157             (mode == Preferences::DarkBackground); | 
| Chris@45 | 158     } | 
| Chris@45 | 159 | 
| Chris@45 | 160     m_paneStack = new PaneStack(0, m_viewManager); | 
| Chris@45 | 161     connect(m_paneStack, SIGNAL(currentPaneChanged(Pane *)), | 
| Chris@45 | 162 	    this, SLOT(currentPaneChanged(Pane *))); | 
| Chris@45 | 163     connect(m_paneStack, SIGNAL(currentLayerChanged(Pane *, Layer *)), | 
| Chris@45 | 164 	    this, SLOT(currentLayerChanged(Pane *, Layer *))); | 
| Chris@45 | 165     connect(m_paneStack, SIGNAL(rightButtonMenuRequested(Pane *, QPoint)), | 
| Chris@45 | 166             this, SLOT(rightButtonMenuRequested(Pane *, QPoint))); | 
| Chris@45 | 167     connect(m_paneStack, SIGNAL(contextHelpChanged(const QString &)), | 
| Chris@45 | 168             this, SLOT(contextHelpChanged(const QString &))); | 
| Chris@45 | 169     connect(m_paneStack, SIGNAL(paneAdded(Pane *)), | 
| Chris@45 | 170             this, SLOT(paneAdded(Pane *))); | 
| Chris@45 | 171     connect(m_paneStack, SIGNAL(paneHidden(Pane *)), | 
| Chris@45 | 172             this, SLOT(paneHidden(Pane *))); | 
| Chris@45 | 173     connect(m_paneStack, SIGNAL(paneAboutToBeDeleted(Pane *)), | 
| Chris@45 | 174             this, SLOT(paneAboutToBeDeleted(Pane *))); | 
| Chris@45 | 175     connect(m_paneStack, SIGNAL(dropAccepted(Pane *, QStringList)), | 
| Chris@45 | 176             this, SLOT(paneDropAccepted(Pane *, QStringList))); | 
| Chris@45 | 177     connect(m_paneStack, SIGNAL(dropAccepted(Pane *, QString)), | 
| Chris@45 | 178             this, SLOT(paneDropAccepted(Pane *, QString))); | 
| Chris@55 | 179     connect(m_paneStack, SIGNAL(paneDeleteButtonClicked(Pane *)), | 
| Chris@55 | 180             this, SLOT(paneDeleteButtonClicked(Pane *))); | 
| Chris@45 | 181 | 
| Chris@57 | 182     m_playSource = new AudioCallbackPlaySource(m_viewManager, | 
| Chris@57 | 183                                                QApplication::applicationName()); | 
| Chris@45 | 184 | 
| Chris@45 | 185     connect(m_playSource, SIGNAL(sampleRateMismatch(size_t, size_t, bool)), | 
| Chris@45 | 186 	    this,           SLOT(sampleRateMismatch(size_t, size_t, bool))); | 
| Chris@45 | 187     connect(m_playSource, SIGNAL(audioOverloadPluginDisabled()), | 
| Chris@45 | 188             this,           SLOT(audioOverloadPluginDisabled())); | 
| Chris@130 | 189     connect(m_playSource, SIGNAL(audioTimeStretchMultiChannelDisabled()), | 
| Chris@130 | 190             this,           SLOT(audioTimeStretchMultiChannelDisabled())); | 
| Chris@45 | 191 | 
| Chris@45 | 192     connect(m_viewManager, SIGNAL(outputLevelsChanged(float, float)), | 
| Chris@45 | 193 	    this, SLOT(outputLevelsChanged(float, float))); | 
| Chris@45 | 194 | 
| Chris@45 | 195     connect(m_viewManager, SIGNAL(playbackFrameChanged(unsigned long)), | 
| Chris@45 | 196             this, SLOT(playbackFrameChanged(unsigned long))); | 
| Chris@45 | 197 | 
| Chris@45 | 198     connect(m_viewManager, SIGNAL(globalCentreFrameChanged(unsigned long)), | 
| Chris@45 | 199             this, SLOT(globalCentreFrameChanged(unsigned long))); | 
| Chris@45 | 200 | 
| Chris@45 | 201     connect(m_viewManager, SIGNAL(viewCentreFrameChanged(View *, unsigned long)), | 
| Chris@45 | 202             this, SLOT(viewCentreFrameChanged(View *, unsigned long))); | 
| Chris@45 | 203 | 
| Chris@45 | 204     connect(m_viewManager, SIGNAL(viewZoomLevelChanged(View *, unsigned long, bool)), | 
| Chris@45 | 205             this, SLOT(viewZoomLevelChanged(View *, unsigned long, bool))); | 
| Chris@45 | 206 | 
| Chris@45 | 207     connect(Preferences::getInstance(), | 
| Chris@45 | 208             SIGNAL(propertyChanged(PropertyContainer::PropertyName)), | 
| Chris@45 | 209             this, | 
| Chris@45 | 210             SLOT(preferenceChanged(PropertyContainer::PropertyName))); | 
| Chris@45 | 211 | 
| Chris@45 | 212     Labeller::ValueType labellerType = Labeller::ValueFromTwoLevelCounter; | 
| Chris@45 | 213     settings.beginGroup("MainWindow"); | 
| Chris@45 | 214     labellerType = (Labeller::ValueType) | 
| Chris@45 | 215         settings.value("labellertype", (int)labellerType).toInt(); | 
| Chris@45 | 216     int cycle = settings.value("labellercycle", 4).toInt(); | 
| Chris@45 | 217     settings.endGroup(); | 
| Chris@45 | 218 | 
| Chris@45 | 219     m_labeller = new Labeller(labellerType); | 
| Chris@45 | 220     m_labeller->setCounterCycleSize(cycle); | 
| Chris@113 | 221 | 
| Chris@161 | 222     if (withMIDIInput) { | 
| Chris@161 | 223         m_midiInput = new MIDIInput(QApplication::applicationName(), this); | 
| Chris@161 | 224     } | 
| Chris@157 | 225 | 
| Chris@113 | 226     if (withOSCSupport) { | 
| Chris@113 | 227         m_oscQueueStarter = new OSCQueueStarter(this); | 
| Chris@113 | 228         connect(m_oscQueueStarter, SIGNAL(finished()), this, SLOT(oscReady())); | 
| Chris@113 | 229         m_oscQueueStarter->start(); | 
| Chris@113 | 230     } | 
| Chris@45 | 231 } | 
| Chris@45 | 232 | 
| Chris@45 | 233 MainWindowBase::~MainWindowBase() | 
| Chris@45 | 234 { | 
| Chris@177 | 235     std::cerr << "MainWindowBase::~MainWindowBase" << std::endl; | 
| Chris@70 | 236     if (m_playTarget) m_playTarget->shutdown(); | 
| Chris@70 | 237 //    delete m_playTarget; | 
| Chris@45 | 238     delete m_playSource; | 
| Chris@45 | 239     delete m_viewManager; | 
| Chris@45 | 240     delete m_oscQueue; | 
| Chris@157 | 241     delete m_midiInput; | 
| Chris@45 | 242     Profiles::getInstance()->dump(); | 
| Chris@45 | 243 } | 
| Chris@45 | 244 | 
| Chris@113 | 245 void | 
| Chris@168 | 246 MainWindowBase::resizeConstrained(QSize size) | 
| Chris@168 | 247 { | 
| Chris@168 | 248     QDesktopWidget *desktop = QApplication::desktop(); | 
| Chris@168 | 249     QRect available = desktop->availableGeometry(); | 
| Chris@168 | 250     QSize actual(std::min(size.width(), available.width()), | 
| Chris@168 | 251                  std::min(size.height(), available.height())); | 
| Chris@168 | 252     resize(actual); | 
| Chris@168 | 253 } | 
| Chris@168 | 254 | 
| Chris@168 | 255 void | 
| Chris@113 | 256 MainWindowBase::oscReady() | 
| Chris@113 | 257 { | 
| Chris@113 | 258     if (m_oscQueue && m_oscQueue->isOK()) { | 
| Chris@113 | 259         connect(m_oscQueue, SIGNAL(messagesAvailable()), this, SLOT(pollOSC())); | 
| Chris@113 | 260         QTimer *oscTimer = new QTimer(this); | 
| Chris@113 | 261         connect(oscTimer, SIGNAL(timeout()), this, SLOT(pollOSC())); | 
| Chris@113 | 262         oscTimer->start(1000); | 
| Chris@113 | 263         std::cerr << "Finished setting up OSC interface" << std::endl; | 
| Chris@113 | 264     } | 
| Chris@113 | 265 } | 
| Chris@113 | 266 | 
| Chris@45 | 267 QString | 
| Chris@45 | 268 MainWindowBase::getOpenFileName(FileFinder::FileType type) | 
| Chris@45 | 269 { | 
| Chris@45 | 270     FileFinder *ff = FileFinder::getInstance(); | 
| Chris@45 | 271     switch (type) { | 
| Chris@45 | 272     case FileFinder::SessionFile: | 
| Chris@45 | 273         return ff->getOpenFileName(type, m_sessionFile); | 
| Chris@45 | 274     case FileFinder::AudioFile: | 
| Chris@45 | 275         return ff->getOpenFileName(type, m_audioFile); | 
| Chris@45 | 276     case FileFinder::LayerFile: | 
| Chris@45 | 277         return ff->getOpenFileName(type, m_sessionFile); | 
| Chris@45 | 278     case FileFinder::LayerFileNoMidi: | 
| Chris@45 | 279         return ff->getOpenFileName(type, m_sessionFile); | 
| Chris@45 | 280     case FileFinder::SessionOrAudioFile: | 
| Chris@45 | 281         return ff->getOpenFileName(type, m_sessionFile); | 
| Chris@45 | 282     case FileFinder::ImageFile: | 
| Chris@45 | 283         return ff->getOpenFileName(type, m_sessionFile); | 
| Chris@45 | 284     case FileFinder::AnyFile: | 
| Chris@45 | 285         if (getMainModel() != 0 && | 
| Chris@45 | 286             m_paneStack != 0 && | 
| Chris@45 | 287             m_paneStack->getCurrentPane() != 0) { // can import a layer | 
| Chris@45 | 288             return ff->getOpenFileName(FileFinder::AnyFile, m_sessionFile); | 
| Chris@45 | 289         } else { | 
| Chris@45 | 290             return ff->getOpenFileName(FileFinder::SessionOrAudioFile, | 
| Chris@45 | 291                                        m_sessionFile); | 
| Chris@45 | 292         } | 
| Chris@45 | 293     } | 
| Chris@45 | 294     return ""; | 
| Chris@45 | 295 } | 
| Chris@45 | 296 | 
| Chris@45 | 297 QString | 
| Chris@45 | 298 MainWindowBase::getSaveFileName(FileFinder::FileType type) | 
| Chris@45 | 299 { | 
| Chris@45 | 300     FileFinder *ff = FileFinder::getInstance(); | 
| Chris@45 | 301     switch (type) { | 
| Chris@45 | 302     case FileFinder::SessionFile: | 
| Chris@45 | 303         return ff->getSaveFileName(type, m_sessionFile); | 
| Chris@45 | 304     case FileFinder::AudioFile: | 
| Chris@45 | 305         return ff->getSaveFileName(type, m_audioFile); | 
| Chris@45 | 306     case FileFinder::LayerFile: | 
| Chris@45 | 307         return ff->getSaveFileName(type, m_sessionFile); | 
| Chris@45 | 308     case FileFinder::LayerFileNoMidi: | 
| Chris@45 | 309         return ff->getSaveFileName(type, m_sessionFile); | 
| Chris@45 | 310     case FileFinder::SessionOrAudioFile: | 
| Chris@45 | 311         return ff->getSaveFileName(type, m_sessionFile); | 
| Chris@45 | 312     case FileFinder::ImageFile: | 
| Chris@45 | 313         return ff->getSaveFileName(type, m_sessionFile); | 
| Chris@45 | 314     case FileFinder::AnyFile: | 
| Chris@45 | 315         return ff->getSaveFileName(type, m_sessionFile); | 
| Chris@45 | 316     } | 
| Chris@45 | 317     return ""; | 
| Chris@45 | 318 } | 
| Chris@45 | 319 | 
| Chris@45 | 320 void | 
| Chris@45 | 321 MainWindowBase::registerLastOpenedFilePath(FileFinder::FileType type, QString path) | 
| Chris@45 | 322 { | 
| Chris@45 | 323     FileFinder *ff = FileFinder::getInstance(); | 
| Chris@45 | 324     ff->registerLastOpenedFilePath(type, path); | 
| Chris@45 | 325 } | 
| Chris@45 | 326 | 
| Chris@45 | 327 void | 
| Chris@45 | 328 MainWindowBase::updateMenuStates() | 
| Chris@45 | 329 { | 
| Chris@45 | 330     Pane *currentPane = 0; | 
| Chris@45 | 331     Layer *currentLayer = 0; | 
| Chris@45 | 332 | 
| Chris@45 | 333     if (m_paneStack) currentPane = m_paneStack->getCurrentPane(); | 
| Chris@45 | 334     if (currentPane) currentLayer = currentPane->getSelectedLayer(); | 
| Chris@45 | 335 | 
| Chris@73 | 336     bool havePrevPane = false, haveNextPane = false; | 
| Chris@73 | 337     bool havePrevLayer = false, haveNextLayer = false; | 
| Chris@73 | 338 | 
| Chris@73 | 339     if (currentPane) { | 
| Chris@73 | 340         for (int i = 0; i < m_paneStack->getPaneCount(); ++i) { | 
| Chris@73 | 341             if (m_paneStack->getPane(i) == currentPane) { | 
| Chris@73 | 342                 if (i > 0) havePrevPane = true; | 
| Chris@73 | 343                 if (i < m_paneStack->getPaneCount()-1) haveNextPane = true; | 
| Chris@73 | 344                 break; | 
| Chris@73 | 345             } | 
| Chris@73 | 346         } | 
| Chris@73 | 347         if (currentLayer) { | 
| Chris@73 | 348             for (int i = 0; i < currentPane->getLayerCount(); ++i) { | 
| Chris@73 | 349                 if (currentPane->getLayer(i) == currentLayer) { | 
| Chris@73 | 350                     if (i > 0) havePrevLayer = true; | 
| Chris@73 | 351                     if (i < currentPane->getLayerCount()-1) haveNextLayer = true; | 
| Chris@73 | 352                     break; | 
| Chris@73 | 353                 } | 
| Chris@73 | 354             } | 
| Chris@73 | 355         } | 
| Chris@73 | 356     } | 
| Chris@73 | 357 | 
| Chris@45 | 358     bool haveCurrentPane = | 
| Chris@45 | 359         (currentPane != 0); | 
| Chris@45 | 360     bool haveCurrentLayer = | 
| Chris@45 | 361         (haveCurrentPane && | 
| Chris@45 | 362          (currentLayer != 0)); | 
| Chris@45 | 363     bool haveMainModel = | 
| Chris@45 | 364 	(getMainModel() != 0); | 
| Chris@45 | 365     bool havePlayTarget = | 
| Chris@45 | 366 	(m_playTarget != 0); | 
| Chris@45 | 367     bool haveSelection = | 
| Chris@45 | 368 	(m_viewManager && | 
| Chris@45 | 369 	 !m_viewManager->getSelections().empty()); | 
| Chris@45 | 370     bool haveCurrentEditableLayer = | 
| Chris@45 | 371 	(haveCurrentLayer && | 
| Chris@45 | 372 	 currentLayer->isLayerEditable()); | 
| Chris@45 | 373     bool haveCurrentTimeInstantsLayer = | 
| Chris@45 | 374 	(haveCurrentLayer && | 
| Chris@45 | 375 	 dynamic_cast<TimeInstantLayer *>(currentLayer)); | 
| Chris@184 | 376     bool haveCurrentDurationLayer = | 
| Chris@184 | 377 	(haveCurrentLayer && | 
| Chris@184 | 378 	 (dynamic_cast<NoteLayer *>(currentLayer) || | 
| Chris@184 | 379           dynamic_cast<RegionLayer *>(currentLayer))); | 
| Chris@45 | 380     bool haveCurrentColour3DPlot = | 
| Chris@45 | 381         (haveCurrentLayer && | 
| Chris@45 | 382          dynamic_cast<Colour3DPlotLayer *>(currentLayer)); | 
| Chris@45 | 383     bool haveClipboardContents = | 
| Chris@45 | 384         (m_viewManager && | 
| Chris@45 | 385          !m_viewManager->getClipboard().empty()); | 
| Chris@146 | 386     bool haveTabularLayer = | 
| Chris@146 | 387         (haveCurrentLayer && | 
| Chris@146 | 388          dynamic_cast<TabularModel *>(currentLayer->getModel())); | 
| Chris@45 | 389 | 
| Chris@45 | 390     emit canAddPane(haveMainModel); | 
| Chris@45 | 391     emit canDeleteCurrentPane(haveCurrentPane); | 
| Chris@45 | 392     emit canZoom(haveMainModel && haveCurrentPane); | 
| Chris@45 | 393     emit canScroll(haveMainModel && haveCurrentPane); | 
| Chris@45 | 394     emit canAddLayer(haveMainModel && haveCurrentPane); | 
| Chris@45 | 395     emit canImportMoreAudio(haveMainModel); | 
| Chris@45 | 396     emit canImportLayer(haveMainModel && haveCurrentPane); | 
| Chris@45 | 397     emit canExportAudio(haveMainModel); | 
| Chris@45 | 398     emit canExportLayer(haveMainModel && | 
| Chris@45 | 399                         (haveCurrentEditableLayer || haveCurrentColour3DPlot)); | 
| Chris@45 | 400     emit canExportImage(haveMainModel && haveCurrentPane); | 
| Chris@45 | 401     emit canDeleteCurrentLayer(haveCurrentLayer); | 
| Chris@45 | 402     emit canRenameLayer(haveCurrentLayer); | 
| Chris@45 | 403     emit canEditLayer(haveCurrentEditableLayer); | 
| Chris@146 | 404     emit canEditLayerTabular(haveCurrentEditableLayer || haveTabularLayer); | 
| Chris@45 | 405     emit canMeasureLayer(haveCurrentLayer); | 
| Chris@45 | 406     emit canSelect(haveMainModel && haveCurrentPane); | 
| Chris@188 | 407     emit canPlay(haveMainModel && havePlayTarget); | 
| Chris@45 | 408     emit canFfwd(true); | 
| Chris@45 | 409     emit canRewind(true); | 
| Chris@87 | 410     emit canPaste(haveClipboardContents); | 
| Chris@45 | 411     emit canInsertInstant(haveCurrentPane); | 
| Chris@45 | 412     emit canInsertInstantsAtBoundaries(haveCurrentPane && haveSelection); | 
| Chris@184 | 413     emit canInsertItemAtSelection(haveCurrentPane && haveSelection && haveCurrentDurationLayer); | 
| Chris@45 | 414     emit canRenumberInstants(haveCurrentTimeInstantsLayer && haveSelection); | 
| Chris@45 | 415     emit canPlaySelection(haveMainModel && havePlayTarget && haveSelection); | 
| Chris@45 | 416     emit canClearSelection(haveSelection); | 
| Chris@45 | 417     emit canEditSelection(haveSelection && haveCurrentEditableLayer); | 
| Chris@45 | 418     emit canSave(m_sessionFile != "" && m_documentModified); | 
| Chris@73 | 419     emit canSelectPreviousPane(havePrevPane); | 
| Chris@73 | 420     emit canSelectNextPane(haveNextPane); | 
| Chris@73 | 421     emit canSelectPreviousLayer(havePrevLayer); | 
| Chris@73 | 422     emit canSelectNextLayer(haveNextLayer); | 
| Chris@45 | 423 } | 
| Chris@45 | 424 | 
| Chris@45 | 425 void | 
| Chris@45 | 426 MainWindowBase::documentModified() | 
| Chris@45 | 427 { | 
| Chris@45 | 428 //    std::cerr << "MainWindowBase::documentModified" << std::endl; | 
| Chris@45 | 429 | 
| Chris@45 | 430     if (!m_documentModified) { | 
| Chris@45 | 431         //!!! this in subclass implementation? | 
| Chris@45 | 432 	setWindowTitle(tr("%1 (modified)").arg(windowTitle())); | 
| Chris@45 | 433     } | 
| Chris@45 | 434 | 
| Chris@45 | 435     m_documentModified = true; | 
| Chris@45 | 436     updateMenuStates(); | 
| Chris@45 | 437 } | 
| Chris@45 | 438 | 
| Chris@45 | 439 void | 
| Chris@45 | 440 MainWindowBase::documentRestored() | 
| Chris@45 | 441 { | 
| Chris@45 | 442 //    std::cerr << "MainWindowBase::documentRestored" << std::endl; | 
| Chris@45 | 443 | 
| Chris@45 | 444     if (m_documentModified) { | 
| Chris@45 | 445         //!!! this in subclass implementation? | 
| Chris@45 | 446 	QString wt(windowTitle()); | 
| Chris@45 | 447 	wt.replace(tr(" (modified)"), ""); | 
| Chris@45 | 448 	setWindowTitle(wt); | 
| Chris@45 | 449     } | 
| Chris@45 | 450 | 
| Chris@45 | 451     m_documentModified = false; | 
| Chris@45 | 452     updateMenuStates(); | 
| Chris@45 | 453 } | 
| Chris@45 | 454 | 
| Chris@45 | 455 void | 
| Chris@45 | 456 MainWindowBase::playLoopToggled() | 
| Chris@45 | 457 { | 
| Chris@45 | 458     QAction *action = dynamic_cast<QAction *>(sender()); | 
| Chris@45 | 459 | 
| Chris@45 | 460     if (action) { | 
| Chris@45 | 461 	m_viewManager->setPlayLoopMode(action->isChecked()); | 
| Chris@45 | 462     } else { | 
| Chris@45 | 463 	m_viewManager->setPlayLoopMode(!m_viewManager->getPlayLoopMode()); | 
| Chris@45 | 464     } | 
| Chris@45 | 465 } | 
| Chris@45 | 466 | 
| Chris@45 | 467 void | 
| Chris@45 | 468 MainWindowBase::playSelectionToggled() | 
| Chris@45 | 469 { | 
| Chris@45 | 470     QAction *action = dynamic_cast<QAction *>(sender()); | 
| Chris@45 | 471 | 
| Chris@45 | 472     if (action) { | 
| Chris@45 | 473 	m_viewManager->setPlaySelectionMode(action->isChecked()); | 
| Chris@45 | 474     } else { | 
| Chris@45 | 475 	m_viewManager->setPlaySelectionMode(!m_viewManager->getPlaySelectionMode()); | 
| Chris@45 | 476     } | 
| Chris@45 | 477 } | 
| Chris@45 | 478 | 
| Chris@45 | 479 void | 
| Chris@45 | 480 MainWindowBase::playSoloToggled() | 
| Chris@45 | 481 { | 
| Chris@45 | 482     QAction *action = dynamic_cast<QAction *>(sender()); | 
| Chris@45 | 483 | 
| Chris@45 | 484     if (action) { | 
| Chris@45 | 485 	m_viewManager->setPlaySoloMode(action->isChecked()); | 
| Chris@45 | 486     } else { | 
| Chris@45 | 487 	m_viewManager->setPlaySoloMode(!m_viewManager->getPlaySoloMode()); | 
| Chris@45 | 488     } | 
| Chris@45 | 489 | 
| Chris@45 | 490     if (m_viewManager->getPlaySoloMode()) { | 
| Chris@45 | 491         currentPaneChanged(m_paneStack->getCurrentPane()); | 
| Chris@45 | 492     } else { | 
| Chris@45 | 493         m_viewManager->setPlaybackModel(0); | 
| Chris@45 | 494         if (m_playSource) { | 
| Chris@45 | 495             m_playSource->clearSoloModelSet(); | 
| Chris@45 | 496         } | 
| Chris@45 | 497     } | 
| Chris@45 | 498 } | 
| Chris@45 | 499 | 
| Chris@45 | 500 void | 
| Chris@45 | 501 MainWindowBase::currentPaneChanged(Pane *p) | 
| Chris@45 | 502 { | 
| Chris@45 | 503     updateMenuStates(); | 
| Chris@45 | 504     updateVisibleRangeDisplay(p); | 
| Chris@45 | 505 | 
| Chris@45 | 506     if (!p) return; | 
| Chris@45 | 507 | 
| Chris@45 | 508     if (!(m_viewManager && | 
| Chris@45 | 509           m_playSource && | 
| Chris@45 | 510           m_viewManager->getPlaySoloMode())) { | 
| Chris@45 | 511         if (m_viewManager) m_viewManager->setPlaybackModel(0); | 
| Chris@45 | 512         return; | 
| Chris@45 | 513     } | 
| Chris@45 | 514 | 
| Chris@45 | 515     Model *prevPlaybackModel = m_viewManager->getPlaybackModel(); | 
| Chris@60 | 516 | 
| Chris@93 | 517     // What we want here is not the currently playing frame (unless we | 
| Chris@93 | 518     // are about to clear out the audio playback buffers -- which may | 
| Chris@93 | 519     // or may not be possible, depending on the audio driver).  What | 
| Chris@93 | 520     // we want is the frame that was last committed to the soundcard | 
| Chris@93 | 521     // buffers, as the audio driver will continue playing up to that | 
| Chris@93 | 522     // frame before switching to whichever one we decide we want to | 
| Chris@93 | 523     // switch to, regardless of our efforts. | 
| Chris@93 | 524 | 
| Chris@93 | 525     int frame = m_playSource->getCurrentBufferedFrame(); | 
| Chris@93 | 526 | 
| Chris@93 | 527 //    std::cerr << "currentPaneChanged: current frame (in ref model) = " << frame << std::endl; | 
| Chris@45 | 528 | 
| Chris@45 | 529     View::ModelSet soloModels = p->getModels(); | 
| Chris@45 | 530 | 
| Chris@57 | 531     View::ModelSet sources; | 
| Chris@57 | 532     for (View::ModelSet::iterator mi = soloModels.begin(); | 
| Chris@57 | 533          mi != soloModels.end(); ++mi) { | 
| Chris@190 | 534         // If a model in this pane is derived from something else, | 
| Chris@190 | 535         // then we want to play that model as well -- if the model | 
| Chris@190 | 536         // that's derived from it is not something that is itself | 
| Chris@190 | 537         // individually playable (e.g. a waveform) | 
| Chris@190 | 538         if (*mi && | 
| Chris@190 | 539             !dynamic_cast<RangeSummarisableTimeValueModel *>(*mi) && | 
| Chris@190 | 540             (*mi)->getSourceModel()) { | 
| Chris@57 | 541             sources.insert((*mi)->getSourceModel()); | 
| Chris@57 | 542         } | 
| Chris@57 | 543     } | 
| Chris@57 | 544     for (View::ModelSet::iterator mi = sources.begin(); | 
| Chris@57 | 545          mi != sources.end(); ++mi) { | 
| Chris@57 | 546         soloModels.insert(*mi); | 
| Chris@57 | 547     } | 
| Chris@57 | 548 | 
| Chris@60 | 549     //!!! Need an "atomic" way of telling the play source that the | 
| Chris@60 | 550     //playback model has changed, and changing it on ViewManager -- | 
| Chris@60 | 551     //the play source should be making the setPlaybackModel call to | 
| Chris@60 | 552     //ViewManager | 
| Chris@60 | 553 | 
| Chris@45 | 554     for (View::ModelSet::iterator mi = soloModels.begin(); | 
| Chris@45 | 555          mi != soloModels.end(); ++mi) { | 
| Chris@45 | 556         if (dynamic_cast<RangeSummarisableTimeValueModel *>(*mi)) { | 
| Chris@45 | 557             m_viewManager->setPlaybackModel(*mi); | 
| Chris@45 | 558         } | 
| Chris@45 | 559     } | 
| Chris@45 | 560 | 
| Chris@45 | 561     RangeSummarisableTimeValueModel *a = | 
| Chris@45 | 562         dynamic_cast<RangeSummarisableTimeValueModel *>(prevPlaybackModel); | 
| Chris@45 | 563     RangeSummarisableTimeValueModel *b = | 
| Chris@45 | 564         dynamic_cast<RangeSummarisableTimeValueModel *>(m_viewManager-> | 
| Chris@45 | 565                                                         getPlaybackModel()); | 
| Chris@45 | 566 | 
| Chris@45 | 567     m_playSource->setSoloModelSet(soloModels); | 
| Chris@45 | 568 | 
| Chris@45 | 569     if (a && b && (a != b)) { | 
| Chris@60 | 570         if (m_playSource->isPlaying()) m_playSource->play(frame); | 
| Chris@45 | 571     } | 
| Chris@45 | 572 } | 
| Chris@45 | 573 | 
| Chris@45 | 574 void | 
| Chris@45 | 575 MainWindowBase::currentLayerChanged(Pane *p, Layer *) | 
| Chris@45 | 576 { | 
| Chris@45 | 577     updateMenuStates(); | 
| Chris@45 | 578     updateVisibleRangeDisplay(p); | 
| Chris@45 | 579 } | 
| Chris@45 | 580 | 
| Chris@45 | 581 void | 
| Chris@45 | 582 MainWindowBase::selectAll() | 
| Chris@45 | 583 { | 
| Chris@45 | 584     if (!getMainModel()) return; | 
| Chris@45 | 585     m_viewManager->setSelection(Selection(getMainModel()->getStartFrame(), | 
| Chris@45 | 586 					  getMainModel()->getEndFrame())); | 
| Chris@45 | 587 } | 
| Chris@45 | 588 | 
| Chris@45 | 589 void | 
| Chris@45 | 590 MainWindowBase::selectToStart() | 
| Chris@45 | 591 { | 
| Chris@45 | 592     if (!getMainModel()) return; | 
| Chris@45 | 593     m_viewManager->setSelection(Selection(getMainModel()->getStartFrame(), | 
| Chris@45 | 594 					  m_viewManager->getGlobalCentreFrame())); | 
| Chris@45 | 595 } | 
| Chris@45 | 596 | 
| Chris@45 | 597 void | 
| Chris@45 | 598 MainWindowBase::selectToEnd() | 
| Chris@45 | 599 { | 
| Chris@45 | 600     if (!getMainModel()) return; | 
| Chris@45 | 601     m_viewManager->setSelection(Selection(m_viewManager->getGlobalCentreFrame(), | 
| Chris@45 | 602 					  getMainModel()->getEndFrame())); | 
| Chris@45 | 603 } | 
| Chris@45 | 604 | 
| Chris@45 | 605 void | 
| Chris@45 | 606 MainWindowBase::selectVisible() | 
| Chris@45 | 607 { | 
| Chris@45 | 608     Model *model = getMainModel(); | 
| Chris@45 | 609     if (!model) return; | 
| Chris@45 | 610 | 
| Chris@45 | 611     Pane *currentPane = m_paneStack->getCurrentPane(); | 
| Chris@45 | 612     if (!currentPane) return; | 
| Chris@45 | 613 | 
| Chris@45 | 614     size_t startFrame, endFrame; | 
| Chris@45 | 615 | 
| Chris@45 | 616     if (currentPane->getStartFrame() < 0) startFrame = 0; | 
| Chris@45 | 617     else startFrame = currentPane->getStartFrame(); | 
| Chris@45 | 618 | 
| Chris@45 | 619     if (currentPane->getEndFrame() > model->getEndFrame()) endFrame = model->getEndFrame(); | 
| Chris@45 | 620     else endFrame = currentPane->getEndFrame(); | 
| Chris@45 | 621 | 
| Chris@45 | 622     m_viewManager->setSelection(Selection(startFrame, endFrame)); | 
| Chris@45 | 623 } | 
| Chris@45 | 624 | 
| Chris@45 | 625 void | 
| Chris@45 | 626 MainWindowBase::clearSelection() | 
| Chris@45 | 627 { | 
| Chris@45 | 628     m_viewManager->clearSelections(); | 
| Chris@45 | 629 } | 
| Chris@45 | 630 | 
| Chris@45 | 631 void | 
| Chris@45 | 632 MainWindowBase::cut() | 
| Chris@45 | 633 { | 
| Chris@45 | 634     Pane *currentPane = m_paneStack->getCurrentPane(); | 
| Chris@45 | 635     if (!currentPane) return; | 
| Chris@45 | 636 | 
| Chris@45 | 637     Layer *layer = currentPane->getSelectedLayer(); | 
| Chris@45 | 638     if (!layer) return; | 
| Chris@45 | 639 | 
| Chris@45 | 640     Clipboard &clipboard = m_viewManager->getClipboard(); | 
| Chris@45 | 641     clipboard.clear(); | 
| Chris@45 | 642 | 
| Chris@45 | 643     MultiSelection::SelectionList selections = m_viewManager->getSelections(); | 
| Chris@45 | 644 | 
| Chris@45 | 645     CommandHistory::getInstance()->startCompoundOperation(tr("Cut"), true); | 
| Chris@45 | 646 | 
| Chris@45 | 647     for (MultiSelection::SelectionList::iterator i = selections.begin(); | 
| Chris@45 | 648          i != selections.end(); ++i) { | 
| Chris@86 | 649         layer->copy(currentPane, *i, clipboard); | 
| Chris@45 | 650         layer->deleteSelection(*i); | 
| Chris@45 | 651     } | 
| Chris@45 | 652 | 
| Chris@45 | 653     CommandHistory::getInstance()->endCompoundOperation(); | 
| Chris@45 | 654 } | 
| Chris@45 | 655 | 
| Chris@45 | 656 void | 
| Chris@45 | 657 MainWindowBase::copy() | 
| Chris@45 | 658 { | 
| Chris@45 | 659     Pane *currentPane = m_paneStack->getCurrentPane(); | 
| Chris@45 | 660     if (!currentPane) return; | 
| Chris@45 | 661 | 
| Chris@45 | 662     Layer *layer = currentPane->getSelectedLayer(); | 
| Chris@45 | 663     if (!layer) return; | 
| Chris@45 | 664 | 
| Chris@45 | 665     Clipboard &clipboard = m_viewManager->getClipboard(); | 
| Chris@45 | 666     clipboard.clear(); | 
| Chris@45 | 667 | 
| Chris@45 | 668     MultiSelection::SelectionList selections = m_viewManager->getSelections(); | 
| Chris@45 | 669 | 
| Chris@45 | 670     for (MultiSelection::SelectionList::iterator i = selections.begin(); | 
| Chris@45 | 671          i != selections.end(); ++i) { | 
| Chris@86 | 672         layer->copy(currentPane, *i, clipboard); | 
| Chris@45 | 673     } | 
| Chris@45 | 674 } | 
| Chris@45 | 675 | 
| Chris@45 | 676 void | 
| Chris@45 | 677 MainWindowBase::paste() | 
| Chris@45 | 678 { | 
| Chris@45 | 679     Pane *currentPane = m_paneStack->getCurrentPane(); | 
| Chris@45 | 680     if (!currentPane) return; | 
| Chris@45 | 681 | 
| Chris@45 | 682     Layer *layer = currentPane->getSelectedLayer(); | 
| Chris@45 | 683 | 
| Chris@45 | 684     Clipboard &clipboard = m_viewManager->getClipboard(); | 
| Chris@87 | 685 //    Clipboard::PointList contents = clipboard.getPoints(); | 
| Chris@87 | 686 | 
| Chris@98 | 687     bool inCompound = false; | 
| Chris@87 | 688 | 
| Chris@87 | 689     if (!layer || !layer->isLayerEditable()) { | 
| Chris@87 | 690 | 
| Chris@87 | 691         CommandHistory::getInstance()->startCompoundOperation | 
| Chris@87 | 692             (tr("Paste"), true); | 
| Chris@87 | 693 | 
| Chris@87 | 694         // no suitable current layer: create one of the most | 
| Chris@87 | 695         // appropriate sort | 
| Chris@87 | 696         LayerFactory::LayerType type = | 
| Chris@87 | 697             LayerFactory::getInstance()->getLayerTypeForClipboardContents(clipboard); | 
| Chris@87 | 698         layer = m_document->createEmptyLayer(type); | 
| Chris@87 | 699 | 
| Chris@87 | 700         if (!layer) { | 
| Chris@87 | 701             CommandHistory::getInstance()->endCompoundOperation(); | 
| Chris@87 | 702             return; | 
| Chris@45 | 703         } | 
| Chris@87 | 704 | 
| Chris@87 | 705         m_document->addLayerToView(currentPane, layer); | 
| Chris@87 | 706         m_paneStack->setCurrentLayer(currentPane, layer); | 
| Chris@87 | 707 | 
| Chris@87 | 708         inCompound = true; | 
| Chris@45 | 709     } | 
| Chris@45 | 710 | 
| Chris@87 | 711     layer->paste(currentPane, clipboard, 0, true); | 
| Chris@45 | 712 | 
| Chris@87 | 713     if (inCompound) CommandHistory::getInstance()->endCompoundOperation(); | 
| Chris@45 | 714 } | 
| Chris@45 | 715 | 
| Chris@45 | 716 void | 
| Chris@45 | 717 MainWindowBase::deleteSelected() | 
| Chris@45 | 718 { | 
| Chris@45 | 719     if (m_paneStack->getCurrentPane() && | 
| Chris@45 | 720 	m_paneStack->getCurrentPane()->getSelectedLayer()) { | 
| Chris@45 | 721 | 
| Chris@45 | 722         Layer *layer = m_paneStack->getCurrentPane()->getSelectedLayer(); | 
| Chris@45 | 723 | 
| Chris@45 | 724         if (m_viewManager && | 
| Chris@45 | 725             (m_viewManager->getToolMode() == ViewManager::MeasureMode)) { | 
| Chris@45 | 726 | 
| Chris@45 | 727             layer->deleteCurrentMeasureRect(); | 
| Chris@45 | 728 | 
| Chris@45 | 729         } else { | 
| Chris@45 | 730 | 
| Chris@45 | 731             MultiSelection::SelectionList selections = | 
| Chris@45 | 732                 m_viewManager->getSelections(); | 
| Chris@45 | 733 | 
| Chris@45 | 734             for (MultiSelection::SelectionList::iterator i = selections.begin(); | 
| Chris@45 | 735                  i != selections.end(); ++i) { | 
| Chris@45 | 736                 layer->deleteSelection(*i); | 
| Chris@45 | 737             } | 
| Chris@45 | 738 	} | 
| Chris@45 | 739     } | 
| Chris@45 | 740 } | 
| Chris@45 | 741 | 
| Chris@161 | 742 // FrameTimer method | 
| Chris@161 | 743 | 
| Chris@161 | 744 unsigned long | 
| Chris@161 | 745 MainWindowBase::getFrame() const | 
| Chris@161 | 746 { | 
| Chris@161 | 747     if (m_playSource && m_playSource->isPlaying()) { | 
| Chris@161 | 748         return m_playSource->getCurrentPlayingFrame(); | 
| Chris@161 | 749     } else { | 
| Chris@161 | 750         return m_viewManager->getPlaybackFrame(); | 
| Chris@161 | 751     } | 
| Chris@161 | 752 } | 
| Chris@161 | 753 | 
| Chris@45 | 754 void | 
| Chris@45 | 755 MainWindowBase::insertInstant() | 
| Chris@45 | 756 { | 
| Chris@161 | 757     insertInstantAt(getFrame()); | 
| Chris@45 | 758 } | 
| Chris@45 | 759 | 
| Chris@45 | 760 void | 
| Chris@45 | 761 MainWindowBase::insertInstantsAtBoundaries() | 
| Chris@45 | 762 { | 
| Chris@45 | 763     MultiSelection::SelectionList selections = m_viewManager->getSelections(); | 
| Chris@45 | 764     for (MultiSelection::SelectionList::iterator i = selections.begin(); | 
| Chris@45 | 765          i != selections.end(); ++i) { | 
| Chris@45 | 766         size_t start = i->getStartFrame(); | 
| Chris@45 | 767         size_t end = i->getEndFrame(); | 
| Chris@45 | 768         if (start != end) { | 
| Chris@184 | 769             insertInstantAt(start); | 
| Chris@184 | 770             insertInstantAt(end); | 
| Chris@45 | 771         } | 
| Chris@45 | 772     } | 
| Chris@45 | 773 } | 
| Chris@45 | 774 | 
| Chris@45 | 775 void | 
| Chris@45 | 776 MainWindowBase::insertInstantAt(size_t frame) | 
| Chris@45 | 777 { | 
| Chris@45 | 778     Pane *pane = m_paneStack->getCurrentPane(); | 
| Chris@45 | 779     if (!pane) { | 
| Chris@45 | 780         return; | 
| Chris@45 | 781     } | 
| Chris@45 | 782 | 
| Chris@74 | 783     frame = pane->alignFromReference(frame); | 
| Chris@74 | 784 | 
| Chris@45 | 785     Layer *layer = dynamic_cast<TimeInstantLayer *> | 
| Chris@45 | 786         (pane->getSelectedLayer()); | 
| Chris@45 | 787 | 
| Chris@45 | 788     if (!layer) { | 
| Chris@45 | 789         for (int i = pane->getLayerCount(); i > 0; --i) { | 
| Chris@45 | 790             layer = dynamic_cast<TimeInstantLayer *>(pane->getLayer(i - 1)); | 
| Chris@45 | 791             if (layer) break; | 
| Chris@45 | 792         } | 
| Chris@45 | 793 | 
| Chris@45 | 794         if (!layer) { | 
| Chris@45 | 795             CommandHistory::getInstance()->startCompoundOperation | 
| Chris@45 | 796                 (tr("Add Point"), true); | 
| Chris@45 | 797             layer = m_document->createEmptyLayer(LayerFactory::TimeInstants); | 
| Chris@45 | 798             if (layer) { | 
| Chris@45 | 799                 m_document->addLayerToView(pane, layer); | 
| Chris@45 | 800                 m_paneStack->setCurrentLayer(pane, layer); | 
| Chris@45 | 801             } | 
| Chris@45 | 802             CommandHistory::getInstance()->endCompoundOperation(); | 
| Chris@45 | 803         } | 
| Chris@45 | 804     } | 
| Chris@45 | 805 | 
| Chris@45 | 806     if (layer) { | 
| Chris@45 | 807 | 
| Chris@45 | 808         Model *model = layer->getModel(); | 
| Chris@45 | 809         SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *> | 
| Chris@45 | 810             (model); | 
| Chris@45 | 811 | 
| Chris@45 | 812         if (sodm) { | 
| Chris@45 | 813             SparseOneDimensionalModel::Point point(frame, ""); | 
| Chris@45 | 814 | 
| Chris@45 | 815             SparseOneDimensionalModel::Point prevPoint(0); | 
| Chris@45 | 816             bool havePrevPoint = false; | 
| Chris@45 | 817 | 
| Chris@45 | 818             SparseOneDimensionalModel::EditCommand *command = | 
| Chris@45 | 819                 new SparseOneDimensionalModel::EditCommand(sodm, tr("Add Point")); | 
| Chris@45 | 820 | 
| Chris@74 | 821             if (m_labeller->requiresPrevPoint()) { | 
| Chris@45 | 822 | 
| Chris@45 | 823                 SparseOneDimensionalModel::PointList prevPoints = | 
| Chris@45 | 824                     sodm->getPreviousPoints(frame); | 
| Chris@45 | 825 | 
| Chris@45 | 826                 if (!prevPoints.empty()) { | 
| Chris@45 | 827                     prevPoint = *prevPoints.begin(); | 
| Chris@45 | 828                     havePrevPoint = true; | 
| Chris@45 | 829                 } | 
| Chris@45 | 830             } | 
| Chris@45 | 831 | 
| Chris@45 | 832             if (m_labeller) { | 
| Chris@45 | 833 | 
| Chris@45 | 834                 m_labeller->setSampleRate(sodm->getSampleRate()); | 
| Chris@45 | 835 | 
| Chris@74 | 836                 if (m_labeller->actingOnPrevPoint()) { | 
| Chris@45 | 837                     command->deletePoint(prevPoint); | 
| Chris@45 | 838                 } | 
| Chris@45 | 839 | 
| Chris@45 | 840                 m_labeller->label<SparseOneDimensionalModel::Point> | 
| Chris@45 | 841                     (point, havePrevPoint ? &prevPoint : 0); | 
| Chris@45 | 842 | 
| Chris@74 | 843                 if (m_labeller->actingOnPrevPoint()) { | 
| Chris@45 | 844                     command->addPoint(prevPoint); | 
| Chris@45 | 845                 } | 
| Chris@45 | 846             } | 
| Chris@45 | 847 | 
| Chris@45 | 848             command->addPoint(point); | 
| Chris@45 | 849 | 
| Chris@45 | 850             command->setName(tr("Add Point at %1 s") | 
| Chris@45 | 851                              .arg(RealTime::frame2RealTime | 
| Chris@45 | 852                                   (frame, | 
| Chris@45 | 853                                    sodm->getSampleRate()) | 
| Chris@45 | 854                                   .toText(false).c_str())); | 
| Chris@45 | 855 | 
| Chris@108 | 856             Command *c = command->finish(); | 
| Chris@108 | 857             if (c) CommandHistory::getInstance()->addCommand(c, false); | 
| Chris@45 | 858         } | 
| Chris@45 | 859     } | 
| Chris@45 | 860 } | 
| Chris@45 | 861 | 
| Chris@45 | 862 void | 
| Chris@184 | 863 MainWindowBase::insertItemAtSelection() | 
| Chris@184 | 864 { | 
| Chris@184 | 865     MultiSelection::SelectionList selections = m_viewManager->getSelections(); | 
| Chris@184 | 866     for (MultiSelection::SelectionList::iterator i = selections.begin(); | 
| Chris@184 | 867          i != selections.end(); ++i) { | 
| Chris@184 | 868         size_t start = i->getStartFrame(); | 
| Chris@184 | 869         size_t end = i->getEndFrame(); | 
| Chris@184 | 870         if (start < end) { | 
| Chris@184 | 871             insertItemAt(start, end - start); | 
| Chris@184 | 872         } | 
| Chris@184 | 873     } | 
| Chris@184 | 874 } | 
| Chris@184 | 875 | 
| Chris@184 | 876 void | 
| Chris@184 | 877 MainWindowBase::insertItemAt(size_t frame, size_t duration) | 
| Chris@184 | 878 { | 
| Chris@184 | 879     Pane *pane = m_paneStack->getCurrentPane(); | 
| Chris@184 | 880     if (!pane) { | 
| Chris@184 | 881         return; | 
| Chris@184 | 882     } | 
| Chris@184 | 883 | 
| Chris@184 | 884     // ugh! | 
| Chris@184 | 885 | 
| Chris@184 | 886     size_t alignedStart = pane->alignFromReference(frame); | 
| Chris@184 | 887     size_t alignedEnd = pane->alignFromReference(frame + duration); | 
| Chris@184 | 888     if (alignedStart >= alignedEnd) return; | 
| Chris@184 | 889     size_t alignedDuration = alignedEnd - alignedStart; | 
| Chris@184 | 890 | 
| Chris@184 | 891     Command *c = 0; | 
| Chris@184 | 892 | 
| Chris@184 | 893     QString name = tr("Add Item at %1 s") | 
| Chris@184 | 894         .arg(RealTime::frame2RealTime | 
| Chris@184 | 895              (alignedStart, | 
| Chris@184 | 896               getMainModel()->getSampleRate()) | 
| Chris@184 | 897              .toText(false).c_str()); | 
| Chris@184 | 898 | 
| Chris@184 | 899     Layer *layer = pane->getSelectedLayer(); | 
| Chris@184 | 900     if (!layer) return; | 
| Chris@184 | 901 | 
| Chris@184 | 902     RegionModel *rm = dynamic_cast<RegionModel *>(layer->getModel()); | 
| Chris@184 | 903     if (rm) { | 
| Chris@184 | 904         RegionModel::Point point(alignedStart, | 
| Chris@185 | 905                                  rm->getValueMaximum() + 1, | 
| Chris@184 | 906                                  alignedDuration, | 
| Chris@184 | 907                                  ""); | 
| Chris@184 | 908         RegionModel::EditCommand *command = | 
| Chris@184 | 909             new RegionModel::EditCommand(rm, tr("Add Point")); | 
| Chris@184 | 910         command->addPoint(point); | 
| Chris@184 | 911         command->setName(name); | 
| Chris@184 | 912         c = command->finish(); | 
| Chris@184 | 913     } | 
| Chris@184 | 914 | 
| Chris@184 | 915     if (c) { | 
| Chris@184 | 916         CommandHistory::getInstance()->addCommand(c, false); | 
| Chris@184 | 917         return; | 
| Chris@184 | 918     } | 
| Chris@184 | 919 | 
| Chris@184 | 920     NoteModel *nm = dynamic_cast<NoteModel *>(layer->getModel()); | 
| Chris@184 | 921     if (nm) { | 
| Chris@184 | 922         NoteModel::Point point(alignedStart, | 
| Chris@184 | 923                                rm->getValueMinimum(), | 
| Chris@184 | 924                                alignedDuration, | 
| Chris@184 | 925                                1.f, | 
| Chris@184 | 926                                ""); | 
| Chris@184 | 927         NoteModel::EditCommand *command = | 
| Chris@184 | 928             new NoteModel::EditCommand(nm, tr("Add Point")); | 
| Chris@184 | 929         command->addPoint(point); | 
| Chris@184 | 930         command->setName(name); | 
| Chris@184 | 931         c = command->finish(); | 
| Chris@184 | 932     } | 
| Chris@184 | 933 | 
| Chris@184 | 934     if (c) { | 
| Chris@184 | 935         CommandHistory::getInstance()->addCommand(c, false); | 
| Chris@184 | 936         return; | 
| Chris@184 | 937     } | 
| Chris@184 | 938 } | 
| Chris@184 | 939 | 
| Chris@184 | 940 void | 
| Chris@45 | 941 MainWindowBase::renumberInstants() | 
| Chris@45 | 942 { | 
| Chris@45 | 943     Pane *pane = m_paneStack->getCurrentPane(); | 
| Chris@45 | 944     if (!pane) return; | 
| Chris@45 | 945 | 
| Chris@45 | 946     Layer *layer = dynamic_cast<TimeInstantLayer *>(pane->getSelectedLayer()); | 
| Chris@45 | 947     if (!layer) return; | 
| Chris@45 | 948 | 
| Chris@45 | 949     MultiSelection ms(m_viewManager->getSelection()); | 
| Chris@45 | 950 | 
| Chris@45 | 951     Model *model = layer->getModel(); | 
| Chris@45 | 952     SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *> | 
| Chris@45 | 953         (model); | 
| Chris@45 | 954     if (!sodm) return; | 
| Chris@45 | 955 | 
| Chris@45 | 956     if (!m_labeller) return; | 
| Chris@45 | 957 | 
| Chris@45 | 958     Labeller labeller(*m_labeller); | 
| Chris@45 | 959     labeller.setSampleRate(sodm->getSampleRate()); | 
| Chris@45 | 960 | 
| Chris@45 | 961     // This uses a command | 
| Chris@45 | 962 | 
| Chris@45 | 963     labeller.labelAll<SparseOneDimensionalModel::Point>(*sodm, &ms); | 
| Chris@45 | 964 } | 
| Chris@45 | 965 | 
| Chris@45 | 966 MainWindowBase::FileOpenStatus | 
| Chris@45 | 967 MainWindowBase::open(QString fileOrUrl, AudioFileOpenMode mode) | 
| Chris@45 | 968 { | 
| Chris@134 | 969     ProgressDialog dialog(tr("Opening file or URL..."), true, 2000, this); | 
| Chris@134 | 970     connect(&dialog, SIGNAL(showing()), this, SIGNAL(hideSplash())); | 
| Chris@109 | 971     return open(FileSource(fileOrUrl, &dialog), mode); | 
| Chris@45 | 972 } | 
| Chris@45 | 973 | 
| Chris@45 | 974 MainWindowBase::FileOpenStatus | 
| Chris@45 | 975 MainWindowBase::open(FileSource source, AudioFileOpenMode mode) | 
| Chris@45 | 976 { | 
| Chris@45 | 977     FileOpenStatus status; | 
| Chris@45 | 978 | 
| Chris@45 | 979     if (!source.isAvailable()) return FileOpenFailed; | 
| Chris@45 | 980     source.waitForData(); | 
| Chris@45 | 981 | 
| Chris@45 | 982     bool canImportLayer = (getMainModel() != 0 && | 
| Chris@45 | 983                            m_paneStack != 0 && | 
| Chris@45 | 984                            m_paneStack->getCurrentPane() != 0); | 
| Chris@45 | 985 | 
| Chris@152 | 986     bool rdf = (source.getExtension().toLower() == "rdf" || | 
| Chris@152 | 987                 source.getExtension().toLower() == "n3" || | 
| Chris@152 | 988                 source.getExtension().toLower() == "ttl"); | 
| Chris@152 | 989 | 
| Chris@152 | 990     bool audio = AudioFileReaderFactory::getKnownExtensions().contains | 
| Chris@152 | 991         (source.getExtension().toLower()); | 
| Chris@145 | 992 | 
| Chris@145 | 993     bool rdfSession = false; | 
| Chris@145 | 994     if (rdf) { | 
| Chris@145 | 995         RDFImporter::RDFDocumentType rdfType = | 
| Chris@145 | 996             RDFImporter::identifyDocumentType | 
| Chris@145 | 997             (QUrl::fromLocalFile(source.getLocalFilename()).toString()); | 
| Chris@148 | 998 //        std::cerr << "RDF type: " << (int)rdfType << std::endl; | 
| Chris@145 | 999         if (rdfType == RDFImporter::AudioRefAndAnnotations || | 
| Chris@145 | 1000             rdfType == RDFImporter::AudioRef) { | 
| Chris@145 | 1001             rdfSession = true; | 
| Chris@145 | 1002         } else if (rdfType == RDFImporter::NotRDF) { | 
| Chris@145 | 1003             rdf = false; | 
| Chris@145 | 1004         } | 
| Chris@145 | 1005     } | 
| Chris@145 | 1006 | 
| Chris@145 | 1007     if (rdf) { | 
| Chris@145 | 1008         if (rdfSession) { | 
| Chris@147 | 1009             bool cancel = false; | 
| Chris@147 | 1010             if (!canImportLayer || shouldCreateNewSessionForRDFAudio(&cancel)) { | 
| Chris@145 | 1011                 return openSession(source); | 
| Chris@147 | 1012             } else if (cancel) { | 
| Chris@147 | 1013                 return FileOpenCancelled; | 
| Chris@145 | 1014             } else { | 
| Chris@145 | 1015                 return openLayer(source); | 
| Chris@145 | 1016             } | 
| Chris@145 | 1017         } else { | 
| Chris@145 | 1018             if ((status = openSession(source)) != FileOpenFailed) { | 
| Chris@145 | 1019                 return status; | 
| Chris@145 | 1020             } else if (!canImportLayer) { | 
| Chris@145 | 1021                 return FileOpenWrongMode; | 
| Chris@145 | 1022             } else if ((status = openLayer(source)) != FileOpenFailed) { | 
| Chris@145 | 1023                 return status; | 
| Chris@145 | 1024             } else { | 
| Chris@145 | 1025                 return FileOpenFailed; | 
| Chris@145 | 1026             } | 
| Chris@145 | 1027         } | 
| Chris@145 | 1028     } | 
| Chris@145 | 1029 | 
| Chris@152 | 1030     if (audio && (status = openAudio(source, mode)) != FileOpenFailed) { | 
| Chris@45 | 1031         return status; | 
| Chris@45 | 1032     } else if ((status = openSession(source)) != FileOpenFailed) { | 
| Chris@45 | 1033 	return status; | 
| Chris@45 | 1034     } else if ((status = openPlaylist(source, mode)) != FileOpenFailed) { | 
| Chris@45 | 1035         return status; | 
| Chris@45 | 1036     } else if (!canImportLayer) { | 
| Chris@45 | 1037         return FileOpenWrongMode; | 
| Chris@45 | 1038     } else if ((status = openImage(source)) != FileOpenFailed) { | 
| Chris@45 | 1039         return status; | 
| Chris@45 | 1040     } else if ((status = openLayer(source)) != FileOpenFailed) { | 
| Chris@45 | 1041         return status; | 
| Chris@45 | 1042     } else { | 
| Chris@45 | 1043 	return FileOpenFailed; | 
| Chris@45 | 1044     } | 
| Chris@45 | 1045 } | 
| Chris@45 | 1046 | 
| Chris@45 | 1047 MainWindowBase::FileOpenStatus | 
| Chris@45 | 1048 MainWindowBase::openAudio(FileSource source, AudioFileOpenMode mode) | 
| Chris@45 | 1049 { | 
| Chris@132 | 1050 //    std::cerr << "MainWindowBase::openAudio(" << source.getLocation().toStdString() << ")" << std::endl; | 
| Chris@45 | 1051 | 
| Chris@45 | 1052     if (!source.isAvailable()) return FileOpenFailed; | 
| Chris@45 | 1053     source.waitForData(); | 
| Chris@45 | 1054 | 
| Chris@45 | 1055     m_openingAudioFile = true; | 
| Chris@45 | 1056 | 
| Chris@45 | 1057     size_t rate = 0; | 
| Chris@45 | 1058 | 
| Chris@45 | 1059     if (Preferences::getInstance()->getResampleOnLoad()) { | 
| Chris@45 | 1060         rate = m_playSource->getSourceSampleRate(); | 
| Chris@45 | 1061     } | 
| Chris@45 | 1062 | 
| Chris@45 | 1063     WaveFileModel *newModel = new WaveFileModel(source, rate); | 
| Chris@45 | 1064 | 
| Chris@45 | 1065     if (!newModel->isOK()) { | 
| Chris@45 | 1066 	delete newModel; | 
| Chris@45 | 1067         m_openingAudioFile = false; | 
| Chris@45 | 1068 	return FileOpenFailed; | 
| Chris@45 | 1069     } | 
| Chris@45 | 1070 | 
| Chris@132 | 1071 //    std::cerr << "mode = " << mode << std::endl; | 
| Chris@45 | 1072 | 
| Chris@45 | 1073     if (mode == AskUser) { | 
| Chris@45 | 1074         if (getMainModel()) { | 
| Chris@45 | 1075 | 
| Chris@147 | 1076             QSettings settings; | 
| Chris@147 | 1077             settings.beginGroup("MainWindow"); | 
| Chris@147 | 1078             bool prevSetAsMain = settings.value("newsessionforaudio", true).toBool(); | 
| Chris@147 | 1079             settings.endGroup(); | 
| Chris@45 | 1080             bool setAsMain = true; | 
| Chris@45 | 1081 | 
| Chris@45 | 1082             QStringList items; | 
| Chris@45 | 1083             items << tr("Replace the existing main waveform") | 
| Chris@45 | 1084                   << tr("Load this file into a new waveform pane"); | 
| Chris@45 | 1085 | 
| Chris@45 | 1086             bool ok = false; | 
| Chris@45 | 1087             QString item = ListInputDialog::getItem | 
| Chris@45 | 1088                 (this, tr("Select target for import"), | 
| Chris@155 | 1089                  tr("<b>Select a target for import</b><p>You already have an audio waveform loaded.<br>What would you like to do with the new audio file?"), | 
| Chris@45 | 1090                  items, prevSetAsMain ? 0 : 1, &ok); | 
| Chris@45 | 1091 | 
| Chris@45 | 1092             if (!ok || item.isEmpty()) { | 
| Chris@45 | 1093                 delete newModel; | 
| Chris@45 | 1094                 m_openingAudioFile = false; | 
| Chris@45 | 1095                 return FileOpenCancelled; | 
| Chris@45 | 1096             } | 
| Chris@45 | 1097 | 
| Chris@45 | 1098             setAsMain = (item == items[0]); | 
| Chris@147 | 1099             settings.beginGroup("MainWindow"); | 
| Chris@147 | 1100             settings.setValue("newsessionforaudio", setAsMain); | 
| Chris@147 | 1101             settings.endGroup(); | 
| Chris@45 | 1102 | 
| Chris@45 | 1103             if (setAsMain) mode = ReplaceMainModel; | 
| Chris@45 | 1104             else mode = CreateAdditionalModel; | 
| Chris@45 | 1105 | 
| Chris@45 | 1106         } else { | 
| Chris@45 | 1107             mode = ReplaceMainModel; | 
| Chris@45 | 1108         } | 
| Chris@45 | 1109     } | 
| Chris@45 | 1110 | 
| Chris@45 | 1111     if (mode == ReplaceCurrentPane) { | 
| Chris@45 | 1112 | 
| Chris@45 | 1113         Pane *pane = m_paneStack->getCurrentPane(); | 
| Chris@45 | 1114         if (pane) { | 
| Chris@45 | 1115             if (getMainModel()) { | 
| Chris@45 | 1116                 View::ModelSet models(pane->getModels()); | 
| Chris@45 | 1117                 if (models.find(getMainModel()) != models.end()) { | 
| Chris@45 | 1118                     mode = ReplaceMainModel; | 
| Chris@45 | 1119                 } | 
| Chris@45 | 1120             } else { | 
| Chris@45 | 1121                 mode = ReplaceMainModel; | 
| Chris@45 | 1122             } | 
| Chris@45 | 1123         } else { | 
| Chris@45 | 1124             mode = CreateAdditionalModel; | 
| Chris@45 | 1125         } | 
| Chris@45 | 1126     } | 
| Chris@45 | 1127 | 
| Chris@45 | 1128     if (mode == CreateAdditionalModel && !getMainModel()) { | 
| Chris@45 | 1129         mode = ReplaceMainModel; | 
| Chris@45 | 1130     } | 
| Chris@45 | 1131 | 
| Chris@164 | 1132     emit activity(tr("Import audio file \"%1\"").arg(source.getLocation())); | 
| Chris@164 | 1133 | 
| Chris@45 | 1134     if (mode == ReplaceMainModel) { | 
| Chris@45 | 1135 | 
| Chris@45 | 1136         Model *prevMain = getMainModel(); | 
| Chris@45 | 1137         if (prevMain) { | 
| Chris@45 | 1138             m_playSource->removeModel(prevMain); | 
| Chris@108 | 1139             PlayParameterRepository::getInstance()->removePlayable(prevMain); | 
| Chris@45 | 1140         } | 
| Chris@108 | 1141         PlayParameterRepository::getInstance()->addPlayable(newModel); | 
| Chris@45 | 1142 | 
| Chris@45 | 1143 	m_document->setMainModel(newModel); | 
| Chris@45 | 1144 | 
| Chris@45 | 1145 	setupMenus(); | 
| Chris@45 | 1146 | 
| Chris@45 | 1147 	if (m_sessionFile == "") { | 
| Chris@45 | 1148             //!!! shouldn't be dealing directly with title from here -- call a method | 
| Chris@57 | 1149 	    setWindowTitle(tr("%1: %2") | 
| Chris@57 | 1150                            .arg(QApplication::applicationName()) | 
| Chris@45 | 1151                            .arg(source.getLocation())); | 
| Chris@45 | 1152 	    CommandHistory::getInstance()->clear(); | 
| Chris@45 | 1153 	    CommandHistory::getInstance()->documentSaved(); | 
| Chris@45 | 1154 	    m_documentModified = false; | 
| Chris@45 | 1155 	} else { | 
| Chris@57 | 1156 	    setWindowTitle(tr("%1: %2 [%3]") | 
| Chris@57 | 1157                            .arg(QApplication::applicationName()) | 
| Chris@45 | 1158 			   .arg(QFileInfo(m_sessionFile).fileName()) | 
| Chris@45 | 1159 			   .arg(source.getLocation())); | 
| Chris@45 | 1160 	    if (m_documentModified) { | 
| Chris@45 | 1161 		m_documentModified = false; | 
| Chris@45 | 1162 		documentModified(); // so as to restore "(modified)" window title | 
| Chris@45 | 1163 	    } | 
| Chris@45 | 1164 	} | 
| Chris@45 | 1165 | 
| Chris@45 | 1166         if (!source.isRemote()) m_audioFile = source.getLocalFilename(); | 
| Chris@45 | 1167 | 
| Chris@45 | 1168     } else if (mode == CreateAdditionalModel) { | 
| Chris@45 | 1169 | 
| Chris@45 | 1170 	CommandHistory::getInstance()->startCompoundOperation | 
| Chris@45 | 1171 	    (tr("Import \"%1\"").arg(source.getLocation()), true); | 
| Chris@45 | 1172 | 
| Chris@45 | 1173 	m_document->addImportedModel(newModel); | 
| Chris@45 | 1174 | 
| Chris@45 | 1175 	AddPaneCommand *command = new AddPaneCommand(this); | 
| Chris@45 | 1176 	CommandHistory::getInstance()->addCommand(command); | 
| Chris@45 | 1177 | 
| Chris@45 | 1178 	Pane *pane = command->getPane(); | 
| Chris@45 | 1179 | 
| Chris@47 | 1180         if (m_timeRulerLayer) { | 
| Chris@47 | 1181             m_document->addLayerToView(pane, m_timeRulerLayer); | 
| Chris@47 | 1182         } | 
| Chris@45 | 1183 | 
| Chris@45 | 1184 	Layer *newLayer = m_document->createImportedLayer(newModel); | 
| Chris@45 | 1185 | 
| Chris@45 | 1186 	if (newLayer) { | 
| Chris@45 | 1187 	    m_document->addLayerToView(pane, newLayer); | 
| Chris@45 | 1188 	} | 
| Chris@45 | 1189 | 
| Chris@45 | 1190 	CommandHistory::getInstance()->endCompoundOperation(); | 
| Chris@45 | 1191 | 
| Chris@45 | 1192     } else if (mode == ReplaceCurrentPane) { | 
| Chris@45 | 1193 | 
| Chris@45 | 1194         // We know there is a current pane, otherwise we would have | 
| Chris@45 | 1195         // reset the mode to CreateAdditionalModel above; and we know | 
| Chris@45 | 1196         // the current pane does not contain the main model, otherwise | 
| Chris@45 | 1197         // we would have reset it to ReplaceMainModel.  But we don't | 
| Chris@45 | 1198         // know whether the pane contains a waveform model at all. | 
| Chris@45 | 1199 | 
| Chris@45 | 1200         Pane *pane = m_paneStack->getCurrentPane(); | 
| Chris@45 | 1201         Layer *replace = 0; | 
| Chris@45 | 1202 | 
| Chris@45 | 1203         for (int i = 0; i < pane->getLayerCount(); ++i) { | 
| Chris@45 | 1204             Layer *layer = pane->getLayer(i); | 
| Chris@45 | 1205             if (dynamic_cast<WaveformLayer *>(layer)) { | 
| Chris@45 | 1206                 replace = layer; | 
| Chris@45 | 1207                 break; | 
| Chris@45 | 1208             } | 
| Chris@45 | 1209         } | 
| Chris@45 | 1210 | 
| Chris@45 | 1211 	CommandHistory::getInstance()->startCompoundOperation | 
| Chris@45 | 1212 	    (tr("Import \"%1\"").arg(source.getLocation()), true); | 
| Chris@45 | 1213 | 
| Chris@45 | 1214 	m_document->addImportedModel(newModel); | 
| Chris@45 | 1215 | 
| Chris@45 | 1216         if (replace) { | 
| Chris@45 | 1217             m_document->removeLayerFromView(pane, replace); | 
| Chris@45 | 1218         } | 
| Chris@45 | 1219 | 
| Chris@45 | 1220 	Layer *newLayer = m_document->createImportedLayer(newModel); | 
| Chris@45 | 1221 | 
| Chris@45 | 1222 	if (newLayer) { | 
| Chris@45 | 1223 	    m_document->addLayerToView(pane, newLayer); | 
| Chris@45 | 1224 	} | 
| Chris@45 | 1225 | 
| Chris@45 | 1226 	CommandHistory::getInstance()->endCompoundOperation(); | 
| Chris@45 | 1227     } | 
| Chris@45 | 1228 | 
| Chris@45 | 1229     updateMenuStates(); | 
| Chris@45 | 1230     m_recentFiles.addFile(source.getLocation()); | 
| Chris@45 | 1231     if (!source.isRemote()) { | 
| Chris@45 | 1232         // for file dialog | 
| Chris@45 | 1233         registerLastOpenedFilePath(FileFinder::AudioFile, | 
| Chris@45 | 1234                                    source.getLocalFilename()); | 
| Chris@45 | 1235     } | 
| Chris@45 | 1236     m_openingAudioFile = false; | 
| Chris@45 | 1237 | 
| Chris@45 | 1238     currentPaneChanged(m_paneStack->getCurrentPane()); | 
| Chris@45 | 1239 | 
| Chris@45 | 1240     return FileOpenSucceeded; | 
| Chris@45 | 1241 } | 
| Chris@45 | 1242 | 
| Chris@45 | 1243 MainWindowBase::FileOpenStatus | 
| Chris@45 | 1244 MainWindowBase::openPlaylist(FileSource source, AudioFileOpenMode mode) | 
| Chris@45 | 1245 { | 
| Chris@135 | 1246     std::cerr << "MainWindowBase::openPlaylist(" << source.getLocation().toStdString() << ")" << std::endl; | 
| Chris@135 | 1247 | 
| Chris@45 | 1248     std::set<QString> extensions; | 
| Chris@45 | 1249     PlaylistFileReader::getSupportedExtensions(extensions); | 
| Chris@152 | 1250     QString extension = source.getExtension().toLower(); | 
| Chris@45 | 1251     if (extensions.find(extension) == extensions.end()) return FileOpenFailed; | 
| Chris@45 | 1252 | 
| Chris@45 | 1253     if (!source.isAvailable()) return FileOpenFailed; | 
| Chris@45 | 1254     source.waitForData(); | 
| Chris@45 | 1255 | 
| Chris@45 | 1256     PlaylistFileReader reader(source.getLocalFilename()); | 
| Chris@45 | 1257     if (!reader.isOK()) return FileOpenFailed; | 
| Chris@45 | 1258 | 
| Chris@45 | 1259     PlaylistFileReader::Playlist playlist = reader.load(); | 
| Chris@45 | 1260 | 
| Chris@45 | 1261     bool someSuccess = false; | 
| Chris@45 | 1262 | 
| Chris@45 | 1263     for (PlaylistFileReader::Playlist::const_iterator i = playlist.begin(); | 
| Chris@45 | 1264          i != playlist.end(); ++i) { | 
| Chris@45 | 1265 | 
| Chris@134 | 1266         ProgressDialog dialog(tr("Opening playlist..."), true, 2000, this); | 
| Chris@134 | 1267         connect(&dialog, SIGNAL(showing()), this, SIGNAL(hideSplash())); | 
| Chris@109 | 1268         FileOpenStatus status = openAudio(FileSource(*i, &dialog), mode); | 
| Chris@45 | 1269 | 
| Chris@45 | 1270         if (status == FileOpenCancelled) { | 
| Chris@45 | 1271             return FileOpenCancelled; | 
| Chris@45 | 1272         } | 
| Chris@45 | 1273 | 
| Chris@45 | 1274         if (status == FileOpenSucceeded) { | 
| Chris@45 | 1275             someSuccess = true; | 
| Chris@45 | 1276             mode = CreateAdditionalModel; | 
| Chris@45 | 1277         } | 
| Chris@45 | 1278     } | 
| Chris@45 | 1279 | 
| Chris@45 | 1280     if (someSuccess) return FileOpenSucceeded; | 
| Chris@45 | 1281     else return FileOpenFailed; | 
| Chris@45 | 1282 } | 
| Chris@45 | 1283 | 
| Chris@45 | 1284 MainWindowBase::FileOpenStatus | 
| Chris@45 | 1285 MainWindowBase::openLayer(FileSource source) | 
| Chris@45 | 1286 { | 
| Chris@135 | 1287     std::cerr << "MainWindowBase::openLayer(" << source.getLocation().toStdString() << ")" << std::endl; | 
| Chris@135 | 1288 | 
| Chris@45 | 1289     Pane *pane = m_paneStack->getCurrentPane(); | 
| Chris@45 | 1290 | 
| Chris@45 | 1291     if (!pane) { | 
| Chris@45 | 1292 	// shouldn't happen, as the menu action should have been disabled | 
| Chris@45 | 1293 	std::cerr << "WARNING: MainWindowBase::openLayer: no current pane" << std::endl; | 
| Chris@45 | 1294 	return FileOpenWrongMode; | 
| Chris@45 | 1295     } | 
| Chris@45 | 1296 | 
| Chris@45 | 1297     if (!getMainModel()) { | 
| Chris@45 | 1298 	// shouldn't happen, as the menu action should have been disabled | 
| Chris@45 | 1299 	std::cerr << "WARNING: MainWindowBase::openLayer: No main model -- hence no default sample rate available" << std::endl; | 
| Chris@45 | 1300 	return FileOpenWrongMode; | 
| Chris@45 | 1301     } | 
| Chris@45 | 1302 | 
| Chris@45 | 1303     if (!source.isAvailable()) return FileOpenFailed; | 
| Chris@45 | 1304     source.waitForData(); | 
| Chris@45 | 1305 | 
| Chris@45 | 1306     QString path = source.getLocalFilename(); | 
| Chris@45 | 1307 | 
| Chris@145 | 1308     RDFImporter::RDFDocumentType rdfType = | 
| Chris@145 | 1309         RDFImporter::identifyDocumentType(QUrl::fromLocalFile(path).toString()); | 
| Chris@145 | 1310 | 
| Chris@148 | 1311 //    std::cerr << "RDF type:  (in layer) " << (int) rdfType << std::endl; | 
| Chris@148 | 1312 | 
| Chris@145 | 1313     if (rdfType != RDFImporter::NotRDF) { | 
| Chris@145 | 1314 | 
| Chris@145 | 1315         return openLayersFromRDF(source); | 
| Chris@134 | 1316 | 
| Chris@152 | 1317     } else if (source.getExtension().toLower() == "svl" || | 
| Chris@152 | 1318                (source.getExtension().toLower() == "xml" && | 
| Chris@140 | 1319                 (SVFileReader::identifyXmlFile(source.getLocalFilename()) | 
| Chris@140 | 1320                  == SVFileReader::SVLayerFile))) { | 
| Chris@45 | 1321 | 
| Chris@45 | 1322         PaneCallback callback(this); | 
| Chris@45 | 1323         QFile file(path); | 
| Chris@45 | 1324 | 
| Chris@45 | 1325         if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { | 
| Chris@45 | 1326             std::cerr << "ERROR: MainWindowBase::openLayer(" | 
| Chris@45 | 1327                       << source.getLocation().toStdString() | 
| Chris@45 | 1328                       << "): Failed to open file for reading" << std::endl; | 
| Chris@45 | 1329             return FileOpenFailed; | 
| Chris@45 | 1330         } | 
| Chris@45 | 1331 | 
| Chris@45 | 1332         SVFileReader reader(m_document, callback, source.getLocation()); | 
| Chris@79 | 1333         connect | 
| Chris@79 | 1334             (&reader, SIGNAL(modelRegenerationFailed(QString, QString, QString)), | 
| Chris@79 | 1335              this, SLOT(modelRegenerationFailed(QString, QString, QString))); | 
| Chris@79 | 1336         connect | 
| Chris@79 | 1337             (&reader, SIGNAL(modelRegenerationWarning(QString, QString, QString)), | 
| Chris@79 | 1338              this, SLOT(modelRegenerationWarning(QString, QString, QString))); | 
| Chris@45 | 1339         reader.setCurrentPane(pane); | 
| Chris@45 | 1340 | 
| Chris@45 | 1341         QXmlInputSource inputSource(&file); | 
| Chris@45 | 1342         reader.parse(inputSource); | 
| Chris@45 | 1343 | 
| Chris@45 | 1344         if (!reader.isOK()) { | 
| Chris@45 | 1345             std::cerr << "ERROR: MainWindowBase::openLayer(" | 
| Chris@45 | 1346                       << source.getLocation().toStdString() | 
| Chris@45 | 1347                       << "): Failed to read XML file: " | 
| Chris@45 | 1348                       << reader.getErrorString().toStdString() << std::endl; | 
| Chris@45 | 1349             return FileOpenFailed; | 
| Chris@45 | 1350         } | 
| Chris@45 | 1351 | 
| Chris@164 | 1352         emit activity(tr("Import layer XML file \"%1\"").arg(source.getLocation())); | 
| Chris@164 | 1353 | 
| Chris@45 | 1354         m_recentFiles.addFile(source.getLocation()); | 
| Chris@45 | 1355 | 
| Chris@45 | 1356         if (!source.isRemote()) { | 
| Chris@45 | 1357             registerLastOpenedFilePath(FileFinder::LayerFile, path); // for file dialog | 
| Chris@45 | 1358         } | 
| Chris@45 | 1359 | 
| Chris@75 | 1360         return FileOpenSucceeded; | 
| Chris@75 | 1361 | 
| Chris@45 | 1362     } else { | 
| Chris@45 | 1363 | 
| Chris@45 | 1364         try { | 
| Chris@45 | 1365 | 
| Chris@109 | 1366             MIDIFileImportDialog midiDlg(this); | 
| Chris@109 | 1367 | 
| Chris@109 | 1368             Model *model = DataFileReaderFactory::loadNonCSV | 
| Chris@109 | 1369                 (path, &midiDlg, getMainModel()->getSampleRate()); | 
| Chris@45 | 1370 | 
| Chris@109 | 1371             if (!model) { | 
| Chris@196 | 1372                 CSVFormat format(path); | 
| Chris@196 | 1373                 format.setSampleRate(getMainModel()->getSampleRate()); | 
| Chris@196 | 1374                 CSVFormatDialog *dialog = new CSVFormatDialog(this, format); | 
| Chris@109 | 1375                 if (dialog->exec() == QDialog::Accepted) { | 
| Chris@109 | 1376                     model = DataFileReaderFactory::loadCSV | 
| Chris@109 | 1377                         (path, dialog->getFormat(), | 
| Chris@109 | 1378                          getMainModel()->getSampleRate()); | 
| Chris@109 | 1379                 } | 
| Chris@109 | 1380             } | 
| Chris@109 | 1381 | 
| Chris@45 | 1382             if (model) { | 
| Chris@45 | 1383 | 
| Chris@45 | 1384                 std::cerr << "MainWindowBase::openLayer: Have model" << std::endl; | 
| Chris@45 | 1385 | 
| Chris@164 | 1386                 emit activity(tr("Import MIDI file \"%1\"").arg(source.getLocation())); | 
| Chris@164 | 1387 | 
| Chris@45 | 1388                 Layer *newLayer = m_document->createImportedLayer(model); | 
| Chris@45 | 1389 | 
| Chris@45 | 1390                 if (newLayer) { | 
| Chris@45 | 1391 | 
| Chris@45 | 1392                     m_document->addLayerToView(pane, newLayer); | 
| Chris@88 | 1393                     m_paneStack->setCurrentLayer(pane, newLayer); | 
| Chris@88 | 1394 | 
| Chris@45 | 1395                     m_recentFiles.addFile(source.getLocation()); | 
| Chris@45 | 1396 | 
| Chris@45 | 1397                     if (!source.isRemote()) { | 
| Chris@45 | 1398                         registerLastOpenedFilePath | 
| Chris@45 | 1399                             (FileFinder::LayerFile, | 
| Chris@45 | 1400                              path); // for file dialog | 
| Chris@45 | 1401                     } | 
| Chris@88 | 1402 | 
| Chris@45 | 1403                     return FileOpenSucceeded; | 
| Chris@45 | 1404                 } | 
| Chris@45 | 1405             } | 
| Chris@45 | 1406         } catch (DataFileReaderFactory::Exception e) { | 
| Chris@45 | 1407             if (e == DataFileReaderFactory::ImportCancelled) { | 
| Chris@45 | 1408                 return FileOpenCancelled; | 
| Chris@45 | 1409             } | 
| Chris@45 | 1410         } | 
| Chris@45 | 1411     } | 
| Chris@45 | 1412 | 
| Chris@45 | 1413     return FileOpenFailed; | 
| Chris@45 | 1414 } | 
| Chris@45 | 1415 | 
| Chris@45 | 1416 MainWindowBase::FileOpenStatus | 
| Chris@45 | 1417 MainWindowBase::openImage(FileSource source) | 
| Chris@45 | 1418 { | 
| Chris@135 | 1419     std::cerr << "MainWindowBase::openImage(" << source.getLocation().toStdString() << ")" << std::endl; | 
| Chris@135 | 1420 | 
| Chris@45 | 1421     Pane *pane = m_paneStack->getCurrentPane(); | 
| Chris@45 | 1422 | 
| Chris@45 | 1423     if (!pane) { | 
| Chris@45 | 1424 	// shouldn't happen, as the menu action should have been disabled | 
| Chris@45 | 1425 	std::cerr << "WARNING: MainWindowBase::openImage: no current pane" << std::endl; | 
| Chris@45 | 1426 	return FileOpenWrongMode; | 
| Chris@45 | 1427     } | 
| Chris@45 | 1428 | 
| Chris@45 | 1429     if (!m_document->getMainModel()) { | 
| Chris@45 | 1430         return FileOpenWrongMode; | 
| Chris@45 | 1431     } | 
| Chris@45 | 1432 | 
| Chris@45 | 1433     bool newLayer = false; | 
| Chris@45 | 1434 | 
| Chris@45 | 1435     ImageLayer *il = dynamic_cast<ImageLayer *>(pane->getSelectedLayer()); | 
| Chris@45 | 1436     if (!il) { | 
| Chris@45 | 1437         for (int i = pane->getLayerCount()-1; i >= 0; --i) { | 
| Chris@45 | 1438             il = dynamic_cast<ImageLayer *>(pane->getLayer(i)); | 
| Chris@45 | 1439             if (il) break; | 
| Chris@45 | 1440         } | 
| Chris@45 | 1441     } | 
| Chris@45 | 1442     if (!il) { | 
| Chris@45 | 1443         il = dynamic_cast<ImageLayer *> | 
| Chris@45 | 1444             (m_document->createEmptyLayer(LayerFactory::Image)); | 
| Chris@45 | 1445         if (!il) return FileOpenFailed; | 
| Chris@45 | 1446         newLayer = true; | 
| Chris@45 | 1447     } | 
| Chris@45 | 1448 | 
| Chris@45 | 1449     // We don't put the image file in Recent Files | 
| Chris@45 | 1450 | 
| Chris@45 | 1451     std::cerr << "openImage: trying location \"" << source.getLocation().toStdString() << "\" in image layer" << std::endl; | 
| Chris@45 | 1452 | 
| Chris@45 | 1453     if (!il->addImage(m_viewManager->getGlobalCentreFrame(), source.getLocation())) { | 
| Chris@45 | 1454         if (newLayer) { | 
| Chris@52 | 1455             m_document->deleteLayer(il); // also releases its model | 
| Chris@45 | 1456         } | 
| Chris@45 | 1457         return FileOpenFailed; | 
| Chris@45 | 1458     } else { | 
| Chris@45 | 1459         if (newLayer) { | 
| Chris@45 | 1460             m_document->addLayerToView(pane, il); | 
| Chris@45 | 1461         } | 
| Chris@45 | 1462         m_paneStack->setCurrentLayer(pane, il); | 
| Chris@45 | 1463     } | 
| Chris@45 | 1464 | 
| Chris@45 | 1465     return FileOpenSucceeded; | 
| Chris@45 | 1466 } | 
| Chris@45 | 1467 | 
| Chris@45 | 1468 MainWindowBase::FileOpenStatus | 
| Chris@45 | 1469 MainWindowBase::openSessionFile(QString fileOrUrl) | 
| Chris@45 | 1470 { | 
| Chris@134 | 1471     ProgressDialog dialog(tr("Opening session..."), true, 2000, this); | 
| Chris@134 | 1472     connect(&dialog, SIGNAL(showing()), this, SIGNAL(hideSplash())); | 
| Chris@109 | 1473     return openSession(FileSource(fileOrUrl, &dialog)); | 
| Chris@45 | 1474 } | 
| Chris@45 | 1475 | 
| Chris@45 | 1476 MainWindowBase::FileOpenStatus | 
| Chris@45 | 1477 MainWindowBase::openSession(FileSource source) | 
| Chris@45 | 1478 { | 
| Chris@135 | 1479     std::cerr << "MainWindowBase::openSession(" << source.getLocation().toStdString() << ")" << std::endl; | 
| Chris@135 | 1480 | 
| Chris@45 | 1481     if (!source.isAvailable()) return FileOpenFailed; | 
| Chris@145 | 1482     source.waitForData(); | 
| Chris@141 | 1483 | 
| Chris@152 | 1484     if (source.getExtension().toLower() != "sv") { | 
| Chris@145 | 1485 | 
| Chris@145 | 1486         RDFImporter::RDFDocumentType rdfType = | 
| Chris@145 | 1487             RDFImporter::identifyDocumentType | 
| Chris@145 | 1488             (QUrl::fromLocalFile(source.getLocalFilename()).toString()); | 
| Chris@145 | 1489 | 
| Chris@148 | 1490 //        std::cerr << "RDF type: " << (int)rdfType << std::endl; | 
| Chris@148 | 1491 | 
| Chris@145 | 1492         if (rdfType == RDFImporter::AudioRefAndAnnotations || | 
| Chris@145 | 1493             rdfType == RDFImporter::AudioRef) { | 
| Chris@145 | 1494             return openSessionFromRDF(source); | 
| Chris@145 | 1495         } else if (rdfType != RDFImporter::NotRDF) { | 
| Chris@145 | 1496             return FileOpenFailed; | 
| Chris@145 | 1497         } | 
| Chris@145 | 1498 | 
| Chris@152 | 1499         if (source.getExtension().toLower() == "xml") { | 
| Chris@140 | 1500             if (SVFileReader::identifyXmlFile(source.getLocalFilename()) == | 
| Chris@140 | 1501                 SVFileReader::SVSessionFile) { | 
| Chris@140 | 1502                 std::cerr << "This XML file looks like a session file, attempting to open it as a session" << std::endl; | 
| Chris@140 | 1503             } else { | 
| Chris@140 | 1504                 return FileOpenFailed; | 
| Chris@140 | 1505             } | 
| Chris@140 | 1506         } else { | 
| Chris@140 | 1507             return FileOpenFailed; | 
| Chris@140 | 1508         } | 
| Chris@140 | 1509     } | 
| Chris@45 | 1510 | 
| Chris@140 | 1511     QXmlInputSource *inputSource = 0; | 
| Chris@140 | 1512     BZipFileDevice *bzFile = 0; | 
| Chris@140 | 1513     QFile *rawFile = 0; | 
| Chris@140 | 1514 | 
| Chris@152 | 1515     if (source.getExtension().toLower() == "sv") { | 
| Chris@140 | 1516         bzFile = new BZipFileDevice(source.getLocalFilename()); | 
| Chris@140 | 1517         if (!bzFile->open(QIODevice::ReadOnly)) { | 
| Chris@140 | 1518             delete bzFile; | 
| Chris@140 | 1519             return FileOpenFailed; | 
| Chris@140 | 1520         } | 
| Chris@140 | 1521         inputSource = new QXmlInputSource(bzFile); | 
| Chris@140 | 1522     } else { | 
| Chris@140 | 1523         rawFile = new QFile(source.getLocalFilename()); | 
| Chris@140 | 1524         inputSource = new QXmlInputSource(rawFile); | 
| Chris@140 | 1525     } | 
| Chris@140 | 1526 | 
| Chris@140 | 1527     if (!checkSaveModified()) { | 
| Chris@140 | 1528         if (bzFile) bzFile->close(); | 
| Chris@140 | 1529         delete inputSource; | 
| Chris@140 | 1530         delete bzFile; | 
| Chris@140 | 1531         delete rawFile; | 
| Chris@140 | 1532         return FileOpenCancelled; | 
| Chris@140 | 1533     } | 
| Chris@45 | 1534 | 
| Chris@45 | 1535     QString error; | 
| Chris@45 | 1536     closeSession(); | 
| Chris@45 | 1537     createDocument(); | 
| Chris@45 | 1538 | 
| Chris@45 | 1539     PaneCallback callback(this); | 
| Chris@45 | 1540     m_viewManager->clearSelections(); | 
| Chris@45 | 1541 | 
| Chris@45 | 1542     SVFileReader reader(m_document, callback, source.getLocation()); | 
| Chris@79 | 1543     connect | 
| Chris@79 | 1544         (&reader, SIGNAL(modelRegenerationFailed(QString, QString, QString)), | 
| Chris@79 | 1545          this, SLOT(modelRegenerationFailed(QString, QString, QString))); | 
| Chris@79 | 1546     connect | 
| Chris@79 | 1547         (&reader, SIGNAL(modelRegenerationWarning(QString, QString, QString)), | 
| Chris@79 | 1548          this, SLOT(modelRegenerationWarning(QString, QString, QString))); | 
| Chris@140 | 1549 | 
| Chris@140 | 1550     reader.parse(*inputSource); | 
| Chris@45 | 1551 | 
| Chris@45 | 1552     if (!reader.isOK()) { | 
| Chris@45 | 1553         error = tr("SV XML file read error:\n%1").arg(reader.getErrorString()); | 
| Chris@45 | 1554     } | 
| Chris@45 | 1555 | 
| Chris@140 | 1556     if (bzFile) bzFile->close(); | 
| Chris@140 | 1557 | 
| Chris@140 | 1558     delete inputSource; | 
| Chris@140 | 1559     delete bzFile; | 
| Chris@140 | 1560     delete rawFile; | 
| Chris@45 | 1561 | 
| Chris@45 | 1562     bool ok = (error == ""); | 
| Chris@45 | 1563 | 
| Chris@45 | 1564     if (ok) { | 
| Chris@45 | 1565 | 
| Chris@164 | 1566         emit activity(tr("Import session file \"%1\"").arg(source.getLocation())); | 
| Chris@164 | 1567 | 
| Chris@57 | 1568 	setWindowTitle(tr("%1: %2") | 
| Chris@57 | 1569                        .arg(QApplication::applicationName()) | 
| Chris@45 | 1570 		       .arg(source.getLocation())); | 
| Chris@45 | 1571 | 
| Chris@45 | 1572 	if (!source.isRemote()) m_sessionFile = source.getLocalFilename(); | 
| Chris@45 | 1573 | 
| Chris@45 | 1574 	setupMenus(); | 
| Chris@45 | 1575 | 
| Chris@45 | 1576 	CommandHistory::getInstance()->clear(); | 
| Chris@45 | 1577 	CommandHistory::getInstance()->documentSaved(); | 
| Chris@45 | 1578 	m_documentModified = false; | 
| Chris@45 | 1579 	updateMenuStates(); | 
| Chris@45 | 1580 | 
| Chris@45 | 1581         m_recentFiles.addFile(source.getLocation()); | 
| Chris@45 | 1582 | 
| Chris@45 | 1583         if (!source.isRemote()) { | 
| Chris@45 | 1584             // for file dialog | 
| Chris@45 | 1585             registerLastOpenedFilePath(FileFinder::SessionFile, | 
| Chris@45 | 1586                                         source.getLocalFilename()); | 
| Chris@45 | 1587         } | 
| Chris@45 | 1588 | 
| Chris@45 | 1589     } else { | 
| Chris@57 | 1590 	setWindowTitle(QApplication::applicationName()); | 
| Chris@45 | 1591     } | 
| Chris@45 | 1592 | 
| Chris@45 | 1593     return ok ? FileOpenSucceeded : FileOpenFailed; | 
| Chris@45 | 1594 } | 
| Chris@45 | 1595 | 
| Chris@141 | 1596 MainWindowBase::FileOpenStatus | 
| Chris@141 | 1597 MainWindowBase::openSessionFromRDF(FileSource source) | 
| Chris@141 | 1598 { | 
| Chris@141 | 1599     std::cerr << "MainWindowBase::openSessionFromRDF(" << source.getLocation().toStdString() << ")" << std::endl; | 
| Chris@141 | 1600 | 
| Chris@141 | 1601     if (!source.isAvailable()) return FileOpenFailed; | 
| Chris@141 | 1602     source.waitForData(); | 
| Chris@141 | 1603 | 
| Chris@145 | 1604     if (!checkSaveModified()) { | 
| Chris@145 | 1605         return FileOpenCancelled; | 
| Chris@141 | 1606     } | 
| Chris@143 | 1607 | 
| Chris@145 | 1608     closeSession(); | 
| Chris@145 | 1609     createDocument(); | 
| Chris@145 | 1610 | 
| Chris@145 | 1611     FileOpenStatus status = openLayersFromRDF(source); | 
| Chris@141 | 1612 | 
| Chris@141 | 1613     setupMenus(); | 
| Chris@141 | 1614 | 
| Chris@141 | 1615     setWindowTitle(tr("%1: %2") | 
| Chris@141 | 1616                    .arg(QApplication::applicationName()) | 
| Chris@141 | 1617                    .arg(source.getLocation())); | 
| Chris@141 | 1618     CommandHistory::getInstance()->clear(); | 
| Chris@141 | 1619     CommandHistory::getInstance()->documentSaved(); | 
| Chris@141 | 1620     m_documentModified = false; | 
| Chris@145 | 1621 | 
| Chris@145 | 1622     return status; | 
| Chris@145 | 1623 } | 
| Chris@145 | 1624 | 
| Chris@145 | 1625 MainWindowBase::FileOpenStatus | 
| Chris@145 | 1626 MainWindowBase::openLayersFromRDF(FileSource source) | 
| Chris@145 | 1627 { | 
| Chris@145 | 1628     size_t rate = 0; | 
| Chris@145 | 1629 | 
| Chris@186 | 1630     std::cerr << "MainWindowBase::openLayersFromRDF" << std::endl; | 
| Chris@186 | 1631 | 
| Chris@145 | 1632     ProgressDialog dialog(tr("Importing from RDF..."), true, 2000, this); | 
| Chris@145 | 1633     connect(&dialog, SIGNAL(showing()), this, SIGNAL(hideSplash())); | 
| Chris@145 | 1634 | 
| Chris@145 | 1635     if (getMainModel()) { | 
| Chris@145 | 1636         rate = getMainModel()->getSampleRate(); | 
| Chris@145 | 1637     } else if (Preferences::getInstance()->getResampleOnLoad()) { | 
| Chris@145 | 1638         rate = m_playSource->getSourceSampleRate(); | 
| Chris@145 | 1639     } | 
| Chris@145 | 1640 | 
| Chris@145 | 1641     RDFImporter importer | 
| Chris@145 | 1642         (QUrl::fromLocalFile(source.getLocalFilename()).toString(), rate); | 
| Chris@145 | 1643 | 
| Chris@145 | 1644     if (!importer.isOK()) { | 
| Chris@147 | 1645         if (importer.getErrorString() != "") { | 
| Chris@147 | 1646             QMessageBox::critical | 
| Chris@147 | 1647                 (this, tr("Failed to import RDF"), | 
| Chris@147 | 1648                  tr("<b>Failed to import RDF</b><p>Importing data from RDF document at \"%1\" failed: %2</p>") | 
| Chris@147 | 1649                  .arg(source.getLocation()).arg(importer.getErrorString())); | 
| Chris@147 | 1650         } | 
| Chris@145 | 1651         return FileOpenFailed; | 
| Chris@145 | 1652     } | 
| Chris@145 | 1653 | 
| Chris@145 | 1654     std::vector<Model *> models = importer.getDataModels(&dialog); | 
| Chris@145 | 1655 | 
| Chris@145 | 1656     dialog.setMessage(tr("Importing from RDF...")); | 
| Chris@145 | 1657 | 
| Chris@145 | 1658     if (models.empty()) { | 
| Chris@186 | 1659         QMessageBox::critical | 
| Chris@186 | 1660             (this, tr("Failed to import RDF"), | 
| Chris@186 | 1661              tr("<b>Failed to import RDF</b><p>No suitable data models found for import from RDF document at \"%1\"</p>").arg(source.getLocation())); | 
| Chris@145 | 1662         return FileOpenFailed; | 
| Chris@145 | 1663     } | 
| Chris@145 | 1664 | 
| Chris@164 | 1665     emit activity(tr("Import RDF document \"%1\"").arg(source.getLocation())); | 
| Chris@164 | 1666 | 
| Chris@145 | 1667     std::set<Model *> added; | 
| Chris@145 | 1668 | 
| Chris@145 | 1669     for (int i = 0; i < models.size(); ++i) { | 
| Chris@145 | 1670 | 
| Chris@145 | 1671         Model *m = models[i]; | 
| Chris@145 | 1672         WaveFileModel *w = dynamic_cast<WaveFileModel *>(m); | 
| Chris@145 | 1673 | 
| Chris@145 | 1674         if (w) { | 
| Chris@145 | 1675 | 
| Chris@145 | 1676             Pane *pane = addPaneToStack(); | 
| Chris@145 | 1677             Layer *layer = 0; | 
| Chris@145 | 1678 | 
| Chris@145 | 1679             if (m_timeRulerLayer) { | 
| Chris@145 | 1680                 m_document->addLayerToView(pane, m_timeRulerLayer); | 
| Chris@145 | 1681             } | 
| Chris@145 | 1682 | 
| Chris@145 | 1683             if (!getMainModel()) { | 
| Chris@145 | 1684                 m_document->setMainModel(w); | 
| Chris@145 | 1685                 layer = m_document->createMainModelLayer(LayerFactory::Waveform); | 
| Chris@145 | 1686             } else { | 
| Chris@145 | 1687                 layer = m_document->createImportedLayer(w); | 
| Chris@145 | 1688             } | 
| Chris@145 | 1689 | 
| Chris@145 | 1690             m_document->addLayerToView(pane, layer); | 
| Chris@145 | 1691 | 
| Chris@145 | 1692             added.insert(w); | 
| Chris@145 | 1693 | 
| Chris@145 | 1694             for (int j = 0; j < models.size(); ++j) { | 
| Chris@145 | 1695 | 
| Chris@145 | 1696                 Model *dm = models[j]; | 
| Chris@145 | 1697 | 
| Chris@145 | 1698                 if (dm == m) continue; | 
| Chris@145 | 1699                 if (dm->getSourceModel() != m) continue; | 
| Chris@145 | 1700 | 
| Chris@145 | 1701                 layer = m_document->createImportedLayer(dm); | 
| Chris@145 | 1702 | 
| Chris@145 | 1703                 if (layer->isLayerOpaque() || | 
| Chris@145 | 1704                     dynamic_cast<Colour3DPlotLayer *>(layer)) { | 
| Chris@145 | 1705 | 
| Chris@156 | 1706                     // these always go in a new pane, with nothing | 
| Chris@156 | 1707                     // else going in the same pane | 
| Chris@156 | 1708 | 
| Chris@145 | 1709                     Pane *singleLayerPane = addPaneToStack(); | 
| Chris@145 | 1710                     if (m_timeRulerLayer) { | 
| Chris@145 | 1711                         m_document->addLayerToView(singleLayerPane, m_timeRulerLayer); | 
| Chris@145 | 1712                     } | 
| Chris@145 | 1713                     m_document->addLayerToView(singleLayerPane, layer); | 
| Chris@145 | 1714 | 
| Chris@156 | 1715                 } else if (layer->getLayerColourSignificance() == | 
| Chris@156 | 1716                            Layer::ColourHasMeaningfulValue) { | 
| Chris@156 | 1717 | 
| Chris@156 | 1718                     // these can go in a pane with something else, but | 
| Chris@156 | 1719                     // only if none of the something elses also have | 
| Chris@156 | 1720                     // this quality | 
| Chris@156 | 1721 | 
| Chris@156 | 1722                     bool needNewPane = false; | 
| Chris@156 | 1723                     for (int i = 0; i < pane->getLayerCount(); ++i) { | 
| Chris@156 | 1724                         Layer *otherLayer = pane->getLayer(i); | 
| Chris@156 | 1725                         if (otherLayer && | 
| Chris@156 | 1726                             (otherLayer->getLayerColourSignificance() == | 
| Chris@156 | 1727                              Layer::ColourHasMeaningfulValue)) { | 
| Chris@156 | 1728                             needNewPane = true; | 
| Chris@156 | 1729                             break; | 
| Chris@156 | 1730                         } | 
| Chris@156 | 1731                     } | 
| Chris@156 | 1732                     if (needNewPane) { | 
| Chris@156 | 1733                         pane = addPaneToStack(); | 
| Chris@156 | 1734                     } | 
| Chris@156 | 1735 | 
| Chris@156 | 1736                     m_document->addLayerToView(pane, layer); | 
| Chris@156 | 1737 | 
| Chris@145 | 1738                 } else { | 
| Chris@145 | 1739 | 
| Chris@145 | 1740                     if (pane->getLayerCount() > 4) { | 
| Chris@145 | 1741                         pane = addPaneToStack(); | 
| Chris@145 | 1742                     } | 
| Chris@145 | 1743 | 
| Chris@145 | 1744                     m_document->addLayerToView(pane, layer); | 
| Chris@145 | 1745                 } | 
| Chris@145 | 1746 | 
| Chris@145 | 1747                 added.insert(dm); | 
| Chris@145 | 1748             } | 
| Chris@145 | 1749         } | 
| Chris@145 | 1750     } | 
| Chris@145 | 1751 | 
| Chris@145 | 1752     for (int i = 0; i < models.size(); ++i) { | 
| Chris@145 | 1753 | 
| Chris@145 | 1754         Model *m = models[i]; | 
| Chris@145 | 1755 | 
| Chris@145 | 1756         if (added.find(m) == added.end()) { | 
| Chris@145 | 1757 | 
| Chris@145 | 1758             Layer *layer = m_document->createImportedLayer(m); | 
| Chris@145 | 1759             if (!layer) return FileOpenFailed; | 
| Chris@145 | 1760 | 
| Chris@145 | 1761             Pane *singleLayerPane = addPaneToStack(); | 
| Chris@145 | 1762             if (m_timeRulerLayer) { | 
| Chris@145 | 1763                 m_document->addLayerToView(singleLayerPane, m_timeRulerLayer); | 
| Chris@145 | 1764             } | 
| Chris@145 | 1765             m_document->addLayerToView(singleLayerPane, layer); | 
| Chris@145 | 1766         } | 
| Chris@145 | 1767     } | 
| Chris@145 | 1768 | 
| Chris@145 | 1769     m_recentFiles.addFile(source.getLocation()); | 
| Chris@145 | 1770     return FileOpenSucceeded; | 
| Chris@141 | 1771 } | 
| Chris@141 | 1772 | 
| Chris@45 | 1773 void | 
| Chris@45 | 1774 MainWindowBase::createPlayTarget() | 
| Chris@45 | 1775 { | 
| Chris@45 | 1776     if (m_playTarget) return; | 
| Chris@45 | 1777 | 
| Chris@126 | 1778     QSettings settings; | 
| Chris@126 | 1779     settings.beginGroup("Preferences"); | 
| Chris@126 | 1780     QString targetName = settings.value("audio-target", "").toString(); | 
| Chris@126 | 1781     settings.endGroup(); | 
| Chris@126 | 1782 | 
| Chris@126 | 1783     AudioTargetFactory *factory = AudioTargetFactory::getInstance(); | 
| Chris@126 | 1784 | 
| Chris@126 | 1785     factory->setDefaultCallbackTarget(targetName); | 
| Chris@126 | 1786     m_playTarget = factory->createCallbackTarget(m_playSource); | 
| Chris@126 | 1787 | 
| Chris@45 | 1788     if (!m_playTarget) { | 
| Chris@104 | 1789         emit hideSplash(); | 
| Chris@126 | 1790 | 
| Chris@126 | 1791         if (factory->isAutoCallbackTarget(targetName)) { | 
| Chris@128 | 1792             QMessageBox::warning | 
| Chris@45 | 1793 	    (this, tr("Couldn't open audio device"), | 
| Chris@126 | 1794 	     tr("<b>No audio available</b><p>Could not open an audio device for playback.<p>Automatic audio device detection failed. Audio playback will not be available during this session.</p>"), | 
| Chris@45 | 1795 	     QMessageBox::Ok); | 
| Chris@126 | 1796         } else { | 
| Chris@126 | 1797             QMessageBox::warning | 
| Chris@126 | 1798                 (this, tr("Couldn't open audio device"), | 
| Chris@126 | 1799                  tr("<b>No audio available</b><p>Failed to open your preferred audio device (\"%1\").<p>Audio playback will not be available during this session.</p>") | 
| Chris@126 | 1800                  .arg(factory->getCallbackTargetDescription(targetName)), | 
| Chris@126 | 1801                  QMessageBox::Ok); | 
| Chris@126 | 1802         } | 
| Chris@45 | 1803     } | 
| Chris@45 | 1804 } | 
| Chris@45 | 1805 | 
| Chris@45 | 1806 WaveFileModel * | 
| Chris@45 | 1807 MainWindowBase::getMainModel() | 
| Chris@45 | 1808 { | 
| Chris@45 | 1809     if (!m_document) return 0; | 
| Chris@45 | 1810     return m_document->getMainModel(); | 
| Chris@45 | 1811 } | 
| Chris@45 | 1812 | 
| Chris@45 | 1813 const WaveFileModel * | 
| Chris@45 | 1814 MainWindowBase::getMainModel() const | 
| Chris@45 | 1815 { | 
| Chris@45 | 1816     if (!m_document) return 0; | 
| Chris@45 | 1817     return m_document->getMainModel(); | 
| Chris@45 | 1818 } | 
| Chris@45 | 1819 | 
| Chris@45 | 1820 void | 
| Chris@45 | 1821 MainWindowBase::createDocument() | 
| Chris@45 | 1822 { | 
| Chris@45 | 1823     m_document = new Document; | 
| Chris@45 | 1824 | 
| Chris@45 | 1825     connect(m_document, SIGNAL(layerAdded(Layer *)), | 
| Chris@45 | 1826 	    this, SLOT(layerAdded(Layer *))); | 
| Chris@45 | 1827     connect(m_document, SIGNAL(layerRemoved(Layer *)), | 
| Chris@45 | 1828 	    this, SLOT(layerRemoved(Layer *))); | 
| Chris@45 | 1829     connect(m_document, SIGNAL(layerAboutToBeDeleted(Layer *)), | 
| Chris@45 | 1830 	    this, SLOT(layerAboutToBeDeleted(Layer *))); | 
| Chris@45 | 1831     connect(m_document, SIGNAL(layerInAView(Layer *, bool)), | 
| Chris@45 | 1832 	    this, SLOT(layerInAView(Layer *, bool))); | 
| Chris@45 | 1833 | 
| Chris@45 | 1834     connect(m_document, SIGNAL(modelAdded(Model *)), | 
| Chris@45 | 1835 	    this, SLOT(modelAdded(Model *))); | 
| Chris@45 | 1836     connect(m_document, SIGNAL(mainModelChanged(WaveFileModel *)), | 
| Chris@45 | 1837 	    this, SLOT(mainModelChanged(WaveFileModel *))); | 
| Chris@45 | 1838     connect(m_document, SIGNAL(modelAboutToBeDeleted(Model *)), | 
| Chris@45 | 1839 	    this, SLOT(modelAboutToBeDeleted(Model *))); | 
| Chris@45 | 1840 | 
| Chris@78 | 1841     connect(m_document, SIGNAL(modelGenerationFailed(QString, QString)), | 
| Chris@78 | 1842             this, SLOT(modelGenerationFailed(QString, QString))); | 
| Chris@78 | 1843     connect(m_document, SIGNAL(modelRegenerationWarning(QString, QString, QString)), | 
| Chris@78 | 1844             this, SLOT(modelRegenerationWarning(QString, QString, QString))); | 
| Chris@78 | 1845     connect(m_document, SIGNAL(modelGenerationFailed(QString, QString)), | 
| Chris@78 | 1846             this, SLOT(modelGenerationFailed(QString, QString))); | 
| Chris@78 | 1847     connect(m_document, SIGNAL(modelRegenerationWarning(QString, QString, QString)), | 
| Chris@78 | 1848             this, SLOT(modelRegenerationWarning(QString, QString, QString))); | 
| Chris@78 | 1849     connect(m_document, SIGNAL(alignmentFailed(QString, QString)), | 
| Chris@78 | 1850             this, SLOT(alignmentFailed(QString, QString))); | 
| Chris@160 | 1851 | 
| Chris@160 | 1852     emit replacedDocument(); | 
| Chris@45 | 1853 } | 
| Chris@45 | 1854 | 
| Chris@45 | 1855 bool | 
| Chris@45 | 1856 MainWindowBase::saveSessionFile(QString path) | 
| Chris@45 | 1857 { | 
| Chris@45 | 1858     BZipFileDevice bzFile(path); | 
| Chris@45 | 1859     if (!bzFile.open(QIODevice::WriteOnly)) { | 
| Chris@45 | 1860         std::cerr << "Failed to open session file \"" << path.toStdString() | 
| Chris@45 | 1861                   << "\" for writing: " | 
| Chris@45 | 1862                   << bzFile.errorString().toStdString() << std::endl; | 
| Chris@45 | 1863         return false; | 
| Chris@45 | 1864     } | 
| Chris@45 | 1865 | 
| Chris@45 | 1866     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); | 
| Chris@45 | 1867 | 
| Chris@45 | 1868     QTextStream out(&bzFile); | 
| Chris@45 | 1869     toXml(out); | 
| Chris@45 | 1870     out.flush(); | 
| Chris@45 | 1871 | 
| Chris@45 | 1872     QApplication::restoreOverrideCursor(); | 
| Chris@45 | 1873 | 
| Chris@45 | 1874     if (!bzFile.isOK()) { | 
| Chris@45 | 1875 	QMessageBox::critical(this, tr("Failed to write file"), | 
| Chris@45 | 1876 			      tr("<b>Save failed</b><p>Failed to write to file \"%1\": %2") | 
| Chris@45 | 1877 			      .arg(path).arg(bzFile.errorString())); | 
| Chris@45 | 1878         bzFile.close(); | 
| Chris@45 | 1879 	return false; | 
| Chris@45 | 1880     } | 
| Chris@45 | 1881 | 
| Chris@45 | 1882     bzFile.close(); | 
| Chris@45 | 1883     return true; | 
| Chris@45 | 1884 } | 
| Chris@45 | 1885 | 
| Chris@45 | 1886 void | 
| Chris@45 | 1887 MainWindowBase::toXml(QTextStream &out) | 
| Chris@45 | 1888 { | 
| Chris@45 | 1889     QString indent("  "); | 
| Chris@45 | 1890 | 
| Chris@45 | 1891     out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; | 
| Chris@45 | 1892     out << "<!DOCTYPE sonic-visualiser>\n"; | 
| Chris@45 | 1893     out << "<sv>\n"; | 
| Chris@45 | 1894 | 
| Chris@45 | 1895     m_document->toXml(out, "", ""); | 
| Chris@45 | 1896 | 
| Chris@45 | 1897     out << "<display>\n"; | 
| Chris@45 | 1898 | 
| Chris@45 | 1899     out << QString("  <window width=\"%1\" height=\"%2\"/>\n") | 
| Chris@45 | 1900 	.arg(width()).arg(height()); | 
| Chris@45 | 1901 | 
| Chris@45 | 1902     for (int i = 0; i < m_paneStack->getPaneCount(); ++i) { | 
| Chris@45 | 1903 | 
| Chris@45 | 1904 	Pane *pane = m_paneStack->getPane(i); | 
| Chris@45 | 1905 | 
| Chris@45 | 1906 	if (pane) { | 
| Chris@45 | 1907             pane->toXml(out, indent); | 
| Chris@45 | 1908 	} | 
| Chris@45 | 1909     } | 
| Chris@45 | 1910 | 
| Chris@45 | 1911     out << "</display>\n"; | 
| Chris@45 | 1912 | 
| Chris@45 | 1913     m_viewManager->getSelection().toXml(out); | 
| Chris@45 | 1914 | 
| Chris@45 | 1915     out << "</sv>\n"; | 
| Chris@45 | 1916 } | 
| Chris@45 | 1917 | 
| Chris@45 | 1918 Pane * | 
| Chris@45 | 1919 MainWindowBase::addPaneToStack() | 
| Chris@45 | 1920 { | 
| Chris@45 | 1921     AddPaneCommand *command = new AddPaneCommand(this); | 
| Chris@45 | 1922     CommandHistory::getInstance()->addCommand(command); | 
| Chris@57 | 1923     Pane *pane = command->getPane(); | 
| Chris@57 | 1924     return pane; | 
| Chris@45 | 1925 } | 
| Chris@45 | 1926 | 
| Chris@45 | 1927 void | 
| Chris@45 | 1928 MainWindowBase::zoomIn() | 
| Chris@45 | 1929 { | 
| Chris@45 | 1930     Pane *currentPane = m_paneStack->getCurrentPane(); | 
| Chris@45 | 1931     if (currentPane) currentPane->zoom(true); | 
| Chris@45 | 1932 } | 
| Chris@45 | 1933 | 
| Chris@45 | 1934 void | 
| Chris@45 | 1935 MainWindowBase::zoomOut() | 
| Chris@45 | 1936 { | 
| Chris@45 | 1937     Pane *currentPane = m_paneStack->getCurrentPane(); | 
| Chris@45 | 1938     if (currentPane) currentPane->zoom(false); | 
| Chris@45 | 1939 } | 
| Chris@45 | 1940 | 
| Chris@45 | 1941 void | 
| Chris@45 | 1942 MainWindowBase::zoomToFit() | 
| Chris@45 | 1943 { | 
| Chris@45 | 1944     Pane *currentPane = m_paneStack->getCurrentPane(); | 
| Chris@45 | 1945     if (!currentPane) return; | 
| Chris@45 | 1946 | 
| Chris@45 | 1947     Model *model = getMainModel(); | 
| Chris@45 | 1948     if (!model) return; | 
| Chris@45 | 1949 | 
| Chris@45 | 1950     size_t start = model->getStartFrame(); | 
| Chris@45 | 1951     size_t end = model->getEndFrame(); | 
| Chris@60 | 1952     if (m_playSource) end = std::max(end, m_playSource->getPlayEndFrame()); | 
| Chris@45 | 1953     size_t pixels = currentPane->width(); | 
| Chris@45 | 1954 | 
| Chris@45 | 1955     size_t sw = currentPane->getVerticalScaleWidth(); | 
| Chris@45 | 1956     if (pixels > sw * 2) pixels -= sw * 2; | 
| Chris@45 | 1957     else pixels = 1; | 
| Chris@45 | 1958     if (pixels > 4) pixels -= 4; | 
| Chris@45 | 1959 | 
| Chris@45 | 1960     size_t zoomLevel = (end - start) / pixels; | 
| Chris@150 | 1961     if (zoomLevel < 1) zoomLevel = 1; | 
| Chris@45 | 1962 | 
| Chris@45 | 1963     currentPane->setZoomLevel(zoomLevel); | 
| Chris@45 | 1964     currentPane->setCentreFrame((start + end) / 2); | 
| Chris@45 | 1965 } | 
| Chris@45 | 1966 | 
| Chris@45 | 1967 void | 
| Chris@45 | 1968 MainWindowBase::zoomDefault() | 
| Chris@45 | 1969 { | 
| Chris@45 | 1970     Pane *currentPane = m_paneStack->getCurrentPane(); | 
| Chris@45 | 1971     if (currentPane) currentPane->setZoomLevel(1024); | 
| Chris@45 | 1972 } | 
| Chris@45 | 1973 | 
| Chris@45 | 1974 void | 
| Chris@45 | 1975 MainWindowBase::scrollLeft() | 
| Chris@45 | 1976 { | 
| Chris@45 | 1977     Pane *currentPane = m_paneStack->getCurrentPane(); | 
| Chris@45 | 1978     if (currentPane) currentPane->scroll(false, false); | 
| Chris@45 | 1979 } | 
| Chris@45 | 1980 | 
| Chris@45 | 1981 void | 
| Chris@45 | 1982 MainWindowBase::jumpLeft() | 
| Chris@45 | 1983 { | 
| Chris@45 | 1984     Pane *currentPane = m_paneStack->getCurrentPane(); | 
| Chris@45 | 1985     if (currentPane) currentPane->scroll(false, true); | 
| Chris@45 | 1986 } | 
| Chris@45 | 1987 | 
| Chris@45 | 1988 void | 
| Chris@162 | 1989 MainWindowBase::peekLeft() | 
| Chris@162 | 1990 { | 
| Chris@162 | 1991     Pane *currentPane = m_paneStack->getCurrentPane(); | 
| Chris@162 | 1992     if (currentPane) currentPane->scroll(false, false, false); | 
| Chris@162 | 1993 } | 
| Chris@162 | 1994 | 
| Chris@162 | 1995 void | 
| Chris@45 | 1996 MainWindowBase::scrollRight() | 
| Chris@45 | 1997 { | 
| Chris@45 | 1998     Pane *currentPane = m_paneStack->getCurrentPane(); | 
| Chris@45 | 1999     if (currentPane) currentPane->scroll(true, false); | 
| Chris@45 | 2000 } | 
| Chris@45 | 2001 | 
| Chris@45 | 2002 void | 
| Chris@45 | 2003 MainWindowBase::jumpRight() | 
| Chris@45 | 2004 { | 
| Chris@45 | 2005     Pane *currentPane = m_paneStack->getCurrentPane(); | 
| Chris@45 | 2006     if (currentPane) currentPane->scroll(true, true); | 
| Chris@45 | 2007 } | 
| Chris@45 | 2008 | 
| Chris@45 | 2009 void | 
| Chris@162 | 2010 MainWindowBase::peekRight() | 
| Chris@162 | 2011 { | 
| Chris@162 | 2012     Pane *currentPane = m_paneStack->getCurrentPane(); | 
| Chris@162 | 2013     if (currentPane) currentPane->scroll(true, false, false); | 
| Chris@162 | 2014 } | 
| Chris@162 | 2015 | 
| Chris@162 | 2016 void | 
| Chris@45 | 2017 MainWindowBase::showNoOverlays() | 
| Chris@45 | 2018 { | 
| Chris@45 | 2019     m_viewManager->setOverlayMode(ViewManager::NoOverlays); | 
| Chris@45 | 2020 } | 
| Chris@45 | 2021 | 
| Chris@45 | 2022 void | 
| Chris@45 | 2023 MainWindowBase::showMinimalOverlays() | 
| Chris@45 | 2024 { | 
| Chris@45 | 2025     m_viewManager->setOverlayMode(ViewManager::MinimalOverlays); | 
| Chris@45 | 2026 } | 
| Chris@45 | 2027 | 
| Chris@45 | 2028 void | 
| Chris@45 | 2029 MainWindowBase::showStandardOverlays() | 
| Chris@45 | 2030 { | 
| Chris@45 | 2031     m_viewManager->setOverlayMode(ViewManager::StandardOverlays); | 
| Chris@45 | 2032 } | 
| Chris@45 | 2033 | 
| Chris@45 | 2034 void | 
| Chris@45 | 2035 MainWindowBase::showAllOverlays() | 
| Chris@45 | 2036 { | 
| Chris@45 | 2037     m_viewManager->setOverlayMode(ViewManager::AllOverlays); | 
| Chris@45 | 2038 } | 
| Chris@45 | 2039 | 
| Chris@45 | 2040 void | 
| Chris@45 | 2041 MainWindowBase::toggleZoomWheels() | 
| Chris@45 | 2042 { | 
| Chris@45 | 2043     if (m_viewManager->getZoomWheelsEnabled()) { | 
| Chris@45 | 2044         m_viewManager->setZoomWheelsEnabled(false); | 
| Chris@45 | 2045     } else { | 
| Chris@45 | 2046         m_viewManager->setZoomWheelsEnabled(true); | 
| Chris@45 | 2047     } | 
| Chris@45 | 2048 } | 
| Chris@45 | 2049 | 
| Chris@45 | 2050 void | 
| Chris@45 | 2051 MainWindowBase::togglePropertyBoxes() | 
| Chris@45 | 2052 { | 
| Chris@45 | 2053     if (m_paneStack->getLayoutStyle() == PaneStack::NoPropertyStacks) { | 
| Chris@45 | 2054         if (Preferences::getInstance()->getPropertyBoxLayout() == | 
| Chris@45 | 2055             Preferences::VerticallyStacked) { | 
| Chris@45 | 2056             m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout); | 
| Chris@45 | 2057         } else { | 
| Chris@45 | 2058             m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout); | 
| Chris@45 | 2059         } | 
| Chris@45 | 2060     } else { | 
| Chris@45 | 2061         m_paneStack->setLayoutStyle(PaneStack::NoPropertyStacks); | 
| Chris@45 | 2062     } | 
| Chris@45 | 2063 } | 
| Chris@45 | 2064 | 
| Chris@45 | 2065 void | 
| Chris@45 | 2066 MainWindowBase::toggleStatusBar() | 
| Chris@45 | 2067 { | 
| Chris@45 | 2068     QSettings settings; | 
| Chris@45 | 2069     settings.beginGroup("MainWindow"); | 
| Chris@45 | 2070     bool sb = settings.value("showstatusbar", true).toBool(); | 
| Chris@45 | 2071 | 
| Chris@45 | 2072     if (sb) { | 
| Chris@45 | 2073         statusBar()->hide(); | 
| Chris@45 | 2074     } else { | 
| Chris@45 | 2075         statusBar()->show(); | 
| Chris@45 | 2076     } | 
| Chris@45 | 2077 | 
| Chris@45 | 2078     settings.setValue("showstatusbar", !sb); | 
| Chris@45 | 2079 | 
| Chris@45 | 2080     settings.endGroup(); | 
| Chris@45 | 2081 } | 
| Chris@45 | 2082 | 
| Chris@45 | 2083 void | 
| Chris@45 | 2084 MainWindowBase::preferenceChanged(PropertyContainer::PropertyName name) | 
| Chris@45 | 2085 { | 
| Chris@45 | 2086     if (name == "Property Box Layout") { | 
| Chris@45 | 2087         if (m_paneStack->getLayoutStyle() != PaneStack::NoPropertyStacks) { | 
| Chris@45 | 2088             if (Preferences::getInstance()->getPropertyBoxLayout() == | 
| Chris@45 | 2089                 Preferences::VerticallyStacked) { | 
| Chris@45 | 2090                 m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout); | 
| Chris@45 | 2091             } else { | 
| Chris@45 | 2092                 m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout); | 
| Chris@45 | 2093             } | 
| Chris@45 | 2094         } | 
| Chris@45 | 2095     } else if (name == "Background Mode" && m_viewManager) { | 
| Chris@45 | 2096         Preferences::BackgroundMode mode = | 
| Chris@45 | 2097             Preferences::getInstance()->getBackgroundMode(); | 
| Chris@45 | 2098         if (mode == Preferences::BackgroundFromTheme) { | 
| Chris@45 | 2099             m_viewManager->setGlobalDarkBackground(m_initialDarkBackground); | 
| Chris@45 | 2100         } else if (mode == Preferences::DarkBackground) { | 
| Chris@45 | 2101             m_viewManager->setGlobalDarkBackground(true); | 
| Chris@45 | 2102         } else { | 
| Chris@45 | 2103             m_viewManager->setGlobalDarkBackground(false); | 
| Chris@45 | 2104         } | 
| Chris@45 | 2105     } | 
| Chris@45 | 2106 } | 
| Chris@45 | 2107 | 
| Chris@45 | 2108 void | 
| Chris@45 | 2109 MainWindowBase::play() | 
| Chris@45 | 2110 { | 
| Chris@45 | 2111     if (m_playSource->isPlaying()) { | 
| Chris@45 | 2112         stop(); | 
| Chris@45 | 2113     } else { | 
| Chris@45 | 2114         playbackFrameChanged(m_viewManager->getPlaybackFrame()); | 
| Chris@45 | 2115 	m_playSource->play(m_viewManager->getPlaybackFrame()); | 
| Chris@45 | 2116     } | 
| Chris@45 | 2117 } | 
| Chris@45 | 2118 | 
| Chris@45 | 2119 void | 
| Chris@45 | 2120 MainWindowBase::ffwd() | 
| Chris@45 | 2121 { | 
| Chris@45 | 2122     if (!getMainModel()) return; | 
| Chris@45 | 2123 | 
| Chris@45 | 2124     int frame = m_viewManager->getPlaybackFrame(); | 
| Chris@45 | 2125     ++frame; | 
| Chris@45 | 2126 | 
| Chris@85 | 2127     Pane *pane = m_paneStack->getCurrentPane(); | 
| Chris@45 | 2128     Layer *layer = getSnapLayer(); | 
| Chris@45 | 2129     size_t sr = getMainModel()->getSampleRate(); | 
| Chris@45 | 2130 | 
| Chris@45 | 2131     if (!layer) { | 
| Chris@45 | 2132 | 
| Chris@45 | 2133         frame = RealTime::realTime2Frame | 
| Chris@45 | 2134             (RealTime::frame2RealTime(frame, sr) + RealTime(2, 0), sr); | 
| Chris@45 | 2135         if (frame > int(getMainModel()->getEndFrame())) { | 
| Chris@45 | 2136             frame = getMainModel()->getEndFrame(); | 
| Chris@45 | 2137         } | 
| Chris@45 | 2138 | 
| Chris@45 | 2139     } else { | 
| Chris@45 | 2140 | 
| Chris@45 | 2141         size_t resolution = 0; | 
| Chris@166 | 2142         if (pane) frame = pane->alignFromReference(frame); | 
| Chris@85 | 2143         if (layer->snapToFeatureFrame(m_paneStack->getCurrentPane(), | 
| Chris@85 | 2144                                       frame, resolution, Layer::SnapRight)) { | 
| Chris@85 | 2145             if (pane) frame = pane->alignToReference(frame); | 
| Chris@85 | 2146         } else { | 
| Chris@45 | 2147             frame = getMainModel()->getEndFrame(); | 
| Chris@45 | 2148         } | 
| Chris@45 | 2149     } | 
| Chris@45 | 2150 | 
| Chris@45 | 2151     if (frame < 0) frame = 0; | 
| Chris@45 | 2152 | 
| Chris@45 | 2153     if (m_viewManager->getPlaySelectionMode()) { | 
| Chris@45 | 2154         frame = m_viewManager->constrainFrameToSelection(size_t(frame)); | 
| Chris@45 | 2155     } | 
| Chris@45 | 2156 | 
| Chris@45 | 2157     m_viewManager->setPlaybackFrame(frame); | 
| Chris@166 | 2158 | 
| Chris@166 | 2159     if (frame == getMainModel()->getEndFrame() && | 
| Chris@166 | 2160         m_playSource && | 
| Chris@166 | 2161         m_playSource->isPlaying() && | 
| Chris@166 | 2162         !m_viewManager->getPlayLoopMode()) { | 
| Chris@166 | 2163         stop(); | 
| Chris@166 | 2164     } | 
| Chris@45 | 2165 } | 
| Chris@45 | 2166 | 
| Chris@45 | 2167 void | 
| Chris@45 | 2168 MainWindowBase::ffwdEnd() | 
| Chris@45 | 2169 { | 
| Chris@45 | 2170     if (!getMainModel()) return; | 
| Chris@45 | 2171 | 
| Chris@139 | 2172     if (m_playSource && | 
| Chris@139 | 2173         m_playSource->isPlaying() && | 
| Chris@139 | 2174         !m_viewManager->getPlayLoopMode()) { | 
| Chris@139 | 2175         stop(); | 
| Chris@139 | 2176     } | 
| Chris@139 | 2177 | 
| Chris@45 | 2178     size_t frame = getMainModel()->getEndFrame(); | 
| Chris@45 | 2179 | 
| Chris@45 | 2180     if (m_viewManager->getPlaySelectionMode()) { | 
| Chris@45 | 2181         frame = m_viewManager->constrainFrameToSelection(frame); | 
| Chris@45 | 2182     } | 
| Chris@45 | 2183 | 
| Chris@45 | 2184     m_viewManager->setPlaybackFrame(frame); | 
| Chris@45 | 2185 } | 
| Chris@45 | 2186 | 
| Chris@45 | 2187 void | 
| Chris@166 | 2188 MainWindowBase::ffwdSimilar() | 
| Chris@166 | 2189 { | 
| Chris@166 | 2190     if (!getMainModel()) return; | 
| Chris@166 | 2191 | 
| Chris@166 | 2192     Layer *layer = getSnapLayer(); | 
| Chris@166 | 2193     if (!layer) { ffwd(); return; } | 
| Chris@166 | 2194 | 
| Chris@166 | 2195     Pane *pane = m_paneStack->getCurrentPane(); | 
| Chris@166 | 2196     size_t sr = getMainModel()->getSampleRate(); | 
| Chris@166 | 2197 | 
| Chris@166 | 2198     int frame = m_viewManager->getPlaybackFrame(); | 
| Chris@166 | 2199 | 
| Chris@166 | 2200     size_t resolution = 0; | 
| Chris@166 | 2201     if (pane) frame = pane->alignFromReference(frame); | 
| Chris@166 | 2202     if (layer->snapToSimilarFeature(m_paneStack->getCurrentPane(), | 
| Chris@166 | 2203                                     frame, resolution, Layer::SnapRight)) { | 
| Chris@166 | 2204         if (pane) frame = pane->alignToReference(frame); | 
| Chris@166 | 2205     } else { | 
| Chris@166 | 2206         frame = getMainModel()->getEndFrame(); | 
| Chris@166 | 2207     } | 
| Chris@166 | 2208 | 
| Chris@166 | 2209     if (frame < 0) frame = 0; | 
| Chris@166 | 2210 | 
| Chris@166 | 2211     if (m_viewManager->getPlaySelectionMode()) { | 
| Chris@166 | 2212         frame = m_viewManager->constrainFrameToSelection(size_t(frame)); | 
| Chris@166 | 2213     } | 
| Chris@166 | 2214 | 
| Chris@166 | 2215     m_viewManager->setPlaybackFrame(frame); | 
| Chris@166 | 2216 | 
| Chris@166 | 2217     if (frame == getMainModel()->getEndFrame() && | 
| Chris@166 | 2218         m_playSource && | 
| Chris@166 | 2219         m_playSource->isPlaying() && | 
| Chris@166 | 2220         !m_viewManager->getPlayLoopMode()) { | 
| Chris@166 | 2221         stop(); | 
| Chris@166 | 2222     } | 
| Chris@166 | 2223 } | 
| Chris@166 | 2224 | 
| Chris@166 | 2225 void | 
| Chris@45 | 2226 MainWindowBase::rewind() | 
| Chris@45 | 2227 { | 
| Chris@45 | 2228     if (!getMainModel()) return; | 
| Chris@45 | 2229 | 
| Chris@45 | 2230     int frame = m_viewManager->getPlaybackFrame(); | 
| Chris@45 | 2231     if (frame > 0) --frame; | 
| Chris@45 | 2232 | 
| Chris@85 | 2233     Pane *pane = m_paneStack->getCurrentPane(); | 
| Chris@45 | 2234     Layer *layer = getSnapLayer(); | 
| Chris@45 | 2235     size_t sr = getMainModel()->getSampleRate(); | 
| Chris@45 | 2236 | 
| Chris@45 | 2237     // when rewinding during playback, we want to allow a period | 
| Chris@45 | 2238     // following a rewind target point at which the rewind will go to | 
| Chris@45 | 2239     // the prior point instead of the immediately neighbouring one | 
| Chris@45 | 2240     if (m_playSource && m_playSource->isPlaying()) { | 
| Chris@45 | 2241         RealTime ct = RealTime::frame2RealTime(frame, sr); | 
| Chris@45 | 2242         ct = ct - RealTime::fromSeconds(0.25); | 
| Chris@45 | 2243         if (ct < RealTime::zeroTime) ct = RealTime::zeroTime; | 
| Chris@45 | 2244         frame = RealTime::realTime2Frame(ct, sr); | 
| Chris@45 | 2245     } | 
| Chris@45 | 2246 | 
| Chris@45 | 2247     if (!layer) { | 
| Chris@45 | 2248 | 
| Chris@45 | 2249         frame = RealTime::realTime2Frame | 
| Chris@45 | 2250             (RealTime::frame2RealTime(frame, sr) - RealTime(2, 0), sr); | 
| Chris@45 | 2251         if (frame < int(getMainModel()->getStartFrame())) { | 
| Chris@45 | 2252             frame = getMainModel()->getStartFrame(); | 
| Chris@45 | 2253         } | 
| Chris@45 | 2254 | 
| Chris@45 | 2255     } else { | 
| Chris@45 | 2256 | 
| Chris@45 | 2257         size_t resolution = 0; | 
| Chris@166 | 2258         if (pane) frame = pane->alignFromReference(frame); | 
| Chris@85 | 2259         if (layer->snapToFeatureFrame(m_paneStack->getCurrentPane(), | 
| Chris@85 | 2260                                       frame, resolution, Layer::SnapLeft)) { | 
| Chris@85 | 2261             if (pane) frame = pane->alignToReference(frame); | 
| Chris@85 | 2262         } else { | 
| Chris@45 | 2263             frame = getMainModel()->getStartFrame(); | 
| Chris@45 | 2264         } | 
| Chris@45 | 2265     } | 
| Chris@45 | 2266 | 
| Chris@45 | 2267     if (frame < 0) frame = 0; | 
| Chris@45 | 2268 | 
| Chris@45 | 2269     if (m_viewManager->getPlaySelectionMode()) { | 
| Chris@45 | 2270         frame = m_viewManager->constrainFrameToSelection(size_t(frame)); | 
| Chris@45 | 2271     } | 
| Chris@45 | 2272 | 
| Chris@45 | 2273     m_viewManager->setPlaybackFrame(frame); | 
| Chris@45 | 2274 } | 
| Chris@45 | 2275 | 
| Chris@45 | 2276 void | 
| Chris@45 | 2277 MainWindowBase::rewindStart() | 
| Chris@45 | 2278 { | 
| Chris@45 | 2279     if (!getMainModel()) return; | 
| Chris@45 | 2280 | 
| Chris@45 | 2281     size_t frame = getMainModel()->getStartFrame(); | 
| Chris@45 | 2282 | 
| Chris@45 | 2283     if (m_viewManager->getPlaySelectionMode()) { | 
| Chris@45 | 2284         frame = m_viewManager->constrainFrameToSelection(frame); | 
| Chris@45 | 2285     } | 
| Chris@45 | 2286 | 
| Chris@45 | 2287     m_viewManager->setPlaybackFrame(frame); | 
| Chris@45 | 2288 } | 
| Chris@45 | 2289 | 
| Chris@166 | 2290 void | 
| Chris@166 | 2291 MainWindowBase::rewindSimilar() | 
| Chris@166 | 2292 { | 
| Chris@166 | 2293     if (!getMainModel()) return; | 
| Chris@166 | 2294 | 
| Chris@166 | 2295     Layer *layer = getSnapLayer(); | 
| Chris@166 | 2296     if (!layer) { rewind(); return; } | 
| Chris@166 | 2297 | 
| Chris@166 | 2298     Pane *pane = m_paneStack->getCurrentPane(); | 
| Chris@166 | 2299     size_t sr = getMainModel()->getSampleRate(); | 
| Chris@166 | 2300 | 
| Chris@166 | 2301     int frame = m_viewManager->getPlaybackFrame(); | 
| Chris@166 | 2302 | 
| Chris@166 | 2303     size_t resolution = 0; | 
| Chris@166 | 2304     if (pane) frame = pane->alignFromReference(frame); | 
| Chris@166 | 2305     if (layer->snapToSimilarFeature(m_paneStack->getCurrentPane(), | 
| Chris@166 | 2306                                     frame, resolution, Layer::SnapLeft)) { | 
| Chris@166 | 2307         if (pane) frame = pane->alignToReference(frame); | 
| Chris@166 | 2308     } else { | 
| Chris@166 | 2309         frame = getMainModel()->getStartFrame(); | 
| Chris@166 | 2310     } | 
| Chris@166 | 2311 | 
| Chris@166 | 2312     if (frame < 0) frame = 0; | 
| Chris@166 | 2313 | 
| Chris@166 | 2314     if (m_viewManager->getPlaySelectionMode()) { | 
| Chris@166 | 2315         frame = m_viewManager->constrainFrameToSelection(size_t(frame)); | 
| Chris@166 | 2316     } | 
| Chris@166 | 2317 | 
| Chris@166 | 2318     m_viewManager->setPlaybackFrame(frame); | 
| Chris@166 | 2319 } | 
| Chris@166 | 2320 | 
| Chris@45 | 2321 Layer * | 
| Chris@45 | 2322 MainWindowBase::getSnapLayer() const | 
| Chris@45 | 2323 { | 
| Chris@45 | 2324     Pane *pane = m_paneStack->getCurrentPane(); | 
| Chris@45 | 2325     if (!pane) return 0; | 
| Chris@45 | 2326 | 
| Chris@45 | 2327     Layer *layer = pane->getSelectedLayer(); | 
| Chris@45 | 2328 | 
| Chris@45 | 2329     if (!dynamic_cast<TimeInstantLayer *>(layer) && | 
| Chris@45 | 2330         !dynamic_cast<TimeValueLayer *>(layer) && | 
| Chris@194 | 2331         !dynamic_cast<RegionLayer *>(layer) && | 
| Chris@45 | 2332         !dynamic_cast<TimeRulerLayer *>(layer)) { | 
| Chris@45 | 2333 | 
| Chris@45 | 2334         layer = 0; | 
| Chris@45 | 2335 | 
| Chris@45 | 2336         for (int i = pane->getLayerCount(); i > 0; --i) { | 
| Chris@45 | 2337             Layer *l = pane->getLayer(i-1); | 
| Chris@45 | 2338             if (dynamic_cast<TimeRulerLayer *>(l)) { | 
| Chris@45 | 2339                 layer = l; | 
| Chris@45 | 2340                 break; | 
| Chris@45 | 2341             } | 
| Chris@45 | 2342         } | 
| Chris@45 | 2343     } | 
| Chris@45 | 2344 | 
| Chris@45 | 2345     return layer; | 
| Chris@45 | 2346 } | 
| Chris@45 | 2347 | 
| Chris@45 | 2348 void | 
| Chris@45 | 2349 MainWindowBase::stop() | 
| Chris@45 | 2350 { | 
| Chris@45 | 2351     m_playSource->stop(); | 
| Chris@45 | 2352 | 
| Chris@45 | 2353     if (m_paneStack && m_paneStack->getCurrentPane()) { | 
| Chris@45 | 2354         updateVisibleRangeDisplay(m_paneStack->getCurrentPane()); | 
| Chris@45 | 2355     } else { | 
| Chris@45 | 2356         m_myStatusMessage = ""; | 
| Chris@45 | 2357         statusBar()->showMessage(""); | 
| Chris@45 | 2358     } | 
| Chris@45 | 2359 } | 
| Chris@45 | 2360 | 
| Chris@45 | 2361 MainWindowBase::AddPaneCommand::AddPaneCommand(MainWindowBase *mw) : | 
| Chris@45 | 2362     m_mw(mw), | 
| Chris@45 | 2363     m_pane(0), | 
| Chris@45 | 2364     m_prevCurrentPane(0), | 
| Chris@45 | 2365     m_added(false) | 
| Chris@45 | 2366 { | 
| Chris@45 | 2367 } | 
| Chris@45 | 2368 | 
| Chris@45 | 2369 MainWindowBase::AddPaneCommand::~AddPaneCommand() | 
| Chris@45 | 2370 { | 
| Chris@45 | 2371     if (m_pane && !m_added) { | 
| Chris@45 | 2372 	m_mw->m_paneStack->deletePane(m_pane); | 
| Chris@45 | 2373     } | 
| Chris@45 | 2374 } | 
| Chris@45 | 2375 | 
| Chris@45 | 2376 QString | 
| Chris@45 | 2377 MainWindowBase::AddPaneCommand::getName() const | 
| Chris@45 | 2378 { | 
| Chris@45 | 2379     return tr("Add Pane"); | 
| Chris@45 | 2380 } | 
| Chris@45 | 2381 | 
| Chris@45 | 2382 void | 
| Chris@45 | 2383 MainWindowBase::AddPaneCommand::execute() | 
| Chris@45 | 2384 { | 
| Chris@45 | 2385     if (!m_pane) { | 
| Chris@45 | 2386 	m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane(); | 
| Chris@45 | 2387 	m_pane = m_mw->m_paneStack->addPane(); | 
| Chris@45 | 2388 | 
| Chris@45 | 2389         connect(m_pane, SIGNAL(contextHelpChanged(const QString &)), | 
| Chris@45 | 2390                 m_mw, SLOT(contextHelpChanged(const QString &))); | 
| Chris@45 | 2391     } else { | 
| Chris@45 | 2392 	m_mw->m_paneStack->showPane(m_pane); | 
| Chris@45 | 2393     } | 
| Chris@45 | 2394 | 
| Chris@45 | 2395     m_mw->m_paneStack->setCurrentPane(m_pane); | 
| Chris@45 | 2396     m_added = true; | 
| Chris@45 | 2397 } | 
| Chris@45 | 2398 | 
| Chris@45 | 2399 void | 
| Chris@45 | 2400 MainWindowBase::AddPaneCommand::unexecute() | 
| Chris@45 | 2401 { | 
| Chris@45 | 2402     m_mw->m_paneStack->hidePane(m_pane); | 
| Chris@45 | 2403     m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane); | 
| Chris@45 | 2404     m_added = false; | 
| Chris@45 | 2405 } | 
| Chris@45 | 2406 | 
| Chris@45 | 2407 MainWindowBase::RemovePaneCommand::RemovePaneCommand(MainWindowBase *mw, Pane *pane) : | 
| Chris@45 | 2408     m_mw(mw), | 
| Chris@45 | 2409     m_pane(pane), | 
| Chris@45 | 2410     m_added(true) | 
| Chris@45 | 2411 { | 
| Chris@45 | 2412 } | 
| Chris@45 | 2413 | 
| Chris@45 | 2414 MainWindowBase::RemovePaneCommand::~RemovePaneCommand() | 
| Chris@45 | 2415 { | 
| Chris@45 | 2416     if (m_pane && !m_added) { | 
| Chris@45 | 2417 	m_mw->m_paneStack->deletePane(m_pane); | 
| Chris@45 | 2418     } | 
| Chris@45 | 2419 } | 
| Chris@45 | 2420 | 
| Chris@45 | 2421 QString | 
| Chris@45 | 2422 MainWindowBase::RemovePaneCommand::getName() const | 
| Chris@45 | 2423 { | 
| Chris@45 | 2424     return tr("Remove Pane"); | 
| Chris@45 | 2425 } | 
| Chris@45 | 2426 | 
| Chris@45 | 2427 void | 
| Chris@45 | 2428 MainWindowBase::RemovePaneCommand::execute() | 
| Chris@45 | 2429 { | 
| Chris@45 | 2430     m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane(); | 
| Chris@45 | 2431     m_mw->m_paneStack->hidePane(m_pane); | 
| Chris@45 | 2432     m_added = false; | 
| Chris@45 | 2433 } | 
| Chris@45 | 2434 | 
| Chris@45 | 2435 void | 
| Chris@45 | 2436 MainWindowBase::RemovePaneCommand::unexecute() | 
| Chris@45 | 2437 { | 
| Chris@45 | 2438     m_mw->m_paneStack->showPane(m_pane); | 
| Chris@45 | 2439     m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane); | 
| Chris@45 | 2440     m_added = true; | 
| Chris@45 | 2441 } | 
| Chris@45 | 2442 | 
| Chris@45 | 2443 void | 
| Chris@45 | 2444 MainWindowBase::deleteCurrentPane() | 
| Chris@45 | 2445 { | 
| Chris@45 | 2446     CommandHistory::getInstance()->startCompoundOperation | 
| Chris@45 | 2447 	(tr("Delete Pane"), true); | 
| Chris@45 | 2448 | 
| Chris@45 | 2449     Pane *pane = m_paneStack->getCurrentPane(); | 
| Chris@45 | 2450     if (pane) { | 
| Chris@45 | 2451 	while (pane->getLayerCount() > 0) { | 
| Chris@45 | 2452 	    Layer *layer = pane->getLayer(0); | 
| Chris@45 | 2453 	    if (layer) { | 
| Chris@45 | 2454 		m_document->removeLayerFromView(pane, layer); | 
| Chris@45 | 2455 	    } else { | 
| Chris@45 | 2456 		break; | 
| Chris@45 | 2457 	    } | 
| Chris@45 | 2458 	} | 
| Chris@45 | 2459 | 
| Chris@45 | 2460 	RemovePaneCommand *command = new RemovePaneCommand(this, pane); | 
| Chris@45 | 2461 	CommandHistory::getInstance()->addCommand(command); | 
| Chris@45 | 2462     } | 
| Chris@45 | 2463 | 
| Chris@45 | 2464     CommandHistory::getInstance()->endCompoundOperation(); | 
| Chris@45 | 2465 | 
| Chris@45 | 2466     updateMenuStates(); | 
| Chris@45 | 2467 } | 
| Chris@45 | 2468 | 
| Chris@45 | 2469 void | 
| Chris@45 | 2470 MainWindowBase::deleteCurrentLayer() | 
| Chris@45 | 2471 { | 
| Chris@45 | 2472     Pane *pane = m_paneStack->getCurrentPane(); | 
| Chris@45 | 2473     if (pane) { | 
| Chris@45 | 2474 	Layer *layer = pane->getSelectedLayer(); | 
| Chris@45 | 2475 	if (layer) { | 
| Chris@45 | 2476 	    m_document->removeLayerFromView(pane, layer); | 
| Chris@45 | 2477 	} | 
| Chris@45 | 2478     } | 
| Chris@45 | 2479     updateMenuStates(); | 
| Chris@45 | 2480 } | 
| Chris@45 | 2481 | 
| Chris@45 | 2482 void | 
| Chris@123 | 2483 MainWindowBase::editCurrentLayer() | 
| Chris@123 | 2484 { | 
| Chris@123 | 2485     Layer *layer = 0; | 
| Chris@123 | 2486     Pane *pane = m_paneStack->getCurrentPane(); | 
| Chris@123 | 2487     if (pane) layer = pane->getSelectedLayer(); | 
| Chris@123 | 2488     if (!layer) return; | 
| Chris@123 | 2489 | 
| Chris@123 | 2490     Model *model = layer->getModel(); | 
| Chris@123 | 2491     if (!model) return; | 
| Chris@123 | 2492 | 
| Chris@124 | 2493     TabularModel *tabular = dynamic_cast<TabularModel *>(model); | 
| Chris@124 | 2494     if (!tabular) { | 
| Chris@124 | 2495         //!!! how to prevent this function from being active if not | 
| Chris@124 | 2496         //appropriate model type?  or will we ultimately support | 
| Chris@124 | 2497         //tabular display for all editable models? | 
| Chris@124 | 2498         std::cerr << "NOTE: Not a tabular model" << std::endl; | 
| Chris@124 | 2499         return; | 
| Chris@124 | 2500     } | 
| Chris@124 | 2501 | 
| Chris@123 | 2502     if (m_layerDataDialogMap.find(layer) != m_layerDataDialogMap.end()) { | 
| Chris@126 | 2503         if (!m_layerDataDialogMap[layer].isNull()) { | 
| Chris@126 | 2504             m_layerDataDialogMap[layer]->show(); | 
| Chris@126 | 2505             m_layerDataDialogMap[layer]->raise(); | 
| Chris@126 | 2506             return; | 
| Chris@126 | 2507         } | 
| Chris@123 | 2508     } | 
| Chris@123 | 2509 | 
| Chris@125 | 2510     QString title = layer->getLayerPresentationName(); | 
| Chris@125 | 2511 | 
| Chris@125 | 2512     ModelDataTableDialog *dialog = new ModelDataTableDialog(tabular, title, this); | 
| Chris@128 | 2513     dialog->setAttribute(Qt::WA_DeleteOnClose); | 
| Chris@128 | 2514 | 
| Chris@128 | 2515     connectLayerEditDialog(dialog); | 
| Chris@123 | 2516 | 
| Chris@128 | 2517     m_layerDataDialogMap[layer] = dialog; | 
| Chris@128 | 2518     m_viewDataDialogMap[pane].insert(dialog); | 
| Chris@128 | 2519 | 
| Chris@128 | 2520     dialog->show(); | 
| Chris@128 | 2521 } | 
| Chris@128 | 2522 | 
| Chris@128 | 2523 void | 
| Chris@128 | 2524 MainWindowBase::connectLayerEditDialog(ModelDataTableDialog *dialog) | 
| Chris@128 | 2525 { | 
| Chris@123 | 2526     connect(m_viewManager, | 
| Chris@123 | 2527             SIGNAL(globalCentreFrameChanged(unsigned long)), | 
| Chris@123 | 2528             dialog, | 
| Chris@127 | 2529             SLOT(userScrolledToFrame(unsigned long))); | 
| Chris@127 | 2530 | 
| Chris@127 | 2531     connect(m_viewManager, | 
| Chris@127 | 2532             SIGNAL(playbackFrameChanged(unsigned long)), | 
| Chris@127 | 2533             dialog, | 
| Chris@127 | 2534             SLOT(playbackScrolledToFrame(unsigned long))); | 
| Chris@127 | 2535 | 
| Chris@123 | 2536     connect(dialog, | 
| Chris@123 | 2537             SIGNAL(scrollToFrame(unsigned long)), | 
| Chris@123 | 2538             m_viewManager, | 
| Chris@123 | 2539             SLOT(setGlobalCentreFrame(unsigned long))); | 
| Chris@129 | 2540 | 
| Chris@129 | 2541     connect(dialog, | 
| Chris@129 | 2542             SIGNAL(scrollToFrame(unsigned long)), | 
| Chris@129 | 2543             m_viewManager, | 
| Chris@129 | 2544             SLOT(setPlaybackFrame(unsigned long))); | 
| Chris@128 | 2545 } | 
| Chris@123 | 2546 | 
| Chris@123 | 2547 void | 
| Chris@73 | 2548 MainWindowBase::previousPane() | 
| Chris@73 | 2549 { | 
| Chris@73 | 2550     if (!m_paneStack) return; | 
| Chris@73 | 2551 | 
| Chris@73 | 2552     Pane *currentPane = m_paneStack->getCurrentPane(); | 
| Chris@73 | 2553     if (!currentPane) return; | 
| Chris@73 | 2554 | 
| Chris@73 | 2555     for (int i = 0; i < m_paneStack->getPaneCount(); ++i) { | 
| Chris@73 | 2556         if (m_paneStack->getPane(i) == currentPane) { | 
| Chris@73 | 2557             if (i == 0) return; | 
| Chris@73 | 2558             m_paneStack->setCurrentPane(m_paneStack->getPane(i-1)); | 
| Chris@73 | 2559             updateMenuStates(); | 
| Chris@73 | 2560             return; | 
| Chris@73 | 2561         } | 
| Chris@73 | 2562     } | 
| Chris@73 | 2563 } | 
| Chris@73 | 2564 | 
| Chris@73 | 2565 void | 
| Chris@73 | 2566 MainWindowBase::nextPane() | 
| Chris@73 | 2567 { | 
| Chris@73 | 2568     if (!m_paneStack) return; | 
| Chris@73 | 2569 | 
| Chris@73 | 2570     Pane *currentPane = m_paneStack->getCurrentPane(); | 
| Chris@73 | 2571     if (!currentPane) return; | 
| Chris@73 | 2572 | 
| Chris@73 | 2573     for (int i = 0; i < m_paneStack->getPaneCount(); ++i) { | 
| Chris@73 | 2574         if (m_paneStack->getPane(i) == currentPane) { | 
| Chris@73 | 2575             if (i == m_paneStack->getPaneCount()-1) return; | 
| Chris@73 | 2576             m_paneStack->setCurrentPane(m_paneStack->getPane(i+1)); | 
| Chris@73 | 2577             updateMenuStates(); | 
| Chris@73 | 2578             return; | 
| Chris@73 | 2579         } | 
| Chris@73 | 2580     } | 
| Chris@73 | 2581 } | 
| Chris@73 | 2582 | 
| Chris@73 | 2583 void | 
| Chris@73 | 2584 MainWindowBase::previousLayer() | 
| Chris@73 | 2585 { | 
| Chris@73 | 2586     //!!! Not right -- pane lists layers in stacking order | 
| Chris@73 | 2587 | 
| Chris@73 | 2588     if (!m_paneStack) return; | 
| Chris@73 | 2589 | 
| Chris@73 | 2590     Pane *currentPane = m_paneStack->getCurrentPane(); | 
| Chris@73 | 2591     if (!currentPane) return; | 
| Chris@73 | 2592 | 
| Chris@73 | 2593     Layer *currentLayer = currentPane->getSelectedLayer(); | 
| Chris@73 | 2594     if (!currentLayer) return; | 
| Chris@73 | 2595 | 
| Chris@73 | 2596     for (int i = 0; i < currentPane->getLayerCount(); ++i) { | 
| Chris@73 | 2597         if (currentPane->getLayer(i) == currentLayer) { | 
| Chris@73 | 2598             if (i == 0) return; | 
| Chris@73 | 2599             m_paneStack->setCurrentLayer(currentPane, | 
| Chris@73 | 2600                                          currentPane->getLayer(i-1)); | 
| Chris@73 | 2601             updateMenuStates(); | 
| Chris@73 | 2602             return; | 
| Chris@73 | 2603         } | 
| Chris@73 | 2604     } | 
| Chris@73 | 2605 } | 
| Chris@73 | 2606 | 
| Chris@73 | 2607 void | 
| Chris@73 | 2608 MainWindowBase::nextLayer() | 
| Chris@73 | 2609 { | 
| Chris@73 | 2610     //!!! Not right -- pane lists layers in stacking order | 
| Chris@73 | 2611 | 
| Chris@73 | 2612     if (!m_paneStack) return; | 
| Chris@73 | 2613 | 
| Chris@73 | 2614     Pane *currentPane = m_paneStack->getCurrentPane(); | 
| Chris@73 | 2615     if (!currentPane) return; | 
| Chris@73 | 2616 | 
| Chris@73 | 2617     Layer *currentLayer = currentPane->getSelectedLayer(); | 
| Chris@73 | 2618     if (!currentLayer) return; | 
| Chris@73 | 2619 | 
| Chris@73 | 2620     for (int i = 0; i < currentPane->getLayerCount(); ++i) { | 
| Chris@73 | 2621         if (currentPane->getLayer(i) == currentLayer) { | 
| Chris@73 | 2622             if (i == currentPane->getLayerCount()-1) return; | 
| Chris@73 | 2623             m_paneStack->setCurrentLayer(currentPane, | 
| Chris@73 | 2624                                          currentPane->getLayer(i+1)); | 
| Chris@73 | 2625             updateMenuStates(); | 
| Chris@73 | 2626             return; | 
| Chris@73 | 2627         } | 
| Chris@73 | 2628     } | 
| Chris@73 | 2629 } | 
| Chris@73 | 2630 | 
| Chris@73 | 2631 void | 
| Chris@45 | 2632 MainWindowBase::playbackFrameChanged(unsigned long frame) | 
| Chris@45 | 2633 { | 
| Chris@45 | 2634     if (!(m_playSource && m_playSource->isPlaying()) || !getMainModel()) return; | 
| Chris@45 | 2635 | 
| Chris@187 | 2636     updatePositionStatusDisplays(); | 
| Chris@187 | 2637 | 
| Chris@45 | 2638     RealTime now = RealTime::frame2RealTime | 
| Chris@45 | 2639         (frame, getMainModel()->getSampleRate()); | 
| Chris@45 | 2640 | 
| Chris@45 | 2641     if (now.sec == m_lastPlayStatusSec) return; | 
| Chris@45 | 2642 | 
| Chris@45 | 2643     RealTime then = RealTime::frame2RealTime | 
| Chris@45 | 2644         (m_playSource->getPlayEndFrame(), getMainModel()->getSampleRate()); | 
| Chris@45 | 2645 | 
| Chris@45 | 2646     QString nowStr; | 
| Chris@45 | 2647     QString thenStr; | 
| Chris@45 | 2648     QString remainingStr; | 
| Chris@45 | 2649 | 
| Chris@45 | 2650     if (then.sec > 10) { | 
| Chris@45 | 2651         nowStr = now.toSecText().c_str(); | 
| Chris@45 | 2652         thenStr = then.toSecText().c_str(); | 
| Chris@45 | 2653         remainingStr = (then - now).toSecText().c_str(); | 
| Chris@45 | 2654         m_lastPlayStatusSec = now.sec; | 
| Chris@45 | 2655     } else { | 
| Chris@45 | 2656         nowStr = now.toText(true).c_str(); | 
| Chris@45 | 2657         thenStr = then.toText(true).c_str(); | 
| Chris@45 | 2658         remainingStr = (then - now).toText(true).c_str(); | 
| Chris@45 | 2659     } | 
| Chris@45 | 2660 | 
| Chris@45 | 2661     m_myStatusMessage = tr("Playing: %1 of %2 (%3 remaining)") | 
| Chris@45 | 2662         .arg(nowStr).arg(thenStr).arg(remainingStr); | 
| Chris@45 | 2663 | 
| Chris@45 | 2664     statusBar()->showMessage(m_myStatusMessage); | 
| Chris@45 | 2665 } | 
| Chris@45 | 2666 | 
| Chris@45 | 2667 void | 
| Chris@45 | 2668 MainWindowBase::globalCentreFrameChanged(unsigned long ) | 
| Chris@45 | 2669 { | 
| Chris@45 | 2670     if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return; | 
| Chris@45 | 2671     Pane *p = 0; | 
| Chris@45 | 2672     if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return; | 
| Chris@45 | 2673     if (!p->getFollowGlobalPan()) return; | 
| Chris@45 | 2674     updateVisibleRangeDisplay(p); | 
| Chris@45 | 2675 } | 
| Chris@45 | 2676 | 
| Chris@45 | 2677 void | 
| Chris@123 | 2678 MainWindowBase::viewCentreFrameChanged(View *v, unsigned long frame) | 
| Chris@45 | 2679 { | 
| Chris@130 | 2680 //    std::cerr << "MainWindowBase::viewCentreFrameChanged(" << v << "," << frame << ")" << std::endl; | 
| Chris@123 | 2681 | 
| Chris@123 | 2682     if (m_viewDataDialogMap.find(v) != m_viewDataDialogMap.end()) { | 
| Chris@123 | 2683         for (DataDialogSet::iterator i = m_viewDataDialogMap[v].begin(); | 
| Chris@123 | 2684              i != m_viewDataDialogMap[v].end(); ++i) { | 
| Chris@127 | 2685             (*i)->userScrolledToFrame(frame); | 
| Chris@123 | 2686         } | 
| Chris@123 | 2687     } | 
| Chris@45 | 2688     if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return; | 
| Chris@45 | 2689     Pane *p = 0; | 
| Chris@45 | 2690     if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return; | 
| Chris@45 | 2691     if (v == p) updateVisibleRangeDisplay(p); | 
| Chris@45 | 2692 } | 
| Chris@45 | 2693 | 
| Chris@45 | 2694 void | 
| Chris@45 | 2695 MainWindowBase::viewZoomLevelChanged(View *v, unsigned long , bool ) | 
| Chris@45 | 2696 { | 
| Chris@45 | 2697     if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return; | 
| Chris@45 | 2698     Pane *p = 0; | 
| Chris@45 | 2699     if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return; | 
| Chris@45 | 2700     if (v == p) updateVisibleRangeDisplay(p); | 
| Chris@45 | 2701 } | 
| Chris@45 | 2702 | 
| Chris@45 | 2703 void | 
| Chris@45 | 2704 MainWindowBase::layerAdded(Layer *) | 
| Chris@45 | 2705 { | 
| Chris@45 | 2706 //    std::cerr << "MainWindowBase::layerAdded(" << layer << ")" << std::endl; | 
| Chris@45 | 2707     updateMenuStates(); | 
| Chris@45 | 2708 } | 
| Chris@45 | 2709 | 
| Chris@45 | 2710 void | 
| Chris@45 | 2711 MainWindowBase::layerRemoved(Layer *) | 
| Chris@45 | 2712 { | 
| Chris@45 | 2713 //    std::cerr << "MainWindowBase::layerRemoved(" << layer << ")" << std::endl; | 
| Chris@45 | 2714     updateMenuStates(); | 
| Chris@45 | 2715 } | 
| Chris@45 | 2716 | 
| Chris@45 | 2717 void | 
| Chris@45 | 2718 MainWindowBase::layerAboutToBeDeleted(Layer *layer) | 
| Chris@45 | 2719 { | 
| Chris@132 | 2720 //    std::cerr << "MainWindowBase::layerAboutToBeDeleted(" << layer << ")" << std::endl; | 
| Chris@123 | 2721 | 
| Chris@128 | 2722     removeLayerEditDialog(layer); | 
| Chris@123 | 2723 | 
| Chris@47 | 2724     if (m_timeRulerLayer && (layer == m_timeRulerLayer)) { | 
| Chris@45 | 2725 //	std::cerr << "(this is the time ruler layer)" << std::endl; | 
| Chris@45 | 2726 	m_timeRulerLayer = 0; | 
| Chris@45 | 2727     } | 
| Chris@45 | 2728 } | 
| Chris@45 | 2729 | 
| Chris@45 | 2730 void | 
| Chris@45 | 2731 MainWindowBase::layerInAView(Layer *layer, bool inAView) | 
| Chris@45 | 2732 { | 
| Chris@132 | 2733 //    std::cerr << "MainWindowBase::layerInAView(" << layer << "," << inAView << ")" << std::endl; | 
| Chris@128 | 2734 | 
| Chris@128 | 2735     if (!inAView) removeLayerEditDialog(layer); | 
| Chris@45 | 2736 | 
| Chris@45 | 2737     // Check whether we need to add or remove model from play source | 
| Chris@45 | 2738     Model *model = layer->getModel(); | 
| Chris@45 | 2739     if (model) { | 
| Chris@45 | 2740         if (inAView) { | 
| Chris@45 | 2741             m_playSource->addModel(model); | 
| Chris@45 | 2742         } else { | 
| Chris@45 | 2743             bool found = false; | 
| Chris@45 | 2744             for (int i = 0; i < m_paneStack->getPaneCount(); ++i) { | 
| Chris@45 | 2745                 Pane *pane = m_paneStack->getPane(i); | 
| Chris@45 | 2746                 if (!pane) continue; | 
| Chris@45 | 2747                 for (int j = 0; j < pane->getLayerCount(); ++j) { | 
| Chris@45 | 2748                     Layer *pl = pane->getLayer(j); | 
| Chris@183 | 2749                     if (pl && | 
| Chris@183 | 2750                         !dynamic_cast<TimeRulerLayer *>(pl) && | 
| Chris@183 | 2751                         (pl->getModel() == model)) { | 
| Chris@45 | 2752                         found = true; | 
| Chris@45 | 2753                         break; | 
| Chris@45 | 2754                     } | 
| Chris@45 | 2755                 } | 
| Chris@45 | 2756                 if (found) break; | 
| Chris@45 | 2757             } | 
| Chris@173 | 2758             if (!found) { | 
| Chris@173 | 2759                 m_playSource->removeModel(model); | 
| Chris@173 | 2760             } | 
| Chris@45 | 2761         } | 
| Chris@45 | 2762     } | 
| Chris@45 | 2763 | 
| Chris@45 | 2764     updateMenuStates(); | 
| Chris@45 | 2765 } | 
| Chris@45 | 2766 | 
| Chris@45 | 2767 void | 
| Chris@128 | 2768 MainWindowBase::removeLayerEditDialog(Layer *layer) | 
| Chris@128 | 2769 { | 
| Chris@128 | 2770     if (m_layerDataDialogMap.find(layer) != m_layerDataDialogMap.end()) { | 
| Chris@128 | 2771 | 
| Chris@128 | 2772         ModelDataTableDialog *dialog = m_layerDataDialogMap[layer]; | 
| Chris@128 | 2773 | 
| Chris@128 | 2774         for (ViewDataDialogMap::iterator vi = m_viewDataDialogMap.begin(); | 
| Chris@128 | 2775              vi != m_viewDataDialogMap.end(); ++vi) { | 
| Chris@128 | 2776             vi->second.erase(dialog); | 
| Chris@128 | 2777         } | 
| Chris@128 | 2778 | 
| Chris@128 | 2779         m_layerDataDialogMap.erase(layer); | 
| Chris@128 | 2780         delete dialog; | 
| Chris@128 | 2781     } | 
| Chris@128 | 2782 } | 
| Chris@128 | 2783 | 
| Chris@128 | 2784 void | 
| Chris@45 | 2785 MainWindowBase::modelAdded(Model *model) | 
| Chris@45 | 2786 { | 
| Chris@45 | 2787 //    std::cerr << "MainWindowBase::modelAdded(" << model << ")" << std::endl; | 
| Chris@45 | 2788     m_playSource->addModel(model); | 
| Chris@45 | 2789 } | 
| Chris@45 | 2790 | 
| Chris@45 | 2791 void | 
| Chris@45 | 2792 MainWindowBase::mainModelChanged(WaveFileModel *model) | 
| Chris@45 | 2793 { | 
| Chris@45 | 2794 //    std::cerr << "MainWindowBase::mainModelChanged(" << model << ")" << std::endl; | 
| Chris@45 | 2795     updateDescriptionLabel(); | 
| Chris@45 | 2796     if (model) m_viewManager->setMainModelSampleRate(model->getSampleRate()); | 
| Chris@45 | 2797     if (model && !m_playTarget && m_audioOutput) createPlayTarget(); | 
| Chris@45 | 2798 } | 
| Chris@45 | 2799 | 
| Chris@45 | 2800 void | 
| Chris@45 | 2801 MainWindowBase::modelAboutToBeDeleted(Model *model) | 
| Chris@45 | 2802 { | 
| Chris@45 | 2803 //    std::cerr << "MainWindowBase::modelAboutToBeDeleted(" << model << ")" << std::endl; | 
| Chris@45 | 2804     if (model == m_viewManager->getPlaybackModel()) { | 
| Chris@45 | 2805         m_viewManager->setPlaybackModel(0); | 
| Chris@45 | 2806     } | 
| Chris@45 | 2807     m_playSource->removeModel(model); | 
| Chris@45 | 2808     FFTDataServer::modelAboutToBeDeleted(model); | 
| Chris@45 | 2809 } | 
| Chris@45 | 2810 | 
| Chris@45 | 2811 void | 
| Chris@55 | 2812 MainWindowBase::paneDeleteButtonClicked(Pane *pane) | 
| Chris@55 | 2813 { | 
| Chris@55 | 2814     bool found = false; | 
| Chris@55 | 2815     for (int i = 0; i < m_paneStack->getPaneCount(); ++i) { | 
| Chris@55 | 2816         if (m_paneStack->getPane(i) == pane) { | 
| Chris@55 | 2817             found = true; | 
| Chris@55 | 2818             break; | 
| Chris@55 | 2819         } | 
| Chris@55 | 2820     } | 
| Chris@55 | 2821     if (!found) { | 
| Chris@55 | 2822         std::cerr << "MainWindowBase::paneDeleteButtonClicked: Unknown pane " | 
| Chris@55 | 2823                   << pane << std::endl; | 
| Chris@55 | 2824         return; | 
| Chris@55 | 2825     } | 
| Chris@55 | 2826 | 
| Chris@55 | 2827     CommandHistory::getInstance()->startCompoundOperation | 
| Chris@55 | 2828 	(tr("Delete Pane"), true); | 
| Chris@55 | 2829 | 
| Chris@55 | 2830     while (pane->getLayerCount() > 0) { | 
| Chris@55 | 2831         Layer *layer = pane->getLayer(0); | 
| Chris@55 | 2832         if (layer) { | 
| Chris@55 | 2833             m_document->removeLayerFromView(pane, layer); | 
| Chris@55 | 2834         } else { | 
| Chris@55 | 2835             break; | 
| Chris@55 | 2836         } | 
| Chris@55 | 2837     } | 
| Chris@55 | 2838 | 
| Chris@55 | 2839     RemovePaneCommand *command = new RemovePaneCommand(this, pane); | 
| Chris@55 | 2840     CommandHistory::getInstance()->addCommand(command); | 
| Chris@55 | 2841 | 
| Chris@55 | 2842     CommandHistory::getInstance()->endCompoundOperation(); | 
| Chris@55 | 2843 | 
| Chris@55 | 2844     updateMenuStates(); | 
| Chris@55 | 2845 } | 
| Chris@55 | 2846 | 
| Chris@55 | 2847 void | 
| Chris@45 | 2848 MainWindowBase::pollOSC() | 
| Chris@45 | 2849 { | 
| Chris@45 | 2850     if (!m_oscQueue || m_oscQueue->isEmpty()) return; | 
| Chris@45 | 2851     std::cerr << "MainWindowBase::pollOSC: have " << m_oscQueue->getMessagesAvailable() << " messages" << std::endl; | 
| Chris@45 | 2852 | 
| Chris@45 | 2853     if (m_openingAudioFile) return; | 
| Chris@45 | 2854 | 
| Chris@45 | 2855     OSCMessage message = m_oscQueue->readMessage(); | 
| Chris@45 | 2856 | 
| Chris@45 | 2857     if (message.getTarget() != 0) { | 
| Chris@45 | 2858         return; //!!! for now -- this class is target 0, others not handled yet | 
| Chris@45 | 2859     } | 
| Chris@45 | 2860 | 
| Chris@45 | 2861     handleOSCMessage(message); | 
| Chris@45 | 2862 } | 
| Chris@45 | 2863 | 
| Chris@45 | 2864 void | 
| Chris@45 | 2865 MainWindowBase::inProgressSelectionChanged() | 
| Chris@45 | 2866 { | 
| Chris@45 | 2867     Pane *currentPane = 0; | 
| Chris@45 | 2868     if (m_paneStack) currentPane = m_paneStack->getCurrentPane(); | 
| Chris@45 | 2869     if (currentPane) updateVisibleRangeDisplay(currentPane); | 
| Chris@45 | 2870 } | 
| Chris@45 | 2871 | 
| Chris@45 | 2872 void | 
| Chris@45 | 2873 MainWindowBase::contextHelpChanged(const QString &s) | 
| Chris@45 | 2874 { | 
| Chris@45 | 2875     if (s == "" && m_myStatusMessage != "") { | 
| Chris@45 | 2876         statusBar()->showMessage(m_myStatusMessage); | 
| Chris@45 | 2877         return; | 
| Chris@45 | 2878     } | 
| Chris@45 | 2879     statusBar()->showMessage(s); | 
| Chris@45 | 2880 } | 
| Chris@45 | 2881 | 
| Chris@45 | 2882 void | 
| Chris@45 | 2883 MainWindowBase::openHelpUrl(QString url) | 
| Chris@45 | 2884 { | 
| Chris@45 | 2885     // This method mostly lifted from Qt Assistant source code | 
| Chris@45 | 2886 | 
| Chris@45 | 2887     QProcess *process = new QProcess(this); | 
| Chris@45 | 2888     connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater())); | 
| Chris@45 | 2889 | 
| Chris@45 | 2890     QStringList args; | 
| Chris@45 | 2891 | 
| Chris@45 | 2892 #ifdef Q_OS_MAC | 
| Chris@45 | 2893     args.append(url); | 
| Chris@45 | 2894     process->start("open", args); | 
| Chris@45 | 2895 #else | 
| Chris@45 | 2896 #ifdef Q_OS_WIN32 | 
| Chris@45 | 2897 | 
| Chris@45 | 2898 	QString pf(getenv("ProgramFiles")); | 
| Chris@45 | 2899 	QString command = pf + QString("\\Internet Explorer\\IEXPLORE.EXE"); | 
| Chris@45 | 2900 | 
| Chris@45 | 2901 	args.append(url); | 
| Chris@45 | 2902 	process->start(command, args); | 
| Chris@45 | 2903 | 
| Chris@45 | 2904 #else | 
| Chris@45 | 2905 #ifdef Q_WS_X11 | 
| Chris@45 | 2906     if (!qgetenv("KDE_FULL_SESSION").isEmpty()) { | 
| Chris@45 | 2907         args.append("exec"); | 
| Chris@45 | 2908         args.append(url); | 
| Chris@45 | 2909         process->start("kfmclient", args); | 
| Chris@45 | 2910     } else if (!qgetenv("BROWSER").isEmpty()) { | 
| Chris@45 | 2911         args.append(url); | 
| Chris@45 | 2912         process->start(qgetenv("BROWSER"), args); | 
| Chris@45 | 2913     } else { | 
| Chris@45 | 2914         args.append(url); | 
| Chris@45 | 2915         process->start("firefox", args); | 
| Chris@45 | 2916     } | 
| Chris@45 | 2917 #endif | 
| Chris@45 | 2918 #endif | 
| Chris@45 | 2919 #endif | 
| Chris@45 | 2920 } | 
| Chris@45 | 2921 | 
| Chris@180 | 2922 |