annotate main/MainWindow.cpp @ 468:91eeab6c70a3 integration_library

Update of the version no to 1.9-kiosk-hg (debug mode)
author mathieub <mathieu.barthet@eecs.qmul.ac.uk>
date Tue, 23 Aug 2011 18:51:35 +0100
parents a373a9cdbe13
children e5c6aed2bf6b
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@200 7 This file copyright 2006-2007 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@0 19 #include "PreferencesDialog.h"
Chris@0 20
Chris@1 21 #include "view/Pane.h"
Chris@1 22 #include "view/PaneStack.h"
Chris@1 23 #include "data/model/WaveFileModel.h"
Chris@1 24 #include "data/model/SparseOneDimensionalModel.h"
Chris@415 25 #include "data/model/RangeSummarisableTimeValueModel.h"
Chris@185 26 #include "data/model/NoteModel.h"
Chris@189 27 #include "data/model/Labeller.h"
Chris@222 28 #include "data/osc/OSCQueue.h"
Chris@216 29 #include "framework/Document.h"
Chris@357 30 #include "framework/TransformUserConfigurator.h"
Chris@1 31 #include "view/ViewManager.h"
Chris@0 32 #include "base/Preferences.h"
Chris@423 33 #include "base/ResourceFinder.h"
Chris@0 34 #include "layer/WaveformLayer.h"
Chris@0 35 #include "layer/TimeRulerLayer.h"
Chris@0 36 #include "layer/TimeInstantLayer.h"
Chris@0 37 #include "layer/TimeValueLayer.h"
Chris@307 38 #include "layer/NoteLayer.h"
Chris@0 39 #include "layer/Colour3DPlotLayer.h"
Chris@95 40 #include "layer/SliceLayer.h"
Chris@95 41 #include "layer/SliceableLayer.h"
Chris@193 42 #include "layer/ImageLayer.h"
Chris@340 43 #include "layer/RegionLayer.h"
Chris@0 44 #include "widgets/Fader.h"
Chris@65 45 #include "view/Overview.h"
Chris@0 46 #include "widgets/PropertyBox.h"
Chris@0 47 #include "widgets/PropertyStack.h"
Chris@0 48 #include "widgets/AudioDial.h"
Chris@168 49 #include "widgets/IconLoader.h"
Chris@219 50 #include "widgets/LayerTreeDialog.h"
Chris@0 51 #include "widgets/ListInputDialog.h"
Chris@36 52 #include "widgets/SubdividingMenu.h"
Chris@90 53 #include "widgets/NotifyingPushButton.h"
Chris@162 54 #include "widgets/KeyReference.h"
Chris@273 55 #include "widgets/TransformFinder.h"
Chris@192 56 #include "widgets/LabelCounterInputDialog.h"
Chris@302 57 #include "widgets/ActivityLog.h"
Chris@0 58 #include "audioio/AudioCallbackPlaySource.h"
Chris@0 59 #include "audioio/AudioCallbackPlayTarget.h"
Chris@0 60 #include "audioio/AudioTargetFactory.h"
Chris@59 61 #include "audioio/PlaySpeedRangeMapper.h"
Chris@1 62 #include "data/fileio/DataFileReaderFactory.h"
Chris@180 63 #include "data/fileio/PlaylistFileReader.h"
Chris@1 64 #include "data/fileio/WavFileWriter.h"
Chris@1 65 #include "data/fileio/CSVFileWriter.h"
Chris@185 66 #include "data/fileio/MIDIFileWriter.h"
Chris@1 67 #include "data/fileio/BZipFileDevice.h"
Chris@198 68 #include "data/fileio/FileSource.h"
Chris@91 69 #include "data/fft/FFTDataServer.h"
Chris@304 70 #include "data/midi/MIDIInput.h"
Chris@1 71 #include "base/RecentFiles.h"
Chris@249 72 #include "transform/TransformFactory.h"
Chris@249 73 #include "transform/ModelTransformerFactory.h"
Chris@0 74 #include "base/PlayParameterRepository.h"
Chris@0 75 #include "base/XmlExportable.h"
Chris@248 76 #include "widgets/CommandHistory.h"
Chris@0 77 #include "base/Profiler.h"
Chris@0 78 #include "base/Clipboard.h"
Chris@165 79 #include "base/UnitDatabase.h"
Chris@248 80 #include "layer/ColourDatabase.h"
Chris@265 81 #include "widgets/ModelDataTableDialog.h"
Chris@289 82 #include "rdf/PluginRDFIndexer.h"
Chris@291 83 #include "rdf/RDFExporter.h"
Chris@276 84
Chris@333 85 #include "Surveyer.h"
Chris@334 86 #include "framework/VersionTester.h"
Chris@333 87
Chris@0 88 // For version information
Chris@280 89 #include <vamp/vamp.h>
Chris@280 90 #include <vamp-hostsdk/PluginBase.h>
Chris@0 91 #include "plugin/api/ladspa.h"
Chris@0 92 #include "plugin/api/dssi.h"
Chris@0 93
Chris@0 94 #include <QApplication>
Chris@0 95 #include <QMessageBox>
Chris@0 96 #include <QGridLayout>
Chris@0 97 #include <QLabel>
Chris@0 98 #include <QAction>
Chris@0 99 #include <QMenuBar>
Chris@0 100 #include <QToolBar>
Chris@0 101 #include <QInputDialog>
Chris@0 102 #include <QStatusBar>
Chris@0 103 #include <QTreeView>
Chris@0 104 #include <QFile>
Chris@88 105 #include <QFileInfo>
Chris@88 106 #include <QDir>
Chris@0 107 #include <QTextStream>
Chris@0 108 #include <QProcess>
Chris@7 109 #include <QShortcut>
Chris@5 110 #include <QSettings>
Chris@11 111 #include <QDateTime>
Chris@11 112 #include <QProcess>
Chris@16 113 #include <QCheckBox>
Chris@55 114 #include <QRegExp>
Chris@158 115 #include <QScrollArea>
Chris@425 116 #include <QDesktopServices>
Chris@426 117 #include <QFileSystemWatcher>
Chris@0 118
Chris@0 119 #include <iostream>
Chris@0 120 #include <cstdio>
Chris@0 121 #include <errno.h>
Chris@0 122
Chris@0 123 using std::cerr;
Chris@0 124 using std::endl;
Chris@0 125
Chris@33 126 using std::vector;
Chris@33 127 using std::map;
Chris@33 128 using std::set;
Chris@33 129
Chris@0 130
Chris@70 131 MainWindow::MainWindow(bool withAudioOutput, bool withOSCSupport) :
Chris@305 132 MainWindowBase(withAudioOutput, withOSCSupport, true),
Chris@65 133 m_overview(0),
Chris@0 134 m_mainMenusCreated(false),
Chris@0 135 m_paneMenu(0),
Chris@0 136 m_layerMenu(0),
Chris@34 137 m_transformsMenu(0),
Chris@155 138 m_playbackMenu(0),
Chris@0 139 m_existingLayersMenu(0),
Chris@95 140 m_sliceMenu(0),
Chris@34 141 m_recentFilesMenu(0),
Chris@211 142 m_recentTransformsMenu(0),
Chris@426 143 m_templatesMenu(0),
Chris@0 144 m_rightButtonMenu(0),
Chris@0 145 m_rightButtonLayerMenu(0),
Chris@211 146 m_rightButtonTransformsMenu(0),
Chris@155 147 m_rightButtonPlaybackMenu(0),
Chris@207 148 m_soloAction(0),
Chris@207 149 m_soloModified(false),
Chris@207 150 m_prevSolo(false),
Chris@265 151 m_rwdStartAction(0),
Chris@323 152 m_rwdSimilarAction(0),
Chris@265 153 m_rwdAction(0),
Chris@155 154 m_ffwdAction(0),
Chris@323 155 m_ffwdSimilarAction(0),
Chris@265 156 m_ffwdEndAction(0),
Chris@265 157 m_playAction(0),
Chris@265 158 m_playSelectionAction(0),
Chris@265 159 m_playLoopAction(0),
mathieu@458 160 m_alAction(0),
Chris@239 161 m_playControlsSpacer(0),
Chris@239 162 m_playControlsWidth(0),
Chris@162 163 m_preferencesDialog(0),
Chris@219 164 m_layerTreeDialog(0),
Chris@302 165 m_activityLog(new ActivityLog()),
mathieu@439 166 m_keyReference(new KeyReference()),
mathieu@466 167 m_templateWatcher(0),
mathieu@439 168 m_fileMenu(0),
mathieu@439 169 m_editMenu(0),
mathieu@439 170 m_viewMenu(0),
mathieu@439 171 m_helpMenu(0),
mathieu@439 172 m_importAnnotationLayerAction(0),
mathieu@439 173 m_exportAnnotationLayerAction(0),
mathieu@439 174 m_showNoOverlaysAction(0),
mathieu@439 175 m_showMinimalOverlaysAction(0),
mathieu@439 176 m_showStandardOverlaysAction(0),
mathieu@439 177 m_showAllOverlaysAction(0),
mathieu@439 178 m_showAllTimeRulersAction(0),
mathieu@439 179 m_showZoomWheelsAction(0),
mathieu@439 180 m_showPropertyBoxesAction(0),
mathieu@439 181 m_showStatusBarAction(0),
mathieu@439 182 m_fileToolBar(0),
mathieu@439 183 m_playbackToolBar(0),
mathieu@439 184 m_viewToolBar(0),
mathieu@439 185 m_playModeToolBar(0),
mathieu@439 186 m_editToolBar(0),
mathieu@439 187 m_toolsToolBar(0)
Chris@0 188 {
Chris@253 189 Profiler profiler("MainWindow::MainWindow");
Chris@253 190
mathieu@406 191 setWindowTitle(tr("Sonic Visualiser (Kiosk edition)"));
Chris@0 192
Chris@165 193 UnitDatabase *udb = UnitDatabase::getInstance();
Chris@165 194 udb->registerUnit("Hz");
Chris@165 195 udb->registerUnit("dB");
Chris@165 196 udb->registerUnit("s");
Chris@165 197
Chris@165 198 ColourDatabase *cdb = ColourDatabase::getInstance();
Chris@165 199 cdb->addColour(Qt::black, tr("Black"));
Chris@165 200 cdb->addColour(Qt::darkRed, tr("Red"));
Chris@165 201 cdb->addColour(Qt::darkBlue, tr("Blue"));
Chris@165 202 cdb->addColour(Qt::darkGreen, tr("Green"));
Chris@165 203 cdb->addColour(QColor(200, 50, 255), tr("Purple"));
Chris@165 204 cdb->addColour(QColor(255, 150, 50), tr("Orange"));
Chris@166 205 cdb->setUseDarkBackground(cdb->addColour(Qt::white, tr("White")), true);
Chris@166 206 cdb->setUseDarkBackground(cdb->addColour(Qt::red, tr("Bright Red")), true);
Chris@166 207 cdb->setUseDarkBackground(cdb->addColour(QColor(30, 150, 255), tr("Bright Blue")), true);
Chris@166 208 cdb->setUseDarkBackground(cdb->addColour(Qt::green, tr("Bright Green")), true);
Chris@166 209 cdb->setUseDarkBackground(cdb->addColour(QColor(225, 74, 255), tr("Bright Purple")), true);
Chris@166 210 cdb->setUseDarkBackground(cdb->addColour(QColor(255, 188, 80), tr("Bright Orange")), true);
Chris@0 211
Chris@0 212 QFrame *frame = new QFrame;
Chris@0 213 setCentralWidget(frame);
Chris@0 214
Chris@0 215 QGridLayout *layout = new QGridLayout;
Chris@180 216
Chris@205 217 m_descriptionLabel = new QLabel; //!!! hang on, this is declared in base class -- should be declared and initialised by same class
Chris@0 218
Chris@444 219 m_scroll = new QScrollArea(frame);
Chris@444 220 m_scroll->setWidgetResizable(true);
Chris@444 221 m_scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
Chris@444 222 m_scroll->setFrameShape(QFrame::NoFrame);
Chris@444 223 m_scroll->setWidget(m_paneStack);
Chris@159 224
Chris@65 225 m_overview = new Overview(frame);
Chris@65 226 m_overview->setViewManager(m_viewManager);
Chris@65 227 m_overview->setFixedHeight(40);
Chris@144 228 #ifndef _WIN32
Chris@144 229 // For some reason, the contents of the overview never appear if we
Chris@144 230 // make this setting on Windows. I have no inclination at the moment
Chris@144 231 // to track down the reason why.
Chris@129 232 m_overview->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
Chris@144 233 #endif
Chris@90 234 connect(m_overview, SIGNAL(contextHelpChanged(const QString &)),
Chris@116 235 this, SLOT(contextHelpChanged(const QString &)));
Chris@0 236
Chris@0 237 m_panLayer = new WaveformLayer;
Chris@0 238 m_panLayer->setChannelMode(WaveformLayer::MergeChannels);
Chris@0 239 m_panLayer->setAggressiveCacheing(true);
Chris@65 240 m_overview->addLayer(m_panLayer);
Chris@174 241
Chris@174 242 if (m_viewManager->getGlobalDarkBackground()) {
Chris@174 243 m_panLayer->setBaseColour
Chris@174 244 (ColourDatabase::getInstance()->getColourIndex(tr("Bright Green")));
Chris@174 245 } else {
Chris@174 246 m_panLayer->setBaseColour
Chris@174 247 (ColourDatabase::getInstance()->getColourIndex(tr("Green")));
Chris@200 248 }
Chris@0 249
Chris@0 250 m_fader = new Fader(frame, false);
Chris@90 251 connect(m_fader, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget()));
Chris@90 252 connect(m_fader, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget()));
Chris@0 253
Chris@0 254 m_playSpeed = new AudioDial(frame);
Chris@12 255 m_playSpeed->setMinimum(0);
Chris@48 256 m_playSpeed->setMaximum(200);
Chris@25 257 m_playSpeed->setValue(100);
Chris@261 258 m_playSpeed->setFixedWidth(32);
Chris@261 259 m_playSpeed->setFixedHeight(32);
Chris@0 260 m_playSpeed->setNotchesVisible(true);
Chris@25 261 m_playSpeed->setPageStep(10);
Chris@60 262 m_playSpeed->setObjectName(tr("Playback Speedup"));
Chris@25 263 m_playSpeed->setDefaultValue(100);
Chris@59 264 m_playSpeed->setRangeMapper(new PlaySpeedRangeMapper(0, 200));
Chris@60 265 m_playSpeed->setShowToolTip(true);
Chris@0 266 connect(m_playSpeed, SIGNAL(valueChanged(int)),
Chris@0 267 this, SLOT(playSpeedChanged(int)));
Chris@90 268 connect(m_playSpeed, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget()));
Chris@90 269 connect(m_playSpeed, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget()));
Chris@90 270
Chris@168 271 IconLoader il;
Chris@168 272
Chris@21 273 QSettings settings;
Chris@21 274 settings.beginGroup("MainWindow");
Chris@21 275 settings.endGroup();
Chris@21 276
Chris@239 277 m_playControlsSpacer = new QFrame;
Chris@239 278
Chris@129 279 layout->setSpacing(4);
Chris@444 280 layout->addWidget(m_scroll, 0, 0, 1, 5);
Chris@239 281 layout->addWidget(m_overview, 1, 1);
Chris@239 282 layout->addWidget(m_playControlsSpacer, 1, 2);
Chris@239 283 layout->addWidget(m_playSpeed, 1, 3);
Chris@239 284 layout->addWidget(m_fader, 1, 4);
Chris@239 285
Chris@239 286 m_playControlsWidth =
Chris@240 287 m_fader->width() + m_playSpeed->width() + layout->spacing() * 2;
Chris@239 288
Chris@239 289 layout->setColumnMinimumWidth(0, 14);
Chris@239 290 layout->setColumnStretch(0, 0);
Chris@239 291
Chris@239 292 m_paneStack->setPropertyStackMinWidth(m_playControlsWidth
Chris@239 293 + 2 + layout->spacing());
Chris@239 294 m_playControlsSpacer->setFixedSize(QSize(2, 2));
Chris@239 295
Chris@239 296 layout->setColumnStretch(1, 10);
Chris@239 297
Chris@239 298 connect(m_paneStack, SIGNAL(propertyStacksResized(int)),
Chris@239 299 this, SLOT(propertyStacksResized(int)));
Chris@16 300
Chris@0 301 frame->setLayout(layout);
Chris@0 302
Chris@0 303 setupMenus();
Chris@0 304 setupToolbars();
Chris@155 305 setupHelpMenu();
Chris@0 306
Chris@90 307 statusBar();
Chris@340 308 m_currentLabel = new QLabel;
Chris@340 309 statusBar()->addPermanentWidget(m_currentLabel);
Chris@0 310
Chris@302 311 connect(m_viewManager, SIGNAL(activity(QString)),
Chris@302 312 m_activityLog, SLOT(activityHappened(QString)));
Chris@302 313 connect(m_playSource, SIGNAL(activity(QString)),
Chris@302 314 m_activityLog, SLOT(activityHappened(QString)));
Chris@302 315 connect(CommandHistory::getInstance(), SIGNAL(activity(QString)),
Chris@302 316 m_activityLog, SLOT(activityHappened(QString)));
Chris@310 317 connect(this, SIGNAL(activity(QString)),
Chris@310 318 m_activityLog, SLOT(activityHappened(QString)));
Chris@303 319 connect(this, SIGNAL(replacedDocument()), this, SLOT(documentReplaced()));
Chris@306 320 m_activityLog->hide();
Chris@303 321
Chris@303 322 newSession();
Chris@303 323
Chris@304 324 connect(m_midiInput, SIGNAL(eventsAvailable()),
Chris@304 325 this, SLOT(midiEventsAvailable()));
Chris@281 326
Chris@283 327 TransformFactory::getInstance()->startPopulationThread();
Chris@334 328
Chris@334 329 Surveyer *surveyer = new Surveyer(this);
Chris@334 330 VersionTester *vt = new VersionTester
Chris@334 331 ("sonicvisualiser.org", "/latest-version.txt", SV_VERSION);
Chris@334 332 connect(vt, SIGNAL(newerVersionAvailable(QString)),
Chris@334 333 this, SLOT(newerVersionAvailable(QString)));
Chris@0 334 }
Chris@0 335
Chris@0 336 MainWindow::~MainWindow()
Chris@0 337 {
Chris@438 338 // SVDEBUG << "MainWindow::~MainWindow" << endl;
Chris@162 339 delete m_keyReference;
Chris@163 340 delete m_preferencesDialog;
Chris@219 341 delete m_layerTreeDialog;
Chris@0 342 Profiles::getInstance()->dump();
Chris@438 343 // SVDEBUG << "MainWindow::~MainWindow finishing" << endl;
Chris@0 344 }
Chris@0 345
Chris@81 346 void
Chris@0 347 MainWindow::setupMenus()
Chris@0 348 {
Chris@0 349 if (!m_mainMenusCreated) {
Chris@0 350 m_rightButtonMenu = new QMenu();
Chris@104 351
Chris@104 352 // No -- we don't want tear-off enabled on the right-button
Chris@104 353 // menu. If it is enabled, then simply right-clicking and
Chris@104 354 // releasing will pop up the menu, activate the tear-off, and
Chris@104 355 // leave the torn-off menu window in front of the main window.
Chris@104 356 // That isn't desirable. I'm not sure it ever would be, in a
Chris@104 357 // context menu -- perhaps technically a Qt bug?
Chris@104 358 // m_rightButtonMenu->setTearOffEnabled(true);
Chris@0 359 }
Chris@0 360
Chris@211 361 if (m_rightButtonTransformsMenu) {
Chris@211 362 m_rightButtonTransformsMenu->clear();
Chris@34 363 } else {
Chris@211 364 m_rightButtonTransformsMenu = m_rightButtonMenu->addMenu(tr("&Transform"));
Chris@211 365 m_rightButtonTransformsMenu->setTearOffEnabled(true);
Chris@34 366 m_rightButtonMenu->addSeparator();
Chris@34 367 }
Chris@34 368
Chris@346 369 // This will be created (if not found) or cleared (if found) in
Chris@346 370 // setupPaneAndLayerMenus, but we want to ensure it's created
Chris@346 371 // sooner so it can go nearer the top of the right button menu
Chris@346 372 if (m_rightButtonLayerMenu) {
Chris@346 373 m_rightButtonLayerMenu->clear();
Chris@346 374 } else {
Chris@346 375 m_rightButtonLayerMenu = m_rightButtonMenu->addMenu(tr("&Layer"));
Chris@346 376 m_rightButtonLayerMenu->setTearOffEnabled(true);
Chris@346 377 m_rightButtonMenu->addSeparator();
Chris@346 378 }
Chris@346 379
Chris@0 380 if (!m_mainMenusCreated) {
Chris@0 381 CommandHistory::getInstance()->registerMenu(m_rightButtonMenu);
Chris@0 382 m_rightButtonMenu->addSeparator();
Chris@66 383 }
Chris@66 384
Chris@66 385 setupFileMenu();
Chris@66 386 setupEditMenu();
Chris@66 387 setupViewMenu();
Chris@66 388 setupPaneAndLayerMenus();
Chris@211 389 setupTransformsMenu();
Chris@66 390
Chris@66 391 m_mainMenusCreated = true;
Chris@66 392 }
Chris@66 393
Chris@66 394 void
Chris@66 395 MainWindow::setupFileMenu()
Chris@66 396 {
Chris@66 397 if (m_mainMenusCreated) return;
Chris@66 398
mathieu@439 399 m_fileMenu = menuBar()->addMenu(tr("&File"));
mathieu@439 400 m_fileMenu->setTearOffEnabled(true);
mathieu@439 401 m_fileToolBar = addToolBar(tr("File Toolbar"));
Chris@66 402
Chris@162 403 m_keyReference->setCategory(tr("File and Session Management"));
Chris@162 404
Chris@168 405 IconLoader il;
Chris@168 406
Chris@168 407 QIcon icon = il.load("filenew");
Chris@168 408 icon.addPixmap(il.loadPixmap("filenew-22"));
Chris@66 409 QAction *action = new QAction(icon, tr("&New Session"), this);
Chris@66 410 action->setShortcut(tr("Ctrl+N"));
Chris@90 411 action->setStatusTip(tr("Abandon the current Sonic Visualiser session and start a new one"));
Chris@66 412 connect(action, SIGNAL(triggered()), this, SLOT(newSession()));
Chris@162 413 m_keyReference->registerShortcut(action);
mathieu@439 414 m_fileMenu->addAction(action);
mathieu@439 415 m_fileToolBar->addAction(action);
Chris@418 416 /*
Chris@168 417 icon = il.load("fileopensession");
Chris@66 418 action = new QAction(icon, tr("&Open Session..."), this);
Chris@66 419 action->setShortcut(tr("Ctrl+O"));
Chris@66 420 action->setStatusTip(tr("Open a previously saved Sonic Visualiser session file"));
Chris@66 421 connect(action, SIGNAL(triggered()), this, SLOT(openSession()));
Chris@162 422 m_keyReference->registerShortcut(action);
mathieu@439 423 m_fileMenu->addAction(action);
Chris@418 424 */
Chris@168 425 icon = il.load("fileopen");
Chris@168 426 icon.addPixmap(il.loadPixmap("fileopen-22"));
Chris@66 427 action = new QAction(icon, tr("&Open..."), this);
Chris@418 428 action->setShortcut(tr("Ctrl+O"));
Chris@66 429 action->setStatusTip(tr("Open a session file, audio file, or layer"));
Chris@66 430 connect(action, SIGNAL(triggered()), this, SLOT(openSomething()));
mathieu@439 431 m_fileToolBar->addAction(action);
mathieu@466 432 m_fileMenu->addAction(action);
Chris@418 433
Chris@418 434 // We want this one to go on the toolbar now, if we add it at all,
Chris@418 435 // but on the menu later
Chris@418 436 QAction *iaction = new QAction(tr("&Import More Audio..."), this);
Chris@418 437 iaction->setShortcut(tr("Ctrl+I"));
Chris@418 438 iaction->setStatusTip(tr("Import an extra audio file into a new pane"));
Chris@418 439 connect(iaction, SIGNAL(triggered()), this, SLOT(importMoreAudio()));
Chris@418 440 connect(this, SIGNAL(canImportMoreAudio(bool)), iaction, SLOT(setEnabled(bool)));
Chris@418 441 m_keyReference->registerShortcut(iaction);
Chris@418 442
Chris@418 443 action = new QAction(tr("Open Lo&cation..."), this);
Chris@418 444 action->setShortcut(tr("Ctrl+Shift+O"));
Chris@418 445 action->setStatusTip(tr("Open or import a file from a remote URL"));
Chris@418 446 connect(action, SIGNAL(triggered()), this, SLOT(openLocation()));
Chris@418 447 m_keyReference->registerShortcut(action);
mathieu@466 448 m_fileMenu->addAction(action);
Chris@418 449
mathieu@467 450 m_recentFilesMenu = m_fileMenu->addMenu(tr("Open &Recent"));
Chris@418 451 m_recentFilesMenu->setTearOffEnabled(true);
Chris@418 452 setupRecentFilesMenu();
Chris@418 453 connect(&m_recentFiles, SIGNAL(recentChanged()),
Chris@418 454 this, SLOT(setupRecentFilesMenu()));
Chris@418 455
mathieu@466 456 m_fileMenu->addSeparator();
Chris@66 457
Chris@168 458 icon = il.load("filesave");
Chris@168 459 icon.addPixmap(il.loadPixmap("filesave-22"));
Chris@66 460 action = new QAction(icon, tr("&Save Session"), this);
Chris@66 461 action->setShortcut(tr("Ctrl+S"));
Chris@66 462 action->setStatusTip(tr("Save the current session into a Sonic Visualiser session file"));
Chris@66 463 connect(action, SIGNAL(triggered()), this, SLOT(saveSession()));
Chris@66 464 connect(this, SIGNAL(canSave(bool)), action, SLOT(setEnabled(bool)));
Chris@162 465 m_keyReference->registerShortcut(action);
mathieu@439 466 m_fileMenu->addAction(action);
mathieu@439 467 m_fileToolBar->addAction(action);
Chris@0 468
Chris@168 469 icon = il.load("filesaveas");
Chris@168 470 icon.addPixmap(il.loadPixmap("filesaveas-22"));
Chris@66 471 action = new QAction(icon, tr("Save Session &As..."), this);
Chris@336 472 action->setShortcut(tr("Ctrl+Shift+S"));
Chris@66 473 action->setStatusTip(tr("Save the current session into a new Sonic Visualiser session file"));
Chris@66 474 connect(action, SIGNAL(triggered()), this, SLOT(saveSessionAs()));
mathieu@439 475 m_fileMenu->addAction(action);
mathieu@439 476 m_fileToolBar->addAction(action);
mathieu@439 477
mathieu@439 478 m_fileMenu->addSeparator();
Chris@66 479
Chris@418 480 /*
Chris@168 481 icon = il.load("fileopenaudio");
Chris@138 482 action = new QAction(icon, tr("&Import Audio File..."), this);
Chris@66 483 action->setShortcut(tr("Ctrl+I"));
Chris@66 484 action->setStatusTip(tr("Import an existing audio file"));
Chris@66 485 connect(action, SIGNAL(triggered()), this, SLOT(importAudio()));
Chris@162 486 m_keyReference->registerShortcut(action);
mathieu@439 487 m_fileMenu->addAction(action);
Chris@418 488 */
Chris@418 489
Chris@418 490 // the Import action we made earlier
mathieu@466 491 m_fileMenu->addAction(iaction);
Chris@387 492
mathieu@406 493 /* //removes the Export Audio File functionnality from the File menu
Chris@66 494 action = new QAction(tr("&Export Audio File..."), this);
Chris@66 495 action->setStatusTip(tr("Export selection as an audio file"));
Chris@66 496 connect(action, SIGNAL(triggered()), this, SLOT(exportAudio()));
Chris@66 497 connect(this, SIGNAL(canExportAudio(bool)), action, SLOT(setEnabled(bool)));
mathieu@439 498 m_fileMenu->addAction(action);
mathieu@439 499
mathieu@439 500 m_fileMenu->addSeparator();
mathieu@406 501 */
mathieu@439 502
mathieu@439 503 m_importAnnotationLayerAction = new QAction(tr("Import Annotation &Layer..."), this);
mathieu@439 504 m_importAnnotationLayerAction->setShortcut(tr("Ctrl+L"));
mathieu@439 505 m_importAnnotationLayerAction->setStatusTip(tr("Import layer data from an existing file"));
mathieu@439 506 connect(m_importAnnotationLayerAction, SIGNAL(triggered()), this, SLOT(importLayer()));
Chris@66 507 connect(this, SIGNAL(canImportLayer(bool)), action, SLOT(setEnabled(bool)));
mathieu@439 508 m_keyReference->registerShortcut(m_importAnnotationLayerAction);
mathieu@439 509 m_fileMenu->addAction(m_importAnnotationLayerAction);
mathieu@439 510
mathieu@439 511 m_exportAnnotationLayerAction = new QAction(tr("Export Annotation Layer..."), this);
mathieu@439 512 m_exportAnnotationLayerAction->setStatusTip(tr("Export layer data to a file"));
mathieu@439 513 connect(m_exportAnnotationLayerAction, SIGNAL(triggered()), this, SLOT(exportLayer()));
Chris@66 514 connect(this, SIGNAL(canExportLayer(bool)), action, SLOT(setEnabled(bool)));
mathieu@439 515 m_fileMenu->addAction(m_exportAnnotationLayerAction);
mathieu@439 516
mathieu@439 517 m_fileMenu->addSeparator();
Chris@86 518
Chris@121 519 action = new QAction(tr("Export Image File..."), this);
Chris@121 520 action->setStatusTip(tr("Export a single pane to an image file"));
Chris@121 521 connect(action, SIGNAL(triggered()), this, SLOT(exportImage()));
Chris@121 522 connect(this, SIGNAL(canExportImage(bool)), action, SLOT(setEnabled(bool)));
mathieu@439 523 m_fileMenu->addAction(action);
mathieu@439 524
mathieu@439 525 m_fileMenu->addSeparator();
Chris@121 526
Chris@435 527 QString templatesMenuLabel = tr("Apply Session Template");
mathieu@466 528 m_templatesMenu = m_fileMenu->addMenu(templatesMenuLabel);
Chris@425 529 m_templatesMenu->setTearOffEnabled(true);
Chris@436 530 // We need to have a main model for this option to be useful:
Chris@436 531 // canExportAudio captures that
Chris@436 532 connect(this, SIGNAL(canExportAudio(bool)), m_templatesMenu, SLOT(setEnabled(bool)));
Chris@436 533
Chris@436 534 // Set up the menu in a moment, after m_manageTemplatesAction constructed
Chris@435 535
Chris@435 536 action = new QAction(tr("Export Session as Template..."), this);
Chris@435 537 connect(action, SIGNAL(triggered()), this, SLOT(saveSessionAsTemplate()));
Chris@436 538 // We need to have something in the session for this to be useful:
Chris@436 539 // canDeleteCurrentLayer captures that
Chris@436 540 connect(this, SIGNAL(canExportAudio(bool)), action, SLOT(setEnabled(bool)));
mathieu@439 541 m_fileMenu->addAction(action);
mathieu@439 542
Chris@436 543 m_manageTemplatesAction = new QAction(tr("Manage Exported Templates"), this);
Chris@436 544 connect(m_manageTemplatesAction, SIGNAL(triggered()), this, SLOT(manageSavedTemplates()));
mathieu@466 545 m_fileMenu->addAction(m_manageTemplatesAction);
Chris@436 546
Chris@436 547 setupTemplatesMenu();
Chris@425 548
Chris@66 549 action = new QAction(tr("&Preferences..."), this);
Chris@66 550 action->setStatusTip(tr("Adjust the application preferences"));
Chris@66 551 connect(action, SIGNAL(triggered()), this, SLOT(preferences()));
mathieu@439 552 m_fileMenu->addAction(action);
Chris@0 553
mathieu@439 554 m_fileMenu->addSeparator();
Chris@168 555 action = new QAction(il.load("exit"),
Chris@66 556 tr("&Quit"), this);
Chris@66 557 action->setShortcut(tr("Ctrl+Q"));
Chris@90 558 action->setStatusTip(tr("Exit Sonic Visualiser"));
Chris@66 559 connect(action, SIGNAL(triggered()), this, SLOT(close()));
Chris@162 560 m_keyReference->registerShortcut(action);
mathieu@439 561 m_fileMenu->addAction(action);
Chris@66 562 }
Chris@66 563
Chris@66 564 void
Chris@66 565 MainWindow::setupEditMenu()
Chris@66 566 {
Chris@66 567 if (m_mainMenusCreated) return;
Chris@66 568
mathieu@439 569 m_editMenu = menuBar()->addMenu(tr("&Edit"));
mathieu@439 570 m_editMenu->setTearOffEnabled(true);
mathieu@439 571 CommandHistory::getInstance()->registerMenu(m_editMenu);
Chris@66 572
Chris@162 573 m_keyReference->setCategory(tr("Editing"));
Chris@162 574
mathieu@439 575 m_editMenu->addSeparator();
Chris@66 576
Chris@168 577 IconLoader il;
Chris@168 578
Chris@168 579 QAction *action = new QAction(il.load("editcut"),
Chris@66 580 tr("Cu&t"), this);
Chris@66 581 action->setShortcut(tr("Ctrl+X"));
Chris@90 582 action->setStatusTip(tr("Cut the selection from the current layer to the clipboard"));
Chris@66 583 connect(action, SIGNAL(triggered()), this, SLOT(cut()));
Chris@66 584 connect(this, SIGNAL(canEditSelection(bool)), action, SLOT(setEnabled(bool)));
Chris@162 585 m_keyReference->registerShortcut(action);
mathieu@439 586 m_editMenu->addAction(action);
Chris@66 587 m_rightButtonMenu->addAction(action);
Chris@66 588
Chris@168 589 action = new QAction(il.load("editcopy"),
Chris@66 590 tr("&Copy"), this);
Chris@66 591 action->setShortcut(tr("Ctrl+C"));
Chris@90 592 action->setStatusTip(tr("Copy the selection from the current layer to the clipboard"));
Chris@66 593 connect(action, SIGNAL(triggered()), this, SLOT(copy()));
Chris@66 594 connect(this, SIGNAL(canEditSelection(bool)), action, SLOT(setEnabled(bool)));
Chris@162 595 m_keyReference->registerShortcut(action);
mathieu@439 596 m_editMenu->addAction(action);
Chris@66 597 m_rightButtonMenu->addAction(action);
Chris@66 598
Chris@168 599 action = new QAction(il.load("editpaste"),
Chris@66 600 tr("&Paste"), this);
Chris@66 601 action->setShortcut(tr("Ctrl+V"));
Chris@90 602 action->setStatusTip(tr("Paste from the clipboard to the current layer"));
Chris@66 603 connect(action, SIGNAL(triggered()), this, SLOT(paste()));
Chris@66 604 connect(this, SIGNAL(canPaste(bool)), action, SLOT(setEnabled(bool)));
Chris@162 605 m_keyReference->registerShortcut(action);
mathieu@439 606 m_editMenu->addAction(action);
Chris@66 607 m_rightButtonMenu->addAction(action);
Chris@66 608
Chris@395 609 action = new QAction(tr("Paste at Playback Position"), this);
Chris@395 610 action->setShortcut(tr("Ctrl+Shift+V"));
Chris@395 611 action->setStatusTip(tr("Paste from the clipboard to the current layer, placing the first item at the playback position"));
Chris@395 612 connect(action, SIGNAL(triggered()), this, SLOT(pasteAtPlaybackPosition()));
Chris@395 613 connect(this, SIGNAL(canPaste(bool)), action, SLOT(setEnabled(bool)));
Chris@395 614 m_keyReference->registerShortcut(action);
mathieu@439 615 m_editMenu->addAction(action);
Chris@395 616 m_rightButtonMenu->addAction(action);
Chris@395 617
Chris@164 618 m_deleteSelectedAction = new QAction(tr("&Delete Selected Items"), this);
Chris@164 619 m_deleteSelectedAction->setShortcut(tr("Del"));
Chris@164 620 m_deleteSelectedAction->setStatusTip(tr("Delete items in current selection from the current layer"));
Chris@164 621 connect(m_deleteSelectedAction, SIGNAL(triggered()), this, SLOT(deleteSelected()));
Chris@164 622 connect(this, SIGNAL(canDeleteSelection(bool)), m_deleteSelectedAction, SLOT(setEnabled(bool)));
Chris@164 623 m_keyReference->registerShortcut(m_deleteSelectedAction);
mathieu@439 624 m_editMenu->addAction(m_deleteSelectedAction);
Chris@164 625 m_rightButtonMenu->addAction(m_deleteSelectedAction);
Chris@66 626
mathieu@439 627 m_editMenu->addSeparator();
Chris@66 628 m_rightButtonMenu->addSeparator();
Chris@162 629
Chris@162 630 m_keyReference->setCategory(tr("Selection"));
Chris@162 631
Chris@66 632 action = new QAction(tr("Select &All"), this);
Chris@66 633 action->setShortcut(tr("Ctrl+A"));
Chris@90 634 action->setStatusTip(tr("Select the whole duration of the current session"));
Chris@66 635 connect(action, SIGNAL(triggered()), this, SLOT(selectAll()));
Chris@66 636 connect(this, SIGNAL(canSelect(bool)), action, SLOT(setEnabled(bool)));
Chris@162 637 m_keyReference->registerShortcut(action);
mathieu@439 638 m_editMenu->addAction(action);
Chris@66 639 m_rightButtonMenu->addAction(action);
Chris@0 640
Chris@66 641 action = new QAction(tr("Select &Visible Range"), this);
Chris@66 642 action->setShortcut(tr("Ctrl+Shift+A"));
Chris@90 643 action->setStatusTip(tr("Select the time range corresponding to the current window width"));
Chris@66 644 connect(action, SIGNAL(triggered()), this, SLOT(selectVisible()));
Chris@66 645 connect(this, SIGNAL(canSelect(bool)), action, SLOT(setEnabled(bool)));
Chris@162 646 m_keyReference->registerShortcut(action);
mathieu@439 647 m_editMenu->addAction(action);
Chris@0 648
Chris@66 649 action = new QAction(tr("Select to &Start"), this);
Chris@66 650 action->setShortcut(tr("Shift+Left"));
Chris@90 651 action->setStatusTip(tr("Select from the start of the session to the current playback position"));
Chris@66 652 connect(action, SIGNAL(triggered()), this, SLOT(selectToStart()));
Chris@66 653 connect(this, SIGNAL(canSelect(bool)), action, SLOT(setEnabled(bool)));
Chris@162 654 m_keyReference->registerShortcut(action);
mathieu@439 655 m_editMenu->addAction(action);
Chris@0 656
Chris@66 657 action = new QAction(tr("Select to &End"), this);
Chris@66 658 action->setShortcut(tr("Shift+Right"));
Chris@90 659 action->setStatusTip(tr("Select from the current playback position to the end of the session"));
Chris@66 660 connect(action, SIGNAL(triggered()), this, SLOT(selectToEnd()));
Chris@66 661 connect(this, SIGNAL(canSelect(bool)), action, SLOT(setEnabled(bool)));
Chris@162 662 m_keyReference->registerShortcut(action);
mathieu@439 663 m_editMenu->addAction(action);
Chris@66 664
Chris@66 665 action = new QAction(tr("C&lear Selection"), this);
Chris@66 666 action->setShortcut(tr("Esc"));
Chris@90 667 action->setStatusTip(tr("Clear the selection"));
Chris@66 668 connect(action, SIGNAL(triggered()), this, SLOT(clearSelection()));
Chris@66 669 connect(this, SIGNAL(canClearSelection(bool)), action, SLOT(setEnabled(bool)));
Chris@162 670 m_keyReference->registerShortcut(action);
mathieu@439 671 m_editMenu->addAction(action);
Chris@66 672 m_rightButtonMenu->addAction(action);
Chris@66 673
mathieu@439 674 m_editMenu->addSeparator();
Chris@66 675
Chris@162 676 m_keyReference->setCategory(tr("Tapping Time Instants"));
Chris@162 677
Chris@66 678 action = new QAction(tr("&Insert Instant at Playback Position"), this);
Chris@66 679 action->setShortcut(tr("Enter"));
Chris@90 680 action->setStatusTip(tr("Insert a new time instant at the current playback position, in a new layer if necessary"));
Chris@66 681 connect(action, SIGNAL(triggered()), this, SLOT(insertInstant()));
Chris@66 682 connect(this, SIGNAL(canInsertInstant(bool)), action, SLOT(setEnabled(bool)));
Chris@162 683 m_keyReference->registerShortcut(action);
mathieu@439 684 m_editMenu->addAction(action);
Chris@66 685
Chris@162 686 // Laptop shortcut (no keypad Enter key)
Chris@162 687 QString shortcut(tr(";"));
Chris@162 688 connect(new QShortcut(shortcut, this), SIGNAL(activated()),
Chris@162 689 this, SLOT(insertInstant()));
Chris@162 690 m_keyReference->registerAlternativeShortcut(action, shortcut);
Chris@162 691
Chris@81 692 action = new QAction(tr("Insert Instants at Selection &Boundaries"), this);
Chris@81 693 action->setShortcut(tr("Shift+Enter"));
Chris@163 694 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 695 connect(action, SIGNAL(triggered()), this, SLOT(insertInstantsAtBoundaries()));
Chris@81 696 connect(this, SIGNAL(canInsertInstantsAtBoundaries(bool)), action, SLOT(setEnabled(bool)));
Chris@162 697 m_keyReference->registerShortcut(action);
mathieu@439 698 m_editMenu->addAction(action);
Chris@189 699
Chris@338 700 action = new QAction(tr("Insert Item at Selection"), this);
Chris@338 701 action->setShortcut(tr("Ctrl+Shift+Enter"));
Chris@338 702 action->setStatusTip(tr("Insert a new note or region item corresponding to the current selection"));
Chris@338 703 connect(action, SIGNAL(triggered()), this, SLOT(insertItemAtSelection()));
Chris@338 704 connect(this, SIGNAL(canInsertItemAtSelection(bool)), action, SLOT(setEnabled(bool)));
Chris@338 705 m_keyReference->registerShortcut(action);
mathieu@439 706 m_editMenu->addAction(action);
mathieu@439 707
mathieu@439 708 m_editMenu->addSeparator();
mathieu@439 709
mathieu@439 710 QMenu *numberingMenu = m_editMenu->addMenu(tr("Number New Instants with"));
Chris@225 711 numberingMenu->setTearOffEnabled(true);
Chris@189 712 QActionGroup *numberingGroup = new QActionGroup(this);
Chris@189 713
Chris@189 714 Labeller::TypeNameMap types = m_labeller->getTypeNames();
Chris@189 715 for (Labeller::TypeNameMap::iterator i = types.begin(); i != types.end(); ++i) {
Chris@190 716
Chris@190 717 if (i->first == Labeller::ValueFromLabel ||
Chris@190 718 i->first == Labeller::ValueFromExistingNeighbour) continue;
Chris@190 719
Chris@189 720 action = new QAction(i->second, this);
Chris@189 721 connect(action, SIGNAL(triggered()), this, SLOT(setInstantsNumbering()));
Chris@189 722 action->setCheckable(true);
Chris@189 723 action->setChecked(m_labeller->getType() == i->first);
Chris@189 724 numberingGroup->addAction(action);
Chris@189 725 numberingMenu->addAction(action);
Chris@189 726 m_numberingActions[action] = (int)i->first;
Chris@190 727
Chris@190 728 if (i->first == Labeller::ValueFromTwoLevelCounter) {
Chris@192 729
Chris@190 730 QMenu *cycleMenu = numberingMenu->addMenu(tr("Cycle size"));
Chris@190 731 QActionGroup *cycleGroup = new QActionGroup(this);
Chris@190 732
Chris@229 733 int cycles[] = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 16 };
Chris@200 734 for (int i = 0; i < int(sizeof(cycles)/sizeof(cycles[0])); ++i) {
Chris@190 735 action = new QAction(QString("%1").arg(cycles[i]), this);
Chris@190 736 connect(action, SIGNAL(triggered()), this, SLOT(setInstantsCounterCycle()));
Chris@190 737 action->setCheckable(true);
Chris@190 738 action->setChecked(cycles[i] == m_labeller->getCounterCycleSize());
Chris@190 739 cycleGroup->addAction(action);
Chris@190 740 cycleMenu->addAction(action);
Chris@190 741 }
Chris@190 742 }
Chris@190 743
Chris@190 744 if (i->first == Labeller::ValueNone ||
Chris@190 745 i->first == Labeller::ValueFromTwoLevelCounter ||
Chris@190 746 i->first == Labeller::ValueFromRealTime) {
Chris@190 747 numberingMenu->addSeparator();
Chris@190 748 }
Chris@189 749 }
Chris@189 750
Chris@241 751 action = new QAction(tr("Set Numbering Counters..."), this);
Chris@241 752 action->setStatusTip(tr("Set the counters used for counter-based labelling"));
Chris@241 753 connect(action, SIGNAL(triggered()), this, SLOT(resetInstantsCounters()));
mathieu@439 754 m_editMenu->addAction(action);
Chris@241 755
Chris@241 756 action = new QAction(tr("Renumber Selected Instants"), this);
Chris@241 757 action->setStatusTip(tr("Renumber the selected instants using the current labelling scheme"));
Chris@189 758 connect(action, SIGNAL(triggered()), this, SLOT(renumberInstants()));
Chris@189 759 connect(this, SIGNAL(canRenumberInstants(bool)), action, SLOT(setEnabled(bool)));
Chris@189 760 // m_keyReference->registerShortcut(action);
mathieu@439 761 m_editMenu->addAction(action);
Chris@66 762 }
Chris@66 763
Chris@66 764 void
Chris@66 765 MainWindow::setupViewMenu()
Chris@66 766 {
Chris@66 767 if (m_mainMenusCreated) return;
Chris@66 768
Chris@168 769 IconLoader il;
Chris@168 770
Chris@90 771 QAction *action = 0;
Chris@90 772
mathieu@439 773 m_viewMenu = menuBar()->addMenu(tr("&View"));
mathieu@439 774 m_viewMenu->setTearOffEnabled(true);
mathieu@439 775
mathieu@439 776 m_viewToolBar = addToolBar(tr("View Toolbar"));
mathieu@439 777
Chris@462 778 m_keyReference->setCategory(tr("Display Features"));
mathieu@439 779
mathieu@439 780 QIcon icon = il.load("toggle16");
mathieu@439 781 icon.addPixmap(il.loadPixmap("toggle22"));
mathieu@439 782 action = new QAction(icon,tr("Minimal Mode"), this);
mathieu@439 783 action->setShortcut(tr("C"));
Chris@462 784 action->setStatusTip(tr("Switch between minimal and full view modes"));
mathieu@439 785 connect(action, SIGNAL(triggered()), this, SLOT(toggleViewMode()));
mathieu@439 786 action->setCheckable(true);
mathieu@459 787
mathieu@459 788 QSettings settings;
mathieu@459 789 settings.beginGroup("Preferences");
mathieu@459 790 bool mini = settings.value("start-in-mini-mode",true).toBool();
mathieu@459 791 action->setChecked(mini);
mathieu@459 792 settings.endGroup();
mathieu@459 793
mathieu@439 794 m_keyReference->registerShortcut(action);
mathieu@439 795 m_viewMenu->addAction(action);
mathieu@439 796 m_viewToolBar->addAction(action);
mathieu@439 797
mathieu@439 798 m_viewMenu->addSeparator();
mathieu@439 799
Chris@162 800 m_keyReference->setCategory(tr("Panning and Navigation"));
Chris@162 801
Chris@66 802 action = new QAction(tr("Scroll &Left"), this);
Chris@66 803 action->setShortcut(tr("Left"));
Chris@66 804 action->setStatusTip(tr("Scroll the current pane to the left"));
Chris@66 805 connect(action, SIGNAL(triggered()), this, SLOT(scrollLeft()));
Chris@66 806 connect(this, SIGNAL(canScroll(bool)), action, SLOT(setEnabled(bool)));
Chris@162 807 m_keyReference->registerShortcut(action);
mathieu@439 808 m_viewMenu->addAction(action);
Chris@0 809
Chris@66 810 action = new QAction(tr("Scroll &Right"), this);
Chris@66 811 action->setShortcut(tr("Right"));
Chris@66 812 action->setStatusTip(tr("Scroll the current pane to the right"));
Chris@66 813 connect(action, SIGNAL(triggered()), this, SLOT(scrollRight()));
Chris@66 814 connect(this, SIGNAL(canScroll(bool)), action, SLOT(setEnabled(bool)));
Chris@162 815 m_keyReference->registerShortcut(action);
mathieu@439 816 m_viewMenu->addAction(action);
Chris@0 817
Chris@90 818 action = new QAction(tr("&Jump Left"), this);
Chris@66 819 action->setShortcut(tr("Ctrl+Left"));
Chris@66 820 action->setStatusTip(tr("Scroll the current pane a big step to the left"));
Chris@66 821 connect(action, SIGNAL(triggered()), this, SLOT(jumpLeft()));
Chris@66 822 connect(this, SIGNAL(canScroll(bool)), action, SLOT(setEnabled(bool)));
Chris@162 823 m_keyReference->registerShortcut(action);
mathieu@439 824 m_viewMenu->addAction(action);
Chris@0 825
Chris@90 826 action = new QAction(tr("J&ump Right"), this);
Chris@66 827 action->setShortcut(tr("Ctrl+Right"));
Chris@66 828 action->setStatusTip(tr("Scroll the current pane a big step to the right"));
Chris@66 829 connect(action, SIGNAL(triggered()), this, SLOT(jumpRight()));
Chris@66 830 connect(this, SIGNAL(canScroll(bool)), action, SLOT(setEnabled(bool)));
Chris@162 831 m_keyReference->registerShortcut(action);
mathieu@439 832 m_viewMenu->addAction(action);
Chris@66 833
Chris@308 834 action = new QAction(tr("Peek Left"), this);
Chris@308 835 action->setShortcut(tr("Alt+Left"));
Chris@308 836 action->setStatusTip(tr("Scroll the current pane to the left without moving the playback cursor or other panes"));
Chris@308 837 connect(action, SIGNAL(triggered()), this, SLOT(peekLeft()));
Chris@308 838 connect(this, SIGNAL(canScroll(bool)), action, SLOT(setEnabled(bool)));
Chris@308 839 m_keyReference->registerShortcut(action);
mathieu@439 840 m_viewMenu->addAction(action);
Chris@308 841
Chris@308 842 action = new QAction(tr("Peek Right"), this);
Chris@308 843 action->setShortcut(tr("Alt+Right"));
Chris@308 844 action->setStatusTip(tr("Scroll the current pane to the right without moving the playback cursor or other panes"));
Chris@308 845 connect(action, SIGNAL(triggered()), this, SLOT(peekRight()));
Chris@308 846 connect(this, SIGNAL(canScroll(bool)), action, SLOT(setEnabled(bool)));
Chris@308 847 m_keyReference->registerShortcut(action);
mathieu@439 848 m_viewMenu->addAction(action);
mathieu@439 849
mathieu@439 850 m_viewMenu->addSeparator();
Chris@66 851
Chris@162 852 m_keyReference->setCategory(tr("Zoom"));
Chris@162 853
Chris@168 854 action = new QAction(il.load("zoom-in"),
Chris@66 855 tr("Zoom &In"), this);
Chris@66 856 action->setShortcut(tr("Up"));
Chris@66 857 action->setStatusTip(tr("Increase the zoom level"));
Chris@66 858 connect(action, SIGNAL(triggered()), this, SLOT(zoomIn()));
Chris@66 859 connect(this, SIGNAL(canZoom(bool)), action, SLOT(setEnabled(bool)));
Chris@162 860 m_keyReference->registerShortcut(action);
mathieu@439 861 m_viewMenu->addAction(action);
Chris@0 862
Chris@168 863 action = new QAction(il.load("zoom-out"),
Chris@66 864 tr("Zoom &Out"), this);
Chris@66 865 action->setShortcut(tr("Down"));
Chris@66 866 action->setStatusTip(tr("Decrease the zoom level"));
Chris@66 867 connect(action, SIGNAL(triggered()), this, SLOT(zoomOut()));
Chris@66 868 connect(this, SIGNAL(canZoom(bool)), action, SLOT(setEnabled(bool)));
Chris@162 869 m_keyReference->registerShortcut(action);
mathieu@439 870 m_viewMenu->addAction(action);
Chris@0 871
Chris@66 872 action = new QAction(tr("Restore &Default Zoom"), this);
Chris@90 873 action->setStatusTip(tr("Restore the zoom level to the default"));
Chris@66 874 connect(action, SIGNAL(triggered()), this, SLOT(zoomDefault()));
Chris@66 875 connect(this, SIGNAL(canZoom(bool)), action, SLOT(setEnabled(bool)));
mathieu@439 876 m_viewMenu->addAction(action);
Chris@66 877
Chris@168 878 action = new QAction(il.load("zoom-fit"),
Chris@138 879 tr("Zoom to &Fit"), this);
Chris@155 880 action->setShortcut(tr("F"));
Chris@66 881 action->setStatusTip(tr("Zoom to show the whole file"));
Chris@66 882 connect(action, SIGNAL(triggered()), this, SLOT(zoomToFit()));
Chris@66 883 connect(this, SIGNAL(canZoom(bool)), action, SLOT(setEnabled(bool)));
Chris@162 884 m_keyReference->registerShortcut(action);
mathieu@439 885 m_viewMenu->addAction(action);
mathieu@439 886
mathieu@439 887 m_viewMenu->addSeparator();
Chris@90 888
Chris@162 889 m_keyReference->setCategory(tr("Display Features"));
Chris@162 890
Chris@90 891 QActionGroup *overlayGroup = new QActionGroup(this);
Chris@90 892
mathieu@439 893 m_showNoOverlaysAction = new QAction(tr("Show &No Overlays"), this);
mathieu@439 894 m_showNoOverlaysAction->setShortcut(tr("0"));
mathieu@439 895 m_showNoOverlaysAction->setStatusTip(tr("Hide centre indicator, frame times, layer names and scale"));
mathieu@439 896 connect(m_showNoOverlaysAction, SIGNAL(triggered()), this, SLOT(showNoOverlays()));
mathieu@439 897 m_showNoOverlaysAction->setCheckable(true);
mathieu@439 898 m_showNoOverlaysAction->setChecked(false);
mathieu@439 899 overlayGroup->addAction(m_showNoOverlaysAction);
mathieu@439 900 m_keyReference->registerShortcut(m_showNoOverlaysAction);
mathieu@439 901 m_viewMenu->addAction(m_showNoOverlaysAction);
Chris@90 902
mathieu@439 903 m_showMinimalOverlaysAction = new QAction(tr("Show &Minimal Overlays"), this);
mathieu@439 904 m_showMinimalOverlaysAction->setShortcut(tr("9"));
mathieu@439 905 m_showMinimalOverlaysAction->setStatusTip(tr("Show centre indicator only"));
mathieu@439 906 connect(m_showMinimalOverlaysAction, SIGNAL(triggered()), this, SLOT(showMinimalOverlays()));
mathieu@439 907 m_showMinimalOverlaysAction->setCheckable(true);
mathieu@439 908 m_showMinimalOverlaysAction->setChecked(false);
mathieu@439 909 overlayGroup->addAction(m_showMinimalOverlaysAction);
mathieu@439 910 m_keyReference->registerShortcut(m_showMinimalOverlaysAction);
mathieu@439 911 m_viewMenu->addAction(m_showMinimalOverlaysAction);
Chris@90 912
mathieu@439 913 m_showStandardOverlaysAction = new QAction(tr("Show &Standard Overlays"), this);
mathieu@439 914 m_showStandardOverlaysAction->setShortcut(tr("8"));
mathieu@439 915 m_showStandardOverlaysAction->setStatusTip(tr("Show centre indicator, frame times and scale"));
mathieu@439 916 connect(m_showStandardOverlaysAction, SIGNAL(triggered()), this, SLOT(showStandardOverlays()));
mathieu@439 917 m_showStandardOverlaysAction->setCheckable(true);
mathieu@439 918 m_showStandardOverlaysAction->setChecked(true);
mathieu@439 919 overlayGroup->addAction(m_showStandardOverlaysAction);
mathieu@439 920 m_keyReference->registerShortcut(m_showStandardOverlaysAction);
mathieu@439 921 m_viewMenu->addAction(m_showStandardOverlaysAction);
Chris@90 922
mathieu@439 923 m_showAllOverlaysAction = new QAction(tr("Show &All Overlays"), this);
mathieu@439 924 m_showAllOverlaysAction->setShortcut(tr("7"));
mathieu@439 925 m_showAllOverlaysAction->setStatusTip(tr("Show all texts and scale"));
mathieu@439 926 connect(m_showAllOverlaysAction, SIGNAL(triggered()), this, SLOT(showAllOverlays()));
mathieu@439 927 m_showAllOverlaysAction->setCheckable(true);
mathieu@439 928 m_showAllOverlaysAction->setChecked(false);
mathieu@439 929 overlayGroup->addAction(m_showAllOverlaysAction);
mathieu@439 930 m_keyReference->registerShortcut(m_showAllOverlaysAction);
mathieu@439 931 m_viewMenu->addAction(m_showAllOverlaysAction);
mathieu@439 932
mathieu@439 933 m_viewMenu->addSeparator();
mathieu@439 934
mathieu@439 935 m_showAllTimeRulersAction = new QAction(tr("Show All Time Rulers"), this);
mathieu@439 936 m_showAllTimeRulersAction->setShortcut(tr("#"));
mathieu@439 937 m_showAllTimeRulersAction->setStatusTip(tr("Show or hide all time rulers"));
mathieu@439 938 connect(m_showAllTimeRulersAction, SIGNAL(triggered()), this, SLOT(toggleTimeRulers()));
mathieu@439 939 m_keyReference->registerShortcut(m_showAllTimeRulersAction);
mathieu@439 940 m_viewMenu->addAction(m_showAllTimeRulersAction);
mathieu@439 941
mathieu@439 942 m_viewMenu->addSeparator();
mathieu@439 943
mathieu@439 944 m_showZoomWheelsAction = new QAction(tr("Show &Zoom Wheels"), this);
mathieu@439 945 m_showZoomWheelsAction->setShortcut(tr("Z"));
mathieu@439 946 m_showZoomWheelsAction->setStatusTip(tr("Show thumbwheels for zooming horizontally and vertically"));
mathieu@439 947 connect(m_showZoomWheelsAction, SIGNAL(triggered()), this, SLOT(toggleZoomWheels()));
mathieu@439 948 m_showZoomWheelsAction->setCheckable(true);
mathieu@439 949 m_showZoomWheelsAction->setChecked(m_viewManager->getZoomWheelsEnabled());
mathieu@439 950 m_keyReference->registerShortcut(m_showZoomWheelsAction);
mathieu@439 951 m_viewMenu->addAction(m_showZoomWheelsAction);
mathieu@439 952
mathieu@439 953 m_showPropertyBoxesAction = new QAction(tr("Show Property Bo&xes"), this);
mathieu@439 954 m_showPropertyBoxesAction->setShortcut(tr("X"));
mathieu@439 955 m_showPropertyBoxesAction->setStatusTip(tr("Show the layer property boxes at the side of the main window"));
mathieu@439 956 connect(m_showPropertyBoxesAction, SIGNAL(triggered()), this, SLOT(togglePropertyBoxes()));
mathieu@439 957 m_showPropertyBoxesAction->setCheckable(true);
mathieu@439 958 m_showPropertyBoxesAction->setChecked(true);
mathieu@439 959 m_keyReference->registerShortcut(m_showPropertyBoxesAction);
mathieu@439 960 m_viewMenu->addAction(m_showPropertyBoxesAction);
mathieu@439 961
mathieu@439 962 m_showStatusBarAction = new QAction(tr("Show Status &Bar"), this);
mathieu@439 963 m_showStatusBarAction->setStatusTip(tr("Show context help information in the status bar at the bottom of the window"));
mathieu@439 964 connect(m_showStatusBarAction, SIGNAL(triggered()), this, SLOT(toggleStatusBar()));
mathieu@439 965 m_showStatusBarAction->setCheckable(true);
mathieu@439 966 m_showStatusBarAction->setChecked(true);
mathieu@439 967 m_viewMenu->addAction(m_showStatusBarAction);
Chris@90 968
mathieu@459 969 //QSettings settings;
Chris@90 970 settings.beginGroup("MainWindow");
Chris@90 971 bool sb = settings.value("showstatusbar", true).toBool();
Chris@90 972 if (!sb) {
Chris@90 973 action->setChecked(false);
Chris@90 974 statusBar()->hide();
Chris@90 975 }
Chris@90 976 settings.endGroup();
Chris@90 977
mathieu@439 978 m_viewMenu->addSeparator();
Chris@66 979
Chris@219 980 action = new QAction(tr("Show La&yer Summary"), this);
Chris@219 981 action->setShortcut(tr("Y"));
Chris@90 982 action->setStatusTip(tr("Open a window displaying the hierarchy of panes and layers in this session"));
Chris@66 983 connect(action, SIGNAL(triggered()), this, SLOT(showLayerTree()));
Chris@162 984 m_keyReference->registerShortcut(action);
mathieu@439 985 m_viewMenu->addAction(action);
Chris@306 986
Chris@306 987 action = new QAction(tr("Show Acti&vity Log"), this);
Chris@306 988 action->setStatusTip(tr("Open a window listing interactions and other events"));
Chris@306 989 connect(action, SIGNAL(triggered()), this, SLOT(showActivityLog()));
mathieu@439 990 m_viewMenu->addAction(action);
Chris@66 991 }
Chris@66 992
Chris@66 993 void
Chris@66 994 MainWindow::setupPaneAndLayerMenus()
Chris@66 995 {
Chris@0 996 if (m_paneMenu) {
Chris@0 997 m_paneActions.clear();
Chris@0 998 m_paneMenu->clear();
Chris@0 999 } else {
Chris@0 1000 m_paneMenu = menuBar()->addMenu(tr("&Pane"));
Chris@97 1001 m_paneMenu->setTearOffEnabled(true);
Chris@0 1002 }
Chris@0 1003
Chris@0 1004 if (m_layerMenu) {
Chris@0 1005 m_layerActions.clear();
Chris@0 1006 m_layerMenu->clear();
Chris@0 1007 } else {
Chris@0 1008 m_layerMenu = menuBar()->addMenu(tr("&Layer"));
Chris@97 1009 m_layerMenu->setTearOffEnabled(true);
Chris@0 1010 }
Chris@0 1011
Chris@345 1012 if (m_rightButtonLayerMenu) {
Chris@345 1013 m_rightButtonLayerMenu->clear();
Chris@345 1014 } else {
Chris@345 1015 m_rightButtonLayerMenu = m_rightButtonMenu->addMenu(tr("&Layer"));
Chris@345 1016 m_rightButtonLayerMenu->setTearOffEnabled(true);
Chris@345 1017 m_rightButtonMenu->addSeparator();
Chris@345 1018 }
Chris@345 1019
Chris@66 1020 QMenu *menu = m_paneMenu;
Chris@66 1021
Chris@168 1022 IconLoader il;
Chris@168 1023
Chris@162 1024 m_keyReference->setCategory(tr("Managing Panes and Layers"));
Chris@162 1025
Chris@168 1026 QAction *action = new QAction(il.load("pane"), tr("Add &New Pane"), this);
Chris@155 1027 action->setShortcut(tr("N"));
Chris@66 1028 action->setStatusTip(tr("Add a new pane containing only a time ruler"));
Chris@66 1029 connect(action, SIGNAL(triggered()), this, SLOT(addPane()));
Chris@66 1030 connect(this, SIGNAL(canAddPane(bool)), action, SLOT(setEnabled(bool)));
Chris@232 1031 m_paneActions[action] = LayerConfiguration(LayerFactory::TimeRuler);
Chris@162 1032 m_keyReference->registerShortcut(action);
Chris@66 1033 menu->addAction(action);
Chris@66 1034
Chris@66 1035 menu->addSeparator();
Chris@66 1036
Chris@66 1037 menu = m_layerMenu;
Chris@66 1038
Chris@66 1039 // menu->addSeparator();
Chris@66 1040
Chris@66 1041 LayerFactory::LayerTypeSet emptyLayerTypes =
Chris@66 1042 LayerFactory::getInstance()->getValidEmptyLayerTypes();
Chris@66 1043
Chris@66 1044 for (LayerFactory::LayerTypeSet::iterator i = emptyLayerTypes.begin();
Chris@66 1045 i != emptyLayerTypes.end(); ++i) {
Chris@66 1046
Chris@66 1047 QIcon icon;
Chris@66 1048 QString mainText, tipText, channelText;
Chris@66 1049 LayerFactory::LayerType type = *i;
Chris@66 1050 QString name = LayerFactory::getInstance()->getLayerPresentationName(type);
Chris@66 1051
Chris@168 1052 icon = il.load(LayerFactory::getInstance()->getLayerIconName(type));
Chris@66 1053
Chris@66 1054 mainText = tr("Add New %1 Layer").arg(name);
Chris@66 1055 tipText = tr("Add a new empty layer of type %1").arg(name);
Chris@66 1056
Chris@66 1057 action = new QAction(icon, mainText, this);
Chris@66 1058 action->setStatusTip(tipText);
Chris@66 1059
Chris@66 1060 if (type == LayerFactory::Text) {
Chris@155 1061 action->setShortcut(tr("T"));
Chris@162 1062 m_keyReference->registerShortcut(action);
Chris@66 1063 }
Chris@66 1064
Chris@66 1065 connect(action, SIGNAL(triggered()), this, SLOT(addLayer()));
Chris@66 1066 connect(this, SIGNAL(canAddLayer(bool)), action, SLOT(setEnabled(bool)));
Chris@232 1067 m_layerActions[action] = LayerConfiguration(type);
Chris@66 1068 menu->addAction(action);
Chris@66 1069 m_rightButtonLayerMenu->addAction(action);
Chris@66 1070 }
Chris@66 1071
Chris@66 1072 m_rightButtonLayerMenu->addSeparator();
Chris@66 1073 menu->addSeparator();
Chris@66 1074
Chris@66 1075 LayerFactory::LayerType backgroundTypes[] = {
Chris@66 1076 LayerFactory::Waveform,
Chris@66 1077 LayerFactory::Spectrogram,
Chris@66 1078 LayerFactory::MelodicRangeSpectrogram,
Chris@66 1079 LayerFactory::PeakFrequencySpectrogram,
Chris@66 1080 LayerFactory::Spectrum
Chris@66 1081 };
Chris@66 1082
Chris@66 1083 std::vector<Model *> models;
Chris@224 1084 if (m_document) models = m_document->getTransformInputModels();
Chris@66 1085 bool plural = (models.size() > 1);
Chris@66 1086 if (models.empty()) {
Chris@67 1087 models.push_back(getMainModel()); // probably 0
Chris@66 1088 }
Chris@66 1089
Chris@66 1090 for (unsigned int i = 0;
Chris@66 1091 i < sizeof(backgroundTypes)/sizeof(backgroundTypes[0]); ++i) {
Chris@66 1092
Chris@231 1093 const int paneMenuType = 0, layerMenuType = 1;
Chris@231 1094
Chris@231 1095 for (int menuType = paneMenuType; menuType <= layerMenuType; ++menuType) {
Chris@231 1096
Chris@231 1097 if (menuType == paneMenuType) menu = m_paneMenu;
Chris@66 1098 else menu = m_layerMenu;
Chris@66 1099
Chris@66 1100 QMenu *submenu = 0;
Chris@66 1101
Chris@66 1102 QIcon icon;
Chris@66 1103 QString mainText, shortcutText, tipText, channelText;
Chris@66 1104 LayerFactory::LayerType type = backgroundTypes[i];
Chris@66 1105 bool mono = true;
Chris@66 1106
Chris@66 1107 switch (type) {
Chris@66 1108
Chris@66 1109 case LayerFactory::Waveform:
Chris@168 1110 icon = il.load("waveform");
Chris@66 1111 mainText = tr("Add &Waveform");
Chris@231 1112 if (menuType == paneMenuType) {
Chris@155 1113 shortcutText = tr("W");
Chris@66 1114 tipText = tr("Add a new pane showing a waveform view");
Chris@66 1115 } else {
Chris@348 1116 shortcutText = tr("Shift+W");
Chris@66 1117 tipText = tr("Add a new layer showing a waveform view");
Chris@66 1118 }
Chris@66 1119 mono = false;
Chris@66 1120 break;
Chris@66 1121
Chris@66 1122 case LayerFactory::Spectrogram:
Chris@168 1123 icon = il.load("spectrogram");
Chris@161 1124 mainText = tr("Add Spectro&gram");
Chris@231 1125 if (menuType == paneMenuType) {
Chris@155 1126 shortcutText = tr("G");
Chris@90 1127 tipText = tr("Add a new pane showing a spectrogram");
Chris@66 1128 } else {
Chris@348 1129 shortcutText = tr("Shift+G");
Chris@90 1130 tipText = tr("Add a new layer showing a spectrogram");
Chris@66 1131 }
Chris@66 1132 break;
Chris@66 1133
Chris@66 1134 case LayerFactory::MelodicRangeSpectrogram:
Chris@168 1135 icon = il.load("spectrogram");
Chris@66 1136 mainText = tr("Add &Melodic Range Spectrogram");
Chris@231 1137 if (menuType == paneMenuType) {
Chris@155 1138 shortcutText = tr("M");
Chris@90 1139 tipText = tr("Add a new pane showing a spectrogram set up for an overview of note pitches");
Chris@66 1140 } else {
Chris@348 1141 shortcutText = tr("Shift+M");
Chris@90 1142 tipText = tr("Add a new layer showing a spectrogram set up for an overview of note pitches");
Chris@66 1143 }
Chris@66 1144 break;
Chris@66 1145
Chris@66 1146 case LayerFactory::PeakFrequencySpectrogram:
Chris@168 1147 icon = il.load("spectrogram");
Chris@155 1148 mainText = tr("Add Pea&k Frequency Spectrogram");
Chris@231 1149 if (menuType == paneMenuType) {
Chris@155 1150 shortcutText = tr("K");
Chris@66 1151 tipText = tr("Add a new pane showing a spectrogram set up for tracking frequencies");
Chris@66 1152 } else {
Chris@348 1153 shortcutText = tr("Shift+K");
Chris@66 1154 tipText = tr("Add a new layer showing a spectrogram set up for tracking frequencies");
Chris@66 1155 }
Chris@66 1156 break;
Chris@66 1157
Chris@66 1158 case LayerFactory::Spectrum:
Chris@168 1159 icon = il.load("spectrum");
Chris@66 1160 mainText = tr("Add Spectr&um");
Chris@231 1161 if (menuType == paneMenuType) {
Chris@155 1162 shortcutText = tr("U");
Chris@66 1163 tipText = tr("Add a new pane showing a frequency spectrum");
Chris@66 1164 } else {
Chris@348 1165 shortcutText = tr("Shift+U");
Chris@66 1166 tipText = tr("Add a new layer showing a frequency spectrum");
Chris@66 1167 }
Chris@66 1168 break;
Chris@66 1169
Chris@66 1170 default: break;
Chris@66 1171 }
Chris@66 1172
Chris@346 1173 std::vector<Model *> candidateModels = models;
Chris@66 1174
Chris@66 1175 for (std::vector<Model *>::iterator mi =
Chris@66 1176 candidateModels.begin();
Chris@66 1177 mi != candidateModels.end(); ++mi) {
Chris@66 1178
Chris@66 1179 Model *model = *mi;
Chris@66 1180
Chris@66 1181 int channels = 0;
Chris@66 1182 if (model) {
Chris@66 1183 DenseTimeValueModel *dtvm =
Chris@66 1184 dynamic_cast<DenseTimeValueModel *>(model);
Chris@66 1185 if (dtvm) channels = dtvm->getChannelCount();
Chris@66 1186 }
Chris@66 1187 if (channels < 1 && getMainModel()) {
Chris@66 1188 channels = getMainModel()->getChannelCount();
Chris@66 1189 }
Chris@66 1190 if (channels < 1) channels = 1;
Chris@66 1191
Chris@66 1192 for (int c = 0; c <= channels; ++c) {
Chris@66 1193
Chris@66 1194 if (c == 1 && channels == 1) continue;
Chris@66 1195 bool isDefault = (c == 0);
Chris@66 1196 bool isOnly = (isDefault && (channels == 1));
Chris@66 1197
Chris@346 1198 if (isOnly && !plural) {
Chris@346 1199
Chris@346 1200 action = new QAction(icon, mainText, this);
Chris@67 1201
Chris@66 1202 action->setShortcut(shortcutText);
Chris@66 1203 action->setStatusTip(tipText);
Chris@231 1204 if (menuType == paneMenuType) {
Chris@66 1205 connect(action, SIGNAL(triggered()),
Chris@66 1206 this, SLOT(addPane()));
Chris@66 1207 connect(this, SIGNAL(canAddPane(bool)),
Chris@66 1208 action, SLOT(setEnabled(bool)));
Chris@346 1209 m_paneActions[action] =
Chris@346 1210 LayerConfiguration(type, model);
Chris@66 1211 } else {
Chris@66 1212 connect(action, SIGNAL(triggered()),
Chris@66 1213 this, SLOT(addLayer()));
Chris@66 1214 connect(this, SIGNAL(canAddLayer(bool)),
Chris@66 1215 action, SLOT(setEnabled(bool)));
Chris@346 1216 m_layerActions[action] =
Chris@346 1217 LayerConfiguration(type, model);
Chris@66 1218 }
Chris@162 1219 if (shortcutText != "") {
Chris@162 1220 m_keyReference->registerShortcut(action);
Chris@162 1221 }
Chris@66 1222 menu->addAction(action);
Chris@66 1223
Chris@66 1224 } else {
Chris@66 1225
Chris@66 1226 if (!submenu) {
Chris@66 1227 submenu = menu->addMenu(mainText);
Chris@97 1228 submenu->setTearOffEnabled(true);
Chris@67 1229 } else if (isDefault) {
Chris@67 1230 submenu->addSeparator();
Chris@66 1231 }
Chris@66 1232
Chris@66 1233 QString actionText;
Chris@66 1234 if (c == 0) {
Chris@66 1235 if (mono) {
Chris@66 1236 actionText = tr("&All Channels Mixed");
Chris@66 1237 } else {
Chris@66 1238 actionText = tr("&All Channels");
Chris@66 1239 }
Chris@66 1240 } else {
Chris@66 1241 actionText = tr("Channel &%1").arg(c);
Chris@66 1242 }
Chris@66 1243
Chris@66 1244 if (model) {
Chris@66 1245 actionText = tr("%1: %2")
Chris@66 1246 .arg(model->objectName())
Chris@66 1247 .arg(actionText);
Chris@66 1248 }
Chris@67 1249
Chris@67 1250 if (isDefault) {
Chris@67 1251 action = new QAction(icon, actionText, this);
Chris@67 1252 if (!model || model == getMainModel()) {
Chris@162 1253 action->setShortcut(shortcutText);
Chris@67 1254 }
Chris@67 1255 } else {
Chris@67 1256 action = new QAction(actionText, this);
Chris@67 1257 }
Chris@67 1258
Chris@66 1259 action->setStatusTip(tipText);
Chris@66 1260
Chris@231 1261 if (menuType == paneMenuType) {
Chris@66 1262 connect(action, SIGNAL(triggered()),
Chris@66 1263 this, SLOT(addPane()));
Chris@66 1264 connect(this, SIGNAL(canAddPane(bool)),
Chris@66 1265 action, SLOT(setEnabled(bool)));
Chris@66 1266 m_paneActions[action] =
Chris@232 1267 LayerConfiguration(type, model, c - 1);
Chris@66 1268 } else {
Chris@66 1269 connect(action, SIGNAL(triggered()),
Chris@66 1270 this, SLOT(addLayer()));
Chris@66 1271 connect(this, SIGNAL(canAddLayer(bool)),
Chris@66 1272 action, SLOT(setEnabled(bool)));
Chris@232 1273 m_layerActions[action] =
Chris@232 1274 LayerConfiguration(type, model, c - 1);
Chris@66 1275 }
Chris@66 1276
Chris@66 1277 submenu->addAction(action);
Chris@66 1278 }
Chris@346 1279
Chris@415 1280 if (isDefault && menuType == layerMenuType &&
Chris@415 1281 mi == candidateModels.begin()) {
Chris@415 1282 // only add for one model, one channel, one menu on
Chris@415 1283 // right button -- the action itself will discover
Chris@415 1284 // which model is the correct one (based on pane)
Chris@346 1285 action = new QAction(icon, mainText, this);
Chris@346 1286 action->setStatusTip(tipText);
Chris@346 1287 connect(action, SIGNAL(triggered()),
Chris@346 1288 this, SLOT(addLayer()));
Chris@346 1289 connect(this, SIGNAL(canAddLayer(bool)),
Chris@346 1290 action, SLOT(setEnabled(bool)));
Chris@346 1291 m_layerActions[action] = LayerConfiguration(type, 0, 0);
Chris@346 1292 m_rightButtonLayerMenu->addAction(action);
Chris@346 1293 }
Chris@66 1294 }
Chris@66 1295 }
Chris@66 1296 }
Chris@66 1297 }
Chris@66 1298
Chris@347 1299 m_rightButtonLayerMenu->addSeparator();
Chris@347 1300
Chris@66 1301 menu = m_paneMenu;
Chris@225 1302 menu->addSeparator();
Chris@225 1303
Chris@225 1304 action = new QAction(tr("Switch to Previous Pane"), this);
Chris@225 1305 action->setShortcut(tr("["));
Chris@225 1306 action->setStatusTip(tr("Make the next pane up in the pane stack current"));
Chris@225 1307 connect(action, SIGNAL(triggered()), this, SLOT(previousPane()));
Chris@225 1308 connect(this, SIGNAL(canSelectPreviousPane(bool)), action, SLOT(setEnabled(bool)));
Chris@225 1309 m_keyReference->registerShortcut(action);
Chris@225 1310 menu->addAction(action);
Chris@225 1311
Chris@225 1312 action = new QAction(tr("Switch to Next Pane"), this);
Chris@225 1313 action->setShortcut(tr("]"));
Chris@225 1314 action->setStatusTip(tr("Make the next pane down in the pane stack current"));
Chris@225 1315 connect(action, SIGNAL(triggered()), this, SLOT(nextPane()));
Chris@225 1316 connect(this, SIGNAL(canSelectNextPane(bool)), action, SLOT(setEnabled(bool)));
Chris@225 1317 m_keyReference->registerShortcut(action);
Chris@225 1318 menu->addAction(action);
Chris@66 1319
Chris@66 1320 menu->addSeparator();
Chris@66 1321
Chris@168 1322 action = new QAction(il.load("editdelete"), tr("&Delete Pane"), this);
Chris@155 1323 action->setShortcut(tr("Ctrl+Shift+D"));
Chris@90 1324 action->setStatusTip(tr("Delete the currently active pane"));
Chris@66 1325 connect(action, SIGNAL(triggered()), this, SLOT(deleteCurrentPane()));
Chris@66 1326 connect(this, SIGNAL(canDeleteCurrentPane(bool)), action, SLOT(setEnabled(bool)));
Chris@162 1327 m_keyReference->registerShortcut(action);
Chris@66 1328 menu->addAction(action);
Chris@66 1329
Chris@66 1330 menu = m_layerMenu;
Chris@66 1331
Chris@168 1332 action = new QAction(il.load("timeruler"), tr("Add &Time Ruler"), this);
Chris@66 1333 action->setStatusTip(tr("Add a new layer showing a time ruler"));
Chris@66 1334 connect(action, SIGNAL(triggered()), this, SLOT(addLayer()));
Chris@66 1335 connect(this, SIGNAL(canAddLayer(bool)), action, SLOT(setEnabled(bool)));
Chris@232 1336 m_layerActions[action] = LayerConfiguration(LayerFactory::TimeRuler);
Chris@66 1337 menu->addAction(action);
Chris@66 1338
Chris@66 1339 menu->addSeparator();
Chris@66 1340
Chris@66 1341 m_existingLayersMenu = menu->addMenu(tr("Add &Existing Layer"));
Chris@97 1342 m_existingLayersMenu->setTearOffEnabled(true);
Chris@66 1343 m_rightButtonLayerMenu->addMenu(m_existingLayersMenu);
Chris@95 1344
Chris@95 1345 m_sliceMenu = menu->addMenu(tr("Add S&lice of Layer"));
Chris@97 1346 m_sliceMenu->setTearOffEnabled(true);
Chris@95 1347 m_rightButtonLayerMenu->addMenu(m_sliceMenu);
Chris@95 1348
Chris@95 1349 setupExistingLayersMenus();
Chris@66 1350
Chris@225 1351 /*!!! These don't work correctly -- fix or omit
Chris@225 1352 menu->addSeparator();
Chris@225 1353
Chris@225 1354 action = new QAction(tr("Switch to Previous Layer"), this);
Chris@225 1355 action->setShortcut(tr("{"));
Chris@225 1356 action->setStatusTip(tr("Make the previous layer in the pane current"));
Chris@225 1357 connect(action, SIGNAL(triggered()), this, SLOT(previousLayer()));
Chris@225 1358 connect(this, SIGNAL(canSelectPreviousLayer(bool)), action, SLOT(setEnabled(bool)));
Chris@225 1359 m_keyReference->registerShortcut(action);
Chris@225 1360 menu->addAction(action);
Chris@225 1361
Chris@225 1362 action = new QAction(tr("Switch to Next Layer"), this);
Chris@225 1363 action->setShortcut(tr("}"));
Chris@225 1364 action->setStatusTip(tr("Make the next layer in the pane current"));
Chris@225 1365 connect(action, SIGNAL(triggered()), this, SLOT(nextLayer()));
Chris@225 1366 connect(this, SIGNAL(canSelectNextLayer(bool)), action, SLOT(setEnabled(bool)));
Chris@225 1367 m_keyReference->registerShortcut(action);
Chris@225 1368 menu->addAction(action);
Chris@225 1369 */
Chris@66 1370 m_rightButtonLayerMenu->addSeparator();
Chris@66 1371 menu->addSeparator();
Chris@66 1372
Chris@163 1373 QAction *raction = new QAction(tr("&Rename Layer..."), this);
Chris@163 1374 raction->setShortcut(tr("R"));
Chris@163 1375 raction->setStatusTip(tr("Rename the currently active layer"));
Chris@163 1376 connect(raction, SIGNAL(triggered()), this, SLOT(renameCurrentLayer()));
Chris@163 1377 connect(this, SIGNAL(canRenameLayer(bool)), raction, SLOT(setEnabled(bool)));
Chris@163 1378 menu->addAction(raction);
Chris@163 1379 m_rightButtonLayerMenu->addAction(raction);
Chris@66 1380
Chris@258 1381 QAction *eaction = new QAction(tr("Edit Layer Data"), this);
Chris@258 1382 eaction->setShortcut(tr("E"));
Chris@258 1383 eaction->setStatusTip(tr("Edit the currently active layer as a data grid"));
Chris@258 1384 connect(eaction, SIGNAL(triggered()), this, SLOT(editCurrentLayer()));
Chris@291 1385 connect(this, SIGNAL(canEditLayerTabular(bool)), eaction, SLOT(setEnabled(bool)));
Chris@258 1386 menu->addAction(eaction);
Chris@258 1387 m_rightButtonLayerMenu->addAction(eaction);
Chris@258 1388
Chris@168 1389 action = new QAction(il.load("editdelete"), tr("&Delete Layer"), this);
Chris@155 1390 action->setShortcut(tr("Ctrl+D"));
Chris@66 1391 action->setStatusTip(tr("Delete the currently active layer"));
Chris@66 1392 connect(action, SIGNAL(triggered()), this, SLOT(deleteCurrentLayer()));
Chris@66 1393 connect(this, SIGNAL(canDeleteCurrentLayer(bool)), action, SLOT(setEnabled(bool)));
Chris@162 1394 m_keyReference->registerShortcut(action);
Chris@66 1395 menu->addAction(action);
Chris@66 1396 m_rightButtonLayerMenu->addAction(action);
Chris@163 1397
Chris@163 1398 m_keyReference->registerShortcut(raction); // rename after delete, so delete layer goes next to delete pane
Chris@258 1399 m_keyReference->registerShortcut(eaction); // edit also after delete
Chris@66 1400 }
Chris@66 1401
Chris@66 1402 void
Chris@211 1403 MainWindow::setupTransformsMenu()
Chris@66 1404 {
Chris@34 1405 if (m_transformsMenu) {
Chris@34 1406 m_transformActions.clear();
Chris@34 1407 m_transformActionsReverse.clear();
Chris@34 1408 m_transformsMenu->clear();
Chris@34 1409 } else {
Chris@97 1410 m_transformsMenu = menuBar()->addMenu(tr("&Transform"));
Chris@97 1411 m_transformsMenu->setTearOffEnabled(true);
Chris@286 1412 m_transformsMenu->setSeparatorsCollapsible(true);
Chris@272 1413 }
Chris@34 1414
Chris@288 1415 TransformFactory *factory = TransformFactory::getInstance();
Chris@288 1416
Chris@288 1417 TransformList transforms = factory->getAllTransformDescriptions();
Chris@288 1418 vector<TransformDescription::Type> types = factory->getAllTransformTypes();
Chris@288 1419
Chris@288 1420 map<TransformDescription::Type, map<QString, SubdividingMenu *> > categoryMenus;
Chris@288 1421 map<TransformDescription::Type, map<QString, SubdividingMenu *> > makerMenus;
Chris@288 1422
Chris@288 1423 map<TransformDescription::Type, SubdividingMenu *> byPluginNameMenus;
Chris@288 1424 map<TransformDescription::Type, map<QString, QMenu *> > pluginNameMenus;
Chris@33 1425
Chris@37 1426 set<SubdividingMenu *> pendingMenus;
Chris@37 1427
Chris@211 1428 m_recentTransformsMenu = m_transformsMenu->addMenu(tr("&Recent Transforms"));
Chris@211 1429 m_recentTransformsMenu->setTearOffEnabled(true);
Chris@211 1430 m_rightButtonTransformsMenu->addMenu(m_recentTransformsMenu);
Chris@211 1431 connect(&m_recentTransforms, SIGNAL(recentChanged()),
Chris@211 1432 this, SLOT(setupRecentTransformsMenu()));
Chris@34 1433
Chris@34 1434 m_transformsMenu->addSeparator();
Chris@211 1435 m_rightButtonTransformsMenu->addSeparator();
Chris@34 1436
Chris@288 1437 for (vector<TransformDescription::Type>::iterator i = types.begin();
Chris@288 1438 i != types.end(); ++i) {
Chris@33 1439
Chris@33 1440 if (i != types.begin()) {
Chris@34 1441 m_transformsMenu->addSeparator();
Chris@211 1442 m_rightButtonTransformsMenu->addSeparator();
Chris@33 1443 }
Chris@33 1444
Chris@288 1445 QString byCategoryLabel = tr("%1 by Category")
Chris@288 1446 .arg(factory->getTransformTypeName(*i));
Chris@37 1447 SubdividingMenu *byCategoryMenu = new SubdividingMenu(byCategoryLabel,
Chris@37 1448 20, 40);
Chris@97 1449 byCategoryMenu->setTearOffEnabled(true);
Chris@37 1450 m_transformsMenu->addMenu(byCategoryMenu);
Chris@211 1451 m_rightButtonTransformsMenu->addMenu(byCategoryMenu);
Chris@37 1452 pendingMenus.insert(byCategoryMenu);
Chris@33 1453
Chris@288 1454 vector<QString> categories = factory->getTransformCategories(*i);
Chris@33 1455
Chris@33 1456 for (vector<QString>::iterator j = categories.begin();
Chris@33 1457 j != categories.end(); ++j) {
Chris@33 1458
Chris@33 1459 QString category = *j;
Chris@33 1460 if (category == "") category = tr("Unclassified");
Chris@33 1461
Chris@33 1462 if (categories.size() < 2) {
Chris@33 1463 categoryMenus[*i][category] = byCategoryMenu;
Chris@33 1464 continue;
Chris@33 1465 }
Chris@33 1466
Chris@33 1467 QStringList components = category.split(" > ");
Chris@33 1468 QString key;
Chris@33 1469
Chris@33 1470 for (QStringList::iterator k = components.begin();
Chris@33 1471 k != components.end(); ++k) {
Chris@33 1472
Chris@33 1473 QString parentKey = key;
Chris@33 1474 if (key != "") key += " > ";
Chris@33 1475 key += *k;
Chris@33 1476
Chris@33 1477 if (categoryMenus[*i].find(key) == categoryMenus[*i].end()) {
Chris@37 1478 SubdividingMenu *m = new SubdividingMenu(*k, 20, 40);
Chris@97 1479 m->setTearOffEnabled(true);
Chris@37 1480 pendingMenus.insert(m);
Chris@37 1481 categoryMenus[*i][key] = m;
Chris@33 1482 if (parentKey == "") {
Chris@37 1483 byCategoryMenu->addMenu(m);
Chris@33 1484 } else {
Chris@37 1485 categoryMenus[*i][parentKey]->addMenu(m);
Chris@33 1486 }
Chris@33 1487 }
Chris@33 1488 }
Chris@33 1489 }
Chris@33 1490
Chris@288 1491 QString byPluginNameLabel = tr("%1 by Plugin Name")
Chris@288 1492 .arg(factory->getTransformTypeName(*i));
Chris@36 1493 byPluginNameMenus[*i] = new SubdividingMenu(byPluginNameLabel);
Chris@97 1494 byPluginNameMenus[*i]->setTearOffEnabled(true);
Chris@36 1495 m_transformsMenu->addMenu(byPluginNameMenus[*i]);
Chris@211 1496 m_rightButtonTransformsMenu->addMenu(byPluginNameMenus[*i]);
Chris@37 1497 pendingMenus.insert(byPluginNameMenus[*i]);
Chris@34 1498
Chris@288 1499 QString byMakerLabel = tr("%1 by Maker")
Chris@288 1500 .arg(factory->getTransformTypeName(*i));
Chris@37 1501 SubdividingMenu *byMakerMenu = new SubdividingMenu(byMakerLabel, 20, 40);
Chris@97 1502 byMakerMenu->setTearOffEnabled(true);
Chris@37 1503 m_transformsMenu->addMenu(byMakerMenu);
Chris@211 1504 m_rightButtonTransformsMenu->addMenu(byMakerMenu);
Chris@37 1505 pendingMenus.insert(byMakerMenu);
Chris@33 1506
Chris@288 1507 vector<QString> makers = factory->getTransformMakers(*i);
Chris@37 1508
Chris@33 1509 for (vector<QString>::iterator j = makers.begin();
Chris@33 1510 j != makers.end(); ++j) {
Chris@33 1511
Chris@33 1512 QString maker = *j;
Chris@33 1513 if (maker == "") maker = tr("Unknown");
Chris@55 1514 maker.replace(QRegExp(tr(" [\\(<].*$")), "");
Chris@55 1515
Chris@37 1516 makerMenus[*i][maker] = new SubdividingMenu(maker, 30, 40);
Chris@97 1517 makerMenus[*i][maker]->setTearOffEnabled(true);
Chris@37 1518 byMakerMenu->addMenu(makerMenus[*i][maker]);
Chris@37 1519 pendingMenus.insert(makerMenus[*i][maker]);
Chris@33 1520 }
Chris@0 1521 }
Chris@0 1522
Chris@230 1523 // Names should only be duplicated here if they have the same
Chris@230 1524 // plugin name, output name and maker but are in different library
Chris@230 1525 // .so names -- that won't happen often I hope
Chris@230 1526 std::map<QString, QString> idNameSonameMap;
Chris@230 1527 std::set<QString> seenNames, duplicateNames;
Chris@230 1528 for (unsigned int i = 0; i < transforms.size(); ++i) {
Chris@230 1529 QString name = transforms[i].name;
Chris@230 1530 if (seenNames.find(name) != seenNames.end()) {
Chris@230 1531 duplicateNames.insert(name);
Chris@230 1532 } else {
Chris@230 1533 seenNames.insert(name);
Chris@230 1534 }
Chris@230 1535 }
Chris@230 1536
Chris@0 1537 for (unsigned int i = 0; i < transforms.size(); ++i) {
Chris@0 1538
Chris@107 1539 QString name = transforms[i].name;
Chris@107 1540 if (name == "") name = transforms[i].identifier;
Chris@107 1541
Chris@432 1542 // std::cerr << "Plugin Name: " << name << std::endl;
Chris@80 1543
Chris@288 1544 TransformDescription::Type type = transforms[i].type;
Chris@288 1545 QString typeStr = factory->getTransformTypeName(type);
Chris@33 1546
Chris@33 1547 QString category = transforms[i].category;
Chris@33 1548 if (category == "") category = tr("Unclassified");
Chris@33 1549
Chris@33 1550 QString maker = transforms[i].maker;
Chris@33 1551 if (maker == "") maker = tr("Unknown");
Chris@55 1552 maker.replace(QRegExp(tr(" [\\(<].*$")), "");
Chris@33 1553
Chris@107 1554 QString pluginName = name.section(": ", 0, 0);
Chris@107 1555 QString output = name.section(": ", 1);
Chris@107 1556
Chris@230 1557 if (duplicateNames.find(pluginName) != duplicateNames.end()) {
Chris@230 1558 pluginName = QString("%1 <%2>")
Chris@230 1559 .arg(pluginName)
Chris@230 1560 .arg(transforms[i].identifier.section(':', 1, 1));
Chris@230 1561 if (output == "") name = pluginName;
Chris@230 1562 else name = QString("%1: %2")
Chris@230 1563 .arg(pluginName)
Chris@230 1564 .arg(output);
Chris@230 1565 }
Chris@230 1566
Chris@107 1567 QAction *action = new QAction(tr("%1...").arg(name), this);
Chris@0 1568 connect(action, SIGNAL(triggered()), this, SLOT(addLayer()));
Chris@107 1569 m_transformActions[action] = transforms[i].identifier;
Chris@107 1570 m_transformActionsReverse[transforms[i].identifier] = action;
Chris@0 1571 connect(this, SIGNAL(canAddLayer(bool)), action, SLOT(setEnabled(bool)));
Chris@33 1572
Chris@272 1573 action->setStatusTip(transforms[i].longDescription);
Chris@90 1574
Chris@33 1575 if (categoryMenus[type].find(category) == categoryMenus[type].end()) {
Chris@33 1576 std::cerr << "WARNING: MainWindow::setupMenus: Internal error: "
Chris@33 1577 << "No category menu for transform \""
Chris@432 1578 << name << "\" (category = \""
Chris@432 1579 << category << "\")" << std::endl;
Chris@33 1580 } else {
Chris@33 1581 categoryMenus[type][category]->addAction(action);
Chris@33 1582 }
Chris@33 1583
Chris@33 1584 if (makerMenus[type].find(maker) == makerMenus[type].end()) {
Chris@33 1585 std::cerr << "WARNING: MainWindow::setupMenus: Internal error: "
Chris@33 1586 << "No maker menu for transform \""
Chris@432 1587 << name << "\" (maker = \""
Chris@432 1588 << maker << "\")" << std::endl;
Chris@33 1589 } else {
Chris@80 1590 makerMenus[type][maker]->addAction(action);
Chris@33 1591 }
Chris@33 1592
Chris@33 1593 action = new QAction(tr("%1...").arg(output == "" ? pluginName : output), this);
Chris@33 1594 connect(action, SIGNAL(triggered()), this, SLOT(addLayer()));
Chris@107 1595 m_transformActions[action] = transforms[i].identifier;
Chris@33 1596 connect(this, SIGNAL(canAddLayer(bool)), action, SLOT(setEnabled(bool)));
Chris@272 1597 action->setStatusTip(transforms[i].longDescription);
Chris@33 1598
Chris@432 1599 // cerr << "Transform: \"" << name << "\": plugin name \"" << pluginName << "\"" << endl;
Chris@34 1600
Chris@33 1601 if (pluginNameMenus[type].find(pluginName) ==
Chris@33 1602 pluginNameMenus[type].end()) {
Chris@33 1603
Chris@36 1604 SubdividingMenu *parentMenu = byPluginNameMenus[type];
Chris@97 1605 parentMenu->setTearOffEnabled(true);
Chris@34 1606
Chris@33 1607 if (output == "") {
Chris@36 1608 parentMenu->addAction(pluginName, action);
Chris@33 1609 } else {
Chris@34 1610 pluginNameMenus[type][pluginName] =
Chris@34 1611 parentMenu->addMenu(pluginName);
Chris@33 1612 connect(this, SIGNAL(canAddLayer(bool)),
Chris@33 1613 pluginNameMenus[type][pluginName],
Chris@33 1614 SLOT(setEnabled(bool)));
Chris@33 1615 }
Chris@33 1616 }
Chris@33 1617
Chris@33 1618 if (pluginNameMenus[type].find(pluginName) !=
Chris@33 1619 pluginNameMenus[type].end()) {
Chris@33 1620 pluginNameMenus[type][pluginName]->addAction(action);
Chris@33 1621 }
Chris@0 1622 }
Chris@0 1623
Chris@37 1624 for (set<SubdividingMenu *>::iterator i = pendingMenus.begin();
Chris@37 1625 i != pendingMenus.end(); ++i) {
Chris@37 1626 (*i)->entriesAdded();
Chris@37 1627 }
Chris@37 1628
Chris@273 1629 m_transformsMenu->addSeparator();
Chris@273 1630 m_rightButtonTransformsMenu->addSeparator();
Chris@273 1631
Chris@273 1632 QAction *action = new QAction(tr("Find a Transform..."), this);
Chris@273 1633 action->setStatusTip(tr("Search for a transform from the installed plugins, by name or description"));
Chris@275 1634 action->setShortcut(tr("Ctrl+M"));
Chris@273 1635 connect(action, SIGNAL(triggered()), this, SLOT(findTransform()));
Chris@287 1636 // connect(this, SIGNAL(canAddLayer(bool)), action, SLOT(setEnabled(bool)));
Chris@275 1637 m_keyReference->registerShortcut(action);
Chris@273 1638 m_transformsMenu->addAction(action);
Chris@273 1639 m_rightButtonTransformsMenu->addAction(action);
Chris@273 1640
Chris@211 1641 setupRecentTransformsMenu();
Chris@66 1642 }
Chris@66 1643
Chris@66 1644 void
Chris@66 1645 MainWindow::setupHelpMenu()
Chris@66 1646 {
Chris@448 1647 m_helpMenu = menuBar()->addMenu(tr("&Help"));
Chris@448 1648 m_helpMenu->setTearOffEnabled(true);
Chris@66 1649
Chris@162 1650 m_keyReference->setCategory(tr("Help"));
Chris@162 1651
Chris@168 1652 IconLoader il;
Chris@168 1653
Chris@168 1654 QAction *action = new QAction(il.load("help"),
Chris@138 1655 tr("&Help Reference"), this);
Chris@162 1656 action->setShortcut(tr("F1"));
Chris@66 1657 action->setStatusTip(tr("Open the Sonic Visualiser reference manual"));
Chris@66 1658 connect(action, SIGNAL(triggered()), this, SLOT(help()));
Chris@162 1659 m_keyReference->registerShortcut(action);
Chris@448 1660 m_helpMenu->addAction(action);
Chris@162 1661
Chris@163 1662 action = new QAction(tr("&Key and Mouse Reference"), this);
Chris@162 1663 action->setShortcut(tr("F2"));
Chris@162 1664 action->setStatusTip(tr("Open a window showing the keystrokes you can use in Sonic Visualiser"));
Chris@162 1665 connect(action, SIGNAL(triggered()), this, SLOT(keyReference()));
Chris@162 1666 m_keyReference->registerShortcut(action);
Chris@448 1667 m_helpMenu->addAction(action);
Chris@66 1668
Chris@164 1669 action = new QAction(tr("Sonic Visualiser on the &Web"), this);
Chris@164 1670 action->setStatusTip(tr("Open the Sonic Visualiser website"));
Chris@164 1671 connect(action, SIGNAL(triggered()), this, SLOT(website()));
Chris@448 1672 m_helpMenu->addAction(action);
Chris@164 1673
Chris@66 1674 action = new QAction(tr("&About Sonic Visualiser"), this);
Chris@66 1675 action->setStatusTip(tr("Show information about Sonic Visualiser"));
Chris@66 1676 connect(action, SIGNAL(triggered()), this, SLOT(about()));
Chris@448 1677 m_helpMenu->addAction(action);
Chris@0 1678 }
Chris@0 1679
Chris@0 1680 void
Chris@0 1681 MainWindow::setupRecentFilesMenu()
Chris@0 1682 {
Chris@0 1683 m_recentFilesMenu->clear();
Chris@34 1684 vector<QString> files = m_recentFiles.getRecent();
Chris@0 1685 for (size_t i = 0; i < files.size(); ++i) {
Chris@0 1686 QAction *action = new QAction(files[i], this);
Chris@0 1687 connect(action, SIGNAL(triggered()), this, SLOT(openRecentFile()));
Chris@162 1688 if (i == 0) {
Chris@162 1689 action->setShortcut(tr("Ctrl+R"));
Chris@162 1690 m_keyReference->registerShortcut
Chris@163 1691 (tr("Re-open"),
Chris@163 1692 action->shortcut(),
Chris@163 1693 tr("Re-open the current or most recently opened file"));
Chris@162 1694 }
Chris@0 1695 m_recentFilesMenu->addAction(action);
Chris@0 1696 }
Chris@0 1697 }
Chris@0 1698
Chris@0 1699 void
Chris@423 1700 MainWindow::setupTemplatesMenu()
Chris@423 1701 {
Chris@423 1702 m_templatesMenu->clear();
Chris@423 1703
Chris@455 1704 QAction *defaultAction = new QAction(tr("Standard Waveform"), this);
Chris@435 1705 defaultAction->setObjectName("default");
Chris@435 1706 connect(defaultAction, SIGNAL(triggered()), this, SLOT(applyTemplate()));
Chris@435 1707 m_templatesMenu->addAction(defaultAction);
Chris@435 1708
Chris@435 1709 m_templatesMenu->addSeparator();
Chris@435 1710
Chris@435 1711 QAction *action = 0;
Chris@435 1712
Chris@435 1713 QStringList templates = ResourceFinder().getResourceFiles("templates", "svt");
Chris@435 1714
Chris@436 1715 bool havePersonal = false;
Chris@436 1716
Chris@435 1717 // (ordered by name)
Chris@435 1718 std::set<QString> byName;
Chris@435 1719 foreach (QString t, templates) {
Chris@436 1720 if (!t.startsWith(":")) havePersonal = true;
Chris@435 1721 byName.insert(QFileInfo(t).baseName());
Chris@435 1722 }
Chris@435 1723
Chris@435 1724 foreach (QString t, byName) {
Chris@435 1725 if (t.toLower() == "default") continue;
Chris@435 1726 action = new QAction(t, this);
Chris@435 1727 connect(action, SIGNAL(triggered()), this, SLOT(applyTemplate()));
Chris@435 1728 m_templatesMenu->addAction(action);
Chris@435 1729 }
Chris@435 1730
Chris@435 1731 if (!templates.empty()) m_templatesMenu->addSeparator();
Chris@435 1732
Chris@435 1733 if (!m_templateWatcher) {
Chris@435 1734 m_templateWatcher = new QFileSystemWatcher(this);
Chris@435 1735 m_templateWatcher->addPath(ResourceFinder().getResourceSaveDir("templates"));
Chris@435 1736 connect(m_templateWatcher, SIGNAL(directoryChanged(const QString &)),
Chris@435 1737 this, SLOT(setupTemplatesMenu()));
Chris@435 1738 }
Chris@436 1739
Chris@436 1740 QAction *setDefaultAction = new QAction(tr("Choose Default Template..."), this);
Chris@436 1741 setDefaultAction->setObjectName("set_default_template");
Chris@436 1742 connect(setDefaultAction, SIGNAL(triggered()), this, SLOT(preferences()));
Chris@436 1743 m_templatesMenu->addSeparator();
Chris@436 1744 m_templatesMenu->addAction(setDefaultAction);
Chris@436 1745
Chris@436 1746 m_manageTemplatesAction->setEnabled(havePersonal);
Chris@435 1747 }
Chris@435 1748
Chris@423 1749
Chris@423 1750 void
Chris@211 1751 MainWindow::setupRecentTransformsMenu()
Chris@34 1752 {
Chris@211 1753 m_recentTransformsMenu->clear();
Chris@211 1754 vector<QString> transforms = m_recentTransforms.getRecent();
Chris@34 1755 for (size_t i = 0; i < transforms.size(); ++i) {
Chris@211 1756 TransformActionReverseMap::iterator ti =
Chris@34 1757 m_transformActionsReverse.find(transforms[i]);
Chris@34 1758 if (ti == m_transformActionsReverse.end()) {
Chris@211 1759 std::cerr << "WARNING: MainWindow::setupRecentTransformsMenu: "
Chris@34 1760 << "Unknown transform \"" << transforms[i].toStdString()
Chris@34 1761 << "\" in recent transforms list" << std::endl;
Chris@34 1762 continue;
Chris@34 1763 }
Chris@162 1764 if (i == 0) {
Chris@162 1765 ti->second->setShortcut(tr("Ctrl+T"));
Chris@162 1766 m_keyReference->registerShortcut
Chris@211 1767 (tr("Repeat Transform"),
Chris@162 1768 ti->second->shortcut(),
Chris@163 1769 tr("Re-select the most recently run transform"));
Chris@216 1770 } else {
Chris@216 1771 ti->second->setShortcut(QString(""));
Chris@162 1772 }
Chris@211 1773 m_recentTransformsMenu->addAction(ti->second);
Chris@34 1774 }
Chris@34 1775 }
Chris@34 1776
Chris@34 1777 void
Chris@95 1778 MainWindow::setupExistingLayersMenus()
Chris@0 1779 {
Chris@0 1780 if (!m_existingLayersMenu) return; // should have been created by setupMenus
Chris@0 1781
Chris@438 1782 // SVDEBUG << "MainWindow::setupExistingLayersMenu" << endl;
Chris@0 1783
Chris@0 1784 m_existingLayersMenu->clear();
Chris@0 1785 m_existingLayerActions.clear();
Chris@0 1786
Chris@95 1787 m_sliceMenu->clear();
Chris@95 1788 m_sliceActions.clear();
Chris@95 1789
Chris@168 1790 IconLoader il;
Chris@168 1791
Chris@33 1792 vector<Layer *> orderedLayers;
Chris@33 1793 set<Layer *> observedLayers;
Chris@95 1794 set<Layer *> sliceableLayers;
Chris@95 1795
Chris@95 1796 LayerFactory *factory = LayerFactory::getInstance();
Chris@0 1797
Chris@0 1798 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@0 1799
Chris@0 1800 Pane *pane = m_paneStack->getPane(i);
Chris@0 1801 if (!pane) continue;
Chris@0 1802
Chris@0 1803 for (int j = 0; j < pane->getLayerCount(); ++j) {
Chris@0 1804
Chris@0 1805 Layer *layer = pane->getLayer(j);
Chris@0 1806 if (!layer) continue;
Chris@0 1807 if (observedLayers.find(layer) != observedLayers.end()) {
Chris@137 1808 // std::cerr << "found duplicate layer " << layer << std::endl;
Chris@0 1809 continue;
Chris@0 1810 }
Chris@0 1811
Chris@0 1812 // std::cerr << "found new layer " << layer << " (name = "
Chris@432 1813 // << layer->getLayerPresentationName() << ")" << std::endl;
Chris@0 1814
Chris@0 1815 orderedLayers.push_back(layer);
Chris@0 1816 observedLayers.insert(layer);
Chris@95 1817
Chris@95 1818 if (factory->isLayerSliceable(layer)) {
Chris@95 1819 sliceableLayers.insert(layer);
Chris@95 1820 }
Chris@0 1821 }
Chris@0 1822 }
Chris@0 1823
Chris@33 1824 map<QString, int> observedNames;
Chris@0 1825
Chris@137 1826 for (size_t i = 0; i < orderedLayers.size(); ++i) {
Chris@0 1827
Chris@95 1828 Layer *layer = orderedLayers[i];
Chris@95 1829
Chris@95 1830 QString name = layer->getLayerPresentationName();
Chris@0 1831 int n = ++observedNames[name];
Chris@0 1832 if (n > 1) name = QString("%1 <%2>").arg(name).arg(n);
Chris@0 1833
Chris@168 1834 QIcon icon = il.load(factory->getLayerIconName
Chris@168 1835 (factory->getLayerType(layer)));
Chris@95 1836
Chris@95 1837 QAction *action = new QAction(icon, name, this);
Chris@0 1838 connect(action, SIGNAL(triggered()), this, SLOT(addLayer()));
Chris@0 1839 connect(this, SIGNAL(canAddLayer(bool)), action, SLOT(setEnabled(bool)));
Chris@95 1840 m_existingLayerActions[action] = layer;
Chris@0 1841
Chris@0 1842 m_existingLayersMenu->addAction(action);
Chris@95 1843
Chris@95 1844 if (sliceableLayers.find(layer) != sliceableLayers.end()) {
Chris@95 1845 action = new QAction(icon, name, this);
Chris@95 1846 connect(action, SIGNAL(triggered()), this, SLOT(addLayer()));
Chris@95 1847 connect(this, SIGNAL(canAddLayer(bool)), action, SLOT(setEnabled(bool)));
Chris@95 1848 m_sliceActions[action] = layer;
Chris@95 1849 m_sliceMenu->addAction(action);
Chris@95 1850 }
Chris@0 1851 }
Chris@95 1852
Chris@95 1853 m_sliceMenu->setEnabled(!m_sliceActions.empty());
Chris@0 1854 }
Chris@0 1855
Chris@0 1856 void
Chris@0 1857 MainWindow::setupToolbars()
Chris@0 1858 {
Chris@162 1859 m_keyReference->setCategory(tr("Playback and Transport Controls"));
Chris@162 1860
Chris@168 1861 IconLoader il;
Chris@168 1862
Chris@155 1863 QMenu *menu = m_playbackMenu = menuBar()->addMenu(tr("Play&back"));
Chris@155 1864 menu->setTearOffEnabled(true);
Chris@155 1865 m_rightButtonMenu->addSeparator();
Chris@155 1866 m_rightButtonPlaybackMenu = m_rightButtonMenu->addMenu(tr("Playback"));
Chris@155 1867
mathieu@439 1868 m_playbackToolBar = addToolBar(tr("Playback Toolbar"));
mathieu@439 1869 m_rwdStartAction = m_playbackToolBar->addAction(il.load("rewind-start"),
mathieu@466 1870 tr("Rewind to Start"));
Chris@265 1871 m_rwdStartAction->setShortcut(tr("Home"));
Chris@265 1872 m_rwdStartAction->setStatusTip(tr("Rewind to the start"));
Chris@265 1873 connect(m_rwdStartAction, SIGNAL(triggered()), this, SLOT(rewindStart()));
Chris@265 1874 connect(this, SIGNAL(canPlay(bool)), m_rwdStartAction, SLOT(setEnabled(bool)));
Chris@265 1875
mathieu@439 1876 m_rwdAction = m_playbackToolBar->addAction(il.load("rewind"), tr("Rewind"));
Chris@155 1877 m_rwdAction->setShortcut(tr("PgUp"));
Chris@163 1878 m_rwdAction->setStatusTip(tr("Rewind to the previous time instant or time ruler notch"));
Chris@155 1879 connect(m_rwdAction, SIGNAL(triggered()), this, SLOT(rewind()));
Chris@155 1880 connect(this, SIGNAL(canRewind(bool)), m_rwdAction, SLOT(setEnabled(bool)));
Chris@155 1881
Chris@323 1882 m_rwdSimilarAction = new QAction(tr("Rewind to Similar Point"), this);
Chris@323 1883 m_rwdSimilarAction->setShortcut(tr("Shift+PgUp"));
Chris@323 1884 m_rwdSimilarAction->setStatusTip(tr("Rewind to the previous similarly valued time instant"));
Chris@323 1885 connect(m_rwdSimilarAction, SIGNAL(triggered()), this, SLOT(rewindSimilar()));
Chris@323 1886 connect(this, SIGNAL(canRewind(bool)), m_rwdSimilarAction, SLOT(setEnabled(bool)));
Chris@323 1887
mathieu@439 1888 m_playAction = m_playbackToolBar->addAction(il.load("playpause"),
Chris@265 1889 tr("Play / Pause"));
Chris@265 1890 m_playAction->setCheckable(true);
Chris@265 1891 m_playAction->setShortcut(tr("Space"));
Chris@265 1892 m_playAction->setStatusTip(tr("Start or stop playback from the current position"));
Chris@265 1893 connect(m_playAction, SIGNAL(triggered()), this, SLOT(play()));
Chris@0 1894 connect(m_playSource, SIGNAL(playStatusChanged(bool)),
Chris@265 1895 m_playAction, SLOT(setChecked(bool)));
Chris@305 1896 connect(m_playSource, SIGNAL(playStatusChanged(bool)),
Chris@305 1897 this, SLOT(playStatusChanged(bool)));
Chris@265 1898 connect(this, SIGNAL(canPlay(bool)), m_playAction, SLOT(setEnabled(bool)));
Chris@155 1899
mathieu@439 1900 m_ffwdAction = m_playbackToolBar->addAction(il.load("ffwd"),
Chris@286 1901 tr("Fast Forward"));
Chris@155 1902 m_ffwdAction->setShortcut(tr("PgDown"));
Chris@163 1903 m_ffwdAction->setStatusTip(tr("Fast-forward to the next time instant or time ruler notch"));
Chris@155 1904 connect(m_ffwdAction, SIGNAL(triggered()), this, SLOT(ffwd()));
Chris@155 1905 connect(this, SIGNAL(canFfwd(bool)), m_ffwdAction, SLOT(setEnabled(bool)));
Chris@155 1906
Chris@323 1907 m_ffwdSimilarAction = new QAction(tr("Fast Forward to Similar Point"), this);
Chris@323 1908 m_ffwdSimilarAction->setShortcut(tr("Shift+PgDown"));
Chris@323 1909 m_ffwdSimilarAction->setStatusTip(tr("Fast-forward to the next similarly valued time instant"));
Chris@323 1910 connect(m_ffwdSimilarAction, SIGNAL(triggered()), this, SLOT(ffwdSimilar()));
Chris@323 1911 connect(this, SIGNAL(canFfwd(bool)), m_ffwdSimilarAction, SLOT(setEnabled(bool)));
Chris@323 1912
mathieu@439 1913 m_ffwdEndAction = m_playbackToolBar->addAction(il.load("ffwd-end"),
Chris@265 1914 tr("Fast Forward to End"));
Chris@265 1915 m_ffwdEndAction->setShortcut(tr("End"));
Chris@265 1916 m_ffwdEndAction->setStatusTip(tr("Fast-forward to the end"));
Chris@265 1917 connect(m_ffwdEndAction, SIGNAL(triggered()), this, SLOT(ffwdEnd()));
Chris@265 1918 connect(this, SIGNAL(canPlay(bool)), m_ffwdEndAction, SLOT(setEnabled(bool)));
Chris@0 1919
mathieu@439 1920 m_playModeToolBar = addToolBar(tr("Play Mode Toolbar"));
mathieu@439 1921
mathieu@439 1922 m_playSelectionAction = m_playModeToolBar->addAction(il.load("playselection"),
Chris@265 1923 tr("Constrain Playback to Selection"));
Chris@265 1924 m_playSelectionAction->setCheckable(true);
Chris@265 1925 m_playSelectionAction->setChecked(m_viewManager->getPlaySelectionMode());
Chris@265 1926 m_playSelectionAction->setShortcut(tr("s"));
Chris@265 1927 m_playSelectionAction->setStatusTip(tr("Constrain playback to the selected regions"));
Chris@69 1928 connect(m_viewManager, SIGNAL(playSelectionModeChanged(bool)),
Chris@265 1929 m_playSelectionAction, SLOT(setChecked(bool)));
Chris@265 1930 connect(m_playSelectionAction, SIGNAL(triggered()), this, SLOT(playSelectionToggled()));
Chris@265 1931 connect(this, SIGNAL(canPlaySelection(bool)), m_playSelectionAction, SLOT(setEnabled(bool)));
Chris@265 1932
mathieu@439 1933 m_playLoopAction = m_playModeToolBar->addAction(il.load("playloop"),
Chris@265 1934 tr("Loop Playback"));
Chris@265 1935 m_playLoopAction->setCheckable(true);
Chris@265 1936 m_playLoopAction->setChecked(m_viewManager->getPlayLoopMode());
Chris@265 1937 m_playLoopAction->setShortcut(tr("l"));
Chris@265 1938 m_playLoopAction->setStatusTip(tr("Loop playback"));
Chris@69 1939 connect(m_viewManager, SIGNAL(playLoopModeChanged(bool)),
Chris@265 1940 m_playLoopAction, SLOT(setChecked(bool)));
Chris@265 1941 connect(m_playLoopAction, SIGNAL(triggered()), this, SLOT(playLoopToggled()));
Chris@265 1942 connect(this, SIGNAL(canPlay(bool)), m_playLoopAction, SLOT(setEnabled(bool)));
Chris@155 1943
mathieu@439 1944 m_soloAction = m_playModeToolBar->addAction(il.load("solo"),
Chris@323 1945 tr("Solo Current Pane"));
Chris@207 1946 m_soloAction->setCheckable(true);
Chris@207 1947 m_soloAction->setChecked(m_viewManager->getPlaySoloMode());
Chris@207 1948 m_prevSolo = m_viewManager->getPlaySoloMode();
Chris@207 1949 m_soloAction->setShortcut(tr("o"));
Chris@207 1950 m_soloAction->setStatusTip(tr("Solo the current pane during playback"));
Chris@180 1951 connect(m_viewManager, SIGNAL(playSoloModeChanged(bool)),
Chris@207 1952 m_soloAction, SLOT(setChecked(bool)));
Chris@207 1953 connect(m_soloAction, SIGNAL(triggered()), this, SLOT(playSoloToggled()));
Chris@207 1954 connect(this, SIGNAL(canChangeSolo(bool)), m_soloAction, SLOT(setEnabled(bool)));
Chris@180 1955
mathieu@458 1956 //QAction *alAction = 0;
Chris@208 1957 if (Document::canAlign()) {
mathieu@458 1958 m_alAction = m_playModeToolBar->addAction(il.load("align"),
Chris@208 1959 tr("Align File Timelines"));
mathieu@458 1960 m_alAction->setCheckable(true);
mathieu@458 1961 m_alAction->setChecked(m_viewManager->getAlignMode());
mathieu@458 1962 m_alAction->setStatusTip(tr("Treat multiple audio files as versions of the same work, and align their timelines"));
Chris@208 1963 connect(m_viewManager, SIGNAL(alignModeChanged(bool)),
mathieu@458 1964 m_alAction, SLOT(setChecked(bool)));
mathieu@458 1965 connect(m_alAction, SIGNAL(triggered()), this, SLOT(alignToggled()));
mathieu@458 1966 connect(this, SIGNAL(canAlign(bool)), m_alAction, SLOT(setEnabled(bool)));
Chris@208 1967 }
Chris@206 1968
Chris@265 1969 m_keyReference->registerShortcut(m_playAction);
Chris@265 1970 m_keyReference->registerShortcut(m_playSelectionAction);
Chris@265 1971 m_keyReference->registerShortcut(m_playLoopAction);
Chris@207 1972 m_keyReference->registerShortcut(m_soloAction);
mathieu@458 1973 if (m_alAction) m_keyReference->registerShortcut(m_alAction);
Chris@162 1974 m_keyReference->registerShortcut(m_rwdAction);
Chris@162 1975 m_keyReference->registerShortcut(m_ffwdAction);
Chris@323 1976 m_keyReference->registerShortcut(m_rwdSimilarAction);
Chris@323 1977 m_keyReference->registerShortcut(m_ffwdSimilarAction);
Chris@265 1978 m_keyReference->registerShortcut(m_rwdStartAction);
Chris@265 1979 m_keyReference->registerShortcut(m_ffwdEndAction);
Chris@265 1980
Chris@265 1981 menu->addAction(m_playAction);
Chris@265 1982 menu->addAction(m_playSelectionAction);
Chris@265 1983 menu->addAction(m_playLoopAction);
Chris@207 1984 menu->addAction(m_soloAction);
mathieu@458 1985 if (m_alAction) menu->addAction(m_alAction);
Chris@155 1986 menu->addSeparator();
Chris@155 1987 menu->addAction(m_rwdAction);
Chris@155 1988 menu->addAction(m_ffwdAction);
Chris@155 1989 menu->addSeparator();
Chris@323 1990 menu->addAction(m_rwdSimilarAction);
Chris@323 1991 menu->addAction(m_ffwdSimilarAction);
Chris@323 1992 menu->addSeparator();
Chris@265 1993 menu->addAction(m_rwdStartAction);
Chris@265 1994 menu->addAction(m_ffwdEndAction);
Chris@155 1995 menu->addSeparator();
Chris@155 1996
Chris@265 1997 m_rightButtonPlaybackMenu->addAction(m_playAction);
Chris@265 1998 m_rightButtonPlaybackMenu->addAction(m_playSelectionAction);
Chris@265 1999 m_rightButtonPlaybackMenu->addAction(m_playLoopAction);
Chris@207 2000 m_rightButtonPlaybackMenu->addAction(m_soloAction);
mathieu@458 2001 if (m_alAction) m_rightButtonPlaybackMenu->addAction(m_alAction);
Chris@155 2002 m_rightButtonPlaybackMenu->addSeparator();
Chris@155 2003 m_rightButtonPlaybackMenu->addAction(m_rwdAction);
Chris@155 2004 m_rightButtonPlaybackMenu->addAction(m_ffwdAction);
Chris@155 2005 m_rightButtonPlaybackMenu->addSeparator();
Chris@265 2006 m_rightButtonPlaybackMenu->addAction(m_rwdStartAction);
Chris@265 2007 m_rightButtonPlaybackMenu->addAction(m_ffwdEndAction);
Chris@155 2008 m_rightButtonPlaybackMenu->addSeparator();
Chris@155 2009
Chris@155 2010 QAction *fastAction = menu->addAction(tr("Speed Up"));
Chris@155 2011 fastAction->setShortcut(tr("Ctrl+PgUp"));
Chris@163 2012 fastAction->setStatusTip(tr("Time-stretch playback to speed it up without changing pitch"));
Chris@155 2013 connect(fastAction, SIGNAL(triggered()), this, SLOT(speedUpPlayback()));
Chris@155 2014 connect(this, SIGNAL(canSpeedUpPlayback(bool)), fastAction, SLOT(setEnabled(bool)));
Chris@155 2015
Chris@155 2016 QAction *slowAction = menu->addAction(tr("Slow Down"));
Chris@155 2017 slowAction->setShortcut(tr("Ctrl+PgDown"));
Chris@163 2018 slowAction->setStatusTip(tr("Time-stretch playback to slow it down without changing pitch"));
Chris@155 2019 connect(slowAction, SIGNAL(triggered()), this, SLOT(slowDownPlayback()));
Chris@155 2020 connect(this, SIGNAL(canSlowDownPlayback(bool)), slowAction, SLOT(setEnabled(bool)));
Chris@155 2021
Chris@155 2022 QAction *normalAction = menu->addAction(tr("Restore Normal Speed"));
Chris@155 2023 normalAction->setShortcut(tr("Ctrl+Home"));
Chris@163 2024 normalAction->setStatusTip(tr("Restore non-time-stretched playback"));
Chris@155 2025 connect(normalAction, SIGNAL(triggered()), this, SLOT(restoreNormalPlayback()));
Chris@155 2026 connect(this, SIGNAL(canChangePlaybackSpeed(bool)), normalAction, SLOT(setEnabled(bool)));
Chris@155 2027
Chris@162 2028 m_keyReference->registerShortcut(fastAction);
Chris@162 2029 m_keyReference->registerShortcut(slowAction);
Chris@162 2030 m_keyReference->registerShortcut(normalAction);
Chris@162 2031
Chris@155 2032 m_rightButtonPlaybackMenu->addAction(fastAction);
Chris@155 2033 m_rightButtonPlaybackMenu->addAction(slowAction);
Chris@155 2034 m_rightButtonPlaybackMenu->addAction(normalAction);
Chris@0 2035
mathieu@439 2036 m_editToolBar = addToolBar(tr("Edit Toolbar"));
mathieu@439 2037 CommandHistory::getInstance()->registerToolbar(m_editToolBar);
Chris@0 2038
Chris@162 2039 m_keyReference->setCategory(tr("Tool Selection"));
Chris@162 2040
mathieu@439 2041 m_toolsToolBar = addToolBar(tr("Tools Toolbar"));
Chris@0 2042 QActionGroup *group = new QActionGroup(this);
Chris@0 2043
mathieu@439 2044 QAction *action = m_toolsToolBar->addAction(il.load("navigate"),
Chris@155 2045 tr("Navigate"));
Chris@0 2046 action->setCheckable(true);
Chris@0 2047 action->setChecked(true);
Chris@0 2048 action->setShortcut(tr("1"));
Chris@90 2049 action->setStatusTip(tr("Navigate"));
Chris@0 2050 connect(action, SIGNAL(triggered()), this, SLOT(toolNavigateSelected()));
Chris@0 2051 group->addAction(action);
Chris@162 2052 m_keyReference->registerShortcut(action);
Chris@0 2053 m_toolActions[ViewManager::NavigateMode] = action;
Chris@0 2054
mathieu@439 2055 action = m_toolsToolBar->addAction(il.load("select"),
Chris@0 2056 tr("Select"));
Chris@0 2057 action->setCheckable(true);
Chris@0 2058 action->setShortcut(tr("2"));
Chris@90 2059 action->setStatusTip(tr("Select ranges"));
Chris@0 2060 connect(action, SIGNAL(triggered()), this, SLOT(toolSelectSelected()));
Chris@0 2061 group->addAction(action);
Chris@162 2062 m_keyReference->registerShortcut(action);
Chris@0 2063 m_toolActions[ViewManager::SelectMode] = action;
Chris@0 2064
mathieu@439 2065 action = m_toolsToolBar->addAction(il.load("move"),
Chris@0 2066 tr("Edit"));
Chris@0 2067 action->setCheckable(true);
Chris@0 2068 action->setShortcut(tr("3"));
Chris@90 2069 action->setStatusTip(tr("Edit items in layer"));
Chris@0 2070 connect(action, SIGNAL(triggered()), this, SLOT(toolEditSelected()));
Chris@0 2071 connect(this, SIGNAL(canEditLayer(bool)), action, SLOT(setEnabled(bool)));
Chris@0 2072 group->addAction(action);
Chris@162 2073 m_keyReference->registerShortcut(action);
Chris@0 2074 m_toolActions[ViewManager::EditMode] = action;
Chris@0 2075
mathieu@439 2076 action = m_toolsToolBar->addAction(il.load("draw"),
Chris@0 2077 tr("Draw"));
Chris@0 2078 action->setCheckable(true);
Chris@0 2079 action->setShortcut(tr("4"));
Chris@90 2080 action->setStatusTip(tr("Draw new items in layer"));
Chris@0 2081 connect(action, SIGNAL(triggered()), this, SLOT(toolDrawSelected()));
Chris@0 2082 connect(this, SIGNAL(canEditLayer(bool)), action, SLOT(setEnabled(bool)));
Chris@0 2083 group->addAction(action);
Chris@162 2084 m_keyReference->registerShortcut(action);
Chris@0 2085 m_toolActions[ViewManager::DrawMode] = action;
Chris@0 2086
mathieu@439 2087 action = m_toolsToolBar->addAction(il.load("erase"),
Chris@217 2088 tr("Erase"));
Chris@217 2089 action->setCheckable(true);
Chris@217 2090 action->setShortcut(tr("5"));
Chris@217 2091 action->setStatusTip(tr("Erase items from layer"));
Chris@217 2092 connect(action, SIGNAL(triggered()), this, SLOT(toolEraseSelected()));
Chris@217 2093 connect(this, SIGNAL(canEditLayer(bool)), action, SLOT(setEnabled(bool)));
Chris@217 2094 group->addAction(action);
Chris@217 2095 m_keyReference->registerShortcut(action);
Chris@217 2096 m_toolActions[ViewManager::EraseMode] = action;
Chris@217 2097
mathieu@439 2098 action = m_toolsToolBar->addAction(il.load("measure"), tr("Measure"));
Chris@151 2099 action->setCheckable(true);
Chris@217 2100 action->setShortcut(tr("6"));
Chris@151 2101 action->setStatusTip(tr("Make measurements in layer"));
Chris@151 2102 connect(action, SIGNAL(triggered()), this, SLOT(toolMeasureSelected()));
Chris@169 2103 connect(this, SIGNAL(canMeasureLayer(bool)), action, SLOT(setEnabled(bool)));
Chris@151 2104 group->addAction(action);
Chris@162 2105 m_keyReference->registerShortcut(action);
Chris@151 2106 m_toolActions[ViewManager::MeasureMode] = action;
Chris@151 2107
Chris@0 2108 toolNavigateSelected();
Chris@163 2109
Chris@163 2110 Pane::registerShortcuts(*m_keyReference);
Chris@0 2111 }
Chris@0 2112
Chris@0 2113 void
Chris@265 2114 MainWindow::connectLayerEditDialog(ModelDataTableDialog *dialog)
Chris@265 2115 {
Chris@265 2116 MainWindowBase::connectLayerEditDialog(dialog);
Chris@265 2117 QToolBar *toolbar = dialog->getPlayToolbar();
Chris@265 2118 if (toolbar) {
Chris@265 2119 toolbar->addAction(m_rwdStartAction);
Chris@265 2120 toolbar->addAction(m_rwdAction);
Chris@265 2121 toolbar->addAction(m_playAction);
Chris@265 2122 toolbar->addAction(m_ffwdAction);
Chris@265 2123 toolbar->addAction(m_ffwdEndAction);
Chris@265 2124 }
Chris@265 2125 }
Chris@265 2126
Chris@265 2127 void
Chris@0 2128 MainWindow::updateMenuStates()
Chris@0 2129 {
Chris@200 2130 MainWindowBase::updateMenuStates();
Chris@200 2131
Chris@117 2132 Pane *currentPane = 0;
Chris@117 2133 Layer *currentLayer = 0;
Chris@117 2134
Chris@117 2135 if (m_paneStack) currentPane = m_paneStack->getCurrentPane();
Chris@117 2136 if (currentPane) currentLayer = currentPane->getSelectedLayer();
Chris@117 2137
Chris@0 2138 bool haveCurrentPane =
Chris@117 2139 (currentPane != 0);
Chris@0 2140 bool haveCurrentLayer =
Chris@117 2141 (haveCurrentPane &&
Chris@117 2142 (currentLayer != 0));
Chris@206 2143 bool havePlayTarget =
Chris@206 2144 (m_playTarget != 0);
Chris@0 2145 bool haveSelection =
Chris@0 2146 (m_viewManager &&
Chris@0 2147 !m_viewManager->getSelections().empty());
Chris@0 2148 bool haveCurrentEditableLayer =
Chris@0 2149 (haveCurrentLayer &&
Chris@117 2150 currentLayer->isLayerEditable());
Chris@0 2151 bool haveCurrentTimeInstantsLayer =
Chris@0 2152 (haveCurrentLayer &&
Chris@117 2153 dynamic_cast<TimeInstantLayer *>(currentLayer));
Chris@0 2154 bool haveCurrentTimeValueLayer =
Chris@0 2155 (haveCurrentLayer &&
Chris@117 2156 dynamic_cast<TimeValueLayer *>(currentLayer));
Chris@207 2157
Chris@314 2158 bool alignMode = m_viewManager && m_viewManager->getAlignMode();
Chris@314 2159 emit canChangeSolo(havePlayTarget && !alignMode);
Chris@207 2160 emit canAlign(havePlayTarget && m_document && m_document->canAlign());
Chris@206 2161
Chris@200 2162 emit canChangePlaybackSpeed(true);
Chris@200 2163 int v = m_playSpeed->value();
Chris@200 2164 emit canSpeedUpPlayback(v < m_playSpeed->maximum());
Chris@200 2165 emit canSlowDownPlayback(v > m_playSpeed->minimum());
Chris@155 2166
Chris@164 2167 if (m_viewManager &&
Chris@164 2168 (m_viewManager->getToolMode() == ViewManager::MeasureMode)) {
Chris@164 2169 emit canDeleteSelection(haveCurrentLayer);
Chris@164 2170 m_deleteSelectedAction->setText(tr("&Delete Current Measurement"));
Chris@164 2171 m_deleteSelectedAction->setStatusTip(tr("Delete the measurement currently under the mouse pointer"));
Chris@164 2172 } else {
Chris@164 2173 emit canDeleteSelection(haveSelection && haveCurrentEditableLayer);
Chris@164 2174 m_deleteSelectedAction->setText(tr("&Delete Selected Items"));
Chris@164 2175 m_deleteSelectedAction->setStatusTip(tr("Delete items in current selection from the current layer"));
Chris@164 2176 }
Chris@164 2177
Chris@155 2178 if (m_ffwdAction && m_rwdAction) {
Chris@155 2179 if (haveCurrentTimeInstantsLayer) {
Chris@155 2180 m_ffwdAction->setText(tr("Fast Forward to Next Instant"));
Chris@155 2181 m_ffwdAction->setStatusTip(tr("Fast forward to the next time instant in the current layer"));
Chris@155 2182 m_rwdAction->setText(tr("Rewind to Previous Instant"));
Chris@155 2183 m_rwdAction->setStatusTip(tr("Rewind to the previous time instant in the current layer"));
Chris@155 2184 } else if (haveCurrentTimeValueLayer) {
Chris@155 2185 m_ffwdAction->setText(tr("Fast Forward to Next Point"));
Chris@155 2186 m_ffwdAction->setStatusTip(tr("Fast forward to the next point in the current layer"));
Chris@155 2187 m_rwdAction->setText(tr("Rewind to Previous Point"));
Chris@155 2188 m_rwdAction->setStatusTip(tr("Rewind to the previous point in the current layer"));
Chris@155 2189 } else {
Chris@155 2190 m_ffwdAction->setText(tr("Fast Forward"));
Chris@155 2191 m_ffwdAction->setStatusTip(tr("Fast forward"));
Chris@155 2192 m_rwdAction->setText(tr("Rewind"));
Chris@155 2193 m_rwdAction->setStatusTip(tr("Rewind"));
Chris@155 2194 }
Chris@155 2195 }
Chris@0 2196 }
Chris@0 2197
Chris@0 2198 void
Chris@0 2199 MainWindow::updateDescriptionLabel()
Chris@0 2200 {
Chris@0 2201 if (!getMainModel()) {
Chris@0 2202 m_descriptionLabel->setText(tr("No audio file loaded."));
Chris@0 2203 return;
Chris@0 2204 }
Chris@0 2205
Chris@0 2206 QString description;
Chris@0 2207
Chris@0 2208 size_t ssr = getMainModel()->getSampleRate();
Chris@0 2209 size_t tsr = ssr;
Chris@0 2210 if (m_playSource) tsr = m_playSource->getTargetSampleRate();
Chris@0 2211
Chris@0 2212 if (ssr != tsr) {
Chris@0 2213 description = tr("%1Hz (resampling to %2Hz)").arg(ssr).arg(tsr);
Chris@0 2214 } else {
Chris@0 2215 description = QString("%1Hz").arg(ssr);
Chris@0 2216 }
Chris@0 2217
Chris@0 2218 description = QString("%1 - %2")
Chris@0 2219 .arg(RealTime::frame2RealTime(getMainModel()->getEndFrame(), ssr)
Chris@0 2220 .toText(false).c_str())
Chris@0 2221 .arg(description);
Chris@0 2222
Chris@0 2223 m_descriptionLabel->setText(description);
Chris@0 2224 }
Chris@0 2225
Chris@0 2226 void
Chris@0 2227 MainWindow::documentModified()
Chris@0 2228 {
Chris@200 2229 //!!!
Chris@200 2230 MainWindowBase::documentModified();
Chris@0 2231 }
Chris@0 2232
Chris@0 2233 void
Chris@0 2234 MainWindow::documentRestored()
Chris@0 2235 {
Chris@200 2236 //!!!
Chris@200 2237 MainWindowBase::documentRestored();
Chris@0 2238 }
Chris@0 2239
Chris@0 2240 void
Chris@0 2241 MainWindow::toolNavigateSelected()
Chris@0 2242 {
Chris@0 2243 m_viewManager->setToolMode(ViewManager::NavigateMode);
Chris@0 2244 }
Chris@0 2245
Chris@0 2246 void
Chris@0 2247 MainWindow::toolSelectSelected()
Chris@0 2248 {
Chris@0 2249 m_viewManager->setToolMode(ViewManager::SelectMode);
Chris@0 2250 }
Chris@0 2251
Chris@0 2252 void
Chris@0 2253 MainWindow::toolEditSelected()
Chris@0 2254 {
Chris@0 2255 m_viewManager->setToolMode(ViewManager::EditMode);
Chris@0 2256 }
Chris@0 2257
Chris@0 2258 void
Chris@0 2259 MainWindow::toolDrawSelected()
Chris@0 2260 {
Chris@0 2261 m_viewManager->setToolMode(ViewManager::DrawMode);
Chris@0 2262 }
Chris@0 2263
Chris@151 2264 void
Chris@217 2265 MainWindow::toolEraseSelected()
Chris@217 2266 {
Chris@217 2267 m_viewManager->setToolMode(ViewManager::EraseMode);
Chris@217 2268 }
Chris@217 2269
Chris@217 2270 void
Chris@151 2271 MainWindow::toolMeasureSelected()
Chris@151 2272 {
Chris@151 2273 m_viewManager->setToolMode(ViewManager::MeasureMode);
Chris@151 2274 }
Chris@151 2275
Chris@0 2276 void
Chris@0 2277 MainWindow::importAudio()
Chris@0 2278 {
Chris@88 2279 QString path = getOpenFileName(FileFinder::AudioFile);
Chris@0 2280
Chris@0 2281 if (path != "") {
Chris@417 2282 if (openAudio(path, ReplaceSession) == FileOpenFailed) {
Chris@247 2283 emit hideSplash();
Chris@0 2284 QMessageBox::critical(this, tr("Failed to open file"),
Chris@193 2285 tr("<b>File open failed</b><p>Audio file \"%1\" could not be opened").arg(path));
Chris@0 2286 }
Chris@0 2287 }
Chris@0 2288 }
Chris@0 2289
Chris@0 2290 void
Chris@0 2291 MainWindow::importMoreAudio()
Chris@0 2292 {
Chris@88 2293 QString path = getOpenFileName(FileFinder::AudioFile);
Chris@0 2294
Chris@0 2295 if (path != "") {
Chris@197 2296 if (openAudio(path, CreateAdditionalModel) == FileOpenFailed) {
Chris@247 2297 emit hideSplash();
Chris@0 2298 QMessageBox::critical(this, tr("Failed to open file"),
Chris@193 2299 tr("<b>File open failed</b><p>Audio file \"%1\" could not be opened").arg(path));
Chris@0 2300 }
Chris@0 2301 }
Chris@0 2302 }
Chris@0 2303
mathieu@406 2304 /*
Chris@0 2305 void
Chris@0 2306 MainWindow::exportAudio()
Chris@0 2307 {
Chris@0 2308 if (!getMainModel()) return;
Chris@0 2309
Chris@320 2310 RangeSummarisableTimeValueModel *model = getMainModel();
Chris@320 2311 std::set<RangeSummarisableTimeValueModel *> otherModels;
Chris@320 2312 RangeSummarisableTimeValueModel *current = model;
Chris@320 2313 if (m_paneStack) {
Chris@320 2314 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@320 2315 Pane *pane = m_paneStack->getPane(i);
Chris@320 2316 if (!pane) continue;
Chris@320 2317 for (int j = 0; j < pane->getLayerCount(); ++j) {
Chris@320 2318 Layer *layer = pane->getLayer(j);
Chris@320 2319 if (!layer) continue;
Chris@432 2320 cerr << "layer = " << layer->objectName() << endl;
Chris@320 2321 Model *m = layer->getModel();
Chris@320 2322 RangeSummarisableTimeValueModel *wm =
Chris@320 2323 dynamic_cast<RangeSummarisableTimeValueModel *>(m);
Chris@320 2324 if (wm) {
Chris@432 2325 cerr << "found: " << wm->objectName() << endl;
Chris@320 2326 otherModels.insert(wm);
Chris@320 2327 if (pane == m_paneStack->getCurrentPane()) {
Chris@320 2328 current = wm;
Chris@320 2329 }
Chris@320 2330 }
Chris@320 2331 }
Chris@320 2332 }
Chris@320 2333 }
Chris@320 2334 if (!otherModels.empty()) {
Chris@320 2335 std::map<QString, RangeSummarisableTimeValueModel *> m;
Chris@320 2336 m[tr("1. %2").arg(model->objectName())] = model;
Chris@320 2337 int n = 2;
Chris@320 2338 int c = 0;
Chris@320 2339 for (std::set<RangeSummarisableTimeValueModel *>::const_iterator i
Chris@320 2340 = otherModels.begin();
Chris@320 2341 i != otherModels.end(); ++i) {
Chris@320 2342 if (*i == model) continue;
Chris@320 2343 m[tr("%1. %2").arg(n).arg((*i)->objectName())] = *i;
Chris@320 2344 ++n;
Chris@320 2345 if (*i == current) c = n-1;
Chris@320 2346 }
Chris@320 2347 QStringList items;
Chris@320 2348 for (std::map<QString, RangeSummarisableTimeValueModel *>
Chris@320 2349 ::const_iterator i = m.begin();
Chris@320 2350 i != m.end(); ++i) {
Chris@320 2351 items << i->first;
Chris@320 2352 }
Chris@325 2353 if (items.size() > 1) {
Chris@325 2354 bool ok = false;
Chris@325 2355 QString item = QInputDialog::getItem
Chris@325 2356 (this, tr("Select audio file to export"),
Chris@325 2357 tr("Which audio file do you want to export from?"),
Chris@325 2358 items, c, false, &ok);
Chris@325 2359 if (!ok || item.isEmpty()) return;
Chris@325 2360 if (m.find(item) == m.end()) {
Chris@325 2361 cerr << "WARNING: Model " << item.toStdString()
Chris@325 2362 << " not found in list!" << endl;
Chris@325 2363 } else {
Chris@325 2364 model = m[item];
Chris@325 2365 }
Chris@320 2366 }
Chris@320 2367 }
Chris@320 2368
Chris@88 2369 QString path = getSaveFileName(FileFinder::AudioFile);
Chris@0 2370 if (path == "") return;
Chris@0 2371
Chris@0 2372 bool ok = false;
Chris@0 2373 QString error;
Chris@0 2374
Chris@0 2375 MultiSelection ms = m_viewManager->getSelection();
Chris@0 2376 MultiSelection::SelectionList selections = m_viewManager->getSelections();
Chris@0 2377
Chris@0 2378 bool multiple = false;
Chris@0 2379
Chris@38 2380 MultiSelection *selectionToWrite = 0;
Chris@38 2381
Chris@38 2382 if (selections.size() == 1) {
Chris@0 2383
Chris@0 2384 QStringList items;
Chris@0 2385 items << tr("Export the selected region only")
Chris@0 2386 << tr("Export the whole audio file");
Chris@0 2387
Chris@0 2388 bool ok = false;
Chris@0 2389 QString item = ListInputDialog::getItem
Chris@0 2390 (this, tr("Select region to export"),
Chris@0 2391 tr("Which region from the original audio file do you want to export?"),
Chris@0 2392 items, 0, &ok);
Chris@0 2393
Chris@0 2394 if (!ok || item.isEmpty()) return;
Chris@0 2395
Chris@38 2396 if (item == items[0]) selectionToWrite = &ms;
Chris@38 2397
Chris@38 2398 } else if (selections.size() > 1) {
Chris@0 2399
Chris@0 2400 QStringList items;
Chris@0 2401 items << tr("Export the selected regions into a single audio file")
Chris@0 2402 << tr("Export the selected regions into separate files")
Chris@0 2403 << tr("Export the whole audio file");
Chris@0 2404
Chris@0 2405 QString item = ListInputDialog::getItem
Chris@0 2406 (this, tr("Select region to export"),
Chris@0 2407 tr("Multiple regions of the original audio file are selected.\nWhat do you want to export?"),
Chris@0 2408 items, 0, &ok);
Chris@0 2409
Chris@0 2410 if (!ok || item.isEmpty()) return;
Chris@0 2411
Chris@0 2412 if (item == items[0]) {
Chris@0 2413
Chris@38 2414 selectionToWrite = &ms;
Chris@38 2415
Chris@38 2416 } else if (item == items[1]) {
Chris@0 2417
Chris@0 2418 multiple = true;
Chris@0 2419
Chris@0 2420 int n = 1;
Chris@0 2421 QString base = path;
Chris@0 2422 base.replace(".wav", "");
Chris@0 2423
Chris@0 2424 for (MultiSelection::SelectionList::iterator i = selections.begin();
Chris@0 2425 i != selections.end(); ++i) {
Chris@0 2426
Chris@0 2427 MultiSelection subms;
Chris@0 2428 subms.setSelection(*i);
Chris@0 2429
Chris@0 2430 QString subpath = QString("%1.%2.wav").arg(base).arg(n);
Chris@0 2431 ++n;
Chris@0 2432
Chris@0 2433 if (QFileInfo(subpath).exists()) {
Chris@0 2434 error = tr("Fragment file %1 already exists, aborting").arg(subpath);
Chris@0 2435 break;
Chris@0 2436 }
Chris@0 2437
Chris@38 2438 WavFileWriter subwriter(subpath,
Chris@320 2439 model->getSampleRate(),
Chris@428 2440 model->getChannelCount(),
Chris@428 2441 WavFileWriter::WriteToTemporary);
Chris@320 2442 subwriter.writeModel(model, &subms);
Chris@0 2443 ok = subwriter.isOK();
Chris@0 2444
Chris@0 2445 if (!ok) {
Chris@0 2446 error = subwriter.getError();
Chris@0 2447 break;
Chris@0 2448 }
Chris@0 2449 }
Chris@0 2450 }
Chris@0 2451 }
Chris@0 2452
Chris@38 2453 if (!multiple) {
Chris@38 2454 WavFileWriter writer(path,
Chris@320 2455 model->getSampleRate(),
Chris@428 2456 model->getChannelCount(),
Chris@428 2457 WavFileWriter::WriteToTemporary);
Chris@320 2458 writer.writeModel(model, selectionToWrite);
Chris@38 2459 ok = writer.isOK();
Chris@38 2460 error = writer.getError();
Chris@0 2461 }
Chris@0 2462
Chris@0 2463 if (ok) {
Chris@310 2464 if (multiple) {
Chris@310 2465 emit activity(tr("Export multiple audio files"));
Chris@310 2466 } else {
Chris@310 2467 emit activity(tr("Export audio to \"%1\"").arg(path));
Chris@34 2468 m_recentFiles.addFile(path);
Chris@0 2469 }
Chris@0 2470 } else {
Chris@0 2471 QMessageBox::critical(this, tr("Failed to write file"), error);
Chris@0 2472 }
Chris@0 2473 }
mathieu@406 2474 */
Chris@0 2475
Chris@0 2476 void
Chris@0 2477 MainWindow::importLayer()
Chris@0 2478 {
Chris@0 2479 Pane *pane = m_paneStack->getCurrentPane();
Chris@0 2480
Chris@0 2481 if (!pane) {
Chris@0 2482 // shouldn't happen, as the menu action should have been disabled
Chris@0 2483 std::cerr << "WARNING: MainWindow::importLayer: no current pane" << std::endl;
Chris@0 2484 return;
Chris@0 2485 }
Chris@0 2486
Chris@0 2487 if (!getMainModel()) {
Chris@0 2488 // shouldn't happen, as the menu action should have been disabled
Chris@0 2489 std::cerr << "WARNING: MainWindow::importLayer: No main model -- hence no default sample rate available" << std::endl;
Chris@0 2490 return;
Chris@0 2491 }
Chris@0 2492
Chris@88 2493 QString path = getOpenFileName(FileFinder::LayerFile);
Chris@0 2494
Chris@0 2495 if (path != "") {
Chris@0 2496
Chris@197 2497 FileOpenStatus status = openLayer(path);
Chris@193 2498
Chris@193 2499 if (status == FileOpenFailed) {
Chris@247 2500 emit hideSplash();
Chris@0 2501 QMessageBox::critical(this, tr("Failed to open file"),
Chris@193 2502 tr("<b>File open failed</b><p>Layer file %1 could not be opened.").arg(path));
Chris@0 2503 return;
Chris@193 2504 } else if (status == FileOpenWrongMode) {
Chris@247 2505 emit hideSplash();
Chris@193 2506 QMessageBox::critical(this, tr("Failed to open file"),
Chris@294 2507 tr("<b>Audio required</b><p>Unable to load layer data from \"%1\" without an audio file.<br>Please load at least one audio file before importing annotations.").arg(path));
Chris@0 2508 }
Chris@0 2509 }
Chris@0 2510 }
Chris@0 2511
Chris@0 2512 void
Chris@0 2513 MainWindow::exportLayer()
Chris@0 2514 {
Chris@0 2515 Pane *pane = m_paneStack->getCurrentPane();
Chris@0 2516 if (!pane) return;
Chris@0 2517
Chris@0 2518 Layer *layer = pane->getSelectedLayer();
Chris@0 2519 if (!layer) return;
Chris@0 2520
Chris@0 2521 Model *model = layer->getModel();
Chris@0 2522 if (!model) return;
Chris@0 2523
Chris@185 2524 FileFinder::FileType type = FileFinder::LayerFileNoMidi;
Chris@185 2525
Chris@185 2526 if (dynamic_cast<NoteModel *>(model)) type = FileFinder::LayerFile;
Chris@185 2527
Chris@185 2528 QString path = getSaveFileName(type);
Chris@0 2529
Chris@0 2530 if (path == "") return;
Chris@0 2531
Chris@0 2532 if (QFileInfo(path).suffix() == "") path += ".svl";
Chris@0 2533
Chris@185 2534 QString suffix = QFileInfo(path).suffix().toLower();
Chris@185 2535
Chris@0 2536 QString error;
Chris@0 2537
Chris@185 2538 if (suffix == "xml" || suffix == "svl") {
Chris@0 2539
Chris@0 2540 QFile file(path);
Chris@0 2541 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
Chris@0 2542 error = tr("Failed to open file %1 for writing").arg(path);
Chris@0 2543 } else {
Chris@0 2544 QTextStream out(&file);
Chris@0 2545 out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
Chris@0 2546 << "<!DOCTYPE sonic-visualiser>\n"
Chris@0 2547 << "<sv>\n"
Chris@0 2548 << " <data>\n";
Chris@0 2549
Chris@0 2550 model->toXml(out, " ");
Chris@0 2551
Chris@0 2552 out << " </data>\n"
Chris@0 2553 << " <display>\n";
Chris@0 2554
Chris@0 2555 layer->toXml(out, " ");
Chris@0 2556
Chris@0 2557 out << " </display>\n"
Chris@0 2558 << "</sv>\n";
Chris@0 2559 }
Chris@0 2560
Chris@185 2561 } else if (suffix == "mid" || suffix == "midi") {
Chris@185 2562
Chris@185 2563 NoteModel *nm = dynamic_cast<NoteModel *>(model);
Chris@185 2564
Chris@185 2565 if (!nm) {
Chris@185 2566 error = tr("Can't export non-note layers to MIDI");
Chris@185 2567 } else {
Chris@185 2568 MIDIFileWriter writer(path, nm);
Chris@185 2569 writer.write();
Chris@185 2570 if (!writer.isOK()) {
Chris@185 2571 error = writer.getError();
Chris@185 2572 }
Chris@185 2573 }
Chris@185 2574
Chris@291 2575 } else if (suffix == "ttl" || suffix == "n3") {
Chris@291 2576
Chris@291 2577 RDFExporter exporter(path, model);
Chris@291 2578 exporter.write();
Chris@291 2579 if (!exporter.isOK()) {
Chris@291 2580 error = exporter.getError();
Chris@291 2581 }
Chris@291 2582
Chris@0 2583 } else {
Chris@0 2584
Chris@0 2585 CSVFileWriter writer(path, model,
Chris@185 2586 ((suffix == "csv") ? "," : "\t"));
Chris@0 2587 writer.write();
Chris@0 2588
Chris@0 2589 if (!writer.isOK()) {
Chris@0 2590 error = writer.getError();
Chris@0 2591 }
Chris@0 2592 }
Chris@0 2593
Chris@0 2594 if (error != "") {
Chris@0 2595 QMessageBox::critical(this, tr("Failed to write file"), error);
Chris@0 2596 } else {
Chris@34 2597 m_recentFiles.addFile(path);
Chris@310 2598 emit activity(tr("Export layer to \"%1\"").arg(path));
Chris@0 2599 }
Chris@0 2600 }
Chris@0 2601
Chris@121 2602 void
Chris@121 2603 MainWindow::exportImage()
Chris@121 2604 {
Chris@121 2605 Pane *pane = m_paneStack->getCurrentPane();
Chris@121 2606 if (!pane) return;
Chris@121 2607
Chris@121 2608 QString path = getSaveFileName(FileFinder::ImageFile);
Chris@121 2609
Chris@121 2610 if (path == "") return;
Chris@121 2611
Chris@121 2612 if (QFileInfo(path).suffix() == "") path += ".png";
Chris@121 2613
Chris@123 2614 bool haveSelection = m_viewManager && !m_viewManager->getSelections().empty();
Chris@123 2615
Chris@123 2616 QSize total, visible, selected;
Chris@123 2617 total = pane->getImageSize();
Chris@123 2618 visible = pane->getImageSize(pane->getFirstVisibleFrame(),
Chris@123 2619 pane->getLastVisibleFrame());
Chris@123 2620
Chris@123 2621 size_t sf0 = 0, sf1 = 0;
Chris@123 2622
Chris@123 2623 if (haveSelection) {
Chris@123 2624 MultiSelection::SelectionList selections = m_viewManager->getSelections();
Chris@123 2625 sf0 = selections.begin()->getStartFrame();
Chris@123 2626 MultiSelection::SelectionList::iterator e = selections.end();
Chris@123 2627 --e;
Chris@123 2628 sf1 = e->getEndFrame();
Chris@123 2629 selected = pane->getImageSize(sf0, sf1);
Chris@123 2630 }
Chris@123 2631
Chris@123 2632 QStringList items;
Chris@125 2633 items << tr("Export the whole pane (%1x%2 pixels)")
Chris@123 2634 .arg(total.width()).arg(total.height());
Chris@123 2635 items << tr("Export the visible area only (%1x%2 pixels)")
Chris@123 2636 .arg(visible.width()).arg(visible.height());
Chris@123 2637 if (haveSelection) {
Chris@123 2638 items << tr("Export the selection extent (%1x%2 pixels)")
Chris@123 2639 .arg(selected.width()).arg(selected.height());
Chris@124 2640 } else {
Chris@124 2641 items << tr("Export the selection extent");
Chris@123 2642 }
Chris@123 2643
Chris@123 2644 QSettings settings;
Chris@123 2645 settings.beginGroup("MainWindow");
Chris@123 2646 int deflt = settings.value("lastimageexportregion", 0).toInt();
Chris@123 2647 if (deflt == 2 && !haveSelection) deflt = 1;
Chris@124 2648 if (deflt == 0 && total.width() > 32767) deflt = 1;
Chris@124 2649
Chris@124 2650 ListInputDialog *lid = new ListInputDialog
Chris@123 2651 (this, tr("Select region to export"),
Chris@123 2652 tr("Which region of the current pane do you want to export as an image?"),
Chris@124 2653 items, deflt);
Chris@124 2654
Chris@124 2655 if (!haveSelection) {
Chris@124 2656 lid->setItemAvailability(2, false);
Chris@124 2657 }
Chris@124 2658 if (total.width() > 32767) { // appears to be the limit of a QImage
Chris@124 2659 lid->setItemAvailability(0, false);
Chris@124 2660 lid->setFootnote(tr("Note: the whole pane is too wide to be exported as a single image."));
Chris@124 2661 }
Chris@124 2662
Chris@124 2663 bool ok = lid->exec();
Chris@124 2664 QString item = lid->getCurrentString();
Chris@124 2665 delete lid;
Chris@123 2666
Chris@123 2667 if (!ok || item.isEmpty()) return;
Chris@123 2668
Chris@123 2669 settings.setValue("lastimageexportregion", deflt);
Chris@123 2670
Chris@123 2671 QImage *image = 0;
Chris@123 2672
Chris@123 2673 if (item == items[0]) {
Chris@123 2674 image = pane->toNewImage();
Chris@123 2675 } else if (item == items[1]) {
Chris@123 2676 image = pane->toNewImage(pane->getFirstVisibleFrame(),
Chris@123 2677 pane->getLastVisibleFrame());
Chris@123 2678 } else if (haveSelection) {
Chris@123 2679 image = pane->toNewImage(sf0, sf1);
Chris@123 2680 }
Chris@123 2681
Chris@121 2682 if (!image) return;
Chris@121 2683
Chris@121 2684 if (!image->save(path, "PNG")) {
Chris@121 2685 QMessageBox::critical(this, tr("Failed to save image file"),
Chris@121 2686 tr("Failed to save image file %1").arg(path));
Chris@121 2687 }
Chris@121 2688
Chris@121 2689 delete image;
Chris@121 2690 }
Chris@121 2691
Chris@0 2692 void
Chris@0 2693 MainWindow::newSession()
Chris@0 2694 {
Chris@0 2695 if (!checkSaveModified()) return;
Chris@0 2696
Chris@0 2697 closeSession();
Chris@0 2698 createDocument();
Chris@0 2699
Chris@0 2700 Pane *pane = m_paneStack->addPane();
Chris@0 2701
Chris@90 2702 connect(pane, SIGNAL(contextHelpChanged(const QString &)),
Chris@116 2703 this, SLOT(contextHelpChanged(const QString &)));
Chris@90 2704
Chris@0 2705 if (!m_timeRulerLayer) {
Chris@0 2706 m_timeRulerLayer = m_document->createMainModelLayer
Chris@0 2707 (LayerFactory::TimeRuler);
Chris@0 2708 }
Chris@0 2709
Chris@0 2710 m_document->addLayerToView(pane, m_timeRulerLayer);
Chris@0 2711
Chris@0 2712 Layer *waveform = m_document->createMainModelLayer(LayerFactory::Waveform);
Chris@0 2713 m_document->addLayerToView(pane, waveform);
Chris@0 2714
Chris@65 2715 m_overview->registerView(pane);
Chris@0 2716
Chris@0 2717 CommandHistory::getInstance()->clear();
Chris@0 2718 CommandHistory::getInstance()->documentSaved();
Chris@0 2719 documentRestored();
Chris@0 2720 updateMenuStates();
Chris@0 2721 }
Chris@0 2722
Chris@0 2723 void
Chris@303 2724 MainWindow::documentReplaced()
Chris@303 2725 {
Chris@303 2726 if (m_document) {
Chris@303 2727 connect(m_document, SIGNAL(activity(QString)),
Chris@303 2728 m_activityLog, SLOT(activityHappened(QString)));
Chris@303 2729 }
Chris@303 2730 }
Chris@303 2731
Chris@303 2732 void
Chris@0 2733 MainWindow::closeSession()
Chris@0 2734 {
Chris@0 2735 if (!checkSaveModified()) return;
Chris@0 2736
Chris@0 2737 while (m_paneStack->getPaneCount() > 0) {
Chris@0 2738
Chris@0 2739 Pane *pane = m_paneStack->getPane(m_paneStack->getPaneCount() - 1);
Chris@0 2740
Chris@0 2741 while (pane->getLayerCount() > 0) {
Chris@0 2742 m_document->removeLayerFromView
Chris@0 2743 (pane, pane->getLayer(pane->getLayerCount() - 1));
Chris@0 2744 }
Chris@0 2745
Chris@65 2746 m_overview->unregisterView(pane);
Chris@0 2747 m_paneStack->deletePane(pane);
Chris@0 2748 }
Chris@0 2749
Chris@0 2750 while (m_paneStack->getHiddenPaneCount() > 0) {
Chris@0 2751
Chris@0 2752 Pane *pane = m_paneStack->getHiddenPane
Chris@0 2753 (m_paneStack->getHiddenPaneCount() - 1);
Chris@0 2754
Chris@0 2755 while (pane->getLayerCount() > 0) {
Chris@0 2756 m_document->removeLayerFromView
Chris@0 2757 (pane, pane->getLayer(pane->getLayerCount() - 1));
Chris@0 2758 }
Chris@0 2759
Chris@65 2760 m_overview->unregisterView(pane);
Chris@0 2761 m_paneStack->deletePane(pane);
Chris@0 2762 }
Chris@0 2763
Chris@0 2764 delete m_document;
Chris@0 2765 m_document = 0;
Chris@0 2766 m_viewManager->clearSelections();
Chris@0 2767 m_timeRulerLayer = 0; // document owned this
Chris@0 2768
Chris@0 2769 m_sessionFile = "";
mathieu@406 2770 setWindowTitle(tr("Sonic Visualiser (Kiosk edition)"));
Chris@0 2771
Chris@0 2772 CommandHistory::getInstance()->clear();
Chris@0 2773 CommandHistory::getInstance()->documentSaved();
Chris@0 2774 documentRestored();
Chris@0 2775 }
Chris@0 2776
Chris@0 2777 void
Chris@0 2778 MainWindow::openSession()
Chris@0 2779 {
Chris@0 2780 if (!checkSaveModified()) return;
Chris@0 2781
Chris@0 2782 QString orig = m_audioFile;
Chris@0 2783 if (orig == "") orig = ".";
Chris@0 2784 else orig = QFileInfo(orig).absoluteDir().canonicalPath();
Chris@0 2785
Chris@88 2786 QString path = getOpenFileName(FileFinder::SessionFile);
Chris@0 2787
Chris@0 2788 if (path.isEmpty()) return;
Chris@0 2789
Chris@200 2790 if (openSessionFile(path) == FileOpenFailed) {
Chris@247 2791 emit hideSplash();
Chris@0 2792 QMessageBox::critical(this, tr("Failed to open file"),
Chris@193 2793 tr("<b>File open failed</b><p>Session file \"%1\" could not be opened").arg(path));
Chris@0 2794 }
Chris@0 2795 }
Chris@0 2796
Chris@0 2797 void
Chris@0 2798 MainWindow::openSomething()
Chris@0 2799 {
Chris@0 2800 QString orig = m_audioFile;
Chris@0 2801 if (orig == "") orig = ".";
Chris@0 2802 else orig = QFileInfo(orig).absoluteDir().canonicalPath();
Chris@0 2803
Chris@88 2804 QString path = getOpenFileName(FileFinder::AnyFile);
Chris@0 2805
Chris@0 2806 if (path.isEmpty()) return;
Chris@0 2807
Chris@422 2808 FileOpenStatus status = open(path, ReplaceSession);
Chris@193 2809
Chris@193 2810 if (status == FileOpenFailed) {
Chris@247 2811 emit hideSplash();
Chris@193 2812 QMessageBox::critical(this, tr("Failed to open file"),
Chris@193 2813 tr("<b>File open failed</b><p>File \"%1\" could not be opened").arg(path));
Chris@193 2814 } else if (status == FileOpenWrongMode) {
Chris@247 2815 emit hideSplash();
Chris@193 2816 QMessageBox::critical(this, tr("Failed to open file"),
Chris@294 2817 tr("<b>Audio required</b><p>Unable to load layer data from \"%1\" without an audio file.<br>Please load at least one audio file before importing annotations.").arg(path));
Chris@0 2818 }
Chris@0 2819 }
Chris@0 2820
Chris@0 2821 void
Chris@86 2822 MainWindow::openLocation()
Chris@86 2823 {
Chris@103 2824 QSettings settings;
Chris@103 2825 settings.beginGroup("MainWindow");
Chris@103 2826 QString lastLocation = settings.value("lastremote", "").toString();
Chris@103 2827
Chris@86 2828 bool ok = false;
Chris@86 2829 QString text = QInputDialog::getText
Chris@86 2830 (this, tr("Open Location"),
Chris@86 2831 tr("Please enter the URL of the location to open:"),
Chris@103 2832 QLineEdit::Normal, lastLocation, &ok);
Chris@103 2833
Chris@103 2834 if (!ok) return;
Chris@103 2835
Chris@103 2836 settings.setValue("lastremote", text);
Chris@103 2837
Chris@103 2838 if (text.isEmpty()) return;
Chris@86 2839
Chris@419 2840 FileOpenStatus status = open(text, AskUser);
Chris@193 2841
Chris@193 2842 if (status == FileOpenFailed) {
Chris@247 2843 emit hideSplash();
Chris@86 2844 QMessageBox::critical(this, tr("Failed to open location"),
Chris@193 2845 tr("<b>Open failed</b><p>URL \"%1\" could not be opened").arg(text));
Chris@193 2846 } else if (status == FileOpenWrongMode) {
Chris@247 2847 emit hideSplash();
Chris@193 2848 QMessageBox::critical(this, tr("Failed to open location"),
Chris@294 2849 tr("<b>Audio required</b><p>Unable to load layer data from \"%1\" without an audio file.<br>Please load at least one audio file before importing annotations.").arg(text));
Chris@86 2850 }
Chris@86 2851 }
Chris@86 2852
Chris@86 2853 void
Chris@0 2854 MainWindow::openRecentFile()
Chris@0 2855 {
Chris@0 2856 QObject *obj = sender();
Chris@0 2857 QAction *action = dynamic_cast<QAction *>(obj);
Chris@0 2858
Chris@0 2859 if (!action) {
Chris@0 2860 std::cerr << "WARNING: MainWindow::openRecentFile: sender is not an action"
Chris@0 2861 << std::endl;
Chris@0 2862 return;
Chris@0 2863 }
Chris@0 2864
Chris@0 2865 QString path = action->text();
Chris@0 2866 if (path == "") return;
Chris@0 2867
Chris@422 2868 FileOpenStatus status = open(path, ReplaceSession);
Chris@193 2869
Chris@193 2870 if (status == FileOpenFailed) {
Chris@247 2871 emit hideSplash();
Chris@193 2872 QMessageBox::critical(this, tr("Failed to open location"),
Chris@193 2873 tr("<b>Open failed</b><p>File or URL \"%1\" could not be opened").arg(path));
Chris@193 2874 } else if (status == FileOpenWrongMode) {
Chris@247 2875 emit hideSplash();
Chris@193 2876 QMessageBox::critical(this, tr("Failed to open location"),
Chris@294 2877 tr("<b>Audio required</b><p>Unable to load layer data from \"%1\" without an audio file.<br>Please load at least one audio file before importing annotations.").arg(path));
Chris@0 2878 }
Chris@0 2879 }
Chris@0 2880
Chris@0 2881 void
Chris@435 2882 MainWindow::applyTemplate()
Chris@435 2883 {
Chris@435 2884 QObject *s = sender();
Chris@435 2885 QAction *action = qobject_cast<QAction *>(s);
Chris@435 2886
Chris@435 2887 if (!action) {
Chris@435 2888 std::cerr << "WARNING: MainWindow::applyTemplate: sender is not an action"
Chris@435 2889 << std::endl;
Chris@435 2890 return;
Chris@435 2891 }
Chris@435 2892
Chris@435 2893 QString n = action->objectName();
Chris@435 2894 if (n == "") n = action->text();
Chris@435 2895
Chris@435 2896 if (n == "") {
Chris@435 2897 std::cerr << "WARNING: MainWindow::applyTemplate: sender has no name"
Chris@435 2898 << std::endl;
Chris@435 2899 return;
Chris@435 2900 }
Chris@435 2901
Chris@435 2902 QString mainModelLocation;
Chris@435 2903 WaveFileModel *mm = getMainModel();
Chris@435 2904 if (mm) mainModelLocation = mm->getLocation();
Chris@435 2905 if (mainModelLocation != "") {
Chris@435 2906 openAudio(mainModelLocation, ReplaceSession, n);
Chris@435 2907 } else {
Chris@435 2908 openSessionTemplate(n);
Chris@435 2909 }
Chris@435 2910 }
Chris@435 2911
Chris@435 2912 void
Chris@425 2913 MainWindow::saveSessionAsTemplate()
Chris@425 2914 {
Chris@425 2915 QString name = QInputDialog::getText
Chris@425 2916 (this, tr("Enter template name"),
Chris@425 2917 tr("Please enter a name for the saved template:"));
Chris@425 2918 if (name == "") return;
Chris@425 2919
Chris@431 2920 name.replace(QRegExp("[^\\w\\s\\.\"'-]"), "_");
Chris@426 2921
Chris@426 2922 ResourceFinder rf;
Chris@426 2923 QString dir = rf.getResourceSaveDir("templates");
Chris@431 2924 QString filename = QString("%1/%2.svt").arg(dir).arg(name);
Chris@431 2925 if (QFile(filename).exists()) {
Chris@431 2926 if (QMessageBox::warning(this,
Chris@431 2927 tr("Template file exists"),
Chris@431 2928 tr("<b>Template file exists</b><p>The template \"%1\" already exists.<br>Overwrite it?").arg(name),
Chris@431 2929 QMessageBox::Ok | QMessageBox::Cancel,
Chris@431 2930 QMessageBox::Cancel) != QMessageBox::Ok) {
Chris@431 2931 return;
Chris@431 2932 }
Chris@431 2933 }
Chris@431 2934
Chris@431 2935 saveSessionTemplate(filename);
Chris@425 2936 }
Chris@425 2937
Chris@425 2938 void
Chris@425 2939 MainWindow::manageSavedTemplates()
Chris@425 2940 {
Chris@425 2941 ResourceFinder rf;
Chris@425 2942 QDesktopServices::openUrl("file:" + rf.getResourceSaveDir("templates"));
Chris@423 2943 }
Chris@423 2944
Chris@423 2945 void
Chris@200 2946 MainWindow::paneAdded(Pane *pane)
Chris@200 2947 {
Chris@200 2948 if (m_overview) m_overview->registerView(pane);
Chris@200 2949 }
Chris@200 2950
Chris@200 2951 void
Chris@200 2952 MainWindow::paneHidden(Pane *pane)
Chris@200 2953 {
Chris@200 2954 if (m_overview) m_overview->unregisterView(pane);
Chris@200 2955 }
Chris@200 2956
Chris@200 2957 void
Chris@200 2958 MainWindow::paneAboutToBeDeleted(Pane *pane)
Chris@200 2959 {
Chris@200 2960 if (m_overview) m_overview->unregisterView(pane);
Chris@200 2961 }
Chris@200 2962
Chris@200 2963 void
Chris@193 2964 MainWindow::paneDropAccepted(Pane *pane, QStringList uriList)
Chris@193 2965 {
Chris@193 2966 if (pane) m_paneStack->setCurrentPane(pane);
Chris@193 2967
Chris@193 2968 for (QStringList::iterator i = uriList.begin(); i != uriList.end(); ++i) {
Chris@193 2969
Chris@295 2970 FileOpenStatus status;
Chris@295 2971
Chris@295 2972 if (i == uriList.begin()) {
Chris@295 2973 status = open(*i, ReplaceCurrentPane);
Chris@295 2974 } else {
Chris@295 2975 status = open(*i, CreateAdditionalModel);
Chris@295 2976 }
Chris@193 2977
Chris@193 2978 if (status == FileOpenFailed) {
Chris@247 2979 emit hideSplash();
Chris@193 2980 QMessageBox::critical(this, tr("Failed to open dropped URL"),
Chris@193 2981 tr("<b>Open failed</b><p>Dropped URL \"%1\" could not be opened").arg(*i));
Chris@295 2982 break;
Chris@193 2983 } else if (status == FileOpenWrongMode) {
Chris@247 2984 emit hideSplash();
Chris@193 2985 QMessageBox::critical(this, tr("Failed to open dropped URL"),
Chris@294 2986 tr("<b>Audio required</b><p>Unable to load layer data from \"%1\" without an audio file.<br>Please load at least one audio file before importing annotations.").arg(*i));
Chris@295 2987 break;
Chris@295 2988 } else if (status == FileOpenCancelled) {
Chris@295 2989 break;
Chris@193 2990 }
Chris@193 2991 }
Chris@193 2992 }
Chris@193 2993
Chris@193 2994 void
Chris@193 2995 MainWindow::paneDropAccepted(Pane *pane, QString text)
Chris@193 2996 {
Chris@193 2997 if (pane) m_paneStack->setCurrentPane(pane);
Chris@193 2998
Chris@193 2999 QUrl testUrl(text);
Chris@193 3000 if (testUrl.scheme() == "file" ||
Chris@193 3001 testUrl.scheme() == "http" ||
Chris@193 3002 testUrl.scheme() == "ftp") {
Chris@193 3003 QStringList list;
Chris@193 3004 list.push_back(text);
Chris@193 3005 paneDropAccepted(pane, list);
Chris@193 3006 return;
Chris@193 3007 }
Chris@193 3008
Chris@193 3009 //!!! open as text -- but by importing as if a CSV, or just adding
Chris@193 3010 //to a text layer?
Chris@193 3011 }
Chris@193 3012
Chris@193 3013 void
Chris@0 3014 MainWindow::closeEvent(QCloseEvent *e)
Chris@0 3015 {
Chris@438 3016 // SVDEBUG << "MainWindow::closeEvent" << endl;
Chris@118 3017
Chris@136 3018 if (m_openingAudioFile) {
Chris@137 3019 // std::cerr << "Busy - ignoring close event" << std::endl;
Chris@136 3020 e->ignore();
Chris@136 3021 return;
Chris@136 3022 }
Chris@136 3023
Chris@70 3024 if (!m_abandoning && !checkSaveModified()) {
Chris@438 3025 // SVDEBUG << "Ignoring close event" << endl;
Chris@0 3026 e->ignore();
Chris@0 3027 return;
Chris@0 3028 }
Chris@0 3029
mathieu@459 3030 // Don't save size and position if in minimal mode (in case we
mathieu@459 3031 //start up in full mode)
Chris@454 3032 bool minimal = m_viewManager->getMinimalModeEnabled();
Chris@454 3033 if (!minimal) {
Chris@454 3034 QSettings settings;
Chris@454 3035 settings.beginGroup("MainWindow");
Chris@454 3036 settings.setValue("size", size());
Chris@454 3037 settings.setValue("position", pos());
Chris@454 3038 settings.endGroup();
Chris@454 3039 }
Chris@5 3040
Chris@163 3041 delete m_keyReference;
Chris@163 3042 m_keyReference = 0;
Chris@163 3043
Chris@163 3044 if (m_preferencesDialog &&
Chris@163 3045 m_preferencesDialog->isVisible()) {
Chris@164 3046 closeSession(); // otherwise we'll have to wait for prefs changes
Chris@163 3047 m_preferencesDialog->applicationClosing(false);
Chris@163 3048 }
Chris@163 3049
Chris@200 3050 closeSession();
Chris@200 3051
Chris@0 3052 e->accept();
Chris@0 3053 return;
Chris@0 3054 }
Chris@0 3055
Chris@0 3056 bool
Chris@11 3057 MainWindow::commitData(bool mayAskUser)
Chris@11 3058 {
Chris@11 3059 if (mayAskUser) {
Chris@163 3060 bool rv = checkSaveModified();
Chris@163 3061 if (rv) {
Chris@163 3062 if (m_preferencesDialog &&
Chris@163 3063 m_preferencesDialog->isVisible()) {
Chris@163 3064 m_preferencesDialog->applicationClosing(false);
Chris@163 3065 }
Chris@163 3066 }
Chris@163 3067 return rv;
Chris@11 3068 } else {
Chris@163 3069 if (m_preferencesDialog &&
Chris@163 3070 m_preferencesDialog->isVisible()) {
Chris@163 3071 m_preferencesDialog->applicationClosing(true);
Chris@163 3072 }
Chris@11 3073 if (!m_documentModified) return true;
Chris@11 3074
Chris@11 3075 // If we can't check with the user first, then we can't save
Chris@11 3076 // to the original session file (even if we have it) -- have
Chris@11 3077 // to use a temporary file
Chris@11 3078
Chris@11 3079 QString svDirBase = ".sv1";
Chris@11 3080 QString svDir = QDir::home().filePath(svDirBase);
Chris@11 3081
Chris@11 3082 if (!QFileInfo(svDir).exists()) {
Chris@11 3083 if (!QDir::home().mkdir(svDirBase)) return false;
Chris@11 3084 } else {
Chris@11 3085 if (!QFileInfo(svDir).isDir()) return false;
Chris@11 3086 }
Chris@11 3087
Chris@11 3088 // This name doesn't have to be unguessable
Chris@93 3089 #ifndef _WIN32
Chris@11 3090 QString fname = QString("tmp-%1-%2.sv")
Chris@11 3091 .arg(QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz"))
Chris@11 3092 .arg(QProcess().pid());
Chris@93 3093 #else
Chris@93 3094 QString fname = QString("tmp-%1.sv")
Chris@93 3095 .arg(QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz"));
Chris@93 3096 #endif
Chris@11 3097 QString fpath = QDir(svDir).filePath(fname);
Chris@11 3098 if (saveSessionFile(fpath)) {
Chris@34 3099 m_recentFiles.addFile(fpath);
Chris@310 3100 emit activity(tr("Export image to \"%1\"").arg(fpath));
Chris@11 3101 return true;
Chris@11 3102 } else {
Chris@11 3103 return false;
Chris@11 3104 }
Chris@11 3105 }
Chris@11 3106 }
Chris@11 3107
Chris@11 3108 bool
Chris@0 3109 MainWindow::checkSaveModified()
Chris@0 3110 {
Chris@0 3111 // Called before some destructive operation (e.g. new session,
Chris@0 3112 // exit program). Return true if we can safely proceed, false to
Chris@0 3113 // cancel.
Chris@0 3114
Chris@0 3115 if (!m_documentModified) return true;
Chris@0 3116
Chris@247 3117 emit hideSplash();
Chris@247 3118
Chris@0 3119 int button =
Chris@0 3120 QMessageBox::warning(this,
Chris@0 3121 tr("Session modified"),
Chris@207 3122 tr("<b>Session modified</b><p>The current session has been modified.<br>Do you want to save it?"),
Chris@165 3123 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
Chris@165 3124 QMessageBox::Yes);
Chris@0 3125
Chris@0 3126 if (button == QMessageBox::Yes) {
Chris@0 3127 saveSession();
Chris@0 3128 if (m_documentModified) { // save failed -- don't proceed!
Chris@0 3129 return false;
Chris@0 3130 } else {
Chris@0 3131 return true; // saved, so it's safe to continue now
Chris@0 3132 }
Chris@0 3133 } else if (button == QMessageBox::No) {
Chris@0 3134 m_documentModified = false; // so we know to abandon it
Chris@0 3135 return true;
Chris@0 3136 }
Chris@0 3137
Chris@0 3138 // else cancel
Chris@0 3139 return false;
Chris@0 3140 }
Chris@0 3141
Chris@290 3142 bool
Chris@294 3143 MainWindow::shouldCreateNewSessionForRDFAudio(bool *cancel)
Chris@290 3144 {
Chris@294 3145 //!!! This is very similar to part of MainWindowBase::openAudio --
Chris@294 3146 //!!! make them a bit more uniform
Chris@294 3147
Chris@294 3148 QSettings settings;
Chris@294 3149 settings.beginGroup("MainWindow");
Chris@294 3150 bool prevNewSession = settings.value("newsessionforrdfaudio", true).toBool();
Chris@294 3151 settings.endGroup();
Chris@294 3152 bool newSession = true;
Chris@294 3153
Chris@294 3154 QStringList items;
Chris@294 3155 items << tr("Close the current session and create a new one")
Chris@294 3156 << tr("Add this data to the current session");
Chris@294 3157
Chris@294 3158 bool ok = false;
Chris@294 3159 QString item = ListInputDialog::getItem
Chris@294 3160 (this, tr("Select target for import"),
Chris@294 3161 tr("<b>Select a target for import</b><p>This RDF document refers to one or more audio files.<br>You already have an audio waveform loaded.<br>What would you like to do with the new data?"),
Chris@294 3162 items, prevNewSession ? 0 : 1, &ok);
Chris@294 3163
Chris@294 3164 if (!ok || item.isEmpty()) {
Chris@294 3165 *cancel = true;
Chris@290 3166 return false;
Chris@290 3167 }
Chris@294 3168
Chris@294 3169 newSession = (item == items[0]);
Chris@294 3170 settings.beginGroup("MainWindow");
Chris@294 3171 settings.setValue("newsessionforrdfaudio", newSession);
Chris@294 3172 settings.endGroup();
Chris@294 3173
Chris@294 3174 if (newSession) return true;
Chris@294 3175 else return false;
Chris@290 3176 }
Chris@290 3177
Chris@0 3178 void
Chris@0 3179 MainWindow::saveSession()
Chris@0 3180 {
Chris@0 3181 if (m_sessionFile != "") {
Chris@0 3182 if (!saveSessionFile(m_sessionFile)) {
Chris@0 3183 QMessageBox::critical(this, tr("Failed to save file"),
Chris@193 3184 tr("<b>Save failed</b><p>Session file \"%1\" could not be saved.").arg(m_sessionFile));
Chris@0 3185 } else {
Chris@0 3186 CommandHistory::getInstance()->documentSaved();
Chris@0 3187 documentRestored();
Chris@0 3188 }
Chris@0 3189 } else {
Chris@0 3190 saveSessionAs();
Chris@0 3191 }
Chris@0 3192 }
Chris@0 3193
Chris@0 3194 void
Chris@0 3195 MainWindow::saveSessionAs()
Chris@0 3196 {
Chris@0 3197 QString orig = m_audioFile;
Chris@0 3198 if (orig == "") orig = ".";
Chris@0 3199 else orig = QFileInfo(orig).absoluteDir().canonicalPath();
Chris@0 3200
Chris@88 3201 QString path = getSaveFileName(FileFinder::SessionFile);
Chris@81 3202
Chris@81 3203 if (path == "") return;
Chris@0 3204
Chris@0 3205 if (!saveSessionFile(path)) {
Chris@0 3206 QMessageBox::critical(this, tr("Failed to save file"),
Chris@193 3207 tr("<b>Save failed</b><p>Session file \"%1\" could not be saved.").arg(path));
Chris@0 3208 } else {
mathieu@406 3209 setWindowTitle(tr("Sonic Visualiser (Kiosk edition): %1")
Chris@0 3210 .arg(QFileInfo(path).fileName()));
Chris@0 3211 m_sessionFile = path;
Chris@0 3212 CommandHistory::getInstance()->documentSaved();
Chris@0 3213 documentRestored();
Chris@34 3214 m_recentFiles.addFile(path);
Chris@310 3215 emit activity(tr("Save session as \"%1\"").arg(path));
Chris@0 3216 }
Chris@0 3217 }
Chris@0 3218
Chris@90 3219 void
Chris@72 3220 MainWindow::preferenceChanged(PropertyContainer::PropertyName name)
Chris@72 3221 {
Chris@200 3222 MainWindowBase::preferenceChanged(name);
Chris@200 3223
Chris@200 3224 if (name == "Background Mode" && m_viewManager) {
Chris@180 3225 if (m_viewManager->getGlobalDarkBackground()) {
Chris@180 3226 m_panLayer->setBaseColour
Chris@180 3227 (ColourDatabase::getInstance()->getColourIndex(tr("Bright Green")));
Chris@180 3228 } else {
Chris@180 3229 m_panLayer->setBaseColour
Chris@180 3230 (ColourDatabase::getInstance()->getColourIndex(tr("Green")));
Chris@180 3231 }
Chris@200 3232 }
Chris@0 3233 }
Chris@0 3234
Chris@0 3235 void
Chris@239 3236 MainWindow::propertyStacksResized(int width)
Chris@239 3237 {
Chris@438 3238 // SVDEBUG << "MainWindow::propertyStacksResized(" << width << ")" << endl;
Chris@239 3239
Chris@239 3240 if (!m_playControlsSpacer) return;
Chris@239 3241
Chris@239 3242 int spacerWidth = width - m_playControlsWidth - 4;
Chris@239 3243
Chris@438 3244 // SVDEBUG << "resizing spacer from " << m_playControlsSpacer->width() << " to " << spacerWidth << endl;
Chris@239 3245
Chris@239 3246 m_playControlsSpacer->setFixedSize(QSize(spacerWidth, 2));
Chris@239 3247 }
Chris@239 3248
Chris@239 3249 void
Chris@0 3250 MainWindow::addPane()
Chris@0 3251 {
Chris@0 3252 QObject *s = sender();
Chris@0 3253 QAction *action = dynamic_cast<QAction *>(s);
Chris@0 3254
Chris@0 3255 if (!action) {
Chris@0 3256 std::cerr << "WARNING: MainWindow::addPane: sender is not an action"
Chris@0 3257 << std::endl;
Chris@0 3258 return;
Chris@0 3259 }
Chris@0 3260
Chris@0 3261 PaneActionMap::iterator i = m_paneActions.find(action);
Chris@0 3262
Chris@0 3263 if (i == m_paneActions.end()) {
Chris@0 3264 std::cerr << "WARNING: MainWindow::addPane: unknown action "
Chris@432 3265 << action->objectName() << std::endl;
Chris@0 3266 return;
Chris@0 3267 }
Chris@0 3268
Chris@69 3269 addPane(i->second, action->text());
Chris@69 3270 }
Chris@69 3271
Chris@69 3272 void
Chris@232 3273 MainWindow::addPane(const LayerConfiguration &configuration, QString text)
Chris@69 3274 {
Chris@69 3275 CommandHistory::getInstance()->startCompoundOperation(text, true);
Chris@0 3276
Chris@0 3277 AddPaneCommand *command = new AddPaneCommand(this);
Chris@0 3278 CommandHistory::getInstance()->addCommand(command);
Chris@0 3279
Chris@0 3280 Pane *pane = command->getPane();
Chris@0 3281
Chris@69 3282 if (configuration.layer == LayerFactory::Spectrum) {
Chris@109 3283 pane->setPlaybackFollow(PlaybackScrollContinuous);
Chris@110 3284 pane->setFollowGlobalZoom(false);
Chris@112 3285 pane->setZoomLevel(512);
Chris@7 3286 }
Chris@7 3287
Chris@69 3288 if (configuration.layer != LayerFactory::TimeRuler &&
Chris@69 3289 configuration.layer != LayerFactory::Spectrum) {
Chris@8 3290
Chris@0 3291 if (!m_timeRulerLayer) {
Chris@0 3292 // std::cerr << "no time ruler layer, creating one" << std::endl;
Chris@0 3293 m_timeRulerLayer = m_document->createMainModelLayer
Chris@0 3294 (LayerFactory::TimeRuler);
Chris@0 3295 }
Chris@0 3296
Chris@438 3297 // SVDEBUG << "adding time ruler layer " << m_timeRulerLayer << endl;
Chris@0 3298
Chris@0 3299 m_document->addLayerToView(pane, m_timeRulerLayer);
Chris@0 3300 }
Chris@0 3301
Chris@69 3302 Layer *newLayer = m_document->createLayer(configuration.layer);
Chris@69 3303
Chris@69 3304 Model *suggestedModel = configuration.sourceModel;
Chris@66 3305 Model *model = 0;
Chris@66 3306
Chris@66 3307 if (suggestedModel) {
Chris@66 3308
Chris@66 3309 // check its validity
Chris@224 3310 std::vector<Model *> inputModels = m_document->getTransformInputModels();
Chris@66 3311 for (size_t j = 0; j < inputModels.size(); ++j) {
Chris@66 3312 if (inputModels[j] == suggestedModel) {
Chris@66 3313 model = suggestedModel;
Chris@66 3314 break;
Chris@66 3315 }
Chris@66 3316 }
Chris@66 3317
Chris@66 3318 if (!model) {
Chris@66 3319 std::cerr << "WARNING: Model " << (void *)suggestedModel
Chris@66 3320 << " appears in pane action map, but is not reported "
Chris@66 3321 << "by document as a valid transform source" << std::endl;
Chris@66 3322 }
Chris@66 3323 }
Chris@66 3324
Chris@346 3325 if (!model) {
Chris@346 3326 model = m_document->getMainModel();
Chris@346 3327 }
Chris@66 3328
Chris@66 3329 m_document->setModel(newLayer, model);
Chris@66 3330
Chris@69 3331 m_document->setChannel(newLayer, configuration.channel);
Chris@0 3332 m_document->addLayerToView(pane, newLayer);
Chris@0 3333
Chris@0 3334 m_paneStack->setCurrentPane(pane);
Chris@70 3335 m_paneStack->setCurrentLayer(pane, newLayer);
Chris@0 3336
Chris@438 3337 // SVDEBUG << "MainWindow::addPane: global centre frame is "
Chris@433 3338 // << m_viewManager->getGlobalCentreFrame() << endl;
Chris@130 3339 // pane->setCentreFrame(m_viewManager->getGlobalCentreFrame());
Chris@73 3340
Chris@0 3341 CommandHistory::getInstance()->endCompoundOperation();
Chris@0 3342
Chris@0 3343 updateMenuStates();
Chris@0 3344 }
Chris@0 3345
Chris@0 3346 void
Chris@0 3347 MainWindow::addLayer()
Chris@0 3348 {
Chris@0 3349 QObject *s = sender();
Chris@0 3350 QAction *action = dynamic_cast<QAction *>(s);
Chris@0 3351
Chris@0 3352 if (!action) {
Chris@0 3353 std::cerr << "WARNING: MainWindow::addLayer: sender is not an action"
Chris@0 3354 << std::endl;
Chris@0 3355 return;
Chris@0 3356 }
Chris@0 3357
Chris@0 3358 Pane *pane = m_paneStack->getCurrentPane();
Chris@0 3359
Chris@0 3360 if (!pane) {
Chris@0 3361 std::cerr << "WARNING: MainWindow::addLayer: no current pane" << std::endl;
Chris@0 3362 return;
Chris@0 3363 }
Chris@0 3364
Chris@0 3365 ExistingLayerActionMap::iterator ei = m_existingLayerActions.find(action);
Chris@0 3366
Chris@0 3367 if (ei != m_existingLayerActions.end()) {
Chris@0 3368 Layer *newLayer = ei->second;
Chris@0 3369 m_document->addLayerToView(pane, newLayer);
Chris@0 3370 m_paneStack->setCurrentLayer(pane, newLayer);
Chris@0 3371 return;
Chris@0 3372 }
Chris@0 3373
Chris@95 3374 ei = m_sliceActions.find(action);
Chris@95 3375
Chris@95 3376 if (ei != m_sliceActions.end()) {
Chris@95 3377 Layer *newLayer = m_document->createLayer(LayerFactory::Slice);
Chris@95 3378 // document->setModel(newLayer, ei->second->getModel());
Chris@95 3379 SliceableLayer *source = dynamic_cast<SliceableLayer *>(ei->second);
Chris@95 3380 SliceLayer *dest = dynamic_cast<SliceLayer *>(newLayer);
Chris@95 3381 if (source && dest) {
Chris@205 3382 //!!!???
Chris@95 3383 dest->setSliceableModel(source->getSliceableModel());
Chris@95 3384 connect(source, SIGNAL(sliceableModelReplaced(const Model *, const Model *)),
Chris@95 3385 dest, SLOT(sliceableModelReplaced(const Model *, const Model *)));
Chris@95 3386 connect(m_document, SIGNAL(modelAboutToBeDeleted(Model *)),
Chris@95 3387 dest, SLOT(modelAboutToBeDeleted(Model *)));
Chris@95 3388 }
Chris@95 3389 m_document->addLayerToView(pane, newLayer);
Chris@95 3390 m_paneStack->setCurrentLayer(pane, newLayer);
Chris@95 3391 return;
Chris@95 3392 }
Chris@95 3393
Chris@211 3394 TransformActionMap::iterator i = m_transformActions.find(action);
Chris@34 3395
Chris@34 3396 if (i == m_transformActions.end()) {
Chris@0 3397
Chris@0 3398 LayerActionMap::iterator i = m_layerActions.find(action);
Chris@0 3399
Chris@0 3400 if (i == m_layerActions.end()) {
Chris@0 3401 std::cerr << "WARNING: MainWindow::addLayer: unknown action "
Chris@432 3402 << action->objectName() << std::endl;
Chris@0 3403 return;
Chris@0 3404 }
Chris@0 3405
Chris@232 3406 LayerFactory::LayerType type = i->second.layer;
Chris@0 3407
Chris@0 3408 LayerFactory::LayerTypeSet emptyTypes =
Chris@0 3409 LayerFactory::getInstance()->getValidEmptyLayerTypes();
Chris@0 3410
Chris@0 3411 Layer *newLayer;
Chris@0 3412
Chris@0 3413 if (emptyTypes.find(type) != emptyTypes.end()) {
Chris@0 3414
Chris@0 3415 newLayer = m_document->createEmptyLayer(type);
Chris@217 3416 if (newLayer) {
Chris@217 3417 m_toolActions[ViewManager::DrawMode]->trigger();
Chris@217 3418 }
Chris@0 3419
Chris@0 3420 } else {
Chris@0 3421
Chris@346 3422 Model *model = i->second.sourceModel;
Chris@346 3423
Chris@415 3424 cerr << "model = "<< model << endl;
Chris@415 3425
Chris@346 3426 if (!model) {
Chris@346 3427 if (type == LayerFactory::TimeRuler) {
Chris@346 3428 newLayer = m_document->createMainModelLayer(type);
Chris@346 3429 } else {
Chris@346 3430 // if model is unspecified and this is not a
Chris@415 3431 // time-ruler layer, use any plausible model from
Chris@415 3432 // the current pane -- this is the case for
Chris@415 3433 // right-button menu layer additions
Chris@415 3434 Pane::ModelSet ms = pane->getModels();
Chris@415 3435 foreach (Model *m, ms) {
Chris@415 3436 RangeSummarisableTimeValueModel *r =
Chris@415 3437 dynamic_cast<RangeSummarisableTimeValueModel *>(m);
Chris@415 3438 if (r) model = m;
Chris@346 3439 }
Chris@346 3440 if (!model) model = getMainModel();
Chris@346 3441 }
Chris@346 3442 }
Chris@346 3443
Chris@346 3444 if (model) {
Chris@238 3445 newLayer = m_document->createLayer(type);
Chris@346 3446 if (m_document->isKnownModel(model)) {
Chris@238 3447 m_document->setChannel(newLayer, i->second.channel);
Chris@346 3448 m_document->setModel(newLayer, model);
Chris@238 3449 } else {
Chris@238 3450 std::cerr << "WARNING: MainWindow::addLayer: unknown model "
Chris@346 3451 << model
Chris@238 3452 << " (\""
Chris@346 3453 << (model ? model->objectName().toStdString() : "")
Chris@238 3454 << "\") in layer action map"
Chris@238 3455 << std::endl;
Chris@238 3456 }
Chris@232 3457 }
Chris@238 3458 }
Chris@0 3459
Chris@217 3460 if (newLayer) {
Chris@217 3461 m_document->addLayerToView(pane, newLayer);
Chris@217 3462 m_paneStack->setCurrentLayer(pane, newLayer);
Chris@217 3463 }
Chris@0 3464
Chris@0 3465 return;
Chris@0 3466 }
Chris@0 3467
Chris@224 3468 //!!! want to do something like this, but it's not supported in
Chris@224 3469 //ModelTransformerFactory yet
Chris@224 3470 /*
Chris@0 3471 int channel = -1;
Chris@0 3472 // pick up the default channel from any existing layers on the same pane
Chris@0 3473 for (int j = 0; j < pane->getLayerCount(); ++j) {
Chris@0 3474 int c = LayerFactory::getInstance()->getChannel(pane->getLayer(j));
Chris@0 3475 if (c != -1) {
Chris@0 3476 channel = c;
Chris@0 3477 break;
Chris@0 3478 }
Chris@0 3479 }
Chris@224 3480 */
Chris@0 3481
Chris@33 3482 // We always ask for configuration, even if the plugin isn't
Chris@33 3483 // supposed to be configurable, because we need to let the user
Chris@33 3484 // change the execution context (block size etc).
Chris@0 3485
Chris@224 3486 QString transformId = i->second;
Chris@274 3487
Chris@274 3488 addLayer(transformId);
Chris@274 3489 }
Chris@274 3490
Chris@274 3491 void
Chris@274 3492 MainWindow::addLayer(QString transformId)
Chris@274 3493 {
Chris@274 3494 Pane *pane = m_paneStack->getCurrentPane();
Chris@274 3495 if (!pane) {
Chris@274 3496 std::cerr << "WARNING: MainWindow::addLayer: no current pane" << std::endl;
Chris@274 3497 return;
Chris@274 3498 }
Chris@274 3499
Chris@224 3500 Transform transform = TransformFactory::getInstance()->
Chris@224 3501 getDefaultTransformFor(transformId);
Chris@27 3502
Chris@66 3503 std::vector<Model *> candidateInputModels =
Chris@224 3504 m_document->getTransformInputModels();
Chris@53 3505
Chris@219 3506 Model *defaultInputModel = 0;
Chris@219 3507 for (int j = 0; j < pane->getLayerCount(); ++j) {
Chris@219 3508 Layer *layer = pane->getLayer(j);
Chris@219 3509 if (!layer) continue;
Chris@243 3510 if (LayerFactory::getInstance()->getLayerType(layer) !=
Chris@243 3511 LayerFactory::Waveform &&
Chris@243 3512 !layer->isLayerOpaque()) continue;
Chris@219 3513 Model *model = layer->getModel();
Chris@219 3514 if (!model) continue;
Chris@219 3515 for (size_t k = 0; k < candidateInputModels.size(); ++k) {
Chris@219 3516 if (candidateInputModels[k] == model) {
Chris@219 3517 defaultInputModel = model;
Chris@219 3518 break;
Chris@219 3519 }
Chris@219 3520 }
Chris@219 3521 if (defaultInputModel) break;
Chris@219 3522 }
Chris@219 3523
Chris@184 3524 size_t startFrame = 0, duration = 0;
Chris@184 3525 size_t endFrame = 0;
Chris@184 3526 m_viewManager->getSelection().getExtents(startFrame, endFrame);
Chris@184 3527 if (endFrame > startFrame) duration = endFrame - startFrame;
Chris@184 3528 else startFrame = 0;
Chris@184 3529
Chris@357 3530 TransformUserConfigurator configurator;
Chris@357 3531
Chris@224 3532 ModelTransformer::Input input = ModelTransformerFactory::getInstance()->
Chris@224 3533 getConfigurationForTransform
Chris@211 3534 (transform,
Chris@211 3535 candidateInputModels,
Chris@219 3536 defaultInputModel,
Chris@211 3537 m_playSource,
Chris@211 3538 startFrame,
Chris@357 3539 duration,
Chris@357 3540 &configurator);
Chris@211 3541
Chris@224 3542 if (!input.getModel()) return;
Chris@224 3543
Chris@438 3544 // SVDEBUG << "MainWindow::addLayer: Input model is " << input.getModel() << " \"" << input.getModel()->objectName() << "\"" << endl << "transform:" << endl << transform.toXmlString() << endl;
Chris@224 3545
Chris@224 3546 Layer *newLayer = m_document->createDerivedLayer(transform, input);
Chris@0 3547
Chris@0 3548 if (newLayer) {
Chris@0 3549 m_document->addLayerToView(pane, newLayer);
Chris@224 3550 m_document->setChannel(newLayer, input.getChannel());
Chris@224 3551 m_recentTransforms.add(transformId);
Chris@70 3552 m_paneStack->setCurrentLayer(pane, newLayer);
Chris@0 3553 }
Chris@0 3554
Chris@0 3555 updateMenuStates();
Chris@0 3556 }
Chris@0 3557
Chris@0 3558 void
Chris@0 3559 MainWindow::renameCurrentLayer()
Chris@0 3560 {
Chris@0 3561 Pane *pane = m_paneStack->getCurrentPane();
Chris@0 3562 if (pane) {
Chris@0 3563 Layer *layer = pane->getSelectedLayer();
Chris@0 3564 if (layer) {
Chris@0 3565 bool ok = false;
Chris@0 3566 QString newName = QInputDialog::getText
Chris@0 3567 (this, tr("Rename Layer"),
Chris@0 3568 tr("New name for this layer:"),
Chris@0 3569 QLineEdit::Normal, layer->objectName(), &ok);
Chris@0 3570 if (ok) {
Chris@239 3571 layer->setPresentationName(newName);
Chris@95 3572 setupExistingLayersMenus();
Chris@0 3573 }
Chris@0 3574 }
Chris@0 3575 }
Chris@0 3576 }
Chris@0 3577
Chris@0 3578 void
Chris@272 3579 MainWindow::findTransform()
Chris@272 3580 {
Chris@274 3581 TransformFinder *finder = new TransformFinder(this);
Chris@274 3582 if (!finder->exec()) {
Chris@274 3583 delete finder;
Chris@274 3584 return;
Chris@273 3585 }
Chris@274 3586 TransformId transform = finder->getTransform();
Chris@274 3587 delete finder;
Chris@287 3588
Chris@287 3589 if (getMainModel() != 0 && m_paneStack->getCurrentPane() != 0) {
Chris@287 3590 addLayer(transform);
Chris@287 3591 }
Chris@272 3592 }
Chris@272 3593
Chris@272 3594 void
Chris@207 3595 MainWindow::playSoloToggled()
Chris@207 3596 {
Chris@207 3597 MainWindowBase::playSoloToggled();
Chris@207 3598 m_soloModified = true;
Chris@207 3599 }
Chris@207 3600
Chris@207 3601 void
Chris@206 3602 MainWindow::alignToggled()
Chris@206 3603 {
Chris@206 3604 QAction *action = dynamic_cast<QAction *>(sender());
Chris@206 3605
Chris@207 3606 if (!m_viewManager) return;
Chris@207 3607
Chris@206 3608 if (action) {
Chris@206 3609 m_viewManager->setAlignMode(action->isChecked());
Chris@206 3610 } else {
Chris@206 3611 m_viewManager->setAlignMode(!m_viewManager->getAlignMode());
Chris@206 3612 }
Chris@206 3613
Chris@206 3614 if (m_viewManager->getAlignMode()) {
Chris@207 3615 m_prevSolo = m_soloAction->isChecked();
Chris@208 3616 if (!m_soloAction->isChecked()) {
Chris@208 3617 m_soloAction->setChecked(true);
Chris@208 3618 MainWindowBase::playSoloToggled();
Chris@208 3619 }
Chris@207 3620 m_soloModified = false;
Chris@207 3621 emit canChangeSolo(false);
Chris@206 3622 m_document->alignModels();
Chris@206 3623 m_document->setAutoAlignment(true);
Chris@206 3624 } else {
Chris@207 3625 if (!m_soloModified) {
Chris@208 3626 if (m_soloAction->isChecked() != m_prevSolo) {
Chris@208 3627 m_soloAction->setChecked(m_prevSolo);
Chris@208 3628 MainWindowBase::playSoloToggled();
Chris@208 3629 }
Chris@207 3630 }
Chris@207 3631 emit canChangeSolo(true);
Chris@206 3632 m_document->setAutoAlignment(false);
Chris@206 3633 }
Chris@206 3634
Chris@206 3635 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@206 3636
Chris@206 3637 Pane *pane = m_paneStack->getPane(i);
Chris@206 3638 if (!pane) continue;
Chris@206 3639
Chris@206 3640 pane->update();
Chris@206 3641 }
Chris@206 3642 }
Chris@206 3643
Chris@206 3644 void
Chris@59 3645 MainWindow::playSpeedChanged(int position)
Chris@0 3646 {
Chris@59 3647 PlaySpeedRangeMapper mapper(0, 200);
Chris@60 3648
Chris@60 3649 float percent = m_playSpeed->mappedValue();
Chris@60 3650 float factor = mapper.getFactorForValue(percent);
Chris@60 3651
Chris@267 3652 // std::cerr << "speed = " << position << " percent = " << percent << " factor = " << factor << std::endl;
Chris@60 3653
Chris@59 3654 bool something = (position != 100);
Chris@155 3655
Chris@59 3656 int pc = lrintf(percent);
Chris@21 3657
Chris@155 3658 if (!something) {
Chris@155 3659 contextHelpChanged(tr("Playback speed: Normal"));
Chris@155 3660 } else {
Chris@155 3661 contextHelpChanged(tr("Playback speed: %1%2%")
Chris@155 3662 .arg(position > 100 ? "+" : "")
Chris@155 3663 .arg(pc));
Chris@155 3664 }
Chris@155 3665
Chris@240 3666 m_playSource->setTimeStretch(factor);
Chris@155 3667
Chris@155 3668 updateMenuStates();
Chris@16 3669 }
Chris@16 3670
Chris@26 3671 void
Chris@155 3672 MainWindow::speedUpPlayback()
Chris@155 3673 {
Chris@155 3674 int value = m_playSpeed->value();
Chris@155 3675 value = value + m_playSpeed->pageStep();
Chris@155 3676 if (value > m_playSpeed->maximum()) value = m_playSpeed->maximum();
Chris@155 3677 m_playSpeed->setValue(value);
Chris@155 3678 }
Chris@155 3679
Chris@155 3680 void
Chris@155 3681 MainWindow::slowDownPlayback()
Chris@155 3682 {
Chris@155 3683 int value = m_playSpeed->value();
Chris@155 3684 value = value - m_playSpeed->pageStep();
Chris@155 3685 if (value < m_playSpeed->minimum()) value = m_playSpeed->minimum();
Chris@155 3686 m_playSpeed->setValue(value);
Chris@155 3687 }
Chris@155 3688
Chris@155 3689 void
Chris@155 3690 MainWindow::restoreNormalPlayback()
Chris@155 3691 {
Chris@155 3692 m_playSpeed->setValue(m_playSpeed->defaultValue());
Chris@155 3693 }
Chris@155 3694
Chris@155 3695 void
Chris@227 3696 MainWindow::currentPaneChanged(Pane *pane)
Chris@227 3697 {
Chris@228 3698 MainWindowBase::currentPaneChanged(pane);
Chris@228 3699
Chris@227 3700 if (!pane || !m_panLayer) return;
Chris@227 3701 for (int i = pane->getLayerCount(); i > 0; ) {
Chris@227 3702 --i;
Chris@227 3703 Layer *layer = pane->getLayer(i);
Chris@227 3704 if (LayerFactory::getInstance()->getLayerType(layer) ==
Chris@227 3705 LayerFactory::Waveform) {
Chris@227 3706 RangeSummarisableTimeValueModel *tvm =
Chris@227 3707 dynamic_cast<RangeSummarisableTimeValueModel *>(layer->getModel());
Chris@227 3708 if (tvm) {
Chris@227 3709 m_panLayer->setModel(tvm);
Chris@227 3710 return;
Chris@227 3711 }
Chris@227 3712 }
Chris@227 3713 }
Chris@227 3714 }
Chris@227 3715
Chris@227 3716 void
Chris@116 3717 MainWindow::updateVisibleRangeDisplay(Pane *p) const
Chris@116 3718 {
Chris@116 3719 if (!getMainModel() || !p) {
Chris@116 3720 return;
Chris@116 3721 }
Chris@116 3722
Chris@117 3723 bool haveSelection = false;
Chris@117 3724 size_t startFrame = 0, endFrame = 0;
Chris@117 3725
Chris@117 3726 if (m_viewManager && m_viewManager->haveInProgressSelection()) {
Chris@117 3727
Chris@117 3728 bool exclusive = false;
Chris@117 3729 Selection s = m_viewManager->getInProgressSelection(exclusive);
Chris@117 3730
Chris@117 3731 if (!s.isEmpty()) {
Chris@117 3732 haveSelection = true;
Chris@117 3733 startFrame = s.getStartFrame();
Chris@117 3734 endFrame = s.getEndFrame();
Chris@117 3735 }
Chris@117 3736 }
Chris@117 3737
Chris@117 3738 if (!haveSelection) {
Chris@117 3739 startFrame = p->getFirstVisibleFrame();
Chris@117 3740 endFrame = p->getLastVisibleFrame();
Chris@117 3741 }
Chris@117 3742
Chris@116 3743 RealTime start = RealTime::frame2RealTime
Chris@117 3744 (startFrame, getMainModel()->getSampleRate());
Chris@116 3745
Chris@116 3746 RealTime end = RealTime::frame2RealTime
Chris@117 3747 (endFrame, getMainModel()->getSampleRate());
Chris@116 3748
Chris@116 3749 RealTime duration = end - start;
Chris@116 3750
Chris@116 3751 QString startStr, endStr, durationStr;
Chris@116 3752 startStr = start.toText(true).c_str();
Chris@116 3753 endStr = end.toText(true).c_str();
Chris@116 3754 durationStr = duration.toText(true).c_str();
Chris@116 3755
Chris@117 3756 if (haveSelection) {
Chris@117 3757 m_myStatusMessage = tr("Selection: %1 to %2 (duration %3)")
Chris@117 3758 .arg(startStr).arg(endStr).arg(durationStr);
Chris@117 3759 } else {
Chris@117 3760 m_myStatusMessage = tr("Visible: %1 to %2 (duration %3)")
Chris@117 3761 .arg(startStr).arg(endStr).arg(durationStr);
Chris@117 3762 }
Chris@116 3763
Chris@116 3764 statusBar()->showMessage(m_myStatusMessage);
Chris@340 3765
Chris@340 3766 updatePositionStatusDisplays();
Chris@340 3767 }
Chris@340 3768
Chris@340 3769 void
Chris@340 3770 MainWindow::updatePositionStatusDisplays() const
Chris@340 3771 {
Chris@340 3772 if (!statusBar()->isVisible()) return;
Chris@340 3773
Chris@340 3774 Pane *pane = 0;
Chris@340 3775 size_t frame = m_viewManager->getPlaybackFrame();
Chris@340 3776
Chris@340 3777 if (m_paneStack) pane = m_paneStack->getCurrentPane();
Chris@340 3778 if (!pane) return;
Chris@340 3779
Chris@340 3780 int layers = pane->getLayerCount();
Chris@340 3781 if (layers == 0) m_currentLabel->setText("");
Chris@340 3782
Chris@340 3783 for (int i = layers-1; i >= 0; --i) {
Chris@340 3784 Layer *layer = pane->getLayer(i);
Chris@340 3785 if (!layer) continue;
Chris@340 3786 if (!layer->isLayerEditable()) continue;
Chris@340 3787 QString label = layer->getLabelPreceding
Chris@340 3788 (pane->alignFromReference(frame));
Chris@340 3789 m_currentLabel->setText(label);
Chris@340 3790 break;
Chris@340 3791 }
Chris@116 3792 }
Chris@116 3793
Chris@116 3794 void
Chris@0 3795 MainWindow::outputLevelsChanged(float left, float right)
Chris@0 3796 {
Chris@0 3797 m_fader->setPeakLeft(left);
Chris@0 3798 m_fader->setPeakRight(right);
Chris@0 3799 }
Chris@0 3800
Chris@0 3801 void
Chris@0 3802 MainWindow::sampleRateMismatch(size_t requested, size_t actual,
Chris@0 3803 bool willResample)
Chris@0 3804 {
Chris@0 3805 if (!willResample) {
Chris@247 3806 emit hideSplash();
Chris@0 3807 QMessageBox::information
Chris@0 3808 (this, tr("Sample rate mismatch"),
Chris@193 3809 tr("<b>Wrong sample rate</b><p>The sample rate of this audio file (%1 Hz) does not match\nthe current playback rate (%2 Hz).<p>The file will play at the wrong speed and pitch.<p>Change the <i>Resample mismatching files on import</i> option under <i>File</i> -> <i>Preferences</i> if you want to alter this behaviour.")
Chris@0 3810 .arg(requested).arg(actual));
Chris@0 3811 }
Chris@0 3812
Chris@0 3813 updateDescriptionLabel();
Chris@0 3814 }
Chris@0 3815
Chris@0 3816 void
Chris@42 3817 MainWindow::audioOverloadPluginDisabled()
Chris@42 3818 {
Chris@42 3819 QMessageBox::information
Chris@42 3820 (this, tr("Audio processing overload"),
Chris@193 3821 tr("<b>Overloaded</b><p>Audio effects plugin auditioning has been disabled due to a processing overload."));
Chris@42 3822 }
Chris@42 3823
Chris@42 3824 void
Chris@266 3825 MainWindow::audioTimeStretchMultiChannelDisabled()
Chris@266 3826 {
Chris@266 3827 static bool shownOnce = false;
Chris@266 3828 if (shownOnce) return;
Chris@266 3829 QMessageBox::information
Chris@266 3830 (this, tr("Audio processing overload"),
Chris@266 3831 tr("<b>Overloaded</b><p>Audio playback speed processing has been reduced to a single channel, due to a processing overload."));
Chris@266 3832 shownOnce = true;
Chris@266 3833 }
Chris@266 3834
Chris@266 3835 void
Chris@304 3836 MainWindow::midiEventsAvailable()
Chris@304 3837 {
Chris@307 3838 Pane *currentPane = 0;
Chris@307 3839 NoteLayer *currentNoteLayer = 0;
Chris@309 3840 TimeValueLayer *currentTimeValueLayer = 0;
Chris@307 3841
Chris@307 3842 if (m_paneStack) currentPane = m_paneStack->getCurrentPane();
Chris@307 3843 if (currentPane) {
Chris@307 3844 currentNoteLayer = dynamic_cast<NoteLayer *>
Chris@307 3845 (currentPane->getSelectedLayer());
Chris@309 3846 currentTimeValueLayer = dynamic_cast<TimeValueLayer *>
Chris@309 3847 (currentPane->getSelectedLayer());
Chris@307 3848 }
Chris@307 3849
Chris@305 3850 // This is called through a serialised signal/slot invocation
Chris@305 3851 // (across threads). It could happen quite some time after the
Chris@305 3852 // event was actually received, which is why event timestamping
Chris@305 3853 // happens in the MIDI input class and not here.
Chris@307 3854
Chris@305 3855 while (m_midiInput->getEventsAvailable() > 0) {
Chris@308 3856
Chris@305 3857 MIDIEvent ev(m_midiInput->readEvent());
Chris@307 3858
Chris@309 3859 size_t frame = currentPane->alignFromReference(ev.getTime());
Chris@309 3860
Chris@308 3861 bool noteOn = (ev.getMessageType() == MIDIConstants::MIDI_NOTE_ON &&
Chris@308 3862 ev.getVelocity() > 0);
Chris@308 3863
Chris@308 3864 bool noteOff = (ev.getMessageType() == MIDIConstants::MIDI_NOTE_OFF ||
Chris@308 3865 (ev.getMessageType() == MIDIConstants::MIDI_NOTE_ON &&
Chris@308 3866 ev.getVelocity() == 0));
Chris@308 3867
Chris@307 3868 if (currentNoteLayer) {
Chris@307 3869
Chris@310 3870 if (!m_playSource || !m_playSource->isPlaying()) continue;
Chris@310 3871
Chris@308 3872 if (noteOn) {
Chris@307 3873
Chris@309 3874 currentNoteLayer->addNoteOn(frame,
Chris@307 3875 ev.getPitch(),
Chris@307 3876 ev.getVelocity());
Chris@307 3877
Chris@308 3878 } else if (noteOff) {
Chris@307 3879
Chris@309 3880 currentNoteLayer->addNoteOff(frame,
Chris@307 3881 ev.getPitch());
Chris@307 3882
Chris@307 3883 }
Chris@307 3884
Chris@309 3885 continue;
Chris@309 3886 }
Chris@309 3887
Chris@309 3888 if (currentTimeValueLayer) {
Chris@308 3889
Chris@308 3890 if (!noteOn) continue;
Chris@310 3891
Chris@310 3892 if (!m_playSource || !m_playSource->isPlaying()) continue;
Chris@310 3893
Chris@309 3894 Model *model = static_cast<Layer *>(currentTimeValueLayer)->getModel();
Chris@309 3895 SparseTimeValueModel *tvm =
Chris@309 3896 dynamic_cast<SparseTimeValueModel *>(model);
Chris@309 3897 if (tvm) {
Chris@309 3898 SparseTimeValueModel::Point point(frame, ev.getPitch() % 12, "");
Chris@309 3899 SparseTimeValueModel::AddPointCommand *command =
Chris@309 3900 new SparseTimeValueModel::AddPointCommand
Chris@309 3901 (tvm, point, tr("Add Point"));
Chris@309 3902 CommandHistory::getInstance()->addCommand(command);
Chris@309 3903 }
Chris@309 3904 continue;
Chris@309 3905
Chris@305 3906 }
Chris@309 3907
Chris@309 3908 if (!noteOn) continue;
Chris@309 3909 insertInstantAt(ev.getTime());
Chris@304 3910 }
Chris@304 3911 }
Chris@304 3912
Chris@304 3913 void
Chris@305 3914 MainWindow::playStatusChanged(bool playing)
Chris@305 3915 {
Chris@307 3916 Pane *currentPane = 0;
Chris@307 3917 NoteLayer *currentNoteLayer = 0;
Chris@307 3918
Chris@307 3919 if (m_paneStack) currentPane = m_paneStack->getCurrentPane();
Chris@307 3920 if (currentPane) {
Chris@307 3921 currentNoteLayer = dynamic_cast<NoteLayer *>(currentPane->getSelectedLayer());
Chris@307 3922 }
Chris@307 3923
Chris@307 3924 if (currentNoteLayer) {
Chris@307 3925 currentNoteLayer->abandonNoteOns();
Chris@307 3926 }
Chris@305 3927 }
Chris@305 3928
Chris@305 3929 void
Chris@200 3930 MainWindow::layerRemoved(Layer *layer)
Chris@0 3931 {
Chris@95 3932 setupExistingLayersMenus();
Chris@200 3933 MainWindowBase::layerRemoved(layer);
Chris@0 3934 }
Chris@0 3935
Chris@0 3936 void
Chris@0 3937 MainWindow::layerInAView(Layer *layer, bool inAView)
Chris@0 3938 {
Chris@95 3939 setupExistingLayersMenus();
Chris@200 3940 MainWindowBase::layerInAView(layer, inAView);
Chris@0 3941 }
Chris@0 3942
Chris@0 3943 void
Chris@0 3944 MainWindow::modelAdded(Model *model)
Chris@0 3945 {
Chris@200 3946 MainWindowBase::modelAdded(model);
Chris@66 3947 if (dynamic_cast<DenseTimeValueModel *>(model)) {
Chris@66 3948 setupPaneAndLayerMenus();
Chris@66 3949 }
Chris@0 3950 }
Chris@0 3951
Chris@0 3952 void
Chris@0 3953 MainWindow::mainModelChanged(WaveFileModel *model)
Chris@0 3954 {
Chris@0 3955 m_panLayer->setModel(model);
Chris@200 3956
Chris@200 3957 MainWindowBase::mainModelChanged(model);
Chris@200 3958
Chris@200 3959 if (m_playTarget) {
Chris@200 3960 connect(m_fader, SIGNAL(valueChanged(float)),
Chris@200 3961 m_playTarget, SLOT(setOutputGain(float)));
Chris@200 3962 }
Chris@0 3963 }
Chris@0 3964
Chris@0 3965 void
Chris@200 3966 MainWindow::setInstantsNumbering()
Chris@0 3967 {
Chris@200 3968 QAction *a = dynamic_cast<QAction *>(sender());
Chris@200 3969 if (!a) return;
Chris@200 3970
Chris@200 3971 int type = m_numberingActions[a];
Chris@200 3972
Chris@200 3973 if (m_labeller) m_labeller->setType(Labeller::ValueType(type));
Chris@200 3974
Chris@200 3975 QSettings settings;
Chris@200 3976 settings.beginGroup("MainWindow");
Chris@200 3977 settings.setValue("labellertype", type);
Chris@200 3978 settings.endGroup();
Chris@200 3979 }
Chris@200 3980
Chris@200 3981 void
Chris@200 3982 MainWindow::setInstantsCounterCycle()
Chris@200 3983 {
Chris@200 3984 QAction *a = dynamic_cast<QAction *>(sender());
Chris@200 3985 if (!a) return;
Chris@200 3986
Chris@200 3987 int cycle = a->text().toInt();
Chris@200 3988 if (cycle == 0) return;
Chris@200 3989
Chris@200 3990 if (m_labeller) m_labeller->setCounterCycleSize(cycle);
Chris@200 3991
Chris@200 3992 QSettings settings;
Chris@200 3993 settings.beginGroup("MainWindow");
Chris@200 3994 settings.setValue("labellercycle", cycle);
Chris@200 3995 settings.endGroup();
Chris@200 3996 }
Chris@200 3997
Chris@200 3998 void
Chris@200 3999 MainWindow::resetInstantsCounters()
Chris@200 4000 {
Chris@200 4001 LabelCounterInputDialog dialog(m_labeller, this);
Chris@241 4002 dialog.setWindowTitle(tr("Reset Counters"));
Chris@200 4003 dialog.exec();
Chris@0 4004 }
Chris@0 4005
Chris@0 4006 void
Chris@233 4007 MainWindow::modelGenerationFailed(QString transformName, QString message)
Chris@233 4008 {
Chris@247 4009 emit hideSplash();
Chris@247 4010
Chris@233 4011 if (message != "") {
Chris@233 4012
Chris@233 4013 QMessageBox::warning
Chris@233 4014 (this,
Chris@233 4015 tr("Failed to generate layer"),
Chris@233 4016 tr("<b>Layer generation failed</b><p>Failed to generate derived layer.<p>The layer transform \"%1\" failed:<p>%2")
Chris@233 4017 .arg(transformName).arg(message),
Chris@233 4018 QMessageBox::Ok);
Chris@233 4019 } else {
Chris@233 4020 QMessageBox::warning
Chris@233 4021 (this,
Chris@233 4022 tr("Failed to generate layer"),
Chris@233 4023 tr("<b>Layer generation failed</b><p>Failed to generate a derived layer.<p>The layer transform \"%1\" failed.<p>No error information is available.")
Chris@233 4024 .arg(transformName),
Chris@233 4025 QMessageBox::Ok);
Chris@233 4026 }
Chris@233 4027 }
Chris@233 4028
Chris@233 4029 void
Chris@233 4030 MainWindow::modelGenerationWarning(QString transformName, QString message)
Chris@233 4031 {
Chris@247 4032 emit hideSplash();
Chris@247 4033
Chris@233 4034 QMessageBox::warning
Chris@233 4035 (this, tr("Warning"), message, QMessageBox::Ok);
Chris@233 4036 }
Chris@233 4037
Chris@233 4038 void
Chris@233 4039 MainWindow::modelRegenerationFailed(QString layerName,
Chris@233 4040 QString transformName, QString message)
Chris@233 4041 {
Chris@247 4042 emit hideSplash();
Chris@247 4043
Chris@233 4044 if (message != "") {
Chris@233 4045
Chris@233 4046 QMessageBox::warning
Chris@233 4047 (this,
Chris@233 4048 tr("Failed to regenerate layer"),
Chris@233 4049 tr("<b>Layer generation failed</b><p>Failed to regenerate derived layer \"%1\" using new data model as input.<p>The layer transform \"%2\" failed:<p>%3")
Chris@233 4050 .arg(layerName).arg(transformName).arg(message),
Chris@233 4051 QMessageBox::Ok);
Chris@233 4052 } else {
Chris@233 4053 QMessageBox::warning
Chris@233 4054 (this,
Chris@233 4055 tr("Failed to regenerate layer"),
Chris@233 4056 tr("<b>Layer generation failed</b><p>Failed to regenerate derived layer \"%1\" using new data model as input.<p>The layer transform \"%2\" failed.<p>No error information is available.")
Chris@233 4057 .arg(layerName).arg(transformName),
Chris@233 4058 QMessageBox::Ok);
Chris@233 4059 }
Chris@233 4060 }
Chris@233 4061
Chris@233 4062 void
Chris@233 4063 MainWindow::modelRegenerationWarning(QString layerName,
Chris@233 4064 QString transformName, QString message)
Chris@233 4065 {
Chris@247 4066 emit hideSplash();
Chris@247 4067
Chris@233 4068 QMessageBox::warning
Chris@233 4069 (this, tr("Warning"), tr("<b>Warning when regenerating layer</b><p>When regenerating the derived layer \"%1\" using new data model as input:<p>%2").arg(layerName).arg(message), QMessageBox::Ok);
Chris@233 4070 }
Chris@233 4071
Chris@233 4072 void
Chris@233 4073 MainWindow::alignmentFailed(QString transformName, QString message)
Chris@0 4074 {
Chris@247 4075 emit hideSplash();
Chris@247 4076
Chris@0 4077 QMessageBox::warning
Chris@0 4078 (this,
Chris@233 4079 tr("Failed to calculate alignment"),
Chris@233 4080 tr("<b>Alignment calculation failed</b><p>Failed to calculate an audio alignment using transform \"%1\":<p>%2")
Chris@233 4081 .arg(transformName).arg(message),
Chris@165 4082 QMessageBox::Ok);
Chris@0 4083 }
Chris@0 4084
Chris@0 4085 void
Chris@0 4086 MainWindow::rightButtonMenuRequested(Pane *pane, QPoint position)
Chris@0 4087 {
Chris@438 4088 // SVDEBUG << "MainWindow::rightButtonMenuRequested(" << pane << ", " << position.x() << ", " << position.y() << ")" << endl;
Chris@0 4089 m_paneStack->setCurrentPane(pane);
Chris@0 4090 m_rightButtonMenu->popup(position);
Chris@0 4091 }
Chris@0 4092
Chris@0 4093 void
Chris@0 4094 MainWindow::showLayerTree()
Chris@0 4095 {
Chris@219 4096 if (!m_layerTreeDialog.isNull()) {
Chris@219 4097 m_layerTreeDialog->show();
Chris@219 4098 m_layerTreeDialog->raise();
Chris@177 4099 return;
Chris@177 4100 }
Chris@177 4101
Chris@219 4102 m_layerTreeDialog = new LayerTreeDialog(m_paneStack);
Chris@232 4103 m_layerTreeDialog->setAttribute(Qt::WA_DeleteOnClose); // see below
Chris@219 4104 m_layerTreeDialog->show();
Chris@0 4105 }
Chris@0 4106
Chris@0 4107 void
Chris@306 4108 MainWindow::showActivityLog()
Chris@306 4109 {
Chris@306 4110 m_activityLog->show();
Chris@306 4111 m_activityLog->raise();
Chris@306 4112 m_activityLog->scrollToEnd();
Chris@306 4113 }
Chris@306 4114
Chris@306 4115 void
Chris@0 4116 MainWindow::preferences()
Chris@0 4117 {
Chris@436 4118 bool goToTemplateTab =
Chris@436 4119 (sender() && sender()->objectName() == "set_default_template");
Chris@436 4120
Chris@0 4121 if (!m_preferencesDialog.isNull()) {
Chris@0 4122 m_preferencesDialog->show();
Chris@0 4123 m_preferencesDialog->raise();
Chris@436 4124 if (goToTemplateTab) {
Chris@436 4125 m_preferencesDialog->switchToTab(PreferencesDialog::TemplateTab);
Chris@436 4126 }
Chris@0 4127 return;
Chris@0 4128 }
Chris@0 4129
Chris@0 4130 m_preferencesDialog = new PreferencesDialog(this);
Chris@0 4131
Chris@0 4132 // DeleteOnClose is safe here, because m_preferencesDialog is a
Chris@0 4133 // QPointer that will be zeroed when the dialog is deleted. We
Chris@0 4134 // use it in preference to leaving the dialog lying around because
Chris@0 4135 // if you Cancel the dialog, it resets the preferences state
Chris@0 4136 // without resetting its own widgets, so its state will be
Chris@0 4137 // incorrect when next shown unless we construct it afresh
Chris@0 4138 m_preferencesDialog->setAttribute(Qt::WA_DeleteOnClose);
Chris@0 4139
Chris@0 4140 m_preferencesDialog->show();
Chris@436 4141 if (goToTemplateTab) {
Chris@436 4142 m_preferencesDialog->switchToTab(PreferencesDialog::TemplateTab);
Chris@436 4143 }
Chris@0 4144 }
Chris@0 4145
Chris@0 4146 void
Chris@90 4147 MainWindow::mouseEnteredWidget()
Chris@90 4148 {
Chris@90 4149 QWidget *w = dynamic_cast<QWidget *>(sender());
Chris@90 4150 if (!w) return;
Chris@90 4151
Chris@90 4152 if (w == m_fader) {
Chris@116 4153 contextHelpChanged(tr("Adjust the master playback level"));
Chris@90 4154 } else if (w == m_playSpeed) {
Chris@116 4155 contextHelpChanged(tr("Adjust the master playback speed"));
Chris@90 4156 }
Chris@90 4157 }
Chris@90 4158
Chris@90 4159 void
Chris@90 4160 MainWindow::mouseLeftWidget()
Chris@90 4161 {
Chris@116 4162 contextHelpChanged("");
Chris@116 4163 }
Chris@116 4164
Chris@116 4165 void
Chris@0 4166 MainWindow::website()
Chris@0 4167 {
Chris@0 4168 openHelpUrl(tr("http://www.sonicvisualiser.org/"));
Chris@0 4169 }
Chris@0 4170
Chris@0 4171 void
Chris@0 4172 MainWindow::help()
Chris@0 4173 {
Chris@318 4174 openHelpUrl(tr("http://www.sonicvisualiser.org/doc/reference/%1/en/").arg(SV_VERSION));
Chris@0 4175 }
Chris@0 4176
Chris@0 4177 void
Chris@0 4178 MainWindow::about()
Chris@0 4179 {
Chris@0 4180 bool debug = false;
Chris@0 4181 QString version = "(unknown version)";
Chris@0 4182
Chris@0 4183 #ifdef BUILD_DEBUG
Chris@0 4184 debug = true;
Chris@285 4185 #endif // BUILD_DEBUG
Chris@0 4186 #ifdef SV_VERSION
Chris@0 4187 #ifdef SVNREV
Chris@0 4188 version = tr("Release %1 : Revision %2").arg(SV_VERSION).arg(SVNREV);
Chris@285 4189 #else // !SVNREV
Chris@0 4190 version = tr("Release %1").arg(SV_VERSION);
Chris@285 4191 #endif // SVNREV
Chris@285 4192 #else // !SV_VERSION
Chris@0 4193 #ifdef SVNREV
Chris@0 4194 version = tr("Unreleased : Revision %1").arg(SVNREV);
Chris@285 4195 #endif // SVNREV
Chris@285 4196 #endif // SV_VERSION
Chris@0 4197
Chris@0 4198 QString aboutText;
Chris@0 4199
mathieu@406 4200 aboutText += tr("<h3>About Sonic Visualiser (Kiosk edition)</h3>");
mathieu@406 4201 aboutText += tr("<p>Sonic Visualiser is a program for viewing and exploring audio data for semantic music analysis and annotation. The Kiosk edition provides all of the features of the full Sonic Visualiser, except that audio files cannot be saved from it. <br><a href=\"http://www.sonicvisualiser.org/\">http://www.sonicvisualiser.org/</a></p>");
Chris@285 4202 aboutText += tr("<p><small>%1 : %2 configuration</small></p>")
Chris@0 4203 .arg(version)
Chris@0 4204 .arg(debug ? tr("Debug") : tr("Release"));
Chris@0 4205
Chris@285 4206 aboutText += "<small>";
Chris@285 4207
Chris@285 4208 aboutText += tr("With Qt v%1 &copy; Nokia Corporation").arg(QT_VERSION_STR);
Chris@285 4209
Chris@0 4210 #ifdef HAVE_JACK
Chris@93 4211 #ifdef JACK_VERSION
Chris@285 4212 aboutText += tr("<br>With JACK audio output library v%1 &copy; Paul Davis and Jack O'Quin").arg(JACK_VERSION);
Chris@285 4213 #else // !JACK_VERSION
Chris@257 4214 aboutText += tr("<br>With JACK audio output library &copy; Paul Davis and Jack O'Quin");
Chris@285 4215 #endif // JACK_VERSION
Chris@285 4216 #endif // HAVE_JACK
Chris@0 4217 #ifdef HAVE_PORTAUDIO
Chris@257 4218 aboutText += tr("<br>With PortAudio audio output library &copy; Ross Bencina and Phil Burk");
Chris@285 4219 #endif // HAVE_PORTAUDIO
Chris@257 4220 #ifdef HAVE_LIBPULSE
Chris@285 4221 #ifdef LIBPULSE_VERSION
Chris@285 4222 aboutText += tr("<br>With PulseAudio audio output library v%1 &copy; Lennart Poettering and Pierre Ossman").arg(LIBPULSE_VERSION);
Chris@285 4223 #else // !LIBPULSE_VERSION
Chris@257 4224 aboutText += tr("<br>With PulseAudio audio output library &copy; Lennart Poettering and Pierre Ossman");
Chris@285 4225 #endif // LIBPULSE_VERSION
Chris@285 4226 #endif // HAVE_LIBPULSE
Chris@0 4227 #ifdef HAVE_OGGZ
Chris@93 4228 #ifdef OGGZ_VERSION
Chris@0 4229 aboutText += tr("<br>With Ogg file decoder (oggz v%1, fishsound v%2) &copy; CSIRO Australia").arg(OGGZ_VERSION).arg(FISHSOUND_VERSION);
Chris@285 4230 #else // !OGGZ_VERSION
Chris@93 4231 aboutText += tr("<br>With Ogg file decoder &copy; CSIRO Australia");
Chris@285 4232 #endif // OGGZ_VERSION
Chris@285 4233 #endif // HAVE_OGGZ
Chris@0 4234 #ifdef HAVE_MAD
Chris@93 4235 #ifdef MAD_VERSION
Chris@285 4236 aboutText += tr("<br>With MAD mp3 decoder v%1 &copy; Underbit Technologies Inc").arg(MAD_VERSION);
Chris@285 4237 #else // !MAD_VERSION
Chris@93 4238 aboutText += tr("<br>With MAD mp3 decoder &copy; Underbit Technologies Inc");
Chris@285 4239 #endif // MAD_VERSION
Chris@285 4240 #endif // HAVE_MAD
Chris@0 4241 #ifdef HAVE_SAMPLERATE
Chris@93 4242 #ifdef SAMPLERATE_VERSION
Chris@285 4243 aboutText += tr("<br>With libsamplerate v%1 &copy; Erik de Castro Lopo").arg(SAMPLERATE_VERSION);
Chris@285 4244 #else // !SAMPLERATE_VERSION
Chris@93 4245 aboutText += tr("<br>With libsamplerate &copy; Erik de Castro Lopo");
Chris@285 4246 #endif // SAMPLERATE_VERSION
Chris@285 4247 #endif // HAVE_SAMPLERATE
Chris@0 4248 #ifdef HAVE_SNDFILE
Chris@93 4249 #ifdef SNDFILE_VERSION
Chris@285 4250 aboutText += tr("<br>With libsndfile v%1 &copy; Erik de Castro Lopo").arg(SNDFILE_VERSION);
Chris@285 4251 #else // !SNDFILE_VERSION
Chris@93 4252 aboutText += tr("<br>With libsndfile &copy; Erik de Castro Lopo");
Chris@285 4253 #endif // SNDFILE_VERSION
Chris@285 4254 #endif // HAVE_SNDFILE
Chris@127 4255 #ifdef HAVE_FFTW3F
Chris@93 4256 #ifdef FFTW3_VERSION
Chris@285 4257 aboutText += tr("<br>With FFTW3 v%1 &copy; Matteo Frigo and MIT").arg(FFTW3_VERSION);
Chris@285 4258 #else // !FFTW3_VERSION
Chris@93 4259 aboutText += tr("<br>With FFTW3 &copy; Matteo Frigo and MIT");
Chris@285 4260 #endif // FFTW3_VERSION
Chris@285 4261 #endif // HAVE_FFTW3F
Chris@267 4262 #ifdef HAVE_RUBBERBAND
Chris@267 4263 #ifdef RUBBERBAND_VERSION
Chris@285 4264 aboutText += tr("<br>With Rubber Band v%1 &copy; Chris Cannam").arg(RUBBERBAND_VERSION);
Chris@285 4265 #else // !RUBBERBAND_VERSION
Chris@267 4266 aboutText += tr("<br>With Rubber Band &copy; Chris Cannam");
Chris@285 4267 #endif // RUBBERBAND_VERSION
Chris@285 4268 #endif // HAVE_RUBBERBAND
Chris@0 4269 #ifdef HAVE_VAMP
Chris@114 4270 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@285 4271 #endif // !HAVE_VAMP
Chris@0 4272 aboutText += tr("<br>With LADSPA plugin support (API v%1) &copy; Richard Furse, Paul Davis, Stefan Westerfeld").arg(LADSPA_VERSION);
Chris@0 4273 aboutText += tr("<br>With DSSI plugin support (API v%1) &copy; Chris Cannam, Steve Harris, Sean Bolton").arg(DSSI_VERSION);
Chris@285 4274 #ifdef RAPTOR_VERSION
Chris@285 4275 aboutText += tr("<br>With Raptor RDF parser v%1 &copy; Dave Beckett and the University of Bristol").arg(RAPTOR_VERSION);
Chris@285 4276 #else // !RAPTOR_VERSION
Chris@285 4277 aboutText += tr("<br>With Raptor RDF parser &copy; Dave Beckett and the University of Bristol");
Chris@285 4278 #endif // RAPTOR_VERSION
Chris@285 4279 #ifdef RASQAL_VERSION
Chris@285 4280 aboutText += tr("<br>With Rasqal RDF query engine v%1 &copy; Dave Beckett and the University of Bristol").arg(RASQAL_VERSION);
Chris@285 4281 #else // !RASQAL_VERSION
Chris@285 4282 aboutText += tr("<br>With Rasqal RDF query engine &copy; Dave Beckett and the University of Bristol");
Chris@285 4283 #endif // RASQAL_VERSION
Chris@285 4284 #ifdef HAVE_REDLAND
Chris@285 4285 #ifdef REDLAND_VERSION
Chris@285 4286 aboutText += tr("<br>With Redland RDF datastore v%1 &copy; Dave Beckett and the University of Bristol").arg(REDLAND_VERSION);
Chris@285 4287 #else // !REDLAND_VERSION
Chris@285 4288 aboutText += tr("<br>With Redland RDF datastore &copy; Dave Beckett and the University of Bristol");
Chris@285 4289 #endif // REDLAND_VERSION
Chris@285 4290 #endif // HAVE_REDLAND
Chris@285 4291
Chris@300 4292 aboutText += tr("<br>With RtMidi &copy; Gary P. Scavone");
Chris@300 4293
Chris@69 4294 #ifdef HAVE_LIBLO
Chris@93 4295 #ifdef LIBLO_VERSION
Chris@285 4296 aboutText += tr("<br>With liblo Lite OSC library v%1 &copy; Steve Harris").arg(LIBLO_VERSION);
Chris@285 4297 #else // !LIBLO_VERSION
Chris@327 4298 aboutText += tr("<br>With liblo Lite OSC library &copy; Steve Harris");
Chris@285 4299 #endif // LIBLO_VERSION
Chris@285 4300
Chris@285 4301 if (m_oscQueue && m_oscQueue->isOK()) {
Chris@285 4302 aboutText += tr("</small><p><small>The OSC URL for this instance is: \"%1\"").arg(m_oscQueue->getOSCURL());
Chris@285 4303 }
Chris@285 4304
Chris@285 4305 aboutText += "</small></p>";
Chris@285 4306 #endif // HAVE_LIBLO
Chris@285 4307
Chris@285 4308 #ifndef BUILD_STATIC
Chris@285 4309 aboutText.replace(tr("With "), tr("Using "));
Chris@93 4310 #endif
Chris@0 4311
Chris@0 4312 aboutText +=
Chris@392 4313 "<p><small>Sonic Visualiser Copyright &copy; 2005&ndash;2011 Chris Cannam and "
Chris@285 4314 "Queen Mary, University of London.</small></p>"
Chris@285 4315 "<p><small>This program is free software; you can redistribute it and/or "
Chris@231 4316 "modify it under the terms of the GNU General Public License as "
Chris@231 4317 "published by the Free Software Foundation; either version 2 of the "
Chris@0 4318 "License, or (at your option) any later version.<br>See the file "
Chris@285 4319 "COPYING included with this distribution for more information.</small></p>";
Chris@0 4320
Chris@0 4321 QMessageBox::about(this, tr("About Sonic Visualiser"), aboutText);
Chris@0 4322 }
Chris@0 4323
Chris@162 4324 void
Chris@162 4325 MainWindow::keyReference()
Chris@162 4326 {
Chris@162 4327 m_keyReference->show();
Chris@162 4328 }
Chris@162 4329
Chris@333 4330 void
Chris@333 4331 MainWindow::newerVersionAvailable(QString version)
Chris@333 4332 {
Chris@334 4333 QSettings settings;
Chris@334 4334 settings.beginGroup("NewerVersionWarning");
Chris@334 4335 QString tag = QString("version-%1-available-show").arg(version);
Chris@334 4336 if (settings.value(tag, true).toBool()) {
Chris@334 4337 QString title(tr("Newer version available"));
Chris@334 4338 QString text(tr("<h3>Newer version available</h3><p>You are using version %1 of Sonic Visualiser, but version %3 is now available.</p><p>Please see the <a href=\"http://sonicvisualiser.org/\">Sonic Visualiser website</a> for more information.</p>").arg(SV_VERSION).arg(version));
Chris@334 4339 QMessageBox::information(this, title, text);
Chris@334 4340 settings.setValue(tag, false);
Chris@334 4341 }
Chris@334 4342 settings.endGroup();
Chris@333 4343 }
Chris@333 4344
mathieu@439 4345 void
mathieu@439 4346 MainWindow::toggleViewMode()
mathieu@439 4347 {
Chris@446 4348 QSettings settings;
Chris@446 4349 settings.beginGroup("MainWindow");
Chris@446 4350
Chris@446 4351 bool wasMinimal = m_viewManager->getMinimalModeEnabled();
mathieu@459 4352
mathieu@459 4353 //std::cerr << "minimal mode enabled was: " << wasMinimal << std::endl;
mathieu@459 4354
Chris@445 4355 bool show;
mathieu@439 4356
Chris@464 4357 int maxHeight = QWIDGETSIZE_MAX;
Chris@464 4358
Chris@446 4359 if (wasMinimal) {
Chris@448 4360
Chris@445 4361 show = true;
mathieu@439 4362 m_viewManager->setMinimalModeEnabled(false);
Chris@444 4363 m_scroll->show();
Chris@448 4364
Chris@448 4365 // Restore the hidden menus. We need to make sure they go back
Chris@448 4366 // in the right places, so first remove the ones that need to
Chris@448 4367 // be to the right of them and then add those back in as well
Chris@448 4368 // at the appropriate point
Chris@448 4369 menuBar()->removeAction(m_helpMenu->menuAction());
Chris@450 4370 menuBar()->removeAction(m_playbackMenu->menuAction());
Chris@448 4371 menuBar()->removeAction(m_viewMenu->menuAction());
Chris@448 4372 menuBar()->addMenu(m_editMenu);
Chris@448 4373 menuBar()->addMenu(m_viewMenu);
Chris@448 4374 menuBar()->addMenu(m_paneMenu);
Chris@448 4375 menuBar()->addMenu(m_layerMenu);
Chris@448 4376 menuBar()->addMenu(m_transformsMenu);
Chris@448 4377 menuBar()->addMenu(m_playbackMenu);
Chris@448 4378 menuBar()->addMenu(m_helpMenu);
Chris@448 4379
mathieu@439 4380 } else {
Chris@448 4381
Chris@446 4382 settings.setValue("size", size());
Chris@448 4383
Chris@464 4384 maxHeight = height() - m_scroll->height();
Chris@464 4385
Chris@445 4386 show = false;
mathieu@439 4387 m_viewManager->setMinimalModeEnabled(true);
Chris@444 4388 m_scroll->hide();
Chris@448 4389
Chris@448 4390 menuBar()->removeAction(m_transformsMenu->menuAction());
Chris@448 4391 menuBar()->removeAction(m_layerMenu->menuAction());
Chris@448 4392 menuBar()->removeAction(m_paneMenu->menuAction());
Chris@448 4393 menuBar()->removeAction(m_editMenu->menuAction());
mathieu@439 4394 }
mathieu@439 4395
Chris@449 4396 QGridLayout *layout = qobject_cast<QGridLayout *>
Chris@449 4397 (centralWidget()->layout());
Chris@449 4398 if (layout) {
Chris@449 4399 layout->setColumnMinimumWidth(0, wasMinimal ? 14 : 0);
Chris@449 4400 }
Chris@449 4401
mathieu@439 4402 //cerr << "Call to MainWindow::toggleViewMode"<< endl;
mathieu@439 4403
Chris@445 4404 m_playModeToolBar->setVisible(show);
Chris@445 4405 m_editToolBar->setVisible(show);
Chris@445 4406 m_toolsToolBar->setVisible(show);
Chris@445 4407
mathieu@458 4408 //add/remove actions from the File menu
Chris@445 4409 m_importAnnotationLayerAction->setVisible(show);
Chris@445 4410 m_exportAnnotationLayerAction->setVisible(show);
mathieu@458 4411 //add/remove actions from the View menu
Chris@445 4412 m_showNoOverlaysAction->setVisible(show);
Chris@445 4413 m_showMinimalOverlaysAction->setVisible(show);
Chris@445 4414 m_showStandardOverlaysAction->setVisible(show);
Chris@445 4415 m_showAllOverlaysAction->setVisible(show);
Chris@445 4416 m_showAllTimeRulersAction->setVisible(show);
Chris@445 4417 m_showZoomWheelsAction->setVisible(show);
Chris@445 4418 m_showPropertyBoxesAction->setVisible(show);
Chris@445 4419 m_showStatusBarAction->setVisible(show);
mathieu@458 4420 //add/remove actions from the Playback menu
mathieu@458 4421 m_playSelectionAction->setVisible(show);
mathieu@458 4422 m_playLoopAction->setVisible(show);
mathieu@458 4423 m_soloAction->setVisible(show);
Chris@464 4424 if (m_alAction) m_alAction->setVisible(show);
mathieu@439 4425
Chris@449 4426 m_playControlsSpacer->setVisible(show);
Chris@446 4427
Chris@464 4428 setMaximumHeight(maxHeight);
Chris@464 4429
Chris@446 4430 if (wasMinimal) {
Chris@446 4431 resizeConstrained(settings.value("size").toSize());
Chris@446 4432 } else {
Chris@447 4433 QApplication::processEvents();
mathieu@459 4434 adjustSize();
Chris@446 4435 }
Chris@446 4436
Chris@446 4437 settings.endGroup();
mathieu@439 4438
mathieu@439 4439 //TO-DOS:
mathieu@459 4440 //- The Constrain Playback to Selection option is still effective when the minimal mode is activated whereas
mathieu@458 4441 //the functionality to modify the selection has been removed from this mode. Playback mode should switch to
mathieu@458 4442 //normal when the minimal mode is activated and then be set up again to what it was when the full mode is
mathieu@458 4443 //activated again.
mathieu@459 4444 //- after adding the minimal mode at startup option in Preferences/Appearance, the minimal mode window size
mathieu@459 4445 //is not optimized as before
mathieu@458 4446
mathieu@458 4447 //done:
mathieu@439 4448 //- when switching back to full mode, the pane is not shown entirely, should restore the previous size
mathieu@439 4449 //- the size of the overview (namely its width) should be increased when the minimal mode is activated
mathieu@439 4450 //- the menus which have no effects in the minimal mode should be removed (or their actions disabled)
mathieu@439 4451 //even if this doesn't lead cause the application to crash (the actual changes are made in the hidden pane(s))
mathieu@439 4452 //- the menu actions which have no effects in the minimal mode should be removed or disabled
mathieu@459 4453 //- add Minimal mode at startup in the Preferences/Appearance
mathieu@439 4454 }
mathieu@439 4455