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