annotate main/MainWindow.cpp @ 184:ebd906049fb6

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