annotate framework/MainWindowBase.cpp @ 256:f3f9e3d647c1

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