Chris@0: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@0: Chris@0: /* Chris@0: Tony Chris@0: An intonation analysis and annotation tool Chris@0: Centre for Digital Music, Queen Mary, University of London. Chris@0: This file copyright 2006-2012 Chris Cannam and QMUL. Chris@0: Chris@0: This program is free software; you can redistribute it and/or Chris@0: modify it under the terms of the GNU General Public License as Chris@0: published by the Free Software Foundation; either version 2 of the Chris@0: License, or (at your option) any later version. See the file Chris@0: COPYING included with this distribution for more information. Chris@0: */ Chris@0: Chris@0: #include "../version.h" Chris@0: Chris@0: #include "MainWindow.h" Chris@6: #include "Analyser.h" Chris@6: Chris@0: #include "framework/Document.h" Chris@0: Chris@0: #include "view/Pane.h" Chris@0: #include "view/PaneStack.h" Chris@0: #include "data/model/WaveFileModel.h" matthiasm@26: #include "data/model/NoteModel.h" matthiasm@26: #include "data/model/FlexiNoteModel.h" matthiasm@42: #include "layer/FlexiNoteLayer.h" matthiasm@26: #include "data/model/NoteModel.h" Chris@0: #include "view/ViewManager.h" Chris@0: #include "base/Preferences.h" Chris@0: #include "layer/WaveformLayer.h" Chris@0: #include "layer/TimeInstantLayer.h" Chris@0: #include "layer/TimeValueLayer.h" Chris@0: #include "widgets/Fader.h" Chris@0: #include "view/Overview.h" Chris@0: #include "widgets/AudioDial.h" Chris@0: #include "widgets/IconLoader.h" Chris@0: #include "widgets/KeyReference.h" Chris@0: #include "audioio/AudioCallbackPlaySource.h" Chris@0: #include "audioio/AudioCallbackPlayTarget.h" Chris@0: #include "audioio/PlaySpeedRangeMapper.h" Chris@0: #include "base/Profiler.h" Chris@0: #include "base/UnitDatabase.h" Chris@0: #include "layer/ColourDatabase.h" Chris@0: matthiasm@26: #include "data/fileio/CSVFileWriter.h" matthiasm@26: #include "data/fileio/MIDIFileWriter.h" matthiasm@26: #include "rdf/RDFExporter.h" matthiasm@26: Chris@0: // For version information Chris@0: #include "vamp/vamp.h" Chris@0: #include "vamp-sdk/PluginBase.h" Chris@0: #include "plugin/api/ladspa.h" Chris@0: #include "plugin/api/dssi.h" Chris@0: Chris@0: #include Chris@0: #include Chris@0: #include Chris@0: #include Chris@0: #include Chris@0: #include Chris@0: #include Chris@0: #include Chris@0: #include Chris@0: #include Chris@0: #include Chris@0: #include Chris@2: #include Chris@0: #include Chris@0: #include Chris@0: Chris@0: #include Chris@0: #include Chris@0: #include Chris@0: Chris@0: using std::cerr; Chris@0: using std::endl; Chris@0: Chris@0: using std::vector; Chris@0: Chris@0: Chris@0: MainWindow::MainWindow(bool withAudioOutput, bool withOSCSupport) : Chris@0: MainWindowBase(withAudioOutput, withOSCSupport, false), Chris@0: m_overview(0), Chris@0: m_mainMenusCreated(false), gyorgyf@45: m_intelligentActionOn(true), //GF: !!! temporary Chris@0: m_playbackMenu(0), gyorgyf@45: m_recentFilesMenu(0), Chris@0: m_rightButtonMenu(0), Chris@0: m_rightButtonPlaybackMenu(0), Chris@0: m_deleteSelectedAction(0), Chris@0: m_ffwdAction(0), Chris@0: m_rwdAction(0), Chris@0: m_keyReference(new KeyReference()) Chris@0: { Chris@0: setWindowTitle(QApplication::applicationName()); Chris@0: Chris@0: UnitDatabase *udb = UnitDatabase::getInstance(); Chris@0: udb->registerUnit("Hz"); Chris@0: udb->registerUnit("dB"); Chris@0: udb->registerUnit("s"); Chris@0: Chris@0: ColourDatabase *cdb = ColourDatabase::getInstance(); Chris@0: cdb->addColour(Qt::black, tr("Black")); Chris@0: cdb->addColour(Qt::darkRed, tr("Red")); Chris@0: cdb->addColour(Qt::darkBlue, tr("Blue")); Chris@0: cdb->addColour(Qt::darkGreen, tr("Green")); Chris@0: cdb->addColour(QColor(200, 50, 255), tr("Purple")); Chris@0: cdb->addColour(QColor(255, 150, 50), tr("Orange")); Chris@0: cdb->setUseDarkBackground(cdb->addColour(Qt::white, tr("White")), true); Chris@0: cdb->setUseDarkBackground(cdb->addColour(Qt::red, tr("Bright Red")), true); Chris@0: cdb->setUseDarkBackground(cdb->addColour(QColor(30, 150, 255), tr("Bright Blue")), true); Chris@0: cdb->setUseDarkBackground(cdb->addColour(Qt::green, tr("Bright Green")), true); Chris@0: cdb->setUseDarkBackground(cdb->addColour(QColor(225, 74, 255), tr("Bright Purple")), true); Chris@0: cdb->setUseDarkBackground(cdb->addColour(QColor(255, 188, 80), tr("Bright Orange")), true); Chris@0: Chris@0: Preferences::getInstance()->setResampleOnLoad(true); Chris@0: Preferences::getInstance()->setSpectrogramSmoothing Chris@0: (Preferences::SpectrogramInterpolated); Chris@0: Chris@0: QSettings settings; Chris@0: Chris@0: settings.beginGroup("MainWindow"); Chris@0: settings.setValue("showstatusbar", false); Chris@0: settings.endGroup(); Chris@0: Chris@6: m_viewManager->setAlignMode(false); Chris@6: m_viewManager->setPlaySoloMode(false); Chris@0: m_viewManager->setToolMode(ViewManager::NavigateMode); Chris@0: m_viewManager->setZoomWheelsEnabled(false); Chris@6: m_viewManager->setIlluminateLocalFeatures(true); Chris@0: m_viewManager->setShowWorkTitle(true); Chris@6: m_viewManager->setShowCentreLine(false); Chris@6: m_viewManager->setOverlayMode(ViewManager::NoOverlays); Chris@0: Chris@0: QFrame *frame = new QFrame; Chris@0: setCentralWidget(frame); Chris@0: Chris@0: QGridLayout *layout = new QGridLayout; Chris@0: Chris@0: QScrollArea *scroll = new QScrollArea(frame); Chris@0: scroll->setWidgetResizable(true); Chris@0: scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); Chris@0: scroll->setFrameShape(QFrame::NoFrame); Chris@0: Chris@6: // We have a pane stack: it comes with the territory. However, we Chris@6: // have a fixed and known number of panes in it (e.g. 1) -- it Chris@6: // isn't variable Chris@0: m_paneStack->setLayoutStyle(PaneStack::NoPropertyStacks); Chris@0: scroll->setWidget(m_paneStack); Chris@6: Chris@0: m_overview = new Overview(frame); Chris@0: m_overview->setViewManager(m_viewManager); Chris@0: m_overview->setFixedHeight(40); Chris@0: #ifndef _WIN32 Chris@0: // For some reason, the contents of the overview never appear if we Chris@0: // make this setting on Windows. I have no inclination at the moment Chris@0: // to track down the reason why. Chris@0: m_overview->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); Chris@0: #endif Chris@0: connect(m_overview, SIGNAL(contextHelpChanged(const QString &)), Chris@0: this, SLOT(contextHelpChanged(const QString &))); Chris@0: Chris@0: m_panLayer = new WaveformLayer; Chris@0: m_panLayer->setChannelMode(WaveformLayer::MergeChannels); Chris@0: m_panLayer->setAggressiveCacheing(true); Chris@0: m_overview->addLayer(m_panLayer); Chris@0: Chris@0: if (m_viewManager->getGlobalDarkBackground()) { Chris@0: m_panLayer->setBaseColour Chris@0: (ColourDatabase::getInstance()->getColourIndex(tr("Bright Green"))); Chris@0: } else { Chris@0: m_panLayer->setBaseColour matthiasm@13: (ColourDatabase::getInstance()->getColourIndex(tr("Blue"))); Chris@0: } Chris@0: Chris@0: m_fader = new Fader(frame, false); Chris@0: connect(m_fader, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget())); Chris@0: connect(m_fader, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget())); Chris@0: Chris@0: m_playSpeed = new AudioDial(frame); Chris@0: m_playSpeed->setMinimum(0); Chris@0: m_playSpeed->setMaximum(200); Chris@0: m_playSpeed->setValue(100); Chris@0: m_playSpeed->setFixedWidth(24); Chris@0: m_playSpeed->setFixedHeight(24); Chris@0: m_playSpeed->setNotchesVisible(true); Chris@0: m_playSpeed->setPageStep(10); Chris@0: m_playSpeed->setObjectName(tr("Playback Speedup")); Chris@0: m_playSpeed->setDefaultValue(100); Chris@0: m_playSpeed->setRangeMapper(new PlaySpeedRangeMapper(0, 200)); Chris@0: m_playSpeed->setShowToolTip(true); Chris@0: connect(m_playSpeed, SIGNAL(valueChanged(int)), gyorgyf@27: this, SLOT(playSpeedChanged(int))); Chris@0: connect(m_playSpeed, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget())); Chris@0: connect(m_playSpeed, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget())); Chris@0: Chris@0: layout->setSpacing(4); Chris@6: layout->addWidget(m_overview, 0, 1); Chris@6: layout->addWidget(scroll, 1, 1); Chris@0: Chris@0: layout->setColumnStretch(1, 10); Chris@0: Chris@0: frame->setLayout(layout); Chris@0: gyorgyf@21: m_analyser = new Analyser(); gyorgyf@21: Chris@0: setupMenus(); Chris@0: setupToolbars(); Chris@0: setupHelpMenu(); Chris@0: Chris@0: statusBar(); Chris@0: gyorgyf@21: // m_analyser = new Analyser(); Chris@6: Chris@0: newSession(); Chris@0: } Chris@0: Chris@0: MainWindow::~MainWindow() Chris@0: { Chris@6: delete m_analyser; Chris@0: delete m_keyReference; Chris@0: Profiles::getInstance()->dump(); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::setupMenus() Chris@0: { Chris@0: if (!m_mainMenusCreated) { Chris@0: m_rightButtonMenu = new QMenu(); Chris@0: } Chris@0: Chris@0: if (!m_mainMenusCreated) { Chris@0: CommandHistory::getInstance()->registerMenu(m_rightButtonMenu); Chris@0: m_rightButtonMenu->addSeparator(); Chris@0: } Chris@0: Chris@0: setupFileMenu(); Chris@0: setupEditMenu(); Chris@0: setupViewMenu(); Chris@0: Chris@0: m_mainMenusCreated = true; Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::setupFileMenu() Chris@0: { Chris@0: if (m_mainMenusCreated) return; Chris@0: Chris@0: QMenu *menu = menuBar()->addMenu(tr("&File")); Chris@0: menu->setTearOffEnabled(true); Chris@0: QToolBar *toolbar = addToolBar(tr("File Toolbar")); Chris@0: Chris@0: m_keyReference->setCategory(tr("File and Session Management")); Chris@0: Chris@0: IconLoader il; Chris@1: QIcon icon; Chris@1: QAction *action; Chris@0: Chris@0: icon = il.load("fileopen"); Chris@0: icon.addPixmap(il.loadPixmap("fileopen-22")); Chris@1: action = new QAction(icon, tr("&Open..."), this); Chris@0: action->setShortcut(tr("Ctrl+O")); Chris@1: action->setStatusTip(tr("Open a file")); Chris@0: connect(action, SIGNAL(triggered()), this, SLOT(openFile())); Chris@0: m_keyReference->registerShortcut(action); Chris@0: menu->addAction(action); Chris@0: toolbar->addAction(action); Chris@0: Chris@1: action = new QAction(tr("Open Lo&cation..."), this); Chris@0: action->setShortcut(tr("Ctrl+Shift+O")); Chris@1: action->setStatusTip(tr("Open a file from a remote URL")); Chris@0: connect(action, SIGNAL(triggered()), this, SLOT(openLocation())); Chris@0: m_keyReference->registerShortcut(action); Chris@0: menu->addAction(action); Chris@0: Chris@1: m_recentFilesMenu = menu->addMenu(tr("Open &Recent")); Chris@0: m_recentFilesMenu->setTearOffEnabled(true); Chris@0: setupRecentFilesMenu(); Chris@0: connect(&m_recentFiles, SIGNAL(recentChanged()), Chris@0: this, SLOT(setupRecentFilesMenu())); Chris@0: Chris@0: menu->addSeparator(); matthiasm@26: action = new QAction(tr("Export Annotation Layer..."), this); matthiasm@26: action->setStatusTip(tr("Export layer data to a file")); matthiasm@26: connect(action, SIGNAL(triggered()), this, SLOT(exportLayer())); matthiasm@26: connect(this, SIGNAL(canExportLayer(bool)), action, SLOT(setEnabled(bool))); matthiasm@26: menu->addAction(action); matthiasm@26: matthiasm@26: menu->addSeparator(); Chris@0: action = new QAction(il.load("exit"), tr("&Quit"), this); Chris@0: action->setShortcut(tr("Ctrl+Q")); Chris@0: action->setStatusTip(tr("Exit %1").arg(QApplication::applicationName())); Chris@0: connect(action, SIGNAL(triggered()), this, SLOT(close())); Chris@0: m_keyReference->registerShortcut(action); Chris@0: menu->addAction(action); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::setupEditMenu() Chris@0: { Chris@0: if (m_mainMenusCreated) return; Chris@0: Chris@0: QMenu *menu = menuBar()->addMenu(tr("&Edit")); Chris@0: menu->setTearOffEnabled(true); Chris@0: CommandHistory::getInstance()->registerMenu(menu); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::setupViewMenu() Chris@0: { Chris@0: if (m_mainMenusCreated) return; Chris@0: Chris@0: IconLoader il; Chris@0: Chris@0: QAction *action = 0; Chris@0: Chris@0: m_keyReference->setCategory(tr("Panning and Navigation")); Chris@0: Chris@0: QMenu *menu = menuBar()->addMenu(tr("&View")); Chris@0: menu->setTearOffEnabled(true); Chris@0: action = new QAction(tr("Scroll &Left"), this); Chris@0: action->setShortcut(tr("Left")); Chris@0: action->setStatusTip(tr("Scroll the current pane to the left")); Chris@0: connect(action, SIGNAL(triggered()), this, SLOT(scrollLeft())); Chris@0: connect(this, SIGNAL(canScroll(bool)), action, SLOT(setEnabled(bool))); Chris@0: m_keyReference->registerShortcut(action); Chris@0: menu->addAction(action); gyorgyf@27: Chris@0: action = new QAction(tr("Scroll &Right"), this); Chris@0: action->setShortcut(tr("Right")); Chris@0: action->setStatusTip(tr("Scroll the current pane to the right")); Chris@0: connect(action, SIGNAL(triggered()), this, SLOT(scrollRight())); Chris@0: connect(this, SIGNAL(canScroll(bool)), action, SLOT(setEnabled(bool))); Chris@0: m_keyReference->registerShortcut(action); Chris@0: menu->addAction(action); gyorgyf@27: Chris@0: action = new QAction(tr("&Jump Left"), this); Chris@0: action->setShortcut(tr("Ctrl+Left")); Chris@0: action->setStatusTip(tr("Scroll the current pane a big step to the left")); Chris@0: connect(action, SIGNAL(triggered()), this, SLOT(jumpLeft())); Chris@0: connect(this, SIGNAL(canScroll(bool)), action, SLOT(setEnabled(bool))); Chris@0: m_keyReference->registerShortcut(action); Chris@0: menu->addAction(action); gyorgyf@27: Chris@0: action = new QAction(tr("J&ump Right"), this); Chris@0: action->setShortcut(tr("Ctrl+Right")); Chris@0: action->setStatusTip(tr("Scroll the current pane a big step to the right")); Chris@0: connect(action, SIGNAL(triggered()), this, SLOT(jumpRight())); Chris@0: connect(this, SIGNAL(canScroll(bool)), action, SLOT(setEnabled(bool))); Chris@0: m_keyReference->registerShortcut(action); Chris@0: menu->addAction(action); Chris@0: Chris@0: menu->addSeparator(); Chris@0: Chris@0: m_keyReference->setCategory(tr("Zoom")); Chris@0: Chris@0: action = new QAction(il.load("zoom-in"), Chris@0: tr("Zoom &In"), this); Chris@0: action->setShortcut(tr("Up")); Chris@0: action->setStatusTip(tr("Increase the zoom level")); Chris@0: connect(action, SIGNAL(triggered()), this, SLOT(zoomIn())); Chris@0: connect(this, SIGNAL(canZoom(bool)), action, SLOT(setEnabled(bool))); Chris@0: m_keyReference->registerShortcut(action); Chris@0: menu->addAction(action); gyorgyf@27: Chris@0: action = new QAction(il.load("zoom-out"), Chris@0: tr("Zoom &Out"), this); Chris@0: action->setShortcut(tr("Down")); Chris@0: action->setStatusTip(tr("Decrease the zoom level")); Chris@0: connect(action, SIGNAL(triggered()), this, SLOT(zoomOut())); Chris@0: connect(this, SIGNAL(canZoom(bool)), action, SLOT(setEnabled(bool))); Chris@0: m_keyReference->registerShortcut(action); Chris@0: menu->addAction(action); gyorgyf@27: Chris@0: action = new QAction(tr("Restore &Default Zoom"), this); Chris@0: action->setStatusTip(tr("Restore the zoom level to the default")); Chris@0: connect(action, SIGNAL(triggered()), this, SLOT(zoomDefault())); Chris@0: connect(this, SIGNAL(canZoom(bool)), action, SLOT(setEnabled(bool))); Chris@0: menu->addAction(action); Chris@0: Chris@0: action = new QAction(il.load("zoom-fit"), Chris@0: tr("Zoom to &Fit"), this); Chris@0: action->setShortcut(tr("F")); Chris@0: action->setStatusTip(tr("Zoom to show the whole file")); Chris@0: connect(action, SIGNAL(triggered()), this, SLOT(zoomToFit())); Chris@0: connect(this, SIGNAL(canZoom(bool)), action, SLOT(setEnabled(bool))); Chris@0: m_keyReference->registerShortcut(action); Chris@0: menu->addAction(action); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::setupHelpMenu() Chris@0: { Chris@0: QMenu *menu = menuBar()->addMenu(tr("&Help")); Chris@0: menu->setTearOffEnabled(true); Chris@0: Chris@0: m_keyReference->setCategory(tr("Help")); Chris@0: Chris@0: IconLoader il; Chris@0: Chris@1: QString name = QApplication::applicationName(); Chris@1: Chris@0: QAction *action = new QAction(il.load("help"), Chris@0: tr("&Help Reference"), this); Chris@0: action->setShortcut(tr("F1")); Chris@1: action->setStatusTip(tr("Open the %1 reference manual").arg(name)); Chris@0: connect(action, SIGNAL(triggered()), this, SLOT(help())); Chris@0: m_keyReference->registerShortcut(action); Chris@0: menu->addAction(action); Chris@0: Chris@0: action = new QAction(tr("&Key and Mouse Reference"), this); Chris@0: action->setShortcut(tr("F2")); Chris@1: action->setStatusTip(tr("Open a window showing the keystrokes you can use in %1").arg(name)); Chris@0: connect(action, SIGNAL(triggered()), this, SLOT(keyReference())); Chris@0: m_keyReference->registerShortcut(action); Chris@0: menu->addAction(action); Chris@0: Chris@1: action = new QAction(tr("%1 on the &Web").arg(name), this); Chris@1: action->setStatusTip(tr("Open the %1 website").arg(name)); Chris@0: connect(action, SIGNAL(triggered()), this, SLOT(website())); Chris@0: menu->addAction(action); Chris@0: Chris@1: action = new QAction(tr("&About %1").arg(name), this); Chris@1: action->setStatusTip(tr("Show information about %1").arg(name)); Chris@0: connect(action, SIGNAL(triggered()), this, SLOT(about())); Chris@0: menu->addAction(action); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::setupRecentFilesMenu() Chris@0: { Chris@0: m_recentFilesMenu->clear(); Chris@0: vector files = m_recentFiles.getRecent(); Chris@0: for (size_t i = 0; i < files.size(); ++i) { Chris@50: QAction *action = new QAction(files[i], this); Chris@50: connect(action, SIGNAL(triggered()), this, SLOT(openRecentFile())); Chris@0: if (i == 0) { Chris@0: action->setShortcut(tr("Ctrl+R")); Chris@0: m_keyReference->registerShortcut Chris@0: (tr("Re-open"), Chris@50: action->shortcut().toString(), Chris@0: tr("Re-open the current or most recently opened file")); Chris@0: } Chris@50: m_recentFilesMenu->addAction(action); Chris@0: } Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::setupToolbars() Chris@0: { Chris@0: m_keyReference->setCategory(tr("Playback and Transport Controls")); Chris@0: Chris@0: IconLoader il; Chris@0: Chris@0: QMenu *menu = m_playbackMenu = menuBar()->addMenu(tr("Play&back")); Chris@0: menu->setTearOffEnabled(true); Chris@0: m_rightButtonMenu->addSeparator(); Chris@0: m_rightButtonPlaybackMenu = m_rightButtonMenu->addMenu(tr("Playback")); Chris@0: Chris@0: QToolBar *toolbar = addToolBar(tr("Playback Toolbar")); Chris@0: Chris@0: QAction *rwdStartAction = toolbar->addAction(il.load("rewind-start"), Chris@0: tr("Rewind to Start")); Chris@0: rwdStartAction->setShortcut(tr("Home")); Chris@0: rwdStartAction->setStatusTip(tr("Rewind to the start")); Chris@0: connect(rwdStartAction, SIGNAL(triggered()), this, SLOT(rewindStart())); Chris@0: connect(this, SIGNAL(canPlay(bool)), rwdStartAction, SLOT(setEnabled(bool))); Chris@0: Chris@0: QAction *m_rwdAction = toolbar->addAction(il.load("rewind"), Chris@0: tr("Rewind")); Chris@0: m_rwdAction->setShortcut(tr("PgUp")); Chris@0: m_rwdAction->setStatusTip(tr("Rewind to the previous time instant or time ruler notch")); Chris@0: connect(m_rwdAction, SIGNAL(triggered()), this, SLOT(rewind())); Chris@0: connect(this, SIGNAL(canRewind(bool)), m_rwdAction, SLOT(setEnabled(bool))); Chris@0: Chris@0: QAction *playAction = toolbar->addAction(il.load("playpause"), Chris@0: tr("Play / Pause")); Chris@0: playAction->setCheckable(true); Chris@0: playAction->setShortcut(tr("Space")); Chris@0: playAction->setStatusTip(tr("Start or stop playback from the current position")); Chris@0: connect(playAction, SIGNAL(triggered()), this, SLOT(play())); Chris@0: connect(m_playSource, SIGNAL(playStatusChanged(bool)), gyorgyf@27: playAction, SLOT(setChecked(bool))); Chris@0: connect(this, SIGNAL(canPlay(bool)), playAction, SLOT(setEnabled(bool))); Chris@0: Chris@0: m_ffwdAction = toolbar->addAction(il.load("ffwd"), Chris@0: tr("Fast Forward")); Chris@0: m_ffwdAction->setShortcut(tr("PgDown")); Chris@0: m_ffwdAction->setStatusTip(tr("Fast-forward to the next time instant or time ruler notch")); Chris@0: connect(m_ffwdAction, SIGNAL(triggered()), this, SLOT(ffwd())); Chris@0: connect(this, SIGNAL(canFfwd(bool)), m_ffwdAction, SLOT(setEnabled(bool))); Chris@0: Chris@0: QAction *ffwdEndAction = toolbar->addAction(il.load("ffwd-end"), Chris@0: tr("Fast Forward to End")); Chris@0: ffwdEndAction->setShortcut(tr("End")); Chris@0: ffwdEndAction->setStatusTip(tr("Fast-forward to the end")); Chris@0: connect(ffwdEndAction, SIGNAL(triggered()), this, SLOT(ffwdEnd())); Chris@0: connect(this, SIGNAL(canPlay(bool)), ffwdEndAction, SLOT(setEnabled(bool))); Chris@6: Chris@0: toolbar = addToolBar(tr("Play Mode Toolbar")); Chris@0: Chris@0: QAction *psAction = toolbar->addAction(il.load("playselection"), Chris@0: tr("Constrain Playback to Selection")); Chris@0: psAction->setCheckable(true); Chris@0: psAction->setChecked(m_viewManager->getPlaySelectionMode()); Chris@0: psAction->setShortcut(tr("s")); Chris@0: psAction->setStatusTip(tr("Constrain playback to the selected regions")); Chris@0: connect(m_viewManager, SIGNAL(playSelectionModeChanged(bool)), Chris@0: psAction, SLOT(setChecked(bool))); Chris@0: connect(psAction, SIGNAL(triggered()), this, SLOT(playSelectionToggled())); Chris@0: connect(this, SIGNAL(canPlaySelection(bool)), psAction, SLOT(setEnabled(bool))); Chris@0: Chris@0: QAction *plAction = toolbar->addAction(il.load("playloop"), Chris@0: tr("Loop Playback")); Chris@0: plAction->setCheckable(true); Chris@0: plAction->setChecked(m_viewManager->getPlayLoopMode()); Chris@0: plAction->setShortcut(tr("l")); Chris@0: plAction->setStatusTip(tr("Loop playback")); Chris@0: connect(m_viewManager, SIGNAL(playLoopModeChanged(bool)), Chris@0: plAction, SLOT(setChecked(bool))); Chris@0: connect(plAction, SIGNAL(triggered()), this, SLOT(playLoopToggled())); Chris@0: connect(this, SIGNAL(canPlay(bool)), plAction, SLOT(setEnabled(bool))); Chris@0: Chris@0: m_keyReference->registerShortcut(psAction); Chris@0: m_keyReference->registerShortcut(plAction); Chris@0: m_keyReference->registerShortcut(playAction); Chris@0: m_keyReference->registerShortcut(m_rwdAction); Chris@0: m_keyReference->registerShortcut(m_ffwdAction); Chris@0: m_keyReference->registerShortcut(rwdStartAction); Chris@0: m_keyReference->registerShortcut(ffwdEndAction); Chris@0: Chris@6: menu->addAction(playAction); Chris@0: menu->addAction(psAction); Chris@0: menu->addAction(plAction); Chris@0: menu->addSeparator(); Chris@0: menu->addAction(m_rwdAction); Chris@0: menu->addAction(m_ffwdAction); Chris@0: menu->addSeparator(); Chris@0: menu->addAction(rwdStartAction); Chris@0: menu->addAction(ffwdEndAction); Chris@0: menu->addSeparator(); Chris@0: Chris@0: m_rightButtonPlaybackMenu->addAction(playAction); Chris@0: m_rightButtonPlaybackMenu->addAction(psAction); Chris@0: m_rightButtonPlaybackMenu->addAction(plAction); Chris@0: m_rightButtonPlaybackMenu->addSeparator(); Chris@0: m_rightButtonPlaybackMenu->addAction(m_rwdAction); Chris@0: m_rightButtonPlaybackMenu->addAction(m_ffwdAction); Chris@0: m_rightButtonPlaybackMenu->addSeparator(); Chris@0: m_rightButtonPlaybackMenu->addAction(rwdStartAction); Chris@0: m_rightButtonPlaybackMenu->addAction(ffwdEndAction); Chris@0: m_rightButtonPlaybackMenu->addSeparator(); Chris@0: Chris@0: QAction *fastAction = menu->addAction(tr("Speed Up")); Chris@0: fastAction->setShortcut(tr("Ctrl+PgUp")); Chris@0: fastAction->setStatusTip(tr("Time-stretch playback to speed it up without changing pitch")); Chris@0: connect(fastAction, SIGNAL(triggered()), this, SLOT(speedUpPlayback())); Chris@0: connect(this, SIGNAL(canSpeedUpPlayback(bool)), fastAction, SLOT(setEnabled(bool))); Chris@0: Chris@0: QAction *slowAction = menu->addAction(tr("Slow Down")); Chris@0: slowAction->setShortcut(tr("Ctrl+PgDown")); Chris@0: slowAction->setStatusTip(tr("Time-stretch playback to slow it down without changing pitch")); Chris@0: connect(slowAction, SIGNAL(triggered()), this, SLOT(slowDownPlayback())); Chris@0: connect(this, SIGNAL(canSlowDownPlayback(bool)), slowAction, SLOT(setEnabled(bool))); Chris@0: Chris@0: QAction *normalAction = menu->addAction(tr("Restore Normal Speed")); Chris@0: normalAction->setShortcut(tr("Ctrl+Home")); Chris@0: normalAction->setStatusTip(tr("Restore non-time-stretched playback")); Chris@0: connect(normalAction, SIGNAL(triggered()), this, SLOT(restoreNormalPlayback())); Chris@0: connect(this, SIGNAL(canChangePlaybackSpeed(bool)), normalAction, SLOT(setEnabled(bool))); Chris@0: Chris@0: m_keyReference->registerShortcut(fastAction); Chris@0: m_keyReference->registerShortcut(slowAction); Chris@0: m_keyReference->registerShortcut(normalAction); Chris@0: Chris@0: m_rightButtonPlaybackMenu->addAction(fastAction); Chris@0: m_rightButtonPlaybackMenu->addAction(slowAction); Chris@0: m_rightButtonPlaybackMenu->addAction(normalAction); Chris@6: Chris@6: toolbar = addToolBar(tr("Playback Controls")); Chris@6: toolbar->addWidget(m_playSpeed); Chris@6: toolbar->addWidget(m_fader); Chris@0: gyorgyf@27: toolbar = addToolBar(tr("Test actions toolbar")); // GF: temporary toolbar for triggering actions manually gyorgyf@27: gyorgyf@27: // GF: TEMP : this created a menu item gyorgyf@24: m_editSelectAction = toolbar->addAction(il.load("move"), tr("Edit")); gyorgyf@24: m_editSelectAction->setShortcut(tr("Home")); gyorgyf@24: m_editSelectAction->setStatusTip(tr("Edit Notes")); gyorgyf@27: m_editSelectAction->setEnabled(true); gyorgyf@21: // connect(test, SIGNAL(triggered()), this, SLOT(about())); gyorgyf@21: // connect(test, SIGNAL(triggered()), m_analyser, SLOT(resizeLayer())); gyorgyf@27: connect(m_editSelectAction, SIGNAL(triggered()), this, SLOT(selectNoteEditMode())); gyorgyf@21: // connect(this, SIGNAL(canPlay(bool)), test, SLOT(setEnabled(bool))); gyorgyf@27: menu->addAction(m_editSelectAction); gyorgyf@45: gyorgyf@45: m_toggleIntelligenceAction = toolbar->addAction(il.load("notes"), tr("EditMode")); gyorgyf@45: // m_toggleIntelligenceAction->setShortcut(tr("Home")); gyorgyf@45: m_toggleIntelligenceAction->setStatusTip(tr("Toggle note edit boundary constraints and automation")); gyorgyf@45: m_toggleIntelligenceAction->setEnabled(true); gyorgyf@45: connect(m_toggleIntelligenceAction, SIGNAL(triggered()), this, SLOT(toggleNoteEditIntelligence())); gyorgyf@21: Chris@0: Pane::registerShortcuts(*m_keyReference); Chris@0: } Chris@0: Chris@0: void gyorgyf@27: MainWindow::selectNoteEditMode() gyorgyf@21: { gyorgyf@27: IconLoader il; gyorgyf@27: if (m_viewManager->getToolMode() == ViewManager::NoteEditMode) { gyorgyf@27: m_viewManager->setToolMode(ViewManager::NavigateMode); gyorgyf@27: m_editSelectAction->setIcon(il.load("move")); gyorgyf@27: } else { gyorgyf@27: std::cerr << "NoteEdit mode selected" << std::endl; gyorgyf@27: m_viewManager->setToolMode(ViewManager::NoteEditMode); gyorgyf@27: m_editSelectAction->setIcon(il.load("navigate")); gyorgyf@45: } gyorgyf@45: } gyorgyf@45: gyorgyf@45: void gyorgyf@45: MainWindow::toggleNoteEditIntelligence() gyorgyf@45: { gyorgyf@45: IconLoader il; gyorgyf@45: if (m_intelligentActionOn == true) { gyorgyf@45: m_toggleIntelligenceAction->setIcon(il.load("values")); gyorgyf@45: m_intelligentActionOn = false; gyorgyf@45: m_analyser->setIntelligentActions(false); gyorgyf@45: } else { gyorgyf@45: m_toggleIntelligenceAction->setIcon(il.load("notes")); gyorgyf@45: m_intelligentActionOn = true; gyorgyf@45: m_analyser->setIntelligentActions(true); gyorgyf@27: } gyorgyf@21: } gyorgyf@21: gyorgyf@21: void Chris@0: MainWindow::updateMenuStates() Chris@0: { Chris@0: MainWindowBase::updateMenuStates(); Chris@0: Chris@0: Pane *currentPane = 0; Chris@0: Layer *currentLayer = 0; Chris@0: Chris@0: if (m_paneStack) currentPane = m_paneStack->getCurrentPane(); Chris@0: if (currentPane) currentLayer = currentPane->getSelectedLayer(); Chris@0: Chris@0: bool haveCurrentPane = Chris@0: (currentPane != 0); Chris@0: bool haveCurrentLayer = Chris@0: (haveCurrentPane && Chris@0: (currentLayer != 0)); Chris@0: bool haveSelection = gyorgyf@27: (m_viewManager && gyorgyf@27: !m_viewManager->getSelections().empty()); Chris@0: bool haveCurrentEditableLayer = gyorgyf@27: (haveCurrentLayer && gyorgyf@27: currentLayer->isLayerEditable()); Chris@0: bool haveCurrentTimeInstantsLayer = gyorgyf@27: (haveCurrentLayer && gyorgyf@27: qobject_cast(currentLayer)); Chris@0: bool haveCurrentTimeValueLayer = gyorgyf@27: (haveCurrentLayer && gyorgyf@27: qobject_cast(currentLayer)); Chris@0: Chris@0: emit canChangePlaybackSpeed(true); Chris@0: int v = m_playSpeed->value(); Chris@0: emit canSpeedUpPlayback(v < m_playSpeed->maximum()); Chris@0: emit canSlowDownPlayback(v > m_playSpeed->minimum()); Chris@0: Chris@0: if (m_ffwdAction && m_rwdAction) { Chris@0: if (haveCurrentTimeInstantsLayer) { Chris@0: m_ffwdAction->setText(tr("Fast Forward to Next Instant")); Chris@0: m_ffwdAction->setStatusTip(tr("Fast forward to the next time instant in the current layer")); Chris@0: m_rwdAction->setText(tr("Rewind to Previous Instant")); Chris@0: m_rwdAction->setStatusTip(tr("Rewind to the previous time instant in the current layer")); Chris@0: } else if (haveCurrentTimeValueLayer) { Chris@0: m_ffwdAction->setText(tr("Fast Forward to Next Point")); Chris@0: m_ffwdAction->setStatusTip(tr("Fast forward to the next point in the current layer")); Chris@0: m_rwdAction->setText(tr("Rewind to Previous Point")); Chris@0: m_rwdAction->setStatusTip(tr("Rewind to the previous point in the current layer")); Chris@0: } else { Chris@0: m_ffwdAction->setText(tr("Fast Forward")); Chris@0: m_ffwdAction->setStatusTip(tr("Fast forward")); Chris@0: m_rwdAction->setText(tr("Rewind")); Chris@0: m_rwdAction->setStatusTip(tr("Rewind")); Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::updateDescriptionLabel() Chris@0: { Chris@6: // Nothing, we don't have one Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::documentModified() Chris@0: { Chris@0: MainWindowBase::documentModified(); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::documentRestored() Chris@0: { Chris@0: MainWindowBase::documentRestored(); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::newSession() Chris@0: { Chris@0: if (!checkSaveModified()) return; Chris@0: Chris@0: closeSession(); Chris@0: createDocument(); Chris@0: m_document->setAutoAlignment(true); Chris@0: Chris@0: Pane *pane = m_paneStack->addPane(); Chris@0: Chris@0: connect(pane, SIGNAL(contextHelpChanged(const QString &)), Chris@0: this, SLOT(contextHelpChanged(const QString &))); Chris@0: Chris@6: // Layer *waveform = m_document->createMainModelLayer(LayerFactory::Waveform); Chris@6: // m_document->addLayerToView(pane, waveform); Chris@0: Chris@0: m_overview->registerView(pane); Chris@0: Chris@0: CommandHistory::getInstance()->clear(); Chris@0: CommandHistory::getInstance()->documentSaved(); Chris@0: documentRestored(); Chris@0: updateMenuStates(); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::closeSession() Chris@0: { Chris@0: if (!checkSaveModified()) return; Chris@0: Chris@0: while (m_paneStack->getPaneCount() > 0) { Chris@0: gyorgyf@27: Pane *pane = m_paneStack->getPane(m_paneStack->getPaneCount() - 1); Chris@0: gyorgyf@27: while (pane->getLayerCount() > 0) { gyorgyf@27: m_document->removeLayerFromView gyorgyf@27: (pane, pane->getLayer(pane->getLayerCount() - 1)); gyorgyf@27: } Chris@0: gyorgyf@27: m_overview->unregisterView(pane); gyorgyf@27: m_paneStack->deletePane(pane); Chris@0: } Chris@0: Chris@0: while (m_paneStack->getHiddenPaneCount() > 0) { Chris@0: gyorgyf@27: Pane *pane = m_paneStack->getHiddenPane gyorgyf@27: (m_paneStack->getHiddenPaneCount() - 1); Chris@0: gyorgyf@27: while (pane->getLayerCount() > 0) { gyorgyf@27: m_document->removeLayerFromView gyorgyf@27: (pane, pane->getLayer(pane->getLayerCount() - 1)); gyorgyf@27: } Chris@0: gyorgyf@27: m_overview->unregisterView(pane); gyorgyf@27: m_paneStack->deletePane(pane); Chris@0: } Chris@0: Chris@0: delete m_document; Chris@0: m_document = 0; Chris@0: m_viewManager->clearSelections(); Chris@0: m_timeRulerLayer = 0; // document owned this Chris@0: Chris@0: m_sessionFile = ""; Chris@0: Chris@0: CommandHistory::getInstance()->clear(); Chris@0: CommandHistory::getInstance()->documentSaved(); Chris@0: documentRestored(); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::openFile() Chris@0: { Chris@0: QString orig = m_audioFile; Chris@0: if (orig == "") orig = "."; Chris@0: else orig = QFileInfo(orig).absoluteDir().canonicalPath(); Chris@0: Chris@0: QString path = getOpenFileName(FileFinder::AnyFile); Chris@0: Chris@0: if (path.isEmpty()) return; Chris@0: Chris@1: FileOpenStatus status = open(path, ReplaceSession); Chris@0: Chris@0: if (status == FileOpenFailed) { Chris@0: QMessageBox::critical(this, tr("Failed to open file"), Chris@0: tr("File open failed

File \"%1\" could not be opened").arg(path)); Chris@0: } else if (status == FileOpenWrongMode) { Chris@0: QMessageBox::critical(this, tr("Failed to open file"), Chris@0: tr("Audio required

Please load at least one audio file before importing annotation data")); Chris@0: } else { Chris@0: configureNewPane(m_paneStack->getCurrentPane()); Chris@0: } Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::openLocation() Chris@0: { Chris@0: QSettings settings; Chris@0: settings.beginGroup("MainWindow"); Chris@0: QString lastLocation = settings.value("lastremote", "").toString(); Chris@0: Chris@0: bool ok = false; Chris@0: QString text = QInputDialog::getText Chris@0: (this, tr("Open Location"), Chris@0: tr("Please enter the URL of the location to open:"), Chris@0: QLineEdit::Normal, lastLocation, &ok); Chris@0: Chris@0: if (!ok) return; Chris@0: Chris@0: settings.setValue("lastremote", text); Chris@0: Chris@0: if (text.isEmpty()) return; Chris@0: Chris@1: FileOpenStatus status = open(text, ReplaceSession); Chris@0: Chris@0: if (status == FileOpenFailed) { Chris@0: QMessageBox::critical(this, tr("Failed to open location"), Chris@0: tr("Open failed

URL \"%1\" could not be opened").arg(text)); Chris@0: } else if (status == FileOpenWrongMode) { Chris@0: QMessageBox::critical(this, tr("Failed to open location"), Chris@0: tr("Audio required

Please load at least one audio file before importing annotation data")); Chris@0: } else { Chris@0: configureNewPane(m_paneStack->getCurrentPane()); Chris@0: } Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::openRecentFile() Chris@0: { Chris@0: QObject *obj = sender(); Chris@3: QAction *action = qobject_cast(obj); Chris@0: Chris@0: if (!action) { gyorgyf@27: std::cerr << "WARNING: MainWindow::openRecentFile: sender is not an action" gyorgyf@27: << std::endl; gyorgyf@27: return; Chris@0: } Chris@0: Chris@0: QString path = action->text(); Chris@0: if (path == "") return; Chris@0: Chris@1: FileOpenStatus status = open(path, ReplaceSession); Chris@0: Chris@0: if (status == FileOpenFailed) { Chris@0: QMessageBox::critical(this, tr("Failed to open location"), Chris@0: tr("Open failed

File or URL \"%1\" could not be opened").arg(path)); Chris@0: } else if (status == FileOpenWrongMode) { Chris@0: QMessageBox::critical(this, tr("Failed to open location"), Chris@0: tr("Audio required

Please load at least one audio file before importing annotation data")); Chris@0: } else { Chris@0: configureNewPane(m_paneStack->getCurrentPane()); Chris@0: } Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::paneAdded(Pane *pane) Chris@0: { Chris@6: pane->setPlaybackFollow(PlaybackScrollPage); Chris@0: m_paneStack->sizePanesEqually(); Chris@0: if (m_overview) m_overview->registerView(pane); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::paneHidden(Pane *pane) Chris@0: { Chris@0: if (m_overview) m_overview->unregisterView(pane); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::paneAboutToBeDeleted(Pane *pane) Chris@0: { Chris@0: if (m_overview) m_overview->unregisterView(pane); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::paneDropAccepted(Pane *pane, QStringList uriList) Chris@0: { Chris@4: if (pane) m_paneStack->setCurrentPane(pane); Chris@0: Chris@0: for (QStringList::iterator i = uriList.begin(); i != uriList.end(); ++i) { Chris@0: Chris@1: FileOpenStatus status = open(*i, ReplaceSession); Chris@0: Chris@0: if (status == FileOpenFailed) { Chris@0: QMessageBox::critical(this, tr("Failed to open dropped URL"), Chris@0: tr("Open failed

Dropped URL \"%1\" could not be opened").arg(*i)); Chris@0: } else if (status == FileOpenWrongMode) { Chris@0: QMessageBox::critical(this, tr("Failed to open dropped URL"), Chris@0: tr("Audio required

Please load at least one audio file before importing annotation data")); Chris@0: } else { Chris@0: configureNewPane(m_paneStack->getCurrentPane()); Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::paneDropAccepted(Pane *pane, QString text) Chris@0: { Chris@0: if (pane) m_paneStack->setCurrentPane(pane); Chris@0: Chris@0: QUrl testUrl(text); Chris@0: if (testUrl.scheme() == "file" || Chris@0: testUrl.scheme() == "http" || Chris@0: testUrl.scheme() == "ftp") { Chris@0: QStringList list; Chris@0: list.push_back(text); Chris@0: paneDropAccepted(pane, list); Chris@0: return; Chris@0: } Chris@0: Chris@0: //!!! open as text -- but by importing as if a CSV, or just adding Chris@0: //to a text layer? Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::configureNewPane(Pane *pane) Chris@0: { Chris@0: std::cerr << "MainWindow::configureNewPane(" << pane << ")" << std::endl; Chris@0: Chris@6: if (!pane) { Chris@6: pane = m_paneStack->addPane(); Chris@6: } Chris@0: Chris@6: m_analyser->newFileLoaded(m_document, getMainModel(), m_paneStack, pane); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::closeEvent(QCloseEvent *e) Chris@0: { Chris@0: // std::cerr << "MainWindow::closeEvent" << std::endl; Chris@0: Chris@0: if (m_openingAudioFile) { Chris@0: // std::cerr << "Busy - ignoring close event" << std::endl; gyorgyf@27: e->ignore(); gyorgyf@27: return; Chris@0: } Chris@0: Chris@0: if (!m_abandoning && !checkSaveModified()) { Chris@0: // std::cerr << "Ignoring close event" << std::endl; gyorgyf@27: e->ignore(); gyorgyf@27: return; Chris@0: } Chris@0: Chris@0: QSettings settings; Chris@0: settings.beginGroup("MainWindow"); Chris@0: settings.setValue("size", size()); Chris@0: settings.setValue("position", pos()); Chris@0: settings.endGroup(); Chris@0: Chris@0: delete m_keyReference; Chris@0: m_keyReference = 0; Chris@0: Chris@0: closeSession(); Chris@0: Chris@0: e->accept(); Chris@0: return; Chris@0: } Chris@0: Chris@0: bool Chris@0: MainWindow::commitData(bool mayAskUser) Chris@0: { Chris@0: if (mayAskUser) { Chris@0: bool rv = checkSaveModified(); Chris@0: return rv; Chris@0: } else { Chris@0: if (!m_documentModified) return true; Chris@0: Chris@0: // If we can't check with the user first, then we can't save Chris@0: // to the original session file (even if we have it) -- have Chris@0: // to use a temporary file Chris@0: Chris@0: QString svDirBase = ".sv1"; Chris@0: QString svDir = QDir::home().filePath(svDirBase); Chris@0: Chris@0: if (!QFileInfo(svDir).exists()) { Chris@0: if (!QDir::home().mkdir(svDirBase)) return false; Chris@0: } else { Chris@0: if (!QFileInfo(svDir).isDir()) return false; Chris@0: } Chris@0: Chris@0: // This name doesn't have to be unguessable Chris@0: #ifndef _WIN32 Chris@0: QString fname = QString("tmp-%1-%2.sv") Chris@0: .arg(QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz")) Chris@0: .arg(QProcess().pid()); Chris@0: #else Chris@0: QString fname = QString("tmp-%1.sv") Chris@0: .arg(QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz")); Chris@0: #endif Chris@0: QString fpath = QDir(svDir).filePath(fname); Chris@0: if (saveSessionFile(fpath)) { Chris@0: m_recentFiles.addFile(fpath); Chris@0: return true; Chris@0: } else { Chris@0: return false; Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: bool Chris@0: MainWindow::checkSaveModified() Chris@0: { Chris@0: // Called before some destructive operation (e.g. new session, Chris@0: // exit program). Return true if we can safely proceed, false to Chris@0: // cancel. Chris@0: Chris@0: if (!m_documentModified) return true; Chris@0: Chris@0: int button = gyorgyf@27: QMessageBox::warning(this, gyorgyf@27: tr("Session modified"), gyorgyf@27: tr("The current session has been modified.\nDo you want to save it?"), gyorgyf@27: QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, Chris@0: QMessageBox::Yes); Chris@0: Chris@0: if (button == QMessageBox::Yes) { gyorgyf@27: saveSession(); gyorgyf@27: if (m_documentModified) { // save failed -- don't proceed! gyorgyf@27: return false; gyorgyf@27: } else { Chris@0: return true; // saved, so it's safe to continue now Chris@0: } Chris@0: } else if (button == QMessageBox::No) { gyorgyf@27: m_documentModified = false; // so we know to abandon it gyorgyf@27: return true; Chris@0: } Chris@0: Chris@0: // else cancel Chris@0: return false; Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::saveSession() Chris@0: { Chris@0: if (m_sessionFile != "") { gyorgyf@27: if (!saveSessionFile(m_sessionFile)) { gyorgyf@27: QMessageBox::critical(this, tr("Failed to save file"), gyorgyf@27: tr("Session file \"%1\" could not be saved.").arg(m_sessionFile)); Chris@0: } else { gyorgyf@27: CommandHistory::getInstance()->documentSaved(); gyorgyf@27: documentRestored(); gyorgyf@27: } gyorgyf@27: } else { gyorgyf@27: saveSessionAs(); Chris@0: } Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::saveSessionAs() Chris@0: { Chris@0: QString orig = m_audioFile; Chris@0: if (orig == "") orig = "."; Chris@0: else orig = QFileInfo(orig).absoluteDir().canonicalPath(); Chris@0: Chris@0: QString path = getSaveFileName(FileFinder::SessionFile); Chris@0: Chris@0: if (path == "") return; Chris@0: Chris@0: if (!saveSessionFile(path)) { gyorgyf@27: QMessageBox::critical(this, tr("Failed to save file"), gyorgyf@27: tr("Session file \"%1\" could not be saved.").arg(path)); Chris@0: } else { gyorgyf@27: setWindowTitle(tr("%1: %2") Chris@0: .arg(QApplication::applicationName()) gyorgyf@27: .arg(QFileInfo(path).fileName())); gyorgyf@27: m_sessionFile = path; gyorgyf@27: CommandHistory::getInstance()->documentSaved(); gyorgyf@27: documentRestored(); Chris@0: m_recentFiles.addFile(path); Chris@0: } Chris@0: } Chris@0: Chris@0: void matthiasm@26: MainWindow::exportLayer() matthiasm@26: { matthiasm@26: Pane *pane = m_paneStack->getCurrentPane(); matthiasm@26: if (!pane) return; matthiasm@26: matthiasm@26: Layer *layer = pane->getSelectedLayer(); matthiasm@26: if (!layer) return; matthiasm@26: matthiasm@26: Model *model = layer->getModel(); matthiasm@26: if (!model) return; matthiasm@26: matthiasm@26: FileFinder::FileType type = FileFinder::LayerFileNoMidi; matthiasm@26: matthiasm@26: if (dynamic_cast(model)) type = FileFinder::LayerFile; matthiasm@26: matthiasm@26: QString path = getSaveFileName(type); matthiasm@26: matthiasm@26: if (path == "") return; matthiasm@26: matthiasm@26: if (QFileInfo(path).suffix() == "") path += ".svl"; matthiasm@26: matthiasm@26: QString suffix = QFileInfo(path).suffix().toLower(); matthiasm@26: matthiasm@26: QString error; matthiasm@26: matthiasm@26: if (suffix == "xml" || suffix == "svl") { matthiasm@26: matthiasm@26: QFile file(path); matthiasm@26: if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { matthiasm@26: error = tr("Failed to open file %1 for writing").arg(path); matthiasm@26: } else { matthiasm@26: QTextStream out(&file); matthiasm@26: out << "\n" matthiasm@26: << "\n" matthiasm@26: << "\n" matthiasm@26: << " \n"; matthiasm@26: matthiasm@26: model->toXml(out, " "); matthiasm@26: matthiasm@26: out << " \n" matthiasm@26: << " \n"; matthiasm@26: matthiasm@26: layer->toXml(out, " "); matthiasm@26: matthiasm@26: out << " \n" matthiasm@26: << "\n"; matthiasm@26: } matthiasm@26: matthiasm@26: // } else if (suffix == "mid" || suffix == "midi") { matthiasm@26: // matthiasm@26: // FlexiNoteModel *nm = dynamic_cast(model); matthiasm@26: // matthiasm@26: // if (!nm) { matthiasm@26: // error = tr("Can't export non-note layers to MIDI"); matthiasm@26: // } else { matthiasm@26: // MIDIFileWriter writer(path, nm); matthiasm@26: // writer.write(); matthiasm@26: // if (!writer.isOK()) { matthiasm@26: // error = writer.getError(); matthiasm@26: // } matthiasm@26: // } matthiasm@26: matthiasm@26: } else if (suffix == "ttl" || suffix == "n3") { matthiasm@26: matthiasm@26: if (!RDFExporter::canExportModel(model)) { matthiasm@26: error = tr("Sorry, cannot export this layer type to RDF (supported types are: region, note, text, time instants, time values)"); matthiasm@26: } else { matthiasm@26: RDFExporter exporter(path, model); matthiasm@26: exporter.write(); matthiasm@26: if (!exporter.isOK()) { matthiasm@26: error = exporter.getError(); matthiasm@26: } matthiasm@26: } matthiasm@26: matthiasm@26: } else { matthiasm@26: matthiasm@26: CSVFileWriter writer(path, model, matthiasm@26: ((suffix == "csv") ? "," : "\t")); matthiasm@26: writer.write(); matthiasm@26: matthiasm@26: if (!writer.isOK()) { matthiasm@26: error = writer.getError(); matthiasm@26: } matthiasm@26: } matthiasm@26: matthiasm@26: if (error != "") { matthiasm@26: QMessageBox::critical(this, tr("Failed to write file"), error); matthiasm@26: } else { matthiasm@26: m_recentFiles.addFile(path); matthiasm@26: emit activity(tr("Export layer to \"%1\"").arg(path)); matthiasm@26: } matthiasm@26: } matthiasm@26: matthiasm@26: matthiasm@26: void Chris@0: MainWindow::renameCurrentLayer() Chris@0: { Chris@0: Pane *pane = m_paneStack->getCurrentPane(); Chris@0: if (pane) { gyorgyf@27: Layer *layer = pane->getSelectedLayer(); gyorgyf@27: if (layer) { gyorgyf@27: bool ok = false; gyorgyf@27: QString newName = QInputDialog::getText gyorgyf@27: (this, tr("Rename Layer"), gyorgyf@27: tr("New name for this layer:"), gyorgyf@27: QLineEdit::Normal, layer->objectName(), &ok); gyorgyf@27: if (ok) { gyorgyf@27: layer->setObjectName(newName); gyorgyf@27: } gyorgyf@27: } Chris@0: } Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::playSpeedChanged(int position) Chris@0: { Chris@0: PlaySpeedRangeMapper mapper(0, 200); Chris@0: Chris@0: float percent = m_playSpeed->mappedValue(); Chris@0: float factor = mapper.getFactorForValue(percent); Chris@0: Chris@0: std::cerr << "speed = " << position << " percent = " << percent << " factor = " << factor << std::endl; Chris@0: Chris@0: bool something = (position != 100); Chris@0: Chris@0: int pc = lrintf(percent); Chris@0: Chris@0: if (!something) { Chris@0: contextHelpChanged(tr("Playback speed: Normal")); Chris@0: } else { Chris@0: contextHelpChanged(tr("Playback speed: %1%2%") Chris@0: .arg(position > 100 ? "+" : "") Chris@0: .arg(pc)); Chris@0: } Chris@0: Chris@0: m_playSource->setTimeStretch(factor); Chris@0: Chris@0: updateMenuStates(); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::playSharpenToggled() Chris@0: { Chris@0: QSettings settings; Chris@0: settings.beginGroup("MainWindow"); Chris@0: settings.setValue("playsharpen", m_playSharpen->isChecked()); Chris@0: settings.endGroup(); Chris@0: Chris@0: playSpeedChanged(m_playSpeed->value()); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::playMonoToggled() Chris@0: { Chris@0: QSettings settings; Chris@0: settings.beginGroup("MainWindow"); Chris@0: settings.setValue("playmono", m_playMono->isChecked()); Chris@0: settings.endGroup(); Chris@0: Chris@0: playSpeedChanged(m_playSpeed->value()); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::speedUpPlayback() Chris@0: { Chris@0: int value = m_playSpeed->value(); Chris@0: value = value + m_playSpeed->pageStep(); Chris@0: if (value > m_playSpeed->maximum()) value = m_playSpeed->maximum(); Chris@0: m_playSpeed->setValue(value); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::slowDownPlayback() Chris@0: { Chris@0: int value = m_playSpeed->value(); Chris@0: value = value - m_playSpeed->pageStep(); Chris@0: if (value < m_playSpeed->minimum()) value = m_playSpeed->minimum(); Chris@0: m_playSpeed->setValue(value); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::restoreNormalPlayback() Chris@0: { Chris@0: m_playSpeed->setValue(m_playSpeed->defaultValue()); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::updateVisibleRangeDisplay(Pane *p) const Chris@0: { Chris@0: if (!getMainModel() || !p) { Chris@0: return; Chris@0: } Chris@0: Chris@0: bool haveSelection = false; Chris@0: size_t startFrame = 0, endFrame = 0; Chris@0: Chris@0: if (m_viewManager && m_viewManager->haveInProgressSelection()) { Chris@0: Chris@0: bool exclusive = false; Chris@0: Selection s = m_viewManager->getInProgressSelection(exclusive); Chris@0: Chris@0: if (!s.isEmpty()) { Chris@0: haveSelection = true; Chris@0: startFrame = s.getStartFrame(); Chris@0: endFrame = s.getEndFrame(); Chris@0: } Chris@0: } Chris@0: Chris@0: if (!haveSelection) { Chris@0: startFrame = p->getFirstVisibleFrame(); Chris@0: endFrame = p->getLastVisibleFrame(); Chris@0: } Chris@0: Chris@0: RealTime start = RealTime::frame2RealTime Chris@0: (startFrame, getMainModel()->getSampleRate()); Chris@0: Chris@0: RealTime end = RealTime::frame2RealTime Chris@0: (endFrame, getMainModel()->getSampleRate()); Chris@0: Chris@0: RealTime duration = end - start; Chris@0: Chris@0: QString startStr, endStr, durationStr; Chris@0: startStr = start.toText(true).c_str(); Chris@0: endStr = end.toText(true).c_str(); Chris@0: durationStr = duration.toText(true).c_str(); Chris@0: Chris@0: if (haveSelection) { Chris@0: m_myStatusMessage = tr("Selection: %1 to %2 (duration %3)") Chris@0: .arg(startStr).arg(endStr).arg(durationStr); Chris@0: } else { Chris@0: m_myStatusMessage = tr("Visible: %1 to %2 (duration %3)") Chris@0: .arg(startStr).arg(endStr).arg(durationStr); Chris@0: } matthiasm@42: matthiasm@42: // scale Y axis matthiasm@42: FlexiNoteLayer *fnl = dynamic_cast(p->getLayer(2)); matthiasm@42: if (fnl) { matthiasm@42: fnl->setVerticalRangeToNoteRange(p); matthiasm@42: } matthiasm@42: Chris@0: statusBar()->showMessage(m_myStatusMessage); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::updatePositionStatusDisplays() const Chris@0: { Chris@0: if (!statusBar()->isVisible()) return; Chris@0: Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::outputLevelsChanged(float left, float right) Chris@0: { Chris@0: m_fader->setPeakLeft(left); Chris@0: m_fader->setPeakRight(right); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::sampleRateMismatch(size_t requested, size_t actual, Chris@0: bool willResample) Chris@0: { Chris@0: updateDescriptionLabel(); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::audioOverloadPluginDisabled() Chris@0: { Chris@0: QMessageBox::information Chris@0: (this, tr("Audio processing overload"), Chris@0: tr("Overloaded

Audio effects plugin auditioning has been disabled due to a processing overload.")); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::audioTimeStretchMultiChannelDisabled() Chris@0: { Chris@0: static bool shownOnce = false; Chris@0: if (shownOnce) return; Chris@0: QMessageBox::information Chris@0: (this, tr("Audio processing overload"), Chris@0: tr("Overloaded

Audio playback speed processing has been reduced to a single channel, due to a processing overload.")); Chris@0: shownOnce = true; Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::layerRemoved(Layer *layer) Chris@0: { Chris@0: MainWindowBase::layerRemoved(layer); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::layerInAView(Layer *layer, bool inAView) Chris@0: { Chris@0: MainWindowBase::layerInAView(layer, inAView); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::modelAdded(Model *model) Chris@0: { Chris@0: MainWindowBase::modelAdded(model); Chris@3: DenseTimeValueModel *dtvm = qobject_cast(model); Chris@0: if (dtvm) { Chris@0: std::cerr << "A dense time-value model (such as an audio file) has been loaded" << std::endl; Chris@0: } Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::modelAboutToBeDeleted(Model *model) Chris@0: { Chris@0: MainWindowBase::modelAboutToBeDeleted(model); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::mainModelChanged(WaveFileModel *model) Chris@0: { Chris@0: m_panLayer->setModel(model); Chris@0: Chris@0: MainWindowBase::mainModelChanged(model); Chris@0: Chris@0: if (m_playTarget) { Chris@0: connect(m_fader, SIGNAL(valueChanged(float)), Chris@0: m_playTarget, SLOT(setOutputGain(float))); Chris@0: } Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::modelGenerationFailed(QString transformName, QString message) Chris@0: { Chris@0: if (message != "") { Chris@0: Chris@0: QMessageBox::warning Chris@0: (this, Chris@0: tr("Failed to generate layer"), Chris@0: tr("Layer generation failed

Failed to generate derived layer.

The layer transform \"%1\" failed:

%2") Chris@0: .arg(transformName).arg(message), Chris@0: QMessageBox::Ok); Chris@0: } else { Chris@0: QMessageBox::warning Chris@0: (this, Chris@0: tr("Failed to generate layer"), Chris@0: tr("Layer generation failed

Failed to generate a derived layer.

The layer transform \"%1\" failed.

No error information is available.") Chris@0: .arg(transformName), Chris@0: QMessageBox::Ok); Chris@0: } Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::modelGenerationWarning(QString transformName, QString message) Chris@0: { Chris@0: QMessageBox::warning Chris@0: (this, tr("Warning"), message, QMessageBox::Ok); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::modelRegenerationFailed(QString layerName, Chris@0: QString transformName, QString message) Chris@0: { Chris@0: if (message != "") { Chris@0: Chris@0: QMessageBox::warning Chris@0: (this, Chris@0: tr("Failed to regenerate layer"), Chris@0: tr("Layer generation failed

Failed to regenerate derived layer \"%1\" using new data model as input.

The layer transform \"%2\" failed:

%3") Chris@0: .arg(layerName).arg(transformName).arg(message), Chris@0: QMessageBox::Ok); Chris@0: } else { Chris@0: QMessageBox::warning Chris@0: (this, Chris@0: tr("Failed to regenerate layer"), Chris@0: tr("Layer generation failed

Failed to regenerate derived layer \"%1\" using new data model as input.

The layer transform \"%2\" failed.

No error information is available.") Chris@0: .arg(layerName).arg(transformName), Chris@0: QMessageBox::Ok); Chris@0: } Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::modelRegenerationWarning(QString layerName, Chris@0: QString transformName, QString message) Chris@0: { Chris@0: QMessageBox::warning Chris@0: (this, tr("Warning"), tr("Warning when regenerating layer

When regenerating the derived layer \"%1\" using new data model as input:

%2").arg(layerName).arg(message), QMessageBox::Ok); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::alignmentFailed(QString transformName, QString message) Chris@0: { Chris@0: QMessageBox::warning Chris@0: (this, Chris@0: tr("Failed to calculate alignment"), Chris@0: tr("Alignment calculation failed

Failed to calculate an audio alignment using transform \"%1\":

%2") Chris@0: .arg(transformName).arg(message), Chris@0: QMessageBox::Ok); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::rightButtonMenuRequested(Pane *pane, QPoint position) Chris@0: { Chris@0: // std::cerr << "MainWindow::rightButtonMenuRequested(" << pane << ", " << position.x() << ", " << position.y() << ")" << std::endl; Chris@0: m_paneStack->setCurrentPane(pane); Chris@0: m_rightButtonMenu->popup(position); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::handleOSCMessage(const OSCMessage &message) Chris@0: { Chris@0: std::cerr << "MainWindow::handleOSCMessage: Not implemented" << std::endl; Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::mouseEnteredWidget() Chris@0: { Chris@3: QWidget *w = qobject_cast(sender()); Chris@0: if (!w) return; Chris@0: Chris@0: if (w == m_fader) { Chris@0: contextHelpChanged(tr("Adjust the master playback level")); Chris@0: } else if (w == m_playSpeed) { Chris@0: contextHelpChanged(tr("Adjust the master playback speed")); Chris@0: } else if (w == m_playSharpen && w->isEnabled()) { Chris@0: contextHelpChanged(tr("Toggle transient sharpening for playback time scaling")); Chris@0: } else if (w == m_playMono && w->isEnabled()) { Chris@0: contextHelpChanged(tr("Toggle mono mode for playback time scaling")); Chris@0: } Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::mouseLeftWidget() Chris@0: { Chris@0: contextHelpChanged(""); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::website() Chris@0: { Chris@4: //!!! todo: URL! Chris@4: openHelpUrl(tr("http://code.soundsoftware.ac.uk/projects/tony/")); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::help() Chris@0: { Chris@4: //!!! todo: help URL! Chris@4: openHelpUrl(tr("http://code.soundsoftware.ac.uk/projects/tony/")); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::about() Chris@0: { Chris@0: bool debug = false; Chris@0: QString version = "(unknown version)"; Chris@0: Chris@0: #ifdef BUILD_DEBUG Chris@0: debug = true; Chris@0: #endif Chris@0: version = tr("Release %1").arg(TONY_VERSION); Chris@0: Chris@0: QString aboutText; Chris@0: Chris@0: aboutText += tr("

About Tony

"); Chris@0: aboutText += tr("

Tony is a program for interactive note and pitch analysis and annotation.

"); Chris@0: aboutText += tr("

%1 : %2 configuration

") Chris@0: .arg(version) Chris@0: .arg(debug ? tr("Debug") : tr("Release")); Chris@0: Chris@0: #ifndef BUILD_STATIC Chris@0: aboutText += tr("
Using Qt v%1 © Trolltech AS").arg(QT_VERSION_STR); Chris@0: #else Chris@0: #ifdef QT_SHARED Chris@0: aboutText += tr("
Using Qt v%1 © Trolltech AS").arg(QT_VERSION_STR); Chris@0: #endif Chris@0: #endif Chris@0: Chris@0: #ifdef BUILD_STATIC Chris@0: aboutText += tr("

Statically linked"); Chris@0: #ifndef QT_SHARED Chris@0: aboutText += tr("
With Qt (v%1) © Trolltech AS").arg(QT_VERSION_STR); Chris@0: #endif Chris@0: #ifdef HAVE_JACK Chris@0: #ifdef JACK_VERSION Chris@0: aboutText += tr("
With JACK audio output (v%1) © Paul Davis and Jack O'Quin").arg(JACK_VERSION); Chris@0: #else Chris@0: aboutText += tr("
With JACK audio output © Paul Davis and Jack O'Quin"); Chris@0: #endif Chris@0: #endif Chris@0: #ifdef HAVE_PORTAUDIO Chris@0: aboutText += tr("
With PortAudio audio output © Ross Bencina and Phil Burk"); Chris@0: #endif Chris@0: #ifdef HAVE_OGGZ Chris@0: #ifdef OGGZ_VERSION Chris@0: aboutText += tr("
With Ogg file decoder (oggz v%1, fishsound v%2) © CSIRO Australia").arg(OGGZ_VERSION).arg(FISHSOUND_VERSION); Chris@0: #else Chris@0: aboutText += tr("
With Ogg file decoder © CSIRO Australia"); Chris@0: #endif Chris@0: #endif Chris@0: #ifdef HAVE_MAD Chris@0: #ifdef MAD_VERSION Chris@0: aboutText += tr("
With MAD mp3 decoder (v%1) © Underbit Technologies Inc").arg(MAD_VERSION); Chris@0: #else Chris@0: aboutText += tr("
With MAD mp3 decoder © Underbit Technologies Inc"); Chris@0: #endif Chris@0: #endif Chris@0: #ifdef HAVE_SAMPLERATE Chris@0: #ifdef SAMPLERATE_VERSION Chris@0: aboutText += tr("
With libsamplerate (v%1) © Erik de Castro Lopo").arg(SAMPLERATE_VERSION); Chris@0: #else Chris@0: aboutText += tr("
With libsamplerate © Erik de Castro Lopo"); Chris@0: #endif Chris@0: #endif Chris@0: #ifdef HAVE_SNDFILE Chris@0: #ifdef SNDFILE_VERSION Chris@0: aboutText += tr("
With libsndfile (v%1) © Erik de Castro Lopo").arg(SNDFILE_VERSION); Chris@0: #else Chris@0: aboutText += tr("
With libsndfile © Erik de Castro Lopo"); Chris@0: #endif Chris@0: #endif Chris@0: #ifdef HAVE_FFTW3F Chris@0: #ifdef FFTW3_VERSION Chris@0: aboutText += tr("
With FFTW3 (v%1) © Matteo Frigo and MIT").arg(FFTW3_VERSION); Chris@0: #else Chris@0: aboutText += tr("
With FFTW3 © Matteo Frigo and MIT"); Chris@0: #endif Chris@0: #endif Chris@0: #ifdef HAVE_VAMP Chris@0: aboutText += tr("
With Vamp plugin support (API v%1, host SDK v%2) © Chris Cannam").arg(VAMP_API_VERSION).arg(VAMP_SDK_VERSION); Chris@0: #endif Chris@0: aboutText += tr("
With LADSPA plugin support (API v%1) © Richard Furse, Paul Davis, Stefan Westerfeld").arg(LADSPA_VERSION); Chris@0: aboutText += tr("
With DSSI plugin support (API v%1) © Chris Cannam, Steve Harris, Sean Bolton").arg(DSSI_VERSION); Chris@0: #ifdef HAVE_LIBLO Chris@0: #ifdef LIBLO_VERSION Chris@0: aboutText += tr("
With liblo Lite OSC library (v%1) © Steve Harris").arg(LIBLO_VERSION); Chris@0: #else Chris@0: aboutText += tr("
With liblo Lite OSC library © Steve Harris").arg(LIBLO_VERSION); Chris@0: #endif Chris@0: if (m_oscQueue && m_oscQueue->isOK()) { Chris@0: aboutText += tr("

The OSC URL for this instance is: \"%1\"").arg(m_oscQueue->getOSCURL()); Chris@0: } Chris@0: #endif Chris@0: aboutText += "

"; Chris@0: #endif Chris@0: Chris@0: aboutText += Chris@0: "

Copyright © 2005–2012 Chris Cannam and
" Chris@0: "Queen Mary, University of London.

" Chris@0: "

This program is free software; you can redistribute it and/or
" Chris@0: "modify it under the terms of the GNU General Public License as
" Chris@0: "published by the Free Software Foundation; either version 2 of the
" Chris@0: "License, or (at your option) any later version.
See the file " Chris@0: "COPYING included with this distribution for more information.

"; Chris@0: Chris@0: QMessageBox::about(this, tr("About %1").arg(QApplication::applicationName()), aboutText); Chris@0: } Chris@0: Chris@0: void Chris@0: MainWindow::keyReference() Chris@0: { Chris@0: m_keyReference->show(); Chris@0: } Chris@0: Chris@0: