annotate framework/MainWindowBase.cpp @ 332:151b7c5864e3 tonioni

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