annotate framework/MainWindowBase.cpp @ 180:84b2c1a4984a

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