annotate framework/MainWindowBase.cpp @ 144:675443abbc05

Various fixes: * Fix handling of HTTP redirects (avoiding crashes... I hope) * Fix failure to delete FFT models when a feature extraction model transformer was abandoned (also a cause of crashes in the past) * Fix deadlock when said transform was abandoned before its source model was ready because the session was being cleared (and so the source model would never be ready)
author Chris Cannam
date Fri, 28 Nov 2008 13:36:13 +0000
parents 9ef382913c17
children 937456ffe33e
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@141 1132 RDFImporter importer(QUrl::fromLocalFile(path).toString(),
Chris@141 1133 getMainModel()->getSampleRate());
Chris@134 1134 if (importer.isOK()) {
Chris@134 1135
Chris@135 1136 std::vector<Model *> models;
Chris@135 1137
Chris@135 1138 {
Chris@135 1139 ProgressDialog dialog(tr("Importing from RDF..."), true, 2000, this);
Chris@135 1140 connect(&dialog, SIGNAL(showing()), this, SIGNAL(hideSplash()));
Chris@135 1141 models = importer.getDataModels(&dialog);
Chris@135 1142 }
Chris@135 1143
Chris@135 1144 if (models.empty()) {
Chris@135 1145 return FileOpenFailed;
Chris@135 1146 }
Chris@134 1147
Chris@134 1148 for (int i = 0; i < models.size(); ++i) {
Chris@134 1149 Layer *newLayer = m_document->createImportedLayer(models[i]);
Chris@134 1150 if (newLayer) {
Chris@143 1151 if (newLayer->isLayerOpaque() ||
Chris@143 1152 dynamic_cast<Colour3DPlotLayer *>(newLayer)) {
Chris@143 1153 //!!! general garbage. we should be using
Chris@143 1154 // a separate loader class that uses callbacks
Chris@143 1155 // and directly calls on the document, much
Chris@143 1156 // more like SVFileReader
Chris@143 1157 AddPaneCommand *command = new AddPaneCommand(this);
Chris@143 1158 CommandHistory::getInstance()->addCommand(command);
Chris@143 1159 pane = command->getPane();
Chris@143 1160 }
Chris@134 1161 m_document->addLayerToView(pane, newLayer);
Chris@134 1162 }
Chris@134 1163 }
Chris@134 1164
Chris@134 1165 m_recentFiles.addFile(source.getLocation());
Chris@134 1166 return FileOpenSucceeded;
Chris@134 1167 }
Chris@134 1168
Chris@134 1169 return FileOpenFailed;
Chris@134 1170
Chris@140 1171 } else if (source.getExtension() == "svl" ||
Chris@140 1172 (source.getExtension() == "xml" &&
Chris@140 1173 (SVFileReader::identifyXmlFile(source.getLocalFilename())
Chris@140 1174 == SVFileReader::SVLayerFile))) {
Chris@45 1175
Chris@45 1176 PaneCallback callback(this);
Chris@45 1177 QFile file(path);
Chris@45 1178
Chris@45 1179 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
Chris@45 1180 std::cerr << "ERROR: MainWindowBase::openLayer("
Chris@45 1181 << source.getLocation().toStdString()
Chris@45 1182 << "): Failed to open file for reading" << std::endl;
Chris@45 1183 return FileOpenFailed;
Chris@45 1184 }
Chris@45 1185
Chris@45 1186 SVFileReader reader(m_document, callback, source.getLocation());
Chris@79 1187 connect
Chris@79 1188 (&reader, SIGNAL(modelRegenerationFailed(QString, QString, QString)),
Chris@79 1189 this, SLOT(modelRegenerationFailed(QString, QString, QString)));
Chris@79 1190 connect
Chris@79 1191 (&reader, SIGNAL(modelRegenerationWarning(QString, QString, QString)),
Chris@79 1192 this, SLOT(modelRegenerationWarning(QString, QString, QString)));
Chris@45 1193 reader.setCurrentPane(pane);
Chris@45 1194
Chris@45 1195 QXmlInputSource inputSource(&file);
Chris@45 1196 reader.parse(inputSource);
Chris@45 1197
Chris@45 1198 if (!reader.isOK()) {
Chris@45 1199 std::cerr << "ERROR: MainWindowBase::openLayer("
Chris@45 1200 << source.getLocation().toStdString()
Chris@45 1201 << "): Failed to read XML file: "
Chris@45 1202 << reader.getErrorString().toStdString() << std::endl;
Chris@45 1203 return FileOpenFailed;
Chris@45 1204 }
Chris@45 1205
Chris@45 1206 m_recentFiles.addFile(source.getLocation());
Chris@45 1207
Chris@45 1208 if (!source.isRemote()) {
Chris@45 1209 registerLastOpenedFilePath(FileFinder::LayerFile, path); // for file dialog
Chris@45 1210 }
Chris@45 1211
Chris@75 1212 return FileOpenSucceeded;
Chris@75 1213
Chris@45 1214 } else {
Chris@45 1215
Chris@45 1216 try {
Chris@45 1217
Chris@109 1218 MIDIFileImportDialog midiDlg(this);
Chris@109 1219
Chris@109 1220 Model *model = DataFileReaderFactory::loadNonCSV
Chris@109 1221 (path, &midiDlg, getMainModel()->getSampleRate());
Chris@45 1222
Chris@109 1223 if (!model) {
Chris@109 1224 CSVFormatDialog *dialog = new CSVFormatDialog
Chris@109 1225 (this, CSVFormat(path), getMainModel()->getSampleRate());
Chris@109 1226 if (dialog->exec() == QDialog::Accepted) {
Chris@109 1227 model = DataFileReaderFactory::loadCSV
Chris@109 1228 (path, dialog->getFormat(),
Chris@109 1229 getMainModel()->getSampleRate());
Chris@109 1230 }
Chris@109 1231 }
Chris@109 1232
Chris@45 1233 if (model) {
Chris@45 1234
Chris@45 1235 std::cerr << "MainWindowBase::openLayer: Have model" << std::endl;
Chris@45 1236
Chris@45 1237 Layer *newLayer = m_document->createImportedLayer(model);
Chris@45 1238
Chris@45 1239 if (newLayer) {
Chris@45 1240
Chris@45 1241 m_document->addLayerToView(pane, newLayer);
Chris@88 1242 m_paneStack->setCurrentLayer(pane, newLayer);
Chris@88 1243
Chris@45 1244 m_recentFiles.addFile(source.getLocation());
Chris@45 1245
Chris@45 1246 if (!source.isRemote()) {
Chris@45 1247 registerLastOpenedFilePath
Chris@45 1248 (FileFinder::LayerFile,
Chris@45 1249 path); // for file dialog
Chris@45 1250 }
Chris@88 1251
Chris@45 1252 return FileOpenSucceeded;
Chris@45 1253 }
Chris@45 1254 }
Chris@45 1255 } catch (DataFileReaderFactory::Exception e) {
Chris@45 1256 if (e == DataFileReaderFactory::ImportCancelled) {
Chris@45 1257 return FileOpenCancelled;
Chris@45 1258 }
Chris@45 1259 }
Chris@45 1260 }
Chris@45 1261
Chris@45 1262 return FileOpenFailed;
Chris@45 1263 }
Chris@45 1264
Chris@45 1265 MainWindowBase::FileOpenStatus
Chris@45 1266 MainWindowBase::openImage(FileSource source)
Chris@45 1267 {
Chris@135 1268 std::cerr << "MainWindowBase::openImage(" << source.getLocation().toStdString() << ")" << std::endl;
Chris@135 1269
Chris@45 1270 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 1271
Chris@45 1272 if (!pane) {
Chris@45 1273 // shouldn't happen, as the menu action should have been disabled
Chris@45 1274 std::cerr << "WARNING: MainWindowBase::openImage: no current pane" << std::endl;
Chris@45 1275 return FileOpenWrongMode;
Chris@45 1276 }
Chris@45 1277
Chris@45 1278 if (!m_document->getMainModel()) {
Chris@45 1279 return FileOpenWrongMode;
Chris@45 1280 }
Chris@45 1281
Chris@45 1282 bool newLayer = false;
Chris@45 1283
Chris@45 1284 ImageLayer *il = dynamic_cast<ImageLayer *>(pane->getSelectedLayer());
Chris@45 1285 if (!il) {
Chris@45 1286 for (int i = pane->getLayerCount()-1; i >= 0; --i) {
Chris@45 1287 il = dynamic_cast<ImageLayer *>(pane->getLayer(i));
Chris@45 1288 if (il) break;
Chris@45 1289 }
Chris@45 1290 }
Chris@45 1291 if (!il) {
Chris@45 1292 il = dynamic_cast<ImageLayer *>
Chris@45 1293 (m_document->createEmptyLayer(LayerFactory::Image));
Chris@45 1294 if (!il) return FileOpenFailed;
Chris@45 1295 newLayer = true;
Chris@45 1296 }
Chris@45 1297
Chris@45 1298 // We don't put the image file in Recent Files
Chris@45 1299
Chris@45 1300 std::cerr << "openImage: trying location \"" << source.getLocation().toStdString() << "\" in image layer" << std::endl;
Chris@45 1301
Chris@45 1302 if (!il->addImage(m_viewManager->getGlobalCentreFrame(), source.getLocation())) {
Chris@45 1303 if (newLayer) {
Chris@52 1304 m_document->deleteLayer(il); // also releases its model
Chris@45 1305 }
Chris@45 1306 return FileOpenFailed;
Chris@45 1307 } else {
Chris@45 1308 if (newLayer) {
Chris@45 1309 m_document->addLayerToView(pane, il);
Chris@45 1310 }
Chris@45 1311 m_paneStack->setCurrentLayer(pane, il);
Chris@45 1312 }
Chris@45 1313
Chris@45 1314 return FileOpenSucceeded;
Chris@45 1315 }
Chris@45 1316
Chris@45 1317 MainWindowBase::FileOpenStatus
Chris@45 1318 MainWindowBase::openSessionFile(QString fileOrUrl)
Chris@45 1319 {
Chris@134 1320 ProgressDialog dialog(tr("Opening session..."), true, 2000, this);
Chris@134 1321 connect(&dialog, SIGNAL(showing()), this, SIGNAL(hideSplash()));
Chris@109 1322 return openSession(FileSource(fileOrUrl, &dialog));
Chris@45 1323 }
Chris@45 1324
Chris@45 1325 MainWindowBase::FileOpenStatus
Chris@45 1326 MainWindowBase::openSession(FileSource source)
Chris@45 1327 {
Chris@135 1328 std::cerr << "MainWindowBase::openSession(" << source.getLocation().toStdString() << ")" << std::endl;
Chris@135 1329
Chris@45 1330 if (!source.isAvailable()) return FileOpenFailed;
Chris@140 1331
Chris@141 1332 if (source.getExtension() == "rdf" || source.getExtension() == "n3" ||
Chris@141 1333 source.getExtension() == "ttl") {
Chris@141 1334 return openSessionFromRDF(source);
Chris@141 1335 }
Chris@141 1336
Chris@140 1337 if (source.getExtension() != "sv") {
Chris@140 1338 if (source.getExtension() == "xml") {
Chris@140 1339 source.waitForData();
Chris@140 1340 if (SVFileReader::identifyXmlFile(source.getLocalFilename()) ==
Chris@140 1341 SVFileReader::SVSessionFile) {
Chris@140 1342 std::cerr << "This XML file looks like a session file, attempting to open it as a session" << std::endl;
Chris@140 1343 } else {
Chris@140 1344 return FileOpenFailed;
Chris@140 1345 }
Chris@140 1346 } else {
Chris@140 1347 return FileOpenFailed;
Chris@140 1348 }
Chris@140 1349 }
Chris@45 1350 source.waitForData();
Chris@45 1351
Chris@140 1352 QXmlInputSource *inputSource = 0;
Chris@140 1353 BZipFileDevice *bzFile = 0;
Chris@140 1354 QFile *rawFile = 0;
Chris@140 1355
Chris@140 1356 if (source.getExtension() == "sv") {
Chris@140 1357 bzFile = new BZipFileDevice(source.getLocalFilename());
Chris@140 1358 if (!bzFile->open(QIODevice::ReadOnly)) {
Chris@140 1359 delete bzFile;
Chris@140 1360 return FileOpenFailed;
Chris@140 1361 }
Chris@140 1362 inputSource = new QXmlInputSource(bzFile);
Chris@140 1363 } else {
Chris@140 1364 rawFile = new QFile(source.getLocalFilename());
Chris@140 1365 inputSource = new QXmlInputSource(rawFile);
Chris@140 1366 }
Chris@140 1367
Chris@140 1368 if (!checkSaveModified()) {
Chris@140 1369 if (bzFile) bzFile->close();
Chris@140 1370 delete inputSource;
Chris@140 1371 delete bzFile;
Chris@140 1372 delete rawFile;
Chris@140 1373 return FileOpenCancelled;
Chris@140 1374 }
Chris@45 1375
Chris@45 1376 QString error;
Chris@45 1377 closeSession();
Chris@45 1378 createDocument();
Chris@45 1379
Chris@45 1380 PaneCallback callback(this);
Chris@45 1381 m_viewManager->clearSelections();
Chris@45 1382
Chris@45 1383 SVFileReader reader(m_document, callback, source.getLocation());
Chris@79 1384 connect
Chris@79 1385 (&reader, SIGNAL(modelRegenerationFailed(QString, QString, QString)),
Chris@79 1386 this, SLOT(modelRegenerationFailed(QString, QString, QString)));
Chris@79 1387 connect
Chris@79 1388 (&reader, SIGNAL(modelRegenerationWarning(QString, QString, QString)),
Chris@79 1389 this, SLOT(modelRegenerationWarning(QString, QString, QString)));
Chris@140 1390
Chris@140 1391 reader.parse(*inputSource);
Chris@45 1392
Chris@45 1393 if (!reader.isOK()) {
Chris@45 1394 error = tr("SV XML file read error:\n%1").arg(reader.getErrorString());
Chris@45 1395 }
Chris@45 1396
Chris@140 1397 if (bzFile) bzFile->close();
Chris@140 1398
Chris@140 1399 delete inputSource;
Chris@140 1400 delete bzFile;
Chris@140 1401 delete rawFile;
Chris@45 1402
Chris@45 1403 bool ok = (error == "");
Chris@45 1404
Chris@45 1405 if (ok) {
Chris@45 1406
Chris@57 1407 setWindowTitle(tr("%1: %2")
Chris@57 1408 .arg(QApplication::applicationName())
Chris@45 1409 .arg(source.getLocation()));
Chris@45 1410
Chris@45 1411 if (!source.isRemote()) m_sessionFile = source.getLocalFilename();
Chris@45 1412
Chris@45 1413 setupMenus();
Chris@45 1414
Chris@45 1415 CommandHistory::getInstance()->clear();
Chris@45 1416 CommandHistory::getInstance()->documentSaved();
Chris@45 1417 m_documentModified = false;
Chris@45 1418 updateMenuStates();
Chris@45 1419
Chris@45 1420 m_recentFiles.addFile(source.getLocation());
Chris@45 1421
Chris@45 1422 if (!source.isRemote()) {
Chris@45 1423 // for file dialog
Chris@45 1424 registerLastOpenedFilePath(FileFinder::SessionFile,
Chris@45 1425 source.getLocalFilename());
Chris@45 1426 }
Chris@45 1427
Chris@45 1428 } else {
Chris@57 1429 setWindowTitle(QApplication::applicationName());
Chris@45 1430 }
Chris@45 1431
Chris@45 1432 return ok ? FileOpenSucceeded : FileOpenFailed;
Chris@45 1433 }
Chris@45 1434
Chris@141 1435 MainWindowBase::FileOpenStatus
Chris@141 1436 MainWindowBase::openSessionFromRDF(FileSource source)
Chris@141 1437 {
Chris@141 1438 std::cerr << "MainWindowBase::openSessionFromRDF(" << source.getLocation().toStdString() << ")" << std::endl;
Chris@141 1439
Chris@141 1440 if (!source.isAvailable()) return FileOpenFailed;
Chris@141 1441
Chris@141 1442 source.waitForData();
Chris@141 1443
Chris@141 1444 RDFImporter importer
Chris@141 1445 (QUrl::fromLocalFile(source.getLocalFilename()).toString());
Chris@141 1446
Chris@141 1447 QString audioUrl = importer.getAudioAvailableUrl();
Chris@141 1448 if (audioUrl == "") {
Chris@141 1449 std::cerr << "MainWindowBase::openSessionFromRDF: No audio URL in RDF, can't open a session without audio" << std::endl;
Chris@141 1450 return FileOpenFailed;
Chris@141 1451 }
Chris@141 1452
Chris@141 1453 size_t rate = 0;
Chris@141 1454
Chris@141 1455 if (Preferences::getInstance()->getResampleOnLoad()) {
Chris@141 1456 rate = m_playSource->getSourceSampleRate();
Chris@141 1457 }
Chris@141 1458
Chris@143 1459 {
Chris@143 1460 ProgressDialog dialog(tr("Importing from RDF..."), true, 2000, this);
Chris@143 1461 connect(&dialog, SIGNAL(showing()), this, SIGNAL(hideSplash()));
Chris@143 1462
Chris@143 1463 FileSource audioSource(audioUrl, &dialog);
Chris@144 1464
Chris@143 1465 if (!audioSource.isAvailable()) {
Chris@143 1466 std::cerr << "MainWindowBase::openSessionFromRDF: Cannot open audio URL \"" << audioUrl.toStdString() << "\" referred to in RDF, can't open a session without audio" << std::endl;
Chris@143 1467 return FileOpenFailed;
Chris@143 1468 }
Chris@143 1469
Chris@143 1470 if (!checkSaveModified()) {
Chris@143 1471 return FileOpenCancelled;
Chris@143 1472 }
Chris@143 1473
Chris@143 1474 closeSession();
Chris@143 1475 createDocument();
Chris@143 1476
Chris@143 1477 audioSource.waitForData();
Chris@143 1478
Chris@143 1479 WaveFileModel *newModel = new WaveFileModel(audioSource);
Chris@143 1480
Chris@143 1481 m_viewManager->clearSelections();
Chris@143 1482
Chris@143 1483 AddPaneCommand *command = new AddPaneCommand(this);
Chris@143 1484 CommandHistory::getInstance()->addCommand(command);
Chris@143 1485
Chris@143 1486 Pane *pane = command->getPane();
Chris@143 1487
Chris@143 1488 if (m_timeRulerLayer) {
Chris@143 1489 m_document->addLayerToView(pane, m_timeRulerLayer);
Chris@143 1490 }
Chris@143 1491
Chris@143 1492 Layer *newLayer = m_document->createMainModelLayer(LayerFactory::Waveform);
Chris@143 1493 m_document->addLayerToView(pane, newLayer);
Chris@143 1494
Chris@143 1495 m_document->setMainModel(newModel);
Chris@141 1496 }
Chris@141 1497
Chris@141 1498 FileOpenStatus layerStatus = openLayer(source);
Chris@141 1499
Chris@141 1500 setupMenus();
Chris@141 1501
Chris@141 1502 setWindowTitle(tr("%1: %2")
Chris@141 1503 .arg(QApplication::applicationName())
Chris@141 1504 .arg(source.getLocation()));
Chris@141 1505 CommandHistory::getInstance()->clear();
Chris@141 1506 CommandHistory::getInstance()->documentSaved();
Chris@141 1507 m_documentModified = false;
Chris@141 1508
Chris@141 1509 return layerStatus;
Chris@141 1510 }
Chris@141 1511
Chris@45 1512 void
Chris@45 1513 MainWindowBase::createPlayTarget()
Chris@45 1514 {
Chris@45 1515 if (m_playTarget) return;
Chris@45 1516
Chris@126 1517 QSettings settings;
Chris@126 1518 settings.beginGroup("Preferences");
Chris@126 1519 QString targetName = settings.value("audio-target", "").toString();
Chris@126 1520 settings.endGroup();
Chris@126 1521
Chris@126 1522 AudioTargetFactory *factory = AudioTargetFactory::getInstance();
Chris@126 1523
Chris@126 1524 factory->setDefaultCallbackTarget(targetName);
Chris@126 1525 m_playTarget = factory->createCallbackTarget(m_playSource);
Chris@126 1526
Chris@45 1527 if (!m_playTarget) {
Chris@104 1528 emit hideSplash();
Chris@126 1529
Chris@126 1530 if (factory->isAutoCallbackTarget(targetName)) {
Chris@128 1531 QMessageBox::warning
Chris@45 1532 (this, tr("Couldn't open audio device"),
Chris@126 1533 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 1534 QMessageBox::Ok);
Chris@126 1535 } else {
Chris@126 1536 QMessageBox::warning
Chris@126 1537 (this, tr("Couldn't open audio device"),
Chris@126 1538 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 1539 .arg(factory->getCallbackTargetDescription(targetName)),
Chris@126 1540 QMessageBox::Ok);
Chris@126 1541 }
Chris@45 1542 }
Chris@45 1543 }
Chris@45 1544
Chris@45 1545 WaveFileModel *
Chris@45 1546 MainWindowBase::getMainModel()
Chris@45 1547 {
Chris@45 1548 if (!m_document) return 0;
Chris@45 1549 return m_document->getMainModel();
Chris@45 1550 }
Chris@45 1551
Chris@45 1552 const WaveFileModel *
Chris@45 1553 MainWindowBase::getMainModel() const
Chris@45 1554 {
Chris@45 1555 if (!m_document) return 0;
Chris@45 1556 return m_document->getMainModel();
Chris@45 1557 }
Chris@45 1558
Chris@45 1559 void
Chris@45 1560 MainWindowBase::createDocument()
Chris@45 1561 {
Chris@45 1562 m_document = new Document;
Chris@45 1563
Chris@45 1564 connect(m_document, SIGNAL(layerAdded(Layer *)),
Chris@45 1565 this, SLOT(layerAdded(Layer *)));
Chris@45 1566 connect(m_document, SIGNAL(layerRemoved(Layer *)),
Chris@45 1567 this, SLOT(layerRemoved(Layer *)));
Chris@45 1568 connect(m_document, SIGNAL(layerAboutToBeDeleted(Layer *)),
Chris@45 1569 this, SLOT(layerAboutToBeDeleted(Layer *)));
Chris@45 1570 connect(m_document, SIGNAL(layerInAView(Layer *, bool)),
Chris@45 1571 this, SLOT(layerInAView(Layer *, bool)));
Chris@45 1572
Chris@45 1573 connect(m_document, SIGNAL(modelAdded(Model *)),
Chris@45 1574 this, SLOT(modelAdded(Model *)));
Chris@45 1575 connect(m_document, SIGNAL(mainModelChanged(WaveFileModel *)),
Chris@45 1576 this, SLOT(mainModelChanged(WaveFileModel *)));
Chris@45 1577 connect(m_document, SIGNAL(modelAboutToBeDeleted(Model *)),
Chris@45 1578 this, SLOT(modelAboutToBeDeleted(Model *)));
Chris@45 1579
Chris@78 1580 connect(m_document, SIGNAL(modelGenerationFailed(QString, QString)),
Chris@78 1581 this, SLOT(modelGenerationFailed(QString, QString)));
Chris@78 1582 connect(m_document, SIGNAL(modelRegenerationWarning(QString, QString, QString)),
Chris@78 1583 this, SLOT(modelRegenerationWarning(QString, QString, QString)));
Chris@78 1584 connect(m_document, SIGNAL(modelGenerationFailed(QString, QString)),
Chris@78 1585 this, SLOT(modelGenerationFailed(QString, QString)));
Chris@78 1586 connect(m_document, SIGNAL(modelRegenerationWarning(QString, QString, QString)),
Chris@78 1587 this, SLOT(modelRegenerationWarning(QString, QString, QString)));
Chris@78 1588 connect(m_document, SIGNAL(alignmentFailed(QString, QString)),
Chris@78 1589 this, SLOT(alignmentFailed(QString, QString)));
Chris@45 1590 }
Chris@45 1591
Chris@45 1592 bool
Chris@45 1593 MainWindowBase::saveSessionFile(QString path)
Chris@45 1594 {
Chris@45 1595 BZipFileDevice bzFile(path);
Chris@45 1596 if (!bzFile.open(QIODevice::WriteOnly)) {
Chris@45 1597 std::cerr << "Failed to open session file \"" << path.toStdString()
Chris@45 1598 << "\" for writing: "
Chris@45 1599 << bzFile.errorString().toStdString() << std::endl;
Chris@45 1600 return false;
Chris@45 1601 }
Chris@45 1602
Chris@45 1603 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
Chris@45 1604
Chris@45 1605 QTextStream out(&bzFile);
Chris@45 1606 toXml(out);
Chris@45 1607 out.flush();
Chris@45 1608
Chris@45 1609 QApplication::restoreOverrideCursor();
Chris@45 1610
Chris@45 1611 if (!bzFile.isOK()) {
Chris@45 1612 QMessageBox::critical(this, tr("Failed to write file"),
Chris@45 1613 tr("<b>Save failed</b><p>Failed to write to file \"%1\": %2")
Chris@45 1614 .arg(path).arg(bzFile.errorString()));
Chris@45 1615 bzFile.close();
Chris@45 1616 return false;
Chris@45 1617 }
Chris@45 1618
Chris@45 1619 bzFile.close();
Chris@45 1620 return true;
Chris@45 1621 }
Chris@45 1622
Chris@45 1623 void
Chris@45 1624 MainWindowBase::toXml(QTextStream &out)
Chris@45 1625 {
Chris@45 1626 QString indent(" ");
Chris@45 1627
Chris@45 1628 out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
Chris@45 1629 out << "<!DOCTYPE sonic-visualiser>\n";
Chris@45 1630 out << "<sv>\n";
Chris@45 1631
Chris@45 1632 m_document->toXml(out, "", "");
Chris@45 1633
Chris@45 1634 out << "<display>\n";
Chris@45 1635
Chris@45 1636 out << QString(" <window width=\"%1\" height=\"%2\"/>\n")
Chris@45 1637 .arg(width()).arg(height());
Chris@45 1638
Chris@45 1639 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@45 1640
Chris@45 1641 Pane *pane = m_paneStack->getPane(i);
Chris@45 1642
Chris@45 1643 if (pane) {
Chris@45 1644 pane->toXml(out, indent);
Chris@45 1645 }
Chris@45 1646 }
Chris@45 1647
Chris@45 1648 out << "</display>\n";
Chris@45 1649
Chris@45 1650 m_viewManager->getSelection().toXml(out);
Chris@45 1651
Chris@45 1652 out << "</sv>\n";
Chris@45 1653 }
Chris@45 1654
Chris@45 1655 Pane *
Chris@45 1656 MainWindowBase::addPaneToStack()
Chris@45 1657 {
Chris@45 1658 AddPaneCommand *command = new AddPaneCommand(this);
Chris@45 1659 CommandHistory::getInstance()->addCommand(command);
Chris@57 1660 Pane *pane = command->getPane();
Chris@57 1661 return pane;
Chris@45 1662 }
Chris@45 1663
Chris@45 1664 void
Chris@45 1665 MainWindowBase::zoomIn()
Chris@45 1666 {
Chris@45 1667 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 1668 if (currentPane) currentPane->zoom(true);
Chris@45 1669 }
Chris@45 1670
Chris@45 1671 void
Chris@45 1672 MainWindowBase::zoomOut()
Chris@45 1673 {
Chris@45 1674 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 1675 if (currentPane) currentPane->zoom(false);
Chris@45 1676 }
Chris@45 1677
Chris@45 1678 void
Chris@45 1679 MainWindowBase::zoomToFit()
Chris@45 1680 {
Chris@45 1681 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 1682 if (!currentPane) return;
Chris@45 1683
Chris@45 1684 Model *model = getMainModel();
Chris@45 1685 if (!model) return;
Chris@45 1686
Chris@45 1687 size_t start = model->getStartFrame();
Chris@45 1688 size_t end = model->getEndFrame();
Chris@60 1689 if (m_playSource) end = std::max(end, m_playSource->getPlayEndFrame());
Chris@45 1690 size_t pixels = currentPane->width();
Chris@45 1691
Chris@45 1692 size_t sw = currentPane->getVerticalScaleWidth();
Chris@45 1693 if (pixels > sw * 2) pixels -= sw * 2;
Chris@45 1694 else pixels = 1;
Chris@45 1695 if (pixels > 4) pixels -= 4;
Chris@45 1696
Chris@45 1697 size_t zoomLevel = (end - start) / pixels;
Chris@45 1698
Chris@45 1699 currentPane->setZoomLevel(zoomLevel);
Chris@45 1700 currentPane->setCentreFrame((start + end) / 2);
Chris@45 1701 }
Chris@45 1702
Chris@45 1703 void
Chris@45 1704 MainWindowBase::zoomDefault()
Chris@45 1705 {
Chris@45 1706 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 1707 if (currentPane) currentPane->setZoomLevel(1024);
Chris@45 1708 }
Chris@45 1709
Chris@45 1710 void
Chris@45 1711 MainWindowBase::scrollLeft()
Chris@45 1712 {
Chris@45 1713 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 1714 if (currentPane) currentPane->scroll(false, false);
Chris@45 1715 }
Chris@45 1716
Chris@45 1717 void
Chris@45 1718 MainWindowBase::jumpLeft()
Chris@45 1719 {
Chris@45 1720 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 1721 if (currentPane) currentPane->scroll(false, true);
Chris@45 1722 }
Chris@45 1723
Chris@45 1724 void
Chris@45 1725 MainWindowBase::scrollRight()
Chris@45 1726 {
Chris@45 1727 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 1728 if (currentPane) currentPane->scroll(true, false);
Chris@45 1729 }
Chris@45 1730
Chris@45 1731 void
Chris@45 1732 MainWindowBase::jumpRight()
Chris@45 1733 {
Chris@45 1734 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 1735 if (currentPane) currentPane->scroll(true, true);
Chris@45 1736 }
Chris@45 1737
Chris@45 1738 void
Chris@45 1739 MainWindowBase::showNoOverlays()
Chris@45 1740 {
Chris@45 1741 m_viewManager->setOverlayMode(ViewManager::NoOverlays);
Chris@45 1742 }
Chris@45 1743
Chris@45 1744 void
Chris@45 1745 MainWindowBase::showMinimalOverlays()
Chris@45 1746 {
Chris@45 1747 m_viewManager->setOverlayMode(ViewManager::MinimalOverlays);
Chris@45 1748 }
Chris@45 1749
Chris@45 1750 void
Chris@45 1751 MainWindowBase::showStandardOverlays()
Chris@45 1752 {
Chris@45 1753 m_viewManager->setOverlayMode(ViewManager::StandardOverlays);
Chris@45 1754 }
Chris@45 1755
Chris@45 1756 void
Chris@45 1757 MainWindowBase::showAllOverlays()
Chris@45 1758 {
Chris@45 1759 m_viewManager->setOverlayMode(ViewManager::AllOverlays);
Chris@45 1760 }
Chris@45 1761
Chris@45 1762 void
Chris@45 1763 MainWindowBase::toggleZoomWheels()
Chris@45 1764 {
Chris@45 1765 if (m_viewManager->getZoomWheelsEnabled()) {
Chris@45 1766 m_viewManager->setZoomWheelsEnabled(false);
Chris@45 1767 } else {
Chris@45 1768 m_viewManager->setZoomWheelsEnabled(true);
Chris@45 1769 }
Chris@45 1770 }
Chris@45 1771
Chris@45 1772 void
Chris@45 1773 MainWindowBase::togglePropertyBoxes()
Chris@45 1774 {
Chris@45 1775 if (m_paneStack->getLayoutStyle() == PaneStack::NoPropertyStacks) {
Chris@45 1776 if (Preferences::getInstance()->getPropertyBoxLayout() ==
Chris@45 1777 Preferences::VerticallyStacked) {
Chris@45 1778 m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout);
Chris@45 1779 } else {
Chris@45 1780 m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout);
Chris@45 1781 }
Chris@45 1782 } else {
Chris@45 1783 m_paneStack->setLayoutStyle(PaneStack::NoPropertyStacks);
Chris@45 1784 }
Chris@45 1785 }
Chris@45 1786
Chris@45 1787 void
Chris@45 1788 MainWindowBase::toggleStatusBar()
Chris@45 1789 {
Chris@45 1790 QSettings settings;
Chris@45 1791 settings.beginGroup("MainWindow");
Chris@45 1792 bool sb = settings.value("showstatusbar", true).toBool();
Chris@45 1793
Chris@45 1794 if (sb) {
Chris@45 1795 statusBar()->hide();
Chris@45 1796 } else {
Chris@45 1797 statusBar()->show();
Chris@45 1798 }
Chris@45 1799
Chris@45 1800 settings.setValue("showstatusbar", !sb);
Chris@45 1801
Chris@45 1802 settings.endGroup();
Chris@45 1803 }
Chris@45 1804
Chris@45 1805 void
Chris@45 1806 MainWindowBase::preferenceChanged(PropertyContainer::PropertyName name)
Chris@45 1807 {
Chris@45 1808 if (name == "Property Box Layout") {
Chris@45 1809 if (m_paneStack->getLayoutStyle() != PaneStack::NoPropertyStacks) {
Chris@45 1810 if (Preferences::getInstance()->getPropertyBoxLayout() ==
Chris@45 1811 Preferences::VerticallyStacked) {
Chris@45 1812 m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout);
Chris@45 1813 } else {
Chris@45 1814 m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout);
Chris@45 1815 }
Chris@45 1816 }
Chris@45 1817 } else if (name == "Background Mode" && m_viewManager) {
Chris@45 1818 Preferences::BackgroundMode mode =
Chris@45 1819 Preferences::getInstance()->getBackgroundMode();
Chris@45 1820 if (mode == Preferences::BackgroundFromTheme) {
Chris@45 1821 m_viewManager->setGlobalDarkBackground(m_initialDarkBackground);
Chris@45 1822 } else if (mode == Preferences::DarkBackground) {
Chris@45 1823 m_viewManager->setGlobalDarkBackground(true);
Chris@45 1824 } else {
Chris@45 1825 m_viewManager->setGlobalDarkBackground(false);
Chris@45 1826 }
Chris@45 1827 }
Chris@45 1828 }
Chris@45 1829
Chris@45 1830 void
Chris@45 1831 MainWindowBase::play()
Chris@45 1832 {
Chris@45 1833 if (m_playSource->isPlaying()) {
Chris@45 1834 stop();
Chris@45 1835 } else {
Chris@45 1836 playbackFrameChanged(m_viewManager->getPlaybackFrame());
Chris@45 1837 m_playSource->play(m_viewManager->getPlaybackFrame());
Chris@45 1838 }
Chris@45 1839 }
Chris@45 1840
Chris@45 1841 void
Chris@45 1842 MainWindowBase::ffwd()
Chris@45 1843 {
Chris@45 1844 if (!getMainModel()) return;
Chris@45 1845
Chris@45 1846 int frame = m_viewManager->getPlaybackFrame();
Chris@45 1847 ++frame;
Chris@45 1848
Chris@85 1849 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 1850 Layer *layer = getSnapLayer();
Chris@45 1851 size_t sr = getMainModel()->getSampleRate();
Chris@45 1852
Chris@45 1853 if (!layer) {
Chris@45 1854
Chris@45 1855 frame = RealTime::realTime2Frame
Chris@45 1856 (RealTime::frame2RealTime(frame, sr) + RealTime(2, 0), sr);
Chris@45 1857 if (frame > int(getMainModel()->getEndFrame())) {
Chris@45 1858 frame = getMainModel()->getEndFrame();
Chris@45 1859 }
Chris@45 1860
Chris@45 1861 } else {
Chris@45 1862
Chris@45 1863 size_t resolution = 0;
Chris@85 1864 if (layer->snapToFeatureFrame(m_paneStack->getCurrentPane(),
Chris@85 1865 frame, resolution, Layer::SnapRight)) {
Chris@85 1866 if (pane) frame = pane->alignToReference(frame);
Chris@85 1867 } else {
Chris@45 1868 frame = getMainModel()->getEndFrame();
Chris@45 1869 }
Chris@45 1870 }
Chris@45 1871
Chris@45 1872 if (frame < 0) frame = 0;
Chris@45 1873
Chris@45 1874 if (m_viewManager->getPlaySelectionMode()) {
Chris@45 1875 frame = m_viewManager->constrainFrameToSelection(size_t(frame));
Chris@45 1876 }
Chris@45 1877
Chris@45 1878 m_viewManager->setPlaybackFrame(frame);
Chris@45 1879 }
Chris@45 1880
Chris@45 1881 void
Chris@45 1882 MainWindowBase::ffwdEnd()
Chris@45 1883 {
Chris@45 1884 if (!getMainModel()) return;
Chris@45 1885
Chris@139 1886 if (m_playSource &&
Chris@139 1887 m_playSource->isPlaying() &&
Chris@139 1888 !m_viewManager->getPlayLoopMode()) {
Chris@139 1889 stop();
Chris@139 1890 }
Chris@139 1891
Chris@45 1892 size_t frame = getMainModel()->getEndFrame();
Chris@45 1893
Chris@45 1894 if (m_viewManager->getPlaySelectionMode()) {
Chris@45 1895 frame = m_viewManager->constrainFrameToSelection(frame);
Chris@45 1896 }
Chris@45 1897
Chris@45 1898 m_viewManager->setPlaybackFrame(frame);
Chris@45 1899 }
Chris@45 1900
Chris@45 1901 void
Chris@45 1902 MainWindowBase::rewind()
Chris@45 1903 {
Chris@45 1904 if (!getMainModel()) return;
Chris@45 1905
Chris@45 1906 int frame = m_viewManager->getPlaybackFrame();
Chris@45 1907 if (frame > 0) --frame;
Chris@45 1908
Chris@85 1909 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 1910 Layer *layer = getSnapLayer();
Chris@45 1911 size_t sr = getMainModel()->getSampleRate();
Chris@45 1912
Chris@45 1913 // when rewinding during playback, we want to allow a period
Chris@45 1914 // following a rewind target point at which the rewind will go to
Chris@45 1915 // the prior point instead of the immediately neighbouring one
Chris@45 1916 if (m_playSource && m_playSource->isPlaying()) {
Chris@45 1917 RealTime ct = RealTime::frame2RealTime(frame, sr);
Chris@45 1918 ct = ct - RealTime::fromSeconds(0.25);
Chris@45 1919 if (ct < RealTime::zeroTime) ct = RealTime::zeroTime;
Chris@45 1920 // std::cerr << "rewind: frame " << frame << " -> ";
Chris@45 1921 frame = RealTime::realTime2Frame(ct, sr);
Chris@45 1922 // std::cerr << frame << std::endl;
Chris@45 1923 }
Chris@45 1924
Chris@45 1925 if (!layer) {
Chris@45 1926
Chris@45 1927 frame = RealTime::realTime2Frame
Chris@45 1928 (RealTime::frame2RealTime(frame, sr) - RealTime(2, 0), sr);
Chris@45 1929 if (frame < int(getMainModel()->getStartFrame())) {
Chris@45 1930 frame = getMainModel()->getStartFrame();
Chris@45 1931 }
Chris@45 1932
Chris@45 1933 } else {
Chris@45 1934
Chris@45 1935 size_t resolution = 0;
Chris@85 1936 if (layer->snapToFeatureFrame(m_paneStack->getCurrentPane(),
Chris@85 1937 frame, resolution, Layer::SnapLeft)) {
Chris@85 1938
Chris@85 1939 if (pane) frame = pane->alignToReference(frame);
Chris@85 1940 } else {
Chris@45 1941 frame = getMainModel()->getStartFrame();
Chris@45 1942 }
Chris@45 1943 }
Chris@45 1944
Chris@45 1945 if (frame < 0) frame = 0;
Chris@45 1946
Chris@45 1947 if (m_viewManager->getPlaySelectionMode()) {
Chris@45 1948 frame = m_viewManager->constrainFrameToSelection(size_t(frame));
Chris@45 1949 }
Chris@45 1950
Chris@45 1951 m_viewManager->setPlaybackFrame(frame);
Chris@45 1952 }
Chris@45 1953
Chris@45 1954 void
Chris@45 1955 MainWindowBase::rewindStart()
Chris@45 1956 {
Chris@45 1957 if (!getMainModel()) return;
Chris@45 1958
Chris@45 1959 size_t frame = getMainModel()->getStartFrame();
Chris@45 1960
Chris@45 1961 if (m_viewManager->getPlaySelectionMode()) {
Chris@45 1962 frame = m_viewManager->constrainFrameToSelection(frame);
Chris@45 1963 }
Chris@45 1964
Chris@45 1965 m_viewManager->setPlaybackFrame(frame);
Chris@45 1966 }
Chris@45 1967
Chris@45 1968 Layer *
Chris@45 1969 MainWindowBase::getSnapLayer() const
Chris@45 1970 {
Chris@45 1971 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 1972 if (!pane) return 0;
Chris@45 1973
Chris@45 1974 Layer *layer = pane->getSelectedLayer();
Chris@45 1975
Chris@45 1976 if (!dynamic_cast<TimeInstantLayer *>(layer) &&
Chris@45 1977 !dynamic_cast<TimeValueLayer *>(layer) &&
Chris@45 1978 !dynamic_cast<TimeRulerLayer *>(layer)) {
Chris@45 1979
Chris@45 1980 layer = 0;
Chris@45 1981
Chris@45 1982 for (int i = pane->getLayerCount(); i > 0; --i) {
Chris@45 1983 Layer *l = pane->getLayer(i-1);
Chris@45 1984 if (dynamic_cast<TimeRulerLayer *>(l)) {
Chris@45 1985 layer = l;
Chris@45 1986 break;
Chris@45 1987 }
Chris@45 1988 }
Chris@45 1989 }
Chris@45 1990
Chris@45 1991 return layer;
Chris@45 1992 }
Chris@45 1993
Chris@45 1994 void
Chris@45 1995 MainWindowBase::stop()
Chris@45 1996 {
Chris@45 1997 m_playSource->stop();
Chris@45 1998
Chris@45 1999 if (m_paneStack && m_paneStack->getCurrentPane()) {
Chris@45 2000 updateVisibleRangeDisplay(m_paneStack->getCurrentPane());
Chris@45 2001 } else {
Chris@45 2002 m_myStatusMessage = "";
Chris@45 2003 statusBar()->showMessage("");
Chris@45 2004 }
Chris@45 2005 }
Chris@45 2006
Chris@45 2007 MainWindowBase::AddPaneCommand::AddPaneCommand(MainWindowBase *mw) :
Chris@45 2008 m_mw(mw),
Chris@45 2009 m_pane(0),
Chris@45 2010 m_prevCurrentPane(0),
Chris@45 2011 m_added(false)
Chris@45 2012 {
Chris@45 2013 }
Chris@45 2014
Chris@45 2015 MainWindowBase::AddPaneCommand::~AddPaneCommand()
Chris@45 2016 {
Chris@45 2017 if (m_pane && !m_added) {
Chris@45 2018 m_mw->m_paneStack->deletePane(m_pane);
Chris@45 2019 }
Chris@45 2020 }
Chris@45 2021
Chris@45 2022 QString
Chris@45 2023 MainWindowBase::AddPaneCommand::getName() const
Chris@45 2024 {
Chris@45 2025 return tr("Add Pane");
Chris@45 2026 }
Chris@45 2027
Chris@45 2028 void
Chris@45 2029 MainWindowBase::AddPaneCommand::execute()
Chris@45 2030 {
Chris@45 2031 if (!m_pane) {
Chris@45 2032 m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane();
Chris@45 2033 m_pane = m_mw->m_paneStack->addPane();
Chris@45 2034
Chris@45 2035 connect(m_pane, SIGNAL(contextHelpChanged(const QString &)),
Chris@45 2036 m_mw, SLOT(contextHelpChanged(const QString &)));
Chris@45 2037 } else {
Chris@45 2038 m_mw->m_paneStack->showPane(m_pane);
Chris@45 2039 }
Chris@45 2040
Chris@45 2041 m_mw->m_paneStack->setCurrentPane(m_pane);
Chris@45 2042 m_added = true;
Chris@45 2043 }
Chris@45 2044
Chris@45 2045 void
Chris@45 2046 MainWindowBase::AddPaneCommand::unexecute()
Chris@45 2047 {
Chris@45 2048 m_mw->m_paneStack->hidePane(m_pane);
Chris@45 2049 m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane);
Chris@45 2050 m_added = false;
Chris@45 2051 }
Chris@45 2052
Chris@45 2053 MainWindowBase::RemovePaneCommand::RemovePaneCommand(MainWindowBase *mw, Pane *pane) :
Chris@45 2054 m_mw(mw),
Chris@45 2055 m_pane(pane),
Chris@45 2056 m_added(true)
Chris@45 2057 {
Chris@45 2058 }
Chris@45 2059
Chris@45 2060 MainWindowBase::RemovePaneCommand::~RemovePaneCommand()
Chris@45 2061 {
Chris@45 2062 if (m_pane && !m_added) {
Chris@45 2063 m_mw->m_paneStack->deletePane(m_pane);
Chris@45 2064 }
Chris@45 2065 }
Chris@45 2066
Chris@45 2067 QString
Chris@45 2068 MainWindowBase::RemovePaneCommand::getName() const
Chris@45 2069 {
Chris@45 2070 return tr("Remove Pane");
Chris@45 2071 }
Chris@45 2072
Chris@45 2073 void
Chris@45 2074 MainWindowBase::RemovePaneCommand::execute()
Chris@45 2075 {
Chris@45 2076 m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane();
Chris@45 2077 m_mw->m_paneStack->hidePane(m_pane);
Chris@45 2078 m_added = false;
Chris@45 2079 }
Chris@45 2080
Chris@45 2081 void
Chris@45 2082 MainWindowBase::RemovePaneCommand::unexecute()
Chris@45 2083 {
Chris@45 2084 m_mw->m_paneStack->showPane(m_pane);
Chris@45 2085 m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane);
Chris@45 2086 m_added = true;
Chris@45 2087 }
Chris@45 2088
Chris@45 2089 void
Chris@45 2090 MainWindowBase::deleteCurrentPane()
Chris@45 2091 {
Chris@45 2092 CommandHistory::getInstance()->startCompoundOperation
Chris@45 2093 (tr("Delete Pane"), true);
Chris@45 2094
Chris@45 2095 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 2096 if (pane) {
Chris@45 2097 while (pane->getLayerCount() > 0) {
Chris@45 2098 Layer *layer = pane->getLayer(0);
Chris@45 2099 if (layer) {
Chris@45 2100 m_document->removeLayerFromView(pane, layer);
Chris@45 2101 } else {
Chris@45 2102 break;
Chris@45 2103 }
Chris@45 2104 }
Chris@45 2105
Chris@45 2106 RemovePaneCommand *command = new RemovePaneCommand(this, pane);
Chris@45 2107 CommandHistory::getInstance()->addCommand(command);
Chris@45 2108 }
Chris@45 2109
Chris@45 2110 CommandHistory::getInstance()->endCompoundOperation();
Chris@45 2111
Chris@45 2112 updateMenuStates();
Chris@45 2113 }
Chris@45 2114
Chris@45 2115 void
Chris@45 2116 MainWindowBase::deleteCurrentLayer()
Chris@45 2117 {
Chris@45 2118 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 2119 if (pane) {
Chris@45 2120 Layer *layer = pane->getSelectedLayer();
Chris@45 2121 if (layer) {
Chris@45 2122 m_document->removeLayerFromView(pane, layer);
Chris@45 2123 }
Chris@45 2124 }
Chris@45 2125 updateMenuStates();
Chris@45 2126 }
Chris@45 2127
Chris@45 2128 void
Chris@123 2129 MainWindowBase::editCurrentLayer()
Chris@123 2130 {
Chris@123 2131 Layer *layer = 0;
Chris@123 2132 Pane *pane = m_paneStack->getCurrentPane();
Chris@123 2133 if (pane) layer = pane->getSelectedLayer();
Chris@123 2134 if (!layer) return;
Chris@123 2135
Chris@123 2136 Model *model = layer->getModel();
Chris@123 2137 if (!model) return;
Chris@123 2138
Chris@124 2139 TabularModel *tabular = dynamic_cast<TabularModel *>(model);
Chris@124 2140 if (!tabular) {
Chris@124 2141 //!!! how to prevent this function from being active if not
Chris@124 2142 //appropriate model type? or will we ultimately support
Chris@124 2143 //tabular display for all editable models?
Chris@124 2144 std::cerr << "NOTE: Not a tabular model" << std::endl;
Chris@124 2145 return;
Chris@124 2146 }
Chris@124 2147
Chris@123 2148 if (m_layerDataDialogMap.find(layer) != m_layerDataDialogMap.end()) {
Chris@126 2149 if (!m_layerDataDialogMap[layer].isNull()) {
Chris@126 2150 m_layerDataDialogMap[layer]->show();
Chris@126 2151 m_layerDataDialogMap[layer]->raise();
Chris@126 2152 return;
Chris@126 2153 }
Chris@123 2154 }
Chris@123 2155
Chris@125 2156 QString title = layer->getLayerPresentationName();
Chris@125 2157
Chris@125 2158 ModelDataTableDialog *dialog = new ModelDataTableDialog(tabular, title, this);
Chris@128 2159 dialog->setAttribute(Qt::WA_DeleteOnClose);
Chris@128 2160
Chris@128 2161 connectLayerEditDialog(dialog);
Chris@123 2162
Chris@128 2163 m_layerDataDialogMap[layer] = dialog;
Chris@128 2164 m_viewDataDialogMap[pane].insert(dialog);
Chris@128 2165
Chris@128 2166 dialog->show();
Chris@128 2167 }
Chris@128 2168
Chris@128 2169 void
Chris@128 2170 MainWindowBase::connectLayerEditDialog(ModelDataTableDialog *dialog)
Chris@128 2171 {
Chris@123 2172 connect(m_viewManager,
Chris@123 2173 SIGNAL(globalCentreFrameChanged(unsigned long)),
Chris@123 2174 dialog,
Chris@127 2175 SLOT(userScrolledToFrame(unsigned long)));
Chris@127 2176
Chris@127 2177 connect(m_viewManager,
Chris@127 2178 SIGNAL(playbackFrameChanged(unsigned long)),
Chris@127 2179 dialog,
Chris@127 2180 SLOT(playbackScrolledToFrame(unsigned long)));
Chris@127 2181
Chris@123 2182 connect(dialog,
Chris@123 2183 SIGNAL(scrollToFrame(unsigned long)),
Chris@123 2184 m_viewManager,
Chris@123 2185 SLOT(setGlobalCentreFrame(unsigned long)));
Chris@129 2186
Chris@129 2187 connect(dialog,
Chris@129 2188 SIGNAL(scrollToFrame(unsigned long)),
Chris@129 2189 m_viewManager,
Chris@129 2190 SLOT(setPlaybackFrame(unsigned long)));
Chris@128 2191 }
Chris@123 2192
Chris@123 2193 void
Chris@73 2194 MainWindowBase::previousPane()
Chris@73 2195 {
Chris@73 2196 if (!m_paneStack) return;
Chris@73 2197
Chris@73 2198 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@73 2199 if (!currentPane) return;
Chris@73 2200
Chris@73 2201 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@73 2202 if (m_paneStack->getPane(i) == currentPane) {
Chris@73 2203 if (i == 0) return;
Chris@73 2204 m_paneStack->setCurrentPane(m_paneStack->getPane(i-1));
Chris@73 2205 updateMenuStates();
Chris@73 2206 return;
Chris@73 2207 }
Chris@73 2208 }
Chris@73 2209 }
Chris@73 2210
Chris@73 2211 void
Chris@73 2212 MainWindowBase::nextPane()
Chris@73 2213 {
Chris@73 2214 if (!m_paneStack) return;
Chris@73 2215
Chris@73 2216 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@73 2217 if (!currentPane) return;
Chris@73 2218
Chris@73 2219 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@73 2220 if (m_paneStack->getPane(i) == currentPane) {
Chris@73 2221 if (i == m_paneStack->getPaneCount()-1) return;
Chris@73 2222 m_paneStack->setCurrentPane(m_paneStack->getPane(i+1));
Chris@73 2223 updateMenuStates();
Chris@73 2224 return;
Chris@73 2225 }
Chris@73 2226 }
Chris@73 2227 }
Chris@73 2228
Chris@73 2229 void
Chris@73 2230 MainWindowBase::previousLayer()
Chris@73 2231 {
Chris@73 2232 //!!! Not right -- pane lists layers in stacking order
Chris@73 2233
Chris@73 2234 if (!m_paneStack) return;
Chris@73 2235
Chris@73 2236 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@73 2237 if (!currentPane) return;
Chris@73 2238
Chris@73 2239 Layer *currentLayer = currentPane->getSelectedLayer();
Chris@73 2240 if (!currentLayer) return;
Chris@73 2241
Chris@73 2242 for (int i = 0; i < currentPane->getLayerCount(); ++i) {
Chris@73 2243 if (currentPane->getLayer(i) == currentLayer) {
Chris@73 2244 if (i == 0) return;
Chris@73 2245 m_paneStack->setCurrentLayer(currentPane,
Chris@73 2246 currentPane->getLayer(i-1));
Chris@73 2247 updateMenuStates();
Chris@73 2248 return;
Chris@73 2249 }
Chris@73 2250 }
Chris@73 2251 }
Chris@73 2252
Chris@73 2253 void
Chris@73 2254 MainWindowBase::nextLayer()
Chris@73 2255 {
Chris@73 2256 //!!! Not right -- pane lists layers in stacking order
Chris@73 2257
Chris@73 2258 if (!m_paneStack) return;
Chris@73 2259
Chris@73 2260 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@73 2261 if (!currentPane) return;
Chris@73 2262
Chris@73 2263 Layer *currentLayer = currentPane->getSelectedLayer();
Chris@73 2264 if (!currentLayer) return;
Chris@73 2265
Chris@73 2266 for (int i = 0; i < currentPane->getLayerCount(); ++i) {
Chris@73 2267 if (currentPane->getLayer(i) == currentLayer) {
Chris@73 2268 if (i == currentPane->getLayerCount()-1) return;
Chris@73 2269 m_paneStack->setCurrentLayer(currentPane,
Chris@73 2270 currentPane->getLayer(i+1));
Chris@73 2271 updateMenuStates();
Chris@73 2272 return;
Chris@73 2273 }
Chris@73 2274 }
Chris@73 2275 }
Chris@73 2276
Chris@73 2277 void
Chris@45 2278 MainWindowBase::playbackFrameChanged(unsigned long frame)
Chris@45 2279 {
Chris@45 2280 if (!(m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
Chris@45 2281
Chris@45 2282 RealTime now = RealTime::frame2RealTime
Chris@45 2283 (frame, getMainModel()->getSampleRate());
Chris@45 2284
Chris@45 2285 if (now.sec == m_lastPlayStatusSec) return;
Chris@45 2286
Chris@45 2287 RealTime then = RealTime::frame2RealTime
Chris@45 2288 (m_playSource->getPlayEndFrame(), getMainModel()->getSampleRate());
Chris@45 2289
Chris@45 2290 QString nowStr;
Chris@45 2291 QString thenStr;
Chris@45 2292 QString remainingStr;
Chris@45 2293
Chris@45 2294 if (then.sec > 10) {
Chris@45 2295 nowStr = now.toSecText().c_str();
Chris@45 2296 thenStr = then.toSecText().c_str();
Chris@45 2297 remainingStr = (then - now).toSecText().c_str();
Chris@45 2298 m_lastPlayStatusSec = now.sec;
Chris@45 2299 } else {
Chris@45 2300 nowStr = now.toText(true).c_str();
Chris@45 2301 thenStr = then.toText(true).c_str();
Chris@45 2302 remainingStr = (then - now).toText(true).c_str();
Chris@45 2303 }
Chris@45 2304
Chris@45 2305 m_myStatusMessage = tr("Playing: %1 of %2 (%3 remaining)")
Chris@45 2306 .arg(nowStr).arg(thenStr).arg(remainingStr);
Chris@45 2307
Chris@45 2308 statusBar()->showMessage(m_myStatusMessage);
Chris@45 2309 }
Chris@45 2310
Chris@45 2311 void
Chris@45 2312 MainWindowBase::globalCentreFrameChanged(unsigned long )
Chris@45 2313 {
Chris@45 2314 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
Chris@45 2315 Pane *p = 0;
Chris@45 2316 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
Chris@45 2317 if (!p->getFollowGlobalPan()) return;
Chris@45 2318 updateVisibleRangeDisplay(p);
Chris@45 2319 }
Chris@45 2320
Chris@45 2321 void
Chris@123 2322 MainWindowBase::viewCentreFrameChanged(View *v, unsigned long frame)
Chris@45 2323 {
Chris@130 2324 // std::cerr << "MainWindowBase::viewCentreFrameChanged(" << v << "," << frame << ")" << std::endl;
Chris@123 2325
Chris@123 2326 if (m_viewDataDialogMap.find(v) != m_viewDataDialogMap.end()) {
Chris@123 2327 for (DataDialogSet::iterator i = m_viewDataDialogMap[v].begin();
Chris@123 2328 i != m_viewDataDialogMap[v].end(); ++i) {
Chris@127 2329 (*i)->userScrolledToFrame(frame);
Chris@123 2330 }
Chris@123 2331 }
Chris@45 2332 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
Chris@45 2333 Pane *p = 0;
Chris@45 2334 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
Chris@45 2335 if (v == p) updateVisibleRangeDisplay(p);
Chris@45 2336 }
Chris@45 2337
Chris@45 2338 void
Chris@45 2339 MainWindowBase::viewZoomLevelChanged(View *v, unsigned long , bool )
Chris@45 2340 {
Chris@45 2341 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
Chris@45 2342 Pane *p = 0;
Chris@45 2343 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
Chris@45 2344 if (v == p) updateVisibleRangeDisplay(p);
Chris@45 2345 }
Chris@45 2346
Chris@45 2347 void
Chris@45 2348 MainWindowBase::layerAdded(Layer *)
Chris@45 2349 {
Chris@45 2350 // std::cerr << "MainWindowBase::layerAdded(" << layer << ")" << std::endl;
Chris@45 2351 updateMenuStates();
Chris@45 2352 }
Chris@45 2353
Chris@45 2354 void
Chris@45 2355 MainWindowBase::layerRemoved(Layer *)
Chris@45 2356 {
Chris@45 2357 // std::cerr << "MainWindowBase::layerRemoved(" << layer << ")" << std::endl;
Chris@45 2358 updateMenuStates();
Chris@45 2359 }
Chris@45 2360
Chris@45 2361 void
Chris@45 2362 MainWindowBase::layerAboutToBeDeleted(Layer *layer)
Chris@45 2363 {
Chris@132 2364 // std::cerr << "MainWindowBase::layerAboutToBeDeleted(" << layer << ")" << std::endl;
Chris@123 2365
Chris@128 2366 removeLayerEditDialog(layer);
Chris@123 2367
Chris@47 2368 if (m_timeRulerLayer && (layer == m_timeRulerLayer)) {
Chris@45 2369 // std::cerr << "(this is the time ruler layer)" << std::endl;
Chris@45 2370 m_timeRulerLayer = 0;
Chris@45 2371 }
Chris@45 2372 }
Chris@45 2373
Chris@45 2374 void
Chris@45 2375 MainWindowBase::layerInAView(Layer *layer, bool inAView)
Chris@45 2376 {
Chris@132 2377 // std::cerr << "MainWindowBase::layerInAView(" << layer << "," << inAView << ")" << std::endl;
Chris@128 2378
Chris@128 2379 if (!inAView) removeLayerEditDialog(layer);
Chris@45 2380
Chris@45 2381 // Check whether we need to add or remove model from play source
Chris@45 2382 Model *model = layer->getModel();
Chris@45 2383 if (model) {
Chris@45 2384 if (inAView) {
Chris@45 2385 m_playSource->addModel(model);
Chris@45 2386 } else {
Chris@45 2387 bool found = false;
Chris@45 2388 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@45 2389 Pane *pane = m_paneStack->getPane(i);
Chris@45 2390 if (!pane) continue;
Chris@45 2391 for (int j = 0; j < pane->getLayerCount(); ++j) {
Chris@45 2392 Layer *pl = pane->getLayer(j);
Chris@45 2393 if (pl && pl->getModel() == model) {
Chris@45 2394 found = true;
Chris@45 2395 break;
Chris@45 2396 }
Chris@45 2397 }
Chris@45 2398 if (found) break;
Chris@45 2399 }
Chris@45 2400 if (!found) m_playSource->removeModel(model);
Chris@45 2401 }
Chris@45 2402 }
Chris@45 2403
Chris@45 2404 updateMenuStates();
Chris@45 2405 }
Chris@45 2406
Chris@45 2407 void
Chris@128 2408 MainWindowBase::removeLayerEditDialog(Layer *layer)
Chris@128 2409 {
Chris@128 2410 if (m_layerDataDialogMap.find(layer) != m_layerDataDialogMap.end()) {
Chris@128 2411
Chris@128 2412 ModelDataTableDialog *dialog = m_layerDataDialogMap[layer];
Chris@128 2413
Chris@128 2414 for (ViewDataDialogMap::iterator vi = m_viewDataDialogMap.begin();
Chris@128 2415 vi != m_viewDataDialogMap.end(); ++vi) {
Chris@128 2416 vi->second.erase(dialog);
Chris@128 2417 }
Chris@128 2418
Chris@128 2419 m_layerDataDialogMap.erase(layer);
Chris@128 2420 delete dialog;
Chris@128 2421 }
Chris@128 2422 }
Chris@128 2423
Chris@128 2424 void
Chris@45 2425 MainWindowBase::modelAdded(Model *model)
Chris@45 2426 {
Chris@45 2427 // std::cerr << "MainWindowBase::modelAdded(" << model << ")" << std::endl;
Chris@45 2428 m_playSource->addModel(model);
Chris@45 2429 }
Chris@45 2430
Chris@45 2431 void
Chris@45 2432 MainWindowBase::mainModelChanged(WaveFileModel *model)
Chris@45 2433 {
Chris@45 2434 // std::cerr << "MainWindowBase::mainModelChanged(" << model << ")" << std::endl;
Chris@45 2435 updateDescriptionLabel();
Chris@45 2436 if (model) m_viewManager->setMainModelSampleRate(model->getSampleRate());
Chris@45 2437 if (model && !m_playTarget && m_audioOutput) createPlayTarget();
Chris@45 2438 }
Chris@45 2439
Chris@45 2440 void
Chris@45 2441 MainWindowBase::modelAboutToBeDeleted(Model *model)
Chris@45 2442 {
Chris@45 2443 // std::cerr << "MainWindowBase::modelAboutToBeDeleted(" << model << ")" << std::endl;
Chris@45 2444 if (model == m_viewManager->getPlaybackModel()) {
Chris@45 2445 m_viewManager->setPlaybackModel(0);
Chris@45 2446 }
Chris@45 2447 m_playSource->removeModel(model);
Chris@45 2448 FFTDataServer::modelAboutToBeDeleted(model);
Chris@45 2449 }
Chris@45 2450
Chris@45 2451 void
Chris@55 2452 MainWindowBase::paneDeleteButtonClicked(Pane *pane)
Chris@55 2453 {
Chris@55 2454 bool found = false;
Chris@55 2455 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@55 2456 if (m_paneStack->getPane(i) == pane) {
Chris@55 2457 found = true;
Chris@55 2458 break;
Chris@55 2459 }
Chris@55 2460 }
Chris@55 2461 if (!found) {
Chris@55 2462 std::cerr << "MainWindowBase::paneDeleteButtonClicked: Unknown pane "
Chris@55 2463 << pane << std::endl;
Chris@55 2464 return;
Chris@55 2465 }
Chris@55 2466
Chris@55 2467 CommandHistory::getInstance()->startCompoundOperation
Chris@55 2468 (tr("Delete Pane"), true);
Chris@55 2469
Chris@55 2470 while (pane->getLayerCount() > 0) {
Chris@55 2471 Layer *layer = pane->getLayer(0);
Chris@55 2472 if (layer) {
Chris@55 2473 m_document->removeLayerFromView(pane, layer);
Chris@55 2474 } else {
Chris@55 2475 break;
Chris@55 2476 }
Chris@55 2477 }
Chris@55 2478
Chris@55 2479 RemovePaneCommand *command = new RemovePaneCommand(this, pane);
Chris@55 2480 CommandHistory::getInstance()->addCommand(command);
Chris@55 2481
Chris@55 2482 CommandHistory::getInstance()->endCompoundOperation();
Chris@55 2483
Chris@55 2484 updateMenuStates();
Chris@55 2485 }
Chris@55 2486
Chris@55 2487 void
Chris@45 2488 MainWindowBase::pollOSC()
Chris@45 2489 {
Chris@45 2490 if (!m_oscQueue || m_oscQueue->isEmpty()) return;
Chris@45 2491 std::cerr << "MainWindowBase::pollOSC: have " << m_oscQueue->getMessagesAvailable() << " messages" << std::endl;
Chris@45 2492
Chris@45 2493 if (m_openingAudioFile) return;
Chris@45 2494
Chris@45 2495 OSCMessage message = m_oscQueue->readMessage();
Chris@45 2496
Chris@45 2497 if (message.getTarget() != 0) {
Chris@45 2498 return; //!!! for now -- this class is target 0, others not handled yet
Chris@45 2499 }
Chris@45 2500
Chris@45 2501 handleOSCMessage(message);
Chris@45 2502 }
Chris@45 2503
Chris@45 2504 void
Chris@45 2505 MainWindowBase::inProgressSelectionChanged()
Chris@45 2506 {
Chris@45 2507 Pane *currentPane = 0;
Chris@45 2508 if (m_paneStack) currentPane = m_paneStack->getCurrentPane();
Chris@45 2509 if (currentPane) updateVisibleRangeDisplay(currentPane);
Chris@45 2510 }
Chris@45 2511
Chris@45 2512 void
Chris@45 2513 MainWindowBase::contextHelpChanged(const QString &s)
Chris@45 2514 {
Chris@45 2515 if (s == "" && m_myStatusMessage != "") {
Chris@45 2516 statusBar()->showMessage(m_myStatusMessage);
Chris@45 2517 return;
Chris@45 2518 }
Chris@45 2519 statusBar()->showMessage(s);
Chris@45 2520 }
Chris@45 2521
Chris@45 2522 void
Chris@45 2523 MainWindowBase::openHelpUrl(QString url)
Chris@45 2524 {
Chris@45 2525 // This method mostly lifted from Qt Assistant source code
Chris@45 2526
Chris@45 2527 QProcess *process = new QProcess(this);
Chris@45 2528 connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater()));
Chris@45 2529
Chris@45 2530 QStringList args;
Chris@45 2531
Chris@45 2532 #ifdef Q_OS_MAC
Chris@45 2533 args.append(url);
Chris@45 2534 process->start("open", args);
Chris@45 2535 #else
Chris@45 2536 #ifdef Q_OS_WIN32
Chris@45 2537
Chris@45 2538 QString pf(getenv("ProgramFiles"));
Chris@45 2539 QString command = pf + QString("\\Internet Explorer\\IEXPLORE.EXE");
Chris@45 2540
Chris@45 2541 args.append(url);
Chris@45 2542 process->start(command, args);
Chris@45 2543
Chris@45 2544 #else
Chris@45 2545 #ifdef Q_WS_X11
Chris@45 2546 if (!qgetenv("KDE_FULL_SESSION").isEmpty()) {
Chris@45 2547 args.append("exec");
Chris@45 2548 args.append(url);
Chris@45 2549 process->start("kfmclient", args);
Chris@45 2550 } else if (!qgetenv("BROWSER").isEmpty()) {
Chris@45 2551 args.append(url);
Chris@45 2552 process->start(qgetenv("BROWSER"), args);
Chris@45 2553 } else {
Chris@45 2554 args.append(url);
Chris@45 2555 process->start("firefox", args);
Chris@45 2556 }
Chris@45 2557 #endif
Chris@45 2558 #endif
Chris@45 2559 #endif
Chris@45 2560 }
Chris@45 2561