annotate main/MainWindow.cpp @ 197:c08c312b2399

* Make RemoteFile far more pervasive, and use it for local files as well so that we can handle both transparently. Make it shallow copy with reference counting, so it can be used by value without having to worry about the cache file lifetime. Use RemoteFile for MainWindow file-open functions, etc
author Chris Cannam
date Thu, 18 Oct 2007 15:31:20 +0000
parents 61bf55e80080
children 24ac2e4010c5
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@194 2128 View::ModelSet soloModels = p->getModels();
Chris@194 2129
Chris@194 2130 for (View::ModelSet::iterator mi = soloModels.begin();
Chris@194 2131 mi != soloModels.end(); ++mi) {
Chris@194 2132 if (dynamic_cast<RangeSummarisableTimeValueModel *>(*mi)) {
Chris@194 2133 m_viewManager->setPlaybackModel(*mi);
Chris@180 2134 }
Chris@180 2135 }
Chris@180 2136
Chris@180 2137 RangeSummarisableTimeValueModel *a =
Chris@180 2138 dynamic_cast<RangeSummarisableTimeValueModel *>(prevPlaybackModel);
Chris@180 2139 RangeSummarisableTimeValueModel *b =
Chris@180 2140 dynamic_cast<RangeSummarisableTimeValueModel *>(m_viewManager->
Chris@180 2141 getPlaybackModel());
Chris@180 2142
Chris@180 2143 m_playSource->setSoloModelSet(soloModels);
Chris@180 2144
Chris@180 2145 if (a && b && (a != b)) {
Chris@180 2146 int frame = m_playSource->getCurrentPlayingFrame();
Chris@180 2147 //!!! I don't really believe that these functions are the right way around
Chris@180 2148 int rframe = a->alignFromReference(frame);
Chris@180 2149 int bframe = b->alignToReference(rframe);
Chris@180 2150 if (m_playSource->isPlaying()) m_playSource->play(bframe);
Chris@180 2151 }
Chris@0 2152 }
Chris@0 2153
Chris@0 2154 void
Chris@116 2155 MainWindow::currentLayerChanged(Pane *p, Layer *)
Chris@0 2156 {
Chris@0 2157 updateMenuStates();
Chris@116 2158 updateVisibleRangeDisplay(p);
Chris@0 2159 }
Chris@0 2160
Chris@0 2161 void
Chris@0 2162 MainWindow::toolNavigateSelected()
Chris@0 2163 {
Chris@0 2164 m_viewManager->setToolMode(ViewManager::NavigateMode);
Chris@0 2165 }
Chris@0 2166
Chris@0 2167 void
Chris@0 2168 MainWindow::toolSelectSelected()
Chris@0 2169 {
Chris@0 2170 m_viewManager->setToolMode(ViewManager::SelectMode);
Chris@0 2171 }
Chris@0 2172
Chris@0 2173 void
Chris@0 2174 MainWindow::toolEditSelected()
Chris@0 2175 {
Chris@0 2176 m_viewManager->setToolMode(ViewManager::EditMode);
Chris@0 2177 }
Chris@0 2178
Chris@0 2179 void
Chris@0 2180 MainWindow::toolDrawSelected()
Chris@0 2181 {
Chris@0 2182 m_viewManager->setToolMode(ViewManager::DrawMode);
Chris@0 2183 }
Chris@0 2184
Chris@151 2185 void
Chris@151 2186 MainWindow::toolMeasureSelected()
Chris@151 2187 {
Chris@151 2188 m_viewManager->setToolMode(ViewManager::MeasureMode);
Chris@151 2189 }
Chris@151 2190
Chris@0 2191 //void
Chris@0 2192 //MainWindow::toolTextSelected()
Chris@0 2193 //{
Chris@0 2194 // m_viewManager->setToolMode(ViewManager::TextMode);
Chris@0 2195 //}
Chris@0 2196
Chris@0 2197 void
Chris@0 2198 MainWindow::selectAll()
Chris@0 2199 {
Chris@0 2200 if (!getMainModel()) return;
Chris@0 2201 m_viewManager->setSelection(Selection(getMainModel()->getStartFrame(),
Chris@0 2202 getMainModel()->getEndFrame()));
Chris@0 2203 }
Chris@0 2204
Chris@0 2205 void
Chris@0 2206 MainWindow::selectToStart()
Chris@0 2207 {
Chris@0 2208 if (!getMainModel()) return;
Chris@0 2209 m_viewManager->setSelection(Selection(getMainModel()->getStartFrame(),
Chris@0 2210 m_viewManager->getGlobalCentreFrame()));
Chris@0 2211 }
Chris@0 2212
Chris@0 2213 void
Chris@0 2214 MainWindow::selectToEnd()
Chris@0 2215 {
Chris@0 2216 if (!getMainModel()) return;
Chris@0 2217 m_viewManager->setSelection(Selection(m_viewManager->getGlobalCentreFrame(),
Chris@0 2218 getMainModel()->getEndFrame()));
Chris@0 2219 }
Chris@0 2220
Chris@0 2221 void
Chris@0 2222 MainWindow::selectVisible()
Chris@0 2223 {
Chris@0 2224 Model *model = getMainModel();
Chris@0 2225 if (!model) return;
Chris@0 2226
Chris@0 2227 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@0 2228 if (!currentPane) return;
Chris@0 2229
Chris@0 2230 size_t startFrame, endFrame;
Chris@0 2231
Chris@0 2232 if (currentPane->getStartFrame() < 0) startFrame = 0;
Chris@0 2233 else startFrame = currentPane->getStartFrame();
Chris@0 2234
Chris@0 2235 if (currentPane->getEndFrame() > model->getEndFrame()) endFrame = model->getEndFrame();
Chris@0 2236 else endFrame = currentPane->getEndFrame();
Chris@0 2237
Chris@0 2238 m_viewManager->setSelection(Selection(startFrame, endFrame));
Chris@0 2239 }
Chris@0 2240
Chris@0 2241 void
Chris@0 2242 MainWindow::clearSelection()
Chris@0 2243 {
Chris@0 2244 m_viewManager->clearSelections();
Chris@0 2245 }
Chris@0 2246
Chris@0 2247 void
Chris@0 2248 MainWindow::cut()
Chris@0 2249 {
Chris@0 2250 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@0 2251 if (!currentPane) return;
Chris@0 2252
Chris@0 2253 Layer *layer = currentPane->getSelectedLayer();
Chris@0 2254 if (!layer) return;
Chris@0 2255
Chris@0 2256 Clipboard &clipboard = m_viewManager->getClipboard();
Chris@0 2257 clipboard.clear();
Chris@0 2258
Chris@0 2259 MultiSelection::SelectionList selections = m_viewManager->getSelections();
Chris@0 2260
Chris@0 2261 CommandHistory::getInstance()->startCompoundOperation(tr("Cut"), true);
Chris@0 2262
Chris@0 2263 for (MultiSelection::SelectionList::iterator i = selections.begin();
Chris@0 2264 i != selections.end(); ++i) {
Chris@0 2265 layer->copy(*i, clipboard);
Chris@0 2266 layer->deleteSelection(*i);
Chris@0 2267 }
Chris@0 2268
Chris@0 2269 CommandHistory::getInstance()->endCompoundOperation();
Chris@0 2270 }
Chris@0 2271
Chris@0 2272 void
Chris@0 2273 MainWindow::copy()
Chris@0 2274 {
Chris@0 2275 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@0 2276 if (!currentPane) return;
Chris@0 2277
Chris@0 2278 Layer *layer = currentPane->getSelectedLayer();
Chris@0 2279 if (!layer) return;
Chris@0 2280
Chris@0 2281 Clipboard &clipboard = m_viewManager->getClipboard();
Chris@0 2282 clipboard.clear();
Chris@0 2283
Chris@0 2284 MultiSelection::SelectionList selections = m_viewManager->getSelections();
Chris@0 2285
Chris@0 2286 for (MultiSelection::SelectionList::iterator i = selections.begin();
Chris@0 2287 i != selections.end(); ++i) {
Chris@0 2288 layer->copy(*i, clipboard);
Chris@0 2289 }
Chris@0 2290 }
Chris@0 2291
Chris@0 2292 void
Chris@0 2293 MainWindow::paste()
Chris@0 2294 {
Chris@0 2295 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@0 2296 if (!currentPane) return;
Chris@0 2297
Chris@0 2298 //!!! if we have no current layer, we should create one of the most
Chris@0 2299 // appropriate type
Chris@0 2300
Chris@0 2301 Layer *layer = currentPane->getSelectedLayer();
Chris@0 2302 if (!layer) return;
Chris@0 2303
Chris@0 2304 Clipboard &clipboard = m_viewManager->getClipboard();
Chris@0 2305 Clipboard::PointList contents = clipboard.getPoints();
Chris@0 2306 /*
Chris@0 2307 long minFrame = 0;
Chris@0 2308 bool have = false;
Chris@0 2309 for (int i = 0; i < contents.size(); ++i) {
Chris@0 2310 if (!contents[i].haveFrame()) continue;
Chris@0 2311 if (!have || contents[i].getFrame() < minFrame) {
Chris@0 2312 minFrame = contents[i].getFrame();
Chris@0 2313 have = true;
Chris@0 2314 }
Chris@0 2315 }
Chris@0 2316
Chris@0 2317 long frameOffset = long(m_viewManager->getGlobalCentreFrame()) - minFrame;
Chris@0 2318
Chris@0 2319 layer->paste(clipboard, frameOffset);
Chris@0 2320 */
Chris@0 2321 layer->paste(clipboard, 0, true);
Chris@0 2322 }
Chris@0 2323
Chris@0 2324 void
Chris@0 2325 MainWindow::deleteSelected()
Chris@0 2326 {
Chris@0 2327 if (m_paneStack->getCurrentPane() &&
Chris@0 2328 m_paneStack->getCurrentPane()->getSelectedLayer()) {
Chris@164 2329
Chris@164 2330 Layer *layer = m_paneStack->getCurrentPane()->getSelectedLayer();
Chris@164 2331
Chris@164 2332 if (m_viewManager &&
Chris@164 2333 (m_viewManager->getToolMode() == ViewManager::MeasureMode)) {
Chris@164 2334
Chris@164 2335 layer->deleteCurrentMeasureRect();
Chris@164 2336
Chris@164 2337 } else {
Chris@164 2338
Chris@164 2339 MultiSelection::SelectionList selections =
Chris@164 2340 m_viewManager->getSelections();
Chris@164 2341
Chris@164 2342 for (MultiSelection::SelectionList::iterator i = selections.begin();
Chris@164 2343 i != selections.end(); ++i) {
Chris@164 2344 layer->deleteSelection(*i);
Chris@164 2345 }
Chris@0 2346 }
Chris@0 2347 }
Chris@0 2348 }
Chris@0 2349
Chris@0 2350 void
Chris@0 2351 MainWindow::insertInstant()
Chris@0 2352 {
Chris@0 2353 int frame = m_viewManager->getPlaybackFrame();
Chris@81 2354 insertInstantAt(frame);
Chris@81 2355 }
Chris@81 2356
Chris@81 2357 void
Chris@81 2358 MainWindow::insertInstantsAtBoundaries()
Chris@81 2359 {
Chris@81 2360 MultiSelection::SelectionList selections = m_viewManager->getSelections();
Chris@81 2361 for (MultiSelection::SelectionList::iterator i = selections.begin();
Chris@81 2362 i != selections.end(); ++i) {
Chris@81 2363 size_t start = i->getStartFrame();
Chris@81 2364 size_t end = i->getEndFrame();
Chris@81 2365 if (start != end) {
Chris@81 2366 insertInstantAt(i->getStartFrame());
Chris@81 2367 insertInstantAt(i->getEndFrame());
Chris@81 2368 }
Chris@81 2369 }
Chris@81 2370 }
Chris@81 2371
Chris@81 2372 void
Chris@81 2373 MainWindow::insertInstantAt(size_t frame)
Chris@81 2374 {
Chris@0 2375 Pane *pane = m_paneStack->getCurrentPane();
Chris@0 2376 if (!pane) {
Chris@0 2377 return;
Chris@0 2378 }
Chris@0 2379
Chris@0 2380 Layer *layer = dynamic_cast<TimeInstantLayer *>
Chris@0 2381 (pane->getSelectedLayer());
Chris@0 2382
Chris@0 2383 if (!layer) {
Chris@0 2384 for (int i = pane->getLayerCount(); i > 0; --i) {
Chris@0 2385 layer = dynamic_cast<TimeInstantLayer *>(pane->getLayer(i - 1));
Chris@0 2386 if (layer) break;
Chris@0 2387 }
Chris@0 2388
Chris@0 2389 if (!layer) {
Chris@0 2390 CommandHistory::getInstance()->startCompoundOperation
Chris@0 2391 (tr("Add Point"), true);
Chris@0 2392 layer = m_document->createEmptyLayer(LayerFactory::TimeInstants);
Chris@0 2393 if (layer) {
Chris@0 2394 m_document->addLayerToView(pane, layer);
Chris@0 2395 m_paneStack->setCurrentLayer(pane, layer);
Chris@0 2396 }
Chris@0 2397 CommandHistory::getInstance()->endCompoundOperation();
Chris@0 2398 }
Chris@0 2399 }
Chris@0 2400
Chris@0 2401 if (layer) {
Chris@0 2402
Chris@0 2403 Model *model = layer->getModel();
Chris@0 2404 SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *>
Chris@0 2405 (model);
Chris@0 2406
Chris@0 2407 if (sodm) {
Chris@189 2408 SparseOneDimensionalModel::Point point(frame, "");
Chris@189 2409
Chris@189 2410 SparseOneDimensionalModel::Point prevPoint(0);
Chris@189 2411 bool havePrevPoint = false;
Chris@189 2412
Chris@189 2413 SparseOneDimensionalModel::EditCommand *command =
Chris@189 2414 new SparseOneDimensionalModel::EditCommand(sodm, tr("Add Point"));
Chris@189 2415
Chris@189 2416 if (m_labeller->actingOnPrevPoint()) {
Chris@189 2417
Chris@189 2418 SparseOneDimensionalModel::PointList prevPoints =
Chris@189 2419 sodm->getPreviousPoints(frame);
Chris@189 2420
Chris@189 2421 if (!prevPoints.empty()) {
Chris@189 2422 prevPoint = *prevPoints.begin();
Chris@189 2423 havePrevPoint = true;
Chris@189 2424 }
Chris@189 2425 }
Chris@189 2426
Chris@189 2427 if (m_labeller) {
Chris@189 2428
Chris@189 2429 m_labeller->setSampleRate(sodm->getSampleRate());
Chris@189 2430
Chris@189 2431 if (havePrevPoint) {
Chris@189 2432 command->deletePoint(prevPoint);
Chris@189 2433 }
Chris@189 2434
Chris@189 2435 m_labeller->label<SparseOneDimensionalModel::Point>
Chris@189 2436 (point, havePrevPoint ? &prevPoint : 0);
Chris@189 2437
Chris@189 2438 if (havePrevPoint) {
Chris@189 2439 command->addPoint(prevPoint);
Chris@189 2440 }
Chris@189 2441 }
Chris@189 2442
Chris@189 2443 command->addPoint(point);
Chris@189 2444
Chris@189 2445 command->setName(tr("Add Point at %1 s")
Chris@189 2446 .arg(RealTime::frame2RealTime
Chris@189 2447 (frame,
Chris@189 2448 sodm->getSampleRate())
Chris@189 2449 .toText(false).c_str()));
Chris@189 2450
Chris@189 2451 command->finish();
Chris@0 2452 }
Chris@0 2453 }
Chris@0 2454 }
Chris@0 2455
Chris@0 2456 void
Chris@189 2457 MainWindow::setInstantsNumbering()
Chris@189 2458 {
Chris@189 2459 QAction *a = dynamic_cast<QAction *>(sender());
Chris@189 2460 if (!a) return;
Chris@189 2461
Chris@189 2462 int type = m_numberingActions[a];
Chris@189 2463
Chris@189 2464 if (m_labeller) m_labeller->setType(Labeller::ValueType(type));
Chris@189 2465
Chris@189 2466 QSettings settings;
Chris@189 2467 settings.beginGroup("MainWindow");
Chris@189 2468 settings.setValue("labellertype", type);
Chris@189 2469 settings.endGroup();
Chris@189 2470 }
Chris@189 2471
Chris@189 2472 void
Chris@189 2473 MainWindow::setInstantsCounterCycle()
Chris@189 2474 {
Chris@189 2475 QAction *a = dynamic_cast<QAction *>(sender());
Chris@189 2476 if (!a) return;
Chris@189 2477
Chris@189 2478 int cycle = a->text().toInt();
Chris@189 2479 if (cycle == 0) return;
Chris@189 2480
Chris@189 2481 if (m_labeller) m_labeller->setCounterCycleSize(cycle);
Chris@189 2482
Chris@189 2483 QSettings settings;
Chris@189 2484 settings.beginGroup("MainWindow");
Chris@189 2485 settings.setValue("labellercycle", cycle);
Chris@189 2486 settings.endGroup();
Chris@189 2487 }
Chris@189 2488
Chris@189 2489 void
Chris@192 2490 MainWindow::resetInstantsCounters()
Chris@192 2491 {
Chris@192 2492 LabelCounterInputDialog dialog(m_labeller, this);
Chris@192 2493 dialog.exec();
Chris@192 2494 }
Chris@192 2495
Chris@192 2496 void
Chris@189 2497 MainWindow::renumberInstants()
Chris@189 2498 {
Chris@189 2499 Pane *pane = m_paneStack->getCurrentPane();
Chris@189 2500 if (!pane) return;
Chris@189 2501
Chris@189 2502 Layer *layer = dynamic_cast<TimeInstantLayer *>(pane->getSelectedLayer());
Chris@189 2503 if (!layer) return;
Chris@189 2504
Chris@189 2505 MultiSelection ms(m_viewManager->getSelection());
Chris@189 2506
Chris@189 2507 Model *model = layer->getModel();
Chris@189 2508 SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *>
Chris@189 2509 (model);
Chris@189 2510 if (!sodm) return;
Chris@189 2511
Chris@189 2512 if (!m_labeller) return;
Chris@189 2513
Chris@189 2514 Labeller labeller(*m_labeller);
Chris@189 2515 labeller.setSampleRate(sodm->getSampleRate());
Chris@189 2516
Chris@189 2517 // This uses a command
Chris@189 2518
Chris@189 2519 labeller.labelAll<SparseOneDimensionalModel::Point>(*sodm, &ms);
Chris@189 2520 }
Chris@189 2521
Chris@189 2522 void
Chris@0 2523 MainWindow::importAudio()
Chris@0 2524 {
Chris@88 2525 QString path = getOpenFileName(FileFinder::AudioFile);
Chris@0 2526
Chris@0 2527 if (path != "") {
Chris@197 2528 if (openAudio(path, ReplaceMainModel) == FileOpenFailed) {
Chris@0 2529 QMessageBox::critical(this, tr("Failed to open file"),
Chris@193 2530 tr("<b>File open failed</b><p>Audio file \"%1\" could not be opened").arg(path));
Chris@0 2531 }
Chris@0 2532 }
Chris@0 2533 }
Chris@0 2534
Chris@0 2535 void
Chris@0 2536 MainWindow::importMoreAudio()
Chris@0 2537 {
Chris@88 2538 QString path = getOpenFileName(FileFinder::AudioFile);
Chris@0 2539
Chris@0 2540 if (path != "") {
Chris@197 2541 if (openAudio(path, CreateAdditionalModel) == FileOpenFailed) {
Chris@0 2542 QMessageBox::critical(this, tr("Failed to open file"),
Chris@193 2543 tr("<b>File open failed</b><p>Audio file \"%1\" could not be opened").arg(path));
Chris@0 2544 }
Chris@0 2545 }
Chris@0 2546 }
Chris@0 2547
Chris@0 2548 void
Chris@0 2549 MainWindow::exportAudio()
Chris@0 2550 {
Chris@0 2551 if (!getMainModel()) return;
Chris@0 2552
Chris@88 2553 QString path = getSaveFileName(FileFinder::AudioFile);
Chris@0 2554
Chris@0 2555 if (path == "") return;
Chris@0 2556
Chris@0 2557 bool ok = false;
Chris@0 2558 QString error;
Chris@0 2559
Chris@0 2560 MultiSelection ms = m_viewManager->getSelection();
Chris@0 2561 MultiSelection::SelectionList selections = m_viewManager->getSelections();
Chris@0 2562
Chris@0 2563 bool multiple = false;
Chris@0 2564
Chris@38 2565 MultiSelection *selectionToWrite = 0;
Chris@38 2566
Chris@38 2567 if (selections.size() == 1) {
Chris@0 2568
Chris@0 2569 QStringList items;
Chris@0 2570 items << tr("Export the selected region only")
Chris@0 2571 << tr("Export the whole audio file");
Chris@0 2572
Chris@0 2573 bool ok = false;
Chris@0 2574 QString item = ListInputDialog::getItem
Chris@0 2575 (this, tr("Select region to export"),
Chris@0 2576 tr("Which region from the original audio file do you want to export?"),
Chris@0 2577 items, 0, &ok);
Chris@0 2578
Chris@0 2579 if (!ok || item.isEmpty()) return;
Chris@0 2580
Chris@38 2581 if (item == items[0]) selectionToWrite = &ms;
Chris@38 2582
Chris@38 2583 } else if (selections.size() > 1) {
Chris@0 2584
Chris@0 2585 QStringList items;
Chris@0 2586 items << tr("Export the selected regions into a single audio file")
Chris@0 2587 << tr("Export the selected regions into separate files")
Chris@0 2588 << tr("Export the whole audio file");
Chris@0 2589
Chris@0 2590 QString item = ListInputDialog::getItem
Chris@0 2591 (this, tr("Select region to export"),
Chris@0 2592 tr("Multiple regions of the original audio file are selected.\nWhat do you want to export?"),
Chris@0 2593 items, 0, &ok);
Chris@0 2594
Chris@0 2595 if (!ok || item.isEmpty()) return;
Chris@0 2596
Chris@0 2597 if (item == items[0]) {
Chris@0 2598
Chris@38 2599 selectionToWrite = &ms;
Chris@38 2600
Chris@38 2601 } else if (item == items[1]) {
Chris@0 2602
Chris@0 2603 multiple = true;
Chris@0 2604
Chris@0 2605 int n = 1;
Chris@0 2606 QString base = path;
Chris@0 2607 base.replace(".wav", "");
Chris@0 2608
Chris@0 2609 for (MultiSelection::SelectionList::iterator i = selections.begin();
Chris@0 2610 i != selections.end(); ++i) {
Chris@0 2611
Chris@0 2612 MultiSelection subms;
Chris@0 2613 subms.setSelection(*i);
Chris@0 2614
Chris@0 2615 QString subpath = QString("%1.%2.wav").arg(base).arg(n);
Chris@0 2616 ++n;
Chris@0 2617
Chris@0 2618 if (QFileInfo(subpath).exists()) {
Chris@0 2619 error = tr("Fragment file %1 already exists, aborting").arg(subpath);
Chris@0 2620 break;
Chris@0 2621 }
Chris@0 2622
Chris@38 2623 WavFileWriter subwriter(subpath,
Chris@38 2624 getMainModel()->getSampleRate(),
Chris@38 2625 getMainModel()->getChannelCount());
Chris@38 2626 subwriter.writeModel(getMainModel(), &subms);
Chris@0 2627 ok = subwriter.isOK();
Chris@0 2628
Chris@0 2629 if (!ok) {
Chris@0 2630 error = subwriter.getError();
Chris@0 2631 break;
Chris@0 2632 }
Chris@0 2633 }
Chris@0 2634 }
Chris@0 2635 }
Chris@0 2636
Chris@38 2637 if (!multiple) {
Chris@38 2638 WavFileWriter writer(path,
Chris@38 2639 getMainModel()->getSampleRate(),
Chris@38 2640 getMainModel()->getChannelCount());
Chris@38 2641 writer.writeModel(getMainModel(), selectionToWrite);
Chris@38 2642 ok = writer.isOK();
Chris@38 2643 error = writer.getError();
Chris@0 2644 }
Chris@0 2645
Chris@0 2646 if (ok) {
Chris@0 2647 if (!multiple) {
Chris@34 2648 m_recentFiles.addFile(path);
Chris@0 2649 }
Chris@0 2650 } else {
Chris@0 2651 QMessageBox::critical(this, tr("Failed to write file"), error);
Chris@0 2652 }
Chris@0 2653 }
Chris@0 2654
Chris@0 2655 void
Chris@0 2656 MainWindow::importLayer()
Chris@0 2657 {
Chris@0 2658 Pane *pane = m_paneStack->getCurrentPane();
Chris@0 2659
Chris@0 2660 if (!pane) {
Chris@0 2661 // shouldn't happen, as the menu action should have been disabled
Chris@0 2662 std::cerr << "WARNING: MainWindow::importLayer: no current pane" << std::endl;
Chris@0 2663 return;
Chris@0 2664 }
Chris@0 2665
Chris@0 2666 if (!getMainModel()) {
Chris@0 2667 // shouldn't happen, as the menu action should have been disabled
Chris@0 2668 std::cerr << "WARNING: MainWindow::importLayer: No main model -- hence no default sample rate available" << std::endl;
Chris@0 2669 return;
Chris@0 2670 }
Chris@0 2671
Chris@88 2672 QString path = getOpenFileName(FileFinder::LayerFile);
Chris@0 2673
Chris@0 2674 if (path != "") {
Chris@0 2675
Chris@197 2676 FileOpenStatus status = openLayer(path);
Chris@193 2677
Chris@193 2678 if (status == FileOpenFailed) {
Chris@0 2679 QMessageBox::critical(this, tr("Failed to open file"),
Chris@193 2680 tr("<b>File open failed</b><p>Layer file %1 could not be opened.").arg(path));
Chris@0 2681 return;
Chris@193 2682 } else if (status == FileOpenWrongMode) {
Chris@193 2683 QMessageBox::critical(this, tr("Failed to open file"),
Chris@193 2684 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
Chris@0 2685 }
Chris@0 2686 }
Chris@0 2687 }
Chris@0 2688
Chris@0 2689 void
Chris@0 2690 MainWindow::exportLayer()
Chris@0 2691 {
Chris@0 2692 Pane *pane = m_paneStack->getCurrentPane();
Chris@0 2693 if (!pane) return;
Chris@0 2694
Chris@0 2695 Layer *layer = pane->getSelectedLayer();
Chris@0 2696 if (!layer) return;
Chris@0 2697
Chris@0 2698 Model *model = layer->getModel();
Chris@0 2699 if (!model) return;
Chris@0 2700
Chris@185 2701 FileFinder::FileType type = FileFinder::LayerFileNoMidi;
Chris@185 2702
Chris@185 2703 if (dynamic_cast<NoteModel *>(model)) type = FileFinder::LayerFile;
Chris@185 2704
Chris@185 2705 QString path = getSaveFileName(type);
Chris@0 2706
Chris@0 2707 if (path == "") return;
Chris@0 2708
Chris@0 2709 if (QFileInfo(path).suffix() == "") path += ".svl";
Chris@0 2710
Chris@185 2711 QString suffix = QFileInfo(path).suffix().toLower();
Chris@185 2712
Chris@0 2713 QString error;
Chris@0 2714
Chris@185 2715 if (suffix == "xml" || suffix == "svl") {
Chris@0 2716
Chris@0 2717 QFile file(path);
Chris@0 2718 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
Chris@0 2719 error = tr("Failed to open file %1 for writing").arg(path);
Chris@0 2720 } else {
Chris@0 2721 QTextStream out(&file);
Chris@0 2722 out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
Chris@0 2723 << "<!DOCTYPE sonic-visualiser>\n"
Chris@0 2724 << "<sv>\n"
Chris@0 2725 << " <data>\n";
Chris@0 2726
Chris@0 2727 model->toXml(out, " ");
Chris@0 2728
Chris@0 2729 out << " </data>\n"
Chris@0 2730 << " <display>\n";
Chris@0 2731
Chris@0 2732 layer->toXml(out, " ");
Chris@0 2733
Chris@0 2734 out << " </display>\n"
Chris@0 2735 << "</sv>\n";
Chris@0 2736 }
Chris@0 2737
Chris@185 2738 } else if (suffix == "mid" || suffix == "midi") {
Chris@185 2739
Chris@185 2740 NoteModel *nm = dynamic_cast<NoteModel *>(model);
Chris@185 2741
Chris@185 2742 if (!nm) {
Chris@185 2743 error = tr("Can't export non-note layers to MIDI");
Chris@185 2744 } else {
Chris@185 2745 MIDIFileWriter writer(path, nm);
Chris@185 2746 writer.write();
Chris@185 2747 if (!writer.isOK()) {
Chris@185 2748 error = writer.getError();
Chris@185 2749 }
Chris@185 2750 }
Chris@185 2751
Chris@0 2752 } else {
Chris@0 2753
Chris@0 2754 CSVFileWriter writer(path, model,
Chris@185 2755 ((suffix == "csv") ? "," : "\t"));
Chris@0 2756 writer.write();
Chris@0 2757
Chris@0 2758 if (!writer.isOK()) {
Chris@0 2759 error = writer.getError();
Chris@0 2760 }
Chris@0 2761 }
Chris@0 2762
Chris@0 2763 if (error != "") {
Chris@0 2764 QMessageBox::critical(this, tr("Failed to write file"), error);
Chris@0 2765 } else {
Chris@34 2766 m_recentFiles.addFile(path);
Chris@0 2767 }
Chris@0 2768 }
Chris@0 2769
Chris@121 2770 void
Chris@121 2771 MainWindow::exportImage()
Chris@121 2772 {
Chris@121 2773 Pane *pane = m_paneStack->getCurrentPane();
Chris@121 2774 if (!pane) return;
Chris@121 2775
Chris@121 2776 QString path = getSaveFileName(FileFinder::ImageFile);
Chris@121 2777
Chris@121 2778 if (path == "") return;
Chris@121 2779
Chris@121 2780 if (QFileInfo(path).suffix() == "") path += ".png";
Chris@121 2781
Chris@123 2782 bool haveSelection = m_viewManager && !m_viewManager->getSelections().empty();
Chris@123 2783
Chris@123 2784 QSize total, visible, selected;
Chris@123 2785 total = pane->getImageSize();
Chris@123 2786 visible = pane->getImageSize(pane->getFirstVisibleFrame(),
Chris@123 2787 pane->getLastVisibleFrame());
Chris@123 2788
Chris@123 2789 size_t sf0 = 0, sf1 = 0;
Chris@123 2790
Chris@123 2791 if (haveSelection) {
Chris@123 2792 MultiSelection::SelectionList selections = m_viewManager->getSelections();
Chris@123 2793 sf0 = selections.begin()->getStartFrame();
Chris@123 2794 MultiSelection::SelectionList::iterator e = selections.end();
Chris@123 2795 --e;
Chris@123 2796 sf1 = e->getEndFrame();
Chris@123 2797 selected = pane->getImageSize(sf0, sf1);
Chris@123 2798 }
Chris@123 2799
Chris@123 2800 QStringList items;
Chris@125 2801 items << tr("Export the whole pane (%1x%2 pixels)")
Chris@123 2802 .arg(total.width()).arg(total.height());
Chris@123 2803 items << tr("Export the visible area only (%1x%2 pixels)")
Chris@123 2804 .arg(visible.width()).arg(visible.height());
Chris@123 2805 if (haveSelection) {
Chris@123 2806 items << tr("Export the selection extent (%1x%2 pixels)")
Chris@123 2807 .arg(selected.width()).arg(selected.height());
Chris@124 2808 } else {
Chris@124 2809 items << tr("Export the selection extent");
Chris@123 2810 }
Chris@123 2811
Chris@123 2812 QSettings settings;
Chris@123 2813 settings.beginGroup("MainWindow");
Chris@123 2814 int deflt = settings.value("lastimageexportregion", 0).toInt();
Chris@123 2815 if (deflt == 2 && !haveSelection) deflt = 1;
Chris@124 2816 if (deflt == 0 && total.width() > 32767) deflt = 1;
Chris@124 2817
Chris@124 2818 ListInputDialog *lid = new ListInputDialog
Chris@123 2819 (this, tr("Select region to export"),
Chris@123 2820 tr("Which region of the current pane do you want to export as an image?"),
Chris@124 2821 items, deflt);
Chris@124 2822
Chris@124 2823 if (!haveSelection) {
Chris@124 2824 lid->setItemAvailability(2, false);
Chris@124 2825 }
Chris@124 2826 if (total.width() > 32767) { // appears to be the limit of a QImage
Chris@124 2827 lid->setItemAvailability(0, false);
Chris@124 2828 lid->setFootnote(tr("Note: the whole pane is too wide to be exported as a single image."));
Chris@124 2829 }
Chris@124 2830
Chris@124 2831 bool ok = lid->exec();
Chris@124 2832 QString item = lid->getCurrentString();
Chris@124 2833 delete lid;
Chris@123 2834
Chris@123 2835 if (!ok || item.isEmpty()) return;
Chris@123 2836
Chris@123 2837 settings.setValue("lastimageexportregion", deflt);
Chris@123 2838
Chris@123 2839 QImage *image = 0;
Chris@123 2840
Chris@123 2841 if (item == items[0]) {
Chris@123 2842 image = pane->toNewImage();
Chris@123 2843 } else if (item == items[1]) {
Chris@123 2844 image = pane->toNewImage(pane->getFirstVisibleFrame(),
Chris@123 2845 pane->getLastVisibleFrame());
Chris@123 2846 } else if (haveSelection) {
Chris@123 2847 image = pane->toNewImage(sf0, sf1);
Chris@123 2848 }
Chris@123 2849
Chris@121 2850 if (!image) return;
Chris@121 2851
Chris@121 2852 if (!image->save(path, "PNG")) {
Chris@121 2853 QMessageBox::critical(this, tr("Failed to save image file"),
Chris@121 2854 tr("Failed to save image file %1").arg(path));
Chris@121 2855 }
Chris@121 2856
Chris@121 2857 delete image;
Chris@121 2858 }
Chris@121 2859
Chris@82 2860 MainWindow::FileOpenStatus
Chris@197 2861 MainWindow::open(QString fileOrUrl, AudioFileOpenMode mode)
Chris@0 2862 {
Chris@197 2863 return open(RemoteFile(fileOrUrl), mode);
Chris@86 2864 }
Chris@86 2865
Chris@86 2866 MainWindow::FileOpenStatus
Chris@197 2867 MainWindow::open(RemoteFile source, AudioFileOpenMode mode)
Chris@86 2868 {
Chris@197 2869 FileOpenStatus status;
Chris@197 2870
Chris@197 2871 if (!source.isAvailable()) return FileOpenFailed;
Chris@197 2872 source.waitForData();
Chris@197 2873
Chris@197 2874 bool canImportLayer = (getMainModel() != 0 &&
Chris@197 2875 m_paneStack != 0 &&
Chris@197 2876 m_paneStack->getCurrentPane() != 0);
Chris@197 2877
Chris@197 2878 if ((status = openAudio(source, mode)) != FileOpenFailed) {
Chris@197 2879 return status;
Chris@197 2880 } else if ((status = openSession(source)) != FileOpenFailed) {
Chris@197 2881 return status;
Chris@197 2882 } else if ((status = openPlaylist(source, mode)) != FileOpenFailed) {
Chris@197 2883 return status;
Chris@197 2884 } else if (!canImportLayer) {
Chris@197 2885 return FileOpenWrongMode;
Chris@197 2886 } else if ((status = openImage(source)) != FileOpenFailed) {
Chris@197 2887 return status;
Chris@197 2888 } else if ((status = openLayer(source)) != FileOpenFailed) {
Chris@197 2889 return status;
Chris@197 2890 } else {
Chris@82 2891 return FileOpenFailed;
Chris@0 2892 }
Chris@197 2893 }
Chris@197 2894
Chris@197 2895 MainWindow::FileOpenStatus
Chris@197 2896 MainWindow::openAudio(RemoteFile source, AudioFileOpenMode mode)
Chris@197 2897 {
Chris@197 2898 std::cerr << "MainWindow::openAudio(" << source.getLocation().toStdString() << ")" << std::endl;
Chris@197 2899
Chris@197 2900 if (!source.isAvailable()) return FileOpenFailed;
Chris@197 2901 source.waitForData();
Chris@0 2902
Chris@70 2903 m_openingAudioFile = true;
Chris@70 2904
Chris@180 2905 size_t rate = 0;
Chris@180 2906
Chris@180 2907 if (Preferences::getInstance()->getResampleOnLoad()) {
Chris@180 2908 rate = m_playSource->getSourceSampleRate();
Chris@180 2909 }
Chris@180 2910
Chris@197 2911 WaveFileModel *newModel = new WaveFileModel(source, rate);
Chris@0 2912
Chris@0 2913 if (!newModel->isOK()) {
Chris@0 2914 delete newModel;
Chris@70 2915 m_openingAudioFile = false;
Chris@82 2916 return FileOpenFailed;
Chris@0 2917 }
Chris@0 2918
Chris@194 2919 std::cerr << "mode = " << mode << std::endl;
Chris@194 2920
Chris@194 2921 if (mode == AskUser) {
Chris@194 2922 if (getMainModel()) {
Chris@194 2923
Chris@194 2924 static bool prevSetAsMain = true;
Chris@194 2925 bool setAsMain = true;
Chris@194 2926
Chris@0 2927 QStringList items;
Chris@0 2928 items << tr("Replace the existing main waveform")
Chris@0 2929 << tr("Load this file into a new waveform pane");
Chris@0 2930
Chris@0 2931 bool ok = false;
Chris@0 2932 QString item = ListInputDialog::getItem
Chris@0 2933 (this, tr("Select target for import"),
Chris@0 2934 tr("You already have an audio waveform loaded.\nWhat would you like to do with the new audio file?"),
Chris@0 2935 items, prevSetAsMain ? 0 : 1, &ok);
Chris@0 2936
Chris@0 2937 if (!ok || item.isEmpty()) {
Chris@0 2938 delete newModel;
Chris@70 2939 m_openingAudioFile = false;
Chris@82 2940 return FileOpenCancelled;
Chris@0 2941 }
Chris@0 2942
Chris@0 2943 setAsMain = (item == items[0]);
Chris@0 2944 prevSetAsMain = setAsMain;
Chris@194 2945
Chris@194 2946 if (setAsMain) mode = ReplaceMainModel;
Chris@194 2947 else mode = CreateAdditionalModel;
Chris@194 2948
Chris@194 2949 } else {
Chris@194 2950 mode = ReplaceMainModel;
Chris@0 2951 }
Chris@0 2952 }
Chris@0 2953
Chris@194 2954 if (mode == ReplaceCurrentPane) {
Chris@194 2955
Chris@194 2956 Pane *pane = m_paneStack->getCurrentPane();
Chris@194 2957 if (pane) {
Chris@194 2958 if (getMainModel()) {
Chris@194 2959 View::ModelSet models(pane->getModels());
Chris@194 2960 if (models.find(getMainModel()) != models.end()) {
Chris@194 2961 mode = ReplaceMainModel;
Chris@194 2962 }
Chris@194 2963 } else {
Chris@194 2964 mode = ReplaceMainModel;
Chris@194 2965 }
Chris@194 2966 } else {
Chris@194 2967 mode = CreateAdditionalModel;
Chris@194 2968 }
Chris@194 2969 }
Chris@194 2970
Chris@194 2971 if (mode == CreateAdditionalModel && !getMainModel()) {
Chris@194 2972 mode = ReplaceMainModel;
Chris@194 2973 }
Chris@194 2974
Chris@194 2975 if (mode == ReplaceMainModel) {
Chris@0 2976
Chris@0 2977 Model *prevMain = getMainModel();
Chris@118 2978 if (prevMain) {
Chris@118 2979 m_playSource->removeModel(prevMain);
Chris@118 2980 PlayParameterRepository::getInstance()->removeModel(prevMain);
Chris@118 2981 }
Chris@118 2982 PlayParameterRepository::getInstance()->addModel(newModel);
Chris@0 2983
Chris@0 2984 m_document->setMainModel(newModel);
Chris@0 2985 setupMenus();
Chris@0 2986
Chris@0 2987 if (m_sessionFile == "") {
Chris@0 2988 setWindowTitle(tr("Sonic Visualiser: %1")
Chris@197 2989 .arg(source.getLocation()));
Chris@0 2990 CommandHistory::getInstance()->clear();
Chris@0 2991 CommandHistory::getInstance()->documentSaved();
Chris@0 2992 m_documentModified = false;
Chris@0 2993 } else {
Chris@0 2994 setWindowTitle(tr("Sonic Visualiser: %1 [%2]")
Chris@0 2995 .arg(QFileInfo(m_sessionFile).fileName())
Chris@197 2996 .arg(source.getLocation()));
Chris@0 2997 if (m_documentModified) {
Chris@0 2998 m_documentModified = false;
Chris@0 2999 documentModified(); // so as to restore "(modified)" window title
Chris@0 3000 }
Chris@0 3001 }
Chris@0 3002
Chris@197 3003 if (!source.isRemote()) m_audioFile = source.getLocalFilename();
Chris@0 3004
Chris@194 3005 } else if (mode == CreateAdditionalModel) {
Chris@0 3006
Chris@0 3007 CommandHistory::getInstance()->startCompoundOperation
Chris@197 3008 (tr("Import \"%1\"").arg(source.getLocation()), true);
Chris@0 3009
Chris@0 3010 m_document->addImportedModel(newModel);
Chris@0 3011
Chris@0 3012 AddPaneCommand *command = new AddPaneCommand(this);
Chris@0 3013 CommandHistory::getInstance()->addCommand(command);
Chris@0 3014
Chris@0 3015 Pane *pane = command->getPane();
Chris@0 3016
Chris@0 3017 if (!m_timeRulerLayer) {
Chris@0 3018 m_timeRulerLayer = m_document->createMainModelLayer
Chris@0 3019 (LayerFactory::TimeRuler);
Chris@0 3020 }
Chris@0 3021
Chris@0 3022 m_document->addLayerToView(pane, m_timeRulerLayer);
Chris@0 3023
Chris@0 3024 Layer *newLayer = m_document->createImportedLayer(newModel);
Chris@0 3025
Chris@0 3026 if (newLayer) {
Chris@0 3027 m_document->addLayerToView(pane, newLayer);
Chris@0 3028 }
Chris@0 3029
Chris@0 3030 CommandHistory::getInstance()->endCompoundOperation();
Chris@194 3031
Chris@194 3032 } else if (mode == ReplaceCurrentPane) {
Chris@194 3033
Chris@194 3034 // We know there is a current pane, otherwise we would have
Chris@194 3035 // reset the mode to CreateAdditionalModel above; and we know
Chris@194 3036 // the current pane does not contain the main model, otherwise
Chris@194 3037 // we would have reset it to ReplaceMainModel. But we don't
Chris@194 3038 // know whether the pane contains a waveform model at all.
Chris@194 3039
Chris@194 3040 Pane *pane = m_paneStack->getCurrentPane();
Chris@194 3041 Layer *replace = 0;
Chris@194 3042
Chris@194 3043 for (int i = 0; i < pane->getLayerCount(); ++i) {
Chris@194 3044 Layer *layer = pane->getLayer(i);
Chris@194 3045 if (dynamic_cast<WaveformLayer *>(layer)) {
Chris@194 3046 replace = layer;
Chris@194 3047 break;
Chris@194 3048 }
Chris@194 3049 }
Chris@194 3050
Chris@194 3051 CommandHistory::getInstance()->startCompoundOperation
Chris@197 3052 (tr("Import \"%1\"").arg(source.getLocation()), true);
Chris@194 3053
Chris@194 3054 m_document->addImportedModel(newModel);
Chris@194 3055
Chris@194 3056 if (replace) {
Chris@194 3057 m_document->removeLayerFromView(pane, replace);
Chris@194 3058 }
Chris@194 3059
Chris@194 3060 Layer *newLayer = m_document->createImportedLayer(newModel);
Chris@194 3061
Chris@194 3062 if (newLayer) {
Chris@194 3063 m_document->addLayerToView(pane, newLayer);
Chris@194 3064 }
Chris@194 3065
Chris@194 3066 CommandHistory::getInstance()->endCompoundOperation();
Chris@0 3067 }
Chris@0 3068
Chris@0 3069 updateMenuStates();
Chris@197 3070 m_recentFiles.addFile(source.getLocation());
Chris@197 3071 if (!source.isRemote()) {
Chris@197 3072 // for file dialog
Chris@197 3073 registerLastOpenedFilePath(FileFinder::AudioFile,
Chris@197 3074 source.getLocalFilename());
Chris@86 3075 }
Chris@70 3076 m_openingAudioFile = false;
Chris@0 3077
Chris@180 3078 currentPaneChanged(m_paneStack->getCurrentPane());
Chris@180 3079
Chris@82 3080 return FileOpenSucceeded;
Chris@0 3081 }
Chris@0 3082
Chris@180 3083 MainWindow::FileOpenStatus
Chris@197 3084 MainWindow::openPlaylist(RemoteFile source, AudioFileOpenMode mode)
Chris@180 3085 {
Chris@180 3086 std::set<QString> extensions;
Chris@180 3087 PlaylistFileReader::getSupportedExtensions(extensions);
Chris@197 3088 QString extension = source.getExtension();
Chris@180 3089 if (extensions.find(extension) == extensions.end()) return FileOpenFailed;
Chris@180 3090
Chris@197 3091 if (!source.isAvailable()) return FileOpenFailed;
Chris@197 3092 source.waitForData();
Chris@197 3093
Chris@197 3094 PlaylistFileReader reader(source.getLocalFilename());
Chris@180 3095 if (!reader.isOK()) return FileOpenFailed;
Chris@180 3096
Chris@180 3097 PlaylistFileReader::Playlist playlist = reader.load();
Chris@180 3098
Chris@180 3099 bool someSuccess = false;
Chris@180 3100
Chris@180 3101 for (PlaylistFileReader::Playlist::const_iterator i = playlist.begin();
Chris@180 3102 i != playlist.end(); ++i) {
Chris@180 3103
Chris@197 3104 FileOpenStatus status = openAudio(*i, mode);
Chris@180 3105
Chris@180 3106 if (status == FileOpenCancelled) {
Chris@180 3107 return FileOpenCancelled;
Chris@180 3108 }
Chris@180 3109
Chris@180 3110 if (status == FileOpenSucceeded) {
Chris@180 3111 someSuccess = true;
Chris@180 3112 mode = CreateAdditionalModel;
Chris@180 3113 }
Chris@180 3114 }
Chris@180 3115
Chris@180 3116 if (someSuccess) return FileOpenSucceeded;
Chris@180 3117 else return FileOpenFailed;
Chris@180 3118 }
Chris@180 3119
Chris@197 3120 MainWindow::FileOpenStatus
Chris@197 3121 MainWindow::openLayer(RemoteFile source)
Chris@197 3122 {
Chris@197 3123 Pane *pane = m_paneStack->getCurrentPane();
Chris@197 3124
Chris@197 3125 if (!pane) {
Chris@197 3126 // shouldn't happen, as the menu action should have been disabled
Chris@197 3127 std::cerr << "WARNING: MainWindow::openLayer: no current pane" << std::endl;
Chris@197 3128 return FileOpenWrongMode;
Chris@197 3129 }
Chris@197 3130
Chris@197 3131 if (!getMainModel()) {
Chris@197 3132 // shouldn't happen, as the menu action should have been disabled
Chris@197 3133 std::cerr << "WARNING: MainWindow::openLayer: No main model -- hence no default sample rate available" << std::endl;
Chris@197 3134 return FileOpenWrongMode;
Chris@197 3135 }
Chris@197 3136
Chris@197 3137 if (!source.isAvailable()) return FileOpenFailed;
Chris@197 3138 source.waitForData();
Chris@197 3139
Chris@197 3140 QString path = source.getLocalFilename();
Chris@197 3141
Chris@197 3142 if (source.getExtension() == "svl" || source.getExtension() == "xml") {
Chris@197 3143
Chris@197 3144 PaneCallback callback(this);
Chris@197 3145 QFile file(path);
Chris@197 3146
Chris@197 3147 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
Chris@197 3148 std::cerr << "ERROR: MainWindow::openLayer("
Chris@197 3149 << source.getLocation().toStdString()
Chris@197 3150 << "): Failed to open file for reading" << std::endl;
Chris@197 3151 return FileOpenFailed;
Chris@197 3152 }
Chris@197 3153
Chris@197 3154 SVFileReader reader(m_document, callback, source.getLocation());
Chris@197 3155 reader.setCurrentPane(pane);
Chris@197 3156
Chris@197 3157 QXmlInputSource inputSource(&file);
Chris@197 3158 reader.parse(inputSource);
Chris@197 3159
Chris@197 3160 if (!reader.isOK()) {
Chris@197 3161 std::cerr << "ERROR: MainWindow::openLayer("
Chris@197 3162 << source.getLocation().toStdString()
Chris@197 3163 << "): Failed to read XML file: "
Chris@197 3164 << reader.getErrorString().toStdString() << std::endl;
Chris@197 3165 return FileOpenFailed;
Chris@197 3166 }
Chris@197 3167
Chris@197 3168 m_recentFiles.addFile(source.getLocation());
Chris@197 3169
Chris@197 3170 if (!source.isRemote()) {
Chris@197 3171 registerLastOpenedFilePath(FileFinder::LayerFile, path); // for file dialog
Chris@197 3172 }
Chris@197 3173
Chris@197 3174 } else {
Chris@197 3175
Chris@197 3176 try {
Chris@197 3177
Chris@197 3178 Model *model = DataFileReaderFactory::load
Chris@197 3179 (path, getMainModel()->getSampleRate());
Chris@197 3180
Chris@197 3181 if (model) {
Chris@197 3182
Chris@197 3183 Layer *newLayer = m_document->createImportedLayer(model);
Chris@197 3184
Chris@197 3185 if (newLayer) {
Chris@197 3186
Chris@197 3187 m_document->addLayerToView(pane, newLayer);
Chris@197 3188 m_recentFiles.addFile(source.getLocation());
Chris@197 3189
Chris@197 3190 if (!source.isRemote()) {
Chris@197 3191 registerLastOpenedFilePath
Chris@197 3192 (FileFinder::LayerFile,
Chris@197 3193 path); // for file dialog
Chris@197 3194 }
Chris@197 3195
Chris@197 3196 return FileOpenSucceeded;
Chris@197 3197 }
Chris@197 3198 }
Chris@197 3199 } catch (DataFileReaderFactory::Exception e) {
Chris@197 3200 if (e == DataFileReaderFactory::ImportCancelled) {
Chris@197 3201 return FileOpenCancelled;
Chris@197 3202 }
Chris@197 3203 }
Chris@197 3204 }
Chris@197 3205
Chris@197 3206 source.setLeaveLocalFile(true);
Chris@197 3207 return FileOpenFailed;
Chris@197 3208 }
Chris@197 3209
Chris@197 3210 MainWindow::FileOpenStatus
Chris@197 3211 MainWindow::openImage(RemoteFile source)
Chris@197 3212 {
Chris@197 3213 Pane *pane = m_paneStack->getCurrentPane();
Chris@197 3214
Chris@197 3215 if (!pane) {
Chris@197 3216 // shouldn't happen, as the menu action should have been disabled
Chris@197 3217 std::cerr << "WARNING: MainWindow::openImage: no current pane" << std::endl;
Chris@197 3218 return FileOpenWrongMode;
Chris@197 3219 }
Chris@197 3220
Chris@197 3221 if (!m_document->getMainModel()) {
Chris@197 3222 return FileOpenWrongMode;
Chris@197 3223 }
Chris@197 3224
Chris@197 3225 bool newLayer = false;
Chris@197 3226
Chris@197 3227 ImageLayer *il = dynamic_cast<ImageLayer *>(pane->getSelectedLayer());
Chris@197 3228 if (!il) {
Chris@197 3229 for (int i = pane->getLayerCount()-1; i >= 0; --i) {
Chris@197 3230 il = dynamic_cast<ImageLayer *>(pane->getLayer(i));
Chris@197 3231 if (il) break;
Chris@197 3232 }
Chris@197 3233 }
Chris@197 3234 if (!il) {
Chris@197 3235 il = dynamic_cast<ImageLayer *>
Chris@197 3236 (m_document->createEmptyLayer(LayerFactory::Image));
Chris@197 3237 if (!il) return FileOpenFailed;
Chris@197 3238 newLayer = true;
Chris@197 3239 }
Chris@197 3240
Chris@197 3241 // We don't put the image file in Recent Files
Chris@197 3242
Chris@197 3243 std::cerr << "openImage: trying location \"" << source.getLocation().toStdString() << "\" in image layer" << std::endl;
Chris@197 3244
Chris@197 3245 if (!il->addImage(m_viewManager->getGlobalCentreFrame(), source.getLocation())) {
Chris@197 3246 if (newLayer) {
Chris@197 3247 m_document->setModel(il, 0); // releasing its model
Chris@197 3248 delete il;
Chris@197 3249 }
Chris@197 3250 return FileOpenFailed;
Chris@197 3251 } else {
Chris@197 3252 if (newLayer) {
Chris@197 3253 m_document->addLayerToView(pane, il);
Chris@197 3254 }
Chris@197 3255 m_paneStack->setCurrentLayer(pane, il);
Chris@197 3256 }
Chris@197 3257
Chris@197 3258 return FileOpenSucceeded;
Chris@197 3259 }
Chris@197 3260
Chris@197 3261 MainWindow::FileOpenStatus
Chris@197 3262 MainWindow::openSession(RemoteFile source)
Chris@197 3263 {
Chris@197 3264 if (!source.isAvailable()) return FileOpenFailed;
Chris@197 3265 if (source.getExtension() != "sv") return FileOpenFailed;
Chris@197 3266 source.waitForData();
Chris@197 3267
Chris@197 3268 BZipFileDevice bzFile(source.getLocalFilename());
Chris@197 3269 if (!bzFile.open(QIODevice::ReadOnly)) return FileOpenFailed;
Chris@197 3270
Chris@197 3271 if (!checkSaveModified()) return FileOpenCancelled;
Chris@197 3272
Chris@197 3273 QString error;
Chris@197 3274 closeSession();
Chris@197 3275 createDocument();
Chris@197 3276
Chris@197 3277 PaneCallback callback(this);
Chris@197 3278 m_viewManager->clearSelections();
Chris@197 3279
Chris@197 3280 SVFileReader reader(m_document, callback, source.getLocation());
Chris@197 3281 QXmlInputSource inputSource(&bzFile);
Chris@197 3282 reader.parse(inputSource);
Chris@197 3283
Chris@197 3284 if (!reader.isOK()) {
Chris@197 3285 error = tr("SV XML file read error:\n%1").arg(reader.getErrorString());
Chris@197 3286 }
Chris@197 3287
Chris@197 3288 bzFile.close();
Chris@197 3289
Chris@197 3290 bool ok = (error == "");
Chris@197 3291
Chris@197 3292 if (ok) {
Chris@197 3293
Chris@197 3294 setWindowTitle(tr("Sonic Visualiser: %1")
Chris@197 3295 .arg(source.getLocation()));
Chris@197 3296
Chris@197 3297 if (!source.isRemote()) m_sessionFile = source.getLocalFilename();
Chris@197 3298
Chris@197 3299 setupMenus();
Chris@197 3300 CommandHistory::getInstance()->clear();
Chris@197 3301 CommandHistory::getInstance()->documentSaved();
Chris@197 3302 m_documentModified = false;
Chris@197 3303 updateMenuStates();
Chris@197 3304
Chris@197 3305 m_recentFiles.addFile(source.getLocation());
Chris@197 3306
Chris@197 3307 if (!source.isRemote()) {
Chris@197 3308 // for file dialog
Chris@197 3309 registerLastOpenedFilePath(FileFinder::SessionFile,
Chris@197 3310 source.getLocalFilename());
Chris@197 3311 }
Chris@197 3312
Chris@197 3313 } else {
Chris@197 3314 setWindowTitle(tr("Sonic Visualiser"));
Chris@197 3315 }
Chris@197 3316
Chris@197 3317 return ok ? FileOpenSucceeded : FileOpenFailed;
Chris@197 3318 }
Chris@197 3319
Chris@0 3320 void
Chris@0 3321 MainWindow::createPlayTarget()
Chris@0 3322 {
Chris@0 3323 if (m_playTarget) return;
Chris@0 3324
Chris@0 3325 m_playTarget = AudioTargetFactory::createCallbackTarget(m_playSource);
Chris@0 3326 if (!m_playTarget) {
Chris@0 3327 QMessageBox::warning
Chris@0 3328 (this, tr("Couldn't open audio device"),
Chris@193 3329 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 3330 QMessageBox::Ok);
Chris@0 3331 }
Chris@0 3332 connect(m_fader, SIGNAL(valueChanged(float)),
Chris@0 3333 m_playTarget, SLOT(setOutputGain(float)));
Chris@0 3334 }
Chris@0 3335
Chris@0 3336 WaveFileModel *
Chris@0 3337 MainWindow::getMainModel()
Chris@0 3338 {
Chris@0 3339 if (!m_document) return 0;
Chris@0 3340 return m_document->getMainModel();
Chris@0 3341 }
Chris@0 3342
Chris@116 3343 const WaveFileModel *
Chris@116 3344 MainWindow::getMainModel() const
Chris@116 3345 {
Chris@116 3346 if (!m_document) return 0;
Chris@116 3347 return m_document->getMainModel();
Chris@116 3348 }
Chris@116 3349
Chris@0 3350 void
Chris@0 3351 MainWindow::newSession()
Chris@0 3352 {
Chris@0 3353 if (!checkSaveModified()) return;
Chris@0 3354
Chris@0 3355 closeSession();
Chris@0 3356 createDocument();
Chris@0 3357
Chris@0 3358 Pane *pane = m_paneStack->addPane();
Chris@0 3359
Chris@90 3360 connect(pane, SIGNAL(contextHelpChanged(const QString &)),
Chris@116 3361 this, SLOT(contextHelpChanged(const QString &)));
Chris@90 3362
Chris@0 3363 if (!m_timeRulerLayer) {
Chris@0 3364 m_timeRulerLayer = m_document->createMainModelLayer
Chris@0 3365 (LayerFactory::TimeRuler);
Chris@0 3366 }
Chris@0 3367
Chris@0 3368 m_document->addLayerToView(pane, m_timeRulerLayer);
Chris@0 3369
Chris@0 3370 Layer *waveform = m_document->createMainModelLayer(LayerFactory::Waveform);
Chris@0 3371 m_document->addLayerToView(pane, waveform);
Chris@0 3372
Chris@65 3373 m_overview->registerView(pane);
Chris@0 3374
Chris@0 3375 CommandHistory::getInstance()->clear();
Chris@0 3376 CommandHistory::getInstance()->documentSaved();
Chris@0 3377 documentRestored();
Chris@0 3378 updateMenuStates();
Chris@0 3379 }
Chris@0 3380
Chris@0 3381 void
Chris@0 3382 MainWindow::createDocument()
Chris@0 3383 {
Chris@0 3384 m_document = new Document;
Chris@0 3385
Chris@0 3386 connect(m_document, SIGNAL(layerAdded(Layer *)),
Chris@0 3387 this, SLOT(layerAdded(Layer *)));
Chris@0 3388 connect(m_document, SIGNAL(layerRemoved(Layer *)),
Chris@0 3389 this, SLOT(layerRemoved(Layer *)));
Chris@0 3390 connect(m_document, SIGNAL(layerAboutToBeDeleted(Layer *)),
Chris@0 3391 this, SLOT(layerAboutToBeDeleted(Layer *)));
Chris@0 3392 connect(m_document, SIGNAL(layerInAView(Layer *, bool)),
Chris@0 3393 this, SLOT(layerInAView(Layer *, bool)));
Chris@0 3394
Chris@0 3395 connect(m_document, SIGNAL(modelAdded(Model *)),
Chris@0 3396 this, SLOT(modelAdded(Model *)));
Chris@0 3397 connect(m_document, SIGNAL(mainModelChanged(WaveFileModel *)),
Chris@0 3398 this, SLOT(mainModelChanged(WaveFileModel *)));
Chris@0 3399 connect(m_document, SIGNAL(modelAboutToBeDeleted(Model *)),
Chris@0 3400 this, SLOT(modelAboutToBeDeleted(Model *)));
Chris@0 3401
Chris@0 3402 connect(m_document, SIGNAL(modelGenerationFailed(QString)),
Chris@0 3403 this, SLOT(modelGenerationFailed(QString)));
Chris@63 3404 connect(m_document, SIGNAL(modelRegenerationFailed(QString, QString)),
Chris@63 3405 this, SLOT(modelRegenerationFailed(QString, QString)));
Chris@0 3406 }
Chris@0 3407
Chris@0 3408 void
Chris@0 3409 MainWindow::closeSession()
Chris@0 3410 {
Chris@0 3411 if (!checkSaveModified()) return;
Chris@0 3412
Chris@0 3413 while (m_paneStack->getPaneCount() > 0) {
Chris@0 3414
Chris@0 3415 Pane *pane = m_paneStack->getPane(m_paneStack->getPaneCount() - 1);
Chris@0 3416
Chris@0 3417 while (pane->getLayerCount() > 0) {
Chris@0 3418 m_document->removeLayerFromView
Chris@0 3419 (pane, pane->getLayer(pane->getLayerCount() - 1));
Chris@0 3420 }
Chris@0 3421
Chris@65 3422 m_overview->unregisterView(pane);
Chris@0 3423 m_paneStack->deletePane(pane);
Chris@0 3424 }
Chris@0 3425
Chris@0 3426 while (m_paneStack->getHiddenPaneCount() > 0) {
Chris@0 3427
Chris@0 3428 Pane *pane = m_paneStack->getHiddenPane
Chris@0 3429 (m_paneStack->getHiddenPaneCount() - 1);
Chris@0 3430
Chris@0 3431 while (pane->getLayerCount() > 0) {
Chris@0 3432 m_document->removeLayerFromView
Chris@0 3433 (pane, pane->getLayer(pane->getLayerCount() - 1));
Chris@0 3434 }
Chris@0 3435
Chris@65 3436 m_overview->unregisterView(pane);
Chris@0 3437 m_paneStack->deletePane(pane);
Chris@0 3438 }
Chris@0 3439
Chris@0 3440 delete m_document;
Chris@0 3441 m_document = 0;
Chris@0 3442 m_viewManager->clearSelections();
Chris@0 3443 m_timeRulerLayer = 0; // document owned this
Chris@0 3444
Chris@0 3445 m_sessionFile = "";
Chris@0 3446 setWindowTitle(tr("Sonic Visualiser"));
Chris@0 3447
Chris@0 3448 CommandHistory::getInstance()->clear();
Chris@0 3449 CommandHistory::getInstance()->documentSaved();
Chris@0 3450 documentRestored();
Chris@0 3451 }
Chris@0 3452
Chris@0 3453 void
Chris@0 3454 MainWindow::openSession()
Chris@0 3455 {
Chris@0 3456 if (!checkSaveModified()) return;
Chris@0 3457
Chris@0 3458 QString orig = m_audioFile;
Chris@0 3459 if (orig == "") orig = ".";
Chris@0 3460 else orig = QFileInfo(orig).absoluteDir().canonicalPath();
Chris@0 3461
Chris@88 3462 QString path = getOpenFileName(FileFinder::SessionFile);
Chris@0 3463
Chris@0 3464 if (path.isEmpty()) return;
Chris@0 3465
Chris@197 3466 if (openSession(path) == FileOpenFailed) {
Chris@0 3467 QMessageBox::critical(this, tr("Failed to open file"),
Chris@193 3468 tr("<b>File open failed</b><p>Session file \"%1\" could not be opened").arg(path));
Chris@0 3469 }
Chris@0 3470 }
Chris@0 3471
Chris@0 3472 void
Chris@0 3473 MainWindow::openSomething()
Chris@0 3474 {
Chris@0 3475 QString orig = m_audioFile;
Chris@0 3476 if (orig == "") orig = ".";
Chris@0 3477 else orig = QFileInfo(orig).absoluteDir().canonicalPath();
Chris@0 3478
Chris@88 3479 QString path = getOpenFileName(FileFinder::AnyFile);
Chris@0 3480
Chris@0 3481 if (path.isEmpty()) return;
Chris@0 3482
Chris@197 3483 FileOpenStatus status = open(path, AskUser);
Chris@193 3484
Chris@193 3485 if (status == FileOpenFailed) {
Chris@193 3486 QMessageBox::critical(this, tr("Failed to open file"),
Chris@193 3487 tr("<b>File open failed</b><p>File \"%1\" could not be opened").arg(path));
Chris@193 3488 } else if (status == FileOpenWrongMode) {
Chris@193 3489 QMessageBox::critical(this, tr("Failed to open file"),
Chris@193 3490 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
Chris@0 3491 }
Chris@0 3492 }
Chris@0 3493
Chris@0 3494 void
Chris@86 3495 MainWindow::openLocation()
Chris@86 3496 {
Chris@103 3497 QSettings settings;
Chris@103 3498 settings.beginGroup("MainWindow");
Chris@103 3499 QString lastLocation = settings.value("lastremote", "").toString();
Chris@103 3500
Chris@86 3501 bool ok = false;
Chris@86 3502 QString text = QInputDialog::getText
Chris@86 3503 (this, tr("Open Location"),
Chris@86 3504 tr("Please enter the URL of the location to open:"),
Chris@103 3505 QLineEdit::Normal, lastLocation, &ok);
Chris@103 3506
Chris@103 3507 if (!ok) return;
Chris@103 3508
Chris@103 3509 settings.setValue("lastremote", text);
Chris@103 3510
Chris@103 3511 if (text.isEmpty()) return;
Chris@86 3512
Chris@197 3513 FileOpenStatus status = open(text);
Chris@193 3514
Chris@193 3515 if (status == FileOpenFailed) {
Chris@86 3516 QMessageBox::critical(this, tr("Failed to open location"),
Chris@193 3517 tr("<b>Open failed</b><p>URL \"%1\" could not be opened").arg(text));
Chris@193 3518 } else if (status == FileOpenWrongMode) {
Chris@193 3519 QMessageBox::critical(this, tr("Failed to open location"),
Chris@193 3520 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
Chris@86 3521 }
Chris@86 3522 }
Chris@86 3523
Chris@86 3524 void
Chris@0 3525 MainWindow::openRecentFile()
Chris@0 3526 {
Chris@0 3527 QObject *obj = sender();
Chris@0 3528 QAction *action = dynamic_cast<QAction *>(obj);
Chris@0 3529
Chris@0 3530 if (!action) {
Chris@0 3531 std::cerr << "WARNING: MainWindow::openRecentFile: sender is not an action"
Chris@0 3532 << std::endl;
Chris@0 3533 return;
Chris@0 3534 }
Chris@0 3535
Chris@0 3536 QString path = action->text();
Chris@0 3537 if (path == "") return;
Chris@0 3538
Chris@197 3539 FileOpenStatus status = open(path);
Chris@193 3540
Chris@193 3541 if (status == FileOpenFailed) {
Chris@193 3542 QMessageBox::critical(this, tr("Failed to open location"),
Chris@193 3543 tr("<b>Open failed</b><p>File or URL \"%1\" could not be opened").arg(path));
Chris@193 3544 } else if (status == FileOpenWrongMode) {
Chris@193 3545 QMessageBox::critical(this, tr("Failed to open location"),
Chris@193 3546 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
Chris@0 3547 }
Chris@0 3548 }
Chris@0 3549
Chris@0 3550 void
Chris@193 3551 MainWindow::paneDropAccepted(Pane *pane, QStringList uriList)
Chris@193 3552 {
Chris@193 3553 if (pane) m_paneStack->setCurrentPane(pane);
Chris@193 3554
Chris@193 3555 for (QStringList::iterator i = uriList.begin(); i != uriList.end(); ++i) {
Chris@193 3556
Chris@197 3557 FileOpenStatus status = open(*i, ReplaceCurrentPane);
Chris@193 3558
Chris@193 3559 if (status == FileOpenFailed) {
Chris@193 3560 QMessageBox::critical(this, tr("Failed to open dropped URL"),
Chris@193 3561 tr("<b>Open failed</b><p>Dropped URL \"%1\" could not be opened").arg(*i));
Chris@193 3562 } else if (status == FileOpenWrongMode) {
Chris@193 3563 QMessageBox::critical(this, tr("Failed to open dropped URL"),
Chris@193 3564 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
Chris@193 3565 }
Chris@193 3566 }
Chris@193 3567 }
Chris@193 3568
Chris@193 3569 void
Chris@193 3570 MainWindow::paneDropAccepted(Pane *pane, QString text)
Chris@193 3571 {
Chris@193 3572 if (pane) m_paneStack->setCurrentPane(pane);
Chris@193 3573
Chris@193 3574 QUrl testUrl(text);
Chris@193 3575 if (testUrl.scheme() == "file" ||
Chris@193 3576 testUrl.scheme() == "http" ||
Chris@193 3577 testUrl.scheme() == "ftp") {
Chris@193 3578 QStringList list;
Chris@193 3579 list.push_back(text);
Chris@193 3580 paneDropAccepted(pane, list);
Chris@193 3581 return;
Chris@193 3582 }
Chris@193 3583
Chris@193 3584 //!!! open as text -- but by importing as if a CSV, or just adding
Chris@193 3585 //to a text layer?
Chris@193 3586 }
Chris@193 3587
Chris@193 3588 void
Chris@0 3589 MainWindow::closeEvent(QCloseEvent *e)
Chris@0 3590 {
Chris@137 3591 // std::cerr << "MainWindow::closeEvent" << std::endl;
Chris@118 3592
Chris@136 3593 if (m_openingAudioFile) {
Chris@137 3594 // std::cerr << "Busy - ignoring close event" << std::endl;
Chris@136 3595 e->ignore();
Chris@136 3596 return;
Chris@136 3597 }
Chris@136 3598
Chris@70 3599 if (!m_abandoning && !checkSaveModified()) {
Chris@137 3600 // std::cerr << "Ignoring close event" << std::endl;
Chris@0 3601 e->ignore();
Chris@0 3602 return;
Chris@0 3603 }
Chris@0 3604
Chris@5 3605 QSettings settings;
Chris@5 3606 settings.beginGroup("MainWindow");
Chris@5 3607 settings.setValue("size", size());
Chris@5 3608 settings.setValue("position", pos());
Chris@5 3609 settings.endGroup();
Chris@5 3610
Chris@163 3611 delete m_keyReference;
Chris@163 3612 m_keyReference = 0;
Chris@163 3613
Chris@163 3614 if (m_preferencesDialog &&
Chris@163 3615 m_preferencesDialog->isVisible()) {
Chris@164 3616 closeSession(); // otherwise we'll have to wait for prefs changes
Chris@163 3617 m_preferencesDialog->applicationClosing(false);
Chris@163 3618 }
Chris@163 3619
Chris@177 3620 if (m_layerTreeView &&
Chris@177 3621 m_layerTreeView->isVisible()) {
Chris@177 3622 delete m_layerTreeView;
Chris@177 3623 }
Chris@177 3624
Chris@0 3625 e->accept();
Chris@0 3626 return;
Chris@0 3627 }
Chris@0 3628
Chris@0 3629 bool
Chris@11 3630 MainWindow::commitData(bool mayAskUser)
Chris@11 3631 {
Chris@11 3632 if (mayAskUser) {
Chris@163 3633 bool rv = checkSaveModified();
Chris@163 3634 if (rv) {
Chris@163 3635 if (m_preferencesDialog &&
Chris@163 3636 m_preferencesDialog->isVisible()) {
Chris@163 3637 m_preferencesDialog->applicationClosing(false);
Chris@163 3638 }
Chris@163 3639 }
Chris@163 3640 return rv;
Chris@11 3641 } else {
Chris@163 3642 if (m_preferencesDialog &&
Chris@163 3643 m_preferencesDialog->isVisible()) {
Chris@163 3644 m_preferencesDialog->applicationClosing(true);
Chris@163 3645 }
Chris@11 3646 if (!m_documentModified) return true;
Chris@11 3647
Chris@11 3648 // If we can't check with the user first, then we can't save
Chris@11 3649 // to the original session file (even if we have it) -- have
Chris@11 3650 // to use a temporary file
Chris@11 3651
Chris@11 3652 QString svDirBase = ".sv1";
Chris@11 3653 QString svDir = QDir::home().filePath(svDirBase);
Chris@11 3654
Chris@11 3655 if (!QFileInfo(svDir).exists()) {
Chris@11 3656 if (!QDir::home().mkdir(svDirBase)) return false;
Chris@11 3657 } else {
Chris@11 3658 if (!QFileInfo(svDir).isDir()) return false;
Chris@11 3659 }
Chris@11 3660
Chris@11 3661 // This name doesn't have to be unguessable
Chris@93 3662 #ifndef _WIN32
Chris@11 3663 QString fname = QString("tmp-%1-%2.sv")
Chris@11 3664 .arg(QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz"))
Chris@11 3665 .arg(QProcess().pid());
Chris@93 3666 #else
Chris@93 3667 QString fname = QString("tmp-%1.sv")
Chris@93 3668 .arg(QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz"));
Chris@93 3669 #endif
Chris@11 3670 QString fpath = QDir(svDir).filePath(fname);
Chris@11 3671 if (saveSessionFile(fpath)) {
Chris@34 3672 m_recentFiles.addFile(fpath);
Chris@11 3673 return true;
Chris@11 3674 } else {
Chris@11 3675 return false;
Chris@11 3676 }
Chris@11 3677 }
Chris@11 3678 }
Chris@11 3679
Chris@11 3680 bool
Chris@0 3681 MainWindow::checkSaveModified()
Chris@0 3682 {
Chris@0 3683 // Called before some destructive operation (e.g. new session,
Chris@0 3684 // exit program). Return true if we can safely proceed, false to
Chris@0 3685 // cancel.
Chris@0 3686
Chris@0 3687 if (!m_documentModified) return true;
Chris@0 3688
Chris@0 3689 int button =
Chris@0 3690 QMessageBox::warning(this,
Chris@0 3691 tr("Session modified"),
Chris@193 3692 tr("<b>Session modified</b><p>The current session has been modified.<br>Do you want to save it?<br>"),
Chris@165 3693 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
Chris@165 3694 QMessageBox::Yes);
Chris@0 3695
Chris@0 3696 if (button == QMessageBox::Yes) {
Chris@0 3697 saveSession();
Chris@0 3698 if (m_documentModified) { // save failed -- don't proceed!
Chris@0 3699 return false;
Chris@0 3700 } else {
Chris@0 3701 return true; // saved, so it's safe to continue now
Chris@0 3702 }
Chris@0 3703 } else if (button == QMessageBox::No) {
Chris@0 3704 m_documentModified = false; // so we know to abandon it
Chris@0 3705 return true;
Chris@0 3706 }
Chris@0 3707
Chris@0 3708 // else cancel
Chris@0 3709 return false;
Chris@0 3710 }
Chris@0 3711
Chris@0 3712 void
Chris@0 3713 MainWindow::saveSession()
Chris@0 3714 {
Chris@0 3715 if (m_sessionFile != "") {
Chris@0 3716 if (!saveSessionFile(m_sessionFile)) {
Chris@0 3717 QMessageBox::critical(this, tr("Failed to save file"),
Chris@193 3718 tr("<b>Save failed</b><p>Session file \"%1\" could not be saved.").arg(m_sessionFile));
Chris@0 3719 } else {
Chris@0 3720 CommandHistory::getInstance()->documentSaved();
Chris@0 3721 documentRestored();
Chris@0 3722 }
Chris@0 3723 } else {
Chris@0 3724 saveSessionAs();
Chris@0 3725 }
Chris@0 3726 }
Chris@0 3727
Chris@0 3728 void
Chris@0 3729 MainWindow::saveSessionAs()
Chris@0 3730 {
Chris@0 3731 QString orig = m_audioFile;
Chris@0 3732 if (orig == "") orig = ".";
Chris@0 3733 else orig = QFileInfo(orig).absoluteDir().canonicalPath();
Chris@0 3734
Chris@88 3735 QString path = getSaveFileName(FileFinder::SessionFile);
Chris@81 3736
Chris@81 3737 if (path == "") return;
Chris@0 3738
Chris@0 3739 if (!saveSessionFile(path)) {
Chris@0 3740 QMessageBox::critical(this, tr("Failed to save file"),
Chris@193 3741 tr("<b>Save failed</b><p>Session file \"%1\" could not be saved.").arg(path));
Chris@0 3742 } else {
Chris@0 3743 setWindowTitle(tr("Sonic Visualiser: %1")
Chris@0 3744 .arg(QFileInfo(path).fileName()));
Chris@0 3745 m_sessionFile = path;
Chris@0 3746 CommandHistory::getInstance()->documentSaved();
Chris@0 3747 documentRestored();
Chris@34 3748 m_recentFiles.addFile(path);
Chris@0 3749 }
Chris@0 3750 }
Chris@0 3751
Chris@0 3752 bool
Chris@0 3753 MainWindow::saveSessionFile(QString path)
Chris@0 3754 {
Chris@0 3755 BZipFileDevice bzFile(path);
Chris@0 3756 if (!bzFile.open(QIODevice::WriteOnly)) {
Chris@0 3757 std::cerr << "Failed to open session file \"" << path.toStdString()
Chris@0 3758 << "\" for writing: "
Chris@0 3759 << bzFile.errorString().toStdString() << std::endl;
Chris@0 3760 return false;
Chris@0 3761 }
Chris@0 3762
Chris@0 3763 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
Chris@0 3764
Chris@0 3765 QTextStream out(&bzFile);
Chris@0 3766 toXml(out);
Chris@0 3767 out.flush();
Chris@0 3768
Chris@0 3769 QApplication::restoreOverrideCursor();
Chris@0 3770
Chris@84 3771 if (!bzFile.isOK()) {
Chris@0 3772 QMessageBox::critical(this, tr("Failed to write file"),
Chris@193 3773 tr("<b>Save failed</b><p>Failed to write to file \"%1\": %2")
Chris@0 3774 .arg(path).arg(bzFile.errorString()));
Chris@0 3775 bzFile.close();
Chris@0 3776 return false;
Chris@0 3777 }
Chris@0 3778
Chris@0 3779 bzFile.close();
Chris@0 3780 return true;
Chris@0 3781 }
Chris@0 3782
Chris@0 3783 void
Chris@0 3784 MainWindow::toXml(QTextStream &out)
Chris@0 3785 {
Chris@0 3786 QString indent(" ");
Chris@0 3787
Chris@0 3788 out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
Chris@0 3789 out << "<!DOCTYPE sonic-visualiser>\n";
Chris@0 3790 out << "<sv>\n";
Chris@0 3791
Chris@0 3792 m_document->toXml(out, "", "");
Chris@0 3793
Chris@0 3794 out << "<display>\n";
Chris@0 3795
Chris@0 3796 out << QString(" <window width=\"%1\" height=\"%2\"/>\n")
Chris@0 3797 .arg(width()).arg(height());
Chris@0 3798
Chris@0 3799 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@0 3800
Chris@0 3801 Pane *pane = m_paneStack->getPane(i);
Chris@0 3802
Chris@0 3803 if (pane) {
Chris@0 3804 pane->toXml(out, indent);
Chris@0 3805 }
Chris@0 3806 }
Chris@0 3807
Chris@0 3808 out << "</display>\n";
Chris@0 3809
Chris@0 3810 m_viewManager->getSelection().toXml(out);
Chris@0 3811
Chris@0 3812 out << "</sv>\n";
Chris@0 3813 }
Chris@0 3814
Chris@0 3815 Pane *
Chris@0 3816 MainWindow::addPaneToStack()
Chris@0 3817 {
Chris@0 3818 AddPaneCommand *command = new AddPaneCommand(this);
Chris@0 3819 CommandHistory::getInstance()->addCommand(command);
Chris@0 3820 return command->getPane();
Chris@0 3821 }
Chris@0 3822
Chris@0 3823 void
Chris@0 3824 MainWindow::zoomIn()
Chris@0 3825 {
Chris@0 3826 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@0 3827 if (currentPane) currentPane->zoom(true);
Chris@0 3828 }
Chris@0 3829
Chris@0 3830 void
Chris@0 3831 MainWindow::zoomOut()
Chris@0 3832 {
Chris@0 3833 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@0 3834 if (currentPane) currentPane->zoom(false);
Chris@0 3835 }
Chris@0 3836
Chris@0 3837 void
Chris@0 3838 MainWindow::zoomToFit()
Chris@0 3839 {
Chris@0 3840 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@0 3841 if (!currentPane) return;
Chris@0 3842
Chris@0 3843 Model *model = getMainModel();
Chris@0 3844 if (!model) return;
Chris@0 3845
Chris@0 3846 size_t start = model->getStartFrame();
Chris@0 3847 size_t end = model->getEndFrame();
Chris@0 3848 size_t pixels = currentPane->width();
Chris@159 3849
Chris@158 3850 size_t sw = currentPane->getVerticalScaleWidth();
Chris@158 3851 if (pixels > sw * 2) pixels -= sw * 2;
Chris@158 3852 else pixels = 1;
Chris@159 3853 if (pixels > 4) pixels -= 4;
Chris@159 3854
Chris@0 3855 size_t zoomLevel = (end - start) / pixels;
Chris@0 3856
Chris@0 3857 currentPane->setZoomLevel(zoomLevel);
Chris@159 3858 currentPane->setCentreFrame((start + end) / 2);
Chris@0 3859 }
Chris@0 3860
Chris@0 3861 void
Chris@0 3862 MainWindow::zoomDefault()
Chris@0 3863 {
Chris@0 3864 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@0 3865 if (currentPane) currentPane->setZoomLevel(1024);
Chris@0 3866 }
Chris@0 3867
Chris@0 3868 void
Chris@0 3869 MainWindow::scrollLeft()
Chris@0 3870 {
Chris@0 3871 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@0 3872 if (currentPane) currentPane->scroll(false, false);
Chris@0 3873 }
Chris@0 3874
Chris@0 3875 void
Chris@0 3876 MainWindow::jumpLeft()
Chris@0 3877 {
Chris@0 3878 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@0 3879 if (currentPane) currentPane->scroll(false, true);
Chris@0 3880 }
Chris@0 3881
Chris@0 3882 void
Chris@0 3883 MainWindow::scrollRight()
Chris@0 3884 {
Chris@0 3885 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@0 3886 if (currentPane) currentPane->scroll(true, false);
Chris@0 3887 }
Chris@0 3888
Chris@0 3889 void
Chris@0 3890 MainWindow::jumpRight()
Chris@0 3891 {
Chris@0 3892 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@0 3893 if (currentPane) currentPane->scroll(true, true);
Chris@0 3894 }
Chris@0 3895
Chris@0 3896 void
Chris@0 3897 MainWindow::showNoOverlays()
Chris@0 3898 {
Chris@0 3899 m_viewManager->setOverlayMode(ViewManager::NoOverlays);
Chris@0 3900 }
Chris@0 3901
Chris@0 3902 void
Chris@90 3903 MainWindow::showMinimalOverlays()
Chris@0 3904 {
Chris@90 3905 m_viewManager->setOverlayMode(ViewManager::MinimalOverlays);
Chris@0 3906 }
Chris@0 3907
Chris@0 3908 void
Chris@90 3909 MainWindow::showStandardOverlays()
Chris@90 3910 {
Chris@90 3911 m_viewManager->setOverlayMode(ViewManager::StandardOverlays);
Chris@90 3912 }
Chris@90 3913
Chris@90 3914 void
Chris@90 3915 MainWindow::showAllOverlays()
Chris@0 3916 {
Chris@0 3917 m_viewManager->setOverlayMode(ViewManager::AllOverlays);
Chris@0 3918 }
Chris@0 3919
Chris@0 3920 void
Chris@7 3921 MainWindow::toggleZoomWheels()
Chris@7 3922 {
Chris@7 3923 if (m_viewManager->getZoomWheelsEnabled()) {
Chris@7 3924 m_viewManager->setZoomWheelsEnabled(false);
Chris@7 3925 } else {
Chris@7 3926 m_viewManager->setZoomWheelsEnabled(true);
Chris@7 3927 }
Chris@7 3928 }
Chris@7 3929
Chris@7 3930 void
Chris@72 3931 MainWindow::togglePropertyBoxes()
Chris@72 3932 {
Chris@72 3933 if (m_paneStack->getLayoutStyle() == PaneStack::NoPropertyStacks) {
Chris@72 3934 if (Preferences::getInstance()->getPropertyBoxLayout() ==
Chris@72 3935 Preferences::VerticallyStacked) {
Chris@72 3936 m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout);
Chris@72 3937 } else {
Chris@72 3938 m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout);
Chris@72 3939 }
Chris@72 3940 } else {
Chris@72 3941 m_paneStack->setLayoutStyle(PaneStack::NoPropertyStacks);
Chris@72 3942 }
Chris@72 3943 }
Chris@72 3944
Chris@72 3945 void
Chris@90 3946 MainWindow::toggleStatusBar()
Chris@90 3947 {
Chris@90 3948 QSettings settings;
Chris@90 3949 settings.beginGroup("MainWindow");
Chris@90 3950 bool sb = settings.value("showstatusbar", true).toBool();
Chris@90 3951
Chris@90 3952 if (sb) {
Chris@90 3953 statusBar()->hide();
Chris@90 3954 } else {
Chris@90 3955 statusBar()->show();
Chris@90 3956 }
Chris@90 3957
Chris@90 3958 settings.setValue("showstatusbar", !sb);
Chris@90 3959
Chris@90 3960 settings.endGroup();
Chris@90 3961 }
Chris@90 3962
Chris@90 3963 void
Chris@72 3964 MainWindow::preferenceChanged(PropertyContainer::PropertyName name)
Chris@72 3965 {
Chris@72 3966 if (name == "Property Box Layout") {
Chris@72 3967 if (m_paneStack->getLayoutStyle() != PaneStack::NoPropertyStacks) {
Chris@72 3968 if (Preferences::getInstance()->getPropertyBoxLayout() ==
Chris@72 3969 Preferences::VerticallyStacked) {
Chris@72 3970 m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout);
Chris@72 3971 } else {
Chris@72 3972 m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout);
Chris@72 3973 }
Chris@72 3974 }
Chris@180 3975 } else if (name == "Background Mode" && m_viewManager) {
Chris@180 3976 Preferences::BackgroundMode mode =
Chris@180 3977 Preferences::getInstance()->getBackgroundMode();
Chris@180 3978 if (mode == Preferences::BackgroundFromTheme) {
Chris@180 3979 m_viewManager->setGlobalDarkBackground(m_initialDarkBackground);
Chris@180 3980 } else if (mode == Preferences::DarkBackground) {
Chris@180 3981 m_viewManager->setGlobalDarkBackground(true);
Chris@180 3982 } else {
Chris@180 3983 m_viewManager->setGlobalDarkBackground(false);
Chris@180 3984 }
Chris@180 3985 if (m_viewManager->getGlobalDarkBackground()) {
Chris@180 3986 m_panLayer->setBaseColour
Chris@180 3987 (ColourDatabase::getInstance()->getColourIndex(tr("Bright Green")));
Chris@180 3988 } else {
Chris@180 3989 m_panLayer->setBaseColour
Chris@180 3990 (ColourDatabase::getInstance()->getColourIndex(tr("Green")));
Chris@180 3991 }
Chris@180 3992 }
Chris@72 3993 }
Chris@72 3994
Chris@72 3995 void
Chris@0 3996 MainWindow::play()
Chris@0 3997 {
Chris@0 3998 if (m_playSource->isPlaying()) {
Chris@116 3999 stop();
Chris@0 4000 } else {
Chris@116 4001 playbackFrameChanged(m_viewManager->getPlaybackFrame());
Chris@0 4002 m_playSource->play(m_viewManager->getPlaybackFrame());
Chris@0 4003 }
Chris@0 4004 }
Chris@0 4005
Chris@0 4006 void
Chris@0 4007 MainWindow::ffwd()
Chris@0 4008 {
Chris@0 4009 if (!getMainModel()) return;
Chris@0 4010
Chris@0 4011 int frame = m_viewManager->getPlaybackFrame();
Chris@0 4012 ++frame;
Chris@0 4013
Chris@155 4014 Layer *layer = getSnapLayer();
Chris@155 4015 size_t sr = getMainModel()->getSampleRate();
Chris@155 4016
Chris@155 4017 if (!layer) {
Chris@155 4018
Chris@155 4019 frame = RealTime::realTime2Frame
Chris@155 4020 (RealTime::frame2RealTime(frame, sr) + RealTime(2, 0), sr);
Chris@155 4021 if (frame > int(getMainModel()->getEndFrame())) {
Chris@155 4022 frame = getMainModel()->getEndFrame();
Chris@155 4023 }
Chris@155 4024
Chris@155 4025 } else {
Chris@155 4026
Chris@155 4027 size_t resolution = 0;
Chris@155 4028 if (!layer->snapToFeatureFrame(m_paneStack->getCurrentPane(),
Chris@155 4029 frame, resolution, Layer::SnapRight)) {
Chris@155 4030 frame = getMainModel()->getEndFrame();
Chris@155 4031 }
Chris@0 4032 }
Chris@155 4033
Chris@155 4034 if (frame < 0) frame = 0;
Chris@147 4035
Chris@147 4036 if (m_viewManager->getPlaySelectionMode()) {
Chris@155 4037 frame = m_viewManager->constrainFrameToSelection(size_t(frame));
Chris@147 4038 }
Chris@0 4039
Chris@0 4040 m_viewManager->setPlaybackFrame(frame);
Chris@0 4041 }
Chris@0 4042
Chris@0 4043 void
Chris@0 4044 MainWindow::ffwdEnd()
Chris@0 4045 {
Chris@0 4046 if (!getMainModel()) return;
Chris@147 4047
Chris@147 4048 size_t frame = getMainModel()->getEndFrame();
Chris@147 4049
Chris@147 4050 if (m_viewManager->getPlaySelectionMode()) {
Chris@155 4051 frame = m_viewManager->constrainFrameToSelection(frame);
Chris@147 4052 }
Chris@147 4053
Chris@147 4054 m_viewManager->setPlaybackFrame(frame);
Chris@0 4055 }
Chris@0 4056
Chris@0 4057 void
Chris@0 4058 MainWindow::rewind()
Chris@0 4059 {
Chris@0 4060 if (!getMainModel()) return;
Chris@0 4061
Chris@0 4062 int frame = m_viewManager->getPlaybackFrame();
Chris@0 4063 if (frame > 0) --frame;
Chris@0 4064
Chris@155 4065 Layer *layer = getSnapLayer();
Chris@155 4066 size_t sr = getMainModel()->getSampleRate();
Chris@156 4067
Chris@156 4068 // when rewinding during playback, we want to allow a period
Chris@156 4069 // following a rewind target point at which the rewind will go to
Chris@156 4070 // the prior point instead of the immediately neighbouring one
Chris@156 4071 if (m_playSource && m_playSource->isPlaying()) {
Chris@156 4072 RealTime ct = RealTime::frame2RealTime(frame, sr);
Chris@156 4073 ct = ct - RealTime::fromSeconds(0.25);
Chris@156 4074 if (ct < RealTime::zeroTime) ct = RealTime::zeroTime;
Chris@156 4075 // std::cerr << "rewind: frame " << frame << " -> ";
Chris@156 4076 frame = RealTime::realTime2Frame(ct, sr);
Chris@156 4077 // std::cerr << frame << std::endl;
Chris@156 4078 }
Chris@155 4079
Chris@155 4080 if (!layer) {
Chris@155 4081
Chris@155 4082 frame = RealTime::realTime2Frame
Chris@155 4083 (RealTime::frame2RealTime(frame, sr) - RealTime(2, 0), sr);
Chris@155 4084 if (frame < int(getMainModel()->getStartFrame())) {
Chris@155 4085 frame = getMainModel()->getStartFrame();
Chris@155 4086 }
Chris@155 4087
Chris@155 4088 } else {
Chris@155 4089
Chris@155 4090 size_t resolution = 0;
Chris@155 4091 if (!layer->snapToFeatureFrame(m_paneStack->getCurrentPane(),
Chris@155 4092 frame, resolution, Layer::SnapLeft)) {
Chris@155 4093 frame = getMainModel()->getStartFrame();
Chris@155 4094 }
Chris@0 4095 }
Chris@147 4096
Chris@155 4097 if (frame < 0) frame = 0;
Chris@155 4098
Chris@147 4099 if (m_viewManager->getPlaySelectionMode()) {
Chris@155 4100 frame = m_viewManager->constrainFrameToSelection(size_t(frame));
Chris@147 4101 }
Chris@147 4102
Chris@0 4103 m_viewManager->setPlaybackFrame(frame);
Chris@0 4104 }
Chris@0 4105
Chris@0 4106 void
Chris@0 4107 MainWindow::rewindStart()
Chris@0 4108 {
Chris@0 4109 if (!getMainModel()) return;
Chris@147 4110
Chris@147 4111 size_t frame = getMainModel()->getStartFrame();
Chris@147 4112
Chris@147 4113 if (m_viewManager->getPlaySelectionMode()) {
Chris@155 4114 frame = m_viewManager->constrainFrameToSelection(frame);
Chris@155 4115 }
Chris@155 4116
Chris@155 4117 m_viewManager->setPlaybackFrame(frame);
Chris@155 4118 }
Chris@155 4119
Chris@155 4120 Layer *
Chris@155 4121 MainWindow::getSnapLayer() const
Chris@155 4122 {
Chris@155 4123 Pane *pane = m_paneStack->getCurrentPane();
Chris@155 4124 if (!pane) return 0;
Chris@155 4125
Chris@155 4126 Layer *layer = pane->getSelectedLayer();
Chris@155 4127
Chris@155 4128 if (!dynamic_cast<TimeInstantLayer *>(layer) &&
Chris@155 4129 !dynamic_cast<TimeValueLayer *>(layer) &&
Chris@155 4130 !dynamic_cast<TimeRulerLayer *>(layer)) {
Chris@155 4131
Chris@155 4132 layer = 0;
Chris@155 4133
Chris@155 4134 for (int i = pane->getLayerCount(); i > 0; --i) {
Chris@155 4135 Layer *l = pane->getLayer(i-1);
Chris@155 4136 if (dynamic_cast<TimeRulerLayer *>(l)) {
Chris@155 4137 layer = l;
Chris@155 4138 break;
Chris@155 4139 }
Chris@147 4140 }
Chris@147 4141 }
Chris@147 4142
Chris@155 4143 return layer;
Chris@0 4144 }
Chris@0 4145
Chris@0 4146 void
Chris@0 4147 MainWindow::stop()
Chris@0 4148 {
Chris@0 4149 m_playSource->stop();
Chris@116 4150
Chris@116 4151 if (m_paneStack && m_paneStack->getCurrentPane()) {
Chris@116 4152 updateVisibleRangeDisplay(m_paneStack->getCurrentPane());
Chris@116 4153 } else {
Chris@116 4154 m_myStatusMessage = "";
Chris@116 4155 statusBar()->showMessage("");
Chris@116 4156 }
Chris@0 4157 }
Chris@0 4158
Chris@0 4159 void
Chris@0 4160 MainWindow::addPane()
Chris@0 4161 {
Chris@0 4162 QObject *s = sender();
Chris@0 4163 QAction *action = dynamic_cast<QAction *>(s);
Chris@0 4164
Chris@0 4165 if (!action) {
Chris@0 4166 std::cerr << "WARNING: MainWindow::addPane: sender is not an action"
Chris@0 4167 << std::endl;
Chris@0 4168 return;
Chris@0 4169 }
Chris@0 4170
Chris@0 4171 PaneActionMap::iterator i = m_paneActions.find(action);
Chris@0 4172
Chris@0 4173 if (i == m_paneActions.end()) {
Chris@0 4174 std::cerr << "WARNING: MainWindow::addPane: unknown action "
Chris@0 4175 << action->objectName().toStdString() << std::endl;
Chris@0 4176 return;
Chris@0 4177 }
Chris@0 4178
Chris@69 4179 addPane(i->second, action->text());
Chris@69 4180 }
Chris@69 4181
Chris@69 4182 void
Chris@69 4183 MainWindow::addPane(const PaneConfiguration &configuration, QString text)
Chris@69 4184 {
Chris@69 4185 CommandHistory::getInstance()->startCompoundOperation(text, true);
Chris@0 4186
Chris@0 4187 AddPaneCommand *command = new AddPaneCommand(this);
Chris@0 4188 CommandHistory::getInstance()->addCommand(command);
Chris@0 4189
Chris@0 4190 Pane *pane = command->getPane();
Chris@0 4191
Chris@69 4192 if (configuration.layer == LayerFactory::Spectrum) {
Chris@109 4193 pane->setPlaybackFollow(PlaybackScrollContinuous);
Chris@110 4194 pane->setFollowGlobalZoom(false);
Chris@112 4195 pane->setZoomLevel(512);
Chris@7 4196 }
Chris@7 4197
Chris@69 4198 if (configuration.layer != LayerFactory::TimeRuler &&
Chris@69 4199 configuration.layer != LayerFactory::Spectrum) {
Chris@8 4200
Chris@0 4201 if (!m_timeRulerLayer) {
Chris@0 4202 // std::cerr << "no time ruler layer, creating one" << std::endl;
Chris@0 4203 m_timeRulerLayer = m_document->createMainModelLayer
Chris@0 4204 (LayerFactory::TimeRuler);
Chris@0 4205 }
Chris@0 4206
Chris@0 4207 // std::cerr << "adding time ruler layer " << m_timeRulerLayer << std::endl;
Chris@0 4208
Chris@0 4209 m_document->addLayerToView(pane, m_timeRulerLayer);
Chris@0 4210 }
Chris@0 4211
Chris@69 4212 Layer *newLayer = m_document->createLayer(configuration.layer);
Chris@69 4213
Chris@69 4214 Model *suggestedModel = configuration.sourceModel;
Chris@66 4215 Model *model = 0;
Chris@66 4216
Chris@66 4217 if (suggestedModel) {
Chris@66 4218
Chris@66 4219 // check its validity
Chris@66 4220 std::vector<Model *> inputModels = m_document->getTransformInputModels();
Chris@66 4221 for (size_t j = 0; j < inputModels.size(); ++j) {
Chris@66 4222 if (inputModels[j] == suggestedModel) {
Chris@66 4223 model = suggestedModel;
Chris@66 4224 break;
Chris@66 4225 }
Chris@66 4226 }
Chris@66 4227
Chris@66 4228 if (!model) {
Chris@66 4229 std::cerr << "WARNING: Model " << (void *)suggestedModel
Chris@66 4230 << " appears in pane action map, but is not reported "
Chris@66 4231 << "by document as a valid transform source" << std::endl;
Chris@66 4232 }
Chris@66 4233 }
Chris@66 4234
Chris@66 4235 if (!model) model = m_document->getMainModel();
Chris@66 4236
Chris@66 4237 m_document->setModel(newLayer, model);
Chris@66 4238
Chris@69 4239 m_document->setChannel(newLayer, configuration.channel);
Chris@0 4240 m_document->addLayerToView(pane, newLayer);
Chris@0 4241
Chris@0 4242 m_paneStack->setCurrentPane(pane);
Chris@70 4243 m_paneStack->setCurrentLayer(pane, newLayer);
Chris@0 4244
Chris@130 4245 // std::cerr << "MainWindow::addPane: global centre frame is "
Chris@130 4246 // << m_viewManager->getGlobalCentreFrame() << std::endl;
Chris@130 4247 // pane->setCentreFrame(m_viewManager->getGlobalCentreFrame());
Chris@73 4248
Chris@0 4249 CommandHistory::getInstance()->endCompoundOperation();
Chris@0 4250
Chris@0 4251 updateMenuStates();
Chris@0 4252 }
Chris@0 4253
Chris@0 4254 MainWindow::AddPaneCommand::AddPaneCommand(MainWindow *mw) :
Chris@0 4255 m_mw(mw),
Chris@0 4256 m_pane(0),
Chris@0 4257 m_prevCurrentPane(0),
Chris@0 4258 m_added(false)
Chris@0 4259 {
Chris@0 4260 }
Chris@0 4261
Chris@0 4262 MainWindow::AddPaneCommand::~AddPaneCommand()
Chris@0 4263 {
Chris@0 4264 if (m_pane && !m_added) {
Chris@0 4265 m_mw->m_paneStack->deletePane(m_pane);
Chris@0 4266 }
Chris@0 4267 }
Chris@0 4268
Chris@0 4269 QString
Chris@0 4270 MainWindow::AddPaneCommand::getName() const
Chris@0 4271 {
Chris@0 4272 return tr("Add Pane");
Chris@0 4273 }
Chris@0 4274
Chris@0 4275 void
Chris@0 4276 MainWindow::AddPaneCommand::execute()
Chris@0 4277 {
Chris@0 4278 if (!m_pane) {
Chris@0 4279 m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane();
Chris@0 4280 m_pane = m_mw->m_paneStack->addPane();
Chris@90 4281
Chris@90 4282 connect(m_pane, SIGNAL(contextHelpChanged(const QString &)),
Chris@116 4283 m_mw, SLOT(contextHelpChanged(const QString &)));
Chris@0 4284 } else {
Chris@0 4285 m_mw->m_paneStack->showPane(m_pane);
Chris@0 4286 }
Chris@0 4287
Chris@0 4288 m_mw->m_paneStack->setCurrentPane(m_pane);
Chris@65 4289 m_mw->m_overview->registerView(m_pane);
Chris@0 4290 m_added = true;
Chris@0 4291 }
Chris@0 4292
Chris@0 4293 void
Chris@0 4294 MainWindow::AddPaneCommand::unexecute()
Chris@0 4295 {
Chris@0 4296 m_mw->m_paneStack->hidePane(m_pane);
Chris@0 4297 m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane);
Chris@65 4298 m_mw->m_overview->unregisterView(m_pane);
Chris@0 4299 m_added = false;
Chris@0 4300 }
Chris@0 4301
Chris@0 4302 MainWindow::RemovePaneCommand::RemovePaneCommand(MainWindow *mw, Pane *pane) :
Chris@0 4303 m_mw(mw),
Chris@0 4304 m_pane(pane),
Chris@0 4305 m_added(true)
Chris@0 4306 {
Chris@0 4307 }
Chris@0 4308
Chris@0 4309 MainWindow::RemovePaneCommand::~RemovePaneCommand()
Chris@0 4310 {
Chris@0 4311 if (m_pane && !m_added) {
Chris@0 4312 m_mw->m_paneStack->deletePane(m_pane);
Chris@0 4313 }
Chris@0 4314 }
Chris@0 4315
Chris@0 4316 QString
Chris@0 4317 MainWindow::RemovePaneCommand::getName() const
Chris@0 4318 {
Chris@0 4319 return tr("Remove Pane");
Chris@0 4320 }
Chris@0 4321
Chris@0 4322 void
Chris@0 4323 MainWindow::RemovePaneCommand::execute()
Chris@0 4324 {
Chris@0 4325 m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane();
Chris@0 4326 m_mw->m_paneStack->hidePane(m_pane);
Chris@65 4327 m_mw->m_overview->unregisterView(m_pane);
Chris@0 4328 m_added = false;
Chris@0 4329 }
Chris@0 4330
Chris@0 4331 void
Chris@0 4332 MainWindow::RemovePaneCommand::unexecute()
Chris@0 4333 {
Chris@0 4334 m_mw->m_paneStack->showPane(m_pane);
Chris@0 4335 m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane);
Chris@65 4336 m_mw->m_overview->registerView(m_pane);
Chris@0 4337 m_added = true;
Chris@0 4338 }
Chris@0 4339
Chris@0 4340 void
Chris@0 4341 MainWindow::addLayer()
Chris@0 4342 {
Chris@0 4343 QObject *s = sender();
Chris@0 4344 QAction *action = dynamic_cast<QAction *>(s);
Chris@0 4345
Chris@0 4346 if (!action) {
Chris@0 4347 std::cerr << "WARNING: MainWindow::addLayer: sender is not an action"
Chris@0 4348 << std::endl;
Chris@0 4349 return;
Chris@0 4350 }
Chris@0 4351
Chris@0 4352 Pane *pane = m_paneStack->getCurrentPane();
Chris@0 4353
Chris@0 4354 if (!pane) {
Chris@0 4355 std::cerr << "WARNING: MainWindow::addLayer: no current pane" << std::endl;
Chris@0 4356 return;
Chris@0 4357 }
Chris@0 4358
Chris@0 4359 ExistingLayerActionMap::iterator ei = m_existingLayerActions.find(action);
Chris@0 4360
Chris@0 4361 if (ei != m_existingLayerActions.end()) {
Chris@0 4362 Layer *newLayer = ei->second;
Chris@0 4363 m_document->addLayerToView(pane, newLayer);
Chris@0 4364 m_paneStack->setCurrentLayer(pane, newLayer);
Chris@0 4365 return;
Chris@0 4366 }
Chris@0 4367
Chris@95 4368 ei = m_sliceActions.find(action);
Chris@95 4369
Chris@95 4370 if (ei != m_sliceActions.end()) {
Chris@95 4371 Layer *newLayer = m_document->createLayer(LayerFactory::Slice);
Chris@95 4372 // document->setModel(newLayer, ei->second->getModel());
Chris@95 4373 SliceableLayer *source = dynamic_cast<SliceableLayer *>(ei->second);
Chris@95 4374 SliceLayer *dest = dynamic_cast<SliceLayer *>(newLayer);
Chris@95 4375 if (source && dest) {
Chris@95 4376 dest->setSliceableModel(source->getSliceableModel());
Chris@95 4377 connect(source, SIGNAL(sliceableModelReplaced(const Model *, const Model *)),
Chris@95 4378 dest, SLOT(sliceableModelReplaced(const Model *, const Model *)));
Chris@95 4379 connect(m_document, SIGNAL(modelAboutToBeDeleted(Model *)),
Chris@95 4380 dest, SLOT(modelAboutToBeDeleted(Model *)));
Chris@95 4381 }
Chris@95 4382 m_document->addLayerToView(pane, newLayer);
Chris@95 4383 m_paneStack->setCurrentLayer(pane, newLayer);
Chris@95 4384 return;
Chris@95 4385 }
Chris@95 4386
Chris@34 4387 TransformActionMap::iterator i = m_transformActions.find(action);
Chris@34 4388
Chris@34 4389 if (i == m_transformActions.end()) {
Chris@0 4390
Chris@0 4391 LayerActionMap::iterator i = m_layerActions.find(action);
Chris@0 4392
Chris@0 4393 if (i == m_layerActions.end()) {
Chris@0 4394 std::cerr << "WARNING: MainWindow::addLayer: unknown action "
Chris@0 4395 << action->objectName().toStdString() << std::endl;
Chris@0 4396 return;
Chris@0 4397 }
Chris@0 4398
Chris@0 4399 LayerFactory::LayerType type = i->second;
Chris@0 4400
Chris@0 4401 LayerFactory::LayerTypeSet emptyTypes =
Chris@0 4402 LayerFactory::getInstance()->getValidEmptyLayerTypes();
Chris@0 4403
Chris@0 4404 Layer *newLayer;
Chris@0 4405
Chris@0 4406 if (emptyTypes.find(type) != emptyTypes.end()) {
Chris@0 4407
Chris@0 4408 newLayer = m_document->createEmptyLayer(type);
Chris@0 4409 m_toolActions[ViewManager::DrawMode]->trigger();
Chris@0 4410
Chris@0 4411 } else {
Chris@0 4412
Chris@0 4413 newLayer = m_document->createMainModelLayer(type);
Chris@0 4414 }
Chris@0 4415
Chris@0 4416 m_document->addLayerToView(pane, newLayer);
Chris@0 4417 m_paneStack->setCurrentLayer(pane, newLayer);
Chris@0 4418
Chris@0 4419 return;
Chris@0 4420 }
Chris@0 4421
Chris@107 4422 TransformId transform = i->second;
Chris@0 4423 TransformFactory *factory = TransformFactory::getInstance();
Chris@0 4424
Chris@0 4425 QString configurationXml;
Chris@0 4426
Chris@0 4427 int channel = -1;
Chris@0 4428 // pick up the default channel from any existing layers on the same pane
Chris@0 4429 for (int j = 0; j < pane->getLayerCount(); ++j) {
Chris@0 4430 int c = LayerFactory::getInstance()->getChannel(pane->getLayer(j));
Chris@0 4431 if (c != -1) {
Chris@0 4432 channel = c;
Chris@0 4433 break;
Chris@0 4434 }
Chris@0 4435 }
Chris@0 4436
Chris@33 4437 // We always ask for configuration, even if the plugin isn't
Chris@33 4438 // supposed to be configurable, because we need to let the user
Chris@33 4439 // change the execution context (block size etc).
Chris@0 4440
Chris@27 4441 PluginTransform::ExecutionContext context(channel);
Chris@27 4442
Chris@66 4443 std::vector<Model *> candidateInputModels =
Chris@66 4444 m_document->getTransformInputModels();
Chris@53 4445
Chris@184 4446 size_t startFrame = 0, duration = 0;
Chris@184 4447 size_t endFrame = 0;
Chris@184 4448 m_viewManager->getSelection().getExtents(startFrame, endFrame);
Chris@184 4449 if (endFrame > startFrame) duration = endFrame - startFrame;
Chris@184 4450 else startFrame = 0;
Chris@184 4451
Chris@54 4452 Model *inputModel = factory->getConfigurationForTransform(transform,
Chris@54 4453 candidateInputModels,
Chris@54 4454 context,
Chris@54 4455 configurationXml,
Chris@184 4456 m_playSource,
Chris@184 4457 startFrame,
Chris@184 4458 duration);
Chris@54 4459 if (!inputModel) return;
Chris@54 4460
Chris@135 4461 // std::cerr << "MainWindow::addLayer: Input model is " << inputModel << " \"" << inputModel->objectName().toStdString() << "\"" << std::endl;
Chris@0 4462
Chris@0 4463 Layer *newLayer = m_document->createDerivedLayer(transform,
Chris@54 4464 inputModel,
Chris@27 4465 context,
Chris@0 4466 configurationXml);
Chris@0 4467
Chris@0 4468 if (newLayer) {
Chris@0 4469 m_document->addLayerToView(pane, newLayer);
Chris@27 4470 m_document->setChannel(newLayer, context.channel);
Chris@34 4471 m_recentTransforms.add(transform);
Chris@70 4472 m_paneStack->setCurrentLayer(pane, newLayer);
Chris@0 4473 }
Chris@0 4474
Chris@0 4475 updateMenuStates();
Chris@0 4476 }
Chris@0 4477
Chris@0 4478 void
Chris@0 4479 MainWindow::deleteCurrentPane()
Chris@0 4480 {
Chris@0 4481 CommandHistory::getInstance()->startCompoundOperation
Chris@0 4482 (tr("Delete Pane"), true);
Chris@0 4483
Chris@0 4484 Pane *pane = m_paneStack->getCurrentPane();
Chris@0 4485 if (pane) {
Chris@0 4486 while (pane->getLayerCount() > 0) {
Chris@0 4487 Layer *layer = pane->getLayer(0);
Chris@0 4488 if (layer) {
Chris@0 4489 m_document->removeLayerFromView(pane, layer);
Chris@0 4490 } else {
Chris@0 4491 break;
Chris@0 4492 }
Chris@0 4493 }
Chris@0 4494
Chris@0 4495 RemovePaneCommand *command = new RemovePaneCommand(this, pane);
Chris@0 4496 CommandHistory::getInstance()->addCommand(command);
Chris@0 4497 }
Chris@0 4498
Chris@0 4499 CommandHistory::getInstance()->endCompoundOperation();
Chris@0 4500
Chris@0 4501 updateMenuStates();
Chris@0 4502 }
Chris@0 4503
Chris@0 4504 void
Chris@0 4505 MainWindow::deleteCurrentLayer()
Chris@0 4506 {
Chris@0 4507 Pane *pane = m_paneStack->getCurrentPane();
Chris@0 4508 if (pane) {
Chris@0 4509 Layer *layer = pane->getSelectedLayer();
Chris@0 4510 if (layer) {
Chris@0 4511 m_document->removeLayerFromView(pane, layer);
Chris@0 4512 }
Chris@0 4513 }
Chris@0 4514 updateMenuStates();
Chris@0 4515 }
Chris@0 4516
Chris@0 4517 void
Chris@0 4518 MainWindow::renameCurrentLayer()
Chris@0 4519 {
Chris@0 4520 Pane *pane = m_paneStack->getCurrentPane();
Chris@0 4521 if (pane) {
Chris@0 4522 Layer *layer = pane->getSelectedLayer();
Chris@0 4523 if (layer) {
Chris@0 4524 bool ok = false;
Chris@0 4525 QString newName = QInputDialog::getText
Chris@0 4526 (this, tr("Rename Layer"),
Chris@0 4527 tr("New name for this layer:"),
Chris@0 4528 QLineEdit::Normal, layer->objectName(), &ok);
Chris@0 4529 if (ok) {
Chris@0 4530 layer->setObjectName(newName);
Chris@95 4531 setupExistingLayersMenus();
Chris@0 4532 }
Chris@0 4533 }
Chris@0 4534 }
Chris@0 4535 }
Chris@0 4536
Chris@0 4537 void
Chris@59 4538 MainWindow::playSpeedChanged(int position)
Chris@0 4539 {
Chris@59 4540 PlaySpeedRangeMapper mapper(0, 200);
Chris@60 4541
Chris@60 4542 float percent = m_playSpeed->mappedValue();
Chris@60 4543 float factor = mapper.getFactorForValue(percent);
Chris@60 4544
Chris@60 4545 std::cerr << "speed = " << position << " percent = " << percent << " factor = " << factor << std::endl;
Chris@60 4546
Chris@59 4547 bool something = (position != 100);
Chris@155 4548
Chris@59 4549 int pc = lrintf(percent);
Chris@21 4550
Chris@155 4551 if (!something) {
Chris@155 4552 contextHelpChanged(tr("Playback speed: Normal"));
Chris@155 4553 } else {
Chris@155 4554 contextHelpChanged(tr("Playback speed: %1%2%")
Chris@155 4555 .arg(position > 100 ? "+" : "")
Chris@155 4556 .arg(pc));
Chris@155 4557 }
Chris@155 4558
Chris@25 4559 m_playSharpen->setEnabled(something);
Chris@26 4560 m_playMono->setEnabled(something);
Chris@25 4561 bool sharpen = (something && m_playSharpen->isChecked());
Chris@26 4562 bool mono = (something && m_playMono->isChecked());
Chris@26 4563 m_playSource->setTimeStretch(factor, sharpen, mono);
Chris@155 4564
Chris@155 4565 updateMenuStates();
Chris@16 4566 }
Chris@16 4567
Chris@16 4568 void
Chris@16 4569 MainWindow::playSharpenToggled()
Chris@16 4570 {
Chris@21 4571 QSettings settings;
Chris@21 4572 settings.beginGroup("MainWindow");
Chris@21 4573 settings.setValue("playsharpen", m_playSharpen->isChecked());
Chris@21 4574 settings.endGroup();
Chris@21 4575
Chris@16 4576 playSpeedChanged(m_playSpeed->value());
Chris@0 4577 }
Chris@0 4578
Chris@0 4579 void
Chris@26 4580 MainWindow::playMonoToggled()
Chris@26 4581 {
Chris@26 4582 QSettings settings;
Chris@26 4583 settings.beginGroup("MainWindow");
Chris@26 4584 settings.setValue("playmono", m_playMono->isChecked());
Chris@26 4585 settings.endGroup();
Chris@26 4586
Chris@26 4587 playSpeedChanged(m_playSpeed->value());
Chris@26 4588 }
Chris@26 4589
Chris@26 4590 void
Chris@155 4591 MainWindow::speedUpPlayback()
Chris@155 4592 {
Chris@155 4593 int value = m_playSpeed->value();
Chris@155 4594 value = value + m_playSpeed->pageStep();
Chris@155 4595 if (value > m_playSpeed->maximum()) value = m_playSpeed->maximum();
Chris@155 4596 m_playSpeed->setValue(value);
Chris@155 4597 }
Chris@155 4598
Chris@155 4599 void
Chris@155 4600 MainWindow::slowDownPlayback()
Chris@155 4601 {
Chris@155 4602 int value = m_playSpeed->value();
Chris@155 4603 value = value - m_playSpeed->pageStep();
Chris@155 4604 if (value < m_playSpeed->minimum()) value = m_playSpeed->minimum();
Chris@155 4605 m_playSpeed->setValue(value);
Chris@155 4606 }
Chris@155 4607
Chris@155 4608 void
Chris@155 4609 MainWindow::restoreNormalPlayback()
Chris@155 4610 {
Chris@155 4611 m_playSpeed->setValue(m_playSpeed->defaultValue());
Chris@155 4612 }
Chris@155 4613
Chris@155 4614 void
Chris@116 4615 MainWindow::playbackFrameChanged(unsigned long frame)
Chris@116 4616 {
Chris@116 4617 if (!(m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
Chris@116 4618
Chris@116 4619 RealTime now = RealTime::frame2RealTime
Chris@116 4620 (frame, getMainModel()->getSampleRate());
Chris@116 4621
Chris@116 4622 if (now.sec == m_lastPlayStatusSec) return;
Chris@116 4623
Chris@116 4624 RealTime then = RealTime::frame2RealTime
Chris@116 4625 (m_playSource->getPlayEndFrame(), getMainModel()->getSampleRate());
Chris@116 4626
Chris@116 4627 QString nowStr;
Chris@116 4628 QString thenStr;
Chris@116 4629 QString remainingStr;
Chris@116 4630
Chris@116 4631 if (then.sec > 10) {
Chris@116 4632 nowStr = now.toSecText().c_str();
Chris@116 4633 thenStr = then.toSecText().c_str();
Chris@116 4634 remainingStr = (then - now).toSecText().c_str();
Chris@116 4635 m_lastPlayStatusSec = now.sec;
Chris@116 4636 } else {
Chris@116 4637 nowStr = now.toText(true).c_str();
Chris@116 4638 thenStr = then.toText(true).c_str();
Chris@116 4639 remainingStr = (then - now).toText(true).c_str();
Chris@116 4640 }
Chris@116 4641
Chris@116 4642 m_myStatusMessage = tr("Playing: %1 of %2 (%3 remaining)")
Chris@116 4643 .arg(nowStr).arg(thenStr).arg(remainingStr);
Chris@116 4644
Chris@116 4645 statusBar()->showMessage(m_myStatusMessage);
Chris@116 4646 }
Chris@116 4647
Chris@116 4648 void
Chris@137 4649 MainWindow::globalCentreFrameChanged(unsigned long )
Chris@116 4650 {
Chris@116 4651 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
Chris@116 4652 Pane *p = 0;
Chris@116 4653 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
Chris@116 4654 if (!p->getFollowGlobalPan()) return;
Chris@116 4655 updateVisibleRangeDisplay(p);
Chris@116 4656 }
Chris@116 4657
Chris@116 4658 void
Chris@137 4659 MainWindow::viewCentreFrameChanged(View *v, unsigned long )
Chris@116 4660 {
Chris@116 4661 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
Chris@116 4662 Pane *p = 0;
Chris@116 4663 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
Chris@116 4664 if (v == p) updateVisibleRangeDisplay(p);
Chris@116 4665 }
Chris@116 4666
Chris@116 4667 void
Chris@137 4668 MainWindow::viewZoomLevelChanged(View *v, unsigned long , bool )
Chris@116 4669 {
Chris@116 4670 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
Chris@116 4671 Pane *p = 0;
Chris@116 4672 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
Chris@116 4673 if (v == p) updateVisibleRangeDisplay(p);
Chris@116 4674 }
Chris@116 4675
Chris@116 4676 void
Chris@116 4677 MainWindow::updateVisibleRangeDisplay(Pane *p) const
Chris@116 4678 {
Chris@116 4679 if (!getMainModel() || !p) {
Chris@116 4680 return;
Chris@116 4681 }
Chris@116 4682
Chris@117 4683 bool haveSelection = false;
Chris@117 4684 size_t startFrame = 0, endFrame = 0;
Chris@117 4685
Chris@117 4686 if (m_viewManager && m_viewManager->haveInProgressSelection()) {
Chris@117 4687
Chris@117 4688 bool exclusive = false;
Chris@117 4689 Selection s = m_viewManager->getInProgressSelection(exclusive);
Chris@117 4690
Chris@117 4691 if (!s.isEmpty()) {
Chris@117 4692 haveSelection = true;
Chris@117 4693 startFrame = s.getStartFrame();
Chris@117 4694 endFrame = s.getEndFrame();
Chris@117 4695 }
Chris@117 4696 }
Chris@117 4697
Chris@117 4698 if (!haveSelection) {
Chris@117 4699 startFrame = p->getFirstVisibleFrame();
Chris@117 4700 endFrame = p->getLastVisibleFrame();
Chris@117 4701 }
Chris@117 4702
Chris@116 4703 RealTime start = RealTime::frame2RealTime
Chris@117 4704 (startFrame, getMainModel()->getSampleRate());
Chris@116 4705
Chris@116 4706 RealTime end = RealTime::frame2RealTime
Chris@117 4707 (endFrame, getMainModel()->getSampleRate());
Chris@116 4708
Chris@116 4709 RealTime duration = end - start;
Chris@116 4710
Chris@116 4711 QString startStr, endStr, durationStr;
Chris@116 4712 startStr = start.toText(true).c_str();
Chris@116 4713 endStr = end.toText(true).c_str();
Chris@116 4714 durationStr = duration.toText(true).c_str();
Chris@116 4715
Chris@117 4716 if (haveSelection) {
Chris@117 4717 m_myStatusMessage = tr("Selection: %1 to %2 (duration %3)")
Chris@117 4718 .arg(startStr).arg(endStr).arg(durationStr);
Chris@117 4719 } else {
Chris@117 4720 m_myStatusMessage = tr("Visible: %1 to %2 (duration %3)")
Chris@117 4721 .arg(startStr).arg(endStr).arg(durationStr);
Chris@117 4722 }
Chris@116 4723
Chris@116 4724 statusBar()->showMessage(m_myStatusMessage);
Chris@116 4725 }
Chris@116 4726
Chris@116 4727 void
Chris@0 4728 MainWindow::outputLevelsChanged(float left, float right)
Chris@0 4729 {
Chris@0 4730 m_fader->setPeakLeft(left);
Chris@0 4731 m_fader->setPeakRight(right);
Chris@0 4732 }
Chris@0 4733
Chris@0 4734 void
Chris@0 4735 MainWindow::sampleRateMismatch(size_t requested, size_t actual,
Chris@0 4736 bool willResample)
Chris@0 4737 {
Chris@0 4738 if (!willResample) {
Chris@0 4739 QMessageBox::information
Chris@0 4740 (this, tr("Sample rate mismatch"),
Chris@193 4741 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 4742 .arg(requested).arg(actual));
Chris@0 4743 }
Chris@0 4744
Chris@0 4745 updateDescriptionLabel();
Chris@0 4746 }
Chris@0 4747
Chris@0 4748 void
Chris@42 4749 MainWindow::audioOverloadPluginDisabled()
Chris@42 4750 {
Chris@42 4751 QMessageBox::information
Chris@42 4752 (this, tr("Audio processing overload"),
Chris@193 4753 tr("<b>Overloaded</b><p>Audio effects plugin auditioning has been disabled due to a processing overload."));
Chris@42 4754 }
Chris@42 4755
Chris@42 4756 void
Chris@137 4757 MainWindow::layerAdded(Layer *)
Chris@0 4758 {
Chris@0 4759 // std::cerr << "MainWindow::layerAdded(" << layer << ")" << std::endl;
Chris@0 4760 // setupExistingLayersMenu();
Chris@0 4761 updateMenuStates();
Chris@0 4762 }
Chris@0 4763
Chris@0 4764 void
Chris@137 4765 MainWindow::layerRemoved(Layer *)
Chris@0 4766 {
Chris@0 4767 // std::cerr << "MainWindow::layerRemoved(" << layer << ")" << std::endl;
Chris@95 4768 setupExistingLayersMenus();
Chris@0 4769 updateMenuStates();
Chris@0 4770 }
Chris@0 4771
Chris@0 4772 void
Chris@0 4773 MainWindow::layerAboutToBeDeleted(Layer *layer)
Chris@0 4774 {
Chris@0 4775 // std::cerr << "MainWindow::layerAboutToBeDeleted(" << layer << ")" << std::endl;
Chris@0 4776 if (layer == m_timeRulerLayer) {
Chris@0 4777 // std::cerr << "(this is the time ruler layer)" << std::endl;
Chris@0 4778 m_timeRulerLayer = 0;
Chris@0 4779 }
Chris@0 4780 }
Chris@0 4781
Chris@0 4782 void
Chris@0 4783 MainWindow::layerInAView(Layer *layer, bool inAView)
Chris@0 4784 {
Chris@0 4785 // std::cerr << "MainWindow::layerInAView(" << layer << "," << inAView << ")" << std::endl;
Chris@0 4786
Chris@0 4787 // Check whether we need to add or remove model from play source
Chris@0 4788 Model *model = layer->getModel();
Chris@0 4789 if (model) {
Chris@0 4790 if (inAView) {
Chris@0 4791 m_playSource->addModel(model);
Chris@0 4792 } else {
Chris@0 4793 bool found = false;
Chris@0 4794 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@0 4795 Pane *pane = m_paneStack->getPane(i);
Chris@0 4796 if (!pane) continue;
Chris@0 4797 for (int j = 0; j < pane->getLayerCount(); ++j) {
Chris@0 4798 Layer *pl = pane->getLayer(j);
Chris@0 4799 if (pl && pl->getModel() == model) {
Chris@0 4800 found = true;
Chris@0 4801 break;
Chris@0 4802 }
Chris@0 4803 }
Chris@0 4804 if (found) break;
Chris@0 4805 }
Chris@0 4806 if (!found) m_playSource->removeModel(model);
Chris@0 4807 }
Chris@0 4808 }
Chris@0 4809
Chris@95 4810 setupExistingLayersMenus();
Chris@0 4811 updateMenuStates();
Chris@0 4812 }
Chris@0 4813
Chris@0 4814 void
Chris@0 4815 MainWindow::modelAdded(Model *model)
Chris@0 4816 {
Chris@0 4817 // std::cerr << "MainWindow::modelAdded(" << model << ")" << std::endl;
Chris@0 4818 m_playSource->addModel(model);
Chris@66 4819 if (dynamic_cast<DenseTimeValueModel *>(model)) {
Chris@66 4820 setupPaneAndLayerMenus();
Chris@66 4821 }
Chris@0 4822 }
Chris@0 4823
Chris@0 4824 void
Chris@0 4825 MainWindow::mainModelChanged(WaveFileModel *model)
Chris@0 4826 {
Chris@0 4827 // std::cerr << "MainWindow::mainModelChanged(" << model << ")" << std::endl;
Chris@0 4828 updateDescriptionLabel();
Chris@0 4829 m_panLayer->setModel(model);
Chris@0 4830 if (model) m_viewManager->setMainModelSampleRate(model->getSampleRate());
Chris@46 4831 if (model && !m_playTarget && m_audioOutput) createPlayTarget();
Chris@0 4832 }
Chris@0 4833
Chris@0 4834 void
Chris@0 4835 MainWindow::modelAboutToBeDeleted(Model *model)
Chris@0 4836 {
Chris@0 4837 // std::cerr << "MainWindow::modelAboutToBeDeleted(" << model << ")" << std::endl;
Chris@180 4838 if (model == m_viewManager->getPlaybackModel()) {
Chris@180 4839 m_viewManager->setPlaybackModel(0);
Chris@180 4840 }
Chris@0 4841 m_playSource->removeModel(model);
Chris@91 4842 FFTDataServer::modelAboutToBeDeleted(model);
Chris@0 4843 }
Chris@0 4844
Chris@0 4845 void
Chris@0 4846 MainWindow::modelGenerationFailed(QString transformName)
Chris@0 4847 {
Chris@0 4848 QMessageBox::warning
Chris@0 4849 (this,
Chris@0 4850 tr("Failed to generate layer"),
Chris@193 4851 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 4852 .arg(transformName),
Chris@165 4853 QMessageBox::Ok);
Chris@0 4854 }
Chris@0 4855
Chris@0 4856 void
Chris@0 4857 MainWindow::modelRegenerationFailed(QString layerName, QString transformName)
Chris@0 4858 {
Chris@0 4859 QMessageBox::warning
Chris@0 4860 (this,
Chris@0 4861 tr("Failed to regenerate layer"),
Chris@193 4862 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 4863 .arg(layerName).arg(transformName),
Chris@165 4864 QMessageBox::Ok);
Chris@0 4865 }
Chris@0 4866
Chris@0 4867 void
Chris@0 4868 MainWindow::rightButtonMenuRequested(Pane *pane, QPoint position)
Chris@0 4869 {
Chris@0 4870 // std::cerr << "MainWindow::rightButtonMenuRequested(" << pane << ", " << position.x() << ", " << position.y() << ")" << std::endl;
Chris@0 4871 m_paneStack->setCurrentPane(pane);
Chris@0 4872 m_rightButtonMenu->popup(position);
Chris@0 4873 }
Chris@0 4874
Chris@0 4875 void
Chris@73 4876 MainWindow::propertyStacksResized()
Chris@73 4877 {
Chris@73 4878 /*
Chris@73 4879 std::cerr << "MainWindow::propertyStacksResized" << std::endl;
Chris@73 4880 Pane *pane = m_paneStack->getCurrentPane();
Chris@73 4881 if (pane && m_overview) {
Chris@73 4882 std::cerr << "Fixed width: " << pane->width() << std::endl;
Chris@73 4883 m_overview->setFixedWidth(pane->width());
Chris@73 4884 }
Chris@73 4885 */
Chris@73 4886 }
Chris@73 4887
Chris@73 4888 void
Chris@0 4889 MainWindow::showLayerTree()
Chris@0 4890 {
Chris@177 4891 if (!m_layerTreeView.isNull()) {
Chris@177 4892 m_layerTreeView->show();
Chris@177 4893 m_layerTreeView->raise();
Chris@177 4894 return;
Chris@177 4895 }
Chris@177 4896
Chris@177 4897 //!!! should use an actual dialog class
Chris@177 4898
Chris@177 4899 m_layerTreeView = new QTreeView();
Chris@0 4900 LayerTreeModel *tree = new LayerTreeModel(m_paneStack);
Chris@177 4901 m_layerTreeView->resize(500, 300); //!!!
Chris@177 4902 m_layerTreeView->setModel(tree);
Chris@177 4903 m_layerTreeView->expandAll();
Chris@177 4904 m_layerTreeView->show();
Chris@0 4905 }
Chris@0 4906
Chris@0 4907 void
Chris@69 4908 MainWindow::pollOSC()
Chris@69 4909 {
Chris@70 4910 if (!m_oscQueue || m_oscQueue->isEmpty()) return;
Chris@69 4911 std::cerr << "MainWindow::pollOSC: have " << m_oscQueue->getMessagesAvailable() << " messages" << std::endl;
Chris@69 4912
Chris@70 4913 if (m_openingAudioFile) return;
Chris@70 4914
Chris@69 4915 OSCMessage message = m_oscQueue->readMessage();
Chris@69 4916
Chris@69 4917 if (message.getTarget() != 0) {
Chris@69 4918 return; //!!! for now -- this class is target 0, others not handled yet
Chris@69 4919 }
Chris@69 4920
Chris@69 4921 handleOSCMessage(message);
Chris@69 4922 }
Chris@69 4923
Chris@69 4924 void
Chris@69 4925 MainWindow::handleOSCMessage(const OSCMessage &message)
Chris@69 4926 {
Chris@70 4927 std::cerr << "MainWindow::handleOSCMessage: thread id = "
Chris@70 4928 << QThread::currentThreadId() << std::endl;
Chris@70 4929
Chris@69 4930 // This large function should really be abstracted out.
Chris@69 4931
Chris@69 4932 if (message.getMethod() == "open") {
Chris@69 4933
Chris@69 4934 if (message.getArgCount() == 1 &&
Chris@69 4935 message.getArg(0).canConvert(QVariant::String)) {
Chris@69 4936 QString path = message.getArg(0).toString();
Chris@197 4937 if (open(path, ReplaceMainModel) != FileOpenSucceeded) {
Chris@69 4938 std::cerr << "MainWindow::handleOSCMessage: File open failed for path \""
Chris@69 4939 << path.toStdString() << "\"" << std::endl;
Chris@69 4940 }
Chris@69 4941 //!!! we really need to spin here and not return until the
Chris@69 4942 // file has been completely decoded...
Chris@69 4943 }
Chris@69 4944
Chris@69 4945 } else if (message.getMethod() == "openadditional") {
Chris@69 4946
Chris@69 4947 if (message.getArgCount() == 1 &&
Chris@69 4948 message.getArg(0).canConvert(QVariant::String)) {
Chris@69 4949 QString path = message.getArg(0).toString();
Chris@197 4950 if (open(path, CreateAdditionalModel) != FileOpenSucceeded) {
Chris@69 4951 std::cerr << "MainWindow::handleOSCMessage: File open failed for path \""
Chris@69 4952 << path.toStdString() << "\"" << std::endl;
Chris@69 4953 }
Chris@69 4954 }
Chris@69 4955
Chris@69 4956 } else if (message.getMethod() == "recent" ||
Chris@69 4957 message.getMethod() == "last") {
Chris@69 4958
Chris@69 4959 int n = 0;
Chris@69 4960 if (message.getMethod() == "recent" &&
Chris@69 4961 message.getArgCount() == 1 &&
Chris@69 4962 message.getArg(0).canConvert(QVariant::Int)) {
Chris@69 4963 n = message.getArg(0).toInt() - 1;
Chris@69 4964 }
Chris@69 4965 std::vector<QString> recent = m_recentFiles.getRecent();
Chris@137 4966 if (n >= 0 && n < int(recent.size())) {
Chris@197 4967 if (open(recent[n], ReplaceMainModel) != FileOpenSucceeded) {
Chris@69 4968 std::cerr << "MainWindow::handleOSCMessage: File open failed for path \""
Chris@69 4969 << recent[n].toStdString() << "\"" << std::endl;
Chris@69 4970 }
Chris@69 4971 }
Chris@69 4972
Chris@69 4973 } else if (message.getMethod() == "save") {
Chris@69 4974
Chris@69 4975 QString path;
Chris@69 4976 if (message.getArgCount() == 1 &&
Chris@69 4977 message.getArg(0).canConvert(QVariant::String)) {
Chris@69 4978 path = message.getArg(0).toString();
Chris@69 4979 if (QFileInfo(path).exists()) {
Chris@69 4980 std::cerr << "MainWindow::handleOSCMessage: Refusing to overwrite existing file in save" << std::endl;
Chris@69 4981 } else {
Chris@69 4982 saveSessionFile(path);
Chris@69 4983 }
Chris@69 4984 }
Chris@69 4985
Chris@69 4986 } else if (message.getMethod() == "export") {
Chris@69 4987
Chris@69 4988 QString path;
Chris@69 4989 if (getMainModel()) {
Chris@69 4990 if (message.getArgCount() == 1 &&
Chris@69 4991 message.getArg(0).canConvert(QVariant::String)) {
Chris@69 4992 path = message.getArg(0).toString();
Chris@69 4993 if (QFileInfo(path).exists()) {
Chris@69 4994 std::cerr << "MainWindow::handleOSCMessage: Refusing to overwrite existing file in export" << std::endl;
Chris@69 4995 } else {
Chris@69 4996 WavFileWriter writer(path,
Chris@69 4997 getMainModel()->getSampleRate(),
Chris@69 4998 getMainModel()->getChannelCount());
Chris@69 4999 MultiSelection ms = m_viewManager->getSelection();
Chris@69 5000 if (!ms.getSelections().empty()) {
Chris@69 5001 writer.writeModel(getMainModel(), &ms);
Chris@69 5002 } else {
Chris@69 5003 writer.writeModel(getMainModel());
Chris@69 5004 }
Chris@69 5005 }
Chris@69 5006 }
Chris@69 5007 }
Chris@69 5008
Chris@69 5009 } else if (message.getMethod() == "jump" ||
Chris@69 5010 message.getMethod() == "play") {
Chris@69 5011
Chris@69 5012 if (getMainModel()) {
Chris@69 5013
Chris@69 5014 unsigned long frame = m_viewManager->getPlaybackFrame();
Chris@69 5015 bool selection = false;
Chris@69 5016 bool play = (message.getMethod() == "play");
Chris@69 5017
Chris@69 5018 if (message.getArgCount() == 1) {
Chris@69 5019
Chris@69 5020 if (message.getArg(0).canConvert(QVariant::String) &&
Chris@69 5021 message.getArg(0).toString() == "selection") {
Chris@69 5022
Chris@69 5023 selection = true;
Chris@69 5024
Chris@69 5025 } else if (message.getArg(0).canConvert(QVariant::String) &&
Chris@69 5026 message.getArg(0).toString() == "end") {
Chris@69 5027
Chris@69 5028 frame = getMainModel()->getEndFrame();
Chris@69 5029
Chris@69 5030 } else if (message.getArg(0).canConvert(QVariant::Double)) {
Chris@69 5031
Chris@69 5032 double time = message.getArg(0).toDouble();
Chris@69 5033 if (time < 0.0) time = 0.0;
Chris@69 5034
Chris@69 5035 frame = lrint(time * getMainModel()->getSampleRate());
Chris@69 5036 }
Chris@69 5037 }
Chris@69 5038
Chris@69 5039 if (frame > getMainModel()->getEndFrame()) {
Chris@69 5040 frame = getMainModel()->getEndFrame();
Chris@69 5041 }
Chris@69 5042
Chris@69 5043 if (play) {
Chris@69 5044 m_viewManager->setPlaySelectionMode(selection);
Chris@69 5045 }
Chris@69 5046
Chris@69 5047 if (selection) {
Chris@69 5048 MultiSelection::SelectionList sl = m_viewManager->getSelections();
Chris@69 5049 if (!sl.empty()) {
Chris@69 5050 frame = sl.begin()->getStartFrame();
Chris@69 5051 }
Chris@69 5052 }
Chris@69 5053
Chris@69 5054 m_viewManager->setPlaybackFrame(frame);
Chris@69 5055
Chris@69 5056 if (play && !m_playSource->isPlaying()) {
Chris@69 5057 m_playSource->play(frame);
Chris@69 5058 }
Chris@69 5059 }
Chris@69 5060
Chris@69 5061 } else if (message.getMethod() == "stop") {
Chris@69 5062
Chris@69 5063 if (m_playSource->isPlaying()) m_playSource->stop();
Chris@69 5064
Chris@69 5065 } else if (message.getMethod() == "loop") {
Chris@69 5066
Chris@69 5067 if (message.getArgCount() == 1 &&
Chris@69 5068 message.getArg(0).canConvert(QVariant::String)) {
Chris@69 5069
Chris@69 5070 QString str = message.getArg(0).toString();
Chris@69 5071 if (str == "on") {
Chris@69 5072 m_viewManager->setPlayLoopMode(true);
Chris@69 5073 } else if (str == "off") {
Chris@69 5074 m_viewManager->setPlayLoopMode(false);
Chris@69 5075 }
Chris@69 5076 }
Chris@69 5077
Chris@180 5078 } else if (message.getMethod() == "solo") {
Chris@180 5079
Chris@180 5080 if (message.getArgCount() == 1 &&
Chris@180 5081 message.getArg(0).canConvert(QVariant::String)) {
Chris@180 5082
Chris@180 5083 QString str = message.getArg(0).toString();
Chris@180 5084 if (str == "on") {
Chris@180 5085 m_viewManager->setPlaySoloMode(true);
Chris@180 5086 } else if (str == "off") {
Chris@180 5087 m_viewManager->setPlaySoloMode(false);
Chris@180 5088 }
Chris@180 5089 }
Chris@180 5090
Chris@69 5091 } else if (message.getMethod() == "select" ||
Chris@69 5092 message.getMethod() == "addselect") {
Chris@69 5093
Chris@69 5094 if (getMainModel()) {
Chris@69 5095
Chris@73 5096 int f0 = getMainModel()->getStartFrame();
Chris@73 5097 int f1 = getMainModel()->getEndFrame();
Chris@69 5098
Chris@69 5099 bool done = false;
Chris@69 5100
Chris@69 5101 if (message.getArgCount() == 2 &&
Chris@69 5102 message.getArg(0).canConvert(QVariant::Double) &&
Chris@69 5103 message.getArg(1).canConvert(QVariant::Double)) {
Chris@69 5104
Chris@69 5105 double t0 = message.getArg(0).toDouble();
Chris@69 5106 double t1 = message.getArg(1).toDouble();
Chris@69 5107 if (t1 < t0) { double temp = t0; t0 = t1; t1 = temp; }
Chris@69 5108 if (t0 < 0.0) t0 = 0.0;
Chris@69 5109 if (t1 < 0.0) t1 = 0.0;
Chris@69 5110
Chris@69 5111 f0 = lrint(t0 * getMainModel()->getSampleRate());
Chris@69 5112 f1 = lrint(t1 * getMainModel()->getSampleRate());
Chris@73 5113
Chris@73 5114 Pane *pane = m_paneStack->getCurrentPane();
Chris@73 5115 Layer *layer = 0;
Chris@73 5116 if (pane) layer = pane->getSelectedLayer();
Chris@73 5117 if (layer) {
Chris@73 5118 size_t resolution;
Chris@73 5119 layer->snapToFeatureFrame(pane, f0, resolution,
Chris@73 5120 Layer::SnapLeft);
Chris@73 5121 layer->snapToFeatureFrame(pane, f1, resolution,
Chris@73 5122 Layer::SnapRight);
Chris@73 5123 }
Chris@69 5124
Chris@69 5125 } else if (message.getArgCount() == 1 &&
Chris@69 5126 message.getArg(0).canConvert(QVariant::String)) {
Chris@69 5127
Chris@69 5128 QString str = message.getArg(0).toString();
Chris@69 5129 if (str == "none") {
Chris@69 5130 m_viewManager->clearSelections();
Chris@69 5131 done = true;
Chris@69 5132 }
Chris@69 5133 }
Chris@69 5134
Chris@69 5135 if (!done) {
Chris@69 5136 if (message.getMethod() == "select") {
Chris@69 5137 m_viewManager->setSelection(Selection(f0, f1));
Chris@69 5138 } else {
Chris@69 5139 m_viewManager->addSelection(Selection(f0, f1));
Chris@69 5140 }
Chris@69 5141 }
Chris@69 5142 }
Chris@69 5143
Chris@69 5144 } else if (message.getMethod() == "add") {
Chris@69 5145
Chris@69 5146 if (getMainModel()) {
Chris@69 5147
Chris@69 5148 if (message.getArgCount() >= 1 &&
Chris@69 5149 message.getArg(0).canConvert(QVariant::String)) {
Chris@69 5150
Chris@69 5151 int channel = -1;
Chris@69 5152 if (message.getArgCount() == 2 &&
Chris@69 5153 message.getArg(0).canConvert(QVariant::Int)) {
Chris@69 5154 channel = message.getArg(0).toInt();
Chris@69 5155 if (channel < -1 ||
Chris@137 5156 channel > int(getMainModel()->getChannelCount())) {
Chris@69 5157 std::cerr << "WARNING: MainWindow::handleOSCMessage: channel "
Chris@69 5158 << channel << " out of range" << std::endl;
Chris@69 5159 channel = -1;
Chris@69 5160 }
Chris@69 5161 }
Chris@69 5162
Chris@69 5163 QString str = message.getArg(0).toString();
Chris@69 5164
Chris@69 5165 LayerFactory::LayerType type =
Chris@69 5166 LayerFactory::getInstance()->getLayerTypeForName(str);
Chris@69 5167
Chris@69 5168 if (type == LayerFactory::UnknownLayer) {
Chris@69 5169 std::cerr << "WARNING: MainWindow::handleOSCMessage: unknown layer "
Chris@69 5170 << "type " << str.toStdString() << std::endl;
Chris@69 5171 } else {
Chris@69 5172
Chris@69 5173 PaneConfiguration configuration(type,
Chris@69 5174 getMainModel(),
Chris@69 5175 channel);
Chris@69 5176
Chris@69 5177 addPane(configuration,
Chris@69 5178 tr("Add %1 Pane")
Chris@69 5179 .arg(LayerFactory::getInstance()->
Chris@69 5180 getLayerPresentationName(type)));
Chris@69 5181 }
Chris@69 5182 }
Chris@69 5183 }
Chris@69 5184
Chris@69 5185 } else if (message.getMethod() == "undo") {
Chris@69 5186
Chris@69 5187 CommandHistory::getInstance()->undo();
Chris@69 5188
Chris@69 5189 } else if (message.getMethod() == "redo") {
Chris@69 5190
Chris@69 5191 CommandHistory::getInstance()->redo();
Chris@69 5192
Chris@69 5193 } else if (message.getMethod() == "set") {
Chris@69 5194
Chris@70 5195 if (message.getArgCount() == 2 &&
Chris@69 5196 message.getArg(0).canConvert(QVariant::String) &&
Chris@69 5197 message.getArg(1).canConvert(QVariant::Double)) {
Chris@69 5198
Chris@69 5199 QString property = message.getArg(0).toString();
Chris@69 5200 float value = (float)message.getArg(1).toDouble();
Chris@69 5201
Chris@69 5202 if (property == "gain") {
Chris@69 5203 if (value < 0.0) value = 0.0;
Chris@69 5204 m_fader->setValue(value);
Chris@69 5205 if (m_playTarget) m_playTarget->setOutputGain(value);
Chris@69 5206 } else if (property == "speedup") {
Chris@69 5207 m_playSpeed->setMappedValue(value);
Chris@69 5208 } else if (property == "overlays") {
Chris@69 5209 if (value < 0.5) {
Chris@69 5210 m_viewManager->setOverlayMode(ViewManager::NoOverlays);
Chris@69 5211 } else if (value < 1.5) {
Chris@90 5212 m_viewManager->setOverlayMode(ViewManager::MinimalOverlays);
Chris@90 5213 } else if (value < 2.5) {
Chris@90 5214 m_viewManager->setOverlayMode(ViewManager::StandardOverlays);
Chris@69 5215 } else {
Chris@69 5216 m_viewManager->setOverlayMode(ViewManager::AllOverlays);
Chris@69 5217 }
Chris@70 5218 } else if (property == "zoomwheels") {
Chris@70 5219 m_viewManager->setZoomWheelsEnabled(value > 0.5);
Chris@72 5220 } else if (property == "propertyboxes") {
Chris@72 5221 bool toggle = ((value < 0.5) !=
Chris@72 5222 (m_paneStack->getLayoutStyle() == PaneStack::NoPropertyStacks));
Chris@72 5223 if (toggle) togglePropertyBoxes();
Chris@70 5224 }
Chris@70 5225
Chris@70 5226 } else {
Chris@70 5227 PropertyContainer *container = 0;
Chris@70 5228 Pane *pane = m_paneStack->getCurrentPane();
Chris@70 5229 if (pane &&
Chris@70 5230 message.getArgCount() == 3 &&
Chris@70 5231 message.getArg(0).canConvert(QVariant::String) &&
Chris@70 5232 message.getArg(1).canConvert(QVariant::String) &&
Chris@70 5233 message.getArg(2).canConvert(QVariant::String)) {
Chris@70 5234 if (message.getArg(0).toString() == "pane") {
Chris@70 5235 container = pane->getPropertyContainer(0);
Chris@70 5236 } else if (message.getArg(0).toString() == "layer") {
Chris@70 5237 container = pane->getSelectedLayer();
Chris@70 5238 }
Chris@70 5239 }
Chris@70 5240 if (container) {
Chris@70 5241 QString nameString = message.getArg(1).toString();
Chris@70 5242 QString valueString = message.getArg(2).toString();
Chris@70 5243 container->setPropertyWithCommand(nameString, valueString);
Chris@69 5244 }
Chris@69 5245 }
Chris@69 5246
Chris@69 5247 } else if (message.getMethod() == "setcurrent") {
Chris@69 5248
Chris@69 5249 int paneIndex = -1, layerIndex = -1;
Chris@69 5250 bool wantLayer = false;
Chris@69 5251
Chris@69 5252 if (message.getArgCount() >= 1 &&
Chris@69 5253 message.getArg(0).canConvert(QVariant::Int)) {
Chris@69 5254
Chris@69 5255 paneIndex = message.getArg(0).toInt() - 1;
Chris@69 5256
Chris@69 5257 if (message.getArgCount() >= 2 &&
Chris@69 5258 message.getArg(1).canConvert(QVariant::Int)) {
Chris@69 5259 wantLayer = true;
Chris@69 5260 layerIndex = message.getArg(1).toInt() - 1;
Chris@69 5261 }
Chris@69 5262 }
Chris@69 5263
Chris@69 5264 if (paneIndex >= 0 && paneIndex < m_paneStack->getPaneCount()) {
Chris@69 5265 Pane *pane = m_paneStack->getPane(paneIndex);
Chris@70 5266 m_paneStack->setCurrentPane(pane);
Chris@69 5267 if (layerIndex >= 0 && layerIndex < pane->getLayerCount()) {
Chris@69 5268 Layer *layer = pane->getLayer(layerIndex);
Chris@69 5269 m_paneStack->setCurrentLayer(pane, layer);
Chris@69 5270 } else if (wantLayer && layerIndex == -1) {
Chris@69 5271 m_paneStack->setCurrentLayer(pane, 0);
Chris@69 5272 }
Chris@69 5273 }
Chris@69 5274
Chris@69 5275 } else if (message.getMethod() == "delete") {
Chris@69 5276
Chris@69 5277 if (message.getArgCount() == 1 &&
Chris@69 5278 message.getArg(0).canConvert(QVariant::String)) {
Chris@69 5279
Chris@69 5280 QString target = message.getArg(0).toString();
Chris@69 5281
Chris@69 5282 if (target == "pane") {
Chris@69 5283
Chris@69 5284 deleteCurrentPane();
Chris@69 5285
Chris@69 5286 } else if (target == "layer") {
Chris@69 5287
Chris@69 5288 deleteCurrentLayer();
Chris@69 5289
Chris@69 5290 } else {
Chris@69 5291
Chris@69 5292 std::cerr << "WARNING: MainWindow::handleOSCMessage: Unknown delete target " << target.toStdString() << std::endl;
Chris@69 5293 }
Chris@69 5294 }
Chris@69 5295
Chris@69 5296 } else if (message.getMethod() == "zoom") {
Chris@69 5297
Chris@69 5298 if (message.getArgCount() == 1) {
Chris@69 5299 if (message.getArg(0).canConvert(QVariant::String) &&
Chris@69 5300 message.getArg(0).toString() == "in") {
Chris@69 5301 zoomIn();
Chris@69 5302 } else if (message.getArg(0).canConvert(QVariant::String) &&
Chris@69 5303 message.getArg(0).toString() == "out") {
Chris@69 5304 zoomOut();
Chris@69 5305 } else if (message.getArg(0).canConvert(QVariant::String) &&
Chris@69 5306 message.getArg(0).toString() == "default") {
Chris@69 5307 zoomDefault();
Chris@69 5308 } else if (message.getArg(0).canConvert(QVariant::Double)) {
Chris@69 5309 double level = message.getArg(0).toDouble();
Chris@69 5310 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@69 5311 if (level < 1.0) level = 1.0;
Chris@69 5312 if (currentPane) currentPane->setZoomLevel(lrint(level));
Chris@69 5313 }
Chris@69 5314 }
Chris@69 5315
Chris@73 5316 } else if (message.getMethod() == "zoomvertical") {
Chris@73 5317
Chris@73 5318 Pane *pane = m_paneStack->getCurrentPane();
Chris@73 5319 Layer *layer = 0;
Chris@73 5320 if (pane && pane->getLayerCount() > 0) {
Chris@73 5321 layer = pane->getLayer(pane->getLayerCount() - 1);
Chris@73 5322 }
Chris@73 5323 int defaultStep = 0;
Chris@73 5324 int steps = 0;
Chris@73 5325 if (layer) {
Chris@73 5326 steps = layer->getVerticalZoomSteps(defaultStep);
Chris@73 5327 if (message.getArgCount() == 1 && steps > 0) {
Chris@73 5328 if (message.getArg(0).canConvert(QVariant::String) &&
Chris@73 5329 message.getArg(0).toString() == "in") {
Chris@73 5330 int step = layer->getCurrentVerticalZoomStep() + 1;
Chris@73 5331 if (step < steps) layer->setVerticalZoomStep(step);
Chris@73 5332 } else if (message.getArg(0).canConvert(QVariant::String) &&
Chris@73 5333 message.getArg(0).toString() == "out") {
Chris@73 5334 int step = layer->getCurrentVerticalZoomStep() - 1;
Chris@73 5335 if (step >= 0) layer->setVerticalZoomStep(step);
Chris@73 5336 } else if (message.getArg(0).canConvert(QVariant::String) &&
Chris@73 5337 message.getArg(0).toString() == "default") {
Chris@73 5338 layer->setVerticalZoomStep(defaultStep);
Chris@73 5339 }
Chris@73 5340 } else if (message.getArgCount() == 2) {
Chris@73 5341 if (message.getArg(0).canConvert(QVariant::Double) &&
Chris@73 5342 message.getArg(1).canConvert(QVariant::Double)) {
Chris@73 5343 double min = message.getArg(0).toDouble();
Chris@73 5344 double max = message.getArg(1).toDouble();
Chris@73 5345 layer->setDisplayExtents(min, max);
Chris@73 5346 }
Chris@73 5347 }
Chris@73 5348 }
Chris@73 5349
Chris@70 5350 } else if (message.getMethod() == "quit") {
Chris@70 5351
Chris@70 5352 m_abandoning = true;
Chris@70 5353 close();
Chris@70 5354
Chris@70 5355 } else if (message.getMethod() == "resize") {
Chris@70 5356
Chris@70 5357 if (message.getArgCount() == 2) {
Chris@70 5358
Chris@70 5359 int width = 0, height = 0;
Chris@70 5360
Chris@70 5361 if (message.getArg(1).canConvert(QVariant::Int)) {
Chris@70 5362
Chris@70 5363 height = message.getArg(1).toInt();
Chris@70 5364
Chris@70 5365 if (message.getArg(0).canConvert(QVariant::String) &&
Chris@70 5366 message.getArg(0).toString() == "pane") {
Chris@70 5367
Chris@70 5368 Pane *pane = m_paneStack->getCurrentPane();
Chris@70 5369 if (pane) pane->resize(pane->width(), height);
Chris@70 5370
Chris@70 5371 } else if (message.getArg(0).canConvert(QVariant::Int)) {
Chris@70 5372
Chris@70 5373 width = message.getArg(0).toInt();
Chris@70 5374 resize(width, height);
Chris@70 5375 }
Chris@70 5376 }
Chris@70 5377 }
Chris@70 5378
Chris@70 5379 } else if (message.getMethod() == "transform") {
Chris@70 5380
Chris@70 5381 Pane *pane = m_paneStack->getCurrentPane();
Chris@70 5382
Chris@70 5383 if (getMainModel() &&
Chris@70 5384 pane &&
Chris@70 5385 message.getArgCount() == 1 &&
Chris@70 5386 message.getArg(0).canConvert(QVariant::String)) {
Chris@70 5387
Chris@107 5388 TransformId transform = message.getArg(0).toString();
Chris@70 5389
Chris@70 5390 Layer *newLayer = m_document->createDerivedLayer
Chris@70 5391 (transform,
Chris@70 5392 getMainModel(),
Chris@73 5393 TransformFactory::getInstance()->getDefaultContextForTransform
Chris@73 5394 (transform, getMainModel()),
Chris@70 5395 "");
Chris@70 5396
Chris@70 5397 if (newLayer) {
Chris@70 5398 m_document->addLayerToView(pane, newLayer);
Chris@70 5399 m_recentTransforms.add(transform);
Chris@70 5400 m_paneStack->setCurrentLayer(pane, newLayer);
Chris@70 5401 }
Chris@70 5402 }
Chris@70 5403
Chris@69 5404 } else {
Chris@69 5405 std::cerr << "WARNING: MainWindow::handleOSCMessage: Unknown or unsupported "
Chris@69 5406 << "method \"" << message.getMethod().toStdString()
Chris@69 5407 << "\"" << std::endl;
Chris@69 5408 }
Chris@69 5409
Chris@69 5410 }
Chris@69 5411
Chris@69 5412 void
Chris@0 5413 MainWindow::preferences()
Chris@0 5414 {
Chris@0 5415 if (!m_preferencesDialog.isNull()) {
Chris@0 5416 m_preferencesDialog->show();
Chris@0 5417 m_preferencesDialog->raise();
Chris@0 5418 return;
Chris@0 5419 }
Chris@0 5420
Chris@0 5421 m_preferencesDialog = new PreferencesDialog(this);
Chris@0 5422
Chris@0 5423 // DeleteOnClose is safe here, because m_preferencesDialog is a
Chris@0 5424 // QPointer that will be zeroed when the dialog is deleted. We
Chris@0 5425 // use it in preference to leaving the dialog lying around because
Chris@0 5426 // if you Cancel the dialog, it resets the preferences state
Chris@0 5427 // without resetting its own widgets, so its state will be
Chris@0 5428 // incorrect when next shown unless we construct it afresh
Chris@0 5429 m_preferencesDialog->setAttribute(Qt::WA_DeleteOnClose);
Chris@0 5430
Chris@0 5431 m_preferencesDialog->show();
Chris@0 5432 }
Chris@0 5433
Chris@0 5434 void
Chris@90 5435 MainWindow::mouseEnteredWidget()
Chris@90 5436 {
Chris@90 5437 QWidget *w = dynamic_cast<QWidget *>(sender());
Chris@90 5438 if (!w) return;
Chris@90 5439
Chris@90 5440 if (w == m_fader) {
Chris@116 5441 contextHelpChanged(tr("Adjust the master playback level"));
Chris@90 5442 } else if (w == m_playSpeed) {
Chris@116 5443 contextHelpChanged(tr("Adjust the master playback speed"));
Chris@90 5444 } else if (w == m_playSharpen && w->isEnabled()) {
Chris@116 5445 contextHelpChanged(tr("Toggle transient sharpening for playback time scaling"));
Chris@90 5446 } else if (w == m_playMono && w->isEnabled()) {
Chris@116 5447 contextHelpChanged(tr("Toggle mono mode for playback time scaling"));
Chris@90 5448 }
Chris@90 5449 }
Chris@90 5450
Chris@90 5451 void
Chris@90 5452 MainWindow::mouseLeftWidget()
Chris@90 5453 {
Chris@116 5454 contextHelpChanged("");
Chris@116 5455 }
Chris@116 5456
Chris@116 5457 void
Chris@117 5458 MainWindow::inProgressSelectionChanged()
Chris@117 5459 {
Chris@117 5460 Pane *currentPane = 0;
Chris@117 5461 if (m_paneStack) currentPane = m_paneStack->getCurrentPane();
Chris@117 5462 if (currentPane) updateVisibleRangeDisplay(currentPane);
Chris@117 5463 }
Chris@117 5464
Chris@117 5465 void
Chris@116 5466 MainWindow::contextHelpChanged(const QString &s)
Chris@116 5467 {
Chris@116 5468 if (s == "" && m_myStatusMessage != "") {
Chris@116 5469 statusBar()->showMessage(m_myStatusMessage);
Chris@116 5470 return;
Chris@116 5471 }
Chris@116 5472 statusBar()->showMessage(s);
Chris@90 5473 }
Chris@90 5474
Chris@90 5475 void
Chris@0 5476 MainWindow::website()
Chris@0 5477 {
Chris@0 5478 openHelpUrl(tr("http://www.sonicvisualiser.org/"));
Chris@0 5479 }
Chris@0 5480
Chris@0 5481 void
Chris@0 5482 MainWindow::help()
Chris@0 5483 {
Chris@126 5484 openHelpUrl(tr("http://www.sonicvisualiser.org/doc/reference/1.0/en/"));
Chris@0 5485 }
Chris@0 5486
Chris@0 5487 void
Chris@0 5488 MainWindow::openHelpUrl(QString url)
Chris@0 5489 {
Chris@0 5490 // This method mostly lifted from Qt Assistant source code
Chris@0 5491
Chris@0 5492 QProcess *process = new QProcess(this);
Chris@0 5493 connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater()));
Chris@0 5494
Chris@0 5495 QStringList args;
Chris@0 5496
Chris@0 5497 #ifdef Q_OS_MAC
Chris@0 5498 args.append(url);
Chris@0 5499 process->start("open", args);
Chris@0 5500 #else
Chris@0 5501 #ifdef Q_OS_WIN32
Chris@0 5502
Chris@0 5503 QString pf(getenv("ProgramFiles"));
Chris@0 5504 QString command = pf + QString("\\Internet Explorer\\IEXPLORE.EXE");
Chris@0 5505
Chris@0 5506 args.append(url);
Chris@0 5507 process->start(command, args);
Chris@0 5508
Chris@0 5509 #else
Chris@0 5510 #ifdef Q_WS_X11
Chris@0 5511 if (!qgetenv("KDE_FULL_SESSION").isEmpty()) {
Chris@0 5512 args.append("exec");
Chris@0 5513 args.append(url);
Chris@0 5514 process->start("kfmclient", args);
Chris@0 5515 } else if (!qgetenv("BROWSER").isEmpty()) {
Chris@0 5516 args.append(url);
Chris@0 5517 process->start(qgetenv("BROWSER"), args);
Chris@0 5518 } else {
Chris@0 5519 args.append(url);
Chris@0 5520 process->start("firefox", args);
Chris@0 5521 }
Chris@0 5522 #endif
Chris@0 5523 #endif
Chris@0 5524 #endif
Chris@0 5525 }
Chris@0 5526
Chris@0 5527 void
Chris@0 5528 MainWindow::about()
Chris@0 5529 {
Chris@0 5530 bool debug = false;
Chris@0 5531 QString version = "(unknown version)";
Chris@0 5532
Chris@0 5533 #ifdef BUILD_DEBUG
Chris@0 5534 debug = true;
Chris@0 5535 #endif
Chris@0 5536 #ifdef SV_VERSION
Chris@0 5537 #ifdef SVNREV
Chris@0 5538 version = tr("Release %1 : Revision %2").arg(SV_VERSION).arg(SVNREV);
Chris@0 5539 #else
Chris@0 5540 version = tr("Release %1").arg(SV_VERSION);
Chris@0 5541 #endif
Chris@0 5542 #else
Chris@0 5543 #ifdef SVNREV
Chris@0 5544 version = tr("Unreleased : Revision %1").arg(SVNREV);
Chris@0 5545 #endif
Chris@0 5546 #endif
Chris@0 5547
Chris@0 5548 QString aboutText;
Chris@0 5549
Chris@0 5550 aboutText += tr("<h3>About Sonic Visualiser</h3>");
Chris@90 5551 aboutText += tr("<p>Sonic Visualiser is a program for viewing and exploring audio data for<br>semantic music analysis and annotation.</p>");
Chris@111 5552 aboutText += tr("<p>%1 : %2 configuration</p>")
Chris@0 5553 .arg(version)
Chris@0 5554 .arg(debug ? tr("Debug") : tr("Release"));
Chris@0 5555
Chris@132 5556 #ifndef BUILD_STATIC
Chris@132 5557 aboutText += tr("<br>Using Qt v%1 &copy; Trolltech AS").arg(QT_VERSION_STR);
Chris@132 5558 #else
Chris@132 5559 #ifdef QT_SHARED
Chris@132 5560 aboutText += tr("<br>Using Qt v%1 &copy; Trolltech AS").arg(QT_VERSION_STR);
Chris@132 5561 #endif
Chris@132 5562 #endif
Chris@132 5563
Chris@0 5564 #ifdef BUILD_STATIC
Chris@0 5565 aboutText += tr("<p>Statically linked");
Chris@0 5566 #ifndef QT_SHARED
Chris@0 5567 aboutText += tr("<br>With Qt (v%1) &copy; Trolltech AS").arg(QT_VERSION_STR);
Chris@0 5568 #endif
Chris@0 5569 #ifdef HAVE_JACK
Chris@93 5570 #ifdef JACK_VERSION
Chris@0 5571 aboutText += tr("<br>With JACK audio output (v%1) &copy; Paul Davis and Jack O'Quin").arg(JACK_VERSION);
Chris@93 5572 #else
Chris@93 5573 aboutText += tr("<br>With JACK audio output &copy; Paul Davis and Jack O'Quin");
Chris@93 5574 #endif
Chris@0 5575 #endif
Chris@0 5576 #ifdef HAVE_PORTAUDIO
Chris@0 5577 aboutText += tr("<br>With PortAudio audio output &copy; Ross Bencina and Phil Burk");
Chris@0 5578 #endif
Chris@0 5579 #ifdef HAVE_OGGZ
Chris@93 5580 #ifdef OGGZ_VERSION
Chris@0 5581 aboutText += tr("<br>With Ogg file decoder (oggz v%1, fishsound v%2) &copy; CSIRO Australia").arg(OGGZ_VERSION).arg(FISHSOUND_VERSION);
Chris@93 5582 #else
Chris@93 5583 aboutText += tr("<br>With Ogg file decoder &copy; CSIRO Australia");
Chris@93 5584 #endif
Chris@0 5585 #endif
Chris@0 5586 #ifdef HAVE_MAD
Chris@93 5587 #ifdef MAD_VERSION
Chris@0 5588 aboutText += tr("<br>With MAD mp3 decoder (v%1) &copy; Underbit Technologies Inc").arg(MAD_VERSION);
Chris@93 5589 #else
Chris@93 5590 aboutText += tr("<br>With MAD mp3 decoder &copy; Underbit Technologies Inc");
Chris@93 5591 #endif
Chris@0 5592 #endif
Chris@0 5593 #ifdef HAVE_SAMPLERATE
Chris@93 5594 #ifdef SAMPLERATE_VERSION
Chris@0 5595 aboutText += tr("<br>With libsamplerate (v%1) &copy; Erik de Castro Lopo").arg(SAMPLERATE_VERSION);
Chris@93 5596 #else
Chris@93 5597 aboutText += tr("<br>With libsamplerate &copy; Erik de Castro Lopo");
Chris@93 5598 #endif
Chris@0 5599 #endif
Chris@0 5600 #ifdef HAVE_SNDFILE
Chris@93 5601 #ifdef SNDFILE_VERSION
Chris@0 5602 aboutText += tr("<br>With libsndfile (v%1) &copy; Erik de Castro Lopo").arg(SNDFILE_VERSION);
Chris@93 5603 #else
Chris@93 5604 aboutText += tr("<br>With libsndfile &copy; Erik de Castro Lopo");
Chris@93 5605 #endif
Chris@0 5606 #endif
Chris@127 5607 #ifdef HAVE_FFTW3F
Chris@93 5608 #ifdef FFTW3_VERSION
Chris@0 5609 aboutText += tr("<br>With FFTW3 (v%1) &copy; Matteo Frigo and MIT").arg(FFTW3_VERSION);
Chris@93 5610 #else
Chris@93 5611 aboutText += tr("<br>With FFTW3 &copy; Matteo Frigo and MIT");
Chris@93 5612 #endif
Chris@0 5613 #endif
Chris@0 5614 #ifdef HAVE_VAMP
Chris@114 5615 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 5616 #endif
Chris@0 5617 aboutText += tr("<br>With LADSPA plugin support (API v%1) &copy; Richard Furse, Paul Davis, Stefan Westerfeld").arg(LADSPA_VERSION);
Chris@0 5618 aboutText += tr("<br>With DSSI plugin support (API v%1) &copy; Chris Cannam, Steve Harris, Sean Bolton").arg(DSSI_VERSION);
Chris@69 5619 #ifdef HAVE_LIBLO
Chris@93 5620 #ifdef LIBLO_VERSION
Chris@69 5621 aboutText += tr("<br>With liblo Lite OSC library (v%1) &copy; Steve Harris").arg(LIBLO_VERSION);
Chris@93 5622 #else
Chris@93 5623 aboutText += tr("<br>With liblo Lite OSC library &copy; Steve Harris").arg(LIBLO_VERSION);
Chris@93 5624 #endif
Chris@70 5625 if (m_oscQueue && m_oscQueue->isOK()) {
Chris@69 5626 aboutText += tr("<p>The OSC URL for this instance is: \"%1\"").arg(m_oscQueue->getOSCURL());
Chris@69 5627 }
Chris@69 5628 #endif
Chris@0 5629 aboutText += "</p>";
Chris@0 5630 #endif
Chris@0 5631
Chris@0 5632 aboutText +=
Chris@90 5633 "<p>Sonic Visualiser Copyright &copy; 2005 - 2007 Chris Cannam and<br>"
Chris@90 5634 "Queen Mary, University of London.</p>"
Chris@0 5635 "<p>This program is free software; you can redistribute it and/or<br>"
Chris@0 5636 "modify it under the terms of the GNU General Public License as<br>"
Chris@0 5637 "published by the Free Software Foundation; either version 2 of the<br>"
Chris@0 5638 "License, or (at your option) any later version.<br>See the file "
Chris@0 5639 "COPYING included with this distribution for more information.</p>";
Chris@0 5640
Chris@0 5641 QMessageBox::about(this, tr("About Sonic Visualiser"), aboutText);
Chris@0 5642 }
Chris@0 5643
Chris@162 5644 void
Chris@162 5645 MainWindow::keyReference()
Chris@162 5646 {
Chris@162 5647 m_keyReference->show();
Chris@162 5648 }
Chris@162 5649