annotate framework/MainWindowBase.cpp @ 342:4eccff14b4d8 tonioni

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