annotate framework/MainWindowBase.cpp @ 109:2dd30a7cd21a

* More work to abstract out interactive components used in the data library, so that it does not need to depend on QtGui.
author Chris Cannam
date Fri, 14 Mar 2008 17:14:21 +0000
parents e25e8f5d785b
children 0c1ea5ff6518
rev   line source
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@45 26 #include "view/ViewManager.h"
Chris@45 27
Chris@45 28 #include "layer/WaveformLayer.h"
Chris@45 29 #include "layer/TimeRulerLayer.h"
Chris@45 30 #include "layer/TimeInstantLayer.h"
Chris@45 31 #include "layer/TimeValueLayer.h"
Chris@45 32 #include "layer/Colour3DPlotLayer.h"
Chris@45 33 #include "layer/SliceLayer.h"
Chris@45 34 #include "layer/SliceableLayer.h"
Chris@45 35 #include "layer/ImageLayer.h"
Chris@45 36
Chris@45 37 #include "widgets/ListInputDialog.h"
Chris@105 38 #include "widgets/CommandHistory.h"
Chris@109 39 #include "widgets/ProgressDialog.h"
Chris@109 40 #include "widgets/MIDIFileImportDialog.h"
Chris@109 41 #include "widgets/CSVFormatDialog.h"
Chris@45 42
Chris@45 43 #include "audioio/AudioCallbackPlaySource.h"
Chris@45 44 #include "audioio/AudioCallbackPlayTarget.h"
Chris@45 45 #include "audioio/AudioTargetFactory.h"
Chris@45 46 #include "audioio/PlaySpeedRangeMapper.h"
Chris@45 47 #include "data/fileio/DataFileReaderFactory.h"
Chris@45 48 #include "data/fileio/PlaylistFileReader.h"
Chris@45 49 #include "data/fileio/WavFileWriter.h"
Chris@45 50 #include "data/fileio/CSVFileWriter.h"
Chris@45 51 #include "data/fileio/MIDIFileWriter.h"
Chris@45 52 #include "data/fileio/BZipFileDevice.h"
Chris@45 53 #include "data/fileio/FileSource.h"
Chris@45 54
Chris@45 55 #include "data/fft/FFTDataServer.h"
Chris@45 56
Chris@45 57 #include "base/RecentFiles.h"
Chris@45 58
Chris@45 59 #include "base/PlayParameterRepository.h"
Chris@45 60 #include "base/XmlExportable.h"
Chris@45 61 #include "base/Profiler.h"
Chris@45 62 #include "base/Preferences.h"
Chris@45 63
Chris@45 64 #include "data/osc/OSCQueue.h"
Chris@45 65
Chris@45 66 #include <QApplication>
Chris@45 67 #include <QMessageBox>
Chris@45 68 #include <QGridLayout>
Chris@45 69 #include <QLabel>
Chris@45 70 #include <QAction>
Chris@45 71 #include <QMenuBar>
Chris@45 72 #include <QToolBar>
Chris@45 73 #include <QInputDialog>
Chris@45 74 #include <QStatusBar>
Chris@45 75 #include <QTreeView>
Chris@45 76 #include <QFile>
Chris@45 77 #include <QFileInfo>
Chris@45 78 #include <QDir>
Chris@45 79 #include <QTextStream>
Chris@45 80 #include <QProcess>
Chris@45 81 #include <QShortcut>
Chris@45 82 #include <QSettings>
Chris@45 83 #include <QDateTime>
Chris@45 84 #include <QProcess>
Chris@45 85 #include <QCheckBox>
Chris@45 86 #include <QRegExp>
Chris@45 87 #include <QScrollArea>
Chris@45 88
Chris@45 89 #include <iostream>
Chris@45 90 #include <cstdio>
Chris@45 91 #include <errno.h>
Chris@45 92
Chris@45 93 using std::cerr;
Chris@45 94 using std::endl;
Chris@45 95
Chris@45 96 using std::vector;
Chris@45 97 using std::map;
Chris@45 98 using std::set;
Chris@45 99
Chris@45 100
Chris@45 101 MainWindowBase::MainWindowBase(bool withAudioOutput, bool withOSCSupport) :
Chris@45 102 m_document(0),
Chris@45 103 m_paneStack(0),
Chris@45 104 m_viewManager(0),
Chris@45 105 m_timeRulerLayer(0),
Chris@45 106 m_audioOutput(withAudioOutput),
Chris@45 107 m_playSource(0),
Chris@45 108 m_playTarget(0),
Chris@45 109 m_oscQueue(withOSCSupport ? new OSCQueue() : 0),
Chris@45 110 m_recentFiles("RecentFiles", 20),
Chris@54 111 m_recentTransforms("RecentTransforms", 20),
Chris@45 112 m_documentModified(false),
Chris@45 113 m_openingAudioFile(false),
Chris@45 114 m_abandoning(false),
Chris@45 115 m_labeller(0)
Chris@45 116 {
Chris@45 117 connect(CommandHistory::getInstance(), SIGNAL(commandExecuted()),
Chris@45 118 this, SLOT(documentModified()));
Chris@45 119 connect(CommandHistory::getInstance(), SIGNAL(documentRestored()),
Chris@45 120 this, SLOT(documentRestored()));
Chris@45 121
Chris@45 122 m_viewManager = new ViewManager();
Chris@45 123 connect(m_viewManager, SIGNAL(selectionChanged()),
Chris@45 124 this, SLOT(updateMenuStates()));
Chris@45 125 connect(m_viewManager, SIGNAL(inProgressSelectionChanged()),
Chris@45 126 this, SLOT(inProgressSelectionChanged()));
Chris@45 127
Chris@105 128 // set a sensible default font size for views -- cannot do this
Chris@105 129 // in Preferences, which is in base and not supposed to use QtGui
Chris@105 130 int viewFontSize = QApplication::font().pointSize() * 0.9;
Chris@105 131 QSettings settings;
Chris@105 132 settings.beginGroup("Preferences");
Chris@105 133 viewFontSize = settings.value("view-font-size", viewFontSize).toInt();
Chris@105 134 settings.setValue("view-font-size", viewFontSize);
Chris@105 135 settings.endGroup();
Chris@105 136
Chris@45 137 Preferences::BackgroundMode mode =
Chris@45 138 Preferences::getInstance()->getBackgroundMode();
Chris@45 139 m_initialDarkBackground = m_viewManager->getGlobalDarkBackground();
Chris@45 140 if (mode != Preferences::BackgroundFromTheme) {
Chris@45 141 m_viewManager->setGlobalDarkBackground
Chris@45 142 (mode == Preferences::DarkBackground);
Chris@45 143 }
Chris@45 144
Chris@45 145 m_paneStack = new PaneStack(0, m_viewManager);
Chris@45 146 connect(m_paneStack, SIGNAL(currentPaneChanged(Pane *)),
Chris@45 147 this, SLOT(currentPaneChanged(Pane *)));
Chris@45 148 connect(m_paneStack, SIGNAL(currentLayerChanged(Pane *, Layer *)),
Chris@45 149 this, SLOT(currentLayerChanged(Pane *, Layer *)));
Chris@45 150 connect(m_paneStack, SIGNAL(rightButtonMenuRequested(Pane *, QPoint)),
Chris@45 151 this, SLOT(rightButtonMenuRequested(Pane *, QPoint)));
Chris@45 152 connect(m_paneStack, SIGNAL(contextHelpChanged(const QString &)),
Chris@45 153 this, SLOT(contextHelpChanged(const QString &)));
Chris@45 154 connect(m_paneStack, SIGNAL(paneAdded(Pane *)),
Chris@45 155 this, SLOT(paneAdded(Pane *)));
Chris@45 156 connect(m_paneStack, SIGNAL(paneHidden(Pane *)),
Chris@45 157 this, SLOT(paneHidden(Pane *)));
Chris@45 158 connect(m_paneStack, SIGNAL(paneAboutToBeDeleted(Pane *)),
Chris@45 159 this, SLOT(paneAboutToBeDeleted(Pane *)));
Chris@45 160 connect(m_paneStack, SIGNAL(dropAccepted(Pane *, QStringList)),
Chris@45 161 this, SLOT(paneDropAccepted(Pane *, QStringList)));
Chris@45 162 connect(m_paneStack, SIGNAL(dropAccepted(Pane *, QString)),
Chris@45 163 this, SLOT(paneDropAccepted(Pane *, QString)));
Chris@55 164 connect(m_paneStack, SIGNAL(paneDeleteButtonClicked(Pane *)),
Chris@55 165 this, SLOT(paneDeleteButtonClicked(Pane *)));
Chris@45 166
Chris@57 167 m_playSource = new AudioCallbackPlaySource(m_viewManager,
Chris@57 168 QApplication::applicationName());
Chris@45 169
Chris@45 170 connect(m_playSource, SIGNAL(sampleRateMismatch(size_t, size_t, bool)),
Chris@45 171 this, SLOT(sampleRateMismatch(size_t, size_t, bool)));
Chris@45 172 connect(m_playSource, SIGNAL(audioOverloadPluginDisabled()),
Chris@45 173 this, SLOT(audioOverloadPluginDisabled()));
Chris@45 174
Chris@45 175 connect(m_viewManager, SIGNAL(outputLevelsChanged(float, float)),
Chris@45 176 this, SLOT(outputLevelsChanged(float, float)));
Chris@45 177
Chris@45 178 connect(m_viewManager, SIGNAL(playbackFrameChanged(unsigned long)),
Chris@45 179 this, SLOT(playbackFrameChanged(unsigned long)));
Chris@45 180
Chris@45 181 connect(m_viewManager, SIGNAL(globalCentreFrameChanged(unsigned long)),
Chris@45 182 this, SLOT(globalCentreFrameChanged(unsigned long)));
Chris@45 183
Chris@45 184 connect(m_viewManager, SIGNAL(viewCentreFrameChanged(View *, unsigned long)),
Chris@45 185 this, SLOT(viewCentreFrameChanged(View *, unsigned long)));
Chris@45 186
Chris@45 187 connect(m_viewManager, SIGNAL(viewZoomLevelChanged(View *, unsigned long, bool)),
Chris@45 188 this, SLOT(viewZoomLevelChanged(View *, unsigned long, bool)));
Chris@45 189
Chris@45 190 connect(Preferences::getInstance(),
Chris@45 191 SIGNAL(propertyChanged(PropertyContainer::PropertyName)),
Chris@45 192 this,
Chris@45 193 SLOT(preferenceChanged(PropertyContainer::PropertyName)));
Chris@45 194
Chris@45 195 if (m_oscQueue && m_oscQueue->isOK()) {
Chris@45 196 connect(m_oscQueue, SIGNAL(messagesAvailable()), this, SLOT(pollOSC()));
Chris@45 197 QTimer *oscTimer = new QTimer(this);
Chris@45 198 connect(oscTimer, SIGNAL(timeout()), this, SLOT(pollOSC()));
Chris@45 199 oscTimer->start(1000);
Chris@45 200 }
Chris@45 201
Chris@45 202 Labeller::ValueType labellerType = Labeller::ValueFromTwoLevelCounter;
Chris@45 203 settings.beginGroup("MainWindow");
Chris@45 204 labellerType = (Labeller::ValueType)
Chris@45 205 settings.value("labellertype", (int)labellerType).toInt();
Chris@45 206 int cycle = settings.value("labellercycle", 4).toInt();
Chris@45 207 settings.endGroup();
Chris@45 208
Chris@45 209 m_labeller = new Labeller(labellerType);
Chris@45 210 m_labeller->setCounterCycleSize(cycle);
Chris@45 211 }
Chris@45 212
Chris@45 213 MainWindowBase::~MainWindowBase()
Chris@45 214 {
Chris@70 215 if (m_playTarget) m_playTarget->shutdown();
Chris@70 216 // delete m_playTarget;
Chris@45 217 delete m_playSource;
Chris@45 218 delete m_viewManager;
Chris@45 219 delete m_oscQueue;
Chris@45 220 Profiles::getInstance()->dump();
Chris@45 221 }
Chris@45 222
Chris@45 223 QString
Chris@45 224 MainWindowBase::getOpenFileName(FileFinder::FileType type)
Chris@45 225 {
Chris@45 226 FileFinder *ff = FileFinder::getInstance();
Chris@45 227 switch (type) {
Chris@45 228 case FileFinder::SessionFile:
Chris@45 229 return ff->getOpenFileName(type, m_sessionFile);
Chris@45 230 case FileFinder::AudioFile:
Chris@45 231 return ff->getOpenFileName(type, m_audioFile);
Chris@45 232 case FileFinder::LayerFile:
Chris@45 233 return ff->getOpenFileName(type, m_sessionFile);
Chris@45 234 case FileFinder::LayerFileNoMidi:
Chris@45 235 return ff->getOpenFileName(type, m_sessionFile);
Chris@45 236 case FileFinder::SessionOrAudioFile:
Chris@45 237 return ff->getOpenFileName(type, m_sessionFile);
Chris@45 238 case FileFinder::ImageFile:
Chris@45 239 return ff->getOpenFileName(type, m_sessionFile);
Chris@45 240 case FileFinder::AnyFile:
Chris@45 241 if (getMainModel() != 0 &&
Chris@45 242 m_paneStack != 0 &&
Chris@45 243 m_paneStack->getCurrentPane() != 0) { // can import a layer
Chris@45 244 return ff->getOpenFileName(FileFinder::AnyFile, m_sessionFile);
Chris@45 245 } else {
Chris@45 246 return ff->getOpenFileName(FileFinder::SessionOrAudioFile,
Chris@45 247 m_sessionFile);
Chris@45 248 }
Chris@45 249 }
Chris@45 250 return "";
Chris@45 251 }
Chris@45 252
Chris@45 253 QString
Chris@45 254 MainWindowBase::getSaveFileName(FileFinder::FileType type)
Chris@45 255 {
Chris@45 256 FileFinder *ff = FileFinder::getInstance();
Chris@45 257 switch (type) {
Chris@45 258 case FileFinder::SessionFile:
Chris@45 259 return ff->getSaveFileName(type, m_sessionFile);
Chris@45 260 case FileFinder::AudioFile:
Chris@45 261 return ff->getSaveFileName(type, m_audioFile);
Chris@45 262 case FileFinder::LayerFile:
Chris@45 263 return ff->getSaveFileName(type, m_sessionFile);
Chris@45 264 case FileFinder::LayerFileNoMidi:
Chris@45 265 return ff->getSaveFileName(type, m_sessionFile);
Chris@45 266 case FileFinder::SessionOrAudioFile:
Chris@45 267 return ff->getSaveFileName(type, m_sessionFile);
Chris@45 268 case FileFinder::ImageFile:
Chris@45 269 return ff->getSaveFileName(type, m_sessionFile);
Chris@45 270 case FileFinder::AnyFile:
Chris@45 271 return ff->getSaveFileName(type, m_sessionFile);
Chris@45 272 }
Chris@45 273 return "";
Chris@45 274 }
Chris@45 275
Chris@45 276 void
Chris@45 277 MainWindowBase::registerLastOpenedFilePath(FileFinder::FileType type, QString path)
Chris@45 278 {
Chris@45 279 FileFinder *ff = FileFinder::getInstance();
Chris@45 280 ff->registerLastOpenedFilePath(type, path);
Chris@45 281 }
Chris@45 282
Chris@45 283 void
Chris@45 284 MainWindowBase::updateMenuStates()
Chris@45 285 {
Chris@45 286 Pane *currentPane = 0;
Chris@45 287 Layer *currentLayer = 0;
Chris@45 288
Chris@45 289 if (m_paneStack) currentPane = m_paneStack->getCurrentPane();
Chris@45 290 if (currentPane) currentLayer = currentPane->getSelectedLayer();
Chris@45 291
Chris@73 292 bool havePrevPane = false, haveNextPane = false;
Chris@73 293 bool havePrevLayer = false, haveNextLayer = false;
Chris@73 294
Chris@73 295 if (currentPane) {
Chris@73 296 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@73 297 if (m_paneStack->getPane(i) == currentPane) {
Chris@73 298 if (i > 0) havePrevPane = true;
Chris@73 299 if (i < m_paneStack->getPaneCount()-1) haveNextPane = true;
Chris@73 300 break;
Chris@73 301 }
Chris@73 302 }
Chris@73 303 if (currentLayer) {
Chris@73 304 for (int i = 0; i < currentPane->getLayerCount(); ++i) {
Chris@73 305 if (currentPane->getLayer(i) == currentLayer) {
Chris@73 306 if (i > 0) havePrevLayer = true;
Chris@73 307 if (i < currentPane->getLayerCount()-1) haveNextLayer = true;
Chris@73 308 break;
Chris@73 309 }
Chris@73 310 }
Chris@73 311 }
Chris@73 312 }
Chris@73 313
Chris@45 314 bool haveCurrentPane =
Chris@45 315 (currentPane != 0);
Chris@45 316 bool haveCurrentLayer =
Chris@45 317 (haveCurrentPane &&
Chris@45 318 (currentLayer != 0));
Chris@45 319 bool haveMainModel =
Chris@45 320 (getMainModel() != 0);
Chris@45 321 bool havePlayTarget =
Chris@45 322 (m_playTarget != 0);
Chris@45 323 bool haveSelection =
Chris@45 324 (m_viewManager &&
Chris@45 325 !m_viewManager->getSelections().empty());
Chris@45 326 bool haveCurrentEditableLayer =
Chris@45 327 (haveCurrentLayer &&
Chris@45 328 currentLayer->isLayerEditable());
Chris@45 329 bool haveCurrentTimeInstantsLayer =
Chris@45 330 (haveCurrentLayer &&
Chris@45 331 dynamic_cast<TimeInstantLayer *>(currentLayer));
Chris@45 332 bool haveCurrentColour3DPlot =
Chris@45 333 (haveCurrentLayer &&
Chris@45 334 dynamic_cast<Colour3DPlotLayer *>(currentLayer));
Chris@45 335 bool haveClipboardContents =
Chris@45 336 (m_viewManager &&
Chris@45 337 !m_viewManager->getClipboard().empty());
Chris@45 338
Chris@45 339 emit canAddPane(haveMainModel);
Chris@45 340 emit canDeleteCurrentPane(haveCurrentPane);
Chris@45 341 emit canZoom(haveMainModel && haveCurrentPane);
Chris@45 342 emit canScroll(haveMainModel && haveCurrentPane);
Chris@45 343 emit canAddLayer(haveMainModel && haveCurrentPane);
Chris@45 344 emit canImportMoreAudio(haveMainModel);
Chris@45 345 emit canImportLayer(haveMainModel && haveCurrentPane);
Chris@45 346 emit canExportAudio(haveMainModel);
Chris@45 347 emit canExportLayer(haveMainModel &&
Chris@45 348 (haveCurrentEditableLayer || haveCurrentColour3DPlot));
Chris@45 349 emit canExportImage(haveMainModel && haveCurrentPane);
Chris@45 350 emit canDeleteCurrentLayer(haveCurrentLayer);
Chris@45 351 emit canRenameLayer(haveCurrentLayer);
Chris@45 352 emit canEditLayer(haveCurrentEditableLayer);
Chris@45 353 emit canMeasureLayer(haveCurrentLayer);
Chris@45 354 emit canSelect(haveMainModel && haveCurrentPane);
Chris@45 355 emit canPlay(havePlayTarget);
Chris@45 356 emit canFfwd(true);
Chris@45 357 emit canRewind(true);
Chris@87 358 emit canPaste(haveClipboardContents);
Chris@45 359 emit canInsertInstant(haveCurrentPane);
Chris@45 360 emit canInsertInstantsAtBoundaries(haveCurrentPane && haveSelection);
Chris@45 361 emit canRenumberInstants(haveCurrentTimeInstantsLayer && haveSelection);
Chris@45 362 emit canPlaySelection(haveMainModel && havePlayTarget && haveSelection);
Chris@45 363 emit canClearSelection(haveSelection);
Chris@45 364 emit canEditSelection(haveSelection && haveCurrentEditableLayer);
Chris@45 365 emit canSave(m_sessionFile != "" && m_documentModified);
Chris@73 366 emit canSelectPreviousPane(havePrevPane);
Chris@73 367 emit canSelectNextPane(haveNextPane);
Chris@73 368 emit canSelectPreviousLayer(havePrevLayer);
Chris@73 369 emit canSelectNextLayer(haveNextLayer);
Chris@45 370 }
Chris@45 371
Chris@45 372 void
Chris@45 373 MainWindowBase::documentModified()
Chris@45 374 {
Chris@45 375 // std::cerr << "MainWindowBase::documentModified" << std::endl;
Chris@45 376
Chris@45 377 if (!m_documentModified) {
Chris@45 378 //!!! this in subclass implementation?
Chris@45 379 setWindowTitle(tr("%1 (modified)").arg(windowTitle()));
Chris@45 380 }
Chris@45 381
Chris@45 382 m_documentModified = true;
Chris@45 383 updateMenuStates();
Chris@45 384 }
Chris@45 385
Chris@45 386 void
Chris@45 387 MainWindowBase::documentRestored()
Chris@45 388 {
Chris@45 389 // std::cerr << "MainWindowBase::documentRestored" << std::endl;
Chris@45 390
Chris@45 391 if (m_documentModified) {
Chris@45 392 //!!! this in subclass implementation?
Chris@45 393 QString wt(windowTitle());
Chris@45 394 wt.replace(tr(" (modified)"), "");
Chris@45 395 setWindowTitle(wt);
Chris@45 396 }
Chris@45 397
Chris@45 398 m_documentModified = false;
Chris@45 399 updateMenuStates();
Chris@45 400 }
Chris@45 401
Chris@45 402 void
Chris@45 403 MainWindowBase::playLoopToggled()
Chris@45 404 {
Chris@45 405 QAction *action = dynamic_cast<QAction *>(sender());
Chris@45 406
Chris@45 407 if (action) {
Chris@45 408 m_viewManager->setPlayLoopMode(action->isChecked());
Chris@45 409 } else {
Chris@45 410 m_viewManager->setPlayLoopMode(!m_viewManager->getPlayLoopMode());
Chris@45 411 }
Chris@45 412 }
Chris@45 413
Chris@45 414 void
Chris@45 415 MainWindowBase::playSelectionToggled()
Chris@45 416 {
Chris@45 417 QAction *action = dynamic_cast<QAction *>(sender());
Chris@45 418
Chris@45 419 if (action) {
Chris@45 420 m_viewManager->setPlaySelectionMode(action->isChecked());
Chris@45 421 } else {
Chris@45 422 m_viewManager->setPlaySelectionMode(!m_viewManager->getPlaySelectionMode());
Chris@45 423 }
Chris@45 424 }
Chris@45 425
Chris@45 426 void
Chris@45 427 MainWindowBase::playSoloToggled()
Chris@45 428 {
Chris@45 429 QAction *action = dynamic_cast<QAction *>(sender());
Chris@45 430
Chris@45 431 if (action) {
Chris@45 432 m_viewManager->setPlaySoloMode(action->isChecked());
Chris@45 433 } else {
Chris@45 434 m_viewManager->setPlaySoloMode(!m_viewManager->getPlaySoloMode());
Chris@45 435 }
Chris@45 436
Chris@45 437 if (m_viewManager->getPlaySoloMode()) {
Chris@45 438 currentPaneChanged(m_paneStack->getCurrentPane());
Chris@45 439 } else {
Chris@45 440 m_viewManager->setPlaybackModel(0);
Chris@45 441 if (m_playSource) {
Chris@45 442 m_playSource->clearSoloModelSet();
Chris@45 443 }
Chris@45 444 }
Chris@45 445 }
Chris@45 446
Chris@45 447 void
Chris@45 448 MainWindowBase::currentPaneChanged(Pane *p)
Chris@45 449 {
Chris@45 450 updateMenuStates();
Chris@45 451 updateVisibleRangeDisplay(p);
Chris@45 452
Chris@45 453 if (!p) return;
Chris@45 454
Chris@45 455 if (!(m_viewManager &&
Chris@45 456 m_playSource &&
Chris@45 457 m_viewManager->getPlaySoloMode())) {
Chris@45 458 if (m_viewManager) m_viewManager->setPlaybackModel(0);
Chris@45 459 return;
Chris@45 460 }
Chris@45 461
Chris@45 462 Model *prevPlaybackModel = m_viewManager->getPlaybackModel();
Chris@60 463
Chris@93 464 // What we want here is not the currently playing frame (unless we
Chris@93 465 // are about to clear out the audio playback buffers -- which may
Chris@93 466 // or may not be possible, depending on the audio driver). What
Chris@93 467 // we want is the frame that was last committed to the soundcard
Chris@93 468 // buffers, as the audio driver will continue playing up to that
Chris@93 469 // frame before switching to whichever one we decide we want to
Chris@93 470 // switch to, regardless of our efforts.
Chris@93 471
Chris@93 472 int frame = m_playSource->getCurrentBufferedFrame();
Chris@93 473
Chris@93 474 // std::cerr << "currentPaneChanged: current frame (in ref model) = " << frame << std::endl;
Chris@45 475
Chris@45 476 View::ModelSet soloModels = p->getModels();
Chris@45 477
Chris@57 478 View::ModelSet sources;
Chris@57 479 for (View::ModelSet::iterator mi = soloModels.begin();
Chris@57 480 mi != soloModels.end(); ++mi) {
Chris@57 481 if (*mi && (*mi)->getSourceModel()) {
Chris@57 482 sources.insert((*mi)->getSourceModel());
Chris@57 483 }
Chris@57 484 }
Chris@57 485 for (View::ModelSet::iterator mi = sources.begin();
Chris@57 486 mi != sources.end(); ++mi) {
Chris@57 487 soloModels.insert(*mi);
Chris@57 488 }
Chris@57 489
Chris@60 490 //!!! Need an "atomic" way of telling the play source that the
Chris@60 491 //playback model has changed, and changing it on ViewManager --
Chris@60 492 //the play source should be making the setPlaybackModel call to
Chris@60 493 //ViewManager
Chris@60 494
Chris@45 495 for (View::ModelSet::iterator mi = soloModels.begin();
Chris@45 496 mi != soloModels.end(); ++mi) {
Chris@45 497 if (dynamic_cast<RangeSummarisableTimeValueModel *>(*mi)) {
Chris@45 498 m_viewManager->setPlaybackModel(*mi);
Chris@45 499 }
Chris@45 500 }
Chris@45 501
Chris@45 502 RangeSummarisableTimeValueModel *a =
Chris@45 503 dynamic_cast<RangeSummarisableTimeValueModel *>(prevPlaybackModel);
Chris@45 504 RangeSummarisableTimeValueModel *b =
Chris@45 505 dynamic_cast<RangeSummarisableTimeValueModel *>(m_viewManager->
Chris@45 506 getPlaybackModel());
Chris@45 507
Chris@45 508 m_playSource->setSoloModelSet(soloModels);
Chris@45 509
Chris@45 510 if (a && b && (a != b)) {
Chris@60 511 if (m_playSource->isPlaying()) m_playSource->play(frame);
Chris@45 512 }
Chris@45 513 }
Chris@45 514
Chris@45 515 void
Chris@45 516 MainWindowBase::currentLayerChanged(Pane *p, Layer *)
Chris@45 517 {
Chris@45 518 updateMenuStates();
Chris@45 519 updateVisibleRangeDisplay(p);
Chris@45 520 }
Chris@45 521
Chris@45 522 void
Chris@45 523 MainWindowBase::selectAll()
Chris@45 524 {
Chris@45 525 if (!getMainModel()) return;
Chris@45 526 m_viewManager->setSelection(Selection(getMainModel()->getStartFrame(),
Chris@45 527 getMainModel()->getEndFrame()));
Chris@45 528 }
Chris@45 529
Chris@45 530 void
Chris@45 531 MainWindowBase::selectToStart()
Chris@45 532 {
Chris@45 533 if (!getMainModel()) return;
Chris@45 534 m_viewManager->setSelection(Selection(getMainModel()->getStartFrame(),
Chris@45 535 m_viewManager->getGlobalCentreFrame()));
Chris@45 536 }
Chris@45 537
Chris@45 538 void
Chris@45 539 MainWindowBase::selectToEnd()
Chris@45 540 {
Chris@45 541 if (!getMainModel()) return;
Chris@45 542 m_viewManager->setSelection(Selection(m_viewManager->getGlobalCentreFrame(),
Chris@45 543 getMainModel()->getEndFrame()));
Chris@45 544 }
Chris@45 545
Chris@45 546 void
Chris@45 547 MainWindowBase::selectVisible()
Chris@45 548 {
Chris@45 549 Model *model = getMainModel();
Chris@45 550 if (!model) return;
Chris@45 551
Chris@45 552 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 553 if (!currentPane) return;
Chris@45 554
Chris@45 555 size_t startFrame, endFrame;
Chris@45 556
Chris@45 557 if (currentPane->getStartFrame() < 0) startFrame = 0;
Chris@45 558 else startFrame = currentPane->getStartFrame();
Chris@45 559
Chris@45 560 if (currentPane->getEndFrame() > model->getEndFrame()) endFrame = model->getEndFrame();
Chris@45 561 else endFrame = currentPane->getEndFrame();
Chris@45 562
Chris@45 563 m_viewManager->setSelection(Selection(startFrame, endFrame));
Chris@45 564 }
Chris@45 565
Chris@45 566 void
Chris@45 567 MainWindowBase::clearSelection()
Chris@45 568 {
Chris@45 569 m_viewManager->clearSelections();
Chris@45 570 }
Chris@45 571
Chris@45 572 void
Chris@45 573 MainWindowBase::cut()
Chris@45 574 {
Chris@45 575 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 576 if (!currentPane) return;
Chris@45 577
Chris@45 578 Layer *layer = currentPane->getSelectedLayer();
Chris@45 579 if (!layer) return;
Chris@45 580
Chris@45 581 Clipboard &clipboard = m_viewManager->getClipboard();
Chris@45 582 clipboard.clear();
Chris@45 583
Chris@45 584 MultiSelection::SelectionList selections = m_viewManager->getSelections();
Chris@45 585
Chris@45 586 CommandHistory::getInstance()->startCompoundOperation(tr("Cut"), true);
Chris@45 587
Chris@45 588 for (MultiSelection::SelectionList::iterator i = selections.begin();
Chris@45 589 i != selections.end(); ++i) {
Chris@86 590 layer->copy(currentPane, *i, clipboard);
Chris@45 591 layer->deleteSelection(*i);
Chris@45 592 }
Chris@45 593
Chris@45 594 CommandHistory::getInstance()->endCompoundOperation();
Chris@45 595 }
Chris@45 596
Chris@45 597 void
Chris@45 598 MainWindowBase::copy()
Chris@45 599 {
Chris@45 600 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 601 if (!currentPane) return;
Chris@45 602
Chris@45 603 Layer *layer = currentPane->getSelectedLayer();
Chris@45 604 if (!layer) return;
Chris@45 605
Chris@45 606 Clipboard &clipboard = m_viewManager->getClipboard();
Chris@45 607 clipboard.clear();
Chris@45 608
Chris@45 609 MultiSelection::SelectionList selections = m_viewManager->getSelections();
Chris@45 610
Chris@45 611 for (MultiSelection::SelectionList::iterator i = selections.begin();
Chris@45 612 i != selections.end(); ++i) {
Chris@86 613 layer->copy(currentPane, *i, clipboard);
Chris@45 614 }
Chris@45 615 }
Chris@45 616
Chris@45 617 void
Chris@45 618 MainWindowBase::paste()
Chris@45 619 {
Chris@45 620 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 621 if (!currentPane) return;
Chris@45 622
Chris@45 623 Layer *layer = currentPane->getSelectedLayer();
Chris@45 624
Chris@45 625 Clipboard &clipboard = m_viewManager->getClipboard();
Chris@87 626 // Clipboard::PointList contents = clipboard.getPoints();
Chris@87 627
Chris@98 628 bool inCompound = false;
Chris@87 629
Chris@87 630 if (!layer || !layer->isLayerEditable()) {
Chris@87 631
Chris@87 632 CommandHistory::getInstance()->startCompoundOperation
Chris@87 633 (tr("Paste"), true);
Chris@87 634
Chris@87 635 // no suitable current layer: create one of the most
Chris@87 636 // appropriate sort
Chris@87 637 LayerFactory::LayerType type =
Chris@87 638 LayerFactory::getInstance()->getLayerTypeForClipboardContents(clipboard);
Chris@87 639 layer = m_document->createEmptyLayer(type);
Chris@87 640
Chris@87 641 if (!layer) {
Chris@87 642 CommandHistory::getInstance()->endCompoundOperation();
Chris@87 643 return;
Chris@45 644 }
Chris@87 645
Chris@87 646 m_document->addLayerToView(currentPane, layer);
Chris@87 647 m_paneStack->setCurrentLayer(currentPane, layer);
Chris@87 648
Chris@87 649 inCompound = true;
Chris@45 650 }
Chris@45 651
Chris@87 652 layer->paste(currentPane, clipboard, 0, true);
Chris@45 653
Chris@87 654 if (inCompound) CommandHistory::getInstance()->endCompoundOperation();
Chris@45 655 }
Chris@45 656
Chris@45 657 void
Chris@45 658 MainWindowBase::deleteSelected()
Chris@45 659 {
Chris@45 660 if (m_paneStack->getCurrentPane() &&
Chris@45 661 m_paneStack->getCurrentPane()->getSelectedLayer()) {
Chris@45 662
Chris@45 663 Layer *layer = m_paneStack->getCurrentPane()->getSelectedLayer();
Chris@45 664
Chris@45 665 if (m_viewManager &&
Chris@45 666 (m_viewManager->getToolMode() == ViewManager::MeasureMode)) {
Chris@45 667
Chris@45 668 layer->deleteCurrentMeasureRect();
Chris@45 669
Chris@45 670 } else {
Chris@45 671
Chris@45 672 MultiSelection::SelectionList selections =
Chris@45 673 m_viewManager->getSelections();
Chris@45 674
Chris@45 675 for (MultiSelection::SelectionList::iterator i = selections.begin();
Chris@45 676 i != selections.end(); ++i) {
Chris@45 677 layer->deleteSelection(*i);
Chris@45 678 }
Chris@45 679 }
Chris@45 680 }
Chris@45 681 }
Chris@45 682
Chris@45 683 void
Chris@45 684 MainWindowBase::insertInstant()
Chris@45 685 {
Chris@45 686 int frame = m_viewManager->getPlaybackFrame();
Chris@45 687 insertInstantAt(frame);
Chris@45 688 }
Chris@45 689
Chris@45 690 void
Chris@45 691 MainWindowBase::insertInstantsAtBoundaries()
Chris@45 692 {
Chris@45 693 MultiSelection::SelectionList selections = m_viewManager->getSelections();
Chris@45 694 for (MultiSelection::SelectionList::iterator i = selections.begin();
Chris@45 695 i != selections.end(); ++i) {
Chris@45 696 size_t start = i->getStartFrame();
Chris@45 697 size_t end = i->getEndFrame();
Chris@45 698 if (start != end) {
Chris@45 699 insertInstantAt(i->getStartFrame());
Chris@45 700 insertInstantAt(i->getEndFrame());
Chris@45 701 }
Chris@45 702 }
Chris@45 703 }
Chris@45 704
Chris@45 705 void
Chris@45 706 MainWindowBase::insertInstantAt(size_t frame)
Chris@45 707 {
Chris@45 708 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 709 if (!pane) {
Chris@45 710 return;
Chris@45 711 }
Chris@45 712
Chris@74 713 frame = pane->alignFromReference(frame);
Chris@74 714
Chris@45 715 Layer *layer = dynamic_cast<TimeInstantLayer *>
Chris@45 716 (pane->getSelectedLayer());
Chris@45 717
Chris@45 718 if (!layer) {
Chris@45 719 for (int i = pane->getLayerCount(); i > 0; --i) {
Chris@45 720 layer = dynamic_cast<TimeInstantLayer *>(pane->getLayer(i - 1));
Chris@45 721 if (layer) break;
Chris@45 722 }
Chris@45 723
Chris@45 724 if (!layer) {
Chris@45 725 CommandHistory::getInstance()->startCompoundOperation
Chris@45 726 (tr("Add Point"), true);
Chris@45 727 layer = m_document->createEmptyLayer(LayerFactory::TimeInstants);
Chris@45 728 if (layer) {
Chris@45 729 m_document->addLayerToView(pane, layer);
Chris@45 730 m_paneStack->setCurrentLayer(pane, layer);
Chris@45 731 }
Chris@45 732 CommandHistory::getInstance()->endCompoundOperation();
Chris@45 733 }
Chris@45 734 }
Chris@45 735
Chris@45 736 if (layer) {
Chris@45 737
Chris@45 738 Model *model = layer->getModel();
Chris@45 739 SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *>
Chris@45 740 (model);
Chris@45 741
Chris@45 742 if (sodm) {
Chris@45 743 SparseOneDimensionalModel::Point point(frame, "");
Chris@45 744
Chris@45 745 SparseOneDimensionalModel::Point prevPoint(0);
Chris@45 746 bool havePrevPoint = false;
Chris@45 747
Chris@45 748 SparseOneDimensionalModel::EditCommand *command =
Chris@45 749 new SparseOneDimensionalModel::EditCommand(sodm, tr("Add Point"));
Chris@45 750
Chris@74 751 if (m_labeller->requiresPrevPoint()) {
Chris@45 752
Chris@45 753 SparseOneDimensionalModel::PointList prevPoints =
Chris@45 754 sodm->getPreviousPoints(frame);
Chris@45 755
Chris@45 756 if (!prevPoints.empty()) {
Chris@45 757 prevPoint = *prevPoints.begin();
Chris@45 758 havePrevPoint = true;
Chris@45 759 }
Chris@45 760 }
Chris@45 761
Chris@45 762 if (m_labeller) {
Chris@45 763
Chris@45 764 m_labeller->setSampleRate(sodm->getSampleRate());
Chris@45 765
Chris@74 766 if (m_labeller->actingOnPrevPoint()) {
Chris@45 767 command->deletePoint(prevPoint);
Chris@45 768 }
Chris@45 769
Chris@45 770 m_labeller->label<SparseOneDimensionalModel::Point>
Chris@45 771 (point, havePrevPoint ? &prevPoint : 0);
Chris@45 772
Chris@74 773 if (m_labeller->actingOnPrevPoint()) {
Chris@45 774 command->addPoint(prevPoint);
Chris@45 775 }
Chris@45 776 }
Chris@45 777
Chris@45 778 command->addPoint(point);
Chris@45 779
Chris@45 780 command->setName(tr("Add Point at %1 s")
Chris@45 781 .arg(RealTime::frame2RealTime
Chris@45 782 (frame,
Chris@45 783 sodm->getSampleRate())
Chris@45 784 .toText(false).c_str()));
Chris@45 785
Chris@108 786 Command *c = command->finish();
Chris@108 787 if (c) CommandHistory::getInstance()->addCommand(c, false);
Chris@45 788 }
Chris@45 789 }
Chris@45 790 }
Chris@45 791
Chris@45 792 void
Chris@45 793 MainWindowBase::renumberInstants()
Chris@45 794 {
Chris@45 795 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 796 if (!pane) return;
Chris@45 797
Chris@45 798 Layer *layer = dynamic_cast<TimeInstantLayer *>(pane->getSelectedLayer());
Chris@45 799 if (!layer) return;
Chris@45 800
Chris@45 801 MultiSelection ms(m_viewManager->getSelection());
Chris@45 802
Chris@45 803 Model *model = layer->getModel();
Chris@45 804 SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *>
Chris@45 805 (model);
Chris@45 806 if (!sodm) return;
Chris@45 807
Chris@45 808 if (!m_labeller) return;
Chris@45 809
Chris@45 810 Labeller labeller(*m_labeller);
Chris@45 811 labeller.setSampleRate(sodm->getSampleRate());
Chris@45 812
Chris@45 813 // This uses a command
Chris@45 814
Chris@45 815 labeller.labelAll<SparseOneDimensionalModel::Point>(*sodm, &ms);
Chris@45 816 }
Chris@45 817
Chris@45 818 MainWindowBase::FileOpenStatus
Chris@45 819 MainWindowBase::open(QString fileOrUrl, AudioFileOpenMode mode)
Chris@45 820 {
Chris@109 821 ProgressDialog dialog(tr("Opening file or URL..."), true, 2000);
Chris@109 822 return open(FileSource(fileOrUrl, &dialog), mode);
Chris@45 823 }
Chris@45 824
Chris@45 825 MainWindowBase::FileOpenStatus
Chris@45 826 MainWindowBase::open(FileSource source, AudioFileOpenMode mode)
Chris@45 827 {
Chris@45 828 FileOpenStatus status;
Chris@45 829
Chris@45 830 if (!source.isAvailable()) return FileOpenFailed;
Chris@45 831 source.waitForData();
Chris@45 832
Chris@45 833 bool canImportLayer = (getMainModel() != 0 &&
Chris@45 834 m_paneStack != 0 &&
Chris@45 835 m_paneStack->getCurrentPane() != 0);
Chris@45 836
Chris@45 837 if ((status = openAudio(source, mode)) != FileOpenFailed) {
Chris@45 838 return status;
Chris@45 839 } else if ((status = openSession(source)) != FileOpenFailed) {
Chris@45 840 return status;
Chris@45 841 } else if ((status = openPlaylist(source, mode)) != FileOpenFailed) {
Chris@45 842 return status;
Chris@45 843 } else if (!canImportLayer) {
Chris@45 844 return FileOpenWrongMode;
Chris@45 845 } else if ((status = openImage(source)) != FileOpenFailed) {
Chris@45 846 return status;
Chris@45 847 } else if ((status = openLayer(source)) != FileOpenFailed) {
Chris@45 848 return status;
Chris@45 849 } else {
Chris@45 850 return FileOpenFailed;
Chris@45 851 }
Chris@45 852 }
Chris@45 853
Chris@45 854 MainWindowBase::FileOpenStatus
Chris@45 855 MainWindowBase::openAudio(FileSource source, AudioFileOpenMode mode)
Chris@45 856 {
Chris@45 857 std::cerr << "MainWindowBase::openAudio(" << source.getLocation().toStdString() << ")" << std::endl;
Chris@45 858
Chris@45 859 if (!source.isAvailable()) return FileOpenFailed;
Chris@45 860 source.waitForData();
Chris@45 861
Chris@45 862 m_openingAudioFile = true;
Chris@45 863
Chris@45 864 size_t rate = 0;
Chris@45 865
Chris@45 866 if (Preferences::getInstance()->getResampleOnLoad()) {
Chris@45 867 rate = m_playSource->getSourceSampleRate();
Chris@45 868 }
Chris@45 869
Chris@45 870 WaveFileModel *newModel = new WaveFileModel(source, rate);
Chris@45 871
Chris@45 872 if (!newModel->isOK()) {
Chris@45 873 delete newModel;
Chris@45 874 m_openingAudioFile = false;
Chris@45 875 return FileOpenFailed;
Chris@45 876 }
Chris@45 877
Chris@45 878 std::cerr << "mode = " << mode << std::endl;
Chris@45 879
Chris@45 880 if (mode == AskUser) {
Chris@45 881 if (getMainModel()) {
Chris@45 882
Chris@45 883 static bool prevSetAsMain = true;
Chris@45 884 bool setAsMain = true;
Chris@45 885
Chris@45 886 QStringList items;
Chris@45 887 items << tr("Replace the existing main waveform")
Chris@45 888 << tr("Load this file into a new waveform pane");
Chris@45 889
Chris@45 890 bool ok = false;
Chris@45 891 QString item = ListInputDialog::getItem
Chris@45 892 (this, tr("Select target for import"),
Chris@45 893 tr("You already have an audio waveform loaded.\nWhat would you like to do with the new audio file?"),
Chris@45 894 items, prevSetAsMain ? 0 : 1, &ok);
Chris@45 895
Chris@45 896 if (!ok || item.isEmpty()) {
Chris@45 897 delete newModel;
Chris@45 898 m_openingAudioFile = false;
Chris@45 899 return FileOpenCancelled;
Chris@45 900 }
Chris@45 901
Chris@45 902 setAsMain = (item == items[0]);
Chris@45 903 prevSetAsMain = setAsMain;
Chris@45 904
Chris@45 905 if (setAsMain) mode = ReplaceMainModel;
Chris@45 906 else mode = CreateAdditionalModel;
Chris@45 907
Chris@45 908 } else {
Chris@45 909 mode = ReplaceMainModel;
Chris@45 910 }
Chris@45 911 }
Chris@45 912
Chris@45 913 if (mode == ReplaceCurrentPane) {
Chris@45 914
Chris@45 915 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 916 if (pane) {
Chris@45 917 if (getMainModel()) {
Chris@45 918 View::ModelSet models(pane->getModels());
Chris@45 919 if (models.find(getMainModel()) != models.end()) {
Chris@45 920 mode = ReplaceMainModel;
Chris@45 921 }
Chris@45 922 } else {
Chris@45 923 mode = ReplaceMainModel;
Chris@45 924 }
Chris@45 925 } else {
Chris@45 926 mode = CreateAdditionalModel;
Chris@45 927 }
Chris@45 928 }
Chris@45 929
Chris@45 930 if (mode == CreateAdditionalModel && !getMainModel()) {
Chris@45 931 mode = ReplaceMainModel;
Chris@45 932 }
Chris@45 933
Chris@45 934 if (mode == ReplaceMainModel) {
Chris@45 935
Chris@45 936 Model *prevMain = getMainModel();
Chris@45 937 if (prevMain) {
Chris@45 938 m_playSource->removeModel(prevMain);
Chris@108 939 PlayParameterRepository::getInstance()->removePlayable(prevMain);
Chris@45 940 }
Chris@108 941 PlayParameterRepository::getInstance()->addPlayable(newModel);
Chris@45 942
Chris@45 943 m_document->setMainModel(newModel);
Chris@45 944
Chris@45 945 setupMenus();
Chris@45 946
Chris@45 947 if (m_sessionFile == "") {
Chris@45 948 //!!! shouldn't be dealing directly with title from here -- call a method
Chris@57 949 setWindowTitle(tr("%1: %2")
Chris@57 950 .arg(QApplication::applicationName())
Chris@45 951 .arg(source.getLocation()));
Chris@45 952 CommandHistory::getInstance()->clear();
Chris@45 953 CommandHistory::getInstance()->documentSaved();
Chris@45 954 m_documentModified = false;
Chris@45 955 } else {
Chris@57 956 setWindowTitle(tr("%1: %2 [%3]")
Chris@57 957 .arg(QApplication::applicationName())
Chris@45 958 .arg(QFileInfo(m_sessionFile).fileName())
Chris@45 959 .arg(source.getLocation()));
Chris@45 960 if (m_documentModified) {
Chris@45 961 m_documentModified = false;
Chris@45 962 documentModified(); // so as to restore "(modified)" window title
Chris@45 963 }
Chris@45 964 }
Chris@45 965
Chris@45 966 if (!source.isRemote()) m_audioFile = source.getLocalFilename();
Chris@45 967
Chris@45 968 } else if (mode == CreateAdditionalModel) {
Chris@45 969
Chris@45 970 CommandHistory::getInstance()->startCompoundOperation
Chris@45 971 (tr("Import \"%1\"").arg(source.getLocation()), true);
Chris@45 972
Chris@45 973 m_document->addImportedModel(newModel);
Chris@45 974
Chris@45 975 AddPaneCommand *command = new AddPaneCommand(this);
Chris@45 976 CommandHistory::getInstance()->addCommand(command);
Chris@45 977
Chris@45 978 Pane *pane = command->getPane();
Chris@45 979
Chris@47 980 if (m_timeRulerLayer) {
Chris@47 981 m_document->addLayerToView(pane, m_timeRulerLayer);
Chris@47 982 }
Chris@45 983
Chris@45 984 Layer *newLayer = m_document->createImportedLayer(newModel);
Chris@45 985
Chris@45 986 if (newLayer) {
Chris@45 987 m_document->addLayerToView(pane, newLayer);
Chris@45 988 }
Chris@45 989
Chris@45 990 CommandHistory::getInstance()->endCompoundOperation();
Chris@45 991
Chris@45 992 } else if (mode == ReplaceCurrentPane) {
Chris@45 993
Chris@45 994 // We know there is a current pane, otherwise we would have
Chris@45 995 // reset the mode to CreateAdditionalModel above; and we know
Chris@45 996 // the current pane does not contain the main model, otherwise
Chris@45 997 // we would have reset it to ReplaceMainModel. But we don't
Chris@45 998 // know whether the pane contains a waveform model at all.
Chris@45 999
Chris@45 1000 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 1001 Layer *replace = 0;
Chris@45 1002
Chris@45 1003 for (int i = 0; i < pane->getLayerCount(); ++i) {
Chris@45 1004 Layer *layer = pane->getLayer(i);
Chris@45 1005 if (dynamic_cast<WaveformLayer *>(layer)) {
Chris@45 1006 replace = layer;
Chris@45 1007 break;
Chris@45 1008 }
Chris@45 1009 }
Chris@45 1010
Chris@45 1011 CommandHistory::getInstance()->startCompoundOperation
Chris@45 1012 (tr("Import \"%1\"").arg(source.getLocation()), true);
Chris@45 1013
Chris@45 1014 m_document->addImportedModel(newModel);
Chris@45 1015
Chris@45 1016 if (replace) {
Chris@45 1017 m_document->removeLayerFromView(pane, replace);
Chris@45 1018 }
Chris@45 1019
Chris@45 1020 Layer *newLayer = m_document->createImportedLayer(newModel);
Chris@45 1021
Chris@45 1022 if (newLayer) {
Chris@45 1023 m_document->addLayerToView(pane, newLayer);
Chris@45 1024 }
Chris@45 1025
Chris@45 1026 CommandHistory::getInstance()->endCompoundOperation();
Chris@45 1027 }
Chris@45 1028
Chris@45 1029 updateMenuStates();
Chris@45 1030 m_recentFiles.addFile(source.getLocation());
Chris@45 1031 if (!source.isRemote()) {
Chris@45 1032 // for file dialog
Chris@45 1033 registerLastOpenedFilePath(FileFinder::AudioFile,
Chris@45 1034 source.getLocalFilename());
Chris@45 1035 }
Chris@45 1036 m_openingAudioFile = false;
Chris@45 1037
Chris@45 1038 currentPaneChanged(m_paneStack->getCurrentPane());
Chris@45 1039
Chris@45 1040 return FileOpenSucceeded;
Chris@45 1041 }
Chris@45 1042
Chris@45 1043 MainWindowBase::FileOpenStatus
Chris@45 1044 MainWindowBase::openPlaylist(FileSource source, AudioFileOpenMode mode)
Chris@45 1045 {
Chris@45 1046 std::set<QString> extensions;
Chris@45 1047 PlaylistFileReader::getSupportedExtensions(extensions);
Chris@45 1048 QString extension = source.getExtension();
Chris@45 1049 if (extensions.find(extension) == extensions.end()) return FileOpenFailed;
Chris@45 1050
Chris@45 1051 if (!source.isAvailable()) return FileOpenFailed;
Chris@45 1052 source.waitForData();
Chris@45 1053
Chris@45 1054 PlaylistFileReader reader(source.getLocalFilename());
Chris@45 1055 if (!reader.isOK()) return FileOpenFailed;
Chris@45 1056
Chris@45 1057 PlaylistFileReader::Playlist playlist = reader.load();
Chris@45 1058
Chris@45 1059 bool someSuccess = false;
Chris@45 1060
Chris@45 1061 for (PlaylistFileReader::Playlist::const_iterator i = playlist.begin();
Chris@45 1062 i != playlist.end(); ++i) {
Chris@45 1063
Chris@109 1064 ProgressDialog dialog(tr("Opening playlist..."), true, 2000);
Chris@109 1065 FileOpenStatus status = openAudio(FileSource(*i, &dialog), mode);
Chris@45 1066
Chris@45 1067 if (status == FileOpenCancelled) {
Chris@45 1068 return FileOpenCancelled;
Chris@45 1069 }
Chris@45 1070
Chris@45 1071 if (status == FileOpenSucceeded) {
Chris@45 1072 someSuccess = true;
Chris@45 1073 mode = CreateAdditionalModel;
Chris@45 1074 }
Chris@45 1075 }
Chris@45 1076
Chris@45 1077 if (someSuccess) return FileOpenSucceeded;
Chris@45 1078 else return FileOpenFailed;
Chris@45 1079 }
Chris@45 1080
Chris@45 1081 MainWindowBase::FileOpenStatus
Chris@45 1082 MainWindowBase::openLayer(FileSource source)
Chris@45 1083 {
Chris@45 1084 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 1085
Chris@45 1086 if (!pane) {
Chris@45 1087 // shouldn't happen, as the menu action should have been disabled
Chris@45 1088 std::cerr << "WARNING: MainWindowBase::openLayer: no current pane" << std::endl;
Chris@45 1089 return FileOpenWrongMode;
Chris@45 1090 }
Chris@45 1091
Chris@45 1092 if (!getMainModel()) {
Chris@45 1093 // shouldn't happen, as the menu action should have been disabled
Chris@45 1094 std::cerr << "WARNING: MainWindowBase::openLayer: No main model -- hence no default sample rate available" << std::endl;
Chris@45 1095 return FileOpenWrongMode;
Chris@45 1096 }
Chris@45 1097
Chris@45 1098 if (!source.isAvailable()) return FileOpenFailed;
Chris@45 1099 source.waitForData();
Chris@45 1100
Chris@45 1101 QString path = source.getLocalFilename();
Chris@45 1102
Chris@45 1103 if (source.getExtension() == "svl" || source.getExtension() == "xml") {
Chris@45 1104
Chris@45 1105 PaneCallback callback(this);
Chris@45 1106 QFile file(path);
Chris@45 1107
Chris@45 1108 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
Chris@45 1109 std::cerr << "ERROR: MainWindowBase::openLayer("
Chris@45 1110 << source.getLocation().toStdString()
Chris@45 1111 << "): Failed to open file for reading" << std::endl;
Chris@45 1112 return FileOpenFailed;
Chris@45 1113 }
Chris@45 1114
Chris@45 1115 SVFileReader reader(m_document, callback, source.getLocation());
Chris@79 1116 connect
Chris@79 1117 (&reader, SIGNAL(modelRegenerationFailed(QString, QString, QString)),
Chris@79 1118 this, SLOT(modelRegenerationFailed(QString, QString, QString)));
Chris@79 1119 connect
Chris@79 1120 (&reader, SIGNAL(modelRegenerationWarning(QString, QString, QString)),
Chris@79 1121 this, SLOT(modelRegenerationWarning(QString, QString, QString)));
Chris@45 1122 reader.setCurrentPane(pane);
Chris@45 1123
Chris@45 1124 QXmlInputSource inputSource(&file);
Chris@45 1125 reader.parse(inputSource);
Chris@45 1126
Chris@45 1127 if (!reader.isOK()) {
Chris@45 1128 std::cerr << "ERROR: MainWindowBase::openLayer("
Chris@45 1129 << source.getLocation().toStdString()
Chris@45 1130 << "): Failed to read XML file: "
Chris@45 1131 << reader.getErrorString().toStdString() << std::endl;
Chris@45 1132 return FileOpenFailed;
Chris@45 1133 }
Chris@45 1134
Chris@45 1135 m_recentFiles.addFile(source.getLocation());
Chris@45 1136
Chris@45 1137 if (!source.isRemote()) {
Chris@45 1138 registerLastOpenedFilePath(FileFinder::LayerFile, path); // for file dialog
Chris@45 1139 }
Chris@45 1140
Chris@75 1141 return FileOpenSucceeded;
Chris@75 1142
Chris@45 1143 } else {
Chris@45 1144
Chris@45 1145 try {
Chris@45 1146
Chris@109 1147 MIDIFileImportDialog midiDlg(this);
Chris@109 1148
Chris@109 1149 Model *model = DataFileReaderFactory::loadNonCSV
Chris@109 1150 (path, &midiDlg, getMainModel()->getSampleRate());
Chris@45 1151
Chris@109 1152 if (!model) {
Chris@109 1153 CSVFormatDialog *dialog = new CSVFormatDialog
Chris@109 1154 (this, CSVFormat(path), getMainModel()->getSampleRate());
Chris@109 1155 if (dialog->exec() == QDialog::Accepted) {
Chris@109 1156 model = DataFileReaderFactory::loadCSV
Chris@109 1157 (path, dialog->getFormat(),
Chris@109 1158 getMainModel()->getSampleRate());
Chris@109 1159 }
Chris@109 1160 }
Chris@109 1161
Chris@45 1162 if (model) {
Chris@45 1163
Chris@45 1164 std::cerr << "MainWindowBase::openLayer: Have model" << std::endl;
Chris@45 1165
Chris@45 1166 Layer *newLayer = m_document->createImportedLayer(model);
Chris@45 1167
Chris@45 1168 if (newLayer) {
Chris@45 1169
Chris@45 1170 m_document->addLayerToView(pane, newLayer);
Chris@88 1171 m_paneStack->setCurrentLayer(pane, newLayer);
Chris@88 1172
Chris@45 1173 m_recentFiles.addFile(source.getLocation());
Chris@45 1174
Chris@45 1175 if (!source.isRemote()) {
Chris@45 1176 registerLastOpenedFilePath
Chris@45 1177 (FileFinder::LayerFile,
Chris@45 1178 path); // for file dialog
Chris@45 1179 }
Chris@88 1180
Chris@45 1181 return FileOpenSucceeded;
Chris@45 1182 }
Chris@45 1183 }
Chris@45 1184 } catch (DataFileReaderFactory::Exception e) {
Chris@45 1185 if (e == DataFileReaderFactory::ImportCancelled) {
Chris@45 1186 return FileOpenCancelled;
Chris@45 1187 }
Chris@45 1188 }
Chris@45 1189 }
Chris@45 1190
Chris@45 1191 return FileOpenFailed;
Chris@45 1192 }
Chris@45 1193
Chris@45 1194 MainWindowBase::FileOpenStatus
Chris@45 1195 MainWindowBase::openImage(FileSource source)
Chris@45 1196 {
Chris@45 1197 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 1198
Chris@45 1199 if (!pane) {
Chris@45 1200 // shouldn't happen, as the menu action should have been disabled
Chris@45 1201 std::cerr << "WARNING: MainWindowBase::openImage: no current pane" << std::endl;
Chris@45 1202 return FileOpenWrongMode;
Chris@45 1203 }
Chris@45 1204
Chris@45 1205 if (!m_document->getMainModel()) {
Chris@45 1206 return FileOpenWrongMode;
Chris@45 1207 }
Chris@45 1208
Chris@45 1209 bool newLayer = false;
Chris@45 1210
Chris@45 1211 ImageLayer *il = dynamic_cast<ImageLayer *>(pane->getSelectedLayer());
Chris@45 1212 if (!il) {
Chris@45 1213 for (int i = pane->getLayerCount()-1; i >= 0; --i) {
Chris@45 1214 il = dynamic_cast<ImageLayer *>(pane->getLayer(i));
Chris@45 1215 if (il) break;
Chris@45 1216 }
Chris@45 1217 }
Chris@45 1218 if (!il) {
Chris@45 1219 il = dynamic_cast<ImageLayer *>
Chris@45 1220 (m_document->createEmptyLayer(LayerFactory::Image));
Chris@45 1221 if (!il) return FileOpenFailed;
Chris@45 1222 newLayer = true;
Chris@45 1223 }
Chris@45 1224
Chris@45 1225 // We don't put the image file in Recent Files
Chris@45 1226
Chris@45 1227 std::cerr << "openImage: trying location \"" << source.getLocation().toStdString() << "\" in image layer" << std::endl;
Chris@45 1228
Chris@45 1229 if (!il->addImage(m_viewManager->getGlobalCentreFrame(), source.getLocation())) {
Chris@45 1230 if (newLayer) {
Chris@52 1231 m_document->deleteLayer(il); // also releases its model
Chris@45 1232 }
Chris@45 1233 return FileOpenFailed;
Chris@45 1234 } else {
Chris@45 1235 if (newLayer) {
Chris@45 1236 m_document->addLayerToView(pane, il);
Chris@45 1237 }
Chris@45 1238 m_paneStack->setCurrentLayer(pane, il);
Chris@45 1239 }
Chris@45 1240
Chris@45 1241 return FileOpenSucceeded;
Chris@45 1242 }
Chris@45 1243
Chris@45 1244 MainWindowBase::FileOpenStatus
Chris@45 1245 MainWindowBase::openSessionFile(QString fileOrUrl)
Chris@45 1246 {
Chris@109 1247 ProgressDialog dialog(tr("Opening session..."), true, 2000);
Chris@109 1248 return openSession(FileSource(fileOrUrl, &dialog));
Chris@45 1249 }
Chris@45 1250
Chris@45 1251 MainWindowBase::FileOpenStatus
Chris@45 1252 MainWindowBase::openSession(FileSource source)
Chris@45 1253 {
Chris@45 1254 if (!source.isAvailable()) return FileOpenFailed;
Chris@45 1255 if (source.getExtension() != "sv") return FileOpenFailed;
Chris@45 1256 source.waitForData();
Chris@45 1257
Chris@45 1258 BZipFileDevice bzFile(source.getLocalFilename());
Chris@45 1259 if (!bzFile.open(QIODevice::ReadOnly)) return FileOpenFailed;
Chris@45 1260
Chris@45 1261 if (!checkSaveModified()) return FileOpenCancelled;
Chris@45 1262
Chris@45 1263 QString error;
Chris@45 1264 closeSession();
Chris@45 1265 createDocument();
Chris@45 1266
Chris@45 1267 PaneCallback callback(this);
Chris@45 1268 m_viewManager->clearSelections();
Chris@45 1269
Chris@45 1270 SVFileReader reader(m_document, callback, source.getLocation());
Chris@79 1271 connect
Chris@79 1272 (&reader, SIGNAL(modelRegenerationFailed(QString, QString, QString)),
Chris@79 1273 this, SLOT(modelRegenerationFailed(QString, QString, QString)));
Chris@79 1274 connect
Chris@79 1275 (&reader, SIGNAL(modelRegenerationWarning(QString, QString, QString)),
Chris@79 1276 this, SLOT(modelRegenerationWarning(QString, QString, QString)));
Chris@45 1277 QXmlInputSource inputSource(&bzFile);
Chris@45 1278 reader.parse(inputSource);
Chris@45 1279
Chris@45 1280 if (!reader.isOK()) {
Chris@45 1281 error = tr("SV XML file read error:\n%1").arg(reader.getErrorString());
Chris@45 1282 }
Chris@45 1283
Chris@45 1284 bzFile.close();
Chris@45 1285
Chris@45 1286 bool ok = (error == "");
Chris@45 1287
Chris@45 1288 if (ok) {
Chris@45 1289
Chris@57 1290 setWindowTitle(tr("%1: %2")
Chris@57 1291 .arg(QApplication::applicationName())
Chris@45 1292 .arg(source.getLocation()));
Chris@45 1293
Chris@45 1294 if (!source.isRemote()) m_sessionFile = source.getLocalFilename();
Chris@45 1295
Chris@45 1296 setupMenus();
Chris@45 1297
Chris@45 1298 CommandHistory::getInstance()->clear();
Chris@45 1299 CommandHistory::getInstance()->documentSaved();
Chris@45 1300 m_documentModified = false;
Chris@45 1301 updateMenuStates();
Chris@45 1302
Chris@45 1303 m_recentFiles.addFile(source.getLocation());
Chris@45 1304
Chris@45 1305 if (!source.isRemote()) {
Chris@45 1306 // for file dialog
Chris@45 1307 registerLastOpenedFilePath(FileFinder::SessionFile,
Chris@45 1308 source.getLocalFilename());
Chris@45 1309 }
Chris@45 1310
Chris@45 1311 } else {
Chris@57 1312 setWindowTitle(QApplication::applicationName());
Chris@45 1313 }
Chris@45 1314
Chris@45 1315 return ok ? FileOpenSucceeded : FileOpenFailed;
Chris@45 1316 }
Chris@45 1317
Chris@45 1318 void
Chris@45 1319 MainWindowBase::createPlayTarget()
Chris@45 1320 {
Chris@45 1321 if (m_playTarget) return;
Chris@45 1322
Chris@45 1323 m_playTarget = AudioTargetFactory::createCallbackTarget(m_playSource);
Chris@45 1324 if (!m_playTarget) {
Chris@104 1325 emit hideSplash();
Chris@45 1326 QMessageBox::warning
Chris@45 1327 (this, tr("Couldn't open audio device"),
Chris@45 1328 tr("<b>No audio available</b><p>Could not open an audio device for playback.<p>Audio playback will not be available during this session."),
Chris@45 1329 QMessageBox::Ok);
Chris@45 1330 }
Chris@45 1331 }
Chris@45 1332
Chris@45 1333 WaveFileModel *
Chris@45 1334 MainWindowBase::getMainModel()
Chris@45 1335 {
Chris@45 1336 if (!m_document) return 0;
Chris@45 1337 return m_document->getMainModel();
Chris@45 1338 }
Chris@45 1339
Chris@45 1340 const WaveFileModel *
Chris@45 1341 MainWindowBase::getMainModel() const
Chris@45 1342 {
Chris@45 1343 if (!m_document) return 0;
Chris@45 1344 return m_document->getMainModel();
Chris@45 1345 }
Chris@45 1346
Chris@45 1347 void
Chris@45 1348 MainWindowBase::createDocument()
Chris@45 1349 {
Chris@45 1350 m_document = new Document;
Chris@45 1351
Chris@45 1352 connect(m_document, SIGNAL(layerAdded(Layer *)),
Chris@45 1353 this, SLOT(layerAdded(Layer *)));
Chris@45 1354 connect(m_document, SIGNAL(layerRemoved(Layer *)),
Chris@45 1355 this, SLOT(layerRemoved(Layer *)));
Chris@45 1356 connect(m_document, SIGNAL(layerAboutToBeDeleted(Layer *)),
Chris@45 1357 this, SLOT(layerAboutToBeDeleted(Layer *)));
Chris@45 1358 connect(m_document, SIGNAL(layerInAView(Layer *, bool)),
Chris@45 1359 this, SLOT(layerInAView(Layer *, bool)));
Chris@45 1360
Chris@45 1361 connect(m_document, SIGNAL(modelAdded(Model *)),
Chris@45 1362 this, SLOT(modelAdded(Model *)));
Chris@45 1363 connect(m_document, SIGNAL(mainModelChanged(WaveFileModel *)),
Chris@45 1364 this, SLOT(mainModelChanged(WaveFileModel *)));
Chris@45 1365 connect(m_document, SIGNAL(modelAboutToBeDeleted(Model *)),
Chris@45 1366 this, SLOT(modelAboutToBeDeleted(Model *)));
Chris@45 1367
Chris@78 1368 connect(m_document, SIGNAL(modelGenerationFailed(QString, QString)),
Chris@78 1369 this, SLOT(modelGenerationFailed(QString, QString)));
Chris@78 1370 connect(m_document, SIGNAL(modelRegenerationWarning(QString, QString, QString)),
Chris@78 1371 this, SLOT(modelRegenerationWarning(QString, QString, QString)));
Chris@78 1372 connect(m_document, SIGNAL(modelGenerationFailed(QString, QString)),
Chris@78 1373 this, SLOT(modelGenerationFailed(QString, QString)));
Chris@78 1374 connect(m_document, SIGNAL(modelRegenerationWarning(QString, QString, QString)),
Chris@78 1375 this, SLOT(modelRegenerationWarning(QString, QString, QString)));
Chris@78 1376 connect(m_document, SIGNAL(alignmentFailed(QString, QString)),
Chris@78 1377 this, SLOT(alignmentFailed(QString, QString)));
Chris@45 1378 }
Chris@45 1379
Chris@45 1380 bool
Chris@45 1381 MainWindowBase::saveSessionFile(QString path)
Chris@45 1382 {
Chris@45 1383 BZipFileDevice bzFile(path);
Chris@45 1384 if (!bzFile.open(QIODevice::WriteOnly)) {
Chris@45 1385 std::cerr << "Failed to open session file \"" << path.toStdString()
Chris@45 1386 << "\" for writing: "
Chris@45 1387 << bzFile.errorString().toStdString() << std::endl;
Chris@45 1388 return false;
Chris@45 1389 }
Chris@45 1390
Chris@45 1391 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
Chris@45 1392
Chris@45 1393 QTextStream out(&bzFile);
Chris@45 1394 toXml(out);
Chris@45 1395 out.flush();
Chris@45 1396
Chris@45 1397 QApplication::restoreOverrideCursor();
Chris@45 1398
Chris@45 1399 if (!bzFile.isOK()) {
Chris@45 1400 QMessageBox::critical(this, tr("Failed to write file"),
Chris@45 1401 tr("<b>Save failed</b><p>Failed to write to file \"%1\": %2")
Chris@45 1402 .arg(path).arg(bzFile.errorString()));
Chris@45 1403 bzFile.close();
Chris@45 1404 return false;
Chris@45 1405 }
Chris@45 1406
Chris@45 1407 bzFile.close();
Chris@45 1408 return true;
Chris@45 1409 }
Chris@45 1410
Chris@45 1411 void
Chris@45 1412 MainWindowBase::toXml(QTextStream &out)
Chris@45 1413 {
Chris@45 1414 QString indent(" ");
Chris@45 1415
Chris@45 1416 out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
Chris@45 1417 out << "<!DOCTYPE sonic-visualiser>\n";
Chris@45 1418 out << "<sv>\n";
Chris@45 1419
Chris@45 1420 m_document->toXml(out, "", "");
Chris@45 1421
Chris@45 1422 out << "<display>\n";
Chris@45 1423
Chris@45 1424 out << QString(" <window width=\"%1\" height=\"%2\"/>\n")
Chris@45 1425 .arg(width()).arg(height());
Chris@45 1426
Chris@45 1427 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@45 1428
Chris@45 1429 Pane *pane = m_paneStack->getPane(i);
Chris@45 1430
Chris@45 1431 if (pane) {
Chris@45 1432 pane->toXml(out, indent);
Chris@45 1433 }
Chris@45 1434 }
Chris@45 1435
Chris@45 1436 out << "</display>\n";
Chris@45 1437
Chris@45 1438 m_viewManager->getSelection().toXml(out);
Chris@45 1439
Chris@45 1440 out << "</sv>\n";
Chris@45 1441 }
Chris@45 1442
Chris@45 1443 Pane *
Chris@45 1444 MainWindowBase::addPaneToStack()
Chris@45 1445 {
Chris@45 1446 AddPaneCommand *command = new AddPaneCommand(this);
Chris@45 1447 CommandHistory::getInstance()->addCommand(command);
Chris@57 1448 Pane *pane = command->getPane();
Chris@57 1449 return pane;
Chris@45 1450 }
Chris@45 1451
Chris@45 1452 void
Chris@45 1453 MainWindowBase::zoomIn()
Chris@45 1454 {
Chris@45 1455 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 1456 if (currentPane) currentPane->zoom(true);
Chris@45 1457 }
Chris@45 1458
Chris@45 1459 void
Chris@45 1460 MainWindowBase::zoomOut()
Chris@45 1461 {
Chris@45 1462 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 1463 if (currentPane) currentPane->zoom(false);
Chris@45 1464 }
Chris@45 1465
Chris@45 1466 void
Chris@45 1467 MainWindowBase::zoomToFit()
Chris@45 1468 {
Chris@45 1469 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 1470 if (!currentPane) return;
Chris@45 1471
Chris@45 1472 Model *model = getMainModel();
Chris@45 1473 if (!model) return;
Chris@45 1474
Chris@45 1475 size_t start = model->getStartFrame();
Chris@45 1476 size_t end = model->getEndFrame();
Chris@60 1477 if (m_playSource) end = std::max(end, m_playSource->getPlayEndFrame());
Chris@45 1478 size_t pixels = currentPane->width();
Chris@45 1479
Chris@45 1480 size_t sw = currentPane->getVerticalScaleWidth();
Chris@45 1481 if (pixels > sw * 2) pixels -= sw * 2;
Chris@45 1482 else pixels = 1;
Chris@45 1483 if (pixels > 4) pixels -= 4;
Chris@45 1484
Chris@45 1485 size_t zoomLevel = (end - start) / pixels;
Chris@45 1486
Chris@45 1487 currentPane->setZoomLevel(zoomLevel);
Chris@45 1488 currentPane->setCentreFrame((start + end) / 2);
Chris@45 1489 }
Chris@45 1490
Chris@45 1491 void
Chris@45 1492 MainWindowBase::zoomDefault()
Chris@45 1493 {
Chris@45 1494 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 1495 if (currentPane) currentPane->setZoomLevel(1024);
Chris@45 1496 }
Chris@45 1497
Chris@45 1498 void
Chris@45 1499 MainWindowBase::scrollLeft()
Chris@45 1500 {
Chris@45 1501 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 1502 if (currentPane) currentPane->scroll(false, false);
Chris@45 1503 }
Chris@45 1504
Chris@45 1505 void
Chris@45 1506 MainWindowBase::jumpLeft()
Chris@45 1507 {
Chris@45 1508 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 1509 if (currentPane) currentPane->scroll(false, true);
Chris@45 1510 }
Chris@45 1511
Chris@45 1512 void
Chris@45 1513 MainWindowBase::scrollRight()
Chris@45 1514 {
Chris@45 1515 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 1516 if (currentPane) currentPane->scroll(true, false);
Chris@45 1517 }
Chris@45 1518
Chris@45 1519 void
Chris@45 1520 MainWindowBase::jumpRight()
Chris@45 1521 {
Chris@45 1522 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 1523 if (currentPane) currentPane->scroll(true, true);
Chris@45 1524 }
Chris@45 1525
Chris@45 1526 void
Chris@45 1527 MainWindowBase::showNoOverlays()
Chris@45 1528 {
Chris@45 1529 m_viewManager->setOverlayMode(ViewManager::NoOverlays);
Chris@45 1530 }
Chris@45 1531
Chris@45 1532 void
Chris@45 1533 MainWindowBase::showMinimalOverlays()
Chris@45 1534 {
Chris@45 1535 m_viewManager->setOverlayMode(ViewManager::MinimalOverlays);
Chris@45 1536 }
Chris@45 1537
Chris@45 1538 void
Chris@45 1539 MainWindowBase::showStandardOverlays()
Chris@45 1540 {
Chris@45 1541 m_viewManager->setOverlayMode(ViewManager::StandardOverlays);
Chris@45 1542 }
Chris@45 1543
Chris@45 1544 void
Chris@45 1545 MainWindowBase::showAllOverlays()
Chris@45 1546 {
Chris@45 1547 m_viewManager->setOverlayMode(ViewManager::AllOverlays);
Chris@45 1548 }
Chris@45 1549
Chris@45 1550 void
Chris@45 1551 MainWindowBase::toggleZoomWheels()
Chris@45 1552 {
Chris@45 1553 if (m_viewManager->getZoomWheelsEnabled()) {
Chris@45 1554 m_viewManager->setZoomWheelsEnabled(false);
Chris@45 1555 } else {
Chris@45 1556 m_viewManager->setZoomWheelsEnabled(true);
Chris@45 1557 }
Chris@45 1558 }
Chris@45 1559
Chris@45 1560 void
Chris@45 1561 MainWindowBase::togglePropertyBoxes()
Chris@45 1562 {
Chris@45 1563 if (m_paneStack->getLayoutStyle() == PaneStack::NoPropertyStacks) {
Chris@45 1564 if (Preferences::getInstance()->getPropertyBoxLayout() ==
Chris@45 1565 Preferences::VerticallyStacked) {
Chris@45 1566 m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout);
Chris@45 1567 } else {
Chris@45 1568 m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout);
Chris@45 1569 }
Chris@45 1570 } else {
Chris@45 1571 m_paneStack->setLayoutStyle(PaneStack::NoPropertyStacks);
Chris@45 1572 }
Chris@45 1573 }
Chris@45 1574
Chris@45 1575 void
Chris@45 1576 MainWindowBase::toggleStatusBar()
Chris@45 1577 {
Chris@45 1578 QSettings settings;
Chris@45 1579 settings.beginGroup("MainWindow");
Chris@45 1580 bool sb = settings.value("showstatusbar", true).toBool();
Chris@45 1581
Chris@45 1582 if (sb) {
Chris@45 1583 statusBar()->hide();
Chris@45 1584 } else {
Chris@45 1585 statusBar()->show();
Chris@45 1586 }
Chris@45 1587
Chris@45 1588 settings.setValue("showstatusbar", !sb);
Chris@45 1589
Chris@45 1590 settings.endGroup();
Chris@45 1591 }
Chris@45 1592
Chris@45 1593 void
Chris@45 1594 MainWindowBase::preferenceChanged(PropertyContainer::PropertyName name)
Chris@45 1595 {
Chris@45 1596 if (name == "Property Box Layout") {
Chris@45 1597 if (m_paneStack->getLayoutStyle() != PaneStack::NoPropertyStacks) {
Chris@45 1598 if (Preferences::getInstance()->getPropertyBoxLayout() ==
Chris@45 1599 Preferences::VerticallyStacked) {
Chris@45 1600 m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout);
Chris@45 1601 } else {
Chris@45 1602 m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout);
Chris@45 1603 }
Chris@45 1604 }
Chris@45 1605 } else if (name == "Background Mode" && m_viewManager) {
Chris@45 1606 Preferences::BackgroundMode mode =
Chris@45 1607 Preferences::getInstance()->getBackgroundMode();
Chris@45 1608 if (mode == Preferences::BackgroundFromTheme) {
Chris@45 1609 m_viewManager->setGlobalDarkBackground(m_initialDarkBackground);
Chris@45 1610 } else if (mode == Preferences::DarkBackground) {
Chris@45 1611 m_viewManager->setGlobalDarkBackground(true);
Chris@45 1612 } else {
Chris@45 1613 m_viewManager->setGlobalDarkBackground(false);
Chris@45 1614 }
Chris@45 1615 }
Chris@45 1616 }
Chris@45 1617
Chris@45 1618 void
Chris@45 1619 MainWindowBase::play()
Chris@45 1620 {
Chris@45 1621 if (m_playSource->isPlaying()) {
Chris@45 1622 stop();
Chris@45 1623 } else {
Chris@45 1624 playbackFrameChanged(m_viewManager->getPlaybackFrame());
Chris@45 1625 m_playSource->play(m_viewManager->getPlaybackFrame());
Chris@45 1626 }
Chris@45 1627 }
Chris@45 1628
Chris@45 1629 void
Chris@45 1630 MainWindowBase::ffwd()
Chris@45 1631 {
Chris@45 1632 if (!getMainModel()) return;
Chris@45 1633
Chris@45 1634 int frame = m_viewManager->getPlaybackFrame();
Chris@45 1635 ++frame;
Chris@45 1636
Chris@85 1637 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 1638 Layer *layer = getSnapLayer();
Chris@45 1639 size_t sr = getMainModel()->getSampleRate();
Chris@45 1640
Chris@45 1641 if (!layer) {
Chris@45 1642
Chris@45 1643 frame = RealTime::realTime2Frame
Chris@45 1644 (RealTime::frame2RealTime(frame, sr) + RealTime(2, 0), sr);
Chris@45 1645 if (frame > int(getMainModel()->getEndFrame())) {
Chris@45 1646 frame = getMainModel()->getEndFrame();
Chris@45 1647 }
Chris@45 1648
Chris@45 1649 } else {
Chris@45 1650
Chris@45 1651 size_t resolution = 0;
Chris@85 1652 if (layer->snapToFeatureFrame(m_paneStack->getCurrentPane(),
Chris@85 1653 frame, resolution, Layer::SnapRight)) {
Chris@85 1654 if (pane) frame = pane->alignToReference(frame);
Chris@85 1655 } else {
Chris@45 1656 frame = getMainModel()->getEndFrame();
Chris@45 1657 }
Chris@45 1658 }
Chris@45 1659
Chris@45 1660 if (frame < 0) frame = 0;
Chris@45 1661
Chris@45 1662 if (m_viewManager->getPlaySelectionMode()) {
Chris@45 1663 frame = m_viewManager->constrainFrameToSelection(size_t(frame));
Chris@45 1664 }
Chris@45 1665
Chris@45 1666 m_viewManager->setPlaybackFrame(frame);
Chris@45 1667 }
Chris@45 1668
Chris@45 1669 void
Chris@45 1670 MainWindowBase::ffwdEnd()
Chris@45 1671 {
Chris@45 1672 if (!getMainModel()) return;
Chris@45 1673
Chris@45 1674 size_t frame = getMainModel()->getEndFrame();
Chris@45 1675
Chris@45 1676 if (m_viewManager->getPlaySelectionMode()) {
Chris@45 1677 frame = m_viewManager->constrainFrameToSelection(frame);
Chris@45 1678 }
Chris@45 1679
Chris@45 1680 m_viewManager->setPlaybackFrame(frame);
Chris@45 1681 }
Chris@45 1682
Chris@45 1683 void
Chris@45 1684 MainWindowBase::rewind()
Chris@45 1685 {
Chris@45 1686 if (!getMainModel()) return;
Chris@45 1687
Chris@45 1688 int frame = m_viewManager->getPlaybackFrame();
Chris@45 1689 if (frame > 0) --frame;
Chris@45 1690
Chris@85 1691 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 1692 Layer *layer = getSnapLayer();
Chris@45 1693 size_t sr = getMainModel()->getSampleRate();
Chris@45 1694
Chris@45 1695 // when rewinding during playback, we want to allow a period
Chris@45 1696 // following a rewind target point at which the rewind will go to
Chris@45 1697 // the prior point instead of the immediately neighbouring one
Chris@45 1698 if (m_playSource && m_playSource->isPlaying()) {
Chris@45 1699 RealTime ct = RealTime::frame2RealTime(frame, sr);
Chris@45 1700 ct = ct - RealTime::fromSeconds(0.25);
Chris@45 1701 if (ct < RealTime::zeroTime) ct = RealTime::zeroTime;
Chris@45 1702 // std::cerr << "rewind: frame " << frame << " -> ";
Chris@45 1703 frame = RealTime::realTime2Frame(ct, sr);
Chris@45 1704 // std::cerr << frame << std::endl;
Chris@45 1705 }
Chris@45 1706
Chris@45 1707 if (!layer) {
Chris@45 1708
Chris@45 1709 frame = RealTime::realTime2Frame
Chris@45 1710 (RealTime::frame2RealTime(frame, sr) - RealTime(2, 0), sr);
Chris@45 1711 if (frame < int(getMainModel()->getStartFrame())) {
Chris@45 1712 frame = getMainModel()->getStartFrame();
Chris@45 1713 }
Chris@45 1714
Chris@45 1715 } else {
Chris@45 1716
Chris@45 1717 size_t resolution = 0;
Chris@85 1718 if (layer->snapToFeatureFrame(m_paneStack->getCurrentPane(),
Chris@85 1719 frame, resolution, Layer::SnapLeft)) {
Chris@85 1720
Chris@85 1721 if (pane) frame = pane->alignToReference(frame);
Chris@85 1722 } else {
Chris@45 1723 frame = getMainModel()->getStartFrame();
Chris@45 1724 }
Chris@45 1725 }
Chris@45 1726
Chris@45 1727 if (frame < 0) frame = 0;
Chris@45 1728
Chris@45 1729 if (m_viewManager->getPlaySelectionMode()) {
Chris@45 1730 frame = m_viewManager->constrainFrameToSelection(size_t(frame));
Chris@45 1731 }
Chris@45 1732
Chris@45 1733 m_viewManager->setPlaybackFrame(frame);
Chris@45 1734 }
Chris@45 1735
Chris@45 1736 void
Chris@45 1737 MainWindowBase::rewindStart()
Chris@45 1738 {
Chris@45 1739 if (!getMainModel()) return;
Chris@45 1740
Chris@45 1741 size_t frame = getMainModel()->getStartFrame();
Chris@45 1742
Chris@45 1743 if (m_viewManager->getPlaySelectionMode()) {
Chris@45 1744 frame = m_viewManager->constrainFrameToSelection(frame);
Chris@45 1745 }
Chris@45 1746
Chris@45 1747 m_viewManager->setPlaybackFrame(frame);
Chris@45 1748 }
Chris@45 1749
Chris@45 1750 Layer *
Chris@45 1751 MainWindowBase::getSnapLayer() const
Chris@45 1752 {
Chris@45 1753 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 1754 if (!pane) return 0;
Chris@45 1755
Chris@45 1756 Layer *layer = pane->getSelectedLayer();
Chris@45 1757
Chris@45 1758 if (!dynamic_cast<TimeInstantLayer *>(layer) &&
Chris@45 1759 !dynamic_cast<TimeValueLayer *>(layer) &&
Chris@45 1760 !dynamic_cast<TimeRulerLayer *>(layer)) {
Chris@45 1761
Chris@45 1762 layer = 0;
Chris@45 1763
Chris@45 1764 for (int i = pane->getLayerCount(); i > 0; --i) {
Chris@45 1765 Layer *l = pane->getLayer(i-1);
Chris@45 1766 if (dynamic_cast<TimeRulerLayer *>(l)) {
Chris@45 1767 layer = l;
Chris@45 1768 break;
Chris@45 1769 }
Chris@45 1770 }
Chris@45 1771 }
Chris@45 1772
Chris@45 1773 return layer;
Chris@45 1774 }
Chris@45 1775
Chris@45 1776 void
Chris@45 1777 MainWindowBase::stop()
Chris@45 1778 {
Chris@45 1779 m_playSource->stop();
Chris@45 1780
Chris@45 1781 if (m_paneStack && m_paneStack->getCurrentPane()) {
Chris@45 1782 updateVisibleRangeDisplay(m_paneStack->getCurrentPane());
Chris@45 1783 } else {
Chris@45 1784 m_myStatusMessage = "";
Chris@45 1785 statusBar()->showMessage("");
Chris@45 1786 }
Chris@45 1787 }
Chris@45 1788
Chris@45 1789 MainWindowBase::AddPaneCommand::AddPaneCommand(MainWindowBase *mw) :
Chris@45 1790 m_mw(mw),
Chris@45 1791 m_pane(0),
Chris@45 1792 m_prevCurrentPane(0),
Chris@45 1793 m_added(false)
Chris@45 1794 {
Chris@45 1795 }
Chris@45 1796
Chris@45 1797 MainWindowBase::AddPaneCommand::~AddPaneCommand()
Chris@45 1798 {
Chris@45 1799 if (m_pane && !m_added) {
Chris@45 1800 m_mw->m_paneStack->deletePane(m_pane);
Chris@45 1801 }
Chris@45 1802 }
Chris@45 1803
Chris@45 1804 QString
Chris@45 1805 MainWindowBase::AddPaneCommand::getName() const
Chris@45 1806 {
Chris@45 1807 return tr("Add Pane");
Chris@45 1808 }
Chris@45 1809
Chris@45 1810 void
Chris@45 1811 MainWindowBase::AddPaneCommand::execute()
Chris@45 1812 {
Chris@45 1813 if (!m_pane) {
Chris@45 1814 m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane();
Chris@45 1815 m_pane = m_mw->m_paneStack->addPane();
Chris@45 1816
Chris@45 1817 connect(m_pane, SIGNAL(contextHelpChanged(const QString &)),
Chris@45 1818 m_mw, SLOT(contextHelpChanged(const QString &)));
Chris@45 1819 } else {
Chris@45 1820 m_mw->m_paneStack->showPane(m_pane);
Chris@45 1821 }
Chris@45 1822
Chris@45 1823 m_mw->m_paneStack->setCurrentPane(m_pane);
Chris@45 1824 m_added = true;
Chris@45 1825 }
Chris@45 1826
Chris@45 1827 void
Chris@45 1828 MainWindowBase::AddPaneCommand::unexecute()
Chris@45 1829 {
Chris@45 1830 m_mw->m_paneStack->hidePane(m_pane);
Chris@45 1831 m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane);
Chris@45 1832 m_added = false;
Chris@45 1833 }
Chris@45 1834
Chris@45 1835 MainWindowBase::RemovePaneCommand::RemovePaneCommand(MainWindowBase *mw, Pane *pane) :
Chris@45 1836 m_mw(mw),
Chris@45 1837 m_pane(pane),
Chris@45 1838 m_added(true)
Chris@45 1839 {
Chris@45 1840 }
Chris@45 1841
Chris@45 1842 MainWindowBase::RemovePaneCommand::~RemovePaneCommand()
Chris@45 1843 {
Chris@45 1844 if (m_pane && !m_added) {
Chris@45 1845 m_mw->m_paneStack->deletePane(m_pane);
Chris@45 1846 }
Chris@45 1847 }
Chris@45 1848
Chris@45 1849 QString
Chris@45 1850 MainWindowBase::RemovePaneCommand::getName() const
Chris@45 1851 {
Chris@45 1852 return tr("Remove Pane");
Chris@45 1853 }
Chris@45 1854
Chris@45 1855 void
Chris@45 1856 MainWindowBase::RemovePaneCommand::execute()
Chris@45 1857 {
Chris@45 1858 m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane();
Chris@45 1859 m_mw->m_paneStack->hidePane(m_pane);
Chris@45 1860 m_added = false;
Chris@45 1861 }
Chris@45 1862
Chris@45 1863 void
Chris@45 1864 MainWindowBase::RemovePaneCommand::unexecute()
Chris@45 1865 {
Chris@45 1866 m_mw->m_paneStack->showPane(m_pane);
Chris@45 1867 m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane);
Chris@45 1868 m_added = true;
Chris@45 1869 }
Chris@45 1870
Chris@45 1871 void
Chris@45 1872 MainWindowBase::deleteCurrentPane()
Chris@45 1873 {
Chris@45 1874 CommandHistory::getInstance()->startCompoundOperation
Chris@45 1875 (tr("Delete Pane"), true);
Chris@45 1876
Chris@45 1877 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 1878 if (pane) {
Chris@45 1879 while (pane->getLayerCount() > 0) {
Chris@45 1880 Layer *layer = pane->getLayer(0);
Chris@45 1881 if (layer) {
Chris@45 1882 m_document->removeLayerFromView(pane, layer);
Chris@45 1883 } else {
Chris@45 1884 break;
Chris@45 1885 }
Chris@45 1886 }
Chris@45 1887
Chris@45 1888 RemovePaneCommand *command = new RemovePaneCommand(this, pane);
Chris@45 1889 CommandHistory::getInstance()->addCommand(command);
Chris@45 1890 }
Chris@45 1891
Chris@45 1892 CommandHistory::getInstance()->endCompoundOperation();
Chris@45 1893
Chris@45 1894 updateMenuStates();
Chris@45 1895 }
Chris@45 1896
Chris@45 1897 void
Chris@45 1898 MainWindowBase::deleteCurrentLayer()
Chris@45 1899 {
Chris@45 1900 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 1901 if (pane) {
Chris@45 1902 Layer *layer = pane->getSelectedLayer();
Chris@45 1903 if (layer) {
Chris@45 1904 m_document->removeLayerFromView(pane, layer);
Chris@45 1905 }
Chris@45 1906 }
Chris@45 1907 updateMenuStates();
Chris@45 1908 }
Chris@45 1909
Chris@45 1910 void
Chris@73 1911 MainWindowBase::previousPane()
Chris@73 1912 {
Chris@73 1913 if (!m_paneStack) return;
Chris@73 1914
Chris@73 1915 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@73 1916 if (!currentPane) return;
Chris@73 1917
Chris@73 1918 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@73 1919 if (m_paneStack->getPane(i) == currentPane) {
Chris@73 1920 if (i == 0) return;
Chris@73 1921 m_paneStack->setCurrentPane(m_paneStack->getPane(i-1));
Chris@73 1922 updateMenuStates();
Chris@73 1923 return;
Chris@73 1924 }
Chris@73 1925 }
Chris@73 1926 }
Chris@73 1927
Chris@73 1928 void
Chris@73 1929 MainWindowBase::nextPane()
Chris@73 1930 {
Chris@73 1931 if (!m_paneStack) return;
Chris@73 1932
Chris@73 1933 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@73 1934 if (!currentPane) return;
Chris@73 1935
Chris@73 1936 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@73 1937 if (m_paneStack->getPane(i) == currentPane) {
Chris@73 1938 if (i == m_paneStack->getPaneCount()-1) return;
Chris@73 1939 m_paneStack->setCurrentPane(m_paneStack->getPane(i+1));
Chris@73 1940 updateMenuStates();
Chris@73 1941 return;
Chris@73 1942 }
Chris@73 1943 }
Chris@73 1944 }
Chris@73 1945
Chris@73 1946 void
Chris@73 1947 MainWindowBase::previousLayer()
Chris@73 1948 {
Chris@73 1949 //!!! Not right -- pane lists layers in stacking order
Chris@73 1950
Chris@73 1951 if (!m_paneStack) return;
Chris@73 1952
Chris@73 1953 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@73 1954 if (!currentPane) return;
Chris@73 1955
Chris@73 1956 Layer *currentLayer = currentPane->getSelectedLayer();
Chris@73 1957 if (!currentLayer) return;
Chris@73 1958
Chris@73 1959 for (int i = 0; i < currentPane->getLayerCount(); ++i) {
Chris@73 1960 if (currentPane->getLayer(i) == currentLayer) {
Chris@73 1961 if (i == 0) return;
Chris@73 1962 m_paneStack->setCurrentLayer(currentPane,
Chris@73 1963 currentPane->getLayer(i-1));
Chris@73 1964 updateMenuStates();
Chris@73 1965 return;
Chris@73 1966 }
Chris@73 1967 }
Chris@73 1968 }
Chris@73 1969
Chris@73 1970 void
Chris@73 1971 MainWindowBase::nextLayer()
Chris@73 1972 {
Chris@73 1973 //!!! Not right -- pane lists layers in stacking order
Chris@73 1974
Chris@73 1975 if (!m_paneStack) return;
Chris@73 1976
Chris@73 1977 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@73 1978 if (!currentPane) return;
Chris@73 1979
Chris@73 1980 Layer *currentLayer = currentPane->getSelectedLayer();
Chris@73 1981 if (!currentLayer) return;
Chris@73 1982
Chris@73 1983 for (int i = 0; i < currentPane->getLayerCount(); ++i) {
Chris@73 1984 if (currentPane->getLayer(i) == currentLayer) {
Chris@73 1985 if (i == currentPane->getLayerCount()-1) return;
Chris@73 1986 m_paneStack->setCurrentLayer(currentPane,
Chris@73 1987 currentPane->getLayer(i+1));
Chris@73 1988 updateMenuStates();
Chris@73 1989 return;
Chris@73 1990 }
Chris@73 1991 }
Chris@73 1992 }
Chris@73 1993
Chris@73 1994 void
Chris@45 1995 MainWindowBase::playbackFrameChanged(unsigned long frame)
Chris@45 1996 {
Chris@45 1997 if (!(m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
Chris@45 1998
Chris@45 1999 RealTime now = RealTime::frame2RealTime
Chris@45 2000 (frame, getMainModel()->getSampleRate());
Chris@45 2001
Chris@45 2002 if (now.sec == m_lastPlayStatusSec) return;
Chris@45 2003
Chris@45 2004 RealTime then = RealTime::frame2RealTime
Chris@45 2005 (m_playSource->getPlayEndFrame(), getMainModel()->getSampleRate());
Chris@45 2006
Chris@45 2007 QString nowStr;
Chris@45 2008 QString thenStr;
Chris@45 2009 QString remainingStr;
Chris@45 2010
Chris@45 2011 if (then.sec > 10) {
Chris@45 2012 nowStr = now.toSecText().c_str();
Chris@45 2013 thenStr = then.toSecText().c_str();
Chris@45 2014 remainingStr = (then - now).toSecText().c_str();
Chris@45 2015 m_lastPlayStatusSec = now.sec;
Chris@45 2016 } else {
Chris@45 2017 nowStr = now.toText(true).c_str();
Chris@45 2018 thenStr = then.toText(true).c_str();
Chris@45 2019 remainingStr = (then - now).toText(true).c_str();
Chris@45 2020 }
Chris@45 2021
Chris@45 2022 m_myStatusMessage = tr("Playing: %1 of %2 (%3 remaining)")
Chris@45 2023 .arg(nowStr).arg(thenStr).arg(remainingStr);
Chris@45 2024
Chris@45 2025 statusBar()->showMessage(m_myStatusMessage);
Chris@45 2026 }
Chris@45 2027
Chris@45 2028 void
Chris@45 2029 MainWindowBase::globalCentreFrameChanged(unsigned long )
Chris@45 2030 {
Chris@45 2031 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
Chris@45 2032 Pane *p = 0;
Chris@45 2033 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
Chris@45 2034 if (!p->getFollowGlobalPan()) return;
Chris@45 2035 updateVisibleRangeDisplay(p);
Chris@45 2036 }
Chris@45 2037
Chris@45 2038 void
Chris@45 2039 MainWindowBase::viewCentreFrameChanged(View *v, unsigned long )
Chris@45 2040 {
Chris@45 2041 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
Chris@45 2042 Pane *p = 0;
Chris@45 2043 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
Chris@45 2044 if (v == p) updateVisibleRangeDisplay(p);
Chris@45 2045 }
Chris@45 2046
Chris@45 2047 void
Chris@45 2048 MainWindowBase::viewZoomLevelChanged(View *v, unsigned long , bool )
Chris@45 2049 {
Chris@45 2050 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
Chris@45 2051 Pane *p = 0;
Chris@45 2052 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
Chris@45 2053 if (v == p) updateVisibleRangeDisplay(p);
Chris@45 2054 }
Chris@45 2055
Chris@45 2056 void
Chris@45 2057 MainWindowBase::layerAdded(Layer *)
Chris@45 2058 {
Chris@45 2059 // std::cerr << "MainWindowBase::layerAdded(" << layer << ")" << std::endl;
Chris@45 2060 updateMenuStates();
Chris@45 2061 }
Chris@45 2062
Chris@45 2063 void
Chris@45 2064 MainWindowBase::layerRemoved(Layer *)
Chris@45 2065 {
Chris@45 2066 // std::cerr << "MainWindowBase::layerRemoved(" << layer << ")" << std::endl;
Chris@45 2067 updateMenuStates();
Chris@45 2068 }
Chris@45 2069
Chris@45 2070 void
Chris@45 2071 MainWindowBase::layerAboutToBeDeleted(Layer *layer)
Chris@45 2072 {
Chris@45 2073 // std::cerr << "MainWindowBase::layerAboutToBeDeleted(" << layer << ")" << std::endl;
Chris@47 2074 if (m_timeRulerLayer && (layer == m_timeRulerLayer)) {
Chris@45 2075 // std::cerr << "(this is the time ruler layer)" << std::endl;
Chris@45 2076 m_timeRulerLayer = 0;
Chris@45 2077 }
Chris@45 2078 }
Chris@45 2079
Chris@45 2080 void
Chris@45 2081 MainWindowBase::layerInAView(Layer *layer, bool inAView)
Chris@45 2082 {
Chris@45 2083 // std::cerr << "MainWindowBase::layerInAView(" << layer << "," << inAView << ")" << std::endl;
Chris@45 2084
Chris@45 2085 // Check whether we need to add or remove model from play source
Chris@45 2086 Model *model = layer->getModel();
Chris@45 2087 if (model) {
Chris@45 2088 if (inAView) {
Chris@45 2089 m_playSource->addModel(model);
Chris@45 2090 } else {
Chris@45 2091 bool found = false;
Chris@45 2092 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@45 2093 Pane *pane = m_paneStack->getPane(i);
Chris@45 2094 if (!pane) continue;
Chris@45 2095 for (int j = 0; j < pane->getLayerCount(); ++j) {
Chris@45 2096 Layer *pl = pane->getLayer(j);
Chris@45 2097 if (pl && pl->getModel() == model) {
Chris@45 2098 found = true;
Chris@45 2099 break;
Chris@45 2100 }
Chris@45 2101 }
Chris@45 2102 if (found) break;
Chris@45 2103 }
Chris@45 2104 if (!found) m_playSource->removeModel(model);
Chris@45 2105 }
Chris@45 2106 }
Chris@45 2107
Chris@45 2108 updateMenuStates();
Chris@45 2109 }
Chris@45 2110
Chris@45 2111 void
Chris@45 2112 MainWindowBase::modelAdded(Model *model)
Chris@45 2113 {
Chris@45 2114 // std::cerr << "MainWindowBase::modelAdded(" << model << ")" << std::endl;
Chris@45 2115 m_playSource->addModel(model);
Chris@45 2116 }
Chris@45 2117
Chris@45 2118 void
Chris@45 2119 MainWindowBase::mainModelChanged(WaveFileModel *model)
Chris@45 2120 {
Chris@45 2121 // std::cerr << "MainWindowBase::mainModelChanged(" << model << ")" << std::endl;
Chris@45 2122 updateDescriptionLabel();
Chris@45 2123 if (model) m_viewManager->setMainModelSampleRate(model->getSampleRate());
Chris@45 2124 if (model && !m_playTarget && m_audioOutput) createPlayTarget();
Chris@45 2125 }
Chris@45 2126
Chris@45 2127 void
Chris@45 2128 MainWindowBase::modelAboutToBeDeleted(Model *model)
Chris@45 2129 {
Chris@45 2130 // std::cerr << "MainWindowBase::modelAboutToBeDeleted(" << model << ")" << std::endl;
Chris@45 2131 if (model == m_viewManager->getPlaybackModel()) {
Chris@45 2132 m_viewManager->setPlaybackModel(0);
Chris@45 2133 }
Chris@45 2134 m_playSource->removeModel(model);
Chris@45 2135 FFTDataServer::modelAboutToBeDeleted(model);
Chris@45 2136 }
Chris@45 2137
Chris@45 2138 void
Chris@55 2139 MainWindowBase::paneDeleteButtonClicked(Pane *pane)
Chris@55 2140 {
Chris@55 2141 bool found = false;
Chris@55 2142 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@55 2143 if (m_paneStack->getPane(i) == pane) {
Chris@55 2144 found = true;
Chris@55 2145 break;
Chris@55 2146 }
Chris@55 2147 }
Chris@55 2148 if (!found) {
Chris@55 2149 std::cerr << "MainWindowBase::paneDeleteButtonClicked: Unknown pane "
Chris@55 2150 << pane << std::endl;
Chris@55 2151 return;
Chris@55 2152 }
Chris@55 2153
Chris@55 2154 CommandHistory::getInstance()->startCompoundOperation
Chris@55 2155 (tr("Delete Pane"), true);
Chris@55 2156
Chris@55 2157 while (pane->getLayerCount() > 0) {
Chris@55 2158 Layer *layer = pane->getLayer(0);
Chris@55 2159 if (layer) {
Chris@55 2160 m_document->removeLayerFromView(pane, layer);
Chris@55 2161 } else {
Chris@55 2162 break;
Chris@55 2163 }
Chris@55 2164 }
Chris@55 2165
Chris@55 2166 RemovePaneCommand *command = new RemovePaneCommand(this, pane);
Chris@55 2167 CommandHistory::getInstance()->addCommand(command);
Chris@55 2168
Chris@55 2169 CommandHistory::getInstance()->endCompoundOperation();
Chris@55 2170
Chris@55 2171 updateMenuStates();
Chris@55 2172 }
Chris@55 2173
Chris@55 2174 void
Chris@45 2175 MainWindowBase::pollOSC()
Chris@45 2176 {
Chris@45 2177 if (!m_oscQueue || m_oscQueue->isEmpty()) return;
Chris@45 2178 std::cerr << "MainWindowBase::pollOSC: have " << m_oscQueue->getMessagesAvailable() << " messages" << std::endl;
Chris@45 2179
Chris@45 2180 if (m_openingAudioFile) return;
Chris@45 2181
Chris@45 2182 OSCMessage message = m_oscQueue->readMessage();
Chris@45 2183
Chris@45 2184 if (message.getTarget() != 0) {
Chris@45 2185 return; //!!! for now -- this class is target 0, others not handled yet
Chris@45 2186 }
Chris@45 2187
Chris@45 2188 handleOSCMessage(message);
Chris@45 2189 }
Chris@45 2190
Chris@45 2191 void
Chris@45 2192 MainWindowBase::inProgressSelectionChanged()
Chris@45 2193 {
Chris@45 2194 Pane *currentPane = 0;
Chris@45 2195 if (m_paneStack) currentPane = m_paneStack->getCurrentPane();
Chris@45 2196 if (currentPane) updateVisibleRangeDisplay(currentPane);
Chris@45 2197 }
Chris@45 2198
Chris@45 2199 void
Chris@45 2200 MainWindowBase::contextHelpChanged(const QString &s)
Chris@45 2201 {
Chris@45 2202 if (s == "" && m_myStatusMessage != "") {
Chris@45 2203 statusBar()->showMessage(m_myStatusMessage);
Chris@45 2204 return;
Chris@45 2205 }
Chris@45 2206 statusBar()->showMessage(s);
Chris@45 2207 }
Chris@45 2208
Chris@45 2209 void
Chris@45 2210 MainWindowBase::openHelpUrl(QString url)
Chris@45 2211 {
Chris@45 2212 // This method mostly lifted from Qt Assistant source code
Chris@45 2213
Chris@45 2214 QProcess *process = new QProcess(this);
Chris@45 2215 connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater()));
Chris@45 2216
Chris@45 2217 QStringList args;
Chris@45 2218
Chris@45 2219 #ifdef Q_OS_MAC
Chris@45 2220 args.append(url);
Chris@45 2221 process->start("open", args);
Chris@45 2222 #else
Chris@45 2223 #ifdef Q_OS_WIN32
Chris@45 2224
Chris@45 2225 QString pf(getenv("ProgramFiles"));
Chris@45 2226 QString command = pf + QString("\\Internet Explorer\\IEXPLORE.EXE");
Chris@45 2227
Chris@45 2228 args.append(url);
Chris@45 2229 process->start(command, args);
Chris@45 2230
Chris@45 2231 #else
Chris@45 2232 #ifdef Q_WS_X11
Chris@45 2233 if (!qgetenv("KDE_FULL_SESSION").isEmpty()) {
Chris@45 2234 args.append("exec");
Chris@45 2235 args.append(url);
Chris@45 2236 process->start("kfmclient", args);
Chris@45 2237 } else if (!qgetenv("BROWSER").isEmpty()) {
Chris@45 2238 args.append(url);
Chris@45 2239 process->start(qgetenv("BROWSER"), args);
Chris@45 2240 } else {
Chris@45 2241 args.append(url);
Chris@45 2242 process->start("firefox", args);
Chris@45 2243 }
Chris@45 2244 #endif
Chris@45 2245 #endif
Chris@45 2246 #endif
Chris@45 2247 }
Chris@45 2248