annotate main/MainWindowBase.cpp @ 201:de783e8ee5f0

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