annotate main/MainWindow.cpp @ 406:d70890996156 kiosk

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