annotate main/MainWindow.cpp @ 484:1f3afbce6c2f integration_library

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