annotate src/MainWindow.cpp @ 0:158f40a613a5

Initial import of material from SV and Vect. This builds and runs, but does not yet have the layout we need
author Chris Cannam
date Fri, 16 Nov 2012 11:48:16 +0000
parents
children a11a9c04df44
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 Tony
Chris@0 5 An intonation analysis and annotation tool
Chris@0 6 Centre for Digital Music, Queen Mary, University of London.
Chris@0 7 This file copyright 2006-2012 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@0 16 #include "../version.h"
Chris@0 17
Chris@0 18 #include "MainWindow.h"
Chris@0 19 #include "framework/Document.h"
Chris@0 20
Chris@0 21 #include "view/Pane.h"
Chris@0 22 #include "view/PaneStack.h"
Chris@0 23 #include "data/model/WaveFileModel.h"
Chris@0 24 #include "data/model/SparseOneDimensionalModel.h"
Chris@0 25 #include "data/model/FFTModel.h"
Chris@0 26 #include "view/ViewManager.h"
Chris@0 27 #include "base/Preferences.h"
Chris@0 28 #include "layer/WaveformLayer.h"
Chris@0 29 #include "layer/TimeRulerLayer.h"
Chris@0 30 #include "layer/TimeInstantLayer.h"
Chris@0 31 #include "layer/TimeValueLayer.h"
Chris@0 32 #include "layer/Colour3DPlotLayer.h"
Chris@0 33 #include "layer/SliceLayer.h"
Chris@0 34 #include "layer/SliceableLayer.h"
Chris@0 35 #include "widgets/Fader.h"
Chris@0 36 #include "view/Overview.h"
Chris@0 37 #include "widgets/PropertyBox.h"
Chris@0 38 #include "widgets/PropertyStack.h"
Chris@0 39 #include "widgets/AudioDial.h"
Chris@0 40 #include "widgets/IconLoader.h"
Chris@0 41 #include "widgets/LayerTree.h"
Chris@0 42 #include "widgets/ListInputDialog.h"
Chris@0 43 #include "widgets/SubdividingMenu.h"
Chris@0 44 #include "widgets/NotifyingPushButton.h"
Chris@0 45 #include "widgets/KeyReference.h"
Chris@0 46 #include "audioio/AudioCallbackPlaySource.h"
Chris@0 47 #include "audioio/AudioCallbackPlayTarget.h"
Chris@0 48 #include "audioio/AudioTargetFactory.h"
Chris@0 49 #include "audioio/PlaySpeedRangeMapper.h"
Chris@0 50 #include "data/fileio/DataFileReaderFactory.h"
Chris@0 51 #include "data/fileio/PlaylistFileReader.h"
Chris@0 52 #include "data/fileio/WavFileWriter.h"
Chris@0 53 #include "data/fileio/CSVFileWriter.h"
Chris@0 54 #include "data/fileio/BZipFileDevice.h"
Chris@0 55 #include "data/fileio/FileSource.h"
Chris@0 56 #include "data/fft/FFTDataServer.h"
Chris@0 57 #include "base/RecentFiles.h"
Chris@0 58 #include "transform/TransformFactory.h"
Chris@0 59 #include "transform/ModelTransformerFactory.h"
Chris@0 60 #include "base/PlayParameterRepository.h"
Chris@0 61 #include "base/XmlExportable.h"
Chris@0 62 #include "widgets/CommandHistory.h"
Chris@0 63 #include "base/Profiler.h"
Chris@0 64 #include "base/Clipboard.h"
Chris@0 65 #include "base/UnitDatabase.h"
Chris@0 66 #include "layer/ColourDatabase.h"
Chris@0 67 #include "data/osc/OSCQueue.h"
Chris@0 68
Chris@0 69 // For version information
Chris@0 70 #include "vamp/vamp.h"
Chris@0 71 #include "vamp-sdk/PluginBase.h"
Chris@0 72 #include "plugin/api/ladspa.h"
Chris@0 73 #include "plugin/api/dssi.h"
Chris@0 74
Chris@0 75 #include <QApplication>
Chris@0 76 #include <QMessageBox>
Chris@0 77 #include <QGridLayout>
Chris@0 78 #include <QLabel>
Chris@0 79 #include <QAction>
Chris@0 80 #include <QMenuBar>
Chris@0 81 #include <QToolBar>
Chris@0 82 #include <QToolButton>
Chris@0 83 #include <QButtonGroup>
Chris@0 84 #include <QInputDialog>
Chris@0 85 #include <QStatusBar>
Chris@0 86 #include <QTreeView>
Chris@0 87 #include <QFile>
Chris@0 88 #include <QFileInfo>
Chris@0 89 #include <QDir>
Chris@0 90 #include <QTextStream>
Chris@0 91 #include <QProcess>
Chris@0 92 #include <QShortcut>
Chris@0 93 #include <QSettings>
Chris@0 94 #include <QDateTime>
Chris@0 95 #include <QProcess>
Chris@0 96 #include <QCheckBox>
Chris@0 97 #include <QRegExp>
Chris@0 98 #include <QScrollArea>
Chris@0 99
Chris@0 100 #include <iostream>
Chris@0 101 #include <cstdio>
Chris@0 102 #include <errno.h>
Chris@0 103
Chris@0 104 using std::cerr;
Chris@0 105 using std::endl;
Chris@0 106
Chris@0 107 using std::vector;
Chris@0 108 using std::map;
Chris@0 109 using std::set;
Chris@0 110
Chris@0 111
Chris@0 112 MainWindow::MainWindow(bool withAudioOutput, bool withOSCSupport) :
Chris@0 113 MainWindowBase(withAudioOutput, withOSCSupport, false),
Chris@0 114 m_overview(0),
Chris@0 115 m_mainMenusCreated(false),
Chris@0 116 m_playbackMenu(0),
Chris@0 117 m_recentFilesMenu(0),
Chris@0 118 m_rightButtonMenu(0),
Chris@0 119 m_rightButtonPlaybackMenu(0),
Chris@0 120 m_deleteSelectedAction(0),
Chris@0 121 m_ffwdAction(0),
Chris@0 122 m_rwdAction(0),
Chris@0 123 m_layerTreeView(0),
Chris@0 124 m_keyReference(new KeyReference())
Chris@0 125 {
Chris@0 126 setWindowTitle(QApplication::applicationName());
Chris@0 127
Chris@0 128 UnitDatabase *udb = UnitDatabase::getInstance();
Chris@0 129 udb->registerUnit("Hz");
Chris@0 130 udb->registerUnit("dB");
Chris@0 131 udb->registerUnit("s");
Chris@0 132
Chris@0 133 ColourDatabase *cdb = ColourDatabase::getInstance();
Chris@0 134 cdb->addColour(Qt::black, tr("Black"));
Chris@0 135 cdb->addColour(Qt::darkRed, tr("Red"));
Chris@0 136 cdb->addColour(Qt::darkBlue, tr("Blue"));
Chris@0 137 cdb->addColour(Qt::darkGreen, tr("Green"));
Chris@0 138 cdb->addColour(QColor(200, 50, 255), tr("Purple"));
Chris@0 139 cdb->addColour(QColor(255, 150, 50), tr("Orange"));
Chris@0 140 cdb->setUseDarkBackground(cdb->addColour(Qt::white, tr("White")), true);
Chris@0 141 cdb->setUseDarkBackground(cdb->addColour(Qt::red, tr("Bright Red")), true);
Chris@0 142 cdb->setUseDarkBackground(cdb->addColour(QColor(30, 150, 255), tr("Bright Blue")), true);
Chris@0 143 cdb->setUseDarkBackground(cdb->addColour(Qt::green, tr("Bright Green")), true);
Chris@0 144 cdb->setUseDarkBackground(cdb->addColour(QColor(225, 74, 255), tr("Bright Purple")), true);
Chris@0 145 cdb->setUseDarkBackground(cdb->addColour(QColor(255, 188, 80), tr("Bright Orange")), true);
Chris@0 146
Chris@0 147 Preferences::getInstance()->setResampleOnLoad(true);
Chris@0 148 Preferences::getInstance()->setSpectrogramSmoothing
Chris@0 149 (Preferences::SpectrogramInterpolated);
Chris@0 150
Chris@0 151 QSettings settings;
Chris@0 152
Chris@0 153 settings.beginGroup("LayerDefaults");
Chris@0 154
Chris@0 155 settings.setValue("waveform",
Chris@0 156 QString("<layer scale=\"%1\" channelMode=\"%2\"/>")
Chris@0 157 .arg(int(WaveformLayer::MeterScale))
Chris@0 158 // .arg(int(WaveformLayer::LinearScale))
Chris@0 159 .arg(int(WaveformLayer::MergeChannels)));
Chris@0 160
Chris@0 161 settings.setValue("timevalues",
Chris@0 162 QString("<layer plotStyle=\"%1\"/>")
Chris@0 163 .arg(int(TimeValueLayer::PlotStems)));
Chris@0 164
Chris@0 165 settings.setValue("spectrogram",
Chris@0 166 QString("<layer channel=\"-1\" windowSize=\"2048\" windowHopLevel=\"2\"/>"));
Chris@0 167
Chris@0 168 settings.setValue("melodicrange",
Chris@0 169 QString("<layer channel=\"-1\" gain=\"10\" normalizeVisibleArea=\"false\" normalizeColumns=\"false\" minFrequency=\"100\" maxFrequency=\"1200\" windowSize=\"4096\" windowOverlap=\"75\" binDisplay=\"0\" />"));
Chris@0 170
Chris@0 171 settings.endGroup();
Chris@0 172
Chris@0 173 settings.beginGroup("MainWindow");
Chris@0 174 settings.setValue("showstatusbar", false);
Chris@0 175 settings.endGroup();
Chris@0 176
Chris@0 177 m_viewManager->setAlignMode(true);
Chris@0 178 m_viewManager->setPlaySoloMode(true);
Chris@0 179 m_viewManager->setToolMode(ViewManager::NavigateMode);
Chris@0 180 m_viewManager->setZoomWheelsEnabled(false);
Chris@0 181 m_viewManager->setIlluminateLocalFeatures(false);
Chris@0 182 m_viewManager->setShowWorkTitle(true);
Chris@0 183
Chris@0 184 QFrame *frame = new QFrame;
Chris@0 185 setCentralWidget(frame);
Chris@0 186
Chris@0 187 QGridLayout *layout = new QGridLayout;
Chris@0 188
Chris@0 189 m_descriptionLabel = new QLabel;
Chris@0 190
Chris@0 191 QScrollArea *scroll = new QScrollArea(frame);
Chris@0 192 scroll->setWidgetResizable(true);
Chris@0 193 scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
Chris@0 194 scroll->setFrameShape(QFrame::NoFrame);
Chris@0 195
Chris@0 196 m_paneStack->setLayoutStyle(PaneStack::NoPropertyStacks);
Chris@0 197 scroll->setWidget(m_paneStack);
Chris@0 198
Chris@0 199 m_overview = new Overview(frame);
Chris@0 200 m_overview->setViewManager(m_viewManager);
Chris@0 201 m_overview->setFixedHeight(40);
Chris@0 202 #ifndef _WIN32
Chris@0 203 // For some reason, the contents of the overview never appear if we
Chris@0 204 // make this setting on Windows. I have no inclination at the moment
Chris@0 205 // to track down the reason why.
Chris@0 206 m_overview->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
Chris@0 207 #endif
Chris@0 208 connect(m_overview, SIGNAL(contextHelpChanged(const QString &)),
Chris@0 209 this, SLOT(contextHelpChanged(const QString &)));
Chris@0 210 m_overview->hide();
Chris@0 211
Chris@0 212 m_panLayer = new WaveformLayer;
Chris@0 213 m_panLayer->setChannelMode(WaveformLayer::MergeChannels);
Chris@0 214 m_panLayer->setAggressiveCacheing(true);
Chris@0 215 m_overview->addLayer(m_panLayer);
Chris@0 216
Chris@0 217 if (m_viewManager->getGlobalDarkBackground()) {
Chris@0 218 m_panLayer->setBaseColour
Chris@0 219 (ColourDatabase::getInstance()->getColourIndex(tr("Bright Green")));
Chris@0 220 } else {
Chris@0 221 m_panLayer->setBaseColour
Chris@0 222 (ColourDatabase::getInstance()->getColourIndex(tr("Green")));
Chris@0 223 }
Chris@0 224
Chris@0 225 m_fader = new Fader(frame, false);
Chris@0 226 connect(m_fader, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget()));
Chris@0 227 connect(m_fader, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget()));
Chris@0 228
Chris@0 229 m_playSpeed = new AudioDial(frame);
Chris@0 230 m_playSpeed->setMinimum(0);
Chris@0 231 m_playSpeed->setMaximum(200);
Chris@0 232 m_playSpeed->setValue(100);
Chris@0 233 m_playSpeed->setFixedWidth(24);
Chris@0 234 m_playSpeed->setFixedHeight(24);
Chris@0 235 m_playSpeed->setNotchesVisible(true);
Chris@0 236 m_playSpeed->setPageStep(10);
Chris@0 237 m_playSpeed->setObjectName(tr("Playback Speedup"));
Chris@0 238 m_playSpeed->setDefaultValue(100);
Chris@0 239 m_playSpeed->setRangeMapper(new PlaySpeedRangeMapper(0, 200));
Chris@0 240 m_playSpeed->setShowToolTip(true);
Chris@0 241 connect(m_playSpeed, SIGNAL(valueChanged(int)),
Chris@0 242 this, SLOT(playSpeedChanged(int)));
Chris@0 243 connect(m_playSpeed, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget()));
Chris@0 244 connect(m_playSpeed, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget()));
Chris@0 245
Chris@0 246 layout->setSpacing(4);
Chris@0 247 layout->addWidget(scroll, 0, 0, 1, 6);
Chris@0 248 layout->addWidget(m_overview, 1, 1);
Chris@0 249 layout->addWidget(m_fader, 1, 2);
Chris@0 250 layout->addWidget(m_playSpeed, 1, 3);
Chris@0 251
Chris@0 252 m_paneStack->setPropertyStackMinWidth
Chris@0 253 (m_fader->width() + m_playSpeed->width() +
Chris@0 254 layout->spacing() * 4);
Chris@0 255
Chris@0 256 layout->setColumnStretch(1, 10);
Chris@0 257
Chris@0 258 frame->setLayout(layout);
Chris@0 259
Chris@0 260 setupMenus();
Chris@0 261 setupToolbars();
Chris@0 262 setupHelpMenu();
Chris@0 263
Chris@0 264 statusBar();
Chris@0 265
Chris@0 266 newSession();
Chris@0 267 }
Chris@0 268
Chris@0 269 MainWindow::~MainWindow()
Chris@0 270 {
Chris@0 271 delete m_keyReference;
Chris@0 272 delete m_layerTreeView;
Chris@0 273 Profiles::getInstance()->dump();
Chris@0 274 }
Chris@0 275
Chris@0 276 void
Chris@0 277 MainWindow::setupMenus()
Chris@0 278 {
Chris@0 279 if (!m_mainMenusCreated) {
Chris@0 280 m_rightButtonMenu = new QMenu();
Chris@0 281 }
Chris@0 282
Chris@0 283 if (!m_mainMenusCreated) {
Chris@0 284 CommandHistory::getInstance()->registerMenu(m_rightButtonMenu);
Chris@0 285 m_rightButtonMenu->addSeparator();
Chris@0 286 }
Chris@0 287
Chris@0 288 setupFileMenu();
Chris@0 289 setupEditMenu();
Chris@0 290 setupViewMenu();
Chris@0 291
Chris@0 292 m_mainMenusCreated = true;
Chris@0 293 }
Chris@0 294
Chris@0 295 void
Chris@0 296 MainWindow::setupFileMenu()
Chris@0 297 {
Chris@0 298 if (m_mainMenusCreated) return;
Chris@0 299
Chris@0 300 QMenu *menu = menuBar()->addMenu(tr("&File"));
Chris@0 301 menu->setTearOffEnabled(true);
Chris@0 302 QToolBar *toolbar = addToolBar(tr("File Toolbar"));
Chris@0 303
Chris@0 304 m_keyReference->setCategory(tr("File and Session Management"));
Chris@0 305
Chris@0 306 IconLoader il;
Chris@0 307
Chris@0 308 QIcon icon = il.load("filenew");
Chris@0 309 icon.addPixmap(il.loadPixmap("filenew-22"));
Chris@0 310 QAction *action = new QAction(icon, tr("&Clear Session"), this);
Chris@0 311 action->setShortcut(tr("Ctrl+N"));
Chris@0 312 action->setStatusTip(tr("Abandon the current session and start a new one"));
Chris@0 313 connect(action, SIGNAL(triggered()), this, SLOT(newSession()));
Chris@0 314 m_keyReference->registerShortcut(action);
Chris@0 315 menu->addAction(action);
Chris@0 316 toolbar->addAction(action);
Chris@0 317
Chris@0 318 icon = il.load("fileopen");
Chris@0 319 icon.addPixmap(il.loadPixmap("fileopen-22"));
Chris@0 320 action = new QAction(icon, tr("&Add File..."), this);
Chris@0 321 action->setShortcut(tr("Ctrl+O"));
Chris@0 322 action->setStatusTip(tr("Add a file"));
Chris@0 323 connect(action, SIGNAL(triggered()), this, SLOT(openFile()));
Chris@0 324 m_keyReference->registerShortcut(action);
Chris@0 325 menu->addAction(action);
Chris@0 326 toolbar->addAction(action);
Chris@0 327
Chris@0 328 action = new QAction(tr("Add Lo&cation..."), this);
Chris@0 329 action->setShortcut(tr("Ctrl+Shift+O"));
Chris@0 330 action->setStatusTip(tr("Add a file from a remote URL"));
Chris@0 331 connect(action, SIGNAL(triggered()), this, SLOT(openLocation()));
Chris@0 332 m_keyReference->registerShortcut(action);
Chris@0 333 menu->addAction(action);
Chris@0 334
Chris@0 335 menu->addSeparator();
Chris@0 336
Chris@0 337 m_recentFilesMenu = menu->addMenu(tr("&Recent Locations"));
Chris@0 338 m_recentFilesMenu->setTearOffEnabled(true);
Chris@0 339 setupRecentFilesMenu();
Chris@0 340 connect(&m_recentFiles, SIGNAL(recentChanged()),
Chris@0 341 this, SLOT(setupRecentFilesMenu()));
Chris@0 342
Chris@0 343 menu->addSeparator();
Chris@0 344 action = new QAction(il.load("exit"), tr("&Quit"), this);
Chris@0 345 action->setShortcut(tr("Ctrl+Q"));
Chris@0 346 action->setStatusTip(tr("Exit %1").arg(QApplication::applicationName()));
Chris@0 347 connect(action, SIGNAL(triggered()), this, SLOT(close()));
Chris@0 348 m_keyReference->registerShortcut(action);
Chris@0 349 menu->addAction(action);
Chris@0 350 }
Chris@0 351
Chris@0 352 void
Chris@0 353 MainWindow::setupEditMenu()
Chris@0 354 {
Chris@0 355 if (m_mainMenusCreated) return;
Chris@0 356
Chris@0 357 QMenu *menu = menuBar()->addMenu(tr("&Edit"));
Chris@0 358 menu->setTearOffEnabled(true);
Chris@0 359 CommandHistory::getInstance()->registerMenu(menu);
Chris@0 360 }
Chris@0 361
Chris@0 362 void
Chris@0 363 MainWindow::setupViewMenu()
Chris@0 364 {
Chris@0 365 if (m_mainMenusCreated) return;
Chris@0 366
Chris@0 367 IconLoader il;
Chris@0 368
Chris@0 369 QAction *action = 0;
Chris@0 370
Chris@0 371 m_keyReference->setCategory(tr("Panning and Navigation"));
Chris@0 372
Chris@0 373 QMenu *menu = menuBar()->addMenu(tr("&View"));
Chris@0 374 menu->setTearOffEnabled(true);
Chris@0 375 action = new QAction(tr("Scroll &Left"), this);
Chris@0 376 action->setShortcut(tr("Left"));
Chris@0 377 action->setStatusTip(tr("Scroll the current pane to the left"));
Chris@0 378 connect(action, SIGNAL(triggered()), this, SLOT(scrollLeft()));
Chris@0 379 connect(this, SIGNAL(canScroll(bool)), action, SLOT(setEnabled(bool)));
Chris@0 380 m_keyReference->registerShortcut(action);
Chris@0 381 menu->addAction(action);
Chris@0 382
Chris@0 383 action = new QAction(tr("Scroll &Right"), this);
Chris@0 384 action->setShortcut(tr("Right"));
Chris@0 385 action->setStatusTip(tr("Scroll the current pane to the right"));
Chris@0 386 connect(action, SIGNAL(triggered()), this, SLOT(scrollRight()));
Chris@0 387 connect(this, SIGNAL(canScroll(bool)), action, SLOT(setEnabled(bool)));
Chris@0 388 m_keyReference->registerShortcut(action);
Chris@0 389 menu->addAction(action);
Chris@0 390
Chris@0 391 action = new QAction(tr("&Jump Left"), this);
Chris@0 392 action->setShortcut(tr("Ctrl+Left"));
Chris@0 393 action->setStatusTip(tr("Scroll the current pane a big step to the left"));
Chris@0 394 connect(action, SIGNAL(triggered()), this, SLOT(jumpLeft()));
Chris@0 395 connect(this, SIGNAL(canScroll(bool)), action, SLOT(setEnabled(bool)));
Chris@0 396 m_keyReference->registerShortcut(action);
Chris@0 397 menu->addAction(action);
Chris@0 398
Chris@0 399 action = new QAction(tr("J&ump Right"), this);
Chris@0 400 action->setShortcut(tr("Ctrl+Right"));
Chris@0 401 action->setStatusTip(tr("Scroll the current pane a big step to the right"));
Chris@0 402 connect(action, SIGNAL(triggered()), this, SLOT(jumpRight()));
Chris@0 403 connect(this, SIGNAL(canScroll(bool)), action, SLOT(setEnabled(bool)));
Chris@0 404 m_keyReference->registerShortcut(action);
Chris@0 405 menu->addAction(action);
Chris@0 406
Chris@0 407 menu->addSeparator();
Chris@0 408
Chris@0 409 m_keyReference->setCategory(tr("Zoom"));
Chris@0 410
Chris@0 411 action = new QAction(il.load("zoom-in"),
Chris@0 412 tr("Zoom &In"), this);
Chris@0 413 action->setShortcut(tr("Up"));
Chris@0 414 action->setStatusTip(tr("Increase the zoom level"));
Chris@0 415 connect(action, SIGNAL(triggered()), this, SLOT(zoomIn()));
Chris@0 416 connect(this, SIGNAL(canZoom(bool)), action, SLOT(setEnabled(bool)));
Chris@0 417 m_keyReference->registerShortcut(action);
Chris@0 418 menu->addAction(action);
Chris@0 419
Chris@0 420 action = new QAction(il.load("zoom-out"),
Chris@0 421 tr("Zoom &Out"), this);
Chris@0 422 action->setShortcut(tr("Down"));
Chris@0 423 action->setStatusTip(tr("Decrease the zoom level"));
Chris@0 424 connect(action, SIGNAL(triggered()), this, SLOT(zoomOut()));
Chris@0 425 connect(this, SIGNAL(canZoom(bool)), action, SLOT(setEnabled(bool)));
Chris@0 426 m_keyReference->registerShortcut(action);
Chris@0 427 menu->addAction(action);
Chris@0 428
Chris@0 429 action = new QAction(tr("Restore &Default Zoom"), this);
Chris@0 430 action->setStatusTip(tr("Restore the zoom level to the default"));
Chris@0 431 connect(action, SIGNAL(triggered()), this, SLOT(zoomDefault()));
Chris@0 432 connect(this, SIGNAL(canZoom(bool)), action, SLOT(setEnabled(bool)));
Chris@0 433 menu->addAction(action);
Chris@0 434
Chris@0 435 action = new QAction(il.load("zoom-fit"),
Chris@0 436 tr("Zoom to &Fit"), this);
Chris@0 437 action->setShortcut(tr("F"));
Chris@0 438 action->setStatusTip(tr("Zoom to show the whole file"));
Chris@0 439 connect(action, SIGNAL(triggered()), this, SLOT(zoomToFit()));
Chris@0 440 connect(this, SIGNAL(canZoom(bool)), action, SLOT(setEnabled(bool)));
Chris@0 441 m_keyReference->registerShortcut(action);
Chris@0 442 menu->addAction(action);
Chris@0 443
Chris@0 444 menu->addSeparator();
Chris@0 445
Chris@0 446 m_keyReference->setCategory(tr("Display Features"));
Chris@0 447
Chris@0 448 QActionGroup *overlayGroup = new QActionGroup(this);
Chris@0 449
Chris@0 450 action = new QAction(tr("Show &No Overlays"), this);
Chris@0 451 action->setShortcut(tr("0"));
Chris@0 452 action->setStatusTip(tr("Hide centre indicator, frame times, layer names and scale"));
Chris@0 453 connect(action, SIGNAL(triggered()), this, SLOT(showNoOverlays()));
Chris@0 454 action->setCheckable(true);
Chris@0 455 action->setChecked(false);
Chris@0 456 overlayGroup->addAction(action);
Chris@0 457 m_keyReference->registerShortcut(action);
Chris@0 458 menu->addAction(action);
Chris@0 459
Chris@0 460 action = new QAction(tr("Show &Minimal Overlays"), this);
Chris@0 461 action->setShortcut(tr("9"));
Chris@0 462 action->setStatusTip(tr("Show centre indicator only"));
Chris@0 463 connect(action, SIGNAL(triggered()), this, SLOT(showMinimalOverlays()));
Chris@0 464 action->setCheckable(true);
Chris@0 465 action->setChecked(false);
Chris@0 466 overlayGroup->addAction(action);
Chris@0 467 m_keyReference->registerShortcut(action);
Chris@0 468 menu->addAction(action);
Chris@0 469
Chris@0 470 action = new QAction(tr("Show &Standard Overlays"), this);
Chris@0 471 action->setShortcut(tr("8"));
Chris@0 472 action->setStatusTip(tr("Show centre indicator, frame times and scale"));
Chris@0 473 connect(action, SIGNAL(triggered()), this, SLOT(showStandardOverlays()));
Chris@0 474 action->setCheckable(true);
Chris@0 475 action->setChecked(true);
Chris@0 476 overlayGroup->addAction(action);
Chris@0 477 m_keyReference->registerShortcut(action);
Chris@0 478 menu->addAction(action);
Chris@0 479
Chris@0 480 action = new QAction(tr("Show &All Overlays"), this);
Chris@0 481 action->setShortcut(tr("7"));
Chris@0 482 action->setStatusTip(tr("Show all texts and scale"));
Chris@0 483 connect(action, SIGNAL(triggered()), this, SLOT(showAllOverlays()));
Chris@0 484 action->setCheckable(true);
Chris@0 485 action->setChecked(false);
Chris@0 486 overlayGroup->addAction(action);
Chris@0 487 m_keyReference->registerShortcut(action);
Chris@0 488 menu->addAction(action);
Chris@0 489
Chris@0 490 menu->addSeparator();
Chris@0 491
Chris@0 492 action = new QAction(tr("Show &Zoom Wheels"), this);
Chris@0 493 action->setShortcut(tr("Z"));
Chris@0 494 action->setStatusTip(tr("Show thumbwheels for zooming horizontally and vertically"));
Chris@0 495 connect(action, SIGNAL(triggered()), this, SLOT(toggleZoomWheels()));
Chris@0 496 action->setCheckable(true);
Chris@0 497 action->setChecked(m_viewManager->getZoomWheelsEnabled());
Chris@0 498 m_keyReference->registerShortcut(action);
Chris@0 499 menu->addAction(action);
Chris@0 500
Chris@0 501 action = new QAction(tr("Show Property Bo&xes"), this);
Chris@0 502 action->setShortcut(tr("X"));
Chris@0 503 action->setStatusTip(tr("Show the layer property boxes at the side of the main window"));
Chris@0 504 connect(action, SIGNAL(triggered()), this, SLOT(togglePropertyBoxes()));
Chris@0 505 action->setCheckable(true);
Chris@0 506 action->setChecked(false); //!!!
Chris@0 507 m_keyReference->registerShortcut(action);
Chris@0 508 menu->addAction(action);
Chris@0 509
Chris@0 510 action = new QAction(tr("Show Status &Bar"), this);
Chris@0 511 action->setStatusTip(tr("Show context help information in the status bar at the bottom of the window"));
Chris@0 512 connect(action, SIGNAL(triggered()), this, SLOT(toggleStatusBar()));
Chris@0 513 action->setCheckable(true);
Chris@0 514 action->setChecked(true);
Chris@0 515 menu->addAction(action);
Chris@0 516
Chris@0 517 QSettings settings;
Chris@0 518 settings.beginGroup("MainWindow");
Chris@0 519 bool sb = settings.value("showstatusbar", true).toBool();
Chris@0 520 if (!sb) {
Chris@0 521 action->setChecked(false);
Chris@0 522 statusBar()->hide();
Chris@0 523 }
Chris@0 524 settings.endGroup();
Chris@0 525
Chris@0 526 menu->addSeparator();
Chris@0 527
Chris@0 528 action = new QAction(tr("Show La&yer Hierarchy"), this);
Chris@0 529 action->setShortcut(tr("H"));
Chris@0 530 action->setStatusTip(tr("Open a window displaying the hierarchy of panes and layers in this session"));
Chris@0 531 connect(action, SIGNAL(triggered()), this, SLOT(showLayerTree()));
Chris@0 532 m_keyReference->registerShortcut(action);
Chris@0 533 menu->addAction(action);
Chris@0 534 }
Chris@0 535
Chris@0 536 void
Chris@0 537 MainWindow::setupHelpMenu()
Chris@0 538 {
Chris@0 539 QMenu *menu = menuBar()->addMenu(tr("&Help"));
Chris@0 540 menu->setTearOffEnabled(true);
Chris@0 541
Chris@0 542 m_keyReference->setCategory(tr("Help"));
Chris@0 543
Chris@0 544 IconLoader il;
Chris@0 545
Chris@0 546 QAction *action = new QAction(il.load("help"),
Chris@0 547 tr("&Help Reference"), this);
Chris@0 548 action->setShortcut(tr("F1"));
Chris@0 549 action->setStatusTip(tr("Open the reference manual"));
Chris@0 550 connect(action, SIGNAL(triggered()), this, SLOT(help()));
Chris@0 551 m_keyReference->registerShortcut(action);
Chris@0 552 menu->addAction(action);
Chris@0 553
Chris@0 554 action = new QAction(tr("&Key and Mouse Reference"), this);
Chris@0 555 action->setShortcut(tr("F2"));
Chris@0 556 action->setStatusTip(tr("Open a window showing the keystrokes you can use"));
Chris@0 557 connect(action, SIGNAL(triggered()), this, SLOT(keyReference()));
Chris@0 558 m_keyReference->registerShortcut(action);
Chris@0 559 menu->addAction(action);
Chris@0 560
Chris@0 561 action = new QAction(tr("Sonic Visualiser on the &Web"), this);
Chris@0 562 action->setStatusTip(tr("Open the Sonic Visualiser website"));
Chris@0 563 connect(action, SIGNAL(triggered()), this, SLOT(website()));
Chris@0 564 menu->addAction(action);
Chris@0 565
Chris@0 566 action = new QAction(tr("&About Sonic Visualiser"), this);
Chris@0 567 action->setStatusTip(tr("Show information about Sonic Visualiser"));
Chris@0 568 connect(action, SIGNAL(triggered()), this, SLOT(about()));
Chris@0 569 menu->addAction(action);
Chris@0 570 }
Chris@0 571
Chris@0 572 void
Chris@0 573 MainWindow::setupRecentFilesMenu()
Chris@0 574 {
Chris@0 575 m_recentFilesMenu->clear();
Chris@0 576 vector<QString> files = m_recentFiles.getRecent();
Chris@0 577 for (size_t i = 0; i < files.size(); ++i) {
Chris@0 578 QAction *action = new QAction(files[i], this);
Chris@0 579 connect(action, SIGNAL(triggered()), this, SLOT(openRecentFile()));
Chris@0 580 if (i == 0) {
Chris@0 581 action->setShortcut(tr("Ctrl+R"));
Chris@0 582 m_keyReference->registerShortcut
Chris@0 583 (tr("Re-open"),
Chris@0 584 action->shortcut(),
Chris@0 585 tr("Re-open the current or most recently opened file"));
Chris@0 586 }
Chris@0 587 m_recentFilesMenu->addAction(action);
Chris@0 588 }
Chris@0 589 }
Chris@0 590
Chris@0 591 void
Chris@0 592 MainWindow::setupToolbars()
Chris@0 593 {
Chris@0 594 m_keyReference->setCategory(tr("Playback and Transport Controls"));
Chris@0 595
Chris@0 596 IconLoader il;
Chris@0 597
Chris@0 598 QMenu *menu = m_playbackMenu = menuBar()->addMenu(tr("Play&back"));
Chris@0 599 menu->setTearOffEnabled(true);
Chris@0 600 m_rightButtonMenu->addSeparator();
Chris@0 601 m_rightButtonPlaybackMenu = m_rightButtonMenu->addMenu(tr("Playback"));
Chris@0 602
Chris@0 603 QToolBar *toolbar = addToolBar(tr("Playback Toolbar"));
Chris@0 604
Chris@0 605 QAction *rwdStartAction = toolbar->addAction(il.load("rewind-start"),
Chris@0 606 tr("Rewind to Start"));
Chris@0 607 rwdStartAction->setShortcut(tr("Home"));
Chris@0 608 rwdStartAction->setStatusTip(tr("Rewind to the start"));
Chris@0 609 connect(rwdStartAction, SIGNAL(triggered()), this, SLOT(rewindStart()));
Chris@0 610 connect(this, SIGNAL(canPlay(bool)), rwdStartAction, SLOT(setEnabled(bool)));
Chris@0 611
Chris@0 612 QAction *m_rwdAction = toolbar->addAction(il.load("rewind"),
Chris@0 613 tr("Rewind"));
Chris@0 614 m_rwdAction->setShortcut(tr("PgUp"));
Chris@0 615 m_rwdAction->setStatusTip(tr("Rewind to the previous time instant or time ruler notch"));
Chris@0 616 connect(m_rwdAction, SIGNAL(triggered()), this, SLOT(rewind()));
Chris@0 617 connect(this, SIGNAL(canRewind(bool)), m_rwdAction, SLOT(setEnabled(bool)));
Chris@0 618
Chris@0 619 QAction *playAction = toolbar->addAction(il.load("playpause"),
Chris@0 620 tr("Play / Pause"));
Chris@0 621 playAction->setCheckable(true);
Chris@0 622 playAction->setShortcut(tr("Space"));
Chris@0 623 playAction->setStatusTip(tr("Start or stop playback from the current position"));
Chris@0 624 connect(playAction, SIGNAL(triggered()), this, SLOT(play()));
Chris@0 625 connect(m_playSource, SIGNAL(playStatusChanged(bool)),
Chris@0 626 playAction, SLOT(setChecked(bool)));
Chris@0 627 connect(this, SIGNAL(canPlay(bool)), playAction, SLOT(setEnabled(bool)));
Chris@0 628
Chris@0 629 m_ffwdAction = toolbar->addAction(il.load("ffwd"),
Chris@0 630 tr("Fast Forward"));
Chris@0 631 m_ffwdAction->setShortcut(tr("PgDown"));
Chris@0 632 m_ffwdAction->setStatusTip(tr("Fast-forward to the next time instant or time ruler notch"));
Chris@0 633 connect(m_ffwdAction, SIGNAL(triggered()), this, SLOT(ffwd()));
Chris@0 634 connect(this, SIGNAL(canFfwd(bool)), m_ffwdAction, SLOT(setEnabled(bool)));
Chris@0 635
Chris@0 636 QAction *ffwdEndAction = toolbar->addAction(il.load("ffwd-end"),
Chris@0 637 tr("Fast Forward to End"));
Chris@0 638 ffwdEndAction->setShortcut(tr("End"));
Chris@0 639 ffwdEndAction->setStatusTip(tr("Fast-forward to the end"));
Chris@0 640 connect(ffwdEndAction, SIGNAL(triggered()), this, SLOT(ffwdEnd()));
Chris@0 641 connect(this, SIGNAL(canPlay(bool)), ffwdEndAction, SLOT(setEnabled(bool)));
Chris@0 642 /*
Chris@0 643 toolbar = addToolBar(tr("Play Mode Toolbar"));
Chris@0 644
Chris@0 645 QAction *psAction = toolbar->addAction(il.load("playselection"),
Chris@0 646 tr("Constrain Playback to Selection"));
Chris@0 647 psAction->setCheckable(true);
Chris@0 648 psAction->setChecked(m_viewManager->getPlaySelectionMode());
Chris@0 649 psAction->setShortcut(tr("s"));
Chris@0 650 psAction->setStatusTip(tr("Constrain playback to the selected regions"));
Chris@0 651 connect(m_viewManager, SIGNAL(playSelectionModeChanged(bool)),
Chris@0 652 psAction, SLOT(setChecked(bool)));
Chris@0 653 connect(psAction, SIGNAL(triggered()), this, SLOT(playSelectionToggled()));
Chris@0 654 connect(this, SIGNAL(canPlaySelection(bool)), psAction, SLOT(setEnabled(bool)));
Chris@0 655
Chris@0 656 QAction *plAction = toolbar->addAction(il.load("playloop"),
Chris@0 657 tr("Loop Playback"));
Chris@0 658 plAction->setCheckable(true);
Chris@0 659 plAction->setChecked(m_viewManager->getPlayLoopMode());
Chris@0 660 plAction->setShortcut(tr("l"));
Chris@0 661 plAction->setStatusTip(tr("Loop playback"));
Chris@0 662 connect(m_viewManager, SIGNAL(playLoopModeChanged(bool)),
Chris@0 663 plAction, SLOT(setChecked(bool)));
Chris@0 664 connect(plAction, SIGNAL(triggered()), this, SLOT(playLoopToggled()));
Chris@0 665 connect(this, SIGNAL(canPlay(bool)), plAction, SLOT(setEnabled(bool)));
Chris@0 666
Chris@0 667 QAction *soAction = toolbar->addAction(il.load("solo"),
Chris@0 668 tr("Solo Current Pane"));
Chris@0 669 soAction->setCheckable(true);
Chris@0 670 soAction->setChecked(m_viewManager->getPlaySoloMode());
Chris@0 671 soAction->setShortcut(tr("o"));
Chris@0 672 soAction->setStatusTip(tr("Solo the current pane during playback"));
Chris@0 673 connect(m_viewManager, SIGNAL(playSoloModeChanged(bool)),
Chris@0 674 soAction, SLOT(setChecked(bool)));
Chris@0 675 connect(soAction, SIGNAL(triggered()), this, SLOT(playSoloToggled()));
Chris@0 676 connect(this, SIGNAL(canPlay(bool)), soAction, SLOT(setEnabled(bool)));
Chris@0 677
Chris@0 678 m_keyReference->registerShortcut(psAction);
Chris@0 679 m_keyReference->registerShortcut(plAction);
Chris@0 680 m_keyReference->registerShortcut(soAction);
Chris@0 681 */
Chris@0 682 m_keyReference->registerShortcut(playAction);
Chris@0 683 m_keyReference->registerShortcut(m_rwdAction);
Chris@0 684 m_keyReference->registerShortcut(m_ffwdAction);
Chris@0 685 m_keyReference->registerShortcut(rwdStartAction);
Chris@0 686 m_keyReference->registerShortcut(ffwdEndAction);
Chris@0 687
Chris@0 688 /*
Chris@0 689 menu->addAction(psAction);
Chris@0 690 menu->addAction(plAction);
Chris@0 691 menu->addAction(soAction);
Chris@0 692 */
Chris@0 693 menu->addAction(playAction);
Chris@0 694 menu->addSeparator();
Chris@0 695 menu->addAction(m_rwdAction);
Chris@0 696 menu->addAction(m_ffwdAction);
Chris@0 697 menu->addSeparator();
Chris@0 698 menu->addAction(rwdStartAction);
Chris@0 699 menu->addAction(ffwdEndAction);
Chris@0 700 menu->addSeparator();
Chris@0 701
Chris@0 702 m_rightButtonPlaybackMenu->addAction(playAction);
Chris@0 703 /*
Chris@0 704 m_rightButtonPlaybackMenu->addAction(psAction);
Chris@0 705 m_rightButtonPlaybackMenu->addAction(plAction);
Chris@0 706 m_rightButtonPlaybackMenu->addAction(soAction);
Chris@0 707 */
Chris@0 708 m_rightButtonPlaybackMenu->addSeparator();
Chris@0 709 m_rightButtonPlaybackMenu->addAction(m_rwdAction);
Chris@0 710 m_rightButtonPlaybackMenu->addAction(m_ffwdAction);
Chris@0 711 m_rightButtonPlaybackMenu->addSeparator();
Chris@0 712 m_rightButtonPlaybackMenu->addAction(rwdStartAction);
Chris@0 713 m_rightButtonPlaybackMenu->addAction(ffwdEndAction);
Chris@0 714 m_rightButtonPlaybackMenu->addSeparator();
Chris@0 715
Chris@0 716 QAction *fastAction = menu->addAction(tr("Speed Up"));
Chris@0 717 fastAction->setShortcut(tr("Ctrl+PgUp"));
Chris@0 718 fastAction->setStatusTip(tr("Time-stretch playback to speed it up without changing pitch"));
Chris@0 719 connect(fastAction, SIGNAL(triggered()), this, SLOT(speedUpPlayback()));
Chris@0 720 connect(this, SIGNAL(canSpeedUpPlayback(bool)), fastAction, SLOT(setEnabled(bool)));
Chris@0 721
Chris@0 722 QAction *slowAction = menu->addAction(tr("Slow Down"));
Chris@0 723 slowAction->setShortcut(tr("Ctrl+PgDown"));
Chris@0 724 slowAction->setStatusTip(tr("Time-stretch playback to slow it down without changing pitch"));
Chris@0 725 connect(slowAction, SIGNAL(triggered()), this, SLOT(slowDownPlayback()));
Chris@0 726 connect(this, SIGNAL(canSlowDownPlayback(bool)), slowAction, SLOT(setEnabled(bool)));
Chris@0 727
Chris@0 728 QAction *normalAction = menu->addAction(tr("Restore Normal Speed"));
Chris@0 729 normalAction->setShortcut(tr("Ctrl+Home"));
Chris@0 730 normalAction->setStatusTip(tr("Restore non-time-stretched playback"));
Chris@0 731 connect(normalAction, SIGNAL(triggered()), this, SLOT(restoreNormalPlayback()));
Chris@0 732 connect(this, SIGNAL(canChangePlaybackSpeed(bool)), normalAction, SLOT(setEnabled(bool)));
Chris@0 733
Chris@0 734 m_keyReference->registerShortcut(fastAction);
Chris@0 735 m_keyReference->registerShortcut(slowAction);
Chris@0 736 m_keyReference->registerShortcut(normalAction);
Chris@0 737
Chris@0 738 m_rightButtonPlaybackMenu->addAction(fastAction);
Chris@0 739 m_rightButtonPlaybackMenu->addAction(slowAction);
Chris@0 740 m_rightButtonPlaybackMenu->addAction(normalAction);
Chris@0 741 /*
Chris@0 742 toolbar = addToolBar(tr("Edit Toolbar"));
Chris@0 743 CommandHistory::getInstance()->registerToolbar(toolbar);
Chris@0 744 */
Chris@0 745
Chris@0 746 Pane::registerShortcuts(*m_keyReference);
Chris@0 747 }
Chris@0 748
Chris@0 749 void
Chris@0 750 MainWindow::updateMenuStates()
Chris@0 751 {
Chris@0 752 MainWindowBase::updateMenuStates();
Chris@0 753
Chris@0 754 Pane *currentPane = 0;
Chris@0 755 Layer *currentLayer = 0;
Chris@0 756
Chris@0 757 if (m_paneStack) currentPane = m_paneStack->getCurrentPane();
Chris@0 758 if (currentPane) currentLayer = currentPane->getSelectedLayer();
Chris@0 759
Chris@0 760 bool haveCurrentPane =
Chris@0 761 (currentPane != 0);
Chris@0 762 bool haveCurrentLayer =
Chris@0 763 (haveCurrentPane &&
Chris@0 764 (currentLayer != 0));
Chris@0 765 bool haveSelection =
Chris@0 766 (m_viewManager &&
Chris@0 767 !m_viewManager->getSelections().empty());
Chris@0 768 bool haveCurrentEditableLayer =
Chris@0 769 (haveCurrentLayer &&
Chris@0 770 currentLayer->isLayerEditable());
Chris@0 771 bool haveCurrentTimeInstantsLayer =
Chris@0 772 (haveCurrentLayer &&
Chris@0 773 dynamic_cast<TimeInstantLayer *>(currentLayer));
Chris@0 774 bool haveCurrentTimeValueLayer =
Chris@0 775 (haveCurrentLayer &&
Chris@0 776 dynamic_cast<TimeValueLayer *>(currentLayer));
Chris@0 777
Chris@0 778 emit canChangePlaybackSpeed(true);
Chris@0 779 int v = m_playSpeed->value();
Chris@0 780 emit canSpeedUpPlayback(v < m_playSpeed->maximum());
Chris@0 781 emit canSlowDownPlayback(v > m_playSpeed->minimum());
Chris@0 782
Chris@0 783 if (m_ffwdAction && m_rwdAction) {
Chris@0 784 if (haveCurrentTimeInstantsLayer) {
Chris@0 785 m_ffwdAction->setText(tr("Fast Forward to Next Instant"));
Chris@0 786 m_ffwdAction->setStatusTip(tr("Fast forward to the next time instant in the current layer"));
Chris@0 787 m_rwdAction->setText(tr("Rewind to Previous Instant"));
Chris@0 788 m_rwdAction->setStatusTip(tr("Rewind to the previous time instant in the current layer"));
Chris@0 789 } else if (haveCurrentTimeValueLayer) {
Chris@0 790 m_ffwdAction->setText(tr("Fast Forward to Next Point"));
Chris@0 791 m_ffwdAction->setStatusTip(tr("Fast forward to the next point in the current layer"));
Chris@0 792 m_rwdAction->setText(tr("Rewind to Previous Point"));
Chris@0 793 m_rwdAction->setStatusTip(tr("Rewind to the previous point in the current layer"));
Chris@0 794 } else {
Chris@0 795 m_ffwdAction->setText(tr("Fast Forward"));
Chris@0 796 m_ffwdAction->setStatusTip(tr("Fast forward"));
Chris@0 797 m_rwdAction->setText(tr("Rewind"));
Chris@0 798 m_rwdAction->setStatusTip(tr("Rewind"));
Chris@0 799 }
Chris@0 800 }
Chris@0 801 }
Chris@0 802
Chris@0 803 void
Chris@0 804 MainWindow::updateDescriptionLabel()
Chris@0 805 {
Chris@0 806 if (!getMainModel()) {
Chris@0 807 m_descriptionLabel->setText(tr("No audio file loaded."));
Chris@0 808 return;
Chris@0 809 }
Chris@0 810
Chris@0 811 QString description;
Chris@0 812
Chris@0 813 size_t ssr = getMainModel()->getSampleRate();
Chris@0 814 size_t tsr = ssr;
Chris@0 815 if (m_playSource) tsr = m_playSource->getTargetSampleRate();
Chris@0 816
Chris@0 817 if (ssr != tsr) {
Chris@0 818 description = tr("%1Hz (resampling to %2Hz)").arg(ssr).arg(tsr);
Chris@0 819 } else {
Chris@0 820 description = QString("%1Hz").arg(ssr);
Chris@0 821 }
Chris@0 822
Chris@0 823 description = QString("%1 - %2")
Chris@0 824 .arg(RealTime::frame2RealTime(getMainModel()->getEndFrame(), ssr)
Chris@0 825 .toText(false).c_str())
Chris@0 826 .arg(description);
Chris@0 827
Chris@0 828 m_descriptionLabel->setText(description);
Chris@0 829 }
Chris@0 830
Chris@0 831 void
Chris@0 832 MainWindow::documentModified()
Chris@0 833 {
Chris@0 834 //!!!
Chris@0 835 MainWindowBase::documentModified();
Chris@0 836 }
Chris@0 837
Chris@0 838 void
Chris@0 839 MainWindow::documentRestored()
Chris@0 840 {
Chris@0 841 //!!!
Chris@0 842 MainWindowBase::documentRestored();
Chris@0 843 }
Chris@0 844
Chris@0 845 void
Chris@0 846 MainWindow::newSession()
Chris@0 847 {
Chris@0 848 if (!checkSaveModified()) return;
Chris@0 849
Chris@0 850 closeSession();
Chris@0 851 createDocument();
Chris@0 852 m_document->setAutoAlignment(true);
Chris@0 853
Chris@0 854 Pane *pane = m_paneStack->addPane();
Chris@0 855
Chris@0 856 connect(pane, SIGNAL(contextHelpChanged(const QString &)),
Chris@0 857 this, SLOT(contextHelpChanged(const QString &)));
Chris@0 858
Chris@0 859 Layer *waveform = m_document->createMainModelLayer(LayerFactory::Waveform);
Chris@0 860 m_document->addLayerToView(pane, waveform);
Chris@0 861
Chris@0 862 m_overview->registerView(pane);
Chris@0 863
Chris@0 864 CommandHistory::getInstance()->clear();
Chris@0 865 CommandHistory::getInstance()->documentSaved();
Chris@0 866 documentRestored();
Chris@0 867 updateMenuStates();
Chris@0 868 }
Chris@0 869
Chris@0 870 void
Chris@0 871 MainWindow::closeSession()
Chris@0 872 {
Chris@0 873 if (!checkSaveModified()) return;
Chris@0 874
Chris@0 875 while (m_paneStack->getPaneCount() > 0) {
Chris@0 876
Chris@0 877 Pane *pane = m_paneStack->getPane(m_paneStack->getPaneCount() - 1);
Chris@0 878
Chris@0 879 while (pane->getLayerCount() > 0) {
Chris@0 880 m_document->removeLayerFromView
Chris@0 881 (pane, pane->getLayer(pane->getLayerCount() - 1));
Chris@0 882 }
Chris@0 883
Chris@0 884 m_overview->unregisterView(pane);
Chris@0 885 m_paneStack->deletePane(pane);
Chris@0 886 }
Chris@0 887
Chris@0 888 while (m_paneStack->getHiddenPaneCount() > 0) {
Chris@0 889
Chris@0 890 Pane *pane = m_paneStack->getHiddenPane
Chris@0 891 (m_paneStack->getHiddenPaneCount() - 1);
Chris@0 892
Chris@0 893 while (pane->getLayerCount() > 0) {
Chris@0 894 m_document->removeLayerFromView
Chris@0 895 (pane, pane->getLayer(pane->getLayerCount() - 1));
Chris@0 896 }
Chris@0 897
Chris@0 898 m_overview->unregisterView(pane);
Chris@0 899 m_paneStack->deletePane(pane);
Chris@0 900 }
Chris@0 901
Chris@0 902 delete m_document;
Chris@0 903 m_document = 0;
Chris@0 904 m_viewManager->clearSelections();
Chris@0 905 m_timeRulerLayer = 0; // document owned this
Chris@0 906
Chris@0 907 m_sessionFile = "";
Chris@0 908
Chris@0 909 CommandHistory::getInstance()->clear();
Chris@0 910 CommandHistory::getInstance()->documentSaved();
Chris@0 911 documentRestored();
Chris@0 912 }
Chris@0 913
Chris@0 914 void
Chris@0 915 MainWindow::openFile()
Chris@0 916 {
Chris@0 917 QString orig = m_audioFile;
Chris@0 918 if (orig == "") orig = ".";
Chris@0 919 else orig = QFileInfo(orig).absoluteDir().canonicalPath();
Chris@0 920
Chris@0 921 QString path = getOpenFileName(FileFinder::AnyFile);
Chris@0 922
Chris@0 923 if (path.isEmpty()) return;
Chris@0 924
Chris@0 925 FileOpenStatus status = open(path, CreateAdditionalModel);
Chris@0 926
Chris@0 927 if (status == FileOpenFailed) {
Chris@0 928 QMessageBox::critical(this, tr("Failed to open file"),
Chris@0 929 tr("<b>File open failed</b><p>File \"%1\" could not be opened").arg(path));
Chris@0 930 } else if (status == FileOpenWrongMode) {
Chris@0 931 QMessageBox::critical(this, tr("Failed to open file"),
Chris@0 932 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
Chris@0 933 } else {
Chris@0 934 configureNewPane(m_paneStack->getCurrentPane());
Chris@0 935 }
Chris@0 936 }
Chris@0 937
Chris@0 938 void
Chris@0 939 MainWindow::openLocation()
Chris@0 940 {
Chris@0 941 QSettings settings;
Chris@0 942 settings.beginGroup("MainWindow");
Chris@0 943 QString lastLocation = settings.value("lastremote", "").toString();
Chris@0 944
Chris@0 945 bool ok = false;
Chris@0 946 QString text = QInputDialog::getText
Chris@0 947 (this, tr("Open Location"),
Chris@0 948 tr("Please enter the URL of the location to open:"),
Chris@0 949 QLineEdit::Normal, lastLocation, &ok);
Chris@0 950
Chris@0 951 if (!ok) return;
Chris@0 952
Chris@0 953 settings.setValue("lastremote", text);
Chris@0 954
Chris@0 955 if (text.isEmpty()) return;
Chris@0 956
Chris@0 957 FileOpenStatus status = open(text, CreateAdditionalModel);
Chris@0 958
Chris@0 959 if (status == FileOpenFailed) {
Chris@0 960 QMessageBox::critical(this, tr("Failed to open location"),
Chris@0 961 tr("<b>Open failed</b><p>URL \"%1\" could not be opened").arg(text));
Chris@0 962 } else if (status == FileOpenWrongMode) {
Chris@0 963 QMessageBox::critical(this, tr("Failed to open location"),
Chris@0 964 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
Chris@0 965 } else {
Chris@0 966 configureNewPane(m_paneStack->getCurrentPane());
Chris@0 967 }
Chris@0 968 }
Chris@0 969
Chris@0 970 void
Chris@0 971 MainWindow::openRecentFile()
Chris@0 972 {
Chris@0 973 QObject *obj = sender();
Chris@0 974 QAction *action = dynamic_cast<QAction *>(obj);
Chris@0 975
Chris@0 976 if (!action) {
Chris@0 977 std::cerr << "WARNING: MainWindow::openRecentFile: sender is not an action"
Chris@0 978 << std::endl;
Chris@0 979 return;
Chris@0 980 }
Chris@0 981
Chris@0 982 QString path = action->text();
Chris@0 983 if (path == "") return;
Chris@0 984
Chris@0 985 FileOpenStatus status = open(path, CreateAdditionalModel);
Chris@0 986
Chris@0 987 if (status == FileOpenFailed) {
Chris@0 988 QMessageBox::critical(this, tr("Failed to open location"),
Chris@0 989 tr("<b>Open failed</b><p>File or URL \"%1\" could not be opened").arg(path));
Chris@0 990 } else if (status == FileOpenWrongMode) {
Chris@0 991 QMessageBox::critical(this, tr("Failed to open location"),
Chris@0 992 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
Chris@0 993 } else {
Chris@0 994 configureNewPane(m_paneStack->getCurrentPane());
Chris@0 995 }
Chris@0 996 }
Chris@0 997
Chris@0 998 void
Chris@0 999 MainWindow::paneAdded(Pane *pane)
Chris@0 1000 {
Chris@0 1001 pane->setPlaybackFollow(PlaybackScrollContinuous);
Chris@0 1002 m_paneStack->sizePanesEqually();
Chris@0 1003 if (m_overview) m_overview->registerView(pane);
Chris@0 1004 }
Chris@0 1005
Chris@0 1006 void
Chris@0 1007 MainWindow::paneHidden(Pane *pane)
Chris@0 1008 {
Chris@0 1009 if (m_overview) m_overview->unregisterView(pane);
Chris@0 1010 }
Chris@0 1011
Chris@0 1012 void
Chris@0 1013 MainWindow::paneAboutToBeDeleted(Pane *pane)
Chris@0 1014 {
Chris@0 1015 if (m_overview) m_overview->unregisterView(pane);
Chris@0 1016 }
Chris@0 1017
Chris@0 1018 void
Chris@0 1019 MainWindow::paneDropAccepted(Pane *pane, QStringList uriList)
Chris@0 1020 {
Chris@0 1021 // if (pane) m_paneStack->setCurrentPane(pane);
Chris@0 1022
Chris@0 1023 for (QStringList::iterator i = uriList.begin(); i != uriList.end(); ++i) {
Chris@0 1024
Chris@0 1025 FileOpenStatus status = open(*i, CreateAdditionalModel);
Chris@0 1026
Chris@0 1027 if (status == FileOpenFailed) {
Chris@0 1028 QMessageBox::critical(this, tr("Failed to open dropped URL"),
Chris@0 1029 tr("<b>Open failed</b><p>Dropped URL \"%1\" could not be opened").arg(*i));
Chris@0 1030 } else if (status == FileOpenWrongMode) {
Chris@0 1031 QMessageBox::critical(this, tr("Failed to open dropped URL"),
Chris@0 1032 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
Chris@0 1033 } else {
Chris@0 1034 configureNewPane(m_paneStack->getCurrentPane());
Chris@0 1035 }
Chris@0 1036 }
Chris@0 1037 }
Chris@0 1038
Chris@0 1039 void
Chris@0 1040 MainWindow::paneDropAccepted(Pane *pane, QString text)
Chris@0 1041 {
Chris@0 1042 if (pane) m_paneStack->setCurrentPane(pane);
Chris@0 1043
Chris@0 1044 QUrl testUrl(text);
Chris@0 1045 if (testUrl.scheme() == "file" ||
Chris@0 1046 testUrl.scheme() == "http" ||
Chris@0 1047 testUrl.scheme() == "ftp") {
Chris@0 1048 QStringList list;
Chris@0 1049 list.push_back(text);
Chris@0 1050 paneDropAccepted(pane, list);
Chris@0 1051 return;
Chris@0 1052 }
Chris@0 1053
Chris@0 1054 //!!! open as text -- but by importing as if a CSV, or just adding
Chris@0 1055 //to a text layer?
Chris@0 1056 }
Chris@0 1057
Chris@0 1058 void
Chris@0 1059 MainWindow::configureNewPane(Pane *pane)
Chris@0 1060 {
Chris@0 1061 std::cerr << "MainWindow::configureNewPane(" << pane << ")" << std::endl;
Chris@0 1062
Chris@0 1063 if (!pane) return;
Chris@0 1064
Chris@0 1065 Layer *waveformLayer = 0;
Chris@0 1066
Chris@0 1067 for (int i = 0; i < pane->getLayerCount(); ++i) {
Chris@0 1068 Layer *layer = pane->getLayer(i);
Chris@0 1069 if (!layer) continue;
Chris@0 1070 if (dynamic_cast<WaveformLayer *>(layer)) waveformLayer = layer;
Chris@0 1071 if (dynamic_cast<TimeValueLayer *>(layer)) return;
Chris@0 1072 }
Chris@0 1073 if (!waveformLayer) return;
Chris@0 1074
Chris@0 1075 waveformLayer->setObjectName(tr("Waveform"));
Chris@0 1076
Chris@0 1077 zoomToFit();
Chris@0 1078 }
Chris@0 1079
Chris@0 1080 void
Chris@0 1081 MainWindow::closeEvent(QCloseEvent *e)
Chris@0 1082 {
Chris@0 1083 // std::cerr << "MainWindow::closeEvent" << std::endl;
Chris@0 1084
Chris@0 1085 if (m_openingAudioFile) {
Chris@0 1086 // std::cerr << "Busy - ignoring close event" << std::endl;
Chris@0 1087 e->ignore();
Chris@0 1088 return;
Chris@0 1089 }
Chris@0 1090
Chris@0 1091 if (!m_abandoning && !checkSaveModified()) {
Chris@0 1092 // std::cerr << "Ignoring close event" << std::endl;
Chris@0 1093 e->ignore();
Chris@0 1094 return;
Chris@0 1095 }
Chris@0 1096
Chris@0 1097 QSettings settings;
Chris@0 1098 settings.beginGroup("MainWindow");
Chris@0 1099 settings.setValue("size", size());
Chris@0 1100 settings.setValue("position", pos());
Chris@0 1101 settings.endGroup();
Chris@0 1102
Chris@0 1103 delete m_keyReference;
Chris@0 1104 m_keyReference = 0;
Chris@0 1105
Chris@0 1106 if (m_layerTreeView &&
Chris@0 1107 m_layerTreeView->isVisible()) {
Chris@0 1108 delete m_layerTreeView;
Chris@0 1109 }
Chris@0 1110
Chris@0 1111 closeSession();
Chris@0 1112
Chris@0 1113 e->accept();
Chris@0 1114 return;
Chris@0 1115 }
Chris@0 1116
Chris@0 1117 bool
Chris@0 1118 MainWindow::commitData(bool mayAskUser)
Chris@0 1119 {
Chris@0 1120 if (mayAskUser) {
Chris@0 1121 bool rv = checkSaveModified();
Chris@0 1122 return rv;
Chris@0 1123 } else {
Chris@0 1124 if (!m_documentModified) return true;
Chris@0 1125
Chris@0 1126 // If we can't check with the user first, then we can't save
Chris@0 1127 // to the original session file (even if we have it) -- have
Chris@0 1128 // to use a temporary file
Chris@0 1129
Chris@0 1130 QString svDirBase = ".sv1";
Chris@0 1131 QString svDir = QDir::home().filePath(svDirBase);
Chris@0 1132
Chris@0 1133 if (!QFileInfo(svDir).exists()) {
Chris@0 1134 if (!QDir::home().mkdir(svDirBase)) return false;
Chris@0 1135 } else {
Chris@0 1136 if (!QFileInfo(svDir).isDir()) return false;
Chris@0 1137 }
Chris@0 1138
Chris@0 1139 // This name doesn't have to be unguessable
Chris@0 1140 #ifndef _WIN32
Chris@0 1141 QString fname = QString("tmp-%1-%2.sv")
Chris@0 1142 .arg(QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz"))
Chris@0 1143 .arg(QProcess().pid());
Chris@0 1144 #else
Chris@0 1145 QString fname = QString("tmp-%1.sv")
Chris@0 1146 .arg(QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz"));
Chris@0 1147 #endif
Chris@0 1148 QString fpath = QDir(svDir).filePath(fname);
Chris@0 1149 if (saveSessionFile(fpath)) {
Chris@0 1150 m_recentFiles.addFile(fpath);
Chris@0 1151 return true;
Chris@0 1152 } else {
Chris@0 1153 return false;
Chris@0 1154 }
Chris@0 1155 }
Chris@0 1156 }
Chris@0 1157
Chris@0 1158 bool
Chris@0 1159 MainWindow::checkSaveModified()
Chris@0 1160 {
Chris@0 1161 // Called before some destructive operation (e.g. new session,
Chris@0 1162 // exit program). Return true if we can safely proceed, false to
Chris@0 1163 // cancel.
Chris@0 1164
Chris@0 1165 if (!m_documentModified) return true;
Chris@0 1166
Chris@0 1167 int button =
Chris@0 1168 QMessageBox::warning(this,
Chris@0 1169 tr("Session modified"),
Chris@0 1170 tr("The current session has been modified.\nDo you want to save it?"),
Chris@0 1171 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
Chris@0 1172 QMessageBox::Yes);
Chris@0 1173
Chris@0 1174 if (button == QMessageBox::Yes) {
Chris@0 1175 saveSession();
Chris@0 1176 if (m_documentModified) { // save failed -- don't proceed!
Chris@0 1177 return false;
Chris@0 1178 } else {
Chris@0 1179 return true; // saved, so it's safe to continue now
Chris@0 1180 }
Chris@0 1181 } else if (button == QMessageBox::No) {
Chris@0 1182 m_documentModified = false; // so we know to abandon it
Chris@0 1183 return true;
Chris@0 1184 }
Chris@0 1185
Chris@0 1186 // else cancel
Chris@0 1187 return false;
Chris@0 1188 }
Chris@0 1189
Chris@0 1190 void
Chris@0 1191 MainWindow::saveSession()
Chris@0 1192 {
Chris@0 1193 if (m_sessionFile != "") {
Chris@0 1194 if (!saveSessionFile(m_sessionFile)) {
Chris@0 1195 QMessageBox::critical(this, tr("Failed to save file"),
Chris@0 1196 tr("Session file \"%1\" could not be saved.").arg(m_sessionFile));
Chris@0 1197 } else {
Chris@0 1198 CommandHistory::getInstance()->documentSaved();
Chris@0 1199 documentRestored();
Chris@0 1200 }
Chris@0 1201 } else {
Chris@0 1202 saveSessionAs();
Chris@0 1203 }
Chris@0 1204 }
Chris@0 1205
Chris@0 1206 void
Chris@0 1207 MainWindow::saveSessionAs()
Chris@0 1208 {
Chris@0 1209 QString orig = m_audioFile;
Chris@0 1210 if (orig == "") orig = ".";
Chris@0 1211 else orig = QFileInfo(orig).absoluteDir().canonicalPath();
Chris@0 1212
Chris@0 1213 QString path = getSaveFileName(FileFinder::SessionFile);
Chris@0 1214
Chris@0 1215 if (path == "") return;
Chris@0 1216
Chris@0 1217 if (!saveSessionFile(path)) {
Chris@0 1218 QMessageBox::critical(this, tr("Failed to save file"),
Chris@0 1219 tr("Session file \"%1\" could not be saved.").arg(path));
Chris@0 1220 } else {
Chris@0 1221 setWindowTitle(tr("%1: %2")
Chris@0 1222 .arg(QApplication::applicationName())
Chris@0 1223 .arg(QFileInfo(path).fileName()));
Chris@0 1224 m_sessionFile = path;
Chris@0 1225 CommandHistory::getInstance()->documentSaved();
Chris@0 1226 documentRestored();
Chris@0 1227 m_recentFiles.addFile(path);
Chris@0 1228 }
Chris@0 1229 }
Chris@0 1230
Chris@0 1231 void
Chris@0 1232 MainWindow::renameCurrentLayer()
Chris@0 1233 {
Chris@0 1234 Pane *pane = m_paneStack->getCurrentPane();
Chris@0 1235 if (pane) {
Chris@0 1236 Layer *layer = pane->getSelectedLayer();
Chris@0 1237 if (layer) {
Chris@0 1238 bool ok = false;
Chris@0 1239 QString newName = QInputDialog::getText
Chris@0 1240 (this, tr("Rename Layer"),
Chris@0 1241 tr("New name for this layer:"),
Chris@0 1242 QLineEdit::Normal, layer->objectName(), &ok);
Chris@0 1243 if (ok) {
Chris@0 1244 layer->setObjectName(newName);
Chris@0 1245 }
Chris@0 1246 }
Chris@0 1247 }
Chris@0 1248 }
Chris@0 1249
Chris@0 1250 void
Chris@0 1251 MainWindow::playSpeedChanged(int position)
Chris@0 1252 {
Chris@0 1253 PlaySpeedRangeMapper mapper(0, 200);
Chris@0 1254
Chris@0 1255 float percent = m_playSpeed->mappedValue();
Chris@0 1256 float factor = mapper.getFactorForValue(percent);
Chris@0 1257
Chris@0 1258 std::cerr << "speed = " << position << " percent = " << percent << " factor = " << factor << std::endl;
Chris@0 1259
Chris@0 1260 bool something = (position != 100);
Chris@0 1261
Chris@0 1262 int pc = lrintf(percent);
Chris@0 1263
Chris@0 1264 if (!something) {
Chris@0 1265 contextHelpChanged(tr("Playback speed: Normal"));
Chris@0 1266 } else {
Chris@0 1267 contextHelpChanged(tr("Playback speed: %1%2%")
Chris@0 1268 .arg(position > 100 ? "+" : "")
Chris@0 1269 .arg(pc));
Chris@0 1270 }
Chris@0 1271
Chris@0 1272 m_playSource->setTimeStretch(factor);
Chris@0 1273
Chris@0 1274 updateMenuStates();
Chris@0 1275 }
Chris@0 1276
Chris@0 1277 void
Chris@0 1278 MainWindow::playSharpenToggled()
Chris@0 1279 {
Chris@0 1280 QSettings settings;
Chris@0 1281 settings.beginGroup("MainWindow");
Chris@0 1282 settings.setValue("playsharpen", m_playSharpen->isChecked());
Chris@0 1283 settings.endGroup();
Chris@0 1284
Chris@0 1285 playSpeedChanged(m_playSpeed->value());
Chris@0 1286 }
Chris@0 1287
Chris@0 1288 void
Chris@0 1289 MainWindow::playMonoToggled()
Chris@0 1290 {
Chris@0 1291 QSettings settings;
Chris@0 1292 settings.beginGroup("MainWindow");
Chris@0 1293 settings.setValue("playmono", m_playMono->isChecked());
Chris@0 1294 settings.endGroup();
Chris@0 1295
Chris@0 1296 playSpeedChanged(m_playSpeed->value());
Chris@0 1297 }
Chris@0 1298
Chris@0 1299 void
Chris@0 1300 MainWindow::speedUpPlayback()
Chris@0 1301 {
Chris@0 1302 int value = m_playSpeed->value();
Chris@0 1303 value = value + m_playSpeed->pageStep();
Chris@0 1304 if (value > m_playSpeed->maximum()) value = m_playSpeed->maximum();
Chris@0 1305 m_playSpeed->setValue(value);
Chris@0 1306 }
Chris@0 1307
Chris@0 1308 void
Chris@0 1309 MainWindow::slowDownPlayback()
Chris@0 1310 {
Chris@0 1311 int value = m_playSpeed->value();
Chris@0 1312 value = value - m_playSpeed->pageStep();
Chris@0 1313 if (value < m_playSpeed->minimum()) value = m_playSpeed->minimum();
Chris@0 1314 m_playSpeed->setValue(value);
Chris@0 1315 }
Chris@0 1316
Chris@0 1317 void
Chris@0 1318 MainWindow::restoreNormalPlayback()
Chris@0 1319 {
Chris@0 1320 m_playSpeed->setValue(m_playSpeed->defaultValue());
Chris@0 1321 }
Chris@0 1322
Chris@0 1323 void
Chris@0 1324 MainWindow::updateVisibleRangeDisplay(Pane *p) const
Chris@0 1325 {
Chris@0 1326 if (!getMainModel() || !p) {
Chris@0 1327 return;
Chris@0 1328 }
Chris@0 1329
Chris@0 1330 bool haveSelection = false;
Chris@0 1331 size_t startFrame = 0, endFrame = 0;
Chris@0 1332
Chris@0 1333 if (m_viewManager && m_viewManager->haveInProgressSelection()) {
Chris@0 1334
Chris@0 1335 bool exclusive = false;
Chris@0 1336 Selection s = m_viewManager->getInProgressSelection(exclusive);
Chris@0 1337
Chris@0 1338 if (!s.isEmpty()) {
Chris@0 1339 haveSelection = true;
Chris@0 1340 startFrame = s.getStartFrame();
Chris@0 1341 endFrame = s.getEndFrame();
Chris@0 1342 }
Chris@0 1343 }
Chris@0 1344
Chris@0 1345 if (!haveSelection) {
Chris@0 1346 startFrame = p->getFirstVisibleFrame();
Chris@0 1347 endFrame = p->getLastVisibleFrame();
Chris@0 1348 }
Chris@0 1349
Chris@0 1350 RealTime start = RealTime::frame2RealTime
Chris@0 1351 (startFrame, getMainModel()->getSampleRate());
Chris@0 1352
Chris@0 1353 RealTime end = RealTime::frame2RealTime
Chris@0 1354 (endFrame, getMainModel()->getSampleRate());
Chris@0 1355
Chris@0 1356 RealTime duration = end - start;
Chris@0 1357
Chris@0 1358 QString startStr, endStr, durationStr;
Chris@0 1359 startStr = start.toText(true).c_str();
Chris@0 1360 endStr = end.toText(true).c_str();
Chris@0 1361 durationStr = duration.toText(true).c_str();
Chris@0 1362
Chris@0 1363 if (haveSelection) {
Chris@0 1364 m_myStatusMessage = tr("Selection: %1 to %2 (duration %3)")
Chris@0 1365 .arg(startStr).arg(endStr).arg(durationStr);
Chris@0 1366 } else {
Chris@0 1367 m_myStatusMessage = tr("Visible: %1 to %2 (duration %3)")
Chris@0 1368 .arg(startStr).arg(endStr).arg(durationStr);
Chris@0 1369 }
Chris@0 1370
Chris@0 1371 statusBar()->showMessage(m_myStatusMessage);
Chris@0 1372 }
Chris@0 1373
Chris@0 1374 void
Chris@0 1375 MainWindow::updatePositionStatusDisplays() const
Chris@0 1376 {
Chris@0 1377 if (!statusBar()->isVisible()) return;
Chris@0 1378
Chris@0 1379 }
Chris@0 1380
Chris@0 1381 void
Chris@0 1382 MainWindow::outputLevelsChanged(float left, float right)
Chris@0 1383 {
Chris@0 1384 m_fader->setPeakLeft(left);
Chris@0 1385 m_fader->setPeakRight(right);
Chris@0 1386 }
Chris@0 1387
Chris@0 1388 void
Chris@0 1389 MainWindow::sampleRateMismatch(size_t requested, size_t actual,
Chris@0 1390 bool willResample)
Chris@0 1391 {
Chris@0 1392 if (!willResample) {
Chris@0 1393 //!!! more helpful message needed
Chris@0 1394 QMessageBox::information
Chris@0 1395 (this, tr("Sample rate mismatch"),
Chris@0 1396 tr("The sample rate of this audio file (%1 Hz) does not match\nthe current playback rate (%2 Hz).\n\nThe file will play at the wrong speed and pitch.")
Chris@0 1397 .arg(requested).arg(actual));
Chris@0 1398 }
Chris@0 1399
Chris@0 1400 updateDescriptionLabel();
Chris@0 1401 }
Chris@0 1402
Chris@0 1403 void
Chris@0 1404 MainWindow::audioOverloadPluginDisabled()
Chris@0 1405 {
Chris@0 1406 QMessageBox::information
Chris@0 1407 (this, tr("Audio processing overload"),
Chris@0 1408 tr("<b>Overloaded</b><p>Audio effects plugin auditioning has been disabled due to a processing overload."));
Chris@0 1409 }
Chris@0 1410
Chris@0 1411 void
Chris@0 1412 MainWindow::audioTimeStretchMultiChannelDisabled()
Chris@0 1413 {
Chris@0 1414 static bool shownOnce = false;
Chris@0 1415 if (shownOnce) return;
Chris@0 1416 QMessageBox::information
Chris@0 1417 (this, tr("Audio processing overload"),
Chris@0 1418 tr("<b>Overloaded</b><p>Audio playback speed processing has been reduced to a single channel, due to a processing overload."));
Chris@0 1419 shownOnce = true;
Chris@0 1420 }
Chris@0 1421
Chris@0 1422 void
Chris@0 1423 MainWindow::layerRemoved(Layer *layer)
Chris@0 1424 {
Chris@0 1425 MainWindowBase::layerRemoved(layer);
Chris@0 1426 }
Chris@0 1427
Chris@0 1428 void
Chris@0 1429 MainWindow::layerInAView(Layer *layer, bool inAView)
Chris@0 1430 {
Chris@0 1431 MainWindowBase::layerInAView(layer, inAView);
Chris@0 1432 }
Chris@0 1433
Chris@0 1434 void
Chris@0 1435 MainWindow::modelAdded(Model *model)
Chris@0 1436 {
Chris@0 1437 MainWindowBase::modelAdded(model);
Chris@0 1438 DenseTimeValueModel *dtvm = dynamic_cast<DenseTimeValueModel *>(model);
Chris@0 1439 if (dtvm) {
Chris@0 1440 std::cerr << "A dense time-value model (such as an audio file) has been loaded" << std::endl;
Chris@0 1441 }
Chris@0 1442 }
Chris@0 1443
Chris@0 1444 void
Chris@0 1445 MainWindow::modelReady()
Chris@0 1446 {
Chris@0 1447 QObject *s = sender();
Chris@0 1448 std::cerr << "MainWindow::modelReady(" << s << ")" << std::endl;
Chris@0 1449 }
Chris@0 1450
Chris@0 1451 void
Chris@0 1452 MainWindow::modelAboutToBeDeleted(Model *model)
Chris@0 1453 {
Chris@0 1454 MainWindowBase::modelAboutToBeDeleted(model);
Chris@0 1455 }
Chris@0 1456
Chris@0 1457 void
Chris@0 1458 MainWindow::mainModelChanged(WaveFileModel *model)
Chris@0 1459 {
Chris@0 1460 m_panLayer->setModel(model);
Chris@0 1461
Chris@0 1462 MainWindowBase::mainModelChanged(model);
Chris@0 1463
Chris@0 1464 if (m_playTarget) {
Chris@0 1465 connect(m_fader, SIGNAL(valueChanged(float)),
Chris@0 1466 m_playTarget, SLOT(setOutputGain(float)));
Chris@0 1467 }
Chris@0 1468 }
Chris@0 1469
Chris@0 1470 void
Chris@0 1471 MainWindow::modelGenerationFailed(QString transformName, QString message)
Chris@0 1472 {
Chris@0 1473 if (message != "") {
Chris@0 1474
Chris@0 1475 QMessageBox::warning
Chris@0 1476 (this,
Chris@0 1477 tr("Failed to generate layer"),
Chris@0 1478 tr("<b>Layer generation failed</b><p>Failed to generate derived layer.<p>The layer transform \"%1\" failed:<p>%2")
Chris@0 1479 .arg(transformName).arg(message),
Chris@0 1480 QMessageBox::Ok);
Chris@0 1481 } else {
Chris@0 1482 QMessageBox::warning
Chris@0 1483 (this,
Chris@0 1484 tr("Failed to generate layer"),
Chris@0 1485 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@0 1486 .arg(transformName),
Chris@0 1487 QMessageBox::Ok);
Chris@0 1488 }
Chris@0 1489 }
Chris@0 1490
Chris@0 1491 void
Chris@0 1492 MainWindow::modelGenerationWarning(QString transformName, QString message)
Chris@0 1493 {
Chris@0 1494 QMessageBox::warning
Chris@0 1495 (this, tr("Warning"), message, QMessageBox::Ok);
Chris@0 1496 }
Chris@0 1497
Chris@0 1498 void
Chris@0 1499 MainWindow::modelRegenerationFailed(QString layerName,
Chris@0 1500 QString transformName, QString message)
Chris@0 1501 {
Chris@0 1502 if (message != "") {
Chris@0 1503
Chris@0 1504 QMessageBox::warning
Chris@0 1505 (this,
Chris@0 1506 tr("Failed to regenerate layer"),
Chris@0 1507 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@0 1508 .arg(layerName).arg(transformName).arg(message),
Chris@0 1509 QMessageBox::Ok);
Chris@0 1510 } else {
Chris@0 1511 QMessageBox::warning
Chris@0 1512 (this,
Chris@0 1513 tr("Failed to regenerate layer"),
Chris@0 1514 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@0 1515 .arg(layerName).arg(transformName),
Chris@0 1516 QMessageBox::Ok);
Chris@0 1517 }
Chris@0 1518 }
Chris@0 1519
Chris@0 1520 void
Chris@0 1521 MainWindow::modelRegenerationWarning(QString layerName,
Chris@0 1522 QString transformName, QString message)
Chris@0 1523 {
Chris@0 1524 QMessageBox::warning
Chris@0 1525 (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@0 1526 }
Chris@0 1527
Chris@0 1528 void
Chris@0 1529 MainWindow::alignmentFailed(QString transformName, QString message)
Chris@0 1530 {
Chris@0 1531 QMessageBox::warning
Chris@0 1532 (this,
Chris@0 1533 tr("Failed to calculate alignment"),
Chris@0 1534 tr("<b>Alignment calculation failed</b><p>Failed to calculate an audio alignment using transform \"%1\":<p>%2")
Chris@0 1535 .arg(transformName).arg(message),
Chris@0 1536 QMessageBox::Ok);
Chris@0 1537 }
Chris@0 1538
Chris@0 1539 void
Chris@0 1540 MainWindow::rightButtonMenuRequested(Pane *pane, QPoint position)
Chris@0 1541 {
Chris@0 1542 // std::cerr << "MainWindow::rightButtonMenuRequested(" << pane << ", " << position.x() << ", " << position.y() << ")" << std::endl;
Chris@0 1543 m_paneStack->setCurrentPane(pane);
Chris@0 1544 m_rightButtonMenu->popup(position);
Chris@0 1545 }
Chris@0 1546
Chris@0 1547 void
Chris@0 1548 MainWindow::showLayerTree()
Chris@0 1549 {
Chris@0 1550 if (!m_layerTreeView.isNull()) {
Chris@0 1551 m_layerTreeView->show();
Chris@0 1552 m_layerTreeView->raise();
Chris@0 1553 return;
Chris@0 1554 }
Chris@0 1555
Chris@0 1556 //!!! should use an actual dialog class
Chris@0 1557
Chris@0 1558 m_layerTreeView = new QTreeView();
Chris@0 1559 LayerTreeModel *tree = new LayerTreeModel(m_paneStack);
Chris@0 1560 m_layerTreeView->resize(500, 300); //!!!
Chris@0 1561 m_layerTreeView->setModel(tree);
Chris@0 1562 m_layerTreeView->expandAll();
Chris@0 1563 m_layerTreeView->show();
Chris@0 1564 }
Chris@0 1565
Chris@0 1566 void
Chris@0 1567 MainWindow::handleOSCMessage(const OSCMessage &message)
Chris@0 1568 {
Chris@0 1569 std::cerr << "MainWindow::handleOSCMessage: Not implemented" << std::endl;
Chris@0 1570 }
Chris@0 1571
Chris@0 1572 void
Chris@0 1573 MainWindow::mouseEnteredWidget()
Chris@0 1574 {
Chris@0 1575 QWidget *w = dynamic_cast<QWidget *>(sender());
Chris@0 1576 if (!w) return;
Chris@0 1577
Chris@0 1578 if (w == m_fader) {
Chris@0 1579 contextHelpChanged(tr("Adjust the master playback level"));
Chris@0 1580 } else if (w == m_playSpeed) {
Chris@0 1581 contextHelpChanged(tr("Adjust the master playback speed"));
Chris@0 1582 } else if (w == m_playSharpen && w->isEnabled()) {
Chris@0 1583 contextHelpChanged(tr("Toggle transient sharpening for playback time scaling"));
Chris@0 1584 } else if (w == m_playMono && w->isEnabled()) {
Chris@0 1585 contextHelpChanged(tr("Toggle mono mode for playback time scaling"));
Chris@0 1586 }
Chris@0 1587 }
Chris@0 1588
Chris@0 1589 void
Chris@0 1590 MainWindow::mouseLeftWidget()
Chris@0 1591 {
Chris@0 1592 contextHelpChanged("");
Chris@0 1593 }
Chris@0 1594
Chris@0 1595 void
Chris@0 1596 MainWindow::website()
Chris@0 1597 {
Chris@0 1598 openHelpUrl(tr("http://www.sonicvisualiser.org/"));
Chris@0 1599 }
Chris@0 1600
Chris@0 1601 void
Chris@0 1602 MainWindow::help()
Chris@0 1603 {
Chris@0 1604 openHelpUrl(tr("http://www.sonicvisualiser.org/doc/reference/1.0/en/"));
Chris@0 1605 }
Chris@0 1606
Chris@0 1607 void
Chris@0 1608 MainWindow::about()
Chris@0 1609 {
Chris@0 1610 bool debug = false;
Chris@0 1611 QString version = "(unknown version)";
Chris@0 1612
Chris@0 1613 #ifdef BUILD_DEBUG
Chris@0 1614 debug = true;
Chris@0 1615 #endif
Chris@0 1616 version = tr("Release %1").arg(TONY_VERSION);
Chris@0 1617
Chris@0 1618 QString aboutText;
Chris@0 1619
Chris@0 1620 aboutText += tr("<h3>About Tony</h3>");
Chris@0 1621 aboutText += tr("<p>Tony is a program for interactive note and pitch analysis and annotation.</p>");
Chris@0 1622 aboutText += tr("<p>%1 : %2 configuration</p>")
Chris@0 1623 .arg(version)
Chris@0 1624 .arg(debug ? tr("Debug") : tr("Release"));
Chris@0 1625
Chris@0 1626 #ifndef BUILD_STATIC
Chris@0 1627 aboutText += tr("<br>Using Qt v%1 &copy; Trolltech AS").arg(QT_VERSION_STR);
Chris@0 1628 #else
Chris@0 1629 #ifdef QT_SHARED
Chris@0 1630 aboutText += tr("<br>Using Qt v%1 &copy; Trolltech AS").arg(QT_VERSION_STR);
Chris@0 1631 #endif
Chris@0 1632 #endif
Chris@0 1633
Chris@0 1634 #ifdef BUILD_STATIC
Chris@0 1635 aboutText += tr("<p>Statically linked");
Chris@0 1636 #ifndef QT_SHARED
Chris@0 1637 aboutText += tr("<br>With Qt (v%1) &copy; Trolltech AS").arg(QT_VERSION_STR);
Chris@0 1638 #endif
Chris@0 1639 #ifdef HAVE_JACK
Chris@0 1640 #ifdef JACK_VERSION
Chris@0 1641 aboutText += tr("<br>With JACK audio output (v%1) &copy; Paul Davis and Jack O'Quin").arg(JACK_VERSION);
Chris@0 1642 #else
Chris@0 1643 aboutText += tr("<br>With JACK audio output &copy; Paul Davis and Jack O'Quin");
Chris@0 1644 #endif
Chris@0 1645 #endif
Chris@0 1646 #ifdef HAVE_PORTAUDIO
Chris@0 1647 aboutText += tr("<br>With PortAudio audio output &copy; Ross Bencina and Phil Burk");
Chris@0 1648 #endif
Chris@0 1649 #ifdef HAVE_OGGZ
Chris@0 1650 #ifdef OGGZ_VERSION
Chris@0 1651 aboutText += tr("<br>With Ogg file decoder (oggz v%1, fishsound v%2) &copy; CSIRO Australia").arg(OGGZ_VERSION).arg(FISHSOUND_VERSION);
Chris@0 1652 #else
Chris@0 1653 aboutText += tr("<br>With Ogg file decoder &copy; CSIRO Australia");
Chris@0 1654 #endif
Chris@0 1655 #endif
Chris@0 1656 #ifdef HAVE_MAD
Chris@0 1657 #ifdef MAD_VERSION
Chris@0 1658 aboutText += tr("<br>With MAD mp3 decoder (v%1) &copy; Underbit Technologies Inc").arg(MAD_VERSION);
Chris@0 1659 #else
Chris@0 1660 aboutText += tr("<br>With MAD mp3 decoder &copy; Underbit Technologies Inc");
Chris@0 1661 #endif
Chris@0 1662 #endif
Chris@0 1663 #ifdef HAVE_SAMPLERATE
Chris@0 1664 #ifdef SAMPLERATE_VERSION
Chris@0 1665 aboutText += tr("<br>With libsamplerate (v%1) &copy; Erik de Castro Lopo").arg(SAMPLERATE_VERSION);
Chris@0 1666 #else
Chris@0 1667 aboutText += tr("<br>With libsamplerate &copy; Erik de Castro Lopo");
Chris@0 1668 #endif
Chris@0 1669 #endif
Chris@0 1670 #ifdef HAVE_SNDFILE
Chris@0 1671 #ifdef SNDFILE_VERSION
Chris@0 1672 aboutText += tr("<br>With libsndfile (v%1) &copy; Erik de Castro Lopo").arg(SNDFILE_VERSION);
Chris@0 1673 #else
Chris@0 1674 aboutText += tr("<br>With libsndfile &copy; Erik de Castro Lopo");
Chris@0 1675 #endif
Chris@0 1676 #endif
Chris@0 1677 #ifdef HAVE_FFTW3F
Chris@0 1678 #ifdef FFTW3_VERSION
Chris@0 1679 aboutText += tr("<br>With FFTW3 (v%1) &copy; Matteo Frigo and MIT").arg(FFTW3_VERSION);
Chris@0 1680 #else
Chris@0 1681 aboutText += tr("<br>With FFTW3 &copy; Matteo Frigo and MIT");
Chris@0 1682 #endif
Chris@0 1683 #endif
Chris@0 1684 #ifdef HAVE_VAMP
Chris@0 1685 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@0 1686 #endif
Chris@0 1687 aboutText += tr("<br>With LADSPA plugin support (API v%1) &copy; Richard Furse, Paul Davis, Stefan Westerfeld").arg(LADSPA_VERSION);
Chris@0 1688 aboutText += tr("<br>With DSSI plugin support (API v%1) &copy; Chris Cannam, Steve Harris, Sean Bolton").arg(DSSI_VERSION);
Chris@0 1689 #ifdef HAVE_LIBLO
Chris@0 1690 #ifdef LIBLO_VERSION
Chris@0 1691 aboutText += tr("<br>With liblo Lite OSC library (v%1) &copy; Steve Harris").arg(LIBLO_VERSION);
Chris@0 1692 #else
Chris@0 1693 aboutText += tr("<br>With liblo Lite OSC library &copy; Steve Harris").arg(LIBLO_VERSION);
Chris@0 1694 #endif
Chris@0 1695 if (m_oscQueue && m_oscQueue->isOK()) {
Chris@0 1696 aboutText += tr("<p>The OSC URL for this instance is: \"%1\"").arg(m_oscQueue->getOSCURL());
Chris@0 1697 }
Chris@0 1698 #endif
Chris@0 1699 aboutText += "</p>";
Chris@0 1700 #endif
Chris@0 1701
Chris@0 1702 aboutText +=
Chris@0 1703 "<p>Copyright &copy; 2005&ndash;2012 Chris Cannam and<br>"
Chris@0 1704 "Queen Mary, University of London.</p>"
Chris@0 1705 "<p>This program is free software; you can redistribute it and/or<br>"
Chris@0 1706 "modify it under the terms of the GNU General Public License as<br>"
Chris@0 1707 "published by the Free Software Foundation; either version 2 of the<br>"
Chris@0 1708 "License, or (at your option) any later version.<br>See the file "
Chris@0 1709 "COPYING included with this distribution for more information.</p>";
Chris@0 1710
Chris@0 1711 QMessageBox::about(this, tr("About %1").arg(QApplication::applicationName()), aboutText);
Chris@0 1712 }
Chris@0 1713
Chris@0 1714 void
Chris@0 1715 MainWindow::keyReference()
Chris@0 1716 {
Chris@0 1717 m_keyReference->show();
Chris@0 1718 }
Chris@0 1719
Chris@0 1720