annotate main/MainWindow.cpp @ 193:4e030ebb6b36

* Make it possible to drop audio files, layer files, session files and images onto SV panes. Need to do a bit more work on where we expect the dropped file to go, particularly in the case of audio files -- at the moment they're always opened in new panes, but it may be better to by default replace whatever is in the target pane.
author Chris Cannam
date Wed, 10 Oct 2007 15:18:02 +0000
parents d3477f673fb4
children c851c49c79fe
rev   line source
Chris@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@0 4 Sonic Visualiser
Chris@0 5 An audio file viewer and annotation editor.
Chris@0 6 Centre for Digital Music, Queen Mary, University of London.
Chris@77 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@0 8
Chris@0 9 This program is free software; you can redistribute it and/or
Chris@0 10 modify it under the terms of the GNU General Public License as
Chris@0 11 published by the Free Software Foundation; either version 2 of the
Chris@0 12 License, or (at your option) any later version. See the file
Chris@0 13 COPYING included with this distribution for more information.
Chris@0 14 */
Chris@0 15
Chris@144 16 #include "../version.h"
Chris@0 17
Chris@0 18 #include "MainWindow.h"
Chris@1 19 #include "document/Document.h"
Chris@0 20 #include "PreferencesDialog.h"
Chris@0 21
Chris@1 22 #include "view/Pane.h"
Chris@1 23 #include "view/PaneStack.h"
Chris@1 24 #include "data/model/WaveFileModel.h"
Chris@1 25 #include "data/model/SparseOneDimensionalModel.h"
Chris@185 26 #include "data/model/NoteModel.h"
Chris@189 27 #include "data/model/Labeller.h"
Chris@1 28 #include "view/ViewManager.h"
Chris@0 29 #include "base/Preferences.h"
Chris@0 30 #include "layer/WaveformLayer.h"
Chris@0 31 #include "layer/TimeRulerLayer.h"
Chris@0 32 #include "layer/TimeInstantLayer.h"
Chris@0 33 #include "layer/TimeValueLayer.h"
Chris@0 34 #include "layer/Colour3DPlotLayer.h"
Chris@95 35 #include "layer/SliceLayer.h"
Chris@95 36 #include "layer/SliceableLayer.h"
Chris@193 37 #include "layer/ImageLayer.h"
Chris@0 38 #include "widgets/Fader.h"
Chris@65 39 #include "view/Overview.h"
Chris@0 40 #include "widgets/PropertyBox.h"
Chris@0 41 #include "widgets/PropertyStack.h"
Chris@0 42 #include "widgets/AudioDial.h"
Chris@168 43 #include "widgets/IconLoader.h"
Chris@0 44 #include "widgets/LayerTree.h"
Chris@0 45 #include "widgets/ListInputDialog.h"
Chris@36 46 #include "widgets/SubdividingMenu.h"
Chris@90 47 #include "widgets/NotifyingPushButton.h"
Chris@162 48 #include "widgets/KeyReference.h"
Chris@192 49 #include "widgets/LabelCounterInputDialog.h"
Chris@0 50 #include "audioio/AudioCallbackPlaySource.h"
Chris@0 51 #include "audioio/AudioCallbackPlayTarget.h"
Chris@0 52 #include "audioio/AudioTargetFactory.h"
Chris@59 53 #include "audioio/PlaySpeedRangeMapper.h"
Chris@1 54 #include "data/fileio/DataFileReaderFactory.h"
Chris@180 55 #include "data/fileio/PlaylistFileReader.h"
Chris@1 56 #include "data/fileio/WavFileWriter.h"
Chris@1 57 #include "data/fileio/CSVFileWriter.h"
Chris@185 58 #include "data/fileio/MIDIFileWriter.h"
Chris@1 59 #include "data/fileio/BZipFileDevice.h"
Chris@85 60 #include "data/fileio/RemoteFile.h"
Chris@91 61 #include "data/fft/FFTDataServer.h"
Chris@1 62 #include "base/RecentFiles.h"
Chris@0 63 #include "transform/TransformFactory.h"
Chris@0 64 #include "base/PlayParameterRepository.h"
Chris@0 65 #include "base/XmlExportable.h"
Chris@0 66 #include "base/CommandHistory.h"
Chris@0 67 #include "base/Profiler.h"
Chris@0 68 #include "base/Clipboard.h"
Chris@165 69 #include "base/UnitDatabase.h"
Chris@165 70 #include "base/ColourDatabase.h"
Chris@69 71 #include "osc/OSCQueue.h"
Chris@0 72
Chris@180 73 //!!!
Chris@180 74 #include "data/model/AggregateWaveModel.h"
Chris@180 75
Chris@0 76 // For version information
Chris@0 77 #include "vamp/vamp.h"
Chris@0 78 #include "vamp-sdk/PluginBase.h"
Chris@0 79 #include "plugin/api/ladspa.h"
Chris@0 80 #include "plugin/api/dssi.h"
Chris@0 81
Chris@0 82 #include <QApplication>
Chris@0 83 #include <QMessageBox>
Chris@0 84 #include <QGridLayout>
Chris@0 85 #include <QLabel>
Chris@0 86 #include <QAction>
Chris@0 87 #include <QMenuBar>
Chris@0 88 #include <QToolBar>
Chris@0 89 #include <QInputDialog>
Chris@0 90 #include <QStatusBar>
Chris@0 91 #include <QTreeView>
Chris@0 92 #include <QFile>
Chris@88 93 #include <QFileInfo>
Chris@88 94 #include <QDir>
Chris@0 95 #include <QTextStream>
Chris@0 96 #include <QProcess>
Chris@7 97 #include <QShortcut>
Chris@5 98 #include <QSettings>
Chris@11 99 #include <QDateTime>
Chris@11 100 #include <QProcess>
Chris@16 101 #include <QCheckBox>
Chris@55 102 #include <QRegExp>
Chris@158 103 #include <QScrollArea>
Chris@0 104
Chris@0 105 #include <iostream>
Chris@0 106 #include <cstdio>
Chris@0 107 #include <errno.h>
Chris@0 108
Chris@0 109 using std::cerr;
Chris@0 110 using std::endl;
Chris@0 111
Chris@33 112 using std::vector;
Chris@33 113 using std::map;
Chris@33 114 using std::set;
Chris@33 115
Chris@0 116
Chris@70 117 MainWindow::MainWindow(bool withAudioOutput, bool withOSCSupport) :
Chris@0 118 m_document(0),
Chris@0 119 m_paneStack(0),
Chris@0 120 m_viewManager(0),
Chris@65 121 m_overview(0),
Chris@0 122 m_timeRulerLayer(0),
Chris@46 123 m_audioOutput(withAudioOutput),
Chris@0 124 m_playSource(0),
Chris@0 125 m_playTarget(0),
Chris@70 126 m_oscQueue(withOSCSupport ? new OSCQueue() : 0),
Chris@81 127 m_recentFiles("RecentFiles", 20),
Chris@49 128 m_recentTransforms("RecentTransforms", 20),
Chris@0 129 m_mainMenusCreated(false),
Chris@0 130 m_paneMenu(0),
Chris@0 131 m_layerMenu(0),
Chris@34 132 m_transformsMenu(0),
Chris@155 133 m_playbackMenu(0),
Chris@0 134 m_existingLayersMenu(0),
Chris@95 135 m_sliceMenu(0),
Chris@34 136 m_recentFilesMenu(0),
Chris@34 137 m_recentTransformsMenu(0),
Chris@0 138 m_rightButtonMenu(0),
Chris@0 139 m_rightButtonLayerMenu(0),
Chris@34 140 m_rightButtonTransformsMenu(0),
Chris@155 141 m_rightButtonPlaybackMenu(0),
Chris@155 142 m_ffwdAction(0),
Chris@155 143 m_rwdAction(0),
Chris@0 144 m_documentModified(false),
Chris@70 145 m_openingAudioFile(false),
Chris@70 146 m_abandoning(false),
Chris@189 147 m_labeller(0),
Chris@162 148 m_preferencesDialog(0),
Chris@177 149 m_layerTreeView(0),
Chris@162 150 m_keyReference(new KeyReference())
Chris@0 151 {
Chris@0 152 setWindowTitle(tr("Sonic Visualiser"));
Chris@0 153
Chris@165 154 UnitDatabase *udb = UnitDatabase::getInstance();
Chris@165 155 udb->registerUnit("Hz");
Chris@165 156 udb->registerUnit("dB");
Chris@165 157 udb->registerUnit("s");
Chris@165 158
Chris@165 159 ColourDatabase *cdb = ColourDatabase::getInstance();
Chris@165 160 cdb->addColour(Qt::black, tr("Black"));
Chris@165 161 cdb->addColour(Qt::darkRed, tr("Red"));
Chris@165 162 cdb->addColour(Qt::darkBlue, tr("Blue"));
Chris@165 163 cdb->addColour(Qt::darkGreen, tr("Green"));
Chris@165 164 cdb->addColour(QColor(200, 50, 255), tr("Purple"));
Chris@165 165 cdb->addColour(QColor(255, 150, 50), tr("Orange"));
Chris@166 166 cdb->setUseDarkBackground(cdb->addColour(Qt::white, tr("White")), true);
Chris@166 167 cdb->setUseDarkBackground(cdb->addColour(Qt::red, tr("Bright Red")), true);
Chris@166 168 cdb->setUseDarkBackground(cdb->addColour(QColor(30, 150, 255), tr("Bright Blue")), true);
Chris@166 169 cdb->setUseDarkBackground(cdb->addColour(Qt::green, tr("Bright Green")), true);
Chris@166 170 cdb->setUseDarkBackground(cdb->addColour(QColor(225, 74, 255), tr("Bright Purple")), true);
Chris@166 171 cdb->setUseDarkBackground(cdb->addColour(QColor(255, 188, 80), tr("Bright Orange")), true);
Chris@0 172
Chris@0 173 connect(CommandHistory::getInstance(), SIGNAL(commandExecuted()),
Chris@0 174 this, SLOT(documentModified()));
Chris@0 175 connect(CommandHistory::getInstance(), SIGNAL(documentRestored()),
Chris@0 176 this, SLOT(documentRestored()));
Chris@0 177
Chris@0 178 QFrame *frame = new QFrame;
Chris@0 179 setCentralWidget(frame);
Chris@0 180
Chris@0 181 QGridLayout *layout = new QGridLayout;
Chris@0 182
Chris@0 183 m_viewManager = new ViewManager();
Chris@0 184 connect(m_viewManager, SIGNAL(selectionChanged()),
Chris@0 185 this, SLOT(updateMenuStates()));
Chris@117 186 connect(m_viewManager, SIGNAL(inProgressSelectionChanged()),
Chris@117 187 this, SLOT(inProgressSelectionChanged()));
Chris@0 188
Chris@180 189 Preferences::BackgroundMode mode =
Chris@180 190 Preferences::getInstance()->getBackgroundMode();
Chris@180 191 m_initialDarkBackground = m_viewManager->getGlobalDarkBackground();
Chris@180 192 if (mode != Preferences::BackgroundFromTheme) {
Chris@180 193 m_viewManager->setGlobalDarkBackground
Chris@180 194 (mode == Preferences::DarkBackground);
Chris@180 195 }
Chris@180 196
Chris@0 197 m_descriptionLabel = new QLabel;
Chris@0 198
Chris@158 199 QScrollArea *scroll = new QScrollArea(frame);
Chris@158 200 scroll->setWidgetResizable(true);
Chris@158 201 scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
Chris@159 202 scroll->setFrameShape(QFrame::NoFrame);
Chris@159 203
Chris@159 204 m_paneStack = new PaneStack(scroll, m_viewManager);
Chris@0 205 connect(m_paneStack, SIGNAL(currentPaneChanged(Pane *)),
Chris@0 206 this, SLOT(currentPaneChanged(Pane *)));
Chris@0 207 connect(m_paneStack, SIGNAL(currentLayerChanged(Pane *, Layer *)),
Chris@0 208 this, SLOT(currentLayerChanged(Pane *, Layer *)));
Chris@0 209 connect(m_paneStack, SIGNAL(rightButtonMenuRequested(Pane *, QPoint)),
Chris@0 210 this, SLOT(rightButtonMenuRequested(Pane *, QPoint)));
Chris@73 211 connect(m_paneStack, SIGNAL(propertyStacksResized()),
Chris@73 212 this, SLOT(propertyStacksResized()));
Chris@90 213 connect(m_paneStack, SIGNAL(contextHelpChanged(const QString &)),
Chris@116 214 this, SLOT(contextHelpChanged(const QString &)));
Chris@193 215 connect(m_paneStack, SIGNAL(dropAccepted(Pane *, QStringList)),
Chris@193 216 this, SLOT(paneDropAccepted(Pane *, QStringList)));
Chris@193 217 connect(m_paneStack, SIGNAL(dropAccepted(Pane *, QString)),
Chris@193 218 this, SLOT(paneDropAccepted(Pane *, QString)));
Chris@0 219
Chris@159 220 scroll->setWidget(m_paneStack);
Chris@159 221
Chris@65 222 m_overview = new Overview(frame);
Chris@65 223 m_overview->setViewManager(m_viewManager);
Chris@65 224 m_overview->setFixedHeight(40);
Chris@144 225 #ifndef _WIN32
Chris@144 226 // For some reason, the contents of the overview never appear if we
Chris@144 227 // make this setting on Windows. I have no inclination at the moment
Chris@144 228 // to track down the reason why.
Chris@129 229 m_overview->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
Chris@144 230 #endif
Chris@90 231 connect(m_overview, SIGNAL(contextHelpChanged(const QString &)),
Chris@116 232 this, SLOT(contextHelpChanged(const QString &)));
Chris@0 233
Chris@0 234 m_panLayer = new WaveformLayer;
Chris@0 235 m_panLayer->setChannelMode(WaveformLayer::MergeChannels);
Chris@0 236 m_panLayer->setAggressiveCacheing(true);
Chris@65 237 m_overview->addLayer(m_panLayer);
Chris@174 238
Chris@174 239 if (m_viewManager->getGlobalDarkBackground()) {
Chris@174 240 m_panLayer->setBaseColour
Chris@174 241 (ColourDatabase::getInstance()->getColourIndex(tr("Bright Green")));
Chris@174 242 } else {
Chris@174 243 m_panLayer->setBaseColour
Chris@174 244 (ColourDatabase::getInstance()->getColourIndex(tr("Green")));
Chris@174 245 }
Chris@0 246
Chris@0 247 m_playSource = new AudioCallbackPlaySource(m_viewManager);
Chris@0 248
Chris@0 249 connect(m_playSource, SIGNAL(sampleRateMismatch(size_t, size_t, bool)),
Chris@0 250 this, SLOT(sampleRateMismatch(size_t, size_t, bool)));
Chris@42 251 connect(m_playSource, SIGNAL(audioOverloadPluginDisabled()),
Chris@42 252 this, SLOT(audioOverloadPluginDisabled()));
Chris@0 253
Chris@0 254 m_fader = new Fader(frame, false);
Chris@90 255 connect(m_fader, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget()));
Chris@90 256 connect(m_fader, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget()));
Chris@0 257
Chris@0 258 m_playSpeed = new AudioDial(frame);
Chris@12 259 m_playSpeed->setMinimum(0);
Chris@48 260 m_playSpeed->setMaximum(200);
Chris@25 261 m_playSpeed->setValue(100);
Chris@0 262 m_playSpeed->setFixedWidth(24);
Chris@0 263 m_playSpeed->setFixedHeight(24);
Chris@0 264 m_playSpeed->setNotchesVisible(true);
Chris@25 265 m_playSpeed->setPageStep(10);
Chris@60 266 m_playSpeed->setObjectName(tr("Playback Speedup"));
Chris@25 267 m_playSpeed->setDefaultValue(100);
Chris@59 268 m_playSpeed->setRangeMapper(new PlaySpeedRangeMapper(0, 200));
Chris@60 269 m_playSpeed->setShowToolTip(true);
Chris@0 270 connect(m_playSpeed, SIGNAL(valueChanged(int)),
Chris@0 271 this, SLOT(playSpeedChanged(int)));
Chris@90 272 connect(m_playSpeed, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget()));
Chris@90 273 connect(m_playSpeed, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget()));
Chris@90 274
Chris@168 275 IconLoader il;
Chris@168 276
Chris@90 277 m_playSharpen = new NotifyingPushButton(frame);
Chris@17 278 m_playSharpen->setToolTip(tr("Sharpen percussive transients"));
Chris@26 279 m_playSharpen->setFixedSize(20, 20);
Chris@16 280 m_playSharpen->setEnabled(false);
Chris@26 281 m_playSharpen->setCheckable(true);
Chris@26 282 m_playSharpen->setChecked(false);
Chris@168 283 m_playSharpen->setIcon(il.load("sharpen"));
Chris@26 284 connect(m_playSharpen, SIGNAL(clicked()), this, SLOT(playSharpenToggled()));
Chris@90 285 connect(m_playSharpen, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget()));
Chris@90 286 connect(m_playSharpen, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget()));
Chris@90 287
Chris@90 288 m_playMono = new NotifyingPushButton(frame);
Chris@26 289 m_playMono->setToolTip(tr("Run time stretcher in mono only"));
Chris@26 290 m_playMono->setFixedSize(20, 20);
Chris@26 291 m_playMono->setEnabled(false);
Chris@26 292 m_playMono->setCheckable(true);
Chris@26 293 m_playMono->setChecked(false);
Chris@168 294 m_playMono->setIcon(il.load("mono"));
Chris@26 295 connect(m_playMono, SIGNAL(clicked()), this, SLOT(playMonoToggled()));
Chris@90 296 connect(m_playMono, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget()));
Chris@90 297 connect(m_playMono, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget()));
Chris@21 298
Chris@21 299 QSettings settings;
Chris@21 300 settings.beginGroup("MainWindow");
Chris@24 301 m_playSharpen->setChecked(settings.value("playsharpen", true).toBool());
Chris@26 302 m_playMono->setChecked(settings.value("playmono", false).toBool());
Chris@21 303 settings.endGroup();
Chris@21 304
Chris@129 305 layout->setSpacing(4);
Chris@159 306 layout->addWidget(scroll, 0, 0, 1, 5);
Chris@65 307 layout->addWidget(m_overview, 1, 0);
Chris@0 308 layout->addWidget(m_fader, 1, 1);
Chris@0 309 layout->addWidget(m_playSpeed, 1, 2);
Chris@16 310 layout->addWidget(m_playSharpen, 1, 3);
Chris@26 311 layout->addWidget(m_playMono, 1, 4);
Chris@16 312
Chris@129 313 m_paneStack->setPropertyStackMinWidth
Chris@129 314 (m_fader->width() + m_playSpeed->width() + m_playSharpen->width() +
Chris@129 315 m_playMono->width() + layout->spacing() * 4);
Chris@129 316
Chris@16 317 layout->setColumnStretch(0, 10);
Chris@16 318
Chris@0 319 frame->setLayout(layout);
Chris@0 320
Chris@0 321 connect(m_viewManager, SIGNAL(outputLevelsChanged(float, float)),
Chris@0 322 this, SLOT(outputLevelsChanged(float, float)));
Chris@0 323
Chris@116 324 connect(m_viewManager, SIGNAL(playbackFrameChanged(unsigned long)),
Chris@116 325 this, SLOT(playbackFrameChanged(unsigned long)));
Chris@116 326
Chris@116 327 connect(m_viewManager, SIGNAL(globalCentreFrameChanged(unsigned long)),
Chris@116 328 this, SLOT(globalCentreFrameChanged(unsigned long)));
Chris@116 329
Chris@116 330 connect(m_viewManager, SIGNAL(viewCentreFrameChanged(View *, unsigned long)),
Chris@116 331 this, SLOT(viewCentreFrameChanged(View *, unsigned long)));
Chris@116 332
Chris@116 333 connect(m_viewManager, SIGNAL(viewZoomLevelChanged(View *, unsigned long, bool)),
Chris@116 334 this, SLOT(viewZoomLevelChanged(View *, unsigned long, bool)));
Chris@116 335
Chris@0 336 connect(Preferences::getInstance(),
Chris@0 337 SIGNAL(propertyChanged(PropertyContainer::PropertyName)),
Chris@0 338 this,
Chris@0 339 SLOT(preferenceChanged(PropertyContainer::PropertyName)));
Chris@0 340
Chris@98 341 // preferenceChanged("Property Box Layout");
Chris@98 342
Chris@70 343 if (m_oscQueue && m_oscQueue->isOK()) {
Chris@69 344 connect(m_oscQueue, SIGNAL(messagesAvailable()), this, SLOT(pollOSC()));
Chris@69 345 QTimer *oscTimer = new QTimer(this);
Chris@69 346 connect(oscTimer, SIGNAL(timeout()), this, SLOT(pollOSC()));
Chris@69 347 oscTimer->start(1000);
Chris@69 348 }
Chris@69 349
Chris@189 350 Labeller::ValueType labellerType = Labeller::ValueFromTwoLevelCounter;
Chris@189 351 settings.beginGroup("MainWindow");
Chris@189 352 labellerType = (Labeller::ValueType)
Chris@189 353 settings.value("labellertype", (int)labellerType).toInt();
Chris@189 354 int cycle = settings.value("labellercycle", 4).toInt();
Chris@189 355 settings.endGroup();
Chris@189 356
Chris@189 357 m_labeller = new Labeller(labellerType);
Chris@189 358 m_labeller->setCounterCycleSize(cycle);
Chris@189 359
Chris@0 360 setupMenus();
Chris@0 361 setupToolbars();
Chris@155 362 setupHelpMenu();
Chris@0 363
Chris@90 364 statusBar();
Chris@0 365
Chris@0 366 newSession();
Chris@0 367 }
Chris@0 368
Chris@0 369 MainWindow::~MainWindow()
Chris@0 370 {
Chris@137 371 // std::cerr << "MainWindow::~MainWindow()" << std::endl;
Chris@118 372
Chris@70 373 if (!m_abandoning) {
Chris@70 374 closeSession();
Chris@70 375 }
Chris@0 376 delete m_playTarget;
Chris@0 377 delete m_playSource;
Chris@0 378 delete m_viewManager;
Chris@69 379 delete m_oscQueue;
Chris@162 380 delete m_keyReference;
Chris@163 381 delete m_preferencesDialog;
Chris@177 382 delete m_layerTreeView;
Chris@0 383 Profiles::getInstance()->dump();
Chris@0 384 }
Chris@0 385
Chris@81 386 QString
Chris@88 387 MainWindow::getOpenFileName(FileFinder::FileType type)
Chris@81 388 {
Chris@88 389 FileFinder *ff = FileFinder::getInstance();
Chris@81 390 switch (type) {
Chris@88 391 case FileFinder::SessionFile:
Chris@88 392 return ff->getOpenFileName(type, m_sessionFile);
Chris@88 393 case FileFinder::AudioFile:
Chris@88 394 return ff->getOpenFileName(type, m_audioFile);
Chris@88 395 case FileFinder::LayerFile:
Chris@88 396 return ff->getOpenFileName(type, m_sessionFile);
Chris@185 397 case FileFinder::LayerFileNoMidi:
Chris@185 398 return ff->getOpenFileName(type, m_sessionFile);
Chris@88 399 case FileFinder::SessionOrAudioFile:
Chris@88 400 return ff->getOpenFileName(type, m_sessionFile);
Chris@121 401 case FileFinder::ImageFile:
Chris@121 402 return ff->getOpenFileName(type, m_sessionFile);
Chris@88 403 case FileFinder::AnyFile:
Chris@88 404 if (getMainModel() != 0 &&
Chris@88 405 m_paneStack != 0 &&
Chris@88 406 m_paneStack->getCurrentPane() != 0) { // can import a layer
Chris@88 407 return ff->getOpenFileName(FileFinder::AnyFile, m_sessionFile);
Chris@81 408 } else {
Chris@88 409 return ff->getOpenFileName(FileFinder::SessionOrAudioFile,
Chris@88 410 m_sessionFile);
Chris@81 411 }
Chris@81 412 }
Chris@88 413 return "";
Chris@88 414 }
Chris@88 415
Chris@88 416 QString
Chris@88 417 MainWindow::getSaveFileName(FileFinder::FileType type)
Chris@88 418 {
Chris@88 419 FileFinder *ff = FileFinder::getInstance();
Chris@88 420 switch (type) {
Chris@88 421 case FileFinder::SessionFile:
Chris@88 422 return ff->getSaveFileName(type, m_sessionFile);
Chris@88 423 case FileFinder::AudioFile:
Chris@88 424 return ff->getSaveFileName(type, m_audioFile);
Chris@88 425 case FileFinder::LayerFile:
Chris@88 426 return ff->getSaveFileName(type, m_sessionFile);
Chris@185 427 case FileFinder::LayerFileNoMidi:
Chris@185 428 return ff->getSaveFileName(type, m_sessionFile);
Chris@88 429 case FileFinder::SessionOrAudioFile:
Chris@88 430 return ff->getSaveFileName(type, m_sessionFile);
Chris@121 431 case FileFinder::ImageFile:
Chris@121 432 return ff->getSaveFileName(type, m_sessionFile);
Chris@88 433 case FileFinder::AnyFile:
Chris@88 434 return ff->getSaveFileName(type, m_sessionFile);
Chris@81 435 }
Chris@88 436 return "";
Chris@81 437 }
Chris@81 438
Chris@88 439 void
Chris@88 440 MainWindow::registerLastOpenedFilePath(FileFinder::FileType type, QString path)
Chris@81 441 {
Chris@88 442 FileFinder *ff = FileFinder::getInstance();
Chris@88 443 ff->registerLastOpenedFilePath(type, path);
Chris@81 444 }
Chris@81 445
Chris@81 446 void
Chris@0 447 MainWindow::setupMenus()
Chris@0 448 {
Chris@0 449 if (!m_mainMenusCreated) {
Chris@0 450 m_rightButtonMenu = new QMenu();
Chris@104 451
Chris@104 452 // No -- we don't want tear-off enabled on the right-button
Chris@104 453 // menu. If it is enabled, then simply right-clicking and
Chris@104 454 // releasing will pop up the menu, activate the tear-off, and
Chris@104 455 // leave the torn-off menu window in front of the main window.
Chris@104 456 // That isn't desirable. I'm not sure it ever would be, in a
Chris@104 457 // context menu -- perhaps technically a Qt bug?
Chris@104 458 // m_rightButtonMenu->setTearOffEnabled(true);
Chris@0 459 }
Chris@0 460
Chris@0 461 if (m_rightButtonLayerMenu) {
Chris@0 462 m_rightButtonLayerMenu->clear();
Chris@0 463 } else {
Chris@0 464 m_rightButtonLayerMenu = m_rightButtonMenu->addMenu(tr("&Layer"));
Chris@97 465 m_rightButtonLayerMenu->setTearOffEnabled(true);
Chris@0 466 m_rightButtonMenu->addSeparator();
Chris@0 467 }
Chris@0 468
Chris@34 469 if (m_rightButtonTransformsMenu) {
Chris@34 470 m_rightButtonTransformsMenu->clear();
Chris@34 471 } else {
Chris@34 472 m_rightButtonTransformsMenu = m_rightButtonMenu->addMenu(tr("&Transform"));
Chris@97 473 m_rightButtonTransformsMenu->setTearOffEnabled(true);
Chris@34 474 m_rightButtonMenu->addSeparator();
Chris@34 475 }
Chris@34 476
Chris@0 477 if (!m_mainMenusCreated) {
Chris@0 478 CommandHistory::getInstance()->registerMenu(m_rightButtonMenu);
Chris@0 479 m_rightButtonMenu->addSeparator();
Chris@66 480 }
Chris@66 481
Chris@66 482 setupFileMenu();
Chris@66 483 setupEditMenu();
Chris@66 484 setupViewMenu();
Chris@66 485 setupPaneAndLayerMenus();
Chris@66 486 setupTransformsMenu();
Chris@66 487
Chris@66 488 m_mainMenusCreated = true;
Chris@66 489 }
Chris@66 490
Chris@66 491 void
Chris@66 492 MainWindow::setupFileMenu()
Chris@66 493 {
Chris@66 494 if (m_mainMenusCreated) return;
Chris@66 495
Chris@66 496 QMenu *menu = menuBar()->addMenu(tr("&File"));
Chris@97 497 menu->setTearOffEnabled(true);
Chris@66 498 QToolBar *toolbar = addToolBar(tr("File Toolbar"));
Chris@66 499
Chris@162 500 m_keyReference->setCategory(tr("File and Session Management"));
Chris@162 501
Chris@168 502 IconLoader il;
Chris@168 503
Chris@168 504 QIcon icon = il.load("filenew");
Chris@168 505 icon.addPixmap(il.loadPixmap("filenew-22"));
Chris@66 506 QAction *action = new QAction(icon, tr("&New Session"), this);
Chris@66 507 action->setShortcut(tr("Ctrl+N"));
Chris@90 508 action->setStatusTip(tr("Abandon the current Sonic Visualiser session and start a new one"));
Chris@66 509 connect(action, SIGNAL(triggered()), this, SLOT(newSession()));
Chris@162 510 m_keyReference->registerShortcut(action);
Chris@66 511 menu->addAction(action);
Chris@66 512 toolbar->addAction(action);
Chris@138 513
Chris@168 514 icon = il.load("fileopensession");
Chris@66 515 action = new QAction(icon, tr("&Open Session..."), this);
Chris@66 516 action->setShortcut(tr("Ctrl+O"));
Chris@66 517 action->setStatusTip(tr("Open a previously saved Sonic Visualiser session file"));
Chris@66 518 connect(action, SIGNAL(triggered()), this, SLOT(openSession()));
Chris@162 519 m_keyReference->registerShortcut(action);
Chris@66 520 menu->addAction(action);
Chris@66 521
Chris@168 522 icon = il.load("fileopen");
Chris@168 523 icon.addPixmap(il.loadPixmap("fileopen-22"));
Chris@138 524
Chris@66 525 action = new QAction(icon, tr("&Open..."), this);
Chris@66 526 action->setStatusTip(tr("Open a session file, audio file, or layer"));
Chris@66 527 connect(action, SIGNAL(triggered()), this, SLOT(openSomething()));
Chris@66 528 toolbar->addAction(action);
Chris@66 529
Chris@168 530 icon = il.load("filesave");
Chris@168 531 icon.addPixmap(il.loadPixmap("filesave-22"));
Chris@66 532 action = new QAction(icon, tr("&Save Session"), this);
Chris@66 533 action->setShortcut(tr("Ctrl+S"));
Chris@66 534 action->setStatusTip(tr("Save the current session into a Sonic Visualiser session file"));
Chris@66 535 connect(action, SIGNAL(triggered()), this, SLOT(saveSession()));
Chris@66 536 connect(this, SIGNAL(canSave(bool)), action, SLOT(setEnabled(bool)));
Chris@162 537 m_keyReference->registerShortcut(action);
Chris@66 538 menu->addAction(action);
Chris@66 539 toolbar->addAction(action);
Chris@0 540
Chris@168 541 icon = il.load("filesaveas");
Chris@168 542 icon.addPixmap(il.loadPixmap("filesaveas-22"));
Chris@66 543 action = new QAction(icon, tr("Save Session &As..."), this);
Chris@66 544 action->setStatusTip(tr("Save the current session into a new Sonic Visualiser session file"));
Chris@66 545 connect(action, SIGNAL(triggered()), this, SLOT(saveSessionAs()));
Chris@66 546 menu->addAction(action);
Chris@66 547 toolbar->addAction(action);
Chris@66 548
Chris@66 549 menu->addSeparator();
Chris@66 550
Chris@168 551 icon = il.load("fileopenaudio");
Chris@138 552 action = new QAction(icon, tr("&Import Audio File..."), this);
Chris@66 553 action->setShortcut(tr("Ctrl+I"));
Chris@66 554 action->setStatusTip(tr("Import an existing audio file"));
Chris@66 555 connect(action, SIGNAL(triggered()), this, SLOT(importAudio()));
Chris@162 556 m_keyReference->registerShortcut(action);
Chris@66 557 menu->addAction(action);
Chris@66 558
Chris@66 559 action = new QAction(tr("Import Secondary Audio File..."), this);
Chris@66 560 action->setShortcut(tr("Ctrl+Shift+I"));
Chris@66 561 action->setStatusTip(tr("Import an extra audio file as a separate layer"));
Chris@66 562 connect(action, SIGNAL(triggered()), this, SLOT(importMoreAudio()));
Chris@66 563 connect(this, SIGNAL(canImportMoreAudio(bool)), action, SLOT(setEnabled(bool)));
Chris@162 564 m_keyReference->registerShortcut(action);
Chris@66 565 menu->addAction(action);
Chris@66 566
Chris@66 567 action = new QAction(tr("&Export Audio File..."), this);
Chris@66 568 action->setStatusTip(tr("Export selection as an audio file"));
Chris@66 569 connect(action, SIGNAL(triggered()), this, SLOT(exportAudio()));
Chris@66 570 connect(this, SIGNAL(canExportAudio(bool)), action, SLOT(setEnabled(bool)));
Chris@66 571 menu->addAction(action);
Chris@66 572
Chris@66 573 menu->addSeparator();
Chris@66 574
Chris@66 575 action = new QAction(tr("Import Annotation &Layer..."), this);
Chris@66 576 action->setShortcut(tr("Ctrl+L"));
Chris@66 577 action->setStatusTip(tr("Import layer data from an existing file"));
Chris@66 578 connect(action, SIGNAL(triggered()), this, SLOT(importLayer()));
Chris@66 579 connect(this, SIGNAL(canImportLayer(bool)), action, SLOT(setEnabled(bool)));
Chris@162 580 m_keyReference->registerShortcut(action);
Chris@66 581 menu->addAction(action);
Chris@66 582
Chris@66 583 action = new QAction(tr("Export Annotation Layer..."), this);
Chris@66 584 action->setStatusTip(tr("Export layer data to a file"));
Chris@66 585 connect(action, SIGNAL(triggered()), this, SLOT(exportLayer()));
Chris@66 586 connect(this, SIGNAL(canExportLayer(bool)), action, SLOT(setEnabled(bool)));
Chris@66 587 menu->addAction(action);
Chris@66 588
Chris@66 589 menu->addSeparator();
Chris@86 590
Chris@121 591 action = new QAction(tr("Export Image File..."), this);
Chris@121 592 action->setStatusTip(tr("Export a single pane to an image file"));
Chris@121 593 connect(action, SIGNAL(triggered()), this, SLOT(exportImage()));
Chris@121 594 connect(this, SIGNAL(canExportImage(bool)), action, SLOT(setEnabled(bool)));
Chris@121 595 menu->addAction(action);
Chris@121 596
Chris@121 597 menu->addSeparator();
Chris@121 598
Chris@86 599 action = new QAction(tr("Open Lo&cation..."), this);
Chris@86 600 action->setShortcut(tr("Ctrl+Shift+O"));
Chris@86 601 action->setStatusTip(tr("Open or import a file from a remote URL"));
Chris@86 602 connect(action, SIGNAL(triggered()), this, SLOT(openLocation()));
Chris@162 603 m_keyReference->registerShortcut(action);
Chris@86 604 menu->addAction(action);
Chris@86 605
Chris@86 606 menu->addSeparator();
Chris@86 607
Chris@66 608 m_recentFilesMenu = menu->addMenu(tr("&Recent Files"));
Chris@97 609 m_recentFilesMenu->setTearOffEnabled(true);
Chris@66 610 setupRecentFilesMenu();
Chris@66 611 connect(&m_recentFiles, SIGNAL(recentChanged()),
Chris@66 612 this, SLOT(setupRecentFilesMenu()));
Chris@66 613
Chris@66 614 menu->addSeparator();
Chris@66 615 action = new QAction(tr("&Preferences..."), this);
Chris@66 616 action->setStatusTip(tr("Adjust the application preferences"));
Chris@66 617 connect(action, SIGNAL(triggered()), this, SLOT(preferences()));
Chris@66 618 menu->addAction(action);
Chris@0 619
Chris@66 620 menu->addSeparator();
Chris@168 621 action = new QAction(il.load("exit"),
Chris@66 622 tr("&Quit"), this);
Chris@66 623 action->setShortcut(tr("Ctrl+Q"));
Chris@90 624 action->setStatusTip(tr("Exit Sonic Visualiser"));
Chris@66 625 connect(action, SIGNAL(triggered()), this, SLOT(close()));
Chris@162 626 m_keyReference->registerShortcut(action);
Chris@66 627 menu->addAction(action);
Chris@66 628 }
Chris@66 629
Chris@66 630 void
Chris@66 631 MainWindow::setupEditMenu()
Chris@66 632 {
Chris@66 633 if (m_mainMenusCreated) return;
Chris@66 634
Chris@66 635 QMenu *menu = menuBar()->addMenu(tr("&Edit"));
Chris@97 636 menu->setTearOffEnabled(true);
Chris@66 637 CommandHistory::getInstance()->registerMenu(menu);
Chris@66 638
Chris@162 639 m_keyReference->setCategory(tr("Editing"));
Chris@162 640
Chris@66 641 menu->addSeparator();
Chris@66 642
Chris@168 643 IconLoader il;
Chris@168 644
Chris@168 645 QAction *action = new QAction(il.load("editcut"),
Chris@66 646 tr("Cu&t"), this);
Chris@66 647 action->setShortcut(tr("Ctrl+X"));
Chris@90 648 action->setStatusTip(tr("Cut the selection from the current layer to the clipboard"));
Chris@66 649 connect(action, SIGNAL(triggered()), this, SLOT(cut()));
Chris@66 650 connect(this, SIGNAL(canEditSelection(bool)), action, SLOT(setEnabled(bool)));
Chris@162 651 m_keyReference->registerShortcut(action);
Chris@66 652 menu->addAction(action);
Chris@66 653 m_rightButtonMenu->addAction(action);
Chris@66 654
Chris@168 655 action = new QAction(il.load("editcopy"),
Chris@66 656 tr("&Copy"), this);
Chris@66 657 action->setShortcut(tr("Ctrl+C"));
Chris@90 658 action->setStatusTip(tr("Copy the selection from the current layer to the clipboard"));
Chris@66 659 connect(action, SIGNAL(triggered()), this, SLOT(copy()));
Chris@66 660 connect(this, SIGNAL(canEditSelection(bool)), action, SLOT(setEnabled(bool)));
Chris@162 661 m_keyReference->registerShortcut(action);
Chris@66 662 menu->addAction(action);
Chris@66 663 m_rightButtonMenu->addAction(action);
Chris@66 664
Chris@168 665 action = new QAction(il.load("editpaste"),
Chris@66 666 tr("&Paste"), this);
Chris@66 667 action->setShortcut(tr("Ctrl+V"));
Chris@90 668 action->setStatusTip(tr("Paste from the clipboard to the current layer"));
Chris@66 669 connect(action, SIGNAL(triggered()), this, SLOT(paste()));
Chris@66 670 connect(this, SIGNAL(canPaste(bool)), action, SLOT(setEnabled(bool)));
Chris@162 671 m_keyReference->registerShortcut(action);
Chris@66 672 menu->addAction(action);
Chris@66 673 m_rightButtonMenu->addAction(action);
Chris@66 674
Chris@164 675 m_deleteSelectedAction = new QAction(tr("&Delete Selected Items"), this);
Chris@164 676 m_deleteSelectedAction->setShortcut(tr("Del"));
Chris@164 677 m_deleteSelectedAction->setStatusTip(tr("Delete items in current selection from the current layer"));
Chris@164 678 connect(m_deleteSelectedAction, SIGNAL(triggered()), this, SLOT(deleteSelected()));
Chris@164 679 connect(this, SIGNAL(canDeleteSelection(bool)), m_deleteSelectedAction, SLOT(setEnabled(bool)));
Chris@164 680 m_keyReference->registerShortcut(m_deleteSelectedAction);
Chris@164 681 menu->addAction(m_deleteSelectedAction);
Chris@164 682 m_rightButtonMenu->addAction(m_deleteSelectedAction);
Chris@66 683
Chris@66 684 menu->addSeparator();
Chris@66 685 m_rightButtonMenu->addSeparator();
Chris@162 686
Chris@162 687 m_keyReference->setCategory(tr("Selection"));
Chris@162 688
Chris@66 689 action = new QAction(tr("Select &All"), this);
Chris@66 690 action->setShortcut(tr("Ctrl+A"));
Chris@90 691 action->setStatusTip(tr("Select the whole duration of the current session"));
Chris@66 692 connect(action, SIGNAL(triggered()), this, SLOT(selectAll()));
Chris@66 693 connect(this, SIGNAL(canSelect(bool)), action, SLOT(setEnabled(bool)));
Chris@162 694 m_keyReference->registerShortcut(action);
Chris@66 695 menu->addAction(action);
Chris@66 696 m_rightButtonMenu->addAction(action);
Chris@0 697
Chris@66 698 action = new QAction(tr("Select &Visible Range"), this);
Chris@66 699 action->setShortcut(tr("Ctrl+Shift+A"));
Chris@90 700 action->setStatusTip(tr("Select the time range corresponding to the current window width"));
Chris@66 701 connect(action, SIGNAL(triggered()), this, SLOT(selectVisible()));
Chris@66 702 connect(this, SIGNAL(canSelect(bool)), action, SLOT(setEnabled(bool)));
Chris@162 703 m_keyReference->registerShortcut(action);
Chris@66 704 menu->addAction(action);
Chris@0 705
Chris@66 706 action = new QAction(tr("Select to &Start"), this);
Chris@66 707 action->setShortcut(tr("Shift+Left"));
Chris@90 708 action->setStatusTip(tr("Select from the start of the session to the current playback position"));
Chris@66 709 connect(action, SIGNAL(triggered()), this, SLOT(selectToStart()));
Chris@66 710 connect(this, SIGNAL(canSelect(bool)), action, SLOT(setEnabled(bool)));
Chris@162 711 m_keyReference->registerShortcut(action);
Chris@66 712 menu->addAction(action);
Chris@0 713
Chris@66 714 action = new QAction(tr("Select to &End"), this);
Chris@66 715 action->setShortcut(tr("Shift+Right"));
Chris@90 716 action->setStatusTip(tr("Select from the current playback position to the end of the session"));
Chris@66 717 connect(action, SIGNAL(triggered()), this, SLOT(selectToEnd()));
Chris@66 718 connect(this, SIGNAL(canSelect(bool)), action, SLOT(setEnabled(bool)));
Chris@162 719 m_keyReference->registerShortcut(action);
Chris@66 720 menu->addAction(action);
Chris@66 721
Chris@66 722 action = new QAction(tr("C&lear Selection"), this);
Chris@66 723 action->setShortcut(tr("Esc"));
Chris@90 724 action->setStatusTip(tr("Clear the selection"));
Chris@66 725 connect(action, SIGNAL(triggered()), this, SLOT(clearSelection()));
Chris@66 726 connect(this, SIGNAL(canClearSelection(bool)), action, SLOT(setEnabled(bool)));
Chris@162 727 m_keyReference->registerShortcut(action);
Chris@66 728 menu->addAction(action);
Chris@66 729 m_rightButtonMenu->addAction(action);
Chris@66 730
Chris@66 731 menu->addSeparator();
Chris@66 732
Chris@162 733 m_keyReference->setCategory(tr("Tapping Time Instants"));
Chris@162 734
Chris@66 735 action = new QAction(tr("&Insert Instant at Playback Position"), this);
Chris@66 736 action->setShortcut(tr("Enter"));
Chris@90 737 action->setStatusTip(tr("Insert a new time instant at the current playback position, in a new layer if necessary"));
Chris@66 738 connect(action, SIGNAL(triggered()), this, SLOT(insertInstant()));
Chris@66 739 connect(this, SIGNAL(canInsertInstant(bool)), action, SLOT(setEnabled(bool)));
Chris@162 740 m_keyReference->registerShortcut(action);
Chris@66 741 menu->addAction(action);
Chris@66 742
Chris@162 743 // Laptop shortcut (no keypad Enter key)
Chris@162 744 QString shortcut(tr(";"));
Chris@162 745 connect(new QShortcut(shortcut, this), SIGNAL(activated()),
Chris@162 746 this, SLOT(insertInstant()));
Chris@162 747 m_keyReference->registerAlternativeShortcut(action, shortcut);
Chris@162 748
Chris@81 749 action = new QAction(tr("Insert Instants at Selection &Boundaries"), this);
Chris@81 750 action->setShortcut(tr("Shift+Enter"));
Chris@163 751 action->setStatusTip(tr("Insert new time instants at the start and end of the current selected regions, in a new layer if necessary"));
Chris@81 752 connect(action, SIGNAL(triggered()), this, SLOT(insertInstantsAtBoundaries()));
Chris@81 753 connect(this, SIGNAL(canInsertInstantsAtBoundaries(bool)), action, SLOT(setEnabled(bool)));
Chris@162 754 m_keyReference->registerShortcut(action);
Chris@81 755 menu->addAction(action);
Chris@189 756
Chris@190 757 QMenu *numberingMenu = menu->addMenu(tr("Number New Instants with"));
Chris@189 758 QActionGroup *numberingGroup = new QActionGroup(this);
Chris@189 759
Chris@189 760 Labeller::TypeNameMap types = m_labeller->getTypeNames();
Chris@189 761 for (Labeller::TypeNameMap::iterator i = types.begin(); i != types.end(); ++i) {
Chris@190 762
Chris@190 763 if (i->first == Labeller::ValueFromLabel ||
Chris@190 764 i->first == Labeller::ValueFromExistingNeighbour) continue;
Chris@190 765
Chris@189 766 action = new QAction(i->second, this);
Chris@189 767 connect(action, SIGNAL(triggered()), this, SLOT(setInstantsNumbering()));
Chris@189 768 action->setCheckable(true);
Chris@189 769 action->setChecked(m_labeller->getType() == i->first);
Chris@189 770 numberingGroup->addAction(action);
Chris@189 771 numberingMenu->addAction(action);
Chris@189 772 m_numberingActions[action] = (int)i->first;
Chris@190 773
Chris@190 774 if (i->first == Labeller::ValueFromTwoLevelCounter) {
Chris@192 775
Chris@190 776 QMenu *cycleMenu = numberingMenu->addMenu(tr("Cycle size"));
Chris@190 777 QActionGroup *cycleGroup = new QActionGroup(this);
Chris@190 778
Chris@190 779 int cycles[] = { 2, 3, 4, 5, 6, 7, 8, 10, 12, 16 };
Chris@190 780 for (int i = 0; i < sizeof(cycles)/sizeof(cycles[0]); ++i) {
Chris@190 781 action = new QAction(QString("%1").arg(cycles[i]), this);
Chris@190 782 connect(action, SIGNAL(triggered()), this, SLOT(setInstantsCounterCycle()));
Chris@190 783 action->setCheckable(true);
Chris@190 784 action->setChecked(cycles[i] == m_labeller->getCounterCycleSize());
Chris@190 785 cycleGroup->addAction(action);
Chris@190 786 cycleMenu->addAction(action);
Chris@190 787 }
Chris@192 788
Chris@192 789 action = new QAction(tr("Reset Counters..."), this);
Chris@192 790 connect(action, SIGNAL(triggered()), this, SLOT(resetInstantsCounters()));
Chris@192 791 numberingMenu->addAction(action);
Chris@190 792 }
Chris@190 793
Chris@190 794 if (i->first == Labeller::ValueNone ||
Chris@190 795 i->first == Labeller::ValueFromTwoLevelCounter ||
Chris@190 796 i->first == Labeller::ValueFromRealTime) {
Chris@190 797 numberingMenu->addSeparator();
Chris@190 798 }
Chris@189 799 }
Chris@189 800
Chris@189 801 action = new QAction(tr("Re-Number Selected Instants"), this);
Chris@189 802 action->setStatusTip(tr("Re-number the selected instants using the current labelling scheme"));
Chris@189 803 connect(action, SIGNAL(triggered()), this, SLOT(renumberInstants()));
Chris@189 804 connect(this, SIGNAL(canRenumberInstants(bool)), action, SLOT(setEnabled(bool)));
Chris@189 805 // m_keyReference->registerShortcut(action);
Chris@189 806 menu->addAction(action);
Chris@66 807 }
Chris@66 808
Chris@66 809 void
Chris@66 810 MainWindow::setupViewMenu()
Chris@66 811 {
Chris@66 812 if (m_mainMenusCreated) return;
Chris@66 813
Chris@168 814 IconLoader il;
Chris@168 815
Chris@90 816 QAction *action = 0;
Chris@90 817
Chris@162 818 m_keyReference->setCategory(tr("Panning and Navigation"));
Chris@162 819
Chris@66 820 QMenu *menu = menuBar()->addMenu(tr("&View"));
Chris@97 821 menu->setTearOffEnabled(true);
Chris@66 822 action = new QAction(tr("Scroll &Left"), this);
Chris@66 823 action->setShortcut(tr("Left"));
Chris@66 824 action->setStatusTip(tr("Scroll the current pane to the left"));
Chris@66 825 connect(action, SIGNAL(triggered()), this, SLOT(scrollLeft()));
Chris@66 826 connect(this, SIGNAL(canScroll(bool)), action, SLOT(setEnabled(bool)));
Chris@162 827 m_keyReference->registerShortcut(action);
Chris@66 828 menu->addAction(action);
Chris@0 829
Chris@66 830 action = new QAction(tr("Scroll &Right"), this);
Chris@66 831 action->setShortcut(tr("Right"));
Chris@66 832 action->setStatusTip(tr("Scroll the current pane to the right"));
Chris@66 833 connect(action, SIGNAL(triggered()), this, SLOT(scrollRight()));
Chris@66 834 connect(this, SIGNAL(canScroll(bool)), action, SLOT(setEnabled(bool)));
Chris@162 835 m_keyReference->registerShortcut(action);
Chris@66 836 menu->addAction(action);
Chris@0 837
Chris@90 838 action = new QAction(tr("&Jump Left"), this);
Chris@66 839 action->setShortcut(tr("Ctrl+Left"));
Chris@66 840 action->setStatusTip(tr("Scroll the current pane a big step to the left"));
Chris@66 841 connect(action, SIGNAL(triggered()), this, SLOT(jumpLeft()));
Chris@66 842 connect(this, SIGNAL(canScroll(bool)), action, SLOT(setEnabled(bool)));
Chris@162 843 m_keyReference->registerShortcut(action);
Chris@66 844 menu->addAction(action);
Chris@0 845
Chris@90 846 action = new QAction(tr("J&ump Right"), this);
Chris@66 847 action->setShortcut(tr("Ctrl+Right"));
Chris@66 848 action->setStatusTip(tr("Scroll the current pane a big step to the right"));
Chris@66 849 connect(action, SIGNAL(triggered()), this, SLOT(jumpRight()));
Chris@66 850 connect(this, SIGNAL(canScroll(bool)), action, SLOT(setEnabled(bool)));
Chris@162 851 m_keyReference->registerShortcut(action);
Chris@66 852 menu->addAction(action);
Chris@66 853
Chris@66 854 menu->addSeparator();
Chris@66 855
Chris@162 856 m_keyReference->setCategory(tr("Zoom"));
Chris@162 857
Chris@168 858 action = new QAction(il.load("zoom-in"),
Chris@66 859 tr("Zoom &In"), this);
Chris@66 860 action->setShortcut(tr("Up"));
Chris@66 861 action->setStatusTip(tr("Increase the zoom level"));
Chris@66 862 connect(action, SIGNAL(triggered()), this, SLOT(zoomIn()));
Chris@66 863 connect(this, SIGNAL(canZoom(bool)), action, SLOT(setEnabled(bool)));
Chris@162 864 m_keyReference->registerShortcut(action);
Chris@66 865 menu->addAction(action);
Chris@0 866
Chris@168 867 action = new QAction(il.load("zoom-out"),
Chris@66 868 tr("Zoom &Out"), this);
Chris@66 869 action->setShortcut(tr("Down"));
Chris@66 870 action->setStatusTip(tr("Decrease the zoom level"));
Chris@66 871 connect(action, SIGNAL(triggered()), this, SLOT(zoomOut()));
Chris@66 872 connect(this, SIGNAL(canZoom(bool)), action, SLOT(setEnabled(bool)));
Chris@162 873 m_keyReference->registerShortcut(action);
Chris@66 874 menu->addAction(action);
Chris@0 875
Chris@66 876 action = new QAction(tr("Restore &Default Zoom"), this);
Chris@90 877 action->setStatusTip(tr("Restore the zoom level to the default"));
Chris@66 878 connect(action, SIGNAL(triggered()), this, SLOT(zoomDefault()));
Chris@66 879 connect(this, SIGNAL(canZoom(bool)), action, SLOT(setEnabled(bool)));
Chris@66 880 menu->addAction(action);
Chris@66 881
Chris@168 882 action = new QAction(il.load("zoom-fit"),
Chris@138 883 tr("Zoom to &Fit"), this);
Chris@155 884 action->setShortcut(tr("F"));
Chris@66 885 action->setStatusTip(tr("Zoom to show the whole file"));
Chris@66 886 connect(action, SIGNAL(triggered()), this, SLOT(zoomToFit()));
Chris@66 887 connect(this, SIGNAL(canZoom(bool)), action, SLOT(setEnabled(bool)));
Chris@162 888 m_keyReference->registerShortcut(action);
Chris@66 889 menu->addAction(action);
Chris@90 890
Chris@90 891 menu->addSeparator();
Chris@90 892
Chris@162 893 m_keyReference->setCategory(tr("Display Features"));
Chris@162 894
Chris@90 895 QActionGroup *overlayGroup = new QActionGroup(this);
Chris@90 896
Chris@90 897 action = new QAction(tr("Show &No Overlays"), this);
Chris@90 898 action->setShortcut(tr("0"));
Chris@90 899 action->setStatusTip(tr("Hide centre indicator, frame times, layer names and scale"));
Chris@90 900 connect(action, SIGNAL(triggered()), this, SLOT(showNoOverlays()));
Chris@90 901 action->setCheckable(true);
Chris@90 902 action->setChecked(false);
Chris@90 903 overlayGroup->addAction(action);
Chris@162 904 m_keyReference->registerShortcut(action);
Chris@90 905 menu->addAction(action);
Chris@90 906
Chris@90 907 action = new QAction(tr("Show &Minimal Overlays"), this);
Chris@90 908 action->setShortcut(tr("9"));
Chris@90 909 action->setStatusTip(tr("Show centre indicator only"));
Chris@90 910 connect(action, SIGNAL(triggered()), this, SLOT(showMinimalOverlays()));
Chris@90 911 action->setCheckable(true);
Chris@90 912 action->setChecked(false);
Chris@90 913 overlayGroup->addAction(action);
Chris@162 914 m_keyReference->registerShortcut(action);
Chris@90 915 menu->addAction(action);
Chris@90 916
Chris@90 917 action = new QAction(tr("Show &Standard Overlays"), this);
Chris@90 918 action->setShortcut(tr("8"));
Chris@90 919 action->setStatusTip(tr("Show centre indicator, frame times and scale"));
Chris@90 920 connect(action, SIGNAL(triggered()), this, SLOT(showStandardOverlays()));
Chris@90 921 action->setCheckable(true);
Chris@90 922 action->setChecked(true);
Chris@90 923 overlayGroup->addAction(action);
Chris@162 924 m_keyReference->registerShortcut(action);
Chris@90 925 menu->addAction(action);
Chris@90 926
Chris@90 927 action = new QAction(tr("Show &All Overlays"), this);
Chris@90 928 action->setShortcut(tr("7"));
Chris@90 929 action->setStatusTip(tr("Show all texts and scale"));
Chris@90 930 connect(action, SIGNAL(triggered()), this, SLOT(showAllOverlays()));
Chris@90 931 action->setCheckable(true);
Chris@90 932 action->setChecked(false);
Chris@90 933 overlayGroup->addAction(action);
Chris@162 934 m_keyReference->registerShortcut(action);
Chris@90 935 menu->addAction(action);
Chris@7 936
Chris@72 937 menu->addSeparator();
Chris@72 938
Chris@66 939 action = new QAction(tr("Show &Zoom Wheels"), this);
Chris@66 940 action->setShortcut(tr("Z"));
Chris@66 941 action->setStatusTip(tr("Show thumbwheels for zooming horizontally and vertically"));
Chris@66 942 connect(action, SIGNAL(triggered()), this, SLOT(toggleZoomWheels()));
Chris@66 943 action->setCheckable(true);
Chris@66 944 action->setChecked(m_viewManager->getZoomWheelsEnabled());
Chris@162 945 m_keyReference->registerShortcut(action);
Chris@66 946 menu->addAction(action);
Chris@72 947
Chris@72 948 action = new QAction(tr("Show Property Bo&xes"), this);
Chris@72 949 action->setShortcut(tr("X"));
Chris@72 950 action->setStatusTip(tr("Show the layer property boxes at the side of the main window"));
Chris@72 951 connect(action, SIGNAL(triggered()), this, SLOT(togglePropertyBoxes()));
Chris@72 952 action->setCheckable(true);
Chris@72 953 action->setChecked(true);
Chris@162 954 m_keyReference->registerShortcut(action);
Chris@72 955 menu->addAction(action);
Chris@0 956
Chris@90 957 action = new QAction(tr("Show Status &Bar"), this);
Chris@90 958 action->setStatusTip(tr("Show context help information in the status bar at the bottom of the window"));
Chris@90 959 connect(action, SIGNAL(triggered()), this, SLOT(toggleStatusBar()));
Chris@90 960 action->setCheckable(true);
Chris@90 961 action->setChecked(true);
Chris@90 962 menu->addAction(action);
Chris@90 963
Chris@90 964 QSettings settings;
Chris@90 965 settings.beginGroup("MainWindow");
Chris@90 966 bool sb = settings.value("showstatusbar", true).toBool();
Chris@90 967 if (!sb) {
Chris@90 968 action->setChecked(false);
Chris@90 969 statusBar()->hide();
Chris@90 970 }
Chris@90 971 settings.endGroup();
Chris@90 972
Chris@66 973 menu->addSeparator();
Chris@66 974
Chris@90 975 action = new QAction(tr("Show La&yer Hierarchy"), this);
Chris@155 976 action->setShortcut(tr("H"));
Chris@90 977 action->setStatusTip(tr("Open a window displaying the hierarchy of panes and layers in this session"));
Chris@66 978 connect(action, SIGNAL(triggered()), this, SLOT(showLayerTree()));
Chris@162 979 m_keyReference->registerShortcut(action);
Chris@66 980 menu->addAction(action);
Chris@66 981 }
Chris@66 982
Chris@66 983 void
Chris@66 984 MainWindow::setupPaneAndLayerMenus()
Chris@66 985 {
Chris@0 986 if (m_paneMenu) {
Chris@0 987 m_paneActions.clear();
Chris@0 988 m_paneMenu->clear();
Chris@0 989 } else {
Chris@0 990 m_paneMenu = menuBar()->addMenu(tr("&Pane"));
Chris@97 991 m_paneMenu->setTearOffEnabled(true);
Chris@0 992 }
Chris@0 993
Chris@0 994 if (m_layerMenu) {
Chris@0 995 m_layerActions.clear();
Chris@0 996 m_layerMenu->clear();
Chris@0 997 } else {
Chris@0 998 m_layerMenu = menuBar()->addMenu(tr("&Layer"));
Chris@97 999 m_layerMenu->setTearOffEnabled(true);
Chris@0 1000 }
Chris@0 1001
Chris@66 1002 QMenu *menu = m_paneMenu;
Chris@66 1003
Chris@168 1004 IconLoader il;
Chris@168 1005
Chris@162 1006 m_keyReference->setCategory(tr("Managing Panes and Layers"));
Chris@162 1007
Chris@168 1008 QAction *action = new QAction(il.load("pane"), tr("Add &New Pane"), this);
Chris@155 1009 action->setShortcut(tr("N"));
Chris@66 1010 action->setStatusTip(tr("Add a new pane containing only a time ruler"));
Chris@66 1011 connect(action, SIGNAL(triggered()), this, SLOT(addPane()));
Chris@66 1012 connect(this, SIGNAL(canAddPane(bool)), action, SLOT(setEnabled(bool)));
Chris@66 1013 m_paneActions[action] = PaneConfiguration(LayerFactory::TimeRuler);
Chris@162 1014 m_keyReference->registerShortcut(action);
Chris@66 1015 menu->addAction(action);
Chris@66 1016
Chris@66 1017 menu->addSeparator();
Chris@66 1018
Chris@66 1019 menu = m_layerMenu;
Chris@66 1020
Chris@66 1021 // menu->addSeparator();
Chris@66 1022
Chris@66 1023 LayerFactory::LayerTypeSet emptyLayerTypes =
Chris@66 1024 LayerFactory::getInstance()->getValidEmptyLayerTypes();
Chris@66 1025
Chris@66 1026 for (LayerFactory::LayerTypeSet::iterator i = emptyLayerTypes.begin();
Chris@66 1027 i != emptyLayerTypes.end(); ++i) {
Chris@66 1028
Chris@66 1029 QIcon icon;
Chris@66 1030 QString mainText, tipText, channelText;
Chris@66 1031 LayerFactory::LayerType type = *i;
Chris@66 1032 QString name = LayerFactory::getInstance()->getLayerPresentationName(type);
Chris@66 1033
Chris@168 1034 icon = il.load(LayerFactory::getInstance()->getLayerIconName(type));
Chris@66 1035
Chris@66 1036 mainText = tr("Add New %1 Layer").arg(name);
Chris@66 1037 tipText = tr("Add a new empty layer of type %1").arg(name);
Chris@66 1038
Chris@66 1039 action = new QAction(icon, mainText, this);
Chris@66 1040 action->setStatusTip(tipText);
Chris@66 1041
Chris@66 1042 if (type == LayerFactory::Text) {
Chris@155 1043 action->setShortcut(tr("T"));
Chris@162 1044 m_keyReference->registerShortcut(action);
Chris@66 1045 }
Chris@66 1046
Chris@66 1047 connect(action, SIGNAL(triggered()), this, SLOT(addLayer()));
Chris@66 1048 connect(this, SIGNAL(canAddLayer(bool)), action, SLOT(setEnabled(bool)));
Chris@66 1049 m_layerActions[action] = type;
Chris@66 1050 menu->addAction(action);
Chris@66 1051 m_rightButtonLayerMenu->addAction(action);
Chris@66 1052 }
Chris@66 1053
Chris@66 1054 m_rightButtonLayerMenu->addSeparator();
Chris@66 1055 menu->addSeparator();
Chris@66 1056
Chris@66 1057 LayerFactory::LayerType backgroundTypes[] = {
Chris@66 1058 LayerFactory::Waveform,
Chris@66 1059 LayerFactory::Spectrogram,
Chris@66 1060 LayerFactory::MelodicRangeSpectrogram,
Chris@66 1061 LayerFactory::PeakFrequencySpectrogram,
Chris@66 1062 LayerFactory::Spectrum
Chris@66 1063 };
Chris@66 1064
Chris@66 1065 std::vector<Model *> models;
Chris@66 1066 if (m_document) models = m_document->getTransformInputModels(); //!!! not well named for this!
Chris@66 1067 bool plural = (models.size() > 1);
Chris@66 1068 if (models.empty()) {
Chris@67 1069 models.push_back(getMainModel()); // probably 0
Chris@66 1070 }
Chris@66 1071
Chris@66 1072 for (unsigned int i = 0;
Chris@66 1073 i < sizeof(backgroundTypes)/sizeof(backgroundTypes[0]); ++i) {
Chris@66 1074
Chris@66 1075 for (int menuType = 0; menuType <= 1; ++menuType) { // pane, layer
Chris@66 1076
Chris@66 1077 if (menuType == 0) menu = m_paneMenu;
Chris@66 1078 else menu = m_layerMenu;
Chris@66 1079
Chris@66 1080 QMenu *submenu = 0;
Chris@66 1081
Chris@66 1082 QIcon icon;
Chris@66 1083 QString mainText, shortcutText, tipText, channelText;
Chris@66 1084 LayerFactory::LayerType type = backgroundTypes[i];
Chris@66 1085 bool mono = true;
Chris@66 1086
Chris@66 1087 switch (type) {
Chris@66 1088
Chris@66 1089 case LayerFactory::Waveform:
Chris@168 1090 icon = il.load("waveform");
Chris@66 1091 mainText = tr("Add &Waveform");
Chris@66 1092 if (menuType == 0) {
Chris@155 1093 shortcutText = tr("W");
Chris@66 1094 tipText = tr("Add a new pane showing a waveform view");
Chris@66 1095 } else {
Chris@66 1096 tipText = tr("Add a new layer showing a waveform view");
Chris@66 1097 }
Chris@66 1098 mono = false;
Chris@66 1099 break;
Chris@66 1100
Chris@66 1101 case LayerFactory::Spectrogram:
Chris@168 1102 icon = il.load("spectrogram");
Chris@161 1103 mainText = tr("Add Spectro&gram");
Chris@66 1104 if (menuType == 0) {
Chris@155 1105 shortcutText = tr("G");
Chris@90 1106 tipText = tr("Add a new pane showing a spectrogram");
Chris@66 1107 } else {
Chris@90 1108 tipText = tr("Add a new layer showing a spectrogram");
Chris@66 1109 }
Chris@66 1110 break;
Chris@66 1111
Chris@66 1112 case LayerFactory::MelodicRangeSpectrogram:
Chris@168 1113 icon = il.load("spectrogram");
Chris@66 1114 mainText = tr("Add &Melodic Range Spectrogram");
Chris@66 1115 if (menuType == 0) {
Chris@155 1116 shortcutText = tr("M");
Chris@90 1117 tipText = tr("Add a new pane showing a spectrogram set up for an overview of note pitches");
Chris@66 1118 } else {
Chris@90 1119 tipText = tr("Add a new layer showing a spectrogram set up for an overview of note pitches");
Chris@66 1120 }
Chris@66 1121 break;
Chris@66 1122
Chris@66 1123 case LayerFactory::PeakFrequencySpectrogram:
Chris@168 1124 icon = il.load("spectrogram");
Chris@155 1125 mainText = tr("Add Pea&k Frequency Spectrogram");
Chris@66 1126 if (menuType == 0) {
Chris@155 1127 shortcutText = tr("K");
Chris@66 1128 tipText = tr("Add a new pane showing a spectrogram set up for tracking frequencies");
Chris@66 1129 } else {
Chris@66 1130 tipText = tr("Add a new layer showing a spectrogram set up for tracking frequencies");
Chris@66 1131 }
Chris@66 1132 break;
Chris@66 1133
Chris@66 1134 case LayerFactory::Spectrum:
Chris@168 1135 icon = il.load("spectrum");
Chris@66 1136 mainText = tr("Add Spectr&um");
Chris@66 1137 if (menuType == 0) {
Chris@155 1138 shortcutText = tr("U");
Chris@66 1139 tipText = tr("Add a new pane showing a frequency spectrum");
Chris@66 1140 } else {
Chris@66 1141 tipText = tr("Add a new layer showing a frequency spectrum");
Chris@66 1142 }
Chris@66 1143 break;
Chris@66 1144
Chris@66 1145 default: break;
Chris@66 1146 }
Chris@66 1147
Chris@66 1148 std::vector<Model *> candidateModels;
Chris@66 1149 if (menuType == 0) {
Chris@66 1150 candidateModels = models;
Chris@66 1151 } else {
Chris@66 1152 candidateModels.push_back(0);
Chris@66 1153 }
Chris@66 1154
Chris@66 1155 for (std::vector<Model *>::iterator mi =
Chris@66 1156 candidateModels.begin();
Chris@66 1157 mi != candidateModels.end(); ++mi) {
Chris@66 1158
Chris@66 1159 Model *model = *mi;
Chris@66 1160
Chris@66 1161 int channels = 0;
Chris@66 1162 if (model) {
Chris@66 1163 DenseTimeValueModel *dtvm =
Chris@66 1164 dynamic_cast<DenseTimeValueModel *>(model);
Chris@66 1165 if (dtvm) channels = dtvm->getChannelCount();
Chris@66 1166 }
Chris@66 1167 if (channels < 1 && getMainModel()) {
Chris@66 1168 channels = getMainModel()->getChannelCount();
Chris@66 1169 }
Chris@66 1170 if (channels < 1) channels = 1;
Chris@66 1171
Chris@66 1172 for (int c = 0; c <= channels; ++c) {
Chris@66 1173
Chris@66 1174 if (c == 1 && channels == 1) continue;
Chris@66 1175 bool isDefault = (c == 0);
Chris@66 1176 bool isOnly = (isDefault && (channels == 1));
Chris@66 1177
Chris@66 1178 if (menuType == 1) {
Chris@66 1179 if (isDefault) isOnly = true;
Chris@66 1180 else continue;
Chris@66 1181 }
Chris@66 1182
Chris@66 1183 if (isOnly && (!plural || menuType == 1)) {
Chris@66 1184
Chris@138 1185 if (menuType == 1 && type != LayerFactory::Waveform) {
Chris@67 1186 action = new QAction(mainText, this);
Chris@67 1187 } else {
Chris@67 1188 action = new QAction(icon, mainText, this);
Chris@67 1189 }
Chris@67 1190
Chris@66 1191 action->setShortcut(shortcutText);
Chris@66 1192 action->setStatusTip(tipText);
Chris@66 1193 if (menuType == 0) {
Chris@66 1194 connect(action, SIGNAL(triggered()),
Chris@66 1195 this, SLOT(addPane()));
Chris@66 1196 connect(this, SIGNAL(canAddPane(bool)),
Chris@66 1197 action, SLOT(setEnabled(bool)));
Chris@66 1198 m_paneActions[action] = PaneConfiguration(type);
Chris@66 1199 } else {
Chris@66 1200 connect(action, SIGNAL(triggered()),
Chris@66 1201 this, SLOT(addLayer()));
Chris@66 1202 connect(this, SIGNAL(canAddLayer(bool)),
Chris@66 1203 action, SLOT(setEnabled(bool)));
Chris@66 1204 m_layerActions[action] = type;
Chris@66 1205 }
Chris@162 1206 if (shortcutText != "") {
Chris@162 1207 m_keyReference->registerShortcut(action);
Chris@162 1208 }
Chris@66 1209 menu->addAction(action);
Chris@66 1210
Chris@66 1211 } else {
Chris@66 1212
Chris@66 1213 if (!submenu) {
Chris@66 1214 submenu = menu->addMenu(mainText);
Chris@97 1215 submenu->setTearOffEnabled(true);
Chris@67 1216 } else if (isDefault) {
Chris@67 1217 submenu->addSeparator();
Chris@66 1218 }
Chris@66 1219
Chris@66 1220 QString actionText;
Chris@66 1221 if (c == 0) {
Chris@66 1222 if (mono) {
Chris@66 1223 actionText = tr("&All Channels Mixed");
Chris@66 1224 } else {
Chris@66 1225 actionText = tr("&All Channels");
Chris@66 1226 }
Chris@66 1227 } else {
Chris@66 1228 actionText = tr("Channel &%1").arg(c);
Chris@66 1229 }
Chris@66 1230
Chris@66 1231 if (model) {
Chris@66 1232 actionText = tr("%1: %2")
Chris@66 1233 .arg(model->objectName())
Chris@66 1234 .arg(actionText);
Chris@66 1235 }
Chris@67 1236
Chris@67 1237 if (isDefault) {
Chris@67 1238 action = new QAction(icon, actionText, this);
Chris@67 1239 if (!model || model == getMainModel()) {
Chris@162 1240 action->setShortcut(shortcutText);
Chris@67 1241 }
Chris@67 1242 } else {
Chris@67 1243 action = new QAction(actionText, this);
Chris@67 1244 }
Chris@67 1245
Chris@66 1246 action->setStatusTip(tipText);
Chris@66 1247
Chris@66 1248 if (menuType == 0) {
Chris@66 1249 connect(action, SIGNAL(triggered()),
Chris@66 1250 this, SLOT(addPane()));
Chris@66 1251 connect(this, SIGNAL(canAddPane(bool)),
Chris@66 1252 action, SLOT(setEnabled(bool)));
Chris@66 1253 m_paneActions[action] =
Chris@66 1254 PaneConfiguration(type, model, c - 1);
Chris@66 1255 } else {
Chris@66 1256 connect(action, SIGNAL(triggered()),
Chris@66 1257 this, SLOT(addLayer()));
Chris@66 1258 connect(this, SIGNAL(canAddLayer(bool)),
Chris@66 1259 action, SLOT(setEnabled(bool)));
Chris@66 1260 m_layerActions[action] = type;
Chris@66 1261 }
Chris@66 1262
Chris@66 1263 submenu->addAction(action);
Chris@66 1264 }
Chris@66 1265 }
Chris@66 1266 }
Chris@66 1267 }
Chris@66 1268 }
Chris@66 1269
Chris@66 1270 menu = m_paneMenu;
Chris@66 1271
Chris@66 1272 menu->addSeparator();
Chris@66 1273
Chris@168 1274 action = new QAction(il.load("editdelete"), tr("&Delete Pane"), this);
Chris@155 1275 action->setShortcut(tr("Ctrl+Shift+D"));
Chris@90 1276 action->setStatusTip(tr("Delete the currently active pane"));
Chris@66 1277 connect(action, SIGNAL(triggered()), this, SLOT(deleteCurrentPane()));
Chris@66 1278 connect(this, SIGNAL(canDeleteCurrentPane(bool)), action, SLOT(setEnabled(bool)));
Chris@162 1279 m_keyReference->registerShortcut(action);
Chris@66 1280 menu->addAction(action);
Chris@66 1281
Chris@66 1282 menu = m_layerMenu;
Chris@66 1283
Chris@168 1284 action = new QAction(il.load("timeruler"), tr("Add &Time Ruler"), this);
Chris@66 1285 action->setStatusTip(tr("Add a new layer showing a time ruler"));
Chris@66 1286 connect(action, SIGNAL(triggered()), this, SLOT(addLayer()));
Chris@66 1287 connect(this, SIGNAL(canAddLayer(bool)), action, SLOT(setEnabled(bool)));
Chris@66 1288 m_layerActions[action] = LayerFactory::TimeRuler;
Chris@66 1289 menu->addAction(action);
Chris@66 1290
Chris@66 1291 menu->addSeparator();
Chris@66 1292
Chris@66 1293 m_existingLayersMenu = menu->addMenu(tr("Add &Existing Layer"));
Chris@97 1294 m_existingLayersMenu->setTearOffEnabled(true);
Chris@66 1295 m_rightButtonLayerMenu->addMenu(m_existingLayersMenu);
Chris@95 1296
Chris@95 1297 m_sliceMenu = menu->addMenu(tr("Add S&lice of Layer"));
Chris@97 1298 m_sliceMenu->setTearOffEnabled(true);
Chris@95 1299 m_rightButtonLayerMenu->addMenu(m_sliceMenu);
Chris@95 1300
Chris@95 1301 setupExistingLayersMenus();
Chris@66 1302
Chris@66 1303 m_rightButtonLayerMenu->addSeparator();
Chris@66 1304 menu->addSeparator();
Chris@66 1305
Chris@163 1306 QAction *raction = new QAction(tr("&Rename Layer..."), this);
Chris@163 1307 raction->setShortcut(tr("R"));
Chris@163 1308 raction->setStatusTip(tr("Rename the currently active layer"));
Chris@163 1309 connect(raction, SIGNAL(triggered()), this, SLOT(renameCurrentLayer()));
Chris@163 1310 connect(this, SIGNAL(canRenameLayer(bool)), raction, SLOT(setEnabled(bool)));
Chris@163 1311 menu->addAction(raction);
Chris@163 1312 m_rightButtonLayerMenu->addAction(raction);
Chris@66 1313
Chris@168 1314 action = new QAction(il.load("editdelete"), tr("&Delete Layer"), this);
Chris@155 1315 action->setShortcut(tr("Ctrl+D"));
Chris@66 1316 action->setStatusTip(tr("Delete the currently active layer"));
Chris@66 1317 connect(action, SIGNAL(triggered()), this, SLOT(deleteCurrentLayer()));
Chris@66 1318 connect(this, SIGNAL(canDeleteCurrentLayer(bool)), action, SLOT(setEnabled(bool)));
Chris@162 1319 m_keyReference->registerShortcut(action);
Chris@66 1320 menu->addAction(action);
Chris@66 1321 m_rightButtonLayerMenu->addAction(action);
Chris@163 1322
Chris@163 1323 m_keyReference->registerShortcut(raction); // rename after delete, so delete layer goes next to delete pane
Chris@66 1324 }
Chris@66 1325
Chris@66 1326 void
Chris@66 1327 MainWindow::setupTransformsMenu()
Chris@66 1328 {
Chris@34 1329 if (m_transformsMenu) {
Chris@34 1330 m_transformActions.clear();
Chris@34 1331 m_transformActionsReverse.clear();
Chris@34 1332 m_transformsMenu->clear();
Chris@34 1333 } else {
Chris@97 1334 m_transformsMenu = menuBar()->addMenu(tr("&Transform"));
Chris@97 1335 m_transformsMenu->setTearOffEnabled(true);
Chris@97 1336 }
Chris@34 1337
Chris@0 1338 TransformFactory::TransformList transforms =
Chris@0 1339 TransformFactory::getInstance()->getAllTransforms();
Chris@0 1340
Chris@33 1341 vector<QString> types =
Chris@0 1342 TransformFactory::getInstance()->getAllTransformTypes();
Chris@0 1343
Chris@37 1344 map<QString, map<QString, SubdividingMenu *> > categoryMenus;
Chris@37 1345 map<QString, map<QString, SubdividingMenu *> > makerMenus;
Chris@33 1346
Chris@36 1347 map<QString, SubdividingMenu *> byPluginNameMenus;
Chris@33 1348 map<QString, map<QString, QMenu *> > pluginNameMenus;
Chris@33 1349
Chris@37 1350 set<SubdividingMenu *> pendingMenus;
Chris@37 1351
Chris@34 1352 m_recentTransformsMenu = m_transformsMenu->addMenu(tr("&Recent Transforms"));
Chris@97 1353 m_recentTransformsMenu->setTearOffEnabled(true);
Chris@34 1354 m_rightButtonTransformsMenu->addMenu(m_recentTransformsMenu);
Chris@34 1355 connect(&m_recentTransforms, SIGNAL(recentChanged()),
Chris@34 1356 this, SLOT(setupRecentTransformsMenu()));
Chris@34 1357
Chris@34 1358 m_transformsMenu->addSeparator();
Chris@34 1359 m_rightButtonTransformsMenu->addSeparator();
Chris@34 1360
Chris@33 1361 for (vector<QString>::iterator i = types.begin(); i != types.end(); ++i) {
Chris@33 1362
Chris@33 1363 if (i != types.begin()) {
Chris@34 1364 m_transformsMenu->addSeparator();
Chris@34 1365 m_rightButtonTransformsMenu->addSeparator();
Chris@33 1366 }
Chris@33 1367
Chris@33 1368 QString byCategoryLabel = tr("%1 by Category").arg(*i);
Chris@37 1369 SubdividingMenu *byCategoryMenu = new SubdividingMenu(byCategoryLabel,
Chris@37 1370 20, 40);
Chris@97 1371 byCategoryMenu->setTearOffEnabled(true);
Chris@37 1372 m_transformsMenu->addMenu(byCategoryMenu);
Chris@34 1373 m_rightButtonTransformsMenu->addMenu(byCategoryMenu);
Chris@37 1374 pendingMenus.insert(byCategoryMenu);
Chris@33 1375
Chris@33 1376 vector<QString> categories =
Chris@33 1377 TransformFactory::getInstance()->getTransformCategories(*i);
Chris@33 1378
Chris@33 1379 for (vector<QString>::iterator j = categories.begin();
Chris@33 1380 j != categories.end(); ++j) {
Chris@33 1381
Chris@33 1382 QString category = *j;
Chris@33 1383 if (category == "") category = tr("Unclassified");
Chris@33 1384
Chris@33 1385 if (categories.size() < 2) {
Chris@33 1386 categoryMenus[*i][category] = byCategoryMenu;
Chris@33 1387 continue;
Chris@33 1388 }
Chris@33 1389
Chris@33 1390 QStringList components = category.split(" > ");
Chris@33 1391 QString key;
Chris@33 1392
Chris@33 1393 for (QStringList::iterator k = components.begin();
Chris@33 1394 k != components.end(); ++k) {
Chris@33 1395
Chris@33 1396 QString parentKey = key;
Chris@33 1397 if (key != "") key += " > ";
Chris@33 1398 key += *k;
Chris@33 1399
Chris@33 1400 if (categoryMenus[*i].find(key) == categoryMenus[*i].end()) {
Chris@37 1401 SubdividingMenu *m = new SubdividingMenu(*k, 20, 40);
Chris@97 1402 m->setTearOffEnabled(true);
Chris@37 1403 pendingMenus.insert(m);
Chris@37 1404 categoryMenus[*i][key] = m;
Chris@33 1405 if (parentKey == "") {
Chris@37 1406 byCategoryMenu->addMenu(m);
Chris@33 1407 } else {
Chris@37 1408 categoryMenus[*i][parentKey]->addMenu(m);
Chris@33 1409 }
Chris@33 1410 }
Chris@33 1411 }
Chris@33 1412 }
Chris@33 1413
Chris@34 1414 QString byPluginNameLabel = tr("%1 by Plugin Name").arg(*i);
Chris@36 1415 byPluginNameMenus[*i] = new SubdividingMenu(byPluginNameLabel);
Chris@97 1416 byPluginNameMenus[*i]->setTearOffEnabled(true);
Chris@36 1417 m_transformsMenu->addMenu(byPluginNameMenus[*i]);
Chris@34 1418 m_rightButtonTransformsMenu->addMenu(byPluginNameMenus[*i]);
Chris@37 1419 pendingMenus.insert(byPluginNameMenus[*i]);
Chris@34 1420
Chris@33 1421 QString byMakerLabel = tr("%1 by Maker").arg(*i);
Chris@37 1422 SubdividingMenu *byMakerMenu = new SubdividingMenu(byMakerLabel, 20, 40);
Chris@97 1423 byMakerMenu->setTearOffEnabled(true);
Chris@37 1424 m_transformsMenu->addMenu(byMakerMenu);
Chris@34 1425 m_rightButtonTransformsMenu->addMenu(byMakerMenu);
Chris@37 1426 pendingMenus.insert(byMakerMenu);
Chris@33 1427
Chris@33 1428 vector<QString> makers =
Chris@33 1429 TransformFactory::getInstance()->getTransformMakers(*i);
Chris@37 1430
Chris@33 1431 for (vector<QString>::iterator j = makers.begin();
Chris@33 1432 j != makers.end(); ++j) {
Chris@33 1433
Chris@33 1434 QString maker = *j;
Chris@33 1435 if (maker == "") maker = tr("Unknown");
Chris@55 1436 maker.replace(QRegExp(tr(" [\\(<].*$")), "");
Chris@55 1437
Chris@37 1438 makerMenus[*i][maker] = new SubdividingMenu(maker, 30, 40);
Chris@97 1439 makerMenus[*i][maker]->setTearOffEnabled(true);
Chris@37 1440 byMakerMenu->addMenu(makerMenus[*i][maker]);
Chris@37 1441 pendingMenus.insert(makerMenus[*i][maker]);
Chris@33 1442 }
Chris@0 1443 }
Chris@0 1444
Chris@0 1445 for (unsigned int i = 0; i < transforms.size(); ++i) {
Chris@0 1446
Chris@107 1447 QString name = transforms[i].name;
Chris@107 1448 if (name == "") name = transforms[i].identifier;
Chris@107 1449
Chris@107 1450 // std::cerr << "Plugin Name: " << name.toStdString() << std::endl;
Chris@80 1451
Chris@33 1452 QString type = transforms[i].type;
Chris@33 1453
Chris@33 1454 QString category = transforms[i].category;
Chris@33 1455 if (category == "") category = tr("Unclassified");
Chris@33 1456
Chris@33 1457 QString maker = transforms[i].maker;
Chris@33 1458 if (maker == "") maker = tr("Unknown");
Chris@55 1459 maker.replace(QRegExp(tr(" [\\(<].*$")), "");
Chris@33 1460
Chris@107 1461 QString pluginName = name.section(": ", 0, 0);
Chris@107 1462 QString output = name.section(": ", 1);
Chris@107 1463
Chris@107 1464 QAction *action = new QAction(tr("%1...").arg(name), this);
Chris@0 1465 connect(action, SIGNAL(triggered()), this, SLOT(addLayer()));
Chris@107 1466 m_transformActions[action] = transforms[i].identifier;
Chris@107 1467 m_transformActionsReverse[transforms[i].identifier] = action;
Chris@0 1468 connect(this, SIGNAL(canAddLayer(bool)), action, SLOT(setEnabled(bool)));
Chris@33 1469
Chris@108 1470 action->setStatusTip(transforms[i].description);
Chris@90 1471
Chris@33 1472 if (categoryMenus[type].find(category) == categoryMenus[type].end()) {
Chris@33 1473 std::cerr << "WARNING: MainWindow::setupMenus: Internal error: "
Chris@33 1474 << "No category menu for transform \""
Chris@107 1475 << name.toStdString() << "\" (category = \""
Chris@33 1476 << category.toStdString() << "\")" << std::endl;
Chris@33 1477 } else {
Chris@33 1478 categoryMenus[type][category]->addAction(action);
Chris@33 1479 }
Chris@33 1480
Chris@33 1481 if (makerMenus[type].find(maker) == makerMenus[type].end()) {
Chris@33 1482 std::cerr << "WARNING: MainWindow::setupMenus: Internal error: "
Chris@33 1483 << "No maker menu for transform \""
Chris@107 1484 << name.toStdString() << "\" (maker = \""
Chris@33 1485 << maker.toStdString() << "\")" << std::endl;
Chris@33 1486 } else {
Chris@80 1487 makerMenus[type][maker]->addAction(action);
Chris@33 1488 }
Chris@33 1489
Chris@33 1490 action = new QAction(tr("%1...").arg(output == "" ? pluginName : output), this);
Chris@33 1491 connect(action, SIGNAL(triggered()), this, SLOT(addLayer()));
Chris@107 1492 m_transformActions[action] = transforms[i].identifier;
Chris@33 1493 connect(this, SIGNAL(canAddLayer(bool)), action, SLOT(setEnabled(bool)));
Chris@108 1494 action->setStatusTip(transforms[i].description);
Chris@33 1495
Chris@34 1496 // cerr << "Transform: \"" << name.toStdString() << "\": plugin name \"" << pluginName.toStdString() << "\"" << endl;
Chris@34 1497
Chris@33 1498 if (pluginNameMenus[type].find(pluginName) ==
Chris@33 1499 pluginNameMenus[type].end()) {
Chris@33 1500
Chris@36 1501 SubdividingMenu *parentMenu = byPluginNameMenus[type];
Chris@97 1502 parentMenu->setTearOffEnabled(true);
Chris@34 1503
Chris@33 1504 if (output == "") {
Chris@36 1505 parentMenu->addAction(pluginName, action);
Chris@33 1506 } else {
Chris@34 1507 pluginNameMenus[type][pluginName] =
Chris@34 1508 parentMenu->addMenu(pluginName);
Chris@33 1509 connect(this, SIGNAL(canAddLayer(bool)),
Chris@33 1510 pluginNameMenus[type][pluginName],
Chris@33 1511 SLOT(setEnabled(bool)));
Chris@33 1512 }
Chris@33 1513 }
Chris@33 1514
Chris@33 1515 if (pluginNameMenus[type].find(pluginName) !=
Chris@33 1516 pluginNameMenus[type].end()) {
Chris@33 1517 pluginNameMenus[type][pluginName]->addAction(action);
Chris@33 1518 }
Chris@0 1519 }
Chris@0 1520
Chris@37 1521 for (set<SubdividingMenu *>::iterator i = pendingMenus.begin();
Chris@37 1522 i != pendingMenus.end(); ++i) {
Chris@37 1523 (*i)->entriesAdded();
Chris@37 1524 }
Chris@37 1525
Chris@34 1526 setupRecentTransformsMenu();
Chris@66 1527 }
Chris@66 1528
Chris@66 1529 void
Chris@66 1530 MainWindow::setupHelpMenu()
Chris@66 1531 {
Chris@66 1532 QMenu *menu = menuBar()->addMenu(tr("&Help"));
Chris@97 1533 menu->setTearOffEnabled(true);
Chris@66 1534
Chris@162 1535 m_keyReference->setCategory(tr("Help"));
Chris@162 1536
Chris@168 1537 IconLoader il;
Chris@168 1538
Chris@168 1539 QAction *action = new QAction(il.load("help"),
Chris@138 1540 tr("&Help Reference"), this);
Chris@162 1541 action->setShortcut(tr("F1"));
Chris@66 1542 action->setStatusTip(tr("Open the Sonic Visualiser reference manual"));
Chris@66 1543 connect(action, SIGNAL(triggered()), this, SLOT(help()));
Chris@162 1544 m_keyReference->registerShortcut(action);
Chris@0 1545 menu->addAction(action);
Chris@162 1546
Chris@163 1547 action = new QAction(tr("&Key and Mouse Reference"), this);
Chris@162 1548 action->setShortcut(tr("F2"));
Chris@162 1549 action->setStatusTip(tr("Open a window showing the keystrokes you can use in Sonic Visualiser"));
Chris@162 1550 connect(action, SIGNAL(triggered()), this, SLOT(keyReference()));
Chris@162 1551 m_keyReference->registerShortcut(action);
Chris@162 1552 menu->addAction(action);
Chris@66 1553
Chris@164 1554 action = new QAction(tr("Sonic Visualiser on the &Web"), this);
Chris@164 1555 action->setStatusTip(tr("Open the Sonic Visualiser website"));
Chris@164 1556 connect(action, SIGNAL(triggered()), this, SLOT(website()));
Chris@164 1557 menu->addAction(action);
Chris@164 1558
Chris@66 1559 action = new QAction(tr("&About Sonic Visualiser"), this);
Chris@66 1560 action->setStatusTip(tr("Show information about Sonic Visualiser"));
Chris@66 1561 connect(action, SIGNAL(triggered()), this, SLOT(about()));
Chris@0 1562 menu->addAction(action);
Chris@0 1563 }
Chris@0 1564
Chris@0 1565 void
Chris@0 1566 MainWindow::setupRecentFilesMenu()
Chris@0 1567 {
Chris@0 1568 m_recentFilesMenu->clear();
Chris@34 1569 vector<QString> files = m_recentFiles.getRecent();
Chris@0 1570 for (size_t i = 0; i < files.size(); ++i) {
Chris@0 1571 QAction *action = new QAction(files[i], this);
Chris@0 1572 connect(action, SIGNAL(triggered()), this, SLOT(openRecentFile()));
Chris@162 1573 if (i == 0) {
Chris@162 1574 action->setShortcut(tr("Ctrl+R"));
Chris@162 1575 m_keyReference->registerShortcut
Chris@163 1576 (tr("Re-open"),
Chris@163 1577 action->shortcut(),
Chris@163 1578 tr("Re-open the current or most recently opened file"));
Chris@162 1579 }
Chris@0 1580 m_recentFilesMenu->addAction(action);
Chris@0 1581 }
Chris@0 1582 }
Chris@0 1583
Chris@0 1584 void
Chris@34 1585 MainWindow::setupRecentTransformsMenu()
Chris@34 1586 {
Chris@34 1587 m_recentTransformsMenu->clear();
Chris@34 1588 vector<QString> transforms = m_recentTransforms.getRecent();
Chris@34 1589 for (size_t i = 0; i < transforms.size(); ++i) {
Chris@34 1590 TransformActionReverseMap::iterator ti =
Chris@34 1591 m_transformActionsReverse.find(transforms[i]);
Chris@34 1592 if (ti == m_transformActionsReverse.end()) {
Chris@34 1593 std::cerr << "WARNING: MainWindow::setupRecentTransformsMenu: "
Chris@34 1594 << "Unknown transform \"" << transforms[i].toStdString()
Chris@34 1595 << "\" in recent transforms list" << std::endl;
Chris@34 1596 continue;
Chris@34 1597 }
Chris@162 1598 if (i == 0) {
Chris@162 1599 ti->second->setShortcut(tr("Ctrl+T"));
Chris@162 1600 m_keyReference->registerShortcut
Chris@163 1601 (tr("Repeat Transform"),
Chris@162 1602 ti->second->shortcut(),
Chris@163 1603 tr("Re-select the most recently run transform"));
Chris@162 1604 }
Chris@34 1605 m_recentTransformsMenu->addAction(ti->second);
Chris@34 1606 }
Chris@34 1607 }
Chris@34 1608
Chris@34 1609 void
Chris@95 1610 MainWindow::setupExistingLayersMenus()
Chris@0 1611 {
Chris@0 1612 if (!m_existingLayersMenu) return; // should have been created by setupMenus
Chris@0 1613
Chris@0 1614 // std::cerr << "MainWindow::setupExistingLayersMenu" << std::endl;
Chris@0 1615
Chris@0 1616 m_existingLayersMenu->clear();
Chris@0 1617 m_existingLayerActions.clear();
Chris@0 1618
Chris@95 1619 m_sliceMenu->clear();
Chris@95 1620 m_sliceActions.clear();
Chris@95 1621
Chris@168 1622 IconLoader il;
Chris@168 1623
Chris@33 1624 vector<Layer *> orderedLayers;
Chris@33 1625 set<Layer *> observedLayers;
Chris@95 1626 set<Layer *> sliceableLayers;
Chris@95 1627
Chris@95 1628 LayerFactory *factory = LayerFactory::getInstance();
Chris@0 1629
Chris@0 1630 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@0 1631
Chris@0 1632 Pane *pane = m_paneStack->getPane(i);
Chris@0 1633 if (!pane) continue;
Chris@0 1634
Chris@0 1635 for (int j = 0; j < pane->getLayerCount(); ++j) {
Chris@0 1636
Chris@0 1637 Layer *layer = pane->getLayer(j);
Chris@0 1638 if (!layer) continue;
Chris@0 1639 if (observedLayers.find(layer) != observedLayers.end()) {
Chris@137 1640 // std::cerr << "found duplicate layer " << layer << std::endl;
Chris@0 1641 continue;
Chris@0 1642 }
Chris@0 1643
Chris@0 1644 // std::cerr << "found new layer " << layer << " (name = "
Chris@0 1645 // << layer->getLayerPresentationName().toStdString() << ")" << std::endl;
Chris@0 1646
Chris@0 1647 orderedLayers.push_back(layer);
Chris@0 1648 observedLayers.insert(layer);
Chris@95 1649
Chris@95 1650 if (factory->isLayerSliceable(layer)) {
Chris@95 1651 sliceableLayers.insert(layer);
Chris@95 1652 }
Chris@0 1653 }
Chris@0 1654 }
Chris@0 1655
Chris@33 1656 map<QString, int> observedNames;
Chris@0 1657
Chris@137 1658 for (size_t i = 0; i < orderedLayers.size(); ++i) {
Chris@0 1659
Chris@95 1660 Layer *layer = orderedLayers[i];
Chris@95 1661
Chris@95 1662 QString name = layer->getLayerPresentationName();
Chris@0 1663 int n = ++observedNames[name];
Chris@0 1664 if (n > 1) name = QString("%1 <%2>").arg(name).arg(n);
Chris@0 1665
Chris@168 1666 QIcon icon = il.load(factory->getLayerIconName
Chris@168 1667 (factory->getLayerType(layer)));
Chris@95 1668
Chris@95 1669 QAction *action = new QAction(icon, name, this);
Chris@0 1670 connect(action, SIGNAL(triggered()), this, SLOT(addLayer()));
Chris@0 1671 connect(this, SIGNAL(canAddLayer(bool)), action, SLOT(setEnabled(bool)));
Chris@95 1672 m_existingLayerActions[action] = layer;
Chris@0 1673
Chris@0 1674 m_existingLayersMenu->addAction(action);
Chris@95 1675
Chris@95 1676 if (sliceableLayers.find(layer) != sliceableLayers.end()) {
Chris@95 1677 action = new QAction(icon, name, this);
Chris@95 1678 connect(action, SIGNAL(triggered()), this, SLOT(addLayer()));
Chris@95 1679 connect(this, SIGNAL(canAddLayer(bool)), action, SLOT(setEnabled(bool)));
Chris@95 1680 m_sliceActions[action] = layer;
Chris@95 1681 m_sliceMenu->addAction(action);
Chris@95 1682 }
Chris@0 1683 }
Chris@95 1684
Chris@95 1685 m_sliceMenu->setEnabled(!m_sliceActions.empty());
Chris@0 1686 }
Chris@0 1687
Chris@0 1688 void
Chris@0 1689 MainWindow::setupToolbars()
Chris@0 1690 {
Chris@162 1691 m_keyReference->setCategory(tr("Playback and Transport Controls"));
Chris@162 1692
Chris@168 1693 IconLoader il;
Chris@168 1694
Chris@155 1695 QMenu *menu = m_playbackMenu = menuBar()->addMenu(tr("Play&back"));
Chris@155 1696 menu->setTearOffEnabled(true);
Chris@155 1697 m_rightButtonMenu->addSeparator();
Chris@155 1698 m_rightButtonPlaybackMenu = m_rightButtonMenu->addMenu(tr("Playback"));
Chris@155 1699
Chris@155 1700 QToolBar *toolbar = addToolBar(tr("Playback Toolbar"));
Chris@155 1701
Chris@168 1702 QAction *rwdStartAction = toolbar->addAction(il.load("rewind-start"),
Chris@155 1703 tr("Rewind to Start"));
Chris@155 1704 rwdStartAction->setShortcut(tr("Home"));
Chris@155 1705 rwdStartAction->setStatusTip(tr("Rewind to the start"));
Chris@155 1706 connect(rwdStartAction, SIGNAL(triggered()), this, SLOT(rewindStart()));
Chris@155 1707 connect(this, SIGNAL(canPlay(bool)), rwdStartAction, SLOT(setEnabled(bool)));
Chris@155 1708
Chris@168 1709 QAction *m_rwdAction = toolbar->addAction(il.load("rewind"),
Chris@155 1710 tr("Rewind"));
Chris@155 1711 m_rwdAction->setShortcut(tr("PgUp"));
Chris@163 1712 m_rwdAction->setStatusTip(tr("Rewind to the previous time instant or time ruler notch"));
Chris@155 1713 connect(m_rwdAction, SIGNAL(triggered()), this, SLOT(rewind()));
Chris@155 1714 connect(this, SIGNAL(canRewind(bool)), m_rwdAction, SLOT(setEnabled(bool)));
Chris@155 1715
Chris@168 1716 QAction *playAction = toolbar->addAction(il.load("playpause"),
Chris@155 1717 tr("Play / Pause"));
Chris@155 1718 playAction->setCheckable(true);
Chris@155 1719 playAction->setShortcut(tr("Space"));
Chris@155 1720 playAction->setStatusTip(tr("Start or stop playback from the current position"));
Chris@155 1721 connect(playAction, SIGNAL(triggered()), this, SLOT(play()));
Chris@0 1722 connect(m_playSource, SIGNAL(playStatusChanged(bool)),
Chris@155 1723 playAction, SLOT(setChecked(bool)));
Chris@155 1724 connect(this, SIGNAL(canPlay(bool)), playAction, SLOT(setEnabled(bool)));
Chris@155 1725
Chris@168 1726 m_ffwdAction = toolbar->addAction(il.load("ffwd"),
Chris@155 1727 tr("Fast Forward"));
Chris@155 1728 m_ffwdAction->setShortcut(tr("PgDown"));
Chris@163 1729 m_ffwdAction->setStatusTip(tr("Fast-forward to the next time instant or time ruler notch"));
Chris@155 1730 connect(m_ffwdAction, SIGNAL(triggered()), this, SLOT(ffwd()));
Chris@155 1731 connect(this, SIGNAL(canFfwd(bool)), m_ffwdAction, SLOT(setEnabled(bool)));
Chris@155 1732
Chris@168 1733 QAction *ffwdEndAction = toolbar->addAction(il.load("ffwd-end"),
Chris@155 1734 tr("Fast Forward to End"));
Chris@155 1735 ffwdEndAction->setShortcut(tr("End"));
Chris@155 1736 ffwdEndAction->setStatusTip(tr("Fast-forward to the end"));
Chris@155 1737 connect(ffwdEndAction, SIGNAL(triggered()), this, SLOT(ffwdEnd()));
Chris@155 1738 connect(this, SIGNAL(canPlay(bool)), ffwdEndAction, SLOT(setEnabled(bool)));
Chris@0 1739
Chris@0 1740 toolbar = addToolBar(tr("Play Mode Toolbar"));
Chris@0 1741
Chris@168 1742 QAction *psAction = toolbar->addAction(il.load("playselection"),
Chris@155 1743 tr("Constrain Playback to Selection"));
Chris@155 1744 psAction->setCheckable(true);
Chris@155 1745 psAction->setChecked(m_viewManager->getPlaySelectionMode());
Chris@155 1746 psAction->setShortcut(tr("s"));
Chris@163 1747 psAction->setStatusTip(tr("Constrain playback to the selected regions"));
Chris@69 1748 connect(m_viewManager, SIGNAL(playSelectionModeChanged(bool)),
Chris@155 1749 psAction, SLOT(setChecked(bool)));
Chris@155 1750 connect(psAction, SIGNAL(triggered()), this, SLOT(playSelectionToggled()));
Chris@155 1751 connect(this, SIGNAL(canPlaySelection(bool)), psAction, SLOT(setEnabled(bool)));
Chris@155 1752
Chris@168 1753 QAction *plAction = toolbar->addAction(il.load("playloop"),
Chris@155 1754 tr("Loop Playback"));
Chris@155 1755 plAction->setCheckable(true);
Chris@155 1756 plAction->setChecked(m_viewManager->getPlayLoopMode());
Chris@155 1757 plAction->setShortcut(tr("l"));
Chris@155 1758 plAction->setStatusTip(tr("Loop playback"));
Chris@69 1759 connect(m_viewManager, SIGNAL(playLoopModeChanged(bool)),
Chris@155 1760 plAction, SLOT(setChecked(bool)));
Chris@155 1761 connect(plAction, SIGNAL(triggered()), this, SLOT(playLoopToggled()));
Chris@155 1762 connect(this, SIGNAL(canPlay(bool)), plAction, SLOT(setEnabled(bool)));
Chris@155 1763
Chris@180 1764 QAction *soAction = toolbar->addAction(il.load("solo"),
Chris@180 1765 tr("Solo Current Pane"));
Chris@180 1766 soAction->setCheckable(true);
Chris@180 1767 soAction->setChecked(m_viewManager->getPlaySoloMode());
Chris@180 1768 soAction->setShortcut(tr("o"));
Chris@180 1769 soAction->setStatusTip(tr("Solo the current pane during playback"));
Chris@180 1770 connect(m_viewManager, SIGNAL(playSoloModeChanged(bool)),
Chris@180 1771 soAction, SLOT(setChecked(bool)));
Chris@180 1772 connect(soAction, SIGNAL(triggered()), this, SLOT(playSoloToggled()));
Chris@180 1773 connect(this, SIGNAL(canPlay(bool)), soAction, SLOT(setEnabled(bool)));
Chris@180 1774
Chris@162 1775 m_keyReference->registerShortcut(playAction);
Chris@162 1776 m_keyReference->registerShortcut(psAction);
Chris@162 1777 m_keyReference->registerShortcut(plAction);
Chris@180 1778 m_keyReference->registerShortcut(soAction);
Chris@162 1779 m_keyReference->registerShortcut(m_rwdAction);
Chris@162 1780 m_keyReference->registerShortcut(m_ffwdAction);
Chris@162 1781 m_keyReference->registerShortcut(rwdStartAction);
Chris@162 1782 m_keyReference->registerShortcut(ffwdEndAction);
Chris@162 1783
Chris@155 1784 menu->addAction(playAction);
Chris@155 1785 menu->addAction(psAction);
Chris@155 1786 menu->addAction(plAction);
Chris@180 1787 menu->addAction(soAction);
Chris@155 1788 menu->addSeparator();
Chris@155 1789 menu->addAction(m_rwdAction);
Chris@155 1790 menu->addAction(m_ffwdAction);
Chris@155 1791 menu->addSeparator();
Chris@155 1792 menu->addAction(rwdStartAction);
Chris@155 1793 menu->addAction(ffwdEndAction);
Chris@155 1794 menu->addSeparator();
Chris@155 1795
Chris@155 1796 m_rightButtonPlaybackMenu->addAction(playAction);
Chris@155 1797 m_rightButtonPlaybackMenu->addAction(psAction);
Chris@155 1798 m_rightButtonPlaybackMenu->addAction(plAction);
Chris@180 1799 m_rightButtonPlaybackMenu->addAction(soAction);
Chris@155 1800 m_rightButtonPlaybackMenu->addSeparator();
Chris@155 1801 m_rightButtonPlaybackMenu->addAction(m_rwdAction);
Chris@155 1802 m_rightButtonPlaybackMenu->addAction(m_ffwdAction);
Chris@155 1803 m_rightButtonPlaybackMenu->addSeparator();
Chris@155 1804 m_rightButtonPlaybackMenu->addAction(rwdStartAction);
Chris@155 1805 m_rightButtonPlaybackMenu->addAction(ffwdEndAction);
Chris@155 1806 m_rightButtonPlaybackMenu->addSeparator();
Chris@155 1807
Chris@155 1808 QAction *fastAction = menu->addAction(tr("Speed Up"));
Chris@155 1809 fastAction->setShortcut(tr("Ctrl+PgUp"));
Chris@163 1810 fastAction->setStatusTip(tr("Time-stretch playback to speed it up without changing pitch"));
Chris@155 1811 connect(fastAction, SIGNAL(triggered()), this, SLOT(speedUpPlayback()));
Chris@155 1812 connect(this, SIGNAL(canSpeedUpPlayback(bool)), fastAction, SLOT(setEnabled(bool)));
Chris@155 1813
Chris@155 1814 QAction *slowAction = menu->addAction(tr("Slow Down"));
Chris@155 1815 slowAction->setShortcut(tr("Ctrl+PgDown"));
Chris@163 1816 slowAction->setStatusTip(tr("Time-stretch playback to slow it down without changing pitch"));
Chris@155 1817 connect(slowAction, SIGNAL(triggered()), this, SLOT(slowDownPlayback()));
Chris@155 1818 connect(this, SIGNAL(canSlowDownPlayback(bool)), slowAction, SLOT(setEnabled(bool)));
Chris@155 1819
Chris@155 1820 QAction *normalAction = menu->addAction(tr("Restore Normal Speed"));
Chris@155 1821 normalAction->setShortcut(tr("Ctrl+Home"));
Chris@163 1822 normalAction->setStatusTip(tr("Restore non-time-stretched playback"));
Chris@155 1823 connect(normalAction, SIGNAL(triggered()), this, SLOT(restoreNormalPlayback()));
Chris@155 1824 connect(this, SIGNAL(canChangePlaybackSpeed(bool)), normalAction, SLOT(setEnabled(bool)));
Chris@155 1825
Chris@162 1826 m_keyReference->registerShortcut(fastAction);
Chris@162 1827 m_keyReference->registerShortcut(slowAction);
Chris@162 1828 m_keyReference->registerShortcut(normalAction);
Chris@162 1829
Chris@155 1830 m_rightButtonPlaybackMenu->addAction(fastAction);
Chris@155 1831 m_rightButtonPlaybackMenu->addAction(slowAction);
Chris@155 1832 m_rightButtonPlaybackMenu->addAction(normalAction);
Chris@0 1833
Chris@0 1834 toolbar = addToolBar(tr("Edit Toolbar"));
Chris@0 1835 CommandHistory::getInstance()->registerToolbar(toolbar);
Chris@0 1836
Chris@162 1837 m_keyReference->setCategory(tr("Tool Selection"));
Chris@162 1838
Chris@0 1839 toolbar = addToolBar(tr("Tools Toolbar"));
Chris@0 1840 QActionGroup *group = new QActionGroup(this);
Chris@0 1841
Chris@168 1842 QAction *action = toolbar->addAction(il.load("navigate"),
Chris@155 1843 tr("Navigate"));
Chris@0 1844 action->setCheckable(true);
Chris@0 1845 action->setChecked(true);
Chris@0 1846 action->setShortcut(tr("1"));
Chris@90 1847 action->setStatusTip(tr("Navigate"));
Chris@0 1848 connect(action, SIGNAL(triggered()), this, SLOT(toolNavigateSelected()));
Chris@0 1849 group->addAction(action);
Chris@162 1850 m_keyReference->registerShortcut(action);
Chris@0 1851 m_toolActions[ViewManager::NavigateMode] = action;
Chris@0 1852
Chris@168 1853 action = toolbar->addAction(il.load("select"),
Chris@0 1854 tr("Select"));
Chris@0 1855 action->setCheckable(true);
Chris@0 1856 action->setShortcut(tr("2"));
Chris@90 1857 action->setStatusTip(tr("Select ranges"));
Chris@0 1858 connect(action, SIGNAL(triggered()), this, SLOT(toolSelectSelected()));
Chris@0 1859 group->addAction(action);
Chris@162 1860 m_keyReference->registerShortcut(action);
Chris@0 1861 m_toolActions[ViewManager::SelectMode] = action;
Chris@0 1862
Chris@168 1863 action = toolbar->addAction(il.load("move"),
Chris@0 1864 tr("Edit"));
Chris@0 1865 action->setCheckable(true);
Chris@0 1866 action->setShortcut(tr("3"));
Chris@90 1867 action->setStatusTip(tr("Edit items in layer"));
Chris@0 1868 connect(action, SIGNAL(triggered()), this, SLOT(toolEditSelected()));
Chris@0 1869 connect(this, SIGNAL(canEditLayer(bool)), action, SLOT(setEnabled(bool)));
Chris@0 1870 group->addAction(action);
Chris@162 1871 m_keyReference->registerShortcut(action);
Chris@0 1872 m_toolActions[ViewManager::EditMode] = action;
Chris@0 1873
Chris@168 1874 action = toolbar->addAction(il.load("draw"),
Chris@0 1875 tr("Draw"));
Chris@0 1876 action->setCheckable(true);
Chris@0 1877 action->setShortcut(tr("4"));
Chris@90 1878 action->setStatusTip(tr("Draw new items in layer"));
Chris@0 1879 connect(action, SIGNAL(triggered()), this, SLOT(toolDrawSelected()));
Chris@0 1880 connect(this, SIGNAL(canEditLayer(bool)), action, SLOT(setEnabled(bool)));
Chris@0 1881 group->addAction(action);
Chris@162 1882 m_keyReference->registerShortcut(action);
Chris@0 1883 m_toolActions[ViewManager::DrawMode] = action;
Chris@0 1884
Chris@168 1885 action = toolbar->addAction(il.load("measure"),
Chris@151 1886 tr("Measure"));
Chris@151 1887 action->setCheckable(true);
Chris@151 1888 action->setShortcut(tr("5"));
Chris@151 1889 action->setStatusTip(tr("Make measurements in layer"));
Chris@151 1890 connect(action, SIGNAL(triggered()), this, SLOT(toolMeasureSelected()));
Chris@169 1891 connect(this, SIGNAL(canMeasureLayer(bool)), action, SLOT(setEnabled(bool)));
Chris@151 1892 group->addAction(action);
Chris@162 1893 m_keyReference->registerShortcut(action);
Chris@151 1894 m_toolActions[ViewManager::MeasureMode] = action;
Chris@151 1895
Chris@168 1896 // action = toolbar->addAction(il.load("text"),
Chris@0 1897 // tr("Text"));
Chris@0 1898 // action->setCheckable(true);
Chris@0 1899 // action->setShortcut(tr("5"));
Chris@0 1900 // connect(action, SIGNAL(triggered()), this, SLOT(toolTextSelected()));
Chris@0 1901 // group->addAction(action);
Chris@0 1902 // m_toolActions[ViewManager::TextMode] = action;
Chris@0 1903
Chris@0 1904 toolNavigateSelected();
Chris@163 1905
Chris@163 1906 Pane::registerShortcuts(*m_keyReference);
Chris@0 1907 }
Chris@0 1908
Chris@0 1909 void
Chris@0 1910 MainWindow::updateMenuStates()
Chris@0 1911 {
Chris@117 1912 Pane *currentPane = 0;
Chris@117 1913 Layer *currentLayer = 0;
Chris@117 1914
Chris@117 1915 if (m_paneStack) currentPane = m_paneStack->getCurrentPane();
Chris@117 1916 if (currentPane) currentLayer = currentPane->getSelectedLayer();
Chris@117 1917
Chris@0 1918 bool haveCurrentPane =
Chris@117 1919 (currentPane != 0);
Chris@0 1920 bool haveCurrentLayer =
Chris@117 1921 (haveCurrentPane &&
Chris@117 1922 (currentLayer != 0));
Chris@0 1923 bool haveMainModel =
Chris@0 1924 (getMainModel() != 0);
Chris@0 1925 bool havePlayTarget =
Chris@0 1926 (m_playTarget != 0);
Chris@0 1927 bool haveSelection =
Chris@0 1928 (m_viewManager &&
Chris@0 1929 !m_viewManager->getSelections().empty());
Chris@0 1930 bool haveCurrentEditableLayer =
Chris@0 1931 (haveCurrentLayer &&
Chris@117 1932 currentLayer->isLayerEditable());
Chris@0 1933 bool haveCurrentTimeInstantsLayer =
Chris@0 1934 (haveCurrentLayer &&
Chris@117 1935 dynamic_cast<TimeInstantLayer *>(currentLayer));
Chris@0 1936 bool haveCurrentTimeValueLayer =
Chris@0 1937 (haveCurrentLayer &&
Chris@117 1938 dynamic_cast<TimeValueLayer *>(currentLayer));
Chris@0 1939 bool haveCurrentColour3DPlot =
Chris@0 1940 (haveCurrentLayer &&
Chris@117 1941 dynamic_cast<Colour3DPlotLayer *>(currentLayer));
Chris@0 1942 bool haveClipboardContents =
Chris@0 1943 (m_viewManager &&
Chris@0 1944 !m_viewManager->getClipboard().empty());
Chris@0 1945
Chris@0 1946 emit canAddPane(haveMainModel);
Chris@0 1947 emit canDeleteCurrentPane(haveCurrentPane);
Chris@0 1948 emit canZoom(haveMainModel && haveCurrentPane);
Chris@0 1949 emit canScroll(haveMainModel && haveCurrentPane);
Chris@0 1950 emit canAddLayer(haveMainModel && haveCurrentPane);
Chris@0 1951 emit canImportMoreAudio(haveMainModel);
Chris@0 1952 emit canImportLayer(haveMainModel && haveCurrentPane);
Chris@0 1953 emit canExportAudio(haveMainModel);
Chris@0 1954 emit canExportLayer(haveMainModel &&
Chris@0 1955 (haveCurrentEditableLayer || haveCurrentColour3DPlot));
Chris@121 1956 emit canExportImage(haveMainModel && haveCurrentPane);
Chris@0 1957 emit canDeleteCurrentLayer(haveCurrentLayer);
Chris@0 1958 emit canRenameLayer(haveCurrentLayer);
Chris@0 1959 emit canEditLayer(haveCurrentEditableLayer);
Chris@169 1960 emit canMeasureLayer(haveCurrentLayer);
Chris@0 1961 emit canSelect(haveMainModel && haveCurrentPane);
Chris@155 1962 emit canPlay(havePlayTarget);
Chris@155 1963 emit canFfwd(true);
Chris@155 1964 emit canRewind(true);
Chris@0 1965 emit canPaste(haveCurrentEditableLayer && haveClipboardContents);
Chris@0 1966 emit canInsertInstant(haveCurrentPane);
Chris@81 1967 emit canInsertInstantsAtBoundaries(haveCurrentPane && haveSelection);
Chris@189 1968 emit canRenumberInstants(haveCurrentTimeInstantsLayer && haveSelection);
Chris@0 1969 emit canPlaySelection(haveMainModel && havePlayTarget && haveSelection);
Chris@0 1970 emit canClearSelection(haveSelection);
Chris@0 1971 emit canEditSelection(haveSelection && haveCurrentEditableLayer);
Chris@0 1972 emit canSave(m_sessionFile != "" && m_documentModified);
Chris@155 1973
Chris@164 1974 if (m_viewManager &&
Chris@164 1975 (m_viewManager->getToolMode() == ViewManager::MeasureMode)) {
Chris@164 1976 emit canDeleteSelection(haveCurrentLayer);
Chris@164 1977 m_deleteSelectedAction->setText(tr("&Delete Current Measurement"));
Chris@164 1978 m_deleteSelectedAction->setStatusTip(tr("Delete the measurement currently under the mouse pointer"));
Chris@164 1979 } else {
Chris@164 1980 emit canDeleteSelection(haveSelection && haveCurrentEditableLayer);
Chris@164 1981 m_deleteSelectedAction->setText(tr("&Delete Selected Items"));
Chris@164 1982 m_deleteSelectedAction->setStatusTip(tr("Delete items in current selection from the current layer"));
Chris@164 1983 }
Chris@164 1984
Chris@155 1985 emit canChangePlaybackSpeed(true);
Chris@155 1986 int v = m_playSpeed->value();
Chris@155 1987 emit canSpeedUpPlayback(v < m_playSpeed->maximum());
Chris@155 1988 emit canSlowDownPlayback(v > m_playSpeed->minimum());
Chris@155 1989
Chris@155 1990 if (m_ffwdAction && m_rwdAction) {
Chris@155 1991 if (haveCurrentTimeInstantsLayer) {
Chris@155 1992 m_ffwdAction->setText(tr("Fast Forward to Next Instant"));
Chris@155 1993 m_ffwdAction->setStatusTip(tr("Fast forward to the next time instant in the current layer"));
Chris@155 1994 m_rwdAction->setText(tr("Rewind to Previous Instant"));
Chris@155 1995 m_rwdAction->setStatusTip(tr("Rewind to the previous time instant in the current layer"));
Chris@155 1996 } else if (haveCurrentTimeValueLayer) {
Chris@155 1997 m_ffwdAction->setText(tr("Fast Forward to Next Point"));
Chris@155 1998 m_ffwdAction->setStatusTip(tr("Fast forward to the next point in the current layer"));
Chris@155 1999 m_rwdAction->setText(tr("Rewind to Previous Point"));
Chris@155 2000 m_rwdAction->setStatusTip(tr("Rewind to the previous point in the current layer"));
Chris@155 2001 } else {
Chris@155 2002 m_ffwdAction->setText(tr("Fast Forward"));
Chris@155 2003 m_ffwdAction->setStatusTip(tr("Fast forward"));
Chris@155 2004 m_rwdAction->setText(tr("Rewind"));
Chris@155 2005 m_rwdAction->setStatusTip(tr("Rewind"));
Chris@155 2006 }
Chris@155 2007 }
Chris@0 2008 }
Chris@0 2009
Chris@0 2010 void
Chris@0 2011 MainWindow::updateDescriptionLabel()
Chris@0 2012 {
Chris@0 2013 if (!getMainModel()) {
Chris@0 2014 m_descriptionLabel->setText(tr("No audio file loaded."));
Chris@0 2015 return;
Chris@0 2016 }
Chris@0 2017
Chris@0 2018 QString description;
Chris@0 2019
Chris@0 2020 size_t ssr = getMainModel()->getSampleRate();
Chris@0 2021 size_t tsr = ssr;
Chris@0 2022 if (m_playSource) tsr = m_playSource->getTargetSampleRate();
Chris@0 2023
Chris@0 2024 if (ssr != tsr) {
Chris@0 2025 description = tr("%1Hz (resampling to %2Hz)").arg(ssr).arg(tsr);
Chris@0 2026 } else {
Chris@0 2027 description = QString("%1Hz").arg(ssr);
Chris@0 2028 }
Chris@0 2029
Chris@0 2030 description = QString("%1 - %2")
Chris@0 2031 .arg(RealTime::frame2RealTime(getMainModel()->getEndFrame(), ssr)
Chris@0 2032 .toText(false).c_str())
Chris@0 2033 .arg(description);
Chris@0 2034
Chris@0 2035 m_descriptionLabel->setText(description);
Chris@0 2036 }
Chris@0 2037
Chris@0 2038 void
Chris@0 2039 MainWindow::documentModified()
Chris@0 2040 {
Chris@0 2041 // std::cerr << "MainWindow::documentModified" << std::endl;
Chris@0 2042
Chris@0 2043 if (!m_documentModified) {
Chris@0 2044 setWindowTitle(tr("%1 (modified)").arg(windowTitle()));
Chris@0 2045 }
Chris@0 2046
Chris@0 2047 m_documentModified = true;
Chris@0 2048 updateMenuStates();
Chris@0 2049 }
Chris@0 2050
Chris@0 2051 void
Chris@0 2052 MainWindow::documentRestored()
Chris@0 2053 {
Chris@0 2054 // std::cerr << "MainWindow::documentRestored" << std::endl;
Chris@0 2055
Chris@0 2056 if (m_documentModified) {
Chris@0 2057 QString wt(windowTitle());
Chris@0 2058 wt.replace(tr(" (modified)"), "");
Chris@0 2059 setWindowTitle(wt);
Chris@0 2060 }
Chris@0 2061
Chris@0 2062 m_documentModified = false;
Chris@0 2063 updateMenuStates();
Chris@0 2064 }
Chris@0 2065
Chris@0 2066 void
Chris@0 2067 MainWindow::playLoopToggled()
Chris@0 2068 {
Chris@0 2069 QAction *action = dynamic_cast<QAction *>(sender());
Chris@0 2070
Chris@0 2071 if (action) {
Chris@0 2072 m_viewManager->setPlayLoopMode(action->isChecked());
Chris@0 2073 } else {
Chris@0 2074 m_viewManager->setPlayLoopMode(!m_viewManager->getPlayLoopMode());
Chris@0 2075 }
Chris@0 2076 }
Chris@0 2077
Chris@0 2078 void
Chris@0 2079 MainWindow::playSelectionToggled()
Chris@0 2080 {
Chris@0 2081 QAction *action = dynamic_cast<QAction *>(sender());
Chris@0 2082
Chris@0 2083 if (action) {
Chris@0 2084 m_viewManager->setPlaySelectionMode(action->isChecked());
Chris@0 2085 } else {
Chris@0 2086 m_viewManager->setPlaySelectionMode(!m_viewManager->getPlaySelectionMode());
Chris@0 2087 }
Chris@0 2088 }
Chris@0 2089
Chris@0 2090 void
Chris@180 2091 MainWindow::playSoloToggled()
Chris@180 2092 {
Chris@180 2093 QAction *action = dynamic_cast<QAction *>(sender());
Chris@180 2094
Chris@180 2095 if (action) {
Chris@180 2096 m_viewManager->setPlaySoloMode(action->isChecked());
Chris@180 2097 } else {
Chris@180 2098 m_viewManager->setPlaySoloMode(!m_viewManager->getPlaySoloMode());
Chris@180 2099 }
Chris@180 2100
Chris@184 2101 if (m_viewManager->getPlaySoloMode()) {
Chris@184 2102 currentPaneChanged(m_paneStack->getCurrentPane());
Chris@184 2103 } else {
Chris@180 2104 m_viewManager->setPlaybackModel(0);
Chris@180 2105 if (m_playSource) {
Chris@180 2106 m_playSource->clearSoloModelSet();
Chris@180 2107 }
Chris@180 2108 }
Chris@180 2109 }
Chris@180 2110
Chris@180 2111 void
Chris@116 2112 MainWindow::currentPaneChanged(Pane *p)
Chris@0 2113 {
Chris@0 2114 updateMenuStates();
Chris@116 2115 updateVisibleRangeDisplay(p);
Chris@180 2116
Chris@180 2117 if (!p) return;
Chris@180 2118
Chris@180 2119 if (!(m_viewManager &&
Chris@180 2120 m_playSource &&
Chris@180 2121 m_viewManager->getPlaySoloMode())) {
Chris@180 2122 if (m_viewManager) m_viewManager->setPlaybackModel(0);
Chris@180 2123 return;
Chris@180 2124 }
Chris@180 2125
Chris@180 2126 Model *prevPlaybackModel = m_viewManager->getPlaybackModel();
Chris@180 2127
Chris@180 2128 std::set<Model *> soloModels;
Chris@180 2129
Chris@180 2130 for (int i = 0; i < p->getLayerCount(); ++i) {
Chris@180 2131 Layer *layer = p->getLayer(i);
Chris@180 2132 if (dynamic_cast<TimeRulerLayer *>(layer)) {
Chris@180 2133 continue;
Chris@180 2134 }
Chris@180 2135 if (layer && layer->getModel()) {
Chris@180 2136 Model *model = layer->getModel();
Chris@180 2137 if (dynamic_cast<RangeSummarisableTimeValueModel *>(model)) {
Chris@180 2138 m_viewManager->setPlaybackModel(model);
Chris@180 2139 }
Chris@180 2140 soloModels.insert(model);
Chris@180 2141 }
Chris@180 2142 }
Chris@180 2143
Chris@180 2144 RangeSummarisableTimeValueModel *a =
Chris@180 2145 dynamic_cast<RangeSummarisableTimeValueModel *>(prevPlaybackModel);
Chris@180 2146 RangeSummarisableTimeValueModel *b =
Chris@180 2147 dynamic_cast<RangeSummarisableTimeValueModel *>(m_viewManager->
Chris@180 2148 getPlaybackModel());
Chris@180 2149
Chris@180 2150 m_playSource->setSoloModelSet(soloModels);
Chris@180 2151
Chris@180 2152 if (a && b && (a != b)) {
Chris@180 2153 int frame = m_playSource->getCurrentPlayingFrame();
Chris@180 2154 //!!! I don't really believe that these functions are the right way around
Chris@180 2155 int rframe = a->alignFromReference(frame);
Chris@180 2156 int bframe = b->alignToReference(rframe);
Chris@180 2157 if (m_playSource->isPlaying()) m_playSource->play(bframe);
Chris@180 2158 }
Chris@0 2159 }
Chris@0 2160
Chris@0 2161 void
Chris@116 2162 MainWindow::currentLayerChanged(Pane *p, Layer *)
Chris@0 2163 {
Chris@0 2164 updateMenuStates();
Chris@116 2165 updateVisibleRangeDisplay(p);
Chris@0 2166 }
Chris@0 2167
Chris@0 2168 void
Chris@0 2169 MainWindow::toolNavigateSelected()
Chris@0 2170 {
Chris@0 2171 m_viewManager->setToolMode(ViewManager::NavigateMode);
Chris@0 2172 }
Chris@0 2173
Chris@0 2174 void
Chris@0 2175 MainWindow::toolSelectSelected()
Chris@0 2176 {
Chris@0 2177 m_viewManager->setToolMode(ViewManager::SelectMode);
Chris@0 2178 }
Chris@0 2179
Chris@0 2180 void
Chris@0 2181 MainWindow::toolEditSelected()
Chris@0 2182 {
Chris@0 2183 m_viewManager->setToolMode(ViewManager::EditMode);
Chris@0 2184 }
Chris@0 2185
Chris@0 2186 void
Chris@0 2187 MainWindow::toolDrawSelected()
Chris@0 2188 {
Chris@0 2189 m_viewManager->setToolMode(ViewManager::DrawMode);
Chris@0 2190 }
Chris@0 2191
Chris@151 2192 void
Chris@151 2193 MainWindow::toolMeasureSelected()
Chris@151 2194 {
Chris@151 2195 m_viewManager->setToolMode(ViewManager::MeasureMode);
Chris@151 2196 }
Chris@151 2197
Chris@0 2198 //void
Chris@0 2199 //MainWindow::toolTextSelected()
Chris@0 2200 //{
Chris@0 2201 // m_viewManager->setToolMode(ViewManager::TextMode);
Chris@0 2202 //}
Chris@0 2203
Chris@0 2204 void
Chris@0 2205 MainWindow::selectAll()
Chris@0 2206 {
Chris@0 2207 if (!getMainModel()) return;
Chris@0 2208 m_viewManager->setSelection(Selection(getMainModel()->getStartFrame(),
Chris@0 2209 getMainModel()->getEndFrame()));
Chris@0 2210 }
Chris@0 2211
Chris@0 2212 void
Chris@0 2213 MainWindow::selectToStart()
Chris@0 2214 {
Chris@0 2215 if (!getMainModel()) return;
Chris@0 2216 m_viewManager->setSelection(Selection(getMainModel()->getStartFrame(),
Chris@0 2217 m_viewManager->getGlobalCentreFrame()));
Chris@0 2218 }
Chris@0 2219
Chris@0 2220 void
Chris@0 2221 MainWindow::selectToEnd()
Chris@0 2222 {
Chris@0 2223 if (!getMainModel()) return;
Chris@0 2224 m_viewManager->setSelection(Selection(m_viewManager->getGlobalCentreFrame(),
Chris@0 2225 getMainModel()->getEndFrame()));
Chris@0 2226 }
Chris@0 2227
Chris@0 2228 void
Chris@0 2229 MainWindow::selectVisible()
Chris@0 2230 {
Chris@0 2231 Model *model = getMainModel();
Chris@0 2232 if (!model) return;
Chris@0 2233
Chris@0 2234 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@0 2235 if (!currentPane) return;
Chris@0 2236
Chris@0 2237 size_t startFrame, endFrame;
Chris@0 2238
Chris@0 2239 if (currentPane->getStartFrame() < 0) startFrame = 0;
Chris@0 2240 else startFrame = currentPane->getStartFrame();
Chris@0 2241
Chris@0 2242 if (currentPane->getEndFrame() > model->getEndFrame()) endFrame = model->getEndFrame();
Chris@0 2243 else endFrame = currentPane->getEndFrame();
Chris@0 2244
Chris@0 2245 m_viewManager->setSelection(Selection(startFrame, endFrame));
Chris@0 2246 }
Chris@0 2247
Chris@0 2248 void
Chris@0 2249 MainWindow::clearSelection()
Chris@0 2250 {
Chris@0 2251 m_viewManager->clearSelections();
Chris@0 2252 }
Chris@0 2253
Chris@0 2254 void
Chris@0 2255 MainWindow::cut()
Chris@0 2256 {
Chris@0 2257 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@0 2258 if (!currentPane) return;
Chris@0 2259
Chris@0 2260 Layer *layer = currentPane->getSelectedLayer();
Chris@0 2261 if (!layer) return;
Chris@0 2262
Chris@0 2263 Clipboard &clipboard = m_viewManager->getClipboard();
Chris@0 2264 clipboard.clear();
Chris@0 2265
Chris@0 2266 MultiSelection::SelectionList selections = m_viewManager->getSelections();
Chris@0 2267
Chris@0 2268 CommandHistory::getInstance()->startCompoundOperation(tr("Cut"), true);
Chris@0 2269
Chris@0 2270 for (MultiSelection::SelectionList::iterator i = selections.begin();
Chris@0 2271 i != selections.end(); ++i) {
Chris@0 2272 layer->copy(*i, clipboard);
Chris@0 2273 layer->deleteSelection(*i);
Chris@0 2274 }
Chris@0 2275
Chris@0 2276 CommandHistory::getInstance()->endCompoundOperation();
Chris@0 2277 }
Chris@0 2278
Chris@0 2279 void
Chris@0 2280 MainWindow::copy()
Chris@0 2281 {
Chris@0 2282 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@0 2283 if (!currentPane) return;
Chris@0 2284
Chris@0 2285 Layer *layer = currentPane->getSelectedLayer();
Chris@0 2286 if (!layer) return;
Chris@0 2287
Chris@0 2288 Clipboard &clipboard = m_viewManager->getClipboard();
Chris@0 2289 clipboard.clear();
Chris@0 2290
Chris@0 2291 MultiSelection::SelectionList selections = m_viewManager->getSelections();
Chris@0 2292
Chris@0 2293 for (MultiSelection::SelectionList::iterator i = selections.begin();
Chris@0 2294 i != selections.end(); ++i) {
Chris@0 2295 layer->copy(*i, clipboard);
Chris@0 2296 }
Chris@0 2297 }
Chris@0 2298
Chris@0 2299 void
Chris@0 2300 MainWindow::paste()
Chris@0 2301 {
Chris@0 2302 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@0 2303 if (!currentPane) return;
Chris@0 2304
Chris@0 2305 //!!! if we have no current layer, we should create one of the most
Chris@0 2306 // appropriate type
Chris@0 2307
Chris@0 2308 Layer *layer = currentPane->getSelectedLayer();
Chris@0 2309 if (!layer) return;
Chris@0 2310
Chris@0 2311 Clipboard &clipboard = m_viewManager->getClipboard();
Chris@0 2312 Clipboard::PointList contents = clipboard.getPoints();
Chris@0 2313 /*
Chris@0 2314 long minFrame = 0;
Chris@0 2315 bool have = false;
Chris@0 2316 for (int i = 0; i < contents.size(); ++i) {
Chris@0 2317 if (!contents[i].haveFrame()) continue;
Chris@0 2318 if (!have || contents[i].getFrame() < minFrame) {
Chris@0 2319 minFrame = contents[i].getFrame();
Chris@0 2320 have = true;
Chris@0 2321 }
Chris@0 2322 }
Chris@0 2323
Chris@0 2324 long frameOffset = long(m_viewManager->getGlobalCentreFrame()) - minFrame;
Chris@0 2325
Chris@0 2326 layer->paste(clipboard, frameOffset);
Chris@0 2327 */
Chris@0 2328 layer->paste(clipboard, 0, true);
Chris@0 2329 }
Chris@0 2330
Chris@0 2331 void
Chris@0 2332 MainWindow::deleteSelected()
Chris@0 2333 {
Chris@0 2334 if (m_paneStack->getCurrentPane() &&
Chris@0 2335 m_paneStack->getCurrentPane()->getSelectedLayer()) {
Chris@164 2336
Chris@164 2337 Layer *layer = m_paneStack->getCurrentPane()->getSelectedLayer();
Chris@164 2338
Chris@164 2339 if (m_viewManager &&
Chris@164 2340 (m_viewManager->getToolMode() == ViewManager::MeasureMode)) {
Chris@164 2341
Chris@164 2342 layer->deleteCurrentMeasureRect();
Chris@164 2343
Chris@164 2344 } else {
Chris@164 2345
Chris@164 2346 MultiSelection::SelectionList selections =
Chris@164 2347 m_viewManager->getSelections();
Chris@164 2348
Chris@164 2349 for (MultiSelection::SelectionList::iterator i = selections.begin();
Chris@164 2350 i != selections.end(); ++i) {
Chris@164 2351 layer->deleteSelection(*i);
Chris@164 2352 }
Chris@0 2353 }
Chris@0 2354 }
Chris@0 2355 }
Chris@0 2356
Chris@0 2357 void
Chris@0 2358 MainWindow::insertInstant()
Chris@0 2359 {
Chris@0 2360 int frame = m_viewManager->getPlaybackFrame();
Chris@81 2361 insertInstantAt(frame);
Chris@81 2362 }
Chris@81 2363
Chris@81 2364 void
Chris@81 2365 MainWindow::insertInstantsAtBoundaries()
Chris@81 2366 {
Chris@81 2367 MultiSelection::SelectionList selections = m_viewManager->getSelections();
Chris@81 2368 for (MultiSelection::SelectionList::iterator i = selections.begin();
Chris@81 2369 i != selections.end(); ++i) {
Chris@81 2370 size_t start = i->getStartFrame();
Chris@81 2371 size_t end = i->getEndFrame();
Chris@81 2372 if (start != end) {
Chris@81 2373 insertInstantAt(i->getStartFrame());
Chris@81 2374 insertInstantAt(i->getEndFrame());
Chris@81 2375 }
Chris@81 2376 }
Chris@81 2377 }
Chris@81 2378
Chris@81 2379 void
Chris@81 2380 MainWindow::insertInstantAt(size_t frame)
Chris@81 2381 {
Chris@0 2382 Pane *pane = m_paneStack->getCurrentPane();
Chris@0 2383 if (!pane) {
Chris@0 2384 return;
Chris@0 2385 }
Chris@0 2386
Chris@0 2387 Layer *layer = dynamic_cast<TimeInstantLayer *>
Chris@0 2388 (pane->getSelectedLayer());
Chris@0 2389
Chris@0 2390 if (!layer) {
Chris@0 2391 for (int i = pane->getLayerCount(); i > 0; --i) {
Chris@0 2392 layer = dynamic_cast<TimeInstantLayer *>(pane->getLayer(i - 1));
Chris@0 2393 if (layer) break;
Chris@0 2394 }
Chris@0 2395
Chris@0 2396 if (!layer) {
Chris@0 2397 CommandHistory::getInstance()->startCompoundOperation
Chris@0 2398 (tr("Add Point"), true);
Chris@0 2399 layer = m_document->createEmptyLayer(LayerFactory::TimeInstants);
Chris@0 2400 if (layer) {
Chris@0 2401 m_document->addLayerToView(pane, layer);
Chris@0 2402 m_paneStack->setCurrentLayer(pane, layer);
Chris@0 2403 }
Chris@0 2404 CommandHistory::getInstance()->endCompoundOperation();
Chris@0 2405 }
Chris@0 2406 }
Chris@0 2407
Chris@0 2408 if (layer) {
Chris@0 2409
Chris@0 2410 Model *model = layer->getModel();
Chris@0 2411 SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *>
Chris@0 2412 (model);
Chris@0 2413
Chris@0 2414 if (sodm) {
Chris@189 2415 SparseOneDimensionalModel::Point point(frame, "");
Chris@189 2416
Chris@189 2417 SparseOneDimensionalModel::Point prevPoint(0);
Chris@189 2418 bool havePrevPoint = false;
Chris@189 2419
Chris@189 2420 SparseOneDimensionalModel::EditCommand *command =
Chris@189 2421 new SparseOneDimensionalModel::EditCommand(sodm, tr("Add Point"));
Chris@189 2422
Chris@189 2423 if (m_labeller->actingOnPrevPoint()) {
Chris@189 2424
Chris@189 2425 SparseOneDimensionalModel::PointList prevPoints =
Chris@189 2426 sodm->getPreviousPoints(frame);
Chris@189 2427
Chris@189 2428 if (!prevPoints.empty()) {
Chris@189 2429 prevPoint = *prevPoints.begin();
Chris@189 2430 havePrevPoint = true;
Chris@189 2431 }
Chris@189 2432 }
Chris@189 2433
Chris@189 2434 if (m_labeller) {
Chris@189 2435
Chris@189 2436 m_labeller->setSampleRate(sodm->getSampleRate());
Chris@189 2437
Chris@189 2438 if (havePrevPoint) {
Chris@189 2439 command->deletePoint(prevPoint);
Chris@189 2440 }
Chris@189 2441
Chris@189 2442 m_labeller->label<SparseOneDimensionalModel::Point>
Chris@189 2443 (point, havePrevPoint ? &prevPoint : 0);
Chris@189 2444
Chris@189 2445 if (havePrevPoint) {
Chris@189 2446 command->addPoint(prevPoint);
Chris@189 2447 }
Chris@189 2448 }
Chris@189 2449
Chris@189 2450 command->addPoint(point);
Chris@189 2451
Chris@189 2452 command->setName(tr("Add Point at %1 s")
Chris@189 2453 .arg(RealTime::frame2RealTime
Chris@189 2454 (frame,
Chris@189 2455 sodm->getSampleRate())
Chris@189 2456 .toText(false).c_str()));
Chris@189 2457
Chris@189 2458 command->finish();
Chris@0 2459 }
Chris@0 2460 }
Chris@0 2461 }
Chris@0 2462
Chris@0 2463 void
Chris@189 2464 MainWindow::setInstantsNumbering()
Chris@189 2465 {
Chris@189 2466 QAction *a = dynamic_cast<QAction *>(sender());
Chris@189 2467 if (!a) return;
Chris@189 2468
Chris@189 2469 int type = m_numberingActions[a];
Chris@189 2470
Chris@189 2471 if (m_labeller) m_labeller->setType(Labeller::ValueType(type));
Chris@189 2472
Chris@189 2473 QSettings settings;
Chris@189 2474 settings.beginGroup("MainWindow");
Chris@189 2475 settings.setValue("labellertype", type);
Chris@189 2476 settings.endGroup();
Chris@189 2477 }
Chris@189 2478
Chris@189 2479 void
Chris@189 2480 MainWindow::setInstantsCounterCycle()
Chris@189 2481 {
Chris@189 2482 QAction *a = dynamic_cast<QAction *>(sender());
Chris@189 2483 if (!a) return;
Chris@189 2484
Chris@189 2485 int cycle = a->text().toInt();
Chris@189 2486 if (cycle == 0) return;
Chris@189 2487
Chris@189 2488 if (m_labeller) m_labeller->setCounterCycleSize(cycle);
Chris@189 2489
Chris@189 2490 QSettings settings;
Chris@189 2491 settings.beginGroup("MainWindow");
Chris@189 2492 settings.setValue("labellercycle", cycle);
Chris@189 2493 settings.endGroup();
Chris@189 2494 }
Chris@189 2495
Chris@189 2496 void
Chris@192 2497 MainWindow::resetInstantsCounters()
Chris@192 2498 {
Chris@192 2499 LabelCounterInputDialog dialog(m_labeller, this);
Chris@192 2500 dialog.exec();
Chris@192 2501 }
Chris@192 2502
Chris@192 2503 void
Chris@189 2504 MainWindow::renumberInstants()
Chris@189 2505 {
Chris@189 2506 Pane *pane = m_paneStack->getCurrentPane();
Chris@189 2507 if (!pane) return;
Chris@189 2508
Chris@189 2509 Layer *layer = dynamic_cast<TimeInstantLayer *>(pane->getSelectedLayer());
Chris@189 2510 if (!layer) return;
Chris@189 2511
Chris@189 2512 MultiSelection ms(m_viewManager->getSelection());
Chris@189 2513
Chris@189 2514 Model *model = layer->getModel();
Chris@189 2515 SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *>
Chris@189 2516 (model);
Chris@189 2517 if (!sodm) return;
Chris@189 2518
Chris@189 2519 if (!m_labeller) return;
Chris@189 2520
Chris@189 2521 Labeller labeller(*m_labeller);
Chris@189 2522 labeller.setSampleRate(sodm->getSampleRate());
Chris@189 2523
Chris@189 2524 // This uses a command
Chris@189 2525
Chris@189 2526 labeller.labelAll<SparseOneDimensionalModel::Point>(*sodm, &ms);
Chris@189 2527 }
Chris@189 2528
Chris@189 2529 void
Chris@0 2530 MainWindow::importAudio()
Chris@0 2531 {
Chris@88 2532 QString path = getOpenFileName(FileFinder::AudioFile);
Chris@0 2533
Chris@0 2534 if (path != "") {
Chris@82 2535 if (openAudioFile(path, ReplaceMainModel) == FileOpenFailed) {
Chris@0 2536 QMessageBox::critical(this, tr("Failed to open file"),
Chris@193 2537 tr("<b>File open failed</b><p>Audio file \"%1\" could not be opened").arg(path));
Chris@0 2538 }
Chris@0 2539 }
Chris@0 2540 }
Chris@0 2541
Chris@0 2542 void
Chris@0 2543 MainWindow::importMoreAudio()
Chris@0 2544 {
Chris@88 2545 QString path = getOpenFileName(FileFinder::AudioFile);
Chris@0 2546
Chris@0 2547 if (path != "") {
Chris@82 2548 if (openAudioFile(path, CreateAdditionalModel) == FileOpenFailed) {
Chris@0 2549 QMessageBox::critical(this, tr("Failed to open file"),
Chris@193 2550 tr("<b>File open failed</b><p>Audio file \"%1\" could not be opened").arg(path));
Chris@0 2551 }
Chris@0 2552 }
Chris@0 2553 }
Chris@0 2554
Chris@0 2555 void
Chris@0 2556 MainWindow::exportAudio()
Chris@0 2557 {
Chris@0 2558 if (!getMainModel()) return;
Chris@0 2559
Chris@88 2560 QString path = getSaveFileName(FileFinder::AudioFile);
Chris@0 2561
Chris@0 2562 if (path == "") return;
Chris@0 2563
Chris@0 2564 bool ok = false;
Chris@0 2565 QString error;
Chris@0 2566
Chris@0 2567 MultiSelection ms = m_viewManager->getSelection();
Chris@0 2568 MultiSelection::SelectionList selections = m_viewManager->getSelections();
Chris@0 2569
Chris@0 2570 bool multiple = false;
Chris@0 2571
Chris@38 2572 MultiSelection *selectionToWrite = 0;
Chris@38 2573
Chris@38 2574 if (selections.size() == 1) {
Chris@0 2575
Chris@0 2576 QStringList items;
Chris@0 2577 items << tr("Export the selected region only")
Chris@0 2578 << tr("Export the whole audio file");
Chris@0 2579
Chris@0 2580 bool ok = false;
Chris@0 2581 QString item = ListInputDialog::getItem
Chris@0 2582 (this, tr("Select region to export"),
Chris@0 2583 tr("Which region from the original audio file do you want to export?"),
Chris@0 2584 items, 0, &ok);
Chris@0 2585
Chris@0 2586 if (!ok || item.isEmpty()) return;
Chris@0 2587
Chris@38 2588 if (item == items[0]) selectionToWrite = &ms;
Chris@38 2589
Chris@38 2590 } else if (selections.size() > 1) {
Chris@0 2591
Chris@0 2592 QStringList items;
Chris@0 2593 items << tr("Export the selected regions into a single audio file")
Chris@0 2594 << tr("Export the selected regions into separate files")
Chris@0 2595 << tr("Export the whole audio file");
Chris@0 2596
Chris@0 2597 QString item = ListInputDialog::getItem
Chris@0 2598 (this, tr("Select region to export"),
Chris@0 2599 tr("Multiple regions of the original audio file are selected.\nWhat do you want to export?"),
Chris@0 2600 items, 0, &ok);
Chris@0 2601
Chris@0 2602 if (!ok || item.isEmpty()) return;
Chris@0 2603
Chris@0 2604 if (item == items[0]) {
Chris@0 2605
Chris@38 2606 selectionToWrite = &ms;
Chris@38 2607
Chris@38 2608 } else if (item == items[1]) {
Chris@0 2609
Chris@0 2610 multiple = true;
Chris@0 2611
Chris@0 2612 int n = 1;
Chris@0 2613 QString base = path;
Chris@0 2614 base.replace(".wav", "");
Chris@0 2615
Chris@0 2616 for (MultiSelection::SelectionList::iterator i = selections.begin();
Chris@0 2617 i != selections.end(); ++i) {
Chris@0 2618
Chris@0 2619 MultiSelection subms;
Chris@0 2620 subms.setSelection(*i);
Chris@0 2621
Chris@0 2622 QString subpath = QString("%1.%2.wav").arg(base).arg(n);
Chris@0 2623 ++n;
Chris@0 2624
Chris@0 2625 if (QFileInfo(subpath).exists()) {
Chris@0 2626 error = tr("Fragment file %1 already exists, aborting").arg(subpath);
Chris@0 2627 break;
Chris@0 2628 }
Chris@0 2629
Chris@38 2630 WavFileWriter subwriter(subpath,
Chris@38 2631 getMainModel()->getSampleRate(),
Chris@38 2632 getMainModel()->getChannelCount());
Chris@38 2633 subwriter.writeModel(getMainModel(), &subms);
Chris@0 2634 ok = subwriter.isOK();
Chris@0 2635
Chris@0 2636 if (!ok) {
Chris@0 2637 error = subwriter.getError();
Chris@0 2638 break;
Chris@0 2639 }
Chris@0 2640 }
Chris@0 2641 }
Chris@0 2642 }
Chris@0 2643
Chris@38 2644 if (!multiple) {
Chris@38 2645 WavFileWriter writer(path,
Chris@38 2646 getMainModel()->getSampleRate(),
Chris@38 2647 getMainModel()->getChannelCount());
Chris@38 2648 writer.writeModel(getMainModel(), selectionToWrite);
Chris@38 2649 ok = writer.isOK();
Chris@38 2650 error = writer.getError();
Chris@0 2651 }
Chris@0 2652
Chris@0 2653 if (ok) {
Chris@0 2654 if (!multiple) {
Chris@34 2655 m_recentFiles.addFile(path);
Chris@0 2656 }
Chris@0 2657 } else {
Chris@0 2658 QMessageBox::critical(this, tr("Failed to write file"), error);
Chris@0 2659 }
Chris@0 2660 }
Chris@0 2661
Chris@0 2662 void
Chris@0 2663 MainWindow::importLayer()
Chris@0 2664 {
Chris@0 2665 Pane *pane = m_paneStack->getCurrentPane();
Chris@0 2666
Chris@0 2667 if (!pane) {
Chris@0 2668 // shouldn't happen, as the menu action should have been disabled
Chris@0 2669 std::cerr << "WARNING: MainWindow::importLayer: no current pane" << std::endl;
Chris@0 2670 return;
Chris@0 2671 }
Chris@0 2672
Chris@0 2673 if (!getMainModel()) {
Chris@0 2674 // shouldn't happen, as the menu action should have been disabled
Chris@0 2675 std::cerr << "WARNING: MainWindow::importLayer: No main model -- hence no default sample rate available" << std::endl;
Chris@0 2676 return;
Chris@0 2677 }
Chris@0 2678
Chris@88 2679 QString path = getOpenFileName(FileFinder::LayerFile);
Chris@0 2680
Chris@0 2681 if (path != "") {
Chris@0 2682
Chris@193 2683 FileOpenStatus status = openLayerFile(path);
Chris@193 2684
Chris@193 2685 if (status == FileOpenFailed) {
Chris@0 2686 QMessageBox::critical(this, tr("Failed to open file"),
Chris@193 2687 tr("<b>File open failed</b><p>Layer file %1 could not be opened.").arg(path));
Chris@0 2688 return;
Chris@193 2689 } else if (status == FileOpenWrongMode) {
Chris@193 2690 QMessageBox::critical(this, tr("Failed to open file"),
Chris@193 2691 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
Chris@0 2692 }
Chris@0 2693 }
Chris@0 2694 }
Chris@0 2695
Chris@82 2696 MainWindow::FileOpenStatus
Chris@0 2697 MainWindow::openLayerFile(QString path)
Chris@0 2698 {
Chris@86 2699 return openLayerFile(path, path);
Chris@86 2700 }
Chris@86 2701
Chris@86 2702 MainWindow::FileOpenStatus
Chris@86 2703 MainWindow::openLayerFile(QString path, QString location)
Chris@86 2704 {
Chris@0 2705 Pane *pane = m_paneStack->getCurrentPane();
Chris@0 2706
Chris@0 2707 if (!pane) {
Chris@0 2708 // shouldn't happen, as the menu action should have been disabled
Chris@0 2709 std::cerr << "WARNING: MainWindow::openLayerFile: no current pane" << std::endl;
Chris@193 2710 return FileOpenWrongMode;
Chris@0 2711 }
Chris@0 2712
Chris@0 2713 if (!getMainModel()) {
Chris@0 2714 // shouldn't happen, as the menu action should have been disabled
Chris@0 2715 std::cerr << "WARNING: MainWindow::openLayerFile: No main model -- hence no default sample rate available" << std::endl;
Chris@193 2716 return FileOpenWrongMode;
Chris@0 2717 }
Chris@0 2718
Chris@86 2719 bool realFile = (location == path);
Chris@86 2720
Chris@0 2721 if (path.endsWith(".svl") || path.endsWith(".xml")) {
Chris@0 2722
Chris@0 2723 PaneCallback callback(this);
Chris@0 2724 QFile file(path);
Chris@0 2725
Chris@0 2726 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
Chris@0 2727 std::cerr << "ERROR: MainWindow::openLayerFile("
Chris@86 2728 << location.toStdString()
Chris@0 2729 << "): Failed to open file for reading" << std::endl;
Chris@82 2730 return FileOpenFailed;
Chris@0 2731 }
Chris@0 2732
Chris@87 2733 SVFileReader reader(m_document, callback, location);
Chris@0 2734 reader.setCurrentPane(pane);
Chris@0 2735
Chris@0 2736 QXmlInputSource inputSource(&file);
Chris@0 2737 reader.parse(inputSource);
Chris@0 2738
Chris@0 2739 if (!reader.isOK()) {
Chris@0 2740 std::cerr << "ERROR: MainWindow::openLayerFile("
Chris@86 2741 << location.toStdString()
Chris@0 2742 << "): Failed to read XML file: "
Chris@0 2743 << reader.getErrorString().toStdString() << std::endl;
Chris@82 2744 return FileOpenFailed;
Chris@0 2745 }
Chris@0 2746
Chris@86 2747 m_recentFiles.addFile(location);
Chris@86 2748
Chris@86 2749 if (realFile) {
Chris@88 2750 registerLastOpenedFilePath(FileFinder::LayerFile, path); // for file dialog
Chris@86 2751 }
Chris@86 2752
Chris@82 2753 return FileOpenSucceeded;
Chris@0 2754
Chris@0 2755 } else {
Chris@0 2756
Chris@193 2757 try {
Chris@193 2758
Chris@193 2759 Model *model = DataFileReaderFactory::load
Chris@193 2760 (path, getMainModel()->getSampleRate());
Chris@0 2761
Chris@193 2762 if (model) {
Chris@193 2763
Chris@193 2764 Layer *newLayer = m_document->createImportedLayer(model);
Chris@193 2765
Chris@193 2766 if (newLayer) {
Chris@193 2767
Chris@193 2768 m_document->addLayerToView(pane, newLayer);
Chris@193 2769 m_recentFiles.addFile(location);
Chris@193 2770
Chris@193 2771 if (realFile) {
Chris@193 2772 registerLastOpenedFilePath(FileFinder::LayerFile, path); // for file dialog
Chris@193 2773 }
Chris@193 2774
Chris@193 2775 return FileOpenSucceeded;
Chris@86 2776 }
Chris@193 2777 }
Chris@193 2778 } catch (DataFileReaderFactory::Exception e) {
Chris@193 2779 if (e == DataFileReaderFactory::ImportCancelled) {
Chris@193 2780 return FileOpenCancelled;
Chris@0 2781 }
Chris@0 2782 }
Chris@0 2783 }
Chris@0 2784
Chris@82 2785 return FileOpenFailed;
Chris@0 2786 }
Chris@0 2787
Chris@193 2788 MainWindow::FileOpenStatus
Chris@193 2789 MainWindow::openImageFile(QString path)
Chris@193 2790 {
Chris@193 2791 return openImageFile(path, path);
Chris@193 2792 }
Chris@193 2793
Chris@193 2794 MainWindow::FileOpenStatus
Chris@193 2795 MainWindow::openImageFile(QString path, QString location)
Chris@193 2796 {
Chris@193 2797 Pane *pane = m_paneStack->getCurrentPane();
Chris@193 2798
Chris@193 2799 if (!pane) {
Chris@193 2800 // shouldn't happen, as the menu action should have been disabled
Chris@193 2801 std::cerr << "WARNING: MainWindow::openImageFile: no current pane" << std::endl;
Chris@193 2802 return FileOpenWrongMode;
Chris@193 2803 }
Chris@193 2804
Chris@193 2805 if (!m_document->getMainModel()) {
Chris@193 2806 return FileOpenWrongMode;
Chris@193 2807 }
Chris@193 2808
Chris@193 2809 bool newLayer = false;
Chris@193 2810
Chris@193 2811 ImageLayer *il = dynamic_cast<ImageLayer *>(pane->getSelectedLayer());
Chris@193 2812 if (!il) {
Chris@193 2813 for (int i = pane->getLayerCount()-1; i >= 0; --i) {
Chris@193 2814 il = dynamic_cast<ImageLayer *>(pane->getLayer(i));
Chris@193 2815 if (il) break;
Chris@193 2816 }
Chris@193 2817 }
Chris@193 2818 if (!il) {
Chris@193 2819 il = dynamic_cast<ImageLayer *>
Chris@193 2820 (m_document->createEmptyLayer(LayerFactory::Image));
Chris@193 2821 if (!il) return FileOpenFailed;
Chris@193 2822 newLayer = true;
Chris@193 2823 }
Chris@193 2824
Chris@193 2825 // We don't put the image file in Recent Files
Chris@193 2826
Chris@193 2827 std::cerr << "openImageFile: trying location \"" << location.toStdString() << "\" in image layer" << std::endl;
Chris@193 2828
Chris@193 2829 if (!il->addImage(m_viewManager->getGlobalCentreFrame(), location)) {
Chris@193 2830 if (newLayer) {
Chris@193 2831 m_document->setModel(il, 0); // releasing its model
Chris@193 2832 delete il;
Chris@193 2833 }
Chris@193 2834 return FileOpenFailed;
Chris@193 2835 } else {
Chris@193 2836 if (newLayer) {
Chris@193 2837 m_document->addLayerToView(pane, il);
Chris@193 2838 }
Chris@193 2839 m_paneStack->setCurrentLayer(pane, il);
Chris@193 2840 return FileOpenSucceeded;
Chris@193 2841 }
Chris@193 2842 }
Chris@193 2843
Chris@0 2844 void
Chris@0 2845 MainWindow::exportLayer()
Chris@0 2846 {
Chris@0 2847 Pane *pane = m_paneStack->getCurrentPane();
Chris@0 2848 if (!pane) return;
Chris@0 2849
Chris@0 2850 Layer *layer = pane->getSelectedLayer();
Chris@0 2851 if (!layer) return;
Chris@0 2852
Chris@0 2853 Model *model = layer->getModel();
Chris@0 2854 if (!model) return;
Chris@0 2855
Chris@185 2856 FileFinder::FileType type = FileFinder::LayerFileNoMidi;
Chris@185 2857
Chris@185 2858 if (dynamic_cast<NoteModel *>(model)) type = FileFinder::LayerFile;
Chris@185 2859
Chris@185 2860 QString path = getSaveFileName(type);
Chris@0 2861
Chris@0 2862 if (path == "") return;
Chris@0 2863
Chris@0 2864 if (QFileInfo(path).suffix() == "") path += ".svl";
Chris@0 2865
Chris@185 2866 QString suffix = QFileInfo(path).suffix().toLower();
Chris@185 2867
Chris@0 2868 QString error;
Chris@0 2869
Chris@185 2870 if (suffix == "xml" || suffix == "svl") {
Chris@0 2871
Chris@0 2872 QFile file(path);
Chris@0 2873 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
Chris@0 2874 error = tr("Failed to open file %1 for writing").arg(path);
Chris@0 2875 } else {
Chris@0 2876 QTextStream out(&file);
Chris@0 2877 out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
Chris@0 2878 << "<!DOCTYPE sonic-visualiser>\n"
Chris@0 2879 << "<sv>\n"
Chris@0 2880 << " <data>\n";
Chris@0 2881
Chris@0 2882 model->toXml(out, " ");
Chris@0 2883
Chris@0 2884 out << " </data>\n"
Chris@0 2885 << " <display>\n";
Chris@0 2886
Chris@0 2887 layer->toXml(out, " ");
Chris@0 2888
Chris@0 2889 out << " </display>\n"
Chris@0 2890 << "</sv>\n";
Chris@0 2891 }
Chris@0 2892
Chris@185 2893 } else if (suffix == "mid" || suffix == "midi") {
Chris@185 2894
Chris@185 2895 NoteModel *nm = dynamic_cast<NoteModel *>(model);
Chris@185 2896
Chris@185 2897 if (!nm) {
Chris@185 2898 error = tr("Can't export non-note layers to MIDI");
Chris@185 2899 } else {
Chris@185 2900 MIDIFileWriter writer(path, nm);
Chris@185 2901 writer.write();
Chris@185 2902 if (!writer.isOK()) {
Chris@185 2903 error = writer.getError();
Chris@185 2904 }
Chris@185 2905 }
Chris@185 2906
Chris@0 2907 } else {
Chris@0 2908
Chris@0 2909 CSVFileWriter writer(path, model,
Chris@185 2910 ((suffix == "csv") ? "," : "\t"));
Chris@0 2911 writer.write();
Chris@0 2912
Chris@0 2913 if (!writer.isOK()) {
Chris@0 2914 error = writer.getError();
Chris@0 2915 }
Chris@0 2916 }
Chris@0 2917
Chris@0 2918 if (error != "") {
Chris@0 2919 QMessageBox::critical(this, tr("Failed to write file"), error);
Chris@0 2920 } else {
Chris@34 2921 m_recentFiles.addFile(path);
Chris@0 2922 }
Chris@0 2923 }
Chris@0 2924
Chris@121 2925 void
Chris@121 2926 MainWindow::exportImage()
Chris@121 2927 {
Chris@121 2928 Pane *pane = m_paneStack->getCurrentPane();
Chris@121 2929 if (!pane) return;
Chris@121 2930
Chris@121 2931 QString path = getSaveFileName(FileFinder::ImageFile);
Chris@121 2932
Chris@121 2933 if (path == "") return;
Chris@121 2934
Chris@121 2935 if (QFileInfo(path).suffix() == "") path += ".png";
Chris@121 2936
Chris@123 2937 bool haveSelection = m_viewManager && !m_viewManager->getSelections().empty();
Chris@123 2938
Chris@123 2939 QSize total, visible, selected;
Chris@123 2940 total = pane->getImageSize();
Chris@123 2941 visible = pane->getImageSize(pane->getFirstVisibleFrame(),
Chris@123 2942 pane->getLastVisibleFrame());
Chris@123 2943
Chris@123 2944 size_t sf0 = 0, sf1 = 0;
Chris@123 2945
Chris@123 2946 if (haveSelection) {
Chris@123 2947 MultiSelection::SelectionList selections = m_viewManager->getSelections();
Chris@123 2948 sf0 = selections.begin()->getStartFrame();
Chris@123 2949 MultiSelection::SelectionList::iterator e = selections.end();
Chris@123 2950 --e;
Chris@123 2951 sf1 = e->getEndFrame();
Chris@123 2952 selected = pane->getImageSize(sf0, sf1);
Chris@123 2953 }
Chris@123 2954
Chris@123 2955 QStringList items;
Chris@125 2956 items << tr("Export the whole pane (%1x%2 pixels)")
Chris@123 2957 .arg(total.width()).arg(total.height());
Chris@123 2958 items << tr("Export the visible area only (%1x%2 pixels)")
Chris@123 2959 .arg(visible.width()).arg(visible.height());
Chris@123 2960 if (haveSelection) {
Chris@123 2961 items << tr("Export the selection extent (%1x%2 pixels)")
Chris@123 2962 .arg(selected.width()).arg(selected.height());
Chris@124 2963 } else {
Chris@124 2964 items << tr("Export the selection extent");
Chris@123 2965 }
Chris@123 2966
Chris@123 2967 QSettings settings;
Chris@123 2968 settings.beginGroup("MainWindow");
Chris@123 2969 int deflt = settings.value("lastimageexportregion", 0).toInt();
Chris@123 2970 if (deflt == 2 && !haveSelection) deflt = 1;
Chris@124 2971 if (deflt == 0 && total.width() > 32767) deflt = 1;
Chris@124 2972
Chris@124 2973 ListInputDialog *lid = new ListInputDialog
Chris@123 2974 (this, tr("Select region to export"),
Chris@123 2975 tr("Which region of the current pane do you want to export as an image?"),
Chris@124 2976 items, deflt);
Chris@124 2977
Chris@124 2978 if (!haveSelection) {
Chris@124 2979 lid->setItemAvailability(2, false);
Chris@124 2980 }
Chris@124 2981 if (total.width() > 32767) { // appears to be the limit of a QImage
Chris@124 2982 lid->setItemAvailability(0, false);
Chris@124 2983 lid->setFootnote(tr("Note: the whole pane is too wide to be exported as a single image."));
Chris@124 2984 }
Chris@124 2985
Chris@124 2986 bool ok = lid->exec();
Chris@124 2987 QString item = lid->getCurrentString();
Chris@124 2988 delete lid;
Chris@123 2989
Chris@123 2990 if (!ok || item.isEmpty()) return;
Chris@123 2991
Chris@123 2992 settings.setValue("lastimageexportregion", deflt);
Chris@123 2993
Chris@123 2994 QImage *image = 0;
Chris@123 2995
Chris@123 2996 if (item == items[0]) {
Chris@123 2997 image = pane->toNewImage();
Chris@123 2998 } else if (item == items[1]) {
Chris@123 2999 image = pane->toNewImage(pane->getFirstVisibleFrame(),
Chris@123 3000 pane->getLastVisibleFrame());
Chris@123 3001 } else if (haveSelection) {
Chris@123 3002 image = pane->toNewImage(sf0, sf1);
Chris@123 3003 }
Chris@123 3004
Chris@121 3005 if (!image) return;
Chris@121 3006
Chris@121 3007 if (!image->save(path, "PNG")) {
Chris@121 3008 QMessageBox::critical(this, tr("Failed to save image file"),
Chris@121 3009 tr("Failed to save image file %1").arg(path));
Chris@121 3010 }
Chris@121 3011
Chris@121 3012 delete image;
Chris@121 3013 }
Chris@121 3014
Chris@82 3015 MainWindow::FileOpenStatus
Chris@0 3016 MainWindow::openAudioFile(QString path, AudioFileOpenMode mode)
Chris@0 3017 {
Chris@86 3018 return openAudioFile(path, path, mode);
Chris@86 3019 }
Chris@86 3020
Chris@86 3021 MainWindow::FileOpenStatus
Chris@86 3022 MainWindow::openAudioFile(QString path, QString location, AudioFileOpenMode mode)
Chris@86 3023 {
Chris@0 3024 if (!(QFileInfo(path).exists() &&
Chris@0 3025 QFileInfo(path).isFile() &&
Chris@0 3026 QFileInfo(path).isReadable())) {
Chris@82 3027 return FileOpenFailed;
Chris@0 3028 }
Chris@0 3029
Chris@70 3030 m_openingAudioFile = true;
Chris@70 3031
Chris@180 3032 size_t rate = 0;
Chris@180 3033
Chris@180 3034 if (Preferences::getInstance()->getResampleOnLoad()) {
Chris@180 3035 rate = m_playSource->getSourceSampleRate();
Chris@180 3036 }
Chris@180 3037
Chris@180 3038 WaveFileModel *newModel = new WaveFileModel(path, location, rate);
Chris@0 3039
Chris@0 3040 if (!newModel->isOK()) {
Chris@0 3041 delete newModel;
Chris@70 3042 m_openingAudioFile = false;
Chris@82 3043 return FileOpenFailed;
Chris@0 3044 }
Chris@0 3045
Chris@0 3046 bool setAsMain = true;
Chris@0 3047 static bool prevSetAsMain = true;
Chris@0 3048
Chris@86 3049 bool realFile = (location == path);
Chris@86 3050
Chris@0 3051 if (mode == CreateAdditionalModel) setAsMain = false;
Chris@0 3052 else if (mode == AskUser) {
Chris@0 3053 if (m_document->getMainModel()) {
Chris@0 3054
Chris@0 3055 QStringList items;
Chris@0 3056 items << tr("Replace the existing main waveform")
Chris@0 3057 << tr("Load this file into a new waveform pane");
Chris@0 3058
Chris@0 3059 bool ok = false;
Chris@0 3060 QString item = ListInputDialog::getItem
Chris@0 3061 (this, tr("Select target for import"),
Chris@0 3062 tr("You already have an audio waveform loaded.\nWhat would you like to do with the new audio file?"),
Chris@0 3063 items, prevSetAsMain ? 0 : 1, &ok);
Chris@0 3064
Chris@0 3065 if (!ok || item.isEmpty()) {
Chris@0 3066 delete newModel;
Chris@70 3067 m_openingAudioFile = false;
Chris@82 3068 return FileOpenCancelled;
Chris@0 3069 }
Chris@0 3070
Chris@0 3071 setAsMain = (item == items[0]);
Chris@0 3072 prevSetAsMain = setAsMain;
Chris@0 3073 }
Chris@0 3074 }
Chris@0 3075
Chris@0 3076 if (setAsMain) {
Chris@0 3077
Chris@0 3078 Model *prevMain = getMainModel();
Chris@118 3079 if (prevMain) {
Chris@118 3080 m_playSource->removeModel(prevMain);
Chris@118 3081 PlayParameterRepository::getInstance()->removeModel(prevMain);
Chris@118 3082 }
Chris@118 3083
Chris@118 3084 PlayParameterRepository::getInstance()->addModel(newModel);
Chris@0 3085
Chris@0 3086 m_document->setMainModel(newModel);
Chris@0 3087 setupMenus();
Chris@0 3088
Chris@0 3089 if (m_sessionFile == "") {
Chris@0 3090 setWindowTitle(tr("Sonic Visualiser: %1")
Chris@86 3091 .arg(QFileInfo(location).fileName()));
Chris@0 3092 CommandHistory::getInstance()->clear();
Chris@0 3093 CommandHistory::getInstance()->documentSaved();
Chris@0 3094 m_documentModified = false;
Chris@0 3095 } else {
Chris@0 3096 setWindowTitle(tr("Sonic Visualiser: %1 [%2]")
Chris@0 3097 .arg(QFileInfo(m_sessionFile).fileName())
Chris@86 3098 .arg(QFileInfo(location).fileName()));
Chris@0 3099 if (m_documentModified) {
Chris@0 3100 m_documentModified = false;
Chris@0 3101 documentModified(); // so as to restore "(modified)" window title
Chris@0 3102 }
Chris@0 3103 }
Chris@0 3104
Chris@86 3105 if (realFile) m_audioFile = path;
Chris@0 3106
Chris@0 3107 } else { // !setAsMain
Chris@0 3108
Chris@0 3109 CommandHistory::getInstance()->startCompoundOperation
Chris@86 3110 (tr("Import \"%1\"").arg(QFileInfo(location).fileName()), true);
Chris@0 3111
Chris@0 3112 m_document->addImportedModel(newModel);
Chris@0 3113
Chris@0 3114 AddPaneCommand *command = new AddPaneCommand(this);
Chris@0 3115 CommandHistory::getInstance()->addCommand(command);
Chris@0 3116
Chris@0 3117 Pane *pane = command->getPane();
Chris@0 3118
Chris@0 3119 if (!m_timeRulerLayer) {
Chris@0 3120 m_timeRulerLayer = m_document->createMainModelLayer
Chris@0 3121 (LayerFactory::TimeRuler);
Chris@0 3122 }
Chris@0 3123
Chris@0 3124 m_document->addLayerToView(pane, m_timeRulerLayer);
Chris@0 3125
Chris@0 3126 Layer *newLayer = m_document->createImportedLayer(newModel);
Chris@0 3127
Chris@0 3128 if (newLayer) {
Chris@0 3129 m_document->addLayerToView(pane, newLayer);
Chris@0 3130 }
Chris@0 3131
Chris@0 3132 CommandHistory::getInstance()->endCompoundOperation();
Chris@0 3133 }
Chris@0 3134
Chris@0 3135 updateMenuStates();
Chris@86 3136 m_recentFiles.addFile(location);
Chris@86 3137 if (realFile) {
Chris@88 3138 registerLastOpenedFilePath(FileFinder::AudioFile, path); // for file dialog
Chris@86 3139 }
Chris@70 3140 m_openingAudioFile = false;
Chris@0 3141
Chris@180 3142 currentPaneChanged(m_paneStack->getCurrentPane());
Chris@180 3143
Chris@82 3144 return FileOpenSucceeded;
Chris@0 3145 }
Chris@0 3146
Chris@180 3147 MainWindow::FileOpenStatus
Chris@180 3148 MainWindow::openPlaylistFile(QString path, AudioFileOpenMode mode)
Chris@180 3149 {
Chris@180 3150 return openPlaylistFile(path, path, mode);
Chris@180 3151 }
Chris@180 3152
Chris@180 3153 MainWindow::FileOpenStatus
Chris@180 3154 MainWindow::openPlaylistFile(QString path, QString location, AudioFileOpenMode mode)
Chris@180 3155 {
Chris@180 3156 if (!(QFileInfo(path).exists() &&
Chris@180 3157 QFileInfo(path).isFile() &&
Chris@180 3158 QFileInfo(path).isReadable())) {
Chris@180 3159 return FileOpenFailed;
Chris@180 3160 }
Chris@180 3161
Chris@180 3162 std::set<QString> extensions;
Chris@180 3163 PlaylistFileReader::getSupportedExtensions(extensions);
Chris@180 3164 QString extension = QFileInfo(path).suffix();
Chris@180 3165 if (extensions.find(extension) == extensions.end()) return FileOpenFailed;
Chris@180 3166
Chris@180 3167 PlaylistFileReader reader(path);
Chris@180 3168 if (!reader.isOK()) return FileOpenFailed;
Chris@180 3169
Chris@180 3170 PlaylistFileReader::Playlist playlist = reader.load();
Chris@180 3171
Chris@180 3172 bool someSuccess = false;
Chris@180 3173
Chris@180 3174 for (PlaylistFileReader::Playlist::const_iterator i = playlist.begin();
Chris@180 3175 i != playlist.end(); ++i) {
Chris@180 3176
Chris@180 3177 FileOpenStatus status = openURL(*i, mode);
Chris@180 3178
Chris@180 3179 if (status == FileOpenCancelled) {
Chris@180 3180 return FileOpenCancelled;
Chris@180 3181 }
Chris@180 3182
Chris@180 3183 if (status == FileOpenSucceeded) {
Chris@180 3184 someSuccess = true;
Chris@180 3185 mode = CreateAdditionalModel;
Chris@180 3186 }
Chris@180 3187 }
Chris@180 3188
Chris@180 3189 if (someSuccess) return FileOpenSucceeded;
Chris@180 3190 else return FileOpenFailed;
Chris@180 3191 }
Chris@180 3192
Chris@0 3193 void
Chris@0 3194 MainWindow::createPlayTarget()
Chris@0 3195 {
Chris@0 3196 if (m_playTarget) return;
Chris@0 3197
Chris@0 3198 m_playTarget = AudioTargetFactory::createCallbackTarget(m_playSource);
Chris@0 3199 if (!m_playTarget) {
Chris@0 3200 QMessageBox::warning
Chris@0 3201 (this, tr("Couldn't open audio device"),
Chris@193 3202 tr("<b>No audio available</b><p>Could not open an audio device for playback.<p>Audio playback will not be available during this session."),
Chris@165 3203 QMessageBox::Ok);
Chris@0 3204 }
Chris@0 3205 connect(m_fader, SIGNAL(valueChanged(float)),
Chris@0 3206 m_playTarget, SLOT(setOutputGain(float)));
Chris@0 3207 }
Chris@0 3208
Chris@0 3209 WaveFileModel *
Chris@0 3210 MainWindow::getMainModel()
Chris@0 3211 {
Chris@0 3212 if (!m_document) return 0;
Chris@0 3213 return m_document->getMainModel();
Chris@0 3214 }
Chris@0 3215
Chris@116 3216 const WaveFileModel *
Chris@116 3217 MainWindow::getMainModel() const
Chris@116 3218 {
Chris@116 3219 if (!m_document) return 0;
Chris@116 3220 return m_document->getMainModel();
Chris@116 3221 }
Chris@116 3222
Chris@0 3223 void
Chris@0 3224 MainWindow::newSession()
Chris@0 3225 {
Chris@0 3226 if (!checkSaveModified()) return;
Chris@0 3227
Chris@0 3228 closeSession();
Chris@0 3229 createDocument();
Chris@0 3230
Chris@0 3231 Pane *pane = m_paneStack->addPane();
Chris@0 3232
Chris@90 3233 connect(pane, SIGNAL(contextHelpChanged(const QString &)),
Chris@116 3234 this, SLOT(contextHelpChanged(const QString &)));
Chris@90 3235
Chris@0 3236 if (!m_timeRulerLayer) {
Chris@0 3237 m_timeRulerLayer = m_document->createMainModelLayer
Chris@0 3238 (LayerFactory::TimeRuler);
Chris@0 3239 }
Chris@0 3240
Chris@0 3241 m_document->addLayerToView(pane, m_timeRulerLayer);
Chris@0 3242
Chris@0 3243 Layer *waveform = m_document->createMainModelLayer(LayerFactory::Waveform);
Chris@0 3244 m_document->addLayerToView(pane, waveform);
Chris@0 3245
Chris@65 3246 m_overview->registerView(pane);
Chris@0 3247
Chris@0 3248 CommandHistory::getInstance()->clear();
Chris@0 3249 CommandHistory::getInstance()->documentSaved();
Chris@0 3250 documentRestored();
Chris@0 3251 updateMenuStates();
Chris@0 3252 }
Chris@0 3253
Chris@0 3254 void
Chris@0 3255 MainWindow::createDocument()
Chris@0 3256 {
Chris@0 3257 m_document = new Document;
Chris@0 3258
Chris@0 3259 connect(m_document, SIGNAL(layerAdded(Layer *)),
Chris@0 3260 this, SLOT(layerAdded(Layer *)));
Chris@0 3261 connect(m_document, SIGNAL(layerRemoved(Layer *)),
Chris@0 3262 this, SLOT(layerRemoved(Layer *)));
Chris@0 3263 connect(m_document, SIGNAL(layerAboutToBeDeleted(Layer *)),
Chris@0 3264 this, SLOT(layerAboutToBeDeleted(Layer *)));
Chris@0 3265 connect(m_document, SIGNAL(layerInAView(Layer *, bool)),
Chris@0 3266 this, SLOT(layerInAView(Layer *, bool)));
Chris@0 3267
Chris@0 3268 connect(m_document, SIGNAL(modelAdded(Model *)),
Chris@0 3269 this, SLOT(modelAdded(Model *)));
Chris@0 3270 connect(m_document, SIGNAL(mainModelChanged(WaveFileModel *)),
Chris@0 3271 this, SLOT(mainModelChanged(WaveFileModel *)));
Chris@0 3272 connect(m_document, SIGNAL(modelAboutToBeDeleted(Model *)),
Chris@0 3273 this, SLOT(modelAboutToBeDeleted(Model *)));
Chris@0 3274
Chris@0 3275 connect(m_document, SIGNAL(modelGenerationFailed(QString)),
Chris@0 3276 this, SLOT(modelGenerationFailed(QString)));
Chris@63 3277 connect(m_document, SIGNAL(modelRegenerationFailed(QString, QString)),
Chris@63 3278 this, SLOT(modelRegenerationFailed(QString, QString)));
Chris@0 3279 }
Chris@0 3280
Chris@0 3281 void
Chris@0 3282 MainWindow::closeSession()
Chris@0 3283 {
Chris@0 3284 if (!checkSaveModified()) return;
Chris@0 3285
Chris@0 3286 while (m_paneStack->getPaneCount() > 0) {
Chris@0 3287
Chris@0 3288 Pane *pane = m_paneStack->getPane(m_paneStack->getPaneCount() - 1);
Chris@0 3289
Chris@0 3290 while (pane->getLayerCount() > 0) {
Chris@0 3291 m_document->removeLayerFromView
Chris@0 3292 (pane, pane->getLayer(pane->getLayerCount() - 1));
Chris@0 3293 }
Chris@0 3294
Chris@65 3295 m_overview->unregisterView(pane);
Chris@0 3296 m_paneStack->deletePane(pane);
Chris@0 3297 }
Chris@0 3298
Chris@0 3299 while (m_paneStack->getHiddenPaneCount() > 0) {
Chris@0 3300
Chris@0 3301 Pane *pane = m_paneStack->getHiddenPane
Chris@0 3302 (m_paneStack->getHiddenPaneCount() - 1);
Chris@0 3303
Chris@0 3304 while (pane->getLayerCount() > 0) {
Chris@0 3305 m_document->removeLayerFromView
Chris@0 3306 (pane, pane->getLayer(pane->getLayerCount() - 1));
Chris@0 3307 }
Chris@0 3308
Chris@65 3309 m_overview->unregisterView(pane);
Chris@0 3310 m_paneStack->deletePane(pane);
Chris@0 3311 }
Chris@0 3312
Chris@0 3313 delete m_document;
Chris@0 3314 m_document = 0;
Chris@0 3315 m_viewManager->clearSelections();
Chris@0 3316 m_timeRulerLayer = 0; // document owned this
Chris@0 3317
Chris@0 3318 m_sessionFile = "";
Chris@0 3319 setWindowTitle(tr("Sonic Visualiser"));
Chris@0 3320
Chris@0 3321 CommandHistory::getInstance()->clear();
Chris@0 3322 CommandHistory::getInstance()->documentSaved();
Chris@0 3323 documentRestored();
Chris@0 3324 }
Chris@0 3325
Chris@0 3326 void
Chris@0 3327 MainWindow::openSession()
Chris@0 3328 {
Chris@0 3329 if (!checkSaveModified()) return;
Chris@0 3330
Chris@0 3331 QString orig = m_audioFile;
Chris@0 3332 if (orig == "") orig = ".";
Chris@0 3333 else orig = QFileInfo(orig).absoluteDir().canonicalPath();
Chris@0 3334
Chris@88 3335 QString path = getOpenFileName(FileFinder::SessionFile);
Chris@0 3336
Chris@0 3337 if (path.isEmpty()) return;
Chris@0 3338
Chris@82 3339 if (openSessionFile(path) == FileOpenFailed) {
Chris@0 3340 QMessageBox::critical(this, tr("Failed to open file"),
Chris@193 3341 tr("<b>File open failed</b><p>Session file \"%1\" could not be opened").arg(path));
Chris@0 3342 }
Chris@0 3343 }
Chris@0 3344
Chris@0 3345 void
Chris@0 3346 MainWindow::openSomething()
Chris@0 3347 {
Chris@0 3348 QString orig = m_audioFile;
Chris@0 3349 if (orig == "") orig = ".";
Chris@0 3350 else orig = QFileInfo(orig).absoluteDir().canonicalPath();
Chris@0 3351
Chris@88 3352 QString path = getOpenFileName(FileFinder::AnyFile);
Chris@0 3353
Chris@0 3354 if (path.isEmpty()) return;
Chris@0 3355
Chris@193 3356 FileOpenStatus status = openSomeFile(path, AskUser);
Chris@193 3357
Chris@193 3358 if (status == FileOpenFailed) {
Chris@193 3359 QMessageBox::critical(this, tr("Failed to open file"),
Chris@193 3360 tr("<b>File open failed</b><p>File \"%1\" could not be opened").arg(path));
Chris@193 3361 } else if (status == FileOpenWrongMode) {
Chris@193 3362 QMessageBox::critical(this, tr("Failed to open file"),
Chris@193 3363 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
Chris@0 3364 }
Chris@0 3365 }
Chris@0 3366
Chris@0 3367 void
Chris@86 3368 MainWindow::openLocation()
Chris@86 3369 {
Chris@103 3370 QSettings settings;
Chris@103 3371 settings.beginGroup("MainWindow");
Chris@103 3372 QString lastLocation = settings.value("lastremote", "").toString();
Chris@103 3373
Chris@86 3374 bool ok = false;
Chris@86 3375 QString text = QInputDialog::getText
Chris@86 3376 (this, tr("Open Location"),
Chris@86 3377 tr("Please enter the URL of the location to open:"),
Chris@103 3378 QLineEdit::Normal, lastLocation, &ok);
Chris@103 3379
Chris@103 3380 if (!ok) return;
Chris@103 3381
Chris@103 3382 settings.setValue("lastremote", text);
Chris@103 3383
Chris@103 3384 if (text.isEmpty()) return;
Chris@86 3385
Chris@193 3386 FileOpenStatus status = openURL(QUrl(text));
Chris@193 3387
Chris@193 3388 if (status == FileOpenFailed) {
Chris@86 3389 QMessageBox::critical(this, tr("Failed to open location"),
Chris@193 3390 tr("<b>Open failed</b><p>URL \"%1\" could not be opened").arg(text));
Chris@193 3391 } else if (status == FileOpenWrongMode) {
Chris@193 3392 QMessageBox::critical(this, tr("Failed to open location"),
Chris@193 3393 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
Chris@86 3394 }
Chris@86 3395 }
Chris@86 3396
Chris@86 3397 void
Chris@0 3398 MainWindow::openRecentFile()
Chris@0 3399 {
Chris@0 3400 QObject *obj = sender();
Chris@0 3401 QAction *action = dynamic_cast<QAction *>(obj);
Chris@0 3402
Chris@0 3403 if (!action) {
Chris@0 3404 std::cerr << "WARNING: MainWindow::openRecentFile: sender is not an action"
Chris@0 3405 << std::endl;
Chris@0 3406 return;
Chris@0 3407 }
Chris@0 3408
Chris@0 3409 QString path = action->text();
Chris@0 3410 if (path == "") return;
Chris@0 3411
Chris@193 3412 FileOpenStatus status = openURL(path);
Chris@193 3413
Chris@193 3414 if (status == FileOpenFailed) {
Chris@193 3415 QMessageBox::critical(this, tr("Failed to open location"),
Chris@193 3416 tr("<b>Open failed</b><p>File or URL \"%1\" could not be opened").arg(path));
Chris@193 3417 } else if (status == FileOpenWrongMode) {
Chris@193 3418 QMessageBox::critical(this, tr("Failed to open location"),
Chris@193 3419 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
Chris@0 3420 }
Chris@0 3421 }
Chris@0 3422
Chris@82 3423 MainWindow::FileOpenStatus
Chris@180 3424 MainWindow::openURL(QUrl url, AudioFileOpenMode mode)
Chris@85 3425 {
Chris@193 3426 if (url.scheme().toLower() == "file" || url.scheme() == "") {
Chris@180 3427
Chris@180 3428 return openSomeFile(url.toLocalFile(), mode);
Chris@180 3429
Chris@86 3430 } else if (!RemoteFile::canHandleScheme(url)) {
Chris@180 3431
Chris@85 3432 QMessageBox::critical(this, tr("Unsupported scheme in URL"),
Chris@193 3433 tr("<b>Download failed</b><p>The URL scheme \"%1\" is not supported")
Chris@85 3434 .arg(url.scheme()));
Chris@85 3435 return FileOpenFailed;
Chris@180 3436
Chris@85 3437 } else {
Chris@85 3438 RemoteFile rf(url);
Chris@85 3439 rf.wait();
Chris@85 3440 if (!rf.isOK()) {
Chris@85 3441 QMessageBox::critical(this, tr("File download failed"),
Chris@193 3442 tr("<b>Download failed</b><p>Failed to download URL \"%1\": %2")
Chris@85 3443 .arg(url.toString()).arg(rf.getErrorString()));
Chris@85 3444 return FileOpenFailed;
Chris@85 3445 }
Chris@88 3446 FileOpenStatus status;
Chris@180 3447 if ((status = openSomeFile(rf.getLocalFilename(), url.toString(),
Chris@180 3448 mode)) !=
Chris@88 3449 FileOpenSucceeded) {
Chris@88 3450 rf.deleteLocalFile();
Chris@88 3451 }
Chris@88 3452 return status;
Chris@85 3453 }
Chris@85 3454 }
Chris@85 3455
Chris@85 3456 MainWindow::FileOpenStatus
Chris@180 3457 MainWindow::openURL(QString ustr, AudioFileOpenMode mode)
Chris@180 3458 {
Chris@180 3459 // This function is used when we don't know whether the string is
Chris@180 3460 // an encoded or human-readable url
Chris@180 3461
Chris@180 3462 QUrl url(ustr);
Chris@180 3463
Chris@193 3464 if (url.scheme().toLower() == "file" || url.scheme() == "") {
Chris@193 3465
Chris@193 3466 FileOpenStatus status = openSomeFile(url.toLocalFile(), mode);
Chris@193 3467 if (status == FileOpenFailed) {
Chris@193 3468 url.setEncodedUrl(ustr.toAscii());
Chris@193 3469 status = openSomeFile(url.toLocalFile(), mode);
Chris@193 3470 }
Chris@193 3471 return status;
Chris@180 3472
Chris@180 3473 } else if (!RemoteFile::canHandleScheme(url)) {
Chris@180 3474
Chris@180 3475 QMessageBox::critical(this, tr("Unsupported scheme in URL"),
Chris@193 3476 tr("<b>Download failed</b><p>The URL scheme \"%1\" is not supported")
Chris@180 3477 .arg(url.scheme()));
Chris@180 3478 return FileOpenFailed;
Chris@180 3479
Chris@180 3480 } else {
Chris@180 3481 RemoteFile rf(url);
Chris@180 3482 rf.wait();
Chris@180 3483 if (!rf.isOK()) {
Chris@180 3484 // rf was created on the assumption that ustr was
Chris@180 3485 // human-readable. Let's try again, this time assuming it
Chris@180 3486 // was already encoded.
Chris@180 3487 std::cerr << "MainWindow::openURL: Failed to retrieve URL \""
Chris@180 3488 << ustr.toStdString() << "\" as human-readable URL; "
Chris@180 3489 << "trying again treating it as encoded URL"
Chris@180 3490 << std::endl;
Chris@180 3491 url.setEncodedUrl(ustr.toAscii());
Chris@180 3492 return openURL(url, mode);
Chris@180 3493 }
Chris@180 3494
Chris@180 3495 FileOpenStatus status;
Chris@180 3496 if ((status = openSomeFile(rf.getLocalFilename(), ustr, mode)) !=
Chris@180 3497 FileOpenSucceeded) {
Chris@180 3498 rf.deleteLocalFile();
Chris@180 3499 }
Chris@180 3500 return status;
Chris@180 3501 }
Chris@180 3502 }
Chris@180 3503
Chris@180 3504 MainWindow::FileOpenStatus
Chris@54 3505 MainWindow::openSomeFile(QString path, AudioFileOpenMode mode)
Chris@0 3506 {
Chris@86 3507 return openSomeFile(path, path, mode);
Chris@86 3508 }
Chris@86 3509
Chris@86 3510 MainWindow::FileOpenStatus
Chris@86 3511 MainWindow::openSomeFile(QString path, QString location,
Chris@86 3512 AudioFileOpenMode mode)
Chris@86 3513 {
Chris@82 3514 FileOpenStatus status;
Chris@82 3515
Chris@85 3516 bool canImportLayer = (getMainModel() != 0 &&
Chris@85 3517 m_paneStack != 0 &&
Chris@85 3518 m_paneStack->getCurrentPane() != 0);
Chris@85 3519
Chris@180 3520 if ((status = openPlaylistFile(path, location, mode)) != FileOpenFailed) {
Chris@180 3521 return status;
Chris@180 3522 } else if ((status = openAudioFile(path, location, mode)) != FileOpenFailed) {
Chris@82 3523 return status;
Chris@193 3524 } else if (QFileInfo(path).suffix().toLower() == "sv" &&
Chris@193 3525 (status = openSessionFile(path, location)) != FileOpenFailed) {
Chris@82 3526 return status;
Chris@85 3527 } else if (!canImportLayer) {
Chris@193 3528 return FileOpenWrongMode;
Chris@193 3529 } else if ((status = openImageFile(path, location)) != FileOpenFailed) {
Chris@193 3530 return status;
Chris@86 3531 } else if ((status = openLayerFile(path, location)) != FileOpenFailed) {
Chris@85 3532 return status;
Chris@0 3533 } else {
Chris@82 3534 return FileOpenFailed;
Chris@0 3535 }
Chris@0 3536 }
Chris@0 3537
Chris@82 3538 MainWindow::FileOpenStatus
Chris@0 3539 MainWindow::openSessionFile(QString path)
Chris@0 3540 {
Chris@86 3541 return openSessionFile(path, path);
Chris@86 3542 }
Chris@86 3543
Chris@86 3544 MainWindow::FileOpenStatus
Chris@86 3545 MainWindow::openSessionFile(QString path, QString location)
Chris@86 3546 {
Chris@0 3547 BZipFileDevice bzFile(path);
Chris@0 3548 if (!bzFile.open(QIODevice::ReadOnly)) {
Chris@86 3549 std::cerr << "Failed to open session file \"" << location.toStdString()
Chris@0 3550 << "\": " << bzFile.errorString().toStdString() << std::endl;
Chris@82 3551 return FileOpenFailed;
Chris@0 3552 }
Chris@0 3553
Chris@103 3554 if (!checkSaveModified()) return FileOpenCancelled;
Chris@103 3555
Chris@0 3556 QString error;
Chris@0 3557 closeSession();
Chris@0 3558 createDocument();
Chris@0 3559
Chris@0 3560 PaneCallback callback(this);
Chris@0 3561 m_viewManager->clearSelections();
Chris@0 3562
Chris@87 3563 SVFileReader reader(m_document, callback, location);
Chris@0 3564 QXmlInputSource inputSource(&bzFile);
Chris@0 3565 reader.parse(inputSource);
Chris@0 3566
Chris@0 3567 if (!reader.isOK()) {
Chris@0 3568 error = tr("SV XML file read error:\n%1").arg(reader.getErrorString());
Chris@0 3569 }
Chris@0 3570
Chris@0 3571 bzFile.close();
Chris@0 3572
Chris@0 3573 bool ok = (error == "");
Chris@86 3574
Chris@86 3575 bool realFile = (location == path);
Chris@0 3576
Chris@0 3577 if (ok) {
Chris@86 3578
Chris@0 3579 setWindowTitle(tr("Sonic Visualiser: %1")
Chris@86 3580 .arg(QFileInfo(location).fileName()));
Chris@86 3581
Chris@86 3582 if (realFile) m_sessionFile = path;
Chris@86 3583
Chris@0 3584 setupMenus();
Chris@0 3585 CommandHistory::getInstance()->clear();
Chris@0 3586 CommandHistory::getInstance()->documentSaved();
Chris@0 3587 m_documentModified = false;
Chris@0 3588 updateMenuStates();
Chris@86 3589
Chris@86 3590 m_recentFiles.addFile(location);
Chris@86 3591
Chris@86 3592 if (realFile) {
Chris@88 3593 registerLastOpenedFilePath(FileFinder::SessionFile, path); // for file dialog
Chris@86 3594 }
Chris@86 3595
Chris@0 3596 } else {
Chris@0 3597 setWindowTitle(tr("Sonic Visualiser"));
Chris@0 3598 }
Chris@0 3599
Chris@82 3600 return ok ? FileOpenSucceeded : FileOpenFailed;
Chris@0 3601 }
Chris@0 3602
Chris@0 3603 void
Chris@193 3604 MainWindow::paneDropAccepted(Pane *pane, QStringList uriList)
Chris@193 3605 {
Chris@193 3606 if (pane) m_paneStack->setCurrentPane(pane);
Chris@193 3607
Chris@193 3608 for (QStringList::iterator i = uriList.begin(); i != uriList.end(); ++i) {
Chris@193 3609
Chris@193 3610 FileOpenStatus status =
Chris@193 3611 openURL(*i, (m_document->getMainModel() ?
Chris@193 3612 CreateAdditionalModel : ReplaceMainModel));
Chris@193 3613
Chris@193 3614 if (status == FileOpenFailed) {
Chris@193 3615 QMessageBox::critical(this, tr("Failed to open dropped URL"),
Chris@193 3616 tr("<b>Open failed</b><p>Dropped URL \"%1\" could not be opened").arg(*i));
Chris@193 3617 } else if (status == FileOpenWrongMode) {
Chris@193 3618 QMessageBox::critical(this, tr("Failed to open dropped URL"),
Chris@193 3619 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
Chris@193 3620 }
Chris@193 3621 }
Chris@193 3622 }
Chris@193 3623
Chris@193 3624 void
Chris@193 3625 MainWindow::paneDropAccepted(Pane *pane, QString text)
Chris@193 3626 {
Chris@193 3627 if (pane) m_paneStack->setCurrentPane(pane);
Chris@193 3628
Chris@193 3629 QUrl testUrl(text);
Chris@193 3630 if (testUrl.scheme() == "file" ||
Chris@193 3631 testUrl.scheme() == "http" ||
Chris@193 3632 testUrl.scheme() == "ftp") {
Chris@193 3633 QStringList list;
Chris@193 3634 list.push_back(text);
Chris@193 3635 paneDropAccepted(pane, list);
Chris@193 3636 return;
Chris@193 3637 }
Chris@193 3638
Chris@193 3639 //!!! open as text -- but by importing as if a CSV, or just adding
Chris@193 3640 //to a text layer?
Chris@193 3641 }
Chris@193 3642
Chris@193 3643 void
Chris@0 3644 MainWindow::closeEvent(QCloseEvent *e)
Chris@0 3645 {
Chris@137 3646 // std::cerr << "MainWindow::closeEvent" << std::endl;
Chris@118 3647
Chris@136 3648 if (m_openingAudioFile) {
Chris@137 3649 // std::cerr << "Busy - ignoring close event" << std::endl;
Chris@136 3650 e->ignore();
Chris@136 3651 return;
Chris@136 3652 }
Chris@136 3653
Chris@70 3654 if (!m_abandoning && !checkSaveModified()) {
Chris@137 3655 // std::cerr << "Ignoring close event" << std::endl;
Chris@0 3656 e->ignore();
Chris@0 3657 return;
Chris@0 3658 }
Chris@0 3659
Chris@5 3660 QSettings settings;
Chris@5 3661 settings.beginGroup("MainWindow");
Chris@5 3662 settings.setValue("size", size());
Chris@5 3663 settings.setValue("position", pos());
Chris@5 3664 settings.endGroup();
Chris@5 3665
Chris@163 3666 delete m_keyReference;
Chris@163 3667 m_keyReference = 0;
Chris@163 3668
Chris@163 3669 if (m_preferencesDialog &&
Chris@163 3670 m_preferencesDialog->isVisible()) {
Chris@164 3671 closeSession(); // otherwise we'll have to wait for prefs changes
Chris@163 3672 m_preferencesDialog->applicationClosing(false);
Chris@163 3673 }
Chris@163 3674
Chris@177 3675 if (m_layerTreeView &&
Chris@177 3676 m_layerTreeView->isVisible()) {
Chris@177 3677 delete m_layerTreeView;
Chris@177 3678 }
Chris@177 3679
Chris@0 3680 e->accept();
Chris@0 3681 return;
Chris@0 3682 }
Chris@0 3683
Chris@0 3684 bool
Chris@11 3685 MainWindow::commitData(bool mayAskUser)
Chris@11 3686 {
Chris@11 3687 if (mayAskUser) {
Chris@163 3688 bool rv = checkSaveModified();
Chris@163 3689 if (rv) {
Chris@163 3690 if (m_preferencesDialog &&
Chris@163 3691 m_preferencesDialog->isVisible()) {
Chris@163 3692 m_preferencesDialog->applicationClosing(false);
Chris@163 3693 }
Chris@163 3694 }
Chris@163 3695 return rv;
Chris@11 3696 } else {
Chris@163 3697 if (m_preferencesDialog &&
Chris@163 3698 m_preferencesDialog->isVisible()) {
Chris@163 3699 m_preferencesDialog->applicationClosing(true);
Chris@163 3700 }
Chris@11 3701 if (!m_documentModified) return true;
Chris@11 3702
Chris@11 3703 // If we can't check with the user first, then we can't save
Chris@11 3704 // to the original session file (even if we have it) -- have
Chris@11 3705 // to use a temporary file
Chris@11 3706
Chris@11 3707 QString svDirBase = ".sv1";
Chris@11 3708 QString svDir = QDir::home().filePath(svDirBase);
Chris@11 3709
Chris@11 3710 if (!QFileInfo(svDir).exists()) {
Chris@11 3711 if (!QDir::home().mkdir(svDirBase)) return false;
Chris@11 3712 } else {
Chris@11 3713 if (!QFileInfo(svDir).isDir()) return false;
Chris@11 3714 }
Chris@11 3715
Chris@11 3716 // This name doesn't have to be unguessable
Chris@93 3717 #ifndef _WIN32
Chris@11 3718 QString fname = QString("tmp-%1-%2.sv")
Chris@11 3719 .arg(QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz"))
Chris@11 3720 .arg(QProcess().pid());
Chris@93 3721 #else
Chris@93 3722 QString fname = QString("tmp-%1.sv")
Chris@93 3723 .arg(QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz"));
Chris@93 3724 #endif
Chris@11 3725 QString fpath = QDir(svDir).filePath(fname);
Chris@11 3726 if (saveSessionFile(fpath)) {
Chris@34 3727 m_recentFiles.addFile(fpath);
Chris@11 3728 return true;
Chris@11 3729 } else {
Chris@11 3730 return false;
Chris@11 3731 }
Chris@11 3732 }
Chris@11 3733 }
Chris@11 3734
Chris@11 3735 bool
Chris@0 3736 MainWindow::checkSaveModified()
Chris@0 3737 {
Chris@0 3738 // Called before some destructive operation (e.g. new session,
Chris@0 3739 // exit program). Return true if we can safely proceed, false to
Chris@0 3740 // cancel.
Chris@0 3741
Chris@0 3742 if (!m_documentModified) return true;
Chris@0 3743
Chris@0 3744 int button =
Chris@0 3745 QMessageBox::warning(this,
Chris@0 3746 tr("Session modified"),
Chris@193 3747 tr("<b>Session modified</b><p>The current session has been modified.<br>Do you want to save it?<br>"),
Chris@165 3748 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
Chris@165 3749 QMessageBox::Yes);
Chris@0 3750
Chris@0 3751 if (button == QMessageBox::Yes) {
Chris@0 3752 saveSession();
Chris@0 3753 if (m_documentModified) { // save failed -- don't proceed!
Chris@0 3754 return false;
Chris@0 3755 } else {
Chris@0 3756 return true; // saved, so it's safe to continue now
Chris@0 3757 }
Chris@0 3758 } else if (button == QMessageBox::No) {
Chris@0 3759 m_documentModified = false; // so we know to abandon it
Chris@0 3760 return true;
Chris@0 3761 }
Chris@0 3762
Chris@0 3763 // else cancel
Chris@0 3764 return false;
Chris@0 3765 }
Chris@0 3766
Chris@0 3767 void
Chris@0 3768 MainWindow::saveSession()
Chris@0 3769 {
Chris@0 3770 if (m_sessionFile != "") {
Chris@0 3771 if (!saveSessionFile(m_sessionFile)) {
Chris@0 3772 QMessageBox::critical(this, tr("Failed to save file"),
Chris@193 3773 tr("<b>Save failed</b><p>Session file \"%1\" could not be saved.").arg(m_sessionFile));
Chris@0 3774 } else {
Chris@0 3775 CommandHistory::getInstance()->documentSaved();
Chris@0 3776 documentRestored();
Chris@0 3777 }
Chris@0 3778 } else {
Chris@0 3779 saveSessionAs();
Chris@0 3780 }
Chris@0 3781 }
Chris@0 3782
Chris@0 3783 void
Chris@0 3784 MainWindow::saveSessionAs()
Chris@0 3785 {
Chris@0 3786 QString orig = m_audioFile;
Chris@0 3787 if (orig == "") orig = ".";
Chris@0 3788 else orig = QFileInfo(orig).absoluteDir().canonicalPath();
Chris@0 3789
Chris@88 3790 QString path = getSaveFileName(FileFinder::SessionFile);
Chris@81 3791
Chris@81 3792 if (path == "") return;
Chris@0 3793
Chris@0 3794 if (!saveSessionFile(path)) {
Chris@0 3795 QMessageBox::critical(this, tr("Failed to save file"),
Chris@193 3796 tr("<b>Save failed</b><p>Session file \"%1\" could not be saved.").arg(path));
Chris@0 3797 } else {
Chris@0 3798 setWindowTitle(tr("Sonic Visualiser: %1")
Chris@0 3799 .arg(QFileInfo(path).fileName()));
Chris@0 3800 m_sessionFile = path;
Chris@0 3801 CommandHistory::getInstance()->documentSaved();
Chris@0 3802 documentRestored();
Chris@34 3803 m_recentFiles.addFile(path);
Chris@0 3804 }
Chris@0 3805 }
Chris@0 3806
Chris@0 3807 bool
Chris@0 3808 MainWindow::saveSessionFile(QString path)
Chris@0 3809 {
Chris@0 3810 BZipFileDevice bzFile(path);
Chris@0 3811 if (!bzFile.open(QIODevice::WriteOnly)) {
Chris@0 3812 std::cerr << "Failed to open session file \"" << path.toStdString()
Chris@0 3813 << "\" for writing: "
Chris@0 3814 << bzFile.errorString().toStdString() << std::endl;
Chris@0 3815 return false;
Chris@0 3816 }
Chris@0 3817
Chris@0 3818 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
Chris@0 3819
Chris@0 3820 QTextStream out(&bzFile);
Chris@0 3821 toXml(out);
Chris@0 3822 out.flush();
Chris@0 3823
Chris@0 3824 QApplication::restoreOverrideCursor();
Chris@0 3825
Chris@84 3826 if (!bzFile.isOK()) {
Chris@0 3827 QMessageBox::critical(this, tr("Failed to write file"),
Chris@193 3828 tr("<b>Save failed</b><p>Failed to write to file \"%1\": %2")
Chris@0 3829 .arg(path).arg(bzFile.errorString()));
Chris@0 3830 bzFile.close();
Chris@0 3831 return false;
Chris@0 3832 }
Chris@0 3833
Chris@0 3834 bzFile.close();
Chris@0 3835 return true;
Chris@0 3836 }
Chris@0 3837
Chris@0 3838 void
Chris@0 3839 MainWindow::toXml(QTextStream &out)
Chris@0 3840 {
Chris@0 3841 QString indent(" ");
Chris@0 3842
Chris@0 3843 out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
Chris@0 3844 out << "<!DOCTYPE sonic-visualiser>\n";
Chris@0 3845 out << "<sv>\n";
Chris@0 3846
Chris@0 3847 m_document->toXml(out, "", "");
Chris@0 3848
Chris@0 3849 out << "<display>\n";
Chris@0 3850
Chris@0 3851 out << QString(" <window width=\"%1\" height=\"%2\"/>\n")
Chris@0 3852 .arg(width()).arg(height());
Chris@0 3853
Chris@0 3854 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@0 3855
Chris@0 3856 Pane *pane = m_paneStack->getPane(i);
Chris@0 3857
Chris@0 3858 if (pane) {
Chris@0 3859 pane->toXml(out, indent);
Chris@0 3860 }
Chris@0 3861 }
Chris@0 3862
Chris@0 3863 out << "</display>\n";
Chris@0 3864
Chris@0 3865 m_viewManager->getSelection().toXml(out);
Chris@0 3866
Chris@0 3867 out << "</sv>\n";
Chris@0 3868 }
Chris@0 3869
Chris@0 3870 Pane *
Chris@0 3871 MainWindow::addPaneToStack()
Chris@0 3872 {
Chris@0 3873 AddPaneCommand *command = new AddPaneCommand(this);
Chris@0 3874 CommandHistory::getInstance()->addCommand(command);
Chris@0 3875 return command->getPane();
Chris@0 3876 }
Chris@0 3877
Chris@0 3878 void
Chris@0 3879 MainWindow::zoomIn()
Chris@0 3880 {
Chris@0 3881 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@0 3882 if (currentPane) currentPane->zoom(true);
Chris@0 3883 }
Chris@0 3884
Chris@0 3885 void
Chris@0 3886 MainWindow::zoomOut()
Chris@0 3887 {
Chris@0 3888 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@0 3889 if (currentPane) currentPane->zoom(false);
Chris@0 3890 }
Chris@0 3891
Chris@0 3892 void
Chris@0 3893 MainWindow::zoomToFit()
Chris@0 3894 {
Chris@0 3895 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@0 3896 if (!currentPane) return;
Chris@0 3897
Chris@0 3898 Model *model = getMainModel();
Chris@0 3899 if (!model) return;
Chris@0 3900
Chris@0 3901 size_t start = model->getStartFrame();
Chris@0 3902 size_t end = model->getEndFrame();
Chris@0 3903 size_t pixels = currentPane->width();
Chris@159 3904
Chris@158 3905 size_t sw = currentPane->getVerticalScaleWidth();
Chris@158 3906 if (pixels > sw * 2) pixels -= sw * 2;
Chris@158 3907 else pixels = 1;
Chris@159 3908 if (pixels > 4) pixels -= 4;
Chris@159 3909
Chris@0 3910 size_t zoomLevel = (end - start) / pixels;
Chris@0 3911
Chris@0 3912 currentPane->setZoomLevel(zoomLevel);
Chris@159 3913 currentPane->setCentreFrame((start + end) / 2);
Chris@0 3914 }
Chris@0 3915
Chris@0 3916 void
Chris@0 3917 MainWindow::zoomDefault()
Chris@0 3918 {
Chris@0 3919 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@0 3920 if (currentPane) currentPane->setZoomLevel(1024);
Chris@0 3921 }
Chris@0 3922
Chris@0 3923 void
Chris@0 3924 MainWindow::scrollLeft()
Chris@0 3925 {
Chris@0 3926 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@0 3927 if (currentPane) currentPane->scroll(false, false);
Chris@0 3928 }
Chris@0 3929
Chris@0 3930 void
Chris@0 3931 MainWindow::jumpLeft()
Chris@0 3932 {
Chris@0 3933 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@0 3934 if (currentPane) currentPane->scroll(false, true);
Chris@0 3935 }
Chris@0 3936
Chris@0 3937 void
Chris@0 3938 MainWindow::scrollRight()
Chris@0 3939 {
Chris@0 3940 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@0 3941 if (currentPane) currentPane->scroll(true, false);
Chris@0 3942 }
Chris@0 3943
Chris@0 3944 void
Chris@0 3945 MainWindow::jumpRight()
Chris@0 3946 {
Chris@0 3947 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@0 3948 if (currentPane) currentPane->scroll(true, true);
Chris@0 3949 }
Chris@0 3950
Chris@0 3951 void
Chris@0 3952 MainWindow::showNoOverlays()
Chris@0 3953 {
Chris@0 3954 m_viewManager->setOverlayMode(ViewManager::NoOverlays);
Chris@0 3955 }
Chris@0 3956
Chris@0 3957 void
Chris@90 3958 MainWindow::showMinimalOverlays()
Chris@0 3959 {
Chris@90 3960 m_viewManager->setOverlayMode(ViewManager::MinimalOverlays);
Chris@0 3961 }
Chris@0 3962
Chris@0 3963 void
Chris@90 3964 MainWindow::showStandardOverlays()
Chris@90 3965 {
Chris@90 3966 m_viewManager->setOverlayMode(ViewManager::StandardOverlays);
Chris@90 3967 }
Chris@90 3968
Chris@90 3969 void
Chris@90 3970 MainWindow::showAllOverlays()
Chris@0 3971 {
Chris@0 3972 m_viewManager->setOverlayMode(ViewManager::AllOverlays);
Chris@0 3973 }
Chris@0 3974
Chris@0 3975 void
Chris@7 3976 MainWindow::toggleZoomWheels()
Chris@7 3977 {
Chris@7 3978 if (m_viewManager->getZoomWheelsEnabled()) {
Chris@7 3979 m_viewManager->setZoomWheelsEnabled(false);
Chris@7 3980 } else {
Chris@7 3981 m_viewManager->setZoomWheelsEnabled(true);
Chris@7 3982 }
Chris@7 3983 }
Chris@7 3984
Chris@7 3985 void
Chris@72 3986 MainWindow::togglePropertyBoxes()
Chris@72 3987 {
Chris@72 3988 if (m_paneStack->getLayoutStyle() == PaneStack::NoPropertyStacks) {
Chris@72 3989 if (Preferences::getInstance()->getPropertyBoxLayout() ==
Chris@72 3990 Preferences::VerticallyStacked) {
Chris@72 3991 m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout);
Chris@72 3992 } else {
Chris@72 3993 m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout);
Chris@72 3994 }
Chris@72 3995 } else {
Chris@72 3996 m_paneStack->setLayoutStyle(PaneStack::NoPropertyStacks);
Chris@72 3997 }
Chris@72 3998 }
Chris@72 3999
Chris@72 4000 void
Chris@90 4001 MainWindow::toggleStatusBar()
Chris@90 4002 {
Chris@90 4003 QSettings settings;
Chris@90 4004 settings.beginGroup("MainWindow");
Chris@90 4005 bool sb = settings.value("showstatusbar", true).toBool();
Chris@90 4006
Chris@90 4007 if (sb) {
Chris@90 4008 statusBar()->hide();
Chris@90 4009 } else {
Chris@90 4010 statusBar()->show();
Chris@90 4011 }
Chris@90 4012
Chris@90 4013 settings.setValue("showstatusbar", !sb);
Chris@90 4014
Chris@90 4015 settings.endGroup();
Chris@90 4016 }
Chris@90 4017
Chris@90 4018 void
Chris@72 4019 MainWindow::preferenceChanged(PropertyContainer::PropertyName name)
Chris@72 4020 {
Chris@72 4021 if (name == "Property Box Layout") {
Chris@72 4022 if (m_paneStack->getLayoutStyle() != PaneStack::NoPropertyStacks) {
Chris@72 4023 if (Preferences::getInstance()->getPropertyBoxLayout() ==
Chris@72 4024 Preferences::VerticallyStacked) {
Chris@72 4025 m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout);
Chris@72 4026 } else {
Chris@72 4027 m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout);
Chris@72 4028 }
Chris@72 4029 }
Chris@180 4030 } else if (name == "Background Mode" && m_viewManager) {
Chris@180 4031 Preferences::BackgroundMode mode =
Chris@180 4032 Preferences::getInstance()->getBackgroundMode();
Chris@180 4033 if (mode == Preferences::BackgroundFromTheme) {
Chris@180 4034 m_viewManager->setGlobalDarkBackground(m_initialDarkBackground);
Chris@180 4035 } else if (mode == Preferences::DarkBackground) {
Chris@180 4036 m_viewManager->setGlobalDarkBackground(true);
Chris@180 4037 } else {
Chris@180 4038 m_viewManager->setGlobalDarkBackground(false);
Chris@180 4039 }
Chris@180 4040 if (m_viewManager->getGlobalDarkBackground()) {
Chris@180 4041 m_panLayer->setBaseColour
Chris@180 4042 (ColourDatabase::getInstance()->getColourIndex(tr("Bright Green")));
Chris@180 4043 } else {
Chris@180 4044 m_panLayer->setBaseColour
Chris@180 4045 (ColourDatabase::getInstance()->getColourIndex(tr("Green")));
Chris@180 4046 }
Chris@180 4047 }
Chris@72 4048 }
Chris@72 4049
Chris@72 4050 void
Chris@0 4051 MainWindow::play()
Chris@0 4052 {
Chris@0 4053 if (m_playSource->isPlaying()) {
Chris@116 4054 stop();
Chris@0 4055 } else {
Chris@116 4056 playbackFrameChanged(m_viewManager->getPlaybackFrame());
Chris@0 4057 m_playSource->play(m_viewManager->getPlaybackFrame());
Chris@0 4058 }
Chris@0 4059 }
Chris@0 4060
Chris@0 4061 void
Chris@0 4062 MainWindow::ffwd()
Chris@0 4063 {
Chris@0 4064 if (!getMainModel()) return;
Chris@0 4065
Chris@0 4066 int frame = m_viewManager->getPlaybackFrame();
Chris@0 4067 ++frame;
Chris@0 4068
Chris@155 4069 Layer *layer = getSnapLayer();
Chris@155 4070 size_t sr = getMainModel()->getSampleRate();
Chris@155 4071
Chris@155 4072 if (!layer) {
Chris@155 4073
Chris@155 4074 frame = RealTime::realTime2Frame
Chris@155 4075 (RealTime::frame2RealTime(frame, sr) + RealTime(2, 0), sr);
Chris@155 4076 if (frame > int(getMainModel()->getEndFrame())) {
Chris@155 4077 frame = getMainModel()->getEndFrame();
Chris@155 4078 }
Chris@155 4079
Chris@155 4080 } else {
Chris@155 4081
Chris@155 4082 size_t resolution = 0;
Chris@155 4083 if (!layer->snapToFeatureFrame(m_paneStack->getCurrentPane(),
Chris@155 4084 frame, resolution, Layer::SnapRight)) {
Chris@155 4085 frame = getMainModel()->getEndFrame();
Chris@155 4086 }
Chris@0 4087 }
Chris@155 4088
Chris@155 4089 if (frame < 0) frame = 0;
Chris@147 4090
Chris@147 4091 if (m_viewManager->getPlaySelectionMode()) {
Chris@155 4092 frame = m_viewManager->constrainFrameToSelection(size_t(frame));
Chris@147 4093 }
Chris@0 4094
Chris@0 4095 m_viewManager->setPlaybackFrame(frame);
Chris@0 4096 }
Chris@0 4097
Chris@0 4098 void
Chris@0 4099 MainWindow::ffwdEnd()
Chris@0 4100 {
Chris@0 4101 if (!getMainModel()) return;
Chris@147 4102
Chris@147 4103 size_t frame = getMainModel()->getEndFrame();
Chris@147 4104
Chris@147 4105 if (m_viewManager->getPlaySelectionMode()) {
Chris@155 4106 frame = m_viewManager->constrainFrameToSelection(frame);
Chris@147 4107 }
Chris@147 4108
Chris@147 4109 m_viewManager->setPlaybackFrame(frame);
Chris@0 4110 }
Chris@0 4111
Chris@0 4112 void
Chris@0 4113 MainWindow::rewind()
Chris@0 4114 {
Chris@0 4115 if (!getMainModel()) return;
Chris@0 4116
Chris@0 4117 int frame = m_viewManager->getPlaybackFrame();
Chris@0 4118 if (frame > 0) --frame;
Chris@0 4119
Chris@155 4120 Layer *layer = getSnapLayer();
Chris@155 4121 size_t sr = getMainModel()->getSampleRate();
Chris@156 4122
Chris@156 4123 // when rewinding during playback, we want to allow a period
Chris@156 4124 // following a rewind target point at which the rewind will go to
Chris@156 4125 // the prior point instead of the immediately neighbouring one
Chris@156 4126 if (m_playSource && m_playSource->isPlaying()) {
Chris@156 4127 RealTime ct = RealTime::frame2RealTime(frame, sr);
Chris@156 4128 ct = ct - RealTime::fromSeconds(0.25);
Chris@156 4129 if (ct < RealTime::zeroTime) ct = RealTime::zeroTime;
Chris@156 4130 // std::cerr << "rewind: frame " << frame << " -> ";
Chris@156 4131 frame = RealTime::realTime2Frame(ct, sr);
Chris@156 4132 // std::cerr << frame << std::endl;
Chris@156 4133 }
Chris@155 4134
Chris@155 4135 if (!layer) {
Chris@155 4136
Chris@155 4137 frame = RealTime::realTime2Frame
Chris@155 4138 (RealTime::frame2RealTime(frame, sr) - RealTime(2, 0), sr);
Chris@155 4139 if (frame < int(getMainModel()->getStartFrame())) {
Chris@155 4140 frame = getMainModel()->getStartFrame();
Chris@155 4141 }
Chris@155 4142
Chris@155 4143 } else {
Chris@155 4144
Chris@155 4145 size_t resolution = 0;
Chris@155 4146 if (!layer->snapToFeatureFrame(m_paneStack->getCurrentPane(),
Chris@155 4147 frame, resolution, Layer::SnapLeft)) {
Chris@155 4148 frame = getMainModel()->getStartFrame();
Chris@155 4149 }
Chris@0 4150 }
Chris@147 4151
Chris@155 4152 if (frame < 0) frame = 0;
Chris@155 4153
Chris@147 4154 if (m_viewManager->getPlaySelectionMode()) {
Chris@155 4155 frame = m_viewManager->constrainFrameToSelection(size_t(frame));
Chris@147 4156 }
Chris@147 4157
Chris@0 4158 m_viewManager->setPlaybackFrame(frame);
Chris@0 4159 }
Chris@0 4160
Chris@0 4161 void
Chris@0 4162 MainWindow::rewindStart()
Chris@0 4163 {
Chris@0 4164 if (!getMainModel()) return;
Chris@147 4165
Chris@147 4166 size_t frame = getMainModel()->getStartFrame();
Chris@147 4167
Chris@147 4168 if (m_viewManager->getPlaySelectionMode()) {
Chris@155 4169 frame = m_viewManager->constrainFrameToSelection(frame);
Chris@155 4170 }
Chris@155 4171
Chris@155 4172 m_viewManager->setPlaybackFrame(frame);
Chris@155 4173 }
Chris@155 4174
Chris@155 4175 Layer *
Chris@155 4176 MainWindow::getSnapLayer() const
Chris@155 4177 {
Chris@155 4178 Pane *pane = m_paneStack->getCurrentPane();
Chris@155 4179 if (!pane) return 0;
Chris@155 4180
Chris@155 4181 Layer *layer = pane->getSelectedLayer();
Chris@155 4182
Chris@155 4183 if (!dynamic_cast<TimeInstantLayer *>(layer) &&
Chris@155 4184 !dynamic_cast<TimeValueLayer *>(layer) &&
Chris@155 4185 !dynamic_cast<TimeRulerLayer *>(layer)) {
Chris@155 4186
Chris@155 4187 layer = 0;
Chris@155 4188
Chris@155 4189 for (int i = pane->getLayerCount(); i > 0; --i) {
Chris@155 4190 Layer *l = pane->getLayer(i-1);
Chris@155 4191 if (dynamic_cast<TimeRulerLayer *>(l)) {
Chris@155 4192 layer = l;
Chris@155 4193 break;
Chris@155 4194 }
Chris@147 4195 }
Chris@147 4196 }
Chris@147 4197
Chris@155 4198 return layer;
Chris@0 4199 }
Chris@0 4200
Chris@0 4201 void
Chris@0 4202 MainWindow::stop()
Chris@0 4203 {
Chris@0 4204 m_playSource->stop();
Chris@116 4205
Chris@116 4206 if (m_paneStack && m_paneStack->getCurrentPane()) {
Chris@116 4207 updateVisibleRangeDisplay(m_paneStack->getCurrentPane());
Chris@116 4208 } else {
Chris@116 4209 m_myStatusMessage = "";
Chris@116 4210 statusBar()->showMessage("");
Chris@116 4211 }
Chris@0 4212 }
Chris@0 4213
Chris@0 4214 void
Chris@0 4215 MainWindow::addPane()
Chris@0 4216 {
Chris@0 4217 QObject *s = sender();
Chris@0 4218 QAction *action = dynamic_cast<QAction *>(s);
Chris@0 4219
Chris@0 4220 if (!action) {
Chris@0 4221 std::cerr << "WARNING: MainWindow::addPane: sender is not an action"
Chris@0 4222 << std::endl;
Chris@0 4223 return;
Chris@0 4224 }
Chris@0 4225
Chris@0 4226 PaneActionMap::iterator i = m_paneActions.find(action);
Chris@0 4227
Chris@0 4228 if (i == m_paneActions.end()) {
Chris@0 4229 std::cerr << "WARNING: MainWindow::addPane: unknown action "
Chris@0 4230 << action->objectName().toStdString() << std::endl;
Chris@0 4231 return;
Chris@0 4232 }
Chris@0 4233
Chris@69 4234 addPane(i->second, action->text());
Chris@69 4235 }
Chris@69 4236
Chris@69 4237 void
Chris@69 4238 MainWindow::addPane(const PaneConfiguration &configuration, QString text)
Chris@69 4239 {
Chris@69 4240 CommandHistory::getInstance()->startCompoundOperation(text, true);
Chris@0 4241
Chris@0 4242 AddPaneCommand *command = new AddPaneCommand(this);
Chris@0 4243 CommandHistory::getInstance()->addCommand(command);
Chris@0 4244
Chris@0 4245 Pane *pane = command->getPane();
Chris@0 4246
Chris@69 4247 if (configuration.layer == LayerFactory::Spectrum) {
Chris@109 4248 pane->setPlaybackFollow(PlaybackScrollContinuous);
Chris@110 4249 pane->setFollowGlobalZoom(false);
Chris@112 4250 pane->setZoomLevel(512);
Chris@7 4251 }
Chris@7 4252
Chris@69 4253 if (configuration.layer != LayerFactory::TimeRuler &&
Chris@69 4254 configuration.layer != LayerFactory::Spectrum) {
Chris@8 4255
Chris@0 4256 if (!m_timeRulerLayer) {
Chris@0 4257 // std::cerr << "no time ruler layer, creating one" << std::endl;
Chris@0 4258 m_timeRulerLayer = m_document->createMainModelLayer
Chris@0 4259 (LayerFactory::TimeRuler);
Chris@0 4260 }
Chris@0 4261
Chris@0 4262 // std::cerr << "adding time ruler layer " << m_timeRulerLayer << std::endl;
Chris@0 4263
Chris@0 4264 m_document->addLayerToView(pane, m_timeRulerLayer);
Chris@0 4265 }
Chris@0 4266
Chris@69 4267 Layer *newLayer = m_document->createLayer(configuration.layer);
Chris@69 4268
Chris@69 4269 Model *suggestedModel = configuration.sourceModel;
Chris@66 4270 Model *model = 0;
Chris@66 4271
Chris@66 4272 if (suggestedModel) {
Chris@66 4273
Chris@66 4274 // check its validity
Chris@66 4275 std::vector<Model *> inputModels = m_document->getTransformInputModels();
Chris@66 4276 for (size_t j = 0; j < inputModels.size(); ++j) {
Chris@66 4277 if (inputModels[j] == suggestedModel) {
Chris@66 4278 model = suggestedModel;
Chris@66 4279 break;
Chris@66 4280 }
Chris@66 4281 }
Chris@66 4282
Chris@66 4283 if (!model) {
Chris@66 4284 std::cerr << "WARNING: Model " << (void *)suggestedModel
Chris@66 4285 << " appears in pane action map, but is not reported "
Chris@66 4286 << "by document as a valid transform source" << std::endl;
Chris@66 4287 }
Chris@66 4288 }
Chris@66 4289
Chris@66 4290 if (!model) model = m_document->getMainModel();
Chris@66 4291
Chris@66 4292 m_document->setModel(newLayer, model);
Chris@66 4293
Chris@69 4294 m_document->setChannel(newLayer, configuration.channel);
Chris@0 4295 m_document->addLayerToView(pane, newLayer);
Chris@0 4296
Chris@0 4297 m_paneStack->setCurrentPane(pane);
Chris@70 4298 m_paneStack->setCurrentLayer(pane, newLayer);
Chris@0 4299
Chris@130 4300 // std::cerr << "MainWindow::addPane: global centre frame is "
Chris@130 4301 // << m_viewManager->getGlobalCentreFrame() << std::endl;
Chris@130 4302 // pane->setCentreFrame(m_viewManager->getGlobalCentreFrame());
Chris@73 4303
Chris@0 4304 CommandHistory::getInstance()->endCompoundOperation();
Chris@0 4305
Chris@0 4306 updateMenuStates();
Chris@0 4307 }
Chris@0 4308
Chris@0 4309 MainWindow::AddPaneCommand::AddPaneCommand(MainWindow *mw) :
Chris@0 4310 m_mw(mw),
Chris@0 4311 m_pane(0),
Chris@0 4312 m_prevCurrentPane(0),
Chris@0 4313 m_added(false)
Chris@0 4314 {
Chris@0 4315 }
Chris@0 4316
Chris@0 4317 MainWindow::AddPaneCommand::~AddPaneCommand()
Chris@0 4318 {
Chris@0 4319 if (m_pane && !m_added) {
Chris@0 4320 m_mw->m_paneStack->deletePane(m_pane);
Chris@0 4321 }
Chris@0 4322 }
Chris@0 4323
Chris@0 4324 QString
Chris@0 4325 MainWindow::AddPaneCommand::getName() const
Chris@0 4326 {
Chris@0 4327 return tr("Add Pane");
Chris@0 4328 }
Chris@0 4329
Chris@0 4330 void
Chris@0 4331 MainWindow::AddPaneCommand::execute()
Chris@0 4332 {
Chris@0 4333 if (!m_pane) {
Chris@0 4334 m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane();
Chris@0 4335 m_pane = m_mw->m_paneStack->addPane();
Chris@90 4336
Chris@90 4337 connect(m_pane, SIGNAL(contextHelpChanged(const QString &)),
Chris@116 4338 m_mw, SLOT(contextHelpChanged(const QString &)));
Chris@0 4339 } else {
Chris@0 4340 m_mw->m_paneStack->showPane(m_pane);
Chris@0 4341 }
Chris@0 4342
Chris@0 4343 m_mw->m_paneStack->setCurrentPane(m_pane);
Chris@65 4344 m_mw->m_overview->registerView(m_pane);
Chris@0 4345 m_added = true;
Chris@0 4346 }
Chris@0 4347
Chris@0 4348 void
Chris@0 4349 MainWindow::AddPaneCommand::unexecute()
Chris@0 4350 {
Chris@0 4351 m_mw->m_paneStack->hidePane(m_pane);
Chris@0 4352 m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane);
Chris@65 4353 m_mw->m_overview->unregisterView(m_pane);
Chris@0 4354 m_added = false;
Chris@0 4355 }
Chris@0 4356
Chris@0 4357 MainWindow::RemovePaneCommand::RemovePaneCommand(MainWindow *mw, Pane *pane) :
Chris@0 4358 m_mw(mw),
Chris@0 4359 m_pane(pane),
Chris@0 4360 m_added(true)
Chris@0 4361 {
Chris@0 4362 }
Chris@0 4363
Chris@0 4364 MainWindow::RemovePaneCommand::~RemovePaneCommand()
Chris@0 4365 {
Chris@0 4366 if (m_pane && !m_added) {
Chris@0 4367 m_mw->m_paneStack->deletePane(m_pane);
Chris@0 4368 }
Chris@0 4369 }
Chris@0 4370
Chris@0 4371 QString
Chris@0 4372 MainWindow::RemovePaneCommand::getName() const
Chris@0 4373 {
Chris@0 4374 return tr("Remove Pane");
Chris@0 4375 }
Chris@0 4376
Chris@0 4377 void
Chris@0 4378 MainWindow::RemovePaneCommand::execute()
Chris@0 4379 {
Chris@0 4380 m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane();
Chris@0 4381 m_mw->m_paneStack->hidePane(m_pane);
Chris@65 4382 m_mw->m_overview->unregisterView(m_pane);
Chris@0 4383 m_added = false;
Chris@0 4384 }
Chris@0 4385
Chris@0 4386 void
Chris@0 4387 MainWindow::RemovePaneCommand::unexecute()
Chris@0 4388 {
Chris@0 4389 m_mw->m_paneStack->showPane(m_pane);
Chris@0 4390 m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane);
Chris@65 4391 m_mw->m_overview->registerView(m_pane);
Chris@0 4392 m_added = true;
Chris@0 4393 }
Chris@0 4394
Chris@0 4395 void
Chris@0 4396 MainWindow::addLayer()
Chris@0 4397 {
Chris@0 4398 QObject *s = sender();
Chris@0 4399 QAction *action = dynamic_cast<QAction *>(s);
Chris@0 4400
Chris@0 4401 if (!action) {
Chris@0 4402 std::cerr << "WARNING: MainWindow::addLayer: sender is not an action"
Chris@0 4403 << std::endl;
Chris@0 4404 return;
Chris@0 4405 }
Chris@0 4406
Chris@0 4407 Pane *pane = m_paneStack->getCurrentPane();
Chris@0 4408
Chris@0 4409 if (!pane) {
Chris@0 4410 std::cerr << "WARNING: MainWindow::addLayer: no current pane" << std::endl;
Chris@0 4411 return;
Chris@0 4412 }
Chris@0 4413
Chris@0 4414 ExistingLayerActionMap::iterator ei = m_existingLayerActions.find(action);
Chris@0 4415
Chris@0 4416 if (ei != m_existingLayerActions.end()) {
Chris@0 4417 Layer *newLayer = ei->second;
Chris@0 4418 m_document->addLayerToView(pane, newLayer);
Chris@0 4419 m_paneStack->setCurrentLayer(pane, newLayer);
Chris@0 4420 return;
Chris@0 4421 }
Chris@0 4422
Chris@95 4423 ei = m_sliceActions.find(action);
Chris@95 4424
Chris@95 4425 if (ei != m_sliceActions.end()) {
Chris@95 4426 Layer *newLayer = m_document->createLayer(LayerFactory::Slice);
Chris@95 4427 // document->setModel(newLayer, ei->second->getModel());
Chris@95 4428 SliceableLayer *source = dynamic_cast<SliceableLayer *>(ei->second);
Chris@95 4429 SliceLayer *dest = dynamic_cast<SliceLayer *>(newLayer);
Chris@95 4430 if (source && dest) {
Chris@95 4431 dest->setSliceableModel(source->getSliceableModel());
Chris@95 4432 connect(source, SIGNAL(sliceableModelReplaced(const Model *, const Model *)),
Chris@95 4433 dest, SLOT(sliceableModelReplaced(const Model *, const Model *)));
Chris@95 4434 connect(m_document, SIGNAL(modelAboutToBeDeleted(Model *)),
Chris@95 4435 dest, SLOT(modelAboutToBeDeleted(Model *)));
Chris@95 4436 }
Chris@95 4437 m_document->addLayerToView(pane, newLayer);
Chris@95 4438 m_paneStack->setCurrentLayer(pane, newLayer);
Chris@95 4439 return;
Chris@95 4440 }
Chris@95 4441
Chris@34 4442 TransformActionMap::iterator i = m_transformActions.find(action);
Chris@34 4443
Chris@34 4444 if (i == m_transformActions.end()) {
Chris@0 4445
Chris@0 4446 LayerActionMap::iterator i = m_layerActions.find(action);
Chris@0 4447
Chris@0 4448 if (i == m_layerActions.end()) {
Chris@0 4449 std::cerr << "WARNING: MainWindow::addLayer: unknown action "
Chris@0 4450 << action->objectName().toStdString() << std::endl;
Chris@0 4451 return;
Chris@0 4452 }
Chris@0 4453
Chris@0 4454 LayerFactory::LayerType type = i->second;
Chris@0 4455
Chris@0 4456 LayerFactory::LayerTypeSet emptyTypes =
Chris@0 4457 LayerFactory::getInstance()->getValidEmptyLayerTypes();
Chris@0 4458
Chris@0 4459 Layer *newLayer;
Chris@0 4460
Chris@0 4461 if (emptyTypes.find(type) != emptyTypes.end()) {
Chris@0 4462
Chris@0 4463 newLayer = m_document->createEmptyLayer(type);
Chris@0 4464 m_toolActions[ViewManager::DrawMode]->trigger();
Chris@0 4465
Chris@0 4466 } else {
Chris@0 4467
Chris@0 4468 newLayer = m_document->createMainModelLayer(type);
Chris@0 4469 }
Chris@0 4470
Chris@0 4471 m_document->addLayerToView(pane, newLayer);
Chris@0 4472 m_paneStack->setCurrentLayer(pane, newLayer);
Chris@0 4473
Chris@0 4474 return;
Chris@0 4475 }
Chris@0 4476
Chris@107 4477 TransformId transform = i->second;
Chris@0 4478 TransformFactory *factory = TransformFactory::getInstance();
Chris@0 4479
Chris@0 4480 QString configurationXml;
Chris@0 4481
Chris@0 4482 int channel = -1;
Chris@0 4483 // pick up the default channel from any existing layers on the same pane
Chris@0 4484 for (int j = 0; j < pane->getLayerCount(); ++j) {
Chris@0 4485 int c = LayerFactory::getInstance()->getChannel(pane->getLayer(j));
Chris@0 4486 if (c != -1) {
Chris@0 4487 channel = c;
Chris@0 4488 break;
Chris@0 4489 }
Chris@0 4490 }
Chris@0 4491
Chris@33 4492 // We always ask for configuration, even if the plugin isn't
Chris@33 4493 // supposed to be configurable, because we need to let the user
Chris@33 4494 // change the execution context (block size etc).
Chris@0 4495
Chris@27 4496 PluginTransform::ExecutionContext context(channel);
Chris@27 4497
Chris@66 4498 std::vector<Model *> candidateInputModels =
Chris@66 4499 m_document->getTransformInputModels();
Chris@53 4500
Chris@184 4501 size_t startFrame = 0, duration = 0;
Chris@184 4502 size_t endFrame = 0;
Chris@184 4503 m_viewManager->getSelection().getExtents(startFrame, endFrame);
Chris@184 4504 if (endFrame > startFrame) duration = endFrame - startFrame;
Chris@184 4505 else startFrame = 0;
Chris@184 4506
Chris@54 4507 Model *inputModel = factory->getConfigurationForTransform(transform,
Chris@54 4508 candidateInputModels,
Chris@54 4509 context,
Chris@54 4510 configurationXml,
Chris@184 4511 m_playSource,
Chris@184 4512 startFrame,
Chris@184 4513 duration);
Chris@54 4514 if (!inputModel) return;
Chris@54 4515
Chris@135 4516 // std::cerr << "MainWindow::addLayer: Input model is " << inputModel << " \"" << inputModel->objectName().toStdString() << "\"" << std::endl;
Chris@0 4517
Chris@0 4518 Layer *newLayer = m_document->createDerivedLayer(transform,
Chris@54 4519 inputModel,
Chris@27 4520 context,
Chris@0 4521 configurationXml);
Chris@0 4522
Chris@0 4523 if (newLayer) {
Chris@0 4524 m_document->addLayerToView(pane, newLayer);
Chris@27 4525 m_document->setChannel(newLayer, context.channel);
Chris@34 4526 m_recentTransforms.add(transform);
Chris@70 4527 m_paneStack->setCurrentLayer(pane, newLayer);
Chris@0 4528 }
Chris@0 4529
Chris@0 4530 updateMenuStates();
Chris@0 4531 }
Chris@0 4532
Chris@0 4533 void
Chris@0 4534 MainWindow::deleteCurrentPane()
Chris@0 4535 {
Chris@0 4536 CommandHistory::getInstance()->startCompoundOperation
Chris@0 4537 (tr("Delete Pane"), true);
Chris@0 4538
Chris@0 4539 Pane *pane = m_paneStack->getCurrentPane();
Chris@0 4540 if (pane) {
Chris@0 4541 while (pane->getLayerCount() > 0) {
Chris@0 4542 Layer *layer = pane->getLayer(0);
Chris@0 4543 if (layer) {
Chris@0 4544 m_document->removeLayerFromView(pane, layer);
Chris@0 4545 } else {
Chris@0 4546 break;
Chris@0 4547 }
Chris@0 4548 }
Chris@0 4549
Chris@0 4550 RemovePaneCommand *command = new RemovePaneCommand(this, pane);
Chris@0 4551 CommandHistory::getInstance()->addCommand(command);
Chris@0 4552 }
Chris@0 4553
Chris@0 4554 CommandHistory::getInstance()->endCompoundOperation();
Chris@0 4555
Chris@0 4556 updateMenuStates();
Chris@0 4557 }
Chris@0 4558
Chris@0 4559 void
Chris@0 4560 MainWindow::deleteCurrentLayer()
Chris@0 4561 {
Chris@0 4562 Pane *pane = m_paneStack->getCurrentPane();
Chris@0 4563 if (pane) {
Chris@0 4564 Layer *layer = pane->getSelectedLayer();
Chris@0 4565 if (layer) {
Chris@0 4566 m_document->removeLayerFromView(pane, layer);
Chris@0 4567 }
Chris@0 4568 }
Chris@0 4569 updateMenuStates();
Chris@0 4570 }
Chris@0 4571
Chris@0 4572 void
Chris@0 4573 MainWindow::renameCurrentLayer()
Chris@0 4574 {
Chris@0 4575 Pane *pane = m_paneStack->getCurrentPane();
Chris@0 4576 if (pane) {
Chris@0 4577 Layer *layer = pane->getSelectedLayer();
Chris@0 4578 if (layer) {
Chris@0 4579 bool ok = false;
Chris@0 4580 QString newName = QInputDialog::getText
Chris@0 4581 (this, tr("Rename Layer"),
Chris@0 4582 tr("New name for this layer:"),
Chris@0 4583 QLineEdit::Normal, layer->objectName(), &ok);
Chris@0 4584 if (ok) {
Chris@0 4585 layer->setObjectName(newName);
Chris@95 4586 setupExistingLayersMenus();
Chris@0 4587 }
Chris@0 4588 }
Chris@0 4589 }
Chris@0 4590 }
Chris@0 4591
Chris@0 4592 void
Chris@59 4593 MainWindow::playSpeedChanged(int position)
Chris@0 4594 {
Chris@59 4595 PlaySpeedRangeMapper mapper(0, 200);
Chris@60 4596
Chris@60 4597 float percent = m_playSpeed->mappedValue();
Chris@60 4598 float factor = mapper.getFactorForValue(percent);
Chris@60 4599
Chris@60 4600 std::cerr << "speed = " << position << " percent = " << percent << " factor = " << factor << std::endl;
Chris@60 4601
Chris@59 4602 bool something = (position != 100);
Chris@155 4603
Chris@59 4604 int pc = lrintf(percent);
Chris@21 4605
Chris@155 4606 if (!something) {
Chris@155 4607 contextHelpChanged(tr("Playback speed: Normal"));
Chris@155 4608 } else {
Chris@155 4609 contextHelpChanged(tr("Playback speed: %1%2%")
Chris@155 4610 .arg(position > 100 ? "+" : "")
Chris@155 4611 .arg(pc));
Chris@155 4612 }
Chris@155 4613
Chris@25 4614 m_playSharpen->setEnabled(something);
Chris@26 4615 m_playMono->setEnabled(something);
Chris@25 4616 bool sharpen = (something && m_playSharpen->isChecked());
Chris@26 4617 bool mono = (something && m_playMono->isChecked());
Chris@26 4618 m_playSource->setTimeStretch(factor, sharpen, mono);
Chris@155 4619
Chris@155 4620 updateMenuStates();
Chris@16 4621 }
Chris@16 4622
Chris@16 4623 void
Chris@16 4624 MainWindow::playSharpenToggled()
Chris@16 4625 {
Chris@21 4626 QSettings settings;
Chris@21 4627 settings.beginGroup("MainWindow");
Chris@21 4628 settings.setValue("playsharpen", m_playSharpen->isChecked());
Chris@21 4629 settings.endGroup();
Chris@21 4630
Chris@16 4631 playSpeedChanged(m_playSpeed->value());
Chris@0 4632 }
Chris@0 4633
Chris@0 4634 void
Chris@26 4635 MainWindow::playMonoToggled()
Chris@26 4636 {
Chris@26 4637 QSettings settings;
Chris@26 4638 settings.beginGroup("MainWindow");
Chris@26 4639 settings.setValue("playmono", m_playMono->isChecked());
Chris@26 4640 settings.endGroup();
Chris@26 4641
Chris@26 4642 playSpeedChanged(m_playSpeed->value());
Chris@26 4643 }
Chris@26 4644
Chris@26 4645 void
Chris@155 4646 MainWindow::speedUpPlayback()
Chris@155 4647 {
Chris@155 4648 int value = m_playSpeed->value();
Chris@155 4649 value = value + m_playSpeed->pageStep();
Chris@155 4650 if (value > m_playSpeed->maximum()) value = m_playSpeed->maximum();
Chris@155 4651 m_playSpeed->setValue(value);
Chris@155 4652 }
Chris@155 4653
Chris@155 4654 void
Chris@155 4655 MainWindow::slowDownPlayback()
Chris@155 4656 {
Chris@155 4657 int value = m_playSpeed->value();
Chris@155 4658 value = value - m_playSpeed->pageStep();
Chris@155 4659 if (value < m_playSpeed->minimum()) value = m_playSpeed->minimum();
Chris@155 4660 m_playSpeed->setValue(value);
Chris@155 4661 }
Chris@155 4662
Chris@155 4663 void
Chris@155 4664 MainWindow::restoreNormalPlayback()
Chris@155 4665 {
Chris@155 4666 m_playSpeed->setValue(m_playSpeed->defaultValue());
Chris@155 4667 }
Chris@155 4668
Chris@155 4669 void
Chris@116 4670 MainWindow::playbackFrameChanged(unsigned long frame)
Chris@116 4671 {
Chris@116 4672 if (!(m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
Chris@116 4673
Chris@116 4674 RealTime now = RealTime::frame2RealTime
Chris@116 4675 (frame, getMainModel()->getSampleRate());
Chris@116 4676
Chris@116 4677 if (now.sec == m_lastPlayStatusSec) return;
Chris@116 4678
Chris@116 4679 RealTime then = RealTime::frame2RealTime
Chris@116 4680 (m_playSource->getPlayEndFrame(), getMainModel()->getSampleRate());
Chris@116 4681
Chris@116 4682 QString nowStr;
Chris@116 4683 QString thenStr;
Chris@116 4684 QString remainingStr;
Chris@116 4685
Chris@116 4686 if (then.sec > 10) {
Chris@116 4687 nowStr = now.toSecText().c_str();
Chris@116 4688 thenStr = then.toSecText().c_str();
Chris@116 4689 remainingStr = (then - now).toSecText().c_str();
Chris@116 4690 m_lastPlayStatusSec = now.sec;
Chris@116 4691 } else {
Chris@116 4692 nowStr = now.toText(true).c_str();
Chris@116 4693 thenStr = then.toText(true).c_str();
Chris@116 4694 remainingStr = (then - now).toText(true).c_str();
Chris@116 4695 }
Chris@116 4696
Chris@116 4697 m_myStatusMessage = tr("Playing: %1 of %2 (%3 remaining)")
Chris@116 4698 .arg(nowStr).arg(thenStr).arg(remainingStr);
Chris@116 4699
Chris@116 4700 statusBar()->showMessage(m_myStatusMessage);
Chris@116 4701 }
Chris@116 4702
Chris@116 4703 void
Chris@137 4704 MainWindow::globalCentreFrameChanged(unsigned long )
Chris@116 4705 {
Chris@116 4706 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
Chris@116 4707 Pane *p = 0;
Chris@116 4708 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
Chris@116 4709 if (!p->getFollowGlobalPan()) return;
Chris@116 4710 updateVisibleRangeDisplay(p);
Chris@116 4711 }
Chris@116 4712
Chris@116 4713 void
Chris@137 4714 MainWindow::viewCentreFrameChanged(View *v, unsigned long )
Chris@116 4715 {
Chris@116 4716 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
Chris@116 4717 Pane *p = 0;
Chris@116 4718 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
Chris@116 4719 if (v == p) updateVisibleRangeDisplay(p);
Chris@116 4720 }
Chris@116 4721
Chris@116 4722 void
Chris@137 4723 MainWindow::viewZoomLevelChanged(View *v, unsigned long , bool )
Chris@116 4724 {
Chris@116 4725 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
Chris@116 4726 Pane *p = 0;
Chris@116 4727 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
Chris@116 4728 if (v == p) updateVisibleRangeDisplay(p);
Chris@116 4729 }
Chris@116 4730
Chris@116 4731 void
Chris@116 4732 MainWindow::updateVisibleRangeDisplay(Pane *p) const
Chris@116 4733 {
Chris@116 4734 if (!getMainModel() || !p) {
Chris@116 4735 return;
Chris@116 4736 }
Chris@116 4737
Chris@117 4738 bool haveSelection = false;
Chris@117 4739 size_t startFrame = 0, endFrame = 0;
Chris@117 4740
Chris@117 4741 if (m_viewManager && m_viewManager->haveInProgressSelection()) {
Chris@117 4742
Chris@117 4743 bool exclusive = false;
Chris@117 4744 Selection s = m_viewManager->getInProgressSelection(exclusive);
Chris@117 4745
Chris@117 4746 if (!s.isEmpty()) {
Chris@117 4747 haveSelection = true;
Chris@117 4748 startFrame = s.getStartFrame();
Chris@117 4749 endFrame = s.getEndFrame();
Chris@117 4750 }
Chris@117 4751 }
Chris@117 4752
Chris@117 4753 if (!haveSelection) {
Chris@117 4754 startFrame = p->getFirstVisibleFrame();
Chris@117 4755 endFrame = p->getLastVisibleFrame();
Chris@117 4756 }
Chris@117 4757
Chris@116 4758 RealTime start = RealTime::frame2RealTime
Chris@117 4759 (startFrame, getMainModel()->getSampleRate());
Chris@116 4760
Chris@116 4761 RealTime end = RealTime::frame2RealTime
Chris@117 4762 (endFrame, getMainModel()->getSampleRate());
Chris@116 4763
Chris@116 4764 RealTime duration = end - start;
Chris@116 4765
Chris@116 4766 QString startStr, endStr, durationStr;
Chris@116 4767 startStr = start.toText(true).c_str();
Chris@116 4768 endStr = end.toText(true).c_str();
Chris@116 4769 durationStr = duration.toText(true).c_str();
Chris@116 4770
Chris@117 4771 if (haveSelection) {
Chris@117 4772 m_myStatusMessage = tr("Selection: %1 to %2 (duration %3)")
Chris@117 4773 .arg(startStr).arg(endStr).arg(durationStr);
Chris@117 4774 } else {
Chris@117 4775 m_myStatusMessage = tr("Visible: %1 to %2 (duration %3)")
Chris@117 4776 .arg(startStr).arg(endStr).arg(durationStr);
Chris@117 4777 }
Chris@116 4778
Chris@116 4779 statusBar()->showMessage(m_myStatusMessage);
Chris@116 4780 }
Chris@116 4781
Chris@116 4782 void
Chris@0 4783 MainWindow::outputLevelsChanged(float left, float right)
Chris@0 4784 {
Chris@0 4785 m_fader->setPeakLeft(left);
Chris@0 4786 m_fader->setPeakRight(right);
Chris@0 4787 }
Chris@0 4788
Chris@0 4789 void
Chris@0 4790 MainWindow::sampleRateMismatch(size_t requested, size_t actual,
Chris@0 4791 bool willResample)
Chris@0 4792 {
Chris@0 4793 if (!willResample) {
Chris@0 4794 QMessageBox::information
Chris@0 4795 (this, tr("Sample rate mismatch"),
Chris@193 4796 tr("<b>Wrong sample rate</b><p>The sample rate of this audio file (%1 Hz) does not match\nthe current playback rate (%2 Hz).<p>The file will play at the wrong speed and pitch.<p>Change the <i>Resample mismatching files on import</i> option under <i>File</i> -> <i>Preferences</i> if you want to alter this behaviour.")
Chris@0 4797 .arg(requested).arg(actual));
Chris@0 4798 }
Chris@0 4799
Chris@0 4800 updateDescriptionLabel();
Chris@0 4801 }
Chris@0 4802
Chris@0 4803 void
Chris@42 4804 MainWindow::audioOverloadPluginDisabled()
Chris@42 4805 {
Chris@42 4806 QMessageBox::information
Chris@42 4807 (this, tr("Audio processing overload"),
Chris@193 4808 tr("<b>Overloaded</b><p>Audio effects plugin auditioning has been disabled due to a processing overload."));
Chris@42 4809 }
Chris@42 4810
Chris@42 4811 void
Chris@137 4812 MainWindow::layerAdded(Layer *)
Chris@0 4813 {
Chris@0 4814 // std::cerr << "MainWindow::layerAdded(" << layer << ")" << std::endl;
Chris@0 4815 // setupExistingLayersMenu();
Chris@0 4816 updateMenuStates();
Chris@0 4817 }
Chris@0 4818
Chris@0 4819 void
Chris@137 4820 MainWindow::layerRemoved(Layer *)
Chris@0 4821 {
Chris@0 4822 // std::cerr << "MainWindow::layerRemoved(" << layer << ")" << std::endl;
Chris@95 4823 setupExistingLayersMenus();
Chris@0 4824 updateMenuStates();
Chris@0 4825 }
Chris@0 4826
Chris@0 4827 void
Chris@0 4828 MainWindow::layerAboutToBeDeleted(Layer *layer)
Chris@0 4829 {
Chris@0 4830 // std::cerr << "MainWindow::layerAboutToBeDeleted(" << layer << ")" << std::endl;
Chris@0 4831 if (layer == m_timeRulerLayer) {
Chris@0 4832 // std::cerr << "(this is the time ruler layer)" << std::endl;
Chris@0 4833 m_timeRulerLayer = 0;
Chris@0 4834 }
Chris@0 4835 }
Chris@0 4836
Chris@0 4837 void
Chris@0 4838 MainWindow::layerInAView(Layer *layer, bool inAView)
Chris@0 4839 {
Chris@0 4840 // std::cerr << "MainWindow::layerInAView(" << layer << "," << inAView << ")" << std::endl;
Chris@0 4841
Chris@0 4842 // Check whether we need to add or remove model from play source
Chris@0 4843 Model *model = layer->getModel();
Chris@0 4844 if (model) {
Chris@0 4845 if (inAView) {
Chris@0 4846 m_playSource->addModel(model);
Chris@0 4847 } else {
Chris@0 4848 bool found = false;
Chris@0 4849 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@0 4850 Pane *pane = m_paneStack->getPane(i);
Chris@0 4851 if (!pane) continue;
Chris@0 4852 for (int j = 0; j < pane->getLayerCount(); ++j) {
Chris@0 4853 Layer *pl = pane->getLayer(j);
Chris@0 4854 if (pl && pl->getModel() == model) {
Chris@0 4855 found = true;
Chris@0 4856 break;
Chris@0 4857 }
Chris@0 4858 }
Chris@0 4859 if (found) break;
Chris@0 4860 }
Chris@0 4861 if (!found) m_playSource->removeModel(model);
Chris@0 4862 }
Chris@0 4863 }
Chris@0 4864
Chris@95 4865 setupExistingLayersMenus();
Chris@0 4866 updateMenuStates();
Chris@0 4867 }
Chris@0 4868
Chris@0 4869 void
Chris@0 4870 MainWindow::modelAdded(Model *model)
Chris@0 4871 {
Chris@0 4872 // std::cerr << "MainWindow::modelAdded(" << model << ")" << std::endl;
Chris@0 4873 m_playSource->addModel(model);
Chris@66 4874 if (dynamic_cast<DenseTimeValueModel *>(model)) {
Chris@66 4875 setupPaneAndLayerMenus();
Chris@66 4876 }
Chris@0 4877 }
Chris@0 4878
Chris@0 4879 void
Chris@0 4880 MainWindow::mainModelChanged(WaveFileModel *model)
Chris@0 4881 {
Chris@0 4882 // std::cerr << "MainWindow::mainModelChanged(" << model << ")" << std::endl;
Chris@0 4883 updateDescriptionLabel();
Chris@0 4884 m_panLayer->setModel(model);
Chris@0 4885 if (model) m_viewManager->setMainModelSampleRate(model->getSampleRate());
Chris@46 4886 if (model && !m_playTarget && m_audioOutput) createPlayTarget();
Chris@0 4887 }
Chris@0 4888
Chris@0 4889 void
Chris@0 4890 MainWindow::modelAboutToBeDeleted(Model *model)
Chris@0 4891 {
Chris@0 4892 // std::cerr << "MainWindow::modelAboutToBeDeleted(" << model << ")" << std::endl;
Chris@180 4893 if (model == m_viewManager->getPlaybackModel()) {
Chris@180 4894 m_viewManager->setPlaybackModel(0);
Chris@180 4895 }
Chris@0 4896 m_playSource->removeModel(model);
Chris@91 4897 FFTDataServer::modelAboutToBeDeleted(model);
Chris@0 4898 }
Chris@0 4899
Chris@0 4900 void
Chris@0 4901 MainWindow::modelGenerationFailed(QString transformName)
Chris@0 4902 {
Chris@0 4903 QMessageBox::warning
Chris@0 4904 (this,
Chris@0 4905 tr("Failed to generate layer"),
Chris@193 4906 tr("<b>Layer generation failed</b><p>Failed to generate a derived layer.<p>The layer transform \"%1\" failed.<p>This may mean that a plugin failed to initialise, perhaps because it rejected the processing block size that was requested.")
Chris@0 4907 .arg(transformName),
Chris@165 4908 QMessageBox::Ok);
Chris@0 4909 }
Chris@0 4910
Chris@0 4911 void
Chris@0 4912 MainWindow::modelRegenerationFailed(QString layerName, QString transformName)
Chris@0 4913 {
Chris@0 4914 QMessageBox::warning
Chris@0 4915 (this,
Chris@0 4916 tr("Failed to regenerate layer"),
Chris@193 4917 tr("<b>Layer generation failed</b><p>Failed to regenerate derived layer \"%1\".<p>The layer transform \"%2\" failed to run.<p>This may mean that the layer used a plugin that is not currently available.")
Chris@0 4918 .arg(layerName).arg(transformName),
Chris@165 4919 QMessageBox::Ok);
Chris@0 4920 }
Chris@0 4921
Chris@0 4922 void
Chris@0 4923 MainWindow::rightButtonMenuRequested(Pane *pane, QPoint position)
Chris@0 4924 {
Chris@0 4925 // std::cerr << "MainWindow::rightButtonMenuRequested(" << pane << ", " << position.x() << ", " << position.y() << ")" << std::endl;
Chris@0 4926 m_paneStack->setCurrentPane(pane);
Chris@0 4927 m_rightButtonMenu->popup(position);
Chris@0 4928 }
Chris@0 4929
Chris@0 4930 void
Chris@73 4931 MainWindow::propertyStacksResized()
Chris@73 4932 {
Chris@73 4933 /*
Chris@73 4934 std::cerr << "MainWindow::propertyStacksResized" << std::endl;
Chris@73 4935 Pane *pane = m_paneStack->getCurrentPane();
Chris@73 4936 if (pane && m_overview) {
Chris@73 4937 std::cerr << "Fixed width: " << pane->width() << std::endl;
Chris@73 4938 m_overview->setFixedWidth(pane->width());
Chris@73 4939 }
Chris@73 4940 */
Chris@73 4941 }
Chris@73 4942
Chris@73 4943 void
Chris@0 4944 MainWindow::showLayerTree()
Chris@0 4945 {
Chris@177 4946 if (!m_layerTreeView.isNull()) {
Chris@177 4947 m_layerTreeView->show();
Chris@177 4948 m_layerTreeView->raise();
Chris@177 4949 return;
Chris@177 4950 }
Chris@177 4951
Chris@177 4952 //!!! should use an actual dialog class
Chris@177 4953
Chris@177 4954 m_layerTreeView = new QTreeView();
Chris@0 4955 LayerTreeModel *tree = new LayerTreeModel(m_paneStack);
Chris@177 4956 m_layerTreeView->resize(500, 300); //!!!
Chris@177 4957 m_layerTreeView->setModel(tree);
Chris@177 4958 m_layerTreeView->expandAll();
Chris@177 4959 m_layerTreeView->show();
Chris@0 4960 }
Chris@0 4961
Chris@0 4962 void
Chris@69 4963 MainWindow::pollOSC()
Chris@69 4964 {
Chris@70 4965 if (!m_oscQueue || m_oscQueue->isEmpty()) return;
Chris@69 4966 std::cerr << "MainWindow::pollOSC: have " << m_oscQueue->getMessagesAvailable() << " messages" << std::endl;
Chris@69 4967
Chris@70 4968 if (m_openingAudioFile) return;
Chris@70 4969
Chris@69 4970 OSCMessage message = m_oscQueue->readMessage();
Chris@69 4971
Chris@69 4972 if (message.getTarget() != 0) {
Chris@69 4973 return; //!!! for now -- this class is target 0, others not handled yet
Chris@69 4974 }
Chris@69 4975
Chris@69 4976 handleOSCMessage(message);
Chris@69 4977 }
Chris@69 4978
Chris@69 4979 void
Chris@69 4980 MainWindow::handleOSCMessage(const OSCMessage &message)
Chris@69 4981 {
Chris@70 4982 std::cerr << "MainWindow::handleOSCMessage: thread id = "
Chris@70 4983 << QThread::currentThreadId() << std::endl;
Chris@70 4984
Chris@69 4985 // This large function should really be abstracted out.
Chris@69 4986
Chris@69 4987 if (message.getMethod() == "open") {
Chris@69 4988
Chris@69 4989 if (message.getArgCount() == 1 &&
Chris@69 4990 message.getArg(0).canConvert(QVariant::String)) {
Chris@69 4991 QString path = message.getArg(0).toString();
Chris@82 4992 if (openSomeFile(path, ReplaceMainModel) != FileOpenSucceeded) {
Chris@69 4993 std::cerr << "MainWindow::handleOSCMessage: File open failed for path \""
Chris@69 4994 << path.toStdString() << "\"" << std::endl;
Chris@69 4995 }
Chris@69 4996 //!!! we really need to spin here and not return until the
Chris@69 4997 // file has been completely decoded...
Chris@69 4998 }
Chris@69 4999
Chris@69 5000 } else if (message.getMethod() == "openadditional") {
Chris@69 5001
Chris@69 5002 if (message.getArgCount() == 1 &&
Chris@69 5003 message.getArg(0).canConvert(QVariant::String)) {
Chris@69 5004 QString path = message.getArg(0).toString();
Chris@82 5005 if (openSomeFile(path, CreateAdditionalModel) != FileOpenSucceeded) {
Chris@69 5006 std::cerr << "MainWindow::handleOSCMessage: File open failed for path \""
Chris@69 5007 << path.toStdString() << "\"" << std::endl;
Chris@69 5008 }
Chris@69 5009 }
Chris@69 5010
Chris@69 5011 } else if (message.getMethod() == "recent" ||
Chris@69 5012 message.getMethod() == "last") {
Chris@69 5013
Chris@69 5014 int n = 0;
Chris@69 5015 if (message.getMethod() == "recent" &&
Chris@69 5016 message.getArgCount() == 1 &&
Chris@69 5017 message.getArg(0).canConvert(QVariant::Int)) {
Chris@69 5018 n = message.getArg(0).toInt() - 1;
Chris@69 5019 }
Chris@69 5020 std::vector<QString> recent = m_recentFiles.getRecent();
Chris@137 5021 if (n >= 0 && n < int(recent.size())) {
Chris@82 5022 if (openSomeFile(recent[n], ReplaceMainModel) != FileOpenSucceeded) {
Chris@69 5023 std::cerr << "MainWindow::handleOSCMessage: File open failed for path \""
Chris@69 5024 << recent[n].toStdString() << "\"" << std::endl;
Chris@69 5025 }
Chris@69 5026 }
Chris@69 5027
Chris@69 5028 } else if (message.getMethod() == "save") {
Chris@69 5029
Chris@69 5030 QString path;
Chris@69 5031 if (message.getArgCount() == 1 &&
Chris@69 5032 message.getArg(0).canConvert(QVariant::String)) {
Chris@69 5033 path = message.getArg(0).toString();
Chris@69 5034 if (QFileInfo(path).exists()) {
Chris@69 5035 std::cerr << "MainWindow::handleOSCMessage: Refusing to overwrite existing file in save" << std::endl;
Chris@69 5036 } else {
Chris@69 5037 saveSessionFile(path);
Chris@69 5038 }
Chris@69 5039 }
Chris@69 5040
Chris@69 5041 } else if (message.getMethod() == "export") {
Chris@69 5042
Chris@69 5043 QString path;
Chris@69 5044 if (getMainModel()) {
Chris@69 5045 if (message.getArgCount() == 1 &&
Chris@69 5046 message.getArg(0).canConvert(QVariant::String)) {
Chris@69 5047 path = message.getArg(0).toString();
Chris@69 5048 if (QFileInfo(path).exists()) {
Chris@69 5049 std::cerr << "MainWindow::handleOSCMessage: Refusing to overwrite existing file in export" << std::endl;
Chris@69 5050 } else {
Chris@69 5051 WavFileWriter writer(path,
Chris@69 5052 getMainModel()->getSampleRate(),
Chris@69 5053 getMainModel()->getChannelCount());
Chris@69 5054 MultiSelection ms = m_viewManager->getSelection();
Chris@69 5055 if (!ms.getSelections().empty()) {
Chris@69 5056 writer.writeModel(getMainModel(), &ms);
Chris@69 5057 } else {
Chris@69 5058 writer.writeModel(getMainModel());
Chris@69 5059 }
Chris@69 5060 }
Chris@69 5061 }
Chris@69 5062 }
Chris@69 5063
Chris@69 5064 } else if (message.getMethod() == "jump" ||
Chris@69 5065 message.getMethod() == "play") {
Chris@69 5066
Chris@69 5067 if (getMainModel()) {
Chris@69 5068
Chris@69 5069 unsigned long frame = m_viewManager->getPlaybackFrame();
Chris@69 5070 bool selection = false;
Chris@69 5071 bool play = (message.getMethod() == "play");
Chris@69 5072
Chris@69 5073 if (message.getArgCount() == 1) {
Chris@69 5074
Chris@69 5075 if (message.getArg(0).canConvert(QVariant::String) &&
Chris@69 5076 message.getArg(0).toString() == "selection") {
Chris@69 5077
Chris@69 5078 selection = true;
Chris@69 5079
Chris@69 5080 } else if (message.getArg(0).canConvert(QVariant::String) &&
Chris@69 5081 message.getArg(0).toString() == "end") {
Chris@69 5082
Chris@69 5083 frame = getMainModel()->getEndFrame();
Chris@69 5084
Chris@69 5085 } else if (message.getArg(0).canConvert(QVariant::Double)) {
Chris@69 5086
Chris@69 5087 double time = message.getArg(0).toDouble();
Chris@69 5088 if (time < 0.0) time = 0.0;
Chris@69 5089
Chris@69 5090 frame = lrint(time * getMainModel()->getSampleRate());
Chris@69 5091 }
Chris@69 5092 }
Chris@69 5093
Chris@69 5094 if (frame > getMainModel()->getEndFrame()) {
Chris@69 5095 frame = getMainModel()->getEndFrame();
Chris@69 5096 }
Chris@69 5097
Chris@69 5098 if (play) {
Chris@69 5099 m_viewManager->setPlaySelectionMode(selection);
Chris@69 5100 }
Chris@69 5101
Chris@69 5102 if (selection) {
Chris@69 5103 MultiSelection::SelectionList sl = m_viewManager->getSelections();
Chris@69 5104 if (!sl.empty()) {
Chris@69 5105 frame = sl.begin()->getStartFrame();
Chris@69 5106 }
Chris@69 5107 }
Chris@69 5108
Chris@69 5109 m_viewManager->setPlaybackFrame(frame);
Chris@69 5110
Chris@69 5111 if (play && !m_playSource->isPlaying()) {
Chris@69 5112 m_playSource->play(frame);
Chris@69 5113 }
Chris@69 5114 }
Chris@69 5115
Chris@69 5116 } else if (message.getMethod() == "stop") {
Chris@69 5117
Chris@69 5118 if (m_playSource->isPlaying()) m_playSource->stop();
Chris@69 5119
Chris@69 5120 } else if (message.getMethod() == "loop") {
Chris@69 5121
Chris@69 5122 if (message.getArgCount() == 1 &&
Chris@69 5123 message.getArg(0).canConvert(QVariant::String)) {
Chris@69 5124
Chris@69 5125 QString str = message.getArg(0).toString();
Chris@69 5126 if (str == "on") {
Chris@69 5127 m_viewManager->setPlayLoopMode(true);
Chris@69 5128 } else if (str == "off") {
Chris@69 5129 m_viewManager->setPlayLoopMode(false);
Chris@69 5130 }
Chris@69 5131 }
Chris@69 5132
Chris@180 5133 } else if (message.getMethod() == "solo") {
Chris@180 5134
Chris@180 5135 if (message.getArgCount() == 1 &&
Chris@180 5136 message.getArg(0).canConvert(QVariant::String)) {
Chris@180 5137
Chris@180 5138 QString str = message.getArg(0).toString();
Chris@180 5139 if (str == "on") {
Chris@180 5140 m_viewManager->setPlaySoloMode(true);
Chris@180 5141 } else if (str == "off") {
Chris@180 5142 m_viewManager->setPlaySoloMode(false);
Chris@180 5143 }
Chris@180 5144 }
Chris@180 5145
Chris@69 5146 } else if (message.getMethod() == "select" ||
Chris@69 5147 message.getMethod() == "addselect") {
Chris@69 5148
Chris@69 5149 if (getMainModel()) {
Chris@69 5150
Chris@73 5151 int f0 = getMainModel()->getStartFrame();
Chris@73 5152 int f1 = getMainModel()->getEndFrame();
Chris@69 5153
Chris@69 5154 bool done = false;
Chris@69 5155
Chris@69 5156 if (message.getArgCount() == 2 &&
Chris@69 5157 message.getArg(0).canConvert(QVariant::Double) &&
Chris@69 5158 message.getArg(1).canConvert(QVariant::Double)) {
Chris@69 5159
Chris@69 5160 double t0 = message.getArg(0).toDouble();
Chris@69 5161 double t1 = message.getArg(1).toDouble();
Chris@69 5162 if (t1 < t0) { double temp = t0; t0 = t1; t1 = temp; }
Chris@69 5163 if (t0 < 0.0) t0 = 0.0;
Chris@69 5164 if (t1 < 0.0) t1 = 0.0;
Chris@69 5165
Chris@69 5166 f0 = lrint(t0 * getMainModel()->getSampleRate());
Chris@69 5167 f1 = lrint(t1 * getMainModel()->getSampleRate());
Chris@73 5168
Chris@73 5169 Pane *pane = m_paneStack->getCurrentPane();
Chris@73 5170 Layer *layer = 0;
Chris@73 5171 if (pane) layer = pane->getSelectedLayer();
Chris@73 5172 if (layer) {
Chris@73 5173 size_t resolution;
Chris@73 5174 layer->snapToFeatureFrame(pane, f0, resolution,
Chris@73 5175 Layer::SnapLeft);
Chris@73 5176 layer->snapToFeatureFrame(pane, f1, resolution,
Chris@73 5177 Layer::SnapRight);
Chris@73 5178 }
Chris@69 5179
Chris@69 5180 } else if (message.getArgCount() == 1 &&
Chris@69 5181 message.getArg(0).canConvert(QVariant::String)) {
Chris@69 5182
Chris@69 5183 QString str = message.getArg(0).toString();
Chris@69 5184 if (str == "none") {
Chris@69 5185 m_viewManager->clearSelections();
Chris@69 5186 done = true;
Chris@69 5187 }
Chris@69 5188 }
Chris@69 5189
Chris@69 5190 if (!done) {
Chris@69 5191 if (message.getMethod() == "select") {
Chris@69 5192 m_viewManager->setSelection(Selection(f0, f1));
Chris@69 5193 } else {
Chris@69 5194 m_viewManager->addSelection(Selection(f0, f1));
Chris@69 5195 }
Chris@69 5196 }
Chris@69 5197 }
Chris@69 5198
Chris@69 5199 } else if (message.getMethod() == "add") {
Chris@69 5200
Chris@69 5201 if (getMainModel()) {
Chris@69 5202
Chris@69 5203 if (message.getArgCount() >= 1 &&
Chris@69 5204 message.getArg(0).canConvert(QVariant::String)) {
Chris@69 5205
Chris@69 5206 int channel = -1;
Chris@69 5207 if (message.getArgCount() == 2 &&
Chris@69 5208 message.getArg(0).canConvert(QVariant::Int)) {
Chris@69 5209 channel = message.getArg(0).toInt();
Chris@69 5210 if (channel < -1 ||
Chris@137 5211 channel > int(getMainModel()->getChannelCount())) {
Chris@69 5212 std::cerr << "WARNING: MainWindow::handleOSCMessage: channel "
Chris@69 5213 << channel << " out of range" << std::endl;
Chris@69 5214 channel = -1;
Chris@69 5215 }
Chris@69 5216 }
Chris@69 5217
Chris@69 5218 QString str = message.getArg(0).toString();
Chris@69 5219
Chris@69 5220 LayerFactory::LayerType type =
Chris@69 5221 LayerFactory::getInstance()->getLayerTypeForName(str);
Chris@69 5222
Chris@69 5223 if (type == LayerFactory::UnknownLayer) {
Chris@69 5224 std::cerr << "WARNING: MainWindow::handleOSCMessage: unknown layer "
Chris@69 5225 << "type " << str.toStdString() << std::endl;
Chris@69 5226 } else {
Chris@69 5227
Chris@69 5228 PaneConfiguration configuration(type,
Chris@69 5229 getMainModel(),
Chris@69 5230 channel);
Chris@69 5231
Chris@69 5232 addPane(configuration,
Chris@69 5233 tr("Add %1 Pane")
Chris@69 5234 .arg(LayerFactory::getInstance()->
Chris@69 5235 getLayerPresentationName(type)));
Chris@69 5236 }
Chris@69 5237 }
Chris@69 5238 }
Chris@69 5239
Chris@69 5240 } else if (message.getMethod() == "undo") {
Chris@69 5241
Chris@69 5242 CommandHistory::getInstance()->undo();
Chris@69 5243
Chris@69 5244 } else if (message.getMethod() == "redo") {
Chris@69 5245
Chris@69 5246 CommandHistory::getInstance()->redo();
Chris@69 5247
Chris@69 5248 } else if (message.getMethod() == "set") {
Chris@69 5249
Chris@70 5250 if (message.getArgCount() == 2 &&
Chris@69 5251 message.getArg(0).canConvert(QVariant::String) &&
Chris@69 5252 message.getArg(1).canConvert(QVariant::Double)) {
Chris@69 5253
Chris@69 5254 QString property = message.getArg(0).toString();
Chris@69 5255 float value = (float)message.getArg(1).toDouble();
Chris@69 5256
Chris@69 5257 if (property == "gain") {
Chris@69 5258 if (value < 0.0) value = 0.0;
Chris@69 5259 m_fader->setValue(value);
Chris@69 5260 if (m_playTarget) m_playTarget->setOutputGain(value);
Chris@69 5261 } else if (property == "speedup") {
Chris@69 5262 m_playSpeed->setMappedValue(value);
Chris@69 5263 } else if (property == "overlays") {
Chris@69 5264 if (value < 0.5) {
Chris@69 5265 m_viewManager->setOverlayMode(ViewManager::NoOverlays);
Chris@69 5266 } else if (value < 1.5) {
Chris@90 5267 m_viewManager->setOverlayMode(ViewManager::MinimalOverlays);
Chris@90 5268 } else if (value < 2.5) {
Chris@90 5269 m_viewManager->setOverlayMode(ViewManager::StandardOverlays);
Chris@69 5270 } else {
Chris@69 5271 m_viewManager->setOverlayMode(ViewManager::AllOverlays);
Chris@69 5272 }
Chris@70 5273 } else if (property == "zoomwheels") {
Chris@70 5274 m_viewManager->setZoomWheelsEnabled(value > 0.5);
Chris@72 5275 } else if (property == "propertyboxes") {
Chris@72 5276 bool toggle = ((value < 0.5) !=
Chris@72 5277 (m_paneStack->getLayoutStyle() == PaneStack::NoPropertyStacks));
Chris@72 5278 if (toggle) togglePropertyBoxes();
Chris@70 5279 }
Chris@70 5280
Chris@70 5281 } else {
Chris@70 5282 PropertyContainer *container = 0;
Chris@70 5283 Pane *pane = m_paneStack->getCurrentPane();
Chris@70 5284 if (pane &&
Chris@70 5285 message.getArgCount() == 3 &&
Chris@70 5286 message.getArg(0).canConvert(QVariant::String) &&
Chris@70 5287 message.getArg(1).canConvert(QVariant::String) &&
Chris@70 5288 message.getArg(2).canConvert(QVariant::String)) {
Chris@70 5289 if (message.getArg(0).toString() == "pane") {
Chris@70 5290 container = pane->getPropertyContainer(0);
Chris@70 5291 } else if (message.getArg(0).toString() == "layer") {
Chris@70 5292 container = pane->getSelectedLayer();
Chris@70 5293 }
Chris@70 5294 }
Chris@70 5295 if (container) {
Chris@70 5296 QString nameString = message.getArg(1).toString();
Chris@70 5297 QString valueString = message.getArg(2).toString();
Chris@70 5298 container->setPropertyWithCommand(nameString, valueString);
Chris@69 5299 }
Chris@69 5300 }
Chris@69 5301
Chris@69 5302 } else if (message.getMethod() == "setcurrent") {
Chris@69 5303
Chris@69 5304 int paneIndex = -1, layerIndex = -1;
Chris@69 5305 bool wantLayer = false;
Chris@69 5306
Chris@69 5307 if (message.getArgCount() >= 1 &&
Chris@69 5308 message.getArg(0).canConvert(QVariant::Int)) {
Chris@69 5309
Chris@69 5310 paneIndex = message.getArg(0).toInt() - 1;
Chris@69 5311
Chris@69 5312 if (message.getArgCount() >= 2 &&
Chris@69 5313 message.getArg(1).canConvert(QVariant::Int)) {
Chris@69 5314 wantLayer = true;
Chris@69 5315 layerIndex = message.getArg(1).toInt() - 1;
Chris@69 5316 }
Chris@69 5317 }
Chris@69 5318
Chris@69 5319 if (paneIndex >= 0 && paneIndex < m_paneStack->getPaneCount()) {
Chris@69 5320 Pane *pane = m_paneStack->getPane(paneIndex);
Chris@70 5321 m_paneStack->setCurrentPane(pane);
Chris@69 5322 if (layerIndex >= 0 && layerIndex < pane->getLayerCount()) {
Chris@69 5323 Layer *layer = pane->getLayer(layerIndex);
Chris@69 5324 m_paneStack->setCurrentLayer(pane, layer);
Chris@69 5325 } else if (wantLayer && layerIndex == -1) {
Chris@69 5326 m_paneStack->setCurrentLayer(pane, 0);
Chris@69 5327 }
Chris@69 5328 }
Chris@69 5329
Chris@69 5330 } else if (message.getMethod() == "delete") {
Chris@69 5331
Chris@69 5332 if (message.getArgCount() == 1 &&
Chris@69 5333 message.getArg(0).canConvert(QVariant::String)) {
Chris@69 5334
Chris@69 5335 QString target = message.getArg(0).toString();
Chris@69 5336
Chris@69 5337 if (target == "pane") {
Chris@69 5338
Chris@69 5339 deleteCurrentPane();
Chris@69 5340
Chris@69 5341 } else if (target == "layer") {
Chris@69 5342
Chris@69 5343 deleteCurrentLayer();
Chris@69 5344
Chris@69 5345 } else {
Chris@69 5346
Chris@69 5347 std::cerr << "WARNING: MainWindow::handleOSCMessage: Unknown delete target " << target.toStdString() << std::endl;
Chris@69 5348 }
Chris@69 5349 }
Chris@69 5350
Chris@69 5351 } else if (message.getMethod() == "zoom") {
Chris@69 5352
Chris@69 5353 if (message.getArgCount() == 1) {
Chris@69 5354 if (message.getArg(0).canConvert(QVariant::String) &&
Chris@69 5355 message.getArg(0).toString() == "in") {
Chris@69 5356 zoomIn();
Chris@69 5357 } else if (message.getArg(0).canConvert(QVariant::String) &&
Chris@69 5358 message.getArg(0).toString() == "out") {
Chris@69 5359 zoomOut();
Chris@69 5360 } else if (message.getArg(0).canConvert(QVariant::String) &&
Chris@69 5361 message.getArg(0).toString() == "default") {
Chris@69 5362 zoomDefault();
Chris@69 5363 } else if (message.getArg(0).canConvert(QVariant::Double)) {
Chris@69 5364 double level = message.getArg(0).toDouble();
Chris@69 5365 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@69 5366 if (level < 1.0) level = 1.0;
Chris@69 5367 if (currentPane) currentPane->setZoomLevel(lrint(level));
Chris@69 5368 }
Chris@69 5369 }
Chris@69 5370
Chris@73 5371 } else if (message.getMethod() == "zoomvertical") {
Chris@73 5372
Chris@73 5373 Pane *pane = m_paneStack->getCurrentPane();
Chris@73 5374 Layer *layer = 0;
Chris@73 5375 if (pane && pane->getLayerCount() > 0) {
Chris@73 5376 layer = pane->getLayer(pane->getLayerCount() - 1);
Chris@73 5377 }
Chris@73 5378 int defaultStep = 0;
Chris@73 5379 int steps = 0;
Chris@73 5380 if (layer) {
Chris@73 5381 steps = layer->getVerticalZoomSteps(defaultStep);
Chris@73 5382 if (message.getArgCount() == 1 && steps > 0) {
Chris@73 5383 if (message.getArg(0).canConvert(QVariant::String) &&
Chris@73 5384 message.getArg(0).toString() == "in") {
Chris@73 5385 int step = layer->getCurrentVerticalZoomStep() + 1;
Chris@73 5386 if (step < steps) layer->setVerticalZoomStep(step);
Chris@73 5387 } else if (message.getArg(0).canConvert(QVariant::String) &&
Chris@73 5388 message.getArg(0).toString() == "out") {
Chris@73 5389 int step = layer->getCurrentVerticalZoomStep() - 1;
Chris@73 5390 if (step >= 0) layer->setVerticalZoomStep(step);
Chris@73 5391 } else if (message.getArg(0).canConvert(QVariant::String) &&
Chris@73 5392 message.getArg(0).toString() == "default") {
Chris@73 5393 layer->setVerticalZoomStep(defaultStep);
Chris@73 5394 }
Chris@73 5395 } else if (message.getArgCount() == 2) {
Chris@73 5396 if (message.getArg(0).canConvert(QVariant::Double) &&
Chris@73 5397 message.getArg(1).canConvert(QVariant::Double)) {
Chris@73 5398 double min = message.getArg(0).toDouble();
Chris@73 5399 double max = message.getArg(1).toDouble();
Chris@73 5400 layer->setDisplayExtents(min, max);
Chris@73 5401 }
Chris@73 5402 }
Chris@73 5403 }
Chris@73 5404
Chris@70 5405 } else if (message.getMethod() == "quit") {
Chris@70 5406
Chris@70 5407 m_abandoning = true;
Chris@70 5408 close();
Chris@70 5409
Chris@70 5410 } else if (message.getMethod() == "resize") {
Chris@70 5411
Chris@70 5412 if (message.getArgCount() == 2) {
Chris@70 5413
Chris@70 5414 int width = 0, height = 0;
Chris@70 5415
Chris@70 5416 if (message.getArg(1).canConvert(QVariant::Int)) {
Chris@70 5417
Chris@70 5418 height = message.getArg(1).toInt();
Chris@70 5419
Chris@70 5420 if (message.getArg(0).canConvert(QVariant::String) &&
Chris@70 5421 message.getArg(0).toString() == "pane") {
Chris@70 5422
Chris@70 5423 Pane *pane = m_paneStack->getCurrentPane();
Chris@70 5424 if (pane) pane->resize(pane->width(), height);
Chris@70 5425
Chris@70 5426 } else if (message.getArg(0).canConvert(QVariant::Int)) {
Chris@70 5427
Chris@70 5428 width = message.getArg(0).toInt();
Chris@70 5429 resize(width, height);
Chris@70 5430 }
Chris@70 5431 }
Chris@70 5432 }
Chris@70 5433
Chris@70 5434 } else if (message.getMethod() == "transform") {
Chris@70 5435
Chris@70 5436 Pane *pane = m_paneStack->getCurrentPane();
Chris@70 5437
Chris@70 5438 if (getMainModel() &&
Chris@70 5439 pane &&
Chris@70 5440 message.getArgCount() == 1 &&
Chris@70 5441 message.getArg(0).canConvert(QVariant::String)) {
Chris@70 5442
Chris@107 5443 TransformId transform = message.getArg(0).toString();
Chris@70 5444
Chris@70 5445 Layer *newLayer = m_document->createDerivedLayer
Chris@70 5446 (transform,
Chris@70 5447 getMainModel(),
Chris@73 5448 TransformFactory::getInstance()->getDefaultContextForTransform
Chris@73 5449 (transform, getMainModel()),
Chris@70 5450 "");
Chris@70 5451
Chris@70 5452 if (newLayer) {
Chris@70 5453 m_document->addLayerToView(pane, newLayer);
Chris@70 5454 m_recentTransforms.add(transform);
Chris@70 5455 m_paneStack->setCurrentLayer(pane, newLayer);
Chris@70 5456 }
Chris@70 5457 }
Chris@70 5458
Chris@69 5459 } else {
Chris@69 5460 std::cerr << "WARNING: MainWindow::handleOSCMessage: Unknown or unsupported "
Chris@69 5461 << "method \"" << message.getMethod().toStdString()
Chris@69 5462 << "\"" << std::endl;
Chris@69 5463 }
Chris@69 5464
Chris@69 5465 }
Chris@69 5466
Chris@69 5467 void
Chris@0 5468 MainWindow::preferences()
Chris@0 5469 {
Chris@0 5470 if (!m_preferencesDialog.isNull()) {
Chris@0 5471 m_preferencesDialog->show();
Chris@0 5472 m_preferencesDialog->raise();
Chris@0 5473 return;
Chris@0 5474 }
Chris@0 5475
Chris@0 5476 m_preferencesDialog = new PreferencesDialog(this);
Chris@0 5477
Chris@0 5478 // DeleteOnClose is safe here, because m_preferencesDialog is a
Chris@0 5479 // QPointer that will be zeroed when the dialog is deleted. We
Chris@0 5480 // use it in preference to leaving the dialog lying around because
Chris@0 5481 // if you Cancel the dialog, it resets the preferences state
Chris@0 5482 // without resetting its own widgets, so its state will be
Chris@0 5483 // incorrect when next shown unless we construct it afresh
Chris@0 5484 m_preferencesDialog->setAttribute(Qt::WA_DeleteOnClose);
Chris@0 5485
Chris@0 5486 m_preferencesDialog->show();
Chris@0 5487 }
Chris@0 5488
Chris@0 5489 void
Chris@90 5490 MainWindow::mouseEnteredWidget()
Chris@90 5491 {
Chris@90 5492 QWidget *w = dynamic_cast<QWidget *>(sender());
Chris@90 5493 if (!w) return;
Chris@90 5494
Chris@90 5495 if (w == m_fader) {
Chris@116 5496 contextHelpChanged(tr("Adjust the master playback level"));
Chris@90 5497 } else if (w == m_playSpeed) {
Chris@116 5498 contextHelpChanged(tr("Adjust the master playback speed"));
Chris@90 5499 } else if (w == m_playSharpen && w->isEnabled()) {
Chris@116 5500 contextHelpChanged(tr("Toggle transient sharpening for playback time scaling"));
Chris@90 5501 } else if (w == m_playMono && w->isEnabled()) {
Chris@116 5502 contextHelpChanged(tr("Toggle mono mode for playback time scaling"));
Chris@90 5503 }
Chris@90 5504 }
Chris@90 5505
Chris@90 5506 void
Chris@90 5507 MainWindow::mouseLeftWidget()
Chris@90 5508 {
Chris@116 5509 contextHelpChanged("");
Chris@116 5510 }
Chris@116 5511
Chris@116 5512 void
Chris@117 5513 MainWindow::inProgressSelectionChanged()
Chris@117 5514 {
Chris@117 5515 Pane *currentPane = 0;
Chris@117 5516 if (m_paneStack) currentPane = m_paneStack->getCurrentPane();
Chris@117 5517 if (currentPane) updateVisibleRangeDisplay(currentPane);
Chris@117 5518 }
Chris@117 5519
Chris@117 5520 void
Chris@116 5521 MainWindow::contextHelpChanged(const QString &s)
Chris@116 5522 {
Chris@116 5523 if (s == "" && m_myStatusMessage != "") {
Chris@116 5524 statusBar()->showMessage(m_myStatusMessage);
Chris@116 5525 return;
Chris@116 5526 }
Chris@116 5527 statusBar()->showMessage(s);
Chris@90 5528 }
Chris@90 5529
Chris@90 5530 void
Chris@0 5531 MainWindow::website()
Chris@0 5532 {
Chris@0 5533 openHelpUrl(tr("http://www.sonicvisualiser.org/"));
Chris@0 5534 }
Chris@0 5535
Chris@0 5536 void
Chris@0 5537 MainWindow::help()
Chris@0 5538 {
Chris@126 5539 openHelpUrl(tr("http://www.sonicvisualiser.org/doc/reference/1.0/en/"));
Chris@0 5540 }
Chris@0 5541
Chris@0 5542 void
Chris@0 5543 MainWindow::openHelpUrl(QString url)
Chris@0 5544 {
Chris@0 5545 // This method mostly lifted from Qt Assistant source code
Chris@0 5546
Chris@0 5547 QProcess *process = new QProcess(this);
Chris@0 5548 connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater()));
Chris@0 5549
Chris@0 5550 QStringList args;
Chris@0 5551
Chris@0 5552 #ifdef Q_OS_MAC
Chris@0 5553 args.append(url);
Chris@0 5554 process->start("open", args);
Chris@0 5555 #else
Chris@0 5556 #ifdef Q_OS_WIN32
Chris@0 5557
Chris@0 5558 QString pf(getenv("ProgramFiles"));
Chris@0 5559 QString command = pf + QString("\\Internet Explorer\\IEXPLORE.EXE");
Chris@0 5560
Chris@0 5561 args.append(url);
Chris@0 5562 process->start(command, args);
Chris@0 5563
Chris@0 5564 #else
Chris@0 5565 #ifdef Q_WS_X11
Chris@0 5566 if (!qgetenv("KDE_FULL_SESSION").isEmpty()) {
Chris@0 5567 args.append("exec");
Chris@0 5568 args.append(url);
Chris@0 5569 process->start("kfmclient", args);
Chris@0 5570 } else if (!qgetenv("BROWSER").isEmpty()) {
Chris@0 5571 args.append(url);
Chris@0 5572 process->start(qgetenv("BROWSER"), args);
Chris@0 5573 } else {
Chris@0 5574 args.append(url);
Chris@0 5575 process->start("firefox", args);
Chris@0 5576 }
Chris@0 5577 #endif
Chris@0 5578 #endif
Chris@0 5579 #endif
Chris@0 5580 }
Chris@0 5581
Chris@0 5582 void
Chris@0 5583 MainWindow::about()
Chris@0 5584 {
Chris@0 5585 bool debug = false;
Chris@0 5586 QString version = "(unknown version)";
Chris@0 5587
Chris@0 5588 #ifdef BUILD_DEBUG
Chris@0 5589 debug = true;
Chris@0 5590 #endif
Chris@0 5591 #ifdef SV_VERSION
Chris@0 5592 #ifdef SVNREV
Chris@0 5593 version = tr("Release %1 : Revision %2").arg(SV_VERSION).arg(SVNREV);
Chris@0 5594 #else
Chris@0 5595 version = tr("Release %1").arg(SV_VERSION);
Chris@0 5596 #endif
Chris@0 5597 #else
Chris@0 5598 #ifdef SVNREV
Chris@0 5599 version = tr("Unreleased : Revision %1").arg(SVNREV);
Chris@0 5600 #endif
Chris@0 5601 #endif
Chris@0 5602
Chris@0 5603 QString aboutText;
Chris@0 5604
Chris@0 5605 aboutText += tr("<h3>About Sonic Visualiser</h3>");
Chris@90 5606 aboutText += tr("<p>Sonic Visualiser is a program for viewing and exploring audio data for<br>semantic music analysis and annotation.</p>");
Chris@111 5607 aboutText += tr("<p>%1 : %2 configuration</p>")
Chris@0 5608 .arg(version)
Chris@0 5609 .arg(debug ? tr("Debug") : tr("Release"));
Chris@0 5610
Chris@132 5611 #ifndef BUILD_STATIC
Chris@132 5612 aboutText += tr("<br>Using Qt v%1 &copy; Trolltech AS").arg(QT_VERSION_STR);
Chris@132 5613 #else
Chris@132 5614 #ifdef QT_SHARED
Chris@132 5615 aboutText += tr("<br>Using Qt v%1 &copy; Trolltech AS").arg(QT_VERSION_STR);
Chris@132 5616 #endif
Chris@132 5617 #endif
Chris@132 5618
Chris@0 5619 #ifdef BUILD_STATIC
Chris@0 5620 aboutText += tr("<p>Statically linked");
Chris@0 5621 #ifndef QT_SHARED
Chris@0 5622 aboutText += tr("<br>With Qt (v%1) &copy; Trolltech AS").arg(QT_VERSION_STR);
Chris@0 5623 #endif
Chris@0 5624 #ifdef HAVE_JACK
Chris@93 5625 #ifdef JACK_VERSION
Chris@0 5626 aboutText += tr("<br>With JACK audio output (v%1) &copy; Paul Davis and Jack O'Quin").arg(JACK_VERSION);
Chris@93 5627 #else
Chris@93 5628 aboutText += tr("<br>With JACK audio output &copy; Paul Davis and Jack O'Quin");
Chris@93 5629 #endif
Chris@0 5630 #endif
Chris@0 5631 #ifdef HAVE_PORTAUDIO
Chris@0 5632 aboutText += tr("<br>With PortAudio audio output &copy; Ross Bencina and Phil Burk");
Chris@0 5633 #endif
Chris@0 5634 #ifdef HAVE_OGGZ
Chris@93 5635 #ifdef OGGZ_VERSION
Chris@0 5636 aboutText += tr("<br>With Ogg file decoder (oggz v%1, fishsound v%2) &copy; CSIRO Australia").arg(OGGZ_VERSION).arg(FISHSOUND_VERSION);
Chris@93 5637 #else
Chris@93 5638 aboutText += tr("<br>With Ogg file decoder &copy; CSIRO Australia");
Chris@93 5639 #endif
Chris@0 5640 #endif
Chris@0 5641 #ifdef HAVE_MAD
Chris@93 5642 #ifdef MAD_VERSION
Chris@0 5643 aboutText += tr("<br>With MAD mp3 decoder (v%1) &copy; Underbit Technologies Inc").arg(MAD_VERSION);
Chris@93 5644 #else
Chris@93 5645 aboutText += tr("<br>With MAD mp3 decoder &copy; Underbit Technologies Inc");
Chris@93 5646 #endif
Chris@0 5647 #endif
Chris@0 5648 #ifdef HAVE_SAMPLERATE
Chris@93 5649 #ifdef SAMPLERATE_VERSION
Chris@0 5650 aboutText += tr("<br>With libsamplerate (v%1) &copy; Erik de Castro Lopo").arg(SAMPLERATE_VERSION);
Chris@93 5651 #else
Chris@93 5652 aboutText += tr("<br>With libsamplerate &copy; Erik de Castro Lopo");
Chris@93 5653 #endif
Chris@0 5654 #endif
Chris@0 5655 #ifdef HAVE_SNDFILE
Chris@93 5656 #ifdef SNDFILE_VERSION
Chris@0 5657 aboutText += tr("<br>With libsndfile (v%1) &copy; Erik de Castro Lopo").arg(SNDFILE_VERSION);
Chris@93 5658 #else
Chris@93 5659 aboutText += tr("<br>With libsndfile &copy; Erik de Castro Lopo");
Chris@93 5660 #endif
Chris@0 5661 #endif
Chris@127 5662 #ifdef HAVE_FFTW3F
Chris@93 5663 #ifdef FFTW3_VERSION
Chris@0 5664 aboutText += tr("<br>With FFTW3 (v%1) &copy; Matteo Frigo and MIT").arg(FFTW3_VERSION);
Chris@93 5665 #else
Chris@93 5666 aboutText += tr("<br>With FFTW3 &copy; Matteo Frigo and MIT");
Chris@93 5667 #endif
Chris@0 5668 #endif
Chris@0 5669 #ifdef HAVE_VAMP
Chris@114 5670 aboutText += tr("<br>With Vamp plugin support (API v%1, host SDK v%2) &copy; Chris Cannam").arg(VAMP_API_VERSION).arg(VAMP_SDK_VERSION);
Chris@0 5671 #endif
Chris@0 5672 aboutText += tr("<br>With LADSPA plugin support (API v%1) &copy; Richard Furse, Paul Davis, Stefan Westerfeld").arg(LADSPA_VERSION);
Chris@0 5673 aboutText += tr("<br>With DSSI plugin support (API v%1) &copy; Chris Cannam, Steve Harris, Sean Bolton").arg(DSSI_VERSION);
Chris@69 5674 #ifdef HAVE_LIBLO
Chris@93 5675 #ifdef LIBLO_VERSION
Chris@69 5676 aboutText += tr("<br>With liblo Lite OSC library (v%1) &copy; Steve Harris").arg(LIBLO_VERSION);
Chris@93 5677 #else
Chris@93 5678 aboutText += tr("<br>With liblo Lite OSC library &copy; Steve Harris").arg(LIBLO_VERSION);
Chris@93 5679 #endif
Chris@70 5680 if (m_oscQueue && m_oscQueue->isOK()) {
Chris@69 5681 aboutText += tr("<p>The OSC URL for this instance is: \"%1\"").arg(m_oscQueue->getOSCURL());
Chris@69 5682 }
Chris@69 5683 #endif
Chris@0 5684 aboutText += "</p>";
Chris@0 5685 #endif
Chris@0 5686
Chris@0 5687 aboutText +=
Chris@90 5688 "<p>Sonic Visualiser Copyright &copy; 2005 - 2007 Chris Cannam and<br>"
Chris@90 5689 "Queen Mary, University of London.</p>"
Chris@0 5690 "<p>This program is free software; you can redistribute it and/or<br>"
Chris@0 5691 "modify it under the terms of the GNU General Public License as<br>"
Chris@0 5692 "published by the Free Software Foundation; either version 2 of the<br>"
Chris@0 5693 "License, or (at your option) any later version.<br>See the file "
Chris@0 5694 "COPYING included with this distribution for more information.</p>";
Chris@0 5695
Chris@0 5696 QMessageBox::about(this, tr("About Sonic Visualiser"), aboutText);
Chris@0 5697 }
Chris@0 5698
Chris@162 5699 void
Chris@162 5700 MainWindow::keyReference()
Chris@162 5701 {
Chris@162 5702 m_keyReference->show();
Chris@162 5703 }
Chris@162 5704