annotate main/MainWindow.cpp @ 482:e5c6aed2bf6b integration_library

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