annotate main/MainWindow.cpp @ 485:b6c00a0a618e integration_library

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