annotate framework/MainWindowBase.cpp @ 140:9ccaa8fd9b9f

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