annotate src/MainWindow.cpp @ 70:5310637392f6

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