annotate framework/MainWindowBase.cpp @ 191:3bd87e04f060

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