annotate framework/MainWindowBase.cpp @ 122:ab861544f998

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