comparison main/MainWindow.cpp @ 1523:f73a4e8c7040

Merge from branch 3.0-integration
author Chris Cannam
date Tue, 10 Jan 2017 16:21:32 +0000
parents f016667b4adb
children 44e09e1996a3
comparison
equal deleted inserted replaced
1522:a0a37ed3c07a 1523:f73a4e8c7040
40 #include "layer/Colour3DPlotLayer.h" 40 #include "layer/Colour3DPlotLayer.h"
41 #include "layer/SliceLayer.h" 41 #include "layer/SliceLayer.h"
42 #include "layer/SliceableLayer.h" 42 #include "layer/SliceableLayer.h"
43 #include "layer/ImageLayer.h" 43 #include "layer/ImageLayer.h"
44 #include "layer/RegionLayer.h" 44 #include "layer/RegionLayer.h"
45 #include "widgets/Fader.h"
46 #include "view/Overview.h" 45 #include "view/Overview.h"
47 #include "widgets/PropertyBox.h" 46 #include "widgets/PropertyBox.h"
48 #include "widgets/PropertyStack.h" 47 #include "widgets/PropertyStack.h"
49 #include "widgets/AudioDial.h" 48 #include "widgets/AudioDial.h"
49 #include "widgets/LevelPanWidget.h"
50 #include "widgets/LevelPanToolButton.h"
50 #include "widgets/IconLoader.h" 51 #include "widgets/IconLoader.h"
51 #include "widgets/LayerTreeDialog.h" 52 #include "widgets/LayerTreeDialog.h"
52 #include "widgets/ListInputDialog.h" 53 #include "widgets/ListInputDialog.h"
53 #include "widgets/SubdividingMenu.h" 54 #include "widgets/SubdividingMenu.h"
54 #include "widgets/NotifyingPushButton.h" 55 #include "widgets/NotifyingPushButton.h"
55 #include "widgets/KeyReference.h" 56 #include "widgets/KeyReference.h"
56 #include "widgets/TransformFinder.h" 57 #include "widgets/TransformFinder.h"
57 #include "widgets/LabelCounterInputDialog.h" 58 #include "widgets/LabelCounterInputDialog.h"
58 #include "widgets/ActivityLog.h" 59 #include "widgets/ActivityLog.h"
59 #include "widgets/UnitConverter.h" 60 #include "widgets/UnitConverter.h"
60 #include "audioio/AudioCallbackPlaySource.h" 61 #include "audio/AudioCallbackPlaySource.h"
61 #include "audioio/AudioCallbackPlayTarget.h" 62 #include "audio/AudioCallbackRecordTarget.h"
62 #include "audioio/AudioTargetFactory.h" 63 #include "audio/PlaySpeedRangeMapper.h"
63 #include "audioio/PlaySpeedRangeMapper.h"
64 #include "data/fileio/DataFileReaderFactory.h" 64 #include "data/fileio/DataFileReaderFactory.h"
65 #include "data/fileio/PlaylistFileReader.h" 65 #include "data/fileio/PlaylistFileReader.h"
66 #include "data/fileio/WavFileWriter.h" 66 #include "data/fileio/WavFileWriter.h"
67 #include "data/fileio/CSVFileWriter.h" 67 #include "data/fileio/CSVFileWriter.h"
68 #include "data/fileio/MIDIFileWriter.h" 68 #include "data/fileio/MIDIFileWriter.h"
69 #include "data/fileio/BZipFileDevice.h" 69 #include "data/fileio/BZipFileDevice.h"
70 #include "data/fileio/FileSource.h" 70 #include "data/fileio/FileSource.h"
71 #include "data/fft/FFTDataServer.h"
72 #include "data/midi/MIDIInput.h" 71 #include "data/midi/MIDIInput.h"
73 #include "base/RecentFiles.h" 72 #include "base/RecentFiles.h"
73 #include "plugin/PluginScan.h"
74 #include "transform/TransformFactory.h" 74 #include "transform/TransformFactory.h"
75 #include "transform/ModelTransformerFactory.h" 75 #include "transform/ModelTransformerFactory.h"
76 #include "base/PlayParameterRepository.h" 76 #include "base/PlayParameterRepository.h"
77 #include "base/XmlExportable.h" 77 #include "base/XmlExportable.h"
78 #include "widgets/CommandHistory.h" 78 #include "widgets/CommandHistory.h"
91 // For version information 91 // For version information
92 #include <vamp/vamp.h> 92 #include <vamp/vamp.h>
93 #include <vamp-hostsdk/PluginBase.h> 93 #include <vamp-hostsdk/PluginBase.h>
94 #include "plugin/api/ladspa.h" 94 #include "plugin/api/ladspa.h"
95 #include "plugin/api/dssi.h" 95 #include "plugin/api/dssi.h"
96
97 #include <bqaudioio/SystemPlaybackTarget.h>
98 #include <bqaudioio/SystemAudioIO.h>
96 99
97 #include <QApplication> 100 #include <QApplication>
98 #include <QMessageBox> 101 #include <QMessageBox>
99 #include <QGridLayout> 102 #include <QGridLayout>
100 #include <QLabel> 103 #include <QLabel>
115 #include <QDateTime> 118 #include <QDateTime>
116 #include <QProcess> 119 #include <QProcess>
117 #include <QCheckBox> 120 #include <QCheckBox>
118 #include <QRegExp> 121 #include <QRegExp>
119 #include <QScrollArea> 122 #include <QScrollArea>
123 #include <QCloseEvent>
120 #include <QDesktopServices> 124 #include <QDesktopServices>
121 #include <QDialogButtonBox> 125 #include <QDialogButtonBox>
122 #include <QFileSystemWatcher> 126 #include <QFileSystemWatcher>
127 #include <QTextEdit>
123 128
124 #include <iostream> 129 #include <iostream>
125 #include <cstdio> 130 #include <cstdio>
126 #include <errno.h> 131 #include <errno.h>
127 132
128 using std::vector; 133 using std::vector;
129 using std::map; 134 using std::map;
130 using std::set; 135 using std::set;
131 136
132 137
133 MainWindow::MainWindow(bool withAudioOutput, bool withOSCSupport) : 138 MainWindow::MainWindow(SoundOptions options, bool withOSCSupport) :
134 MainWindowBase(withAudioOutput, true), 139 MainWindowBase(options),
135 m_overview(0), 140 m_overview(0),
136 m_mainMenusCreated(false), 141 m_mainMenusCreated(false),
137 m_paneMenu(0), 142 m_paneMenu(0),
138 m_layerMenu(0), 143 m_layerMenu(0),
139 m_transformsMenu(0), 144 m_transformsMenu(0),
153 m_rwdAction(0), 158 m_rwdAction(0),
154 m_ffwdAction(0), 159 m_ffwdAction(0),
155 m_ffwdSimilarAction(0), 160 m_ffwdSimilarAction(0),
156 m_ffwdEndAction(0), 161 m_ffwdEndAction(0),
157 m_playAction(0), 162 m_playAction(0),
163 m_recordAction(0),
158 m_playSelectionAction(0), 164 m_playSelectionAction(0),
159 m_playLoopAction(0), 165 m_playLoopAction(0),
160 m_soloModified(false), 166 m_soloModified(false),
161 m_prevSolo(false), 167 m_prevSolo(false),
162 m_playControlsSpacer(0), 168 m_playControlsSpacer(0),
205 211
206 m_mainScroll->setWidget(m_paneStack); 212 m_mainScroll->setWidget(m_paneStack);
207 213
208 m_overview = new Overview(frame); 214 m_overview = new Overview(frame);
209 m_overview->setViewManager(m_viewManager); 215 m_overview->setViewManager(m_viewManager);
210 m_overview->setFixedHeight(40); 216 int overviewHeight = m_viewManager->scalePixelSize(35);
217 if (overviewHeight < 40) overviewHeight = 40;
218 m_overview->setFixedHeight(overviewHeight);
211 #ifndef _WIN32 219 #ifndef _WIN32
212 // For some reason, the contents of the overview never appear if we 220 // For some reason, the contents of the overview never appear if we
213 // make this setting on Windows. I have no inclination at the moment 221 // make this setting on Windows. I have no inclination at the moment
214 // to track down the reason why. 222 // to track down the reason why.
215 m_overview->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); 223 m_overview->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
220 m_panLayer = new WaveformLayer; 228 m_panLayer = new WaveformLayer;
221 m_panLayer->setChannelMode(WaveformLayer::MergeChannels); 229 m_panLayer->setChannelMode(WaveformLayer::MergeChannels);
222 m_panLayer->setAggressiveCacheing(true); 230 m_panLayer->setAggressiveCacheing(true);
223 m_overview->addLayer(m_panLayer); 231 m_overview->addLayer(m_panLayer);
224 232
225 if (m_viewManager->getGlobalDarkBackground()) { 233 coloursChanged(); // sets pan layer colour from preferences
226 m_panLayer->setBaseColour
227 (ColourDatabase::getInstance()->getColourIndex(tr("Bright Green")));
228 } else {
229 m_panLayer->setBaseColour
230 (ColourDatabase::getInstance()->getColourIndex(tr("Green")));
231 }
232
233 m_fader = new Fader(frame, false);
234 connect(m_fader, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget()));
235 connect(m_fader, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget()));
236 234
237 m_playSpeed = new AudioDial(frame); 235 m_playSpeed = new AudioDial(frame);
238 m_playSpeed->setMinimum(0); 236 m_playSpeed->setMinimum(0);
239 m_playSpeed->setMaximum(120); 237 m_playSpeed->setMaximum(120);
240 m_playSpeed->setValue(60); 238 m_playSpeed->setValue(60);
241 m_playSpeed->setFixedWidth(32); 239 m_playSpeed->setFixedWidth(overviewHeight);
242 m_playSpeed->setFixedHeight(32); 240 m_playSpeed->setFixedHeight(overviewHeight);
243 m_playSpeed->setNotchesVisible(true); 241 m_playSpeed->setNotchesVisible(true);
244 m_playSpeed->setPageStep(10); 242 m_playSpeed->setPageStep(10);
245 m_playSpeed->setObjectName(tr("Playback Speed")); 243 m_playSpeed->setObjectName(tr("Playback Speed"));
246 m_playSpeed->setRangeMapper(new PlaySpeedRangeMapper); 244 m_playSpeed->setRangeMapper(new PlaySpeedRangeMapper);
247 m_playSpeed->setDefaultValue(60); 245 m_playSpeed->setDefaultValue(60);
249 connect(m_playSpeed, SIGNAL(valueChanged(int)), 247 connect(m_playSpeed, SIGNAL(valueChanged(int)),
250 this, SLOT(playSpeedChanged(int))); 248 this, SLOT(playSpeedChanged(int)));
251 connect(m_playSpeed, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget())); 249 connect(m_playSpeed, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget()));
252 connect(m_playSpeed, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget())); 250 connect(m_playSpeed, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget()));
253 251
254 IconLoader il; 252 m_mainLevelPan = new LevelPanToolButton(frame);
253 connect(m_mainLevelPan, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget()));
254 connect(m_mainLevelPan, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget()));
255 m_mainLevelPan->setFixedHeight(overviewHeight);
256 m_mainLevelPan->setFixedWidth(overviewHeight);
257 m_mainLevelPan->setImageSize((overviewHeight * 3) / 4);
258 m_mainLevelPan->setBigImageSize(overviewHeight * 3);
255 259
256 m_playControlsSpacer = new QFrame; 260 m_playControlsSpacer = new QFrame;
257 261
258 layout->setSpacing(4); 262 layout->setSpacing(m_viewManager->scalePixelSize(4));
259 layout->addWidget(m_mainScroll, 0, 0, 1, 5); 263 layout->addWidget(m_mainScroll, 0, 0, 1, 4);
260 layout->addWidget(m_overview, 1, 1); 264 layout->addWidget(m_overview, 1, 0);
265 layout->addWidget(m_playSpeed, 1, 1);
261 layout->addWidget(m_playControlsSpacer, 1, 2); 266 layout->addWidget(m_playControlsSpacer, 1, 2);
262 layout->addWidget(m_playSpeed, 1, 3); 267 layout->addWidget(m_mainLevelPan, 1, 3);
263 layout->addWidget(m_fader, 1, 4);
264 268
265 m_playControlsWidth = 269 m_playControlsWidth =
266 m_fader->width() + m_playSpeed->width() + layout->spacing() * 2; 270 m_mainLevelPan->width() + m_playSpeed->width() + layout->spacing() * 2;
267
268 layout->setColumnMinimumWidth(0, 14);
269 layout->setColumnStretch(0, 0);
270 271
271 m_paneStack->setPropertyStackMinWidth(m_playControlsWidth 272 m_paneStack->setPropertyStackMinWidth(m_playControlsWidth
272 + 2 + layout->spacing()); 273 + 2 + layout->spacing());
273 m_playControlsSpacer->setFixedSize(QSize(2, 2)); 274 m_playControlsSpacer->setFixedSize(QSize(2, 2));
274 275
275 layout->setColumnStretch(1, 10); 276 layout->setColumnStretch(0, 10);
276 277
277 connect(m_paneStack, SIGNAL(propertyStacksResized(int)), 278 connect(m_paneStack, SIGNAL(propertyStacksResized(int)),
278 this, SLOT(propertyStacksResized(int))); 279 this, SLOT(propertyStacksResized(int)));
279 280
280 frame->setLayout(layout); 281 frame->setLayout(layout);
282
283 #ifdef Q_OS_MAC
284 // Mac doesn't align menu labels when icons are shown: result is messy
285 QApplication::setAttribute(Qt::AA_DontShowIconsInMenus);
286 setIconsVisibleInMenus(false);
287 #endif
281 288
282 setupMenus(); 289 setupMenus();
283 setupToolbars(); 290 setupToolbars();
284 setupHelpMenu(); 291 setupHelpMenu();
285 292
296 connect(CommandHistory::getInstance(), SIGNAL(activity(QString)), 303 connect(CommandHistory::getInstance(), SIGNAL(activity(QString)),
297 m_activityLog, SLOT(activityHappened(QString))); 304 m_activityLog, SLOT(activityHappened(QString)));
298 connect(this, SIGNAL(activity(QString)), 305 connect(this, SIGNAL(activity(QString)),
299 m_activityLog, SLOT(activityHappened(QString))); 306 m_activityLog, SLOT(activityHappened(QString)));
300 connect(this, SIGNAL(replacedDocument()), this, SLOT(documentReplaced())); 307 connect(this, SIGNAL(replacedDocument()), this, SLOT(documentReplaced()));
308
301 m_activityLog->hide(); 309 m_activityLog->hide();
302 310
303 m_unitConverter->hide(); 311 m_unitConverter->hide();
312
313 setAudioRecordMode(RecordCreateAdditionalModel);
304 314
305 newSession(); 315 newSession();
306 316
307 connect(m_midiInput, SIGNAL(eventsAvailable()), 317 connect(m_midiInput, SIGNAL(eventsAvailable()),
308 this, SLOT(midiEventsAvailable())); 318 this, SLOT(midiEventsAvailable()));
322 this, SLOT(newerVersionAvailable(QString))); 332 this, SLOT(newerVersionAvailable(QString)));
323 } else { 333 } else {
324 m_surveyer = 0; 334 m_surveyer = 0;
325 m_versionTester = 0; 335 m_versionTester = 0;
326 } 336 }
337
338 QTimer::singleShot(500, this, SLOT(betaReleaseWarning()));
339
340 QString warning = PluginScan::getInstance()->getStartupFailureReport();
341 if (warning != "") {
342 QTimer::singleShot(500, this, SLOT(pluginPopulationWarning()));
343 }
327 } 344 }
328 345
329 MainWindow::~MainWindow() 346 MainWindow::~MainWindow()
330 { 347 {
331 // SVDEBUG << "MainWindow::~MainWindow" << endl; 348 // SVDEBUG << "MainWindow::~MainWindow" << endl;
352 // workaround, to remove the appmenu-qt5 package, but that is 369 // workaround, to remove the appmenu-qt5 package, but that is
353 // awkward and the problem is so severe that it merits disabling 370 // awkward and the problem is so severe that it merits disabling
354 // the system menubar integration altogether. Like this: 371 // the system menubar integration altogether. Like this:
355 menuBar()->setNativeMenuBar(false); // fix #1039 372 menuBar()->setNativeMenuBar(false); // fix #1039
356 #endif 373 #endif
357 374
358 m_rightButtonMenu = new QMenu(); 375 m_rightButtonMenu = new QMenu();
359 376
360 // No -- we don't want tear-off enabled on the right-button 377 // We don't want tear-off enabled on the right-button menu.
361 // menu. If it is enabled, then simply right-clicking and 378 // If it is enabled, then simply right-clicking and releasing
362 // releasing will pop up the menu, activate the tear-off, and 379 // will pop up the menu, activate the tear-off, and leave the
363 // leave the torn-off menu window in front of the main window. 380 // torn-off menu window in front of the main window. That
364 // That isn't desirable. I'm not sure it ever would be, in a 381 // isn't desirable.
365 // context menu -- perhaps technically a Qt bug? 382 m_rightButtonMenu->setTearOffEnabled(false);
366 // m_rightButtonMenu->setTearOffEnabled(true);
367 } 383 }
368 384
369 if (m_rightButtonTransformsMenu) { 385 if (m_rightButtonTransformsMenu) {
370 m_rightButtonTransformsMenu->clear(); 386 m_rightButtonTransformsMenu->clear();
371 } else { 387 } else {
457 m_keyReference->setCategory(tr("File and Session Management")); 473 m_keyReference->setCategory(tr("File and Session Management"));
458 474
459 IconLoader il; 475 IconLoader il;
460 476
461 QIcon icon = il.load("filenew"); 477 QIcon icon = il.load("filenew");
462 icon.addPixmap(il.loadPixmap("filenew-22"));
463 QAction *action = new QAction(icon, tr("&New Session"), this); 478 QAction *action = new QAction(icon, tr("&New Session"), this);
464 action->setShortcut(tr("Ctrl+N")); 479 action->setShortcut(tr("Ctrl+N"));
465 action->setStatusTip(tr("Abandon the current %1 session and start a new one").arg(QApplication::applicationName())); 480 action->setStatusTip(tr("Abandon the current %1 session and start a new one").arg(QApplication::applicationName()));
466 connect(action, SIGNAL(triggered()), this, SLOT(newSession())); 481 connect(action, SIGNAL(triggered()), this, SLOT(newSession()));
467 m_keyReference->registerShortcut(action); 482 m_keyReference->registerShortcut(action);
468 menu->addAction(action); 483 menu->addAction(action);
469 toolbar->addAction(action); 484 toolbar->addAction(action);
470 485
471 icon = il.load("fileopen"); 486 icon = il.load("fileopen");
472 icon.addPixmap(il.loadPixmap("fileopen-22"));
473 action = new QAction(icon, tr("&Open..."), this); 487 action = new QAction(icon, tr("&Open..."), this);
474 action->setShortcut(tr("Ctrl+O")); 488 action->setShortcut(tr("Ctrl+O"));
475 action->setStatusTip(tr("Open a session file, audio file, or layer")); 489 action->setStatusTip(tr("Open a session file, audio file, or layer"));
476 connect(action, SIGNAL(triggered()), this, SLOT(openSomething())); 490 connect(action, SIGNAL(triggered()), this, SLOT(openSomething()));
477 m_keyReference->registerShortcut(action); 491 m_keyReference->registerShortcut(action);
508 this, SLOT(setupRecentFilesMenu())); 522 this, SLOT(setupRecentFilesMenu()));
509 523
510 menu->addSeparator(); 524 menu->addSeparator();
511 525
512 icon = il.load("filesave"); 526 icon = il.load("filesave");
513 icon.addPixmap(il.loadPixmap("filesave-22"));
514 action = new QAction(icon, tr("&Save Session"), this); 527 action = new QAction(icon, tr("&Save Session"), this);
515 action->setShortcut(tr("Ctrl+S")); 528 action->setShortcut(tr("Ctrl+S"));
516 action->setStatusTip(tr("Save the current session into a %1 session file").arg(QApplication::applicationName())); 529 action->setStatusTip(tr("Save the current session into a %1 session file").arg(QApplication::applicationName()));
517 connect(action, SIGNAL(triggered()), this, SLOT(saveSession())); 530 connect(action, SIGNAL(triggered()), this, SLOT(saveSession()));
518 connect(this, SIGNAL(canSave(bool)), action, SLOT(setEnabled(bool))); 531 connect(this, SIGNAL(canSave(bool)), action, SLOT(setEnabled(bool)));
519 m_keyReference->registerShortcut(action); 532 m_keyReference->registerShortcut(action);
520 menu->addAction(action); 533 menu->addAction(action);
521 toolbar->addAction(action); 534 toolbar->addAction(action);
522 535
523 icon = il.load("filesaveas"); 536 icon = il.load("filesaveas");
524 icon.addPixmap(il.loadPixmap("filesaveas-22"));
525 action = new QAction(icon, tr("Save Session &As..."), this); 537 action = new QAction(icon, tr("Save Session &As..."), this);
526 action->setShortcut(tr("Ctrl+Shift+S")); 538 action->setShortcut(tr("Ctrl+Shift+S"));
527 action->setStatusTip(tr("Save the current session into a new %1 session file").arg(QApplication::applicationName())); 539 action->setStatusTip(tr("Save the current session into a new %1 session file").arg(QApplication::applicationName()));
528 connect(action, SIGNAL(triggered()), this, SLOT(saveSessionAs())); 540 connect(action, SIGNAL(triggered()), this, SLOT(saveSessionAs()));
529 menu->addAction(action); 541 menu->addAction(action);
581 593
582 action = new QAction(tr("Export Image File..."), this); 594 action = new QAction(tr("Export Image File..."), this);
583 action->setStatusTip(tr("Export a single pane to an image file")); 595 action->setStatusTip(tr("Export a single pane to an image file"));
584 connect(action, SIGNAL(triggered()), this, SLOT(exportImage())); 596 connect(action, SIGNAL(triggered()), this, SLOT(exportImage()));
585 connect(this, SIGNAL(canExportImage(bool)), action, SLOT(setEnabled(bool))); 597 connect(this, SIGNAL(canExportImage(bool)), action, SLOT(setEnabled(bool)));
598 menu->addAction(action);
599
600 action = new QAction(tr("Export SVG File..."), this);
601 action->setStatusTip(tr("Export a single pane to a scalable SVG image file"));
602 connect(action, SIGNAL(triggered()), this, SLOT(exportSVG()));
603 connect(this, SIGNAL(canExportImage(bool)), action, SLOT(setEnabled(bool)));
604 menu->addAction(action);
605
606 menu->addSeparator();
607
608 action = new QAction(tr("Browse Recorded Audio Folder"), this);
609 action->setStatusTip(tr("Open the Recorded Audio folder in the system file browser"));
610 connect(action, SIGNAL(triggered()), this, SLOT(browseRecordedAudio()));
586 menu->addAction(action); 611 menu->addAction(action);
587 612
588 menu->addSeparator(); 613 menu->addSeparator();
589 614
590 QString templatesMenuLabel = tr("Apply Session Template"); 615 QString templatesMenuLabel = tr("Apply Session Template");
825 action = new QAction(tr("Renumber Selected Instants"), this); 850 action = new QAction(tr("Renumber Selected Instants"), this);
826 action->setStatusTip(tr("Renumber the selected instants using the current labelling scheme")); 851 action->setStatusTip(tr("Renumber the selected instants using the current labelling scheme"));
827 connect(action, SIGNAL(triggered()), this, SLOT(renumberInstants())); 852 connect(action, SIGNAL(triggered()), this, SLOT(renumberInstants()));
828 connect(this, SIGNAL(canRenumberInstants(bool)), action, SLOT(setEnabled(bool))); 853 connect(this, SIGNAL(canRenumberInstants(bool)), action, SLOT(setEnabled(bool)));
829 // m_keyReference->registerShortcut(action); 854 // m_keyReference->registerShortcut(action);
855 menu->addAction(action);
856
857 menu->addSeparator();
858
859 action = new QAction(tr("Subdivide Selected Instants..."), this);
860 action->setStatusTip(tr("Add new instants at regular intervals between the selected instants"));
861 connect(action, SIGNAL(triggered()), this, SLOT(subdivideInstants()));
862 connect(this, SIGNAL(canSubdivideInstants(bool)), action, SLOT(setEnabled(bool)));
863 menu->addAction(action);
864
865 action = new QAction(tr("Winnow Selected Instants..."), this);
866 action->setStatusTip(tr("Remove subdivisions, leaving only every Nth instant"));
867 connect(action, SIGNAL(triggered()), this, SLOT(winnowInstants()));
868 connect(this, SIGNAL(canWinnowInstants(bool)), action, SLOT(setEnabled(bool)));
830 menu->addAction(action); 869 menu->addAction(action);
831 } 870 }
832 871
833 void 872 void
834 MainWindow::setupViewMenu() 873 MainWindow::setupViewMenu()
1039 connect(action, SIGNAL(triggered()), this, SLOT(showUnitConverter())); 1078 connect(action, SIGNAL(triggered()), this, SLOT(showUnitConverter()));
1040 menu->addAction(action); 1079 menu->addAction(action);
1041 1080
1042 menu->addSeparator(); 1081 menu->addSeparator();
1043 1082
1083 #ifndef Q_OS_MAC
1084 // Only on non-Mac platforms -- on the Mac this interacts very
1085 // badly with the "native" full-screen mode
1044 action = new QAction(tr("Go Full-Screen"), this); 1086 action = new QAction(tr("Go Full-Screen"), this);
1045 action->setShortcut(tr("F11")); 1087 action->setShortcut(tr("F11"));
1046 action->setStatusTip(tr("Expand the pane area to the whole screen")); 1088 action->setStatusTip(tr("Expand the pane area to the whole screen"));
1047 connect(action, SIGNAL(triggered()), this, SLOT(goFullScreen())); 1089 connect(action, SIGNAL(triggered()), this, SLOT(goFullScreen()));
1048 m_keyReference->registerShortcut(action); 1090 m_keyReference->registerShortcut(action);
1049 menu->addAction(action); 1091 menu->addAction(action);
1092 #endif
1050 } 1093 }
1051 1094
1052 void 1095 void
1053 MainWindow::setupPaneAndLayerMenus() 1096 MainWindow::setupPaneAndLayerMenus()
1054 { 1097 {
1164 bool mono = true; 1207 bool mono = true;
1165 1208
1166 // Avoid warnings/errors with -Wextra because we aren't explicitly 1209 // Avoid warnings/errors with -Wextra because we aren't explicitly
1167 // handling all layer types (-Wall is OK with this because of the 1210 // handling all layer types (-Wall is OK with this because of the
1168 // default but the stricter level insists) 1211 // default but the stricter level insists)
1212 #ifdef __GNUC__
1169 #pragma GCC diagnostic ignored "-Wswitch-enum" 1213 #pragma GCC diagnostic ignored "-Wswitch-enum"
1214 #endif
1170 1215
1171 switch (type) { 1216 switch (type) {
1172 1217
1173 case LayerFactory::Waveform: 1218 case LayerFactory::Waveform:
1174 icon = il.load("waveform"); 1219 icon = il.load("waveform");
1478 } 1523 }
1479 1524
1480 TransformFactory *factory = TransformFactory::getInstance(); 1525 TransformFactory *factory = TransformFactory::getInstance();
1481 1526
1482 TransformList transforms = factory->getAllTransformDescriptions(); 1527 TransformList transforms = factory->getAllTransformDescriptions();
1528
1529 if (factory->getStartupFailureReport() != "") {
1530 pluginPopulationWarning();
1531 }
1532
1483 vector<TransformDescription::Type> types = factory->getAllTransformTypes(); 1533 vector<TransformDescription::Type> types = factory->getAllTransformTypes();
1484 1534
1485 map<TransformDescription::Type, map<QString, SubdividingMenu *> > categoryMenus; 1535 map<TransformDescription::Type, map<QString, SubdividingMenu *> > categoryMenus;
1486 map<TransformDescription::Type, map<QString, SubdividingMenu *> > makerMenus; 1536 map<TransformDescription::Type, map<QString, SubdividingMenu *> > makerMenus;
1487 1537
1736 action = new QAction(tr("%1 on the &Web").arg(name), this); 1786 action = new QAction(tr("%1 on the &Web").arg(name), this);
1737 action->setStatusTip(tr("Open the %1 website").arg(name)); 1787 action->setStatusTip(tr("Open the %1 website").arg(name));
1738 connect(action, SIGNAL(triggered()), this, SLOT(website())); 1788 connect(action, SIGNAL(triggered()), this, SLOT(website()));
1739 menu->addAction(action); 1789 menu->addAction(action);
1740 1790
1791 action = new QAction(tr("What's &New?").arg(name), this);
1792 action->setStatusTip(tr("Show changes in this release of %1").arg(name));
1793 connect(action, SIGNAL(triggered()), this, SLOT(whatsNew()));
1794 menu->addAction(action);
1795
1741 action = new QAction(tr("&About %1").arg(name), this); 1796 action = new QAction(tr("&About %1").arg(name), this);
1742 action->setStatusTip(tr("Show information about %1").arg(name)); 1797 action->setStatusTip(tr("Show information about %1").arg(name));
1743 connect(action, SIGNAL(triggered()), this, SLOT(about())); 1798 connect(action, SIGNAL(triggered()), this, SLOT(about()));
1744 menu->addAction(action); 1799 menu->addAction(action);
1745 } 1800 }
1748 MainWindow::setupRecentFilesMenu() 1803 MainWindow::setupRecentFilesMenu()
1749 { 1804 {
1750 m_recentFilesMenu->clear(); 1805 m_recentFilesMenu->clear();
1751 vector<QString> files = m_recentFiles.getRecent(); 1806 vector<QString> files = m_recentFiles.getRecent();
1752 for (size_t i = 0; i < files.size(); ++i) { 1807 for (size_t i = 0; i < files.size(); ++i) {
1753 QAction *action = new QAction(files[i], this); 1808 /* F. Nicol patch 13 Aug. 2016 */
1754 connect(action, SIGNAL(triggered()), this, SLOT(openRecentFile())); 1809 const QString& path = files[i];
1810 QAction *action = new QAction(path, this);
1811 connect(action, &QAction::triggered, [this, path] { openRecentFile(path);});
1812 /* end of patch */
1755 if (i == 0) { 1813 if (i == 0) {
1756 action->setShortcut(tr("Ctrl+R")); 1814 action->setShortcut(tr("Ctrl+R"));
1757 m_keyReference->registerShortcut 1815 m_keyReference->registerShortcut
1758 (tr("Re-open"), 1816 (tr("Re-open"),
1759 action->shortcut().toString(), 1817 action->shortcut().toString(),
1983 m_ffwdEndAction->setShortcut(tr("End")); 2041 m_ffwdEndAction->setShortcut(tr("End"));
1984 m_ffwdEndAction->setStatusTip(tr("Fast-forward to the end")); 2042 m_ffwdEndAction->setStatusTip(tr("Fast-forward to the end"));
1985 connect(m_ffwdEndAction, SIGNAL(triggered()), this, SLOT(ffwdEnd())); 2043 connect(m_ffwdEndAction, SIGNAL(triggered()), this, SLOT(ffwdEnd()));
1986 connect(this, SIGNAL(canPlay(bool)), m_ffwdEndAction, SLOT(setEnabled(bool))); 2044 connect(this, SIGNAL(canPlay(bool)), m_ffwdEndAction, SLOT(setEnabled(bool)));
1987 2045
2046 m_recordAction = toolbar->addAction(il.load("record"),
2047 tr("Record"));
2048 m_recordAction->setCheckable(true);
2049 m_recordAction->setShortcut(tr("Ctrl+Space"));
2050 m_recordAction->setStatusTip(tr("Record a new audio file"));
2051 connect(m_recordAction, SIGNAL(triggered()), this, SLOT(record()));
2052 connect(m_recordTarget, SIGNAL(recordStatusChanged(bool)),
2053 m_recordAction, SLOT(setChecked(bool)));
2054 connect(this, SIGNAL(canRecord(bool)),
2055 m_recordAction, SLOT(setEnabled(bool)));
2056
1988 toolbar = addToolBar(tr("Play Mode Toolbar")); 2057 toolbar = addToolBar(tr("Play Mode Toolbar"));
1989 2058
1990 m_playSelectionAction = toolbar->addAction(il.load("playselection"), 2059 m_playSelectionAction = toolbar->addAction(il.load("playselection"),
1991 tr("Constrain Playback to Selection")); 2060 tr("Constrain Playback to Selection"));
1992 m_playSelectionAction->setCheckable(true); 2061 m_playSelectionAction->setCheckable(true);
2033 connect(alAction, SIGNAL(triggered()), this, SLOT(alignToggled())); 2102 connect(alAction, SIGNAL(triggered()), this, SLOT(alignToggled()));
2034 connect(this, SIGNAL(canAlign(bool)), alAction, SLOT(setEnabled(bool))); 2103 connect(this, SIGNAL(canAlign(bool)), alAction, SLOT(setEnabled(bool)));
2035 } 2104 }
2036 2105
2037 m_keyReference->registerShortcut(m_playAction); 2106 m_keyReference->registerShortcut(m_playAction);
2107 m_keyReference->registerShortcut(m_recordAction);
2038 m_keyReference->registerShortcut(m_playSelectionAction); 2108 m_keyReference->registerShortcut(m_playSelectionAction);
2039 m_keyReference->registerShortcut(m_playLoopAction); 2109 m_keyReference->registerShortcut(m_playLoopAction);
2040 m_keyReference->registerShortcut(m_soloAction); 2110 m_keyReference->registerShortcut(m_soloAction);
2041 if (alAction) m_keyReference->registerShortcut(alAction); 2111 if (alAction) m_keyReference->registerShortcut(alAction);
2042 m_keyReference->registerShortcut(m_rwdAction); 2112 m_keyReference->registerShortcut(m_rwdAction);
2045 m_keyReference->registerShortcut(m_ffwdSimilarAction); 2115 m_keyReference->registerShortcut(m_ffwdSimilarAction);
2046 m_keyReference->registerShortcut(m_rwdStartAction); 2116 m_keyReference->registerShortcut(m_rwdStartAction);
2047 m_keyReference->registerShortcut(m_ffwdEndAction); 2117 m_keyReference->registerShortcut(m_ffwdEndAction);
2048 2118
2049 menu->addAction(m_playAction); 2119 menu->addAction(m_playAction);
2120 menu->addAction(m_recordAction);
2050 menu->addAction(m_playSelectionAction); 2121 menu->addAction(m_playSelectionAction);
2051 menu->addAction(m_playLoopAction); 2122 menu->addAction(m_playLoopAction);
2052 menu->addAction(m_soloAction); 2123 menu->addAction(m_soloAction);
2053 if (alAction) menu->addAction(alAction); 2124 if (alAction) menu->addAction(alAction);
2054 menu->addSeparator(); 2125 menu->addSeparator();
2059 menu->addAction(m_ffwdSimilarAction); 2130 menu->addAction(m_ffwdSimilarAction);
2060 menu->addSeparator(); 2131 menu->addSeparator();
2061 menu->addAction(m_rwdStartAction); 2132 menu->addAction(m_rwdStartAction);
2062 menu->addAction(m_ffwdEndAction); 2133 menu->addAction(m_ffwdEndAction);
2063 menu->addSeparator(); 2134 menu->addSeparator();
2135 menu->addAction(m_recordAction);
2136 menu->addSeparator();
2064 2137
2065 m_rightButtonPlaybackMenu->addAction(m_playAction); 2138 m_rightButtonPlaybackMenu->addAction(m_playAction);
2139 m_rightButtonPlaybackMenu->addAction(m_recordAction);
2066 m_rightButtonPlaybackMenu->addAction(m_playSelectionAction); 2140 m_rightButtonPlaybackMenu->addAction(m_playSelectionAction);
2067 m_rightButtonPlaybackMenu->addAction(m_playLoopAction); 2141 m_rightButtonPlaybackMenu->addAction(m_playLoopAction);
2068 m_rightButtonPlaybackMenu->addAction(m_soloAction); 2142 m_rightButtonPlaybackMenu->addAction(m_soloAction);
2069 if (alAction) m_rightButtonPlaybackMenu->addAction(alAction); 2143 if (alAction) m_rightButtonPlaybackMenu->addAction(alAction);
2070 m_rightButtonPlaybackMenu->addSeparator(); 2144 m_rightButtonPlaybackMenu->addSeparator();
2071 m_rightButtonPlaybackMenu->addAction(m_rwdAction); 2145 m_rightButtonPlaybackMenu->addAction(m_rwdAction);
2072 m_rightButtonPlaybackMenu->addAction(m_ffwdAction); 2146 m_rightButtonPlaybackMenu->addAction(m_ffwdAction);
2073 m_rightButtonPlaybackMenu->addSeparator(); 2147 m_rightButtonPlaybackMenu->addSeparator();
2074 m_rightButtonPlaybackMenu->addAction(m_rwdStartAction); 2148 m_rightButtonPlaybackMenu->addAction(m_rwdStartAction);
2075 m_rightButtonPlaybackMenu->addAction(m_ffwdEndAction); 2149 m_rightButtonPlaybackMenu->addAction(m_ffwdEndAction);
2150 m_rightButtonPlaybackMenu->addSeparator();
2151 m_rightButtonPlaybackMenu->addAction(m_recordAction);
2076 m_rightButtonPlaybackMenu->addSeparator(); 2152 m_rightButtonPlaybackMenu->addSeparator();
2077 2153
2078 QAction *fastAction = menu->addAction(tr("Speed Up")); 2154 QAction *fastAction = menu->addAction(tr("Speed Up"));
2079 fastAction->setShortcut(tr("Ctrl+PgUp")); 2155 fastAction->setShortcut(tr("Ctrl+PgUp"));
2080 fastAction->setStatusTip(tr("Time-stretch playback to speed it up without changing pitch")); 2156 fastAction->setStatusTip(tr("Time-stretch playback to speed it up without changing pitch"));
2278 (currentPane != 0); 2354 (currentPane != 0);
2279 bool haveCurrentLayer = 2355 bool haveCurrentLayer =
2280 (haveCurrentPane && 2356 (haveCurrentPane &&
2281 (currentLayer != 0)); 2357 (currentLayer != 0));
2282 bool havePlayTarget = 2358 bool havePlayTarget =
2283 (m_playTarget != 0); 2359 (m_playTarget != 0 || m_audioIO != 0);
2284 bool haveSelection = 2360 bool haveSelection =
2285 (m_viewManager && 2361 (m_viewManager &&
2286 !m_viewManager->getSelections().empty()); 2362 !m_viewManager->getSelections().empty());
2287 bool haveCurrentEditableLayer = 2363 bool haveCurrentEditableLayer =
2288 (haveCurrentLayer && 2364 (haveCurrentLayer &&
2342 return; 2418 return;
2343 } 2419 }
2344 2420
2345 QString description; 2421 QString description;
2346 2422
2423 //!!!???
2424
2347 sv_samplerate_t ssr = getMainModel()->getSampleRate(); 2425 sv_samplerate_t ssr = getMainModel()->getSampleRate();
2348 sv_samplerate_t tsr = ssr; 2426 sv_samplerate_t tsr = ssr;
2349 if (m_playSource) tsr = m_playSource->getTargetSampleRate(); 2427 if (m_playSource) tsr = m_playSource->getDeviceSampleRate();
2350 2428
2351 if (ssr != tsr) { 2429 if (ssr != tsr) {
2352 description = tr("%1Hz (resampling to %2Hz)").arg(ssr).arg(tsr); 2430 description = tr("%1Hz (resampling to %2Hz)").arg(ssr).arg(tsr);
2353 } else { 2431 } else {
2354 description = QString("%1Hz").arg(ssr); 2432 description = QString("%1Hz").arg(ssr);
2796 { 2874 {
2797 Pane *pane = m_paneStack->getCurrentPane(); 2875 Pane *pane = m_paneStack->getCurrentPane();
2798 if (!pane) return; 2876 if (!pane) return;
2799 2877
2800 QString path = getSaveFileName(FileFinder::ImageFile); 2878 QString path = getSaveFileName(FileFinder::ImageFile);
2801
2802 if (path == "") return; 2879 if (path == "") return;
2803
2804 if (QFileInfo(path).suffix() == "") path += ".png"; 2880 if (QFileInfo(path).suffix() == "") path += ".png";
2805 2881
2806 bool haveSelection = m_viewManager && !m_viewManager->getSelections().empty(); 2882 bool haveSelection = m_viewManager && !m_viewManager->getSelections().empty();
2807 2883
2808 QSize total, visible, selected; 2884 QSize total, visible, selected;
2809 total = pane->getImageSize(); 2885 total = pane->getRenderedImageSize();
2810 visible = pane->getImageSize(pane->getFirstVisibleFrame(), 2886 visible = pane->getRenderedPartImageSize(pane->getFirstVisibleFrame(),
2811 pane->getLastVisibleFrame()); 2887 pane->getLastVisibleFrame());
2812 2888
2813 sv_frame_t sf0 = 0, sf1 = 0; 2889 sv_frame_t sf0 = 0, sf1 = 0;
2814 2890
2815 if (haveSelection) { 2891 if (haveSelection) {
2816 MultiSelection::SelectionList selections = m_viewManager->getSelections(); 2892 MultiSelection::SelectionList selections = m_viewManager->getSelections();
2817 sf0 = selections.begin()->getStartFrame(); 2893 sf0 = selections.begin()->getStartFrame();
2818 MultiSelection::SelectionList::iterator e = selections.end(); 2894 MultiSelection::SelectionList::iterator e = selections.end();
2819 --e; 2895 --e;
2820 sf1 = e->getEndFrame(); 2896 sf1 = e->getEndFrame();
2821 selected = pane->getImageSize(sf0, sf1); 2897 selected = pane->getRenderedPartImageSize(sf0, sf1);
2822 } 2898 }
2823 2899
2824 QStringList items; 2900 QStringList items;
2825 items << tr("Export the whole pane (%1x%2 pixels)") 2901 items << tr("Export the whole pane (%1x%2 pixels)")
2826 .arg(total.width()).arg(total.height()); 2902 .arg(total.width()).arg(total.height());
2845 items, deflt); 2921 items, deflt);
2846 2922
2847 if (!haveSelection) { 2923 if (!haveSelection) {
2848 lid->setItemAvailability(2, false); 2924 lid->setItemAvailability(2, false);
2849 } 2925 }
2850 if (total.width() > 32767) { // appears to be the limit of a QImage 2926 if (total.width() > 32767) { // appears to be limit of a QImage
2851 lid->setItemAvailability(0, false); 2927 lid->setItemAvailability(0, false);
2852 lid->setFootnote(tr("Note: the whole pane is too wide to be exported as a single image.")); 2928 lid->setFootnote(tr("Note: the whole pane is too wide to be exported as a single image."));
2853 } 2929 }
2854 2930
2855 bool ok = lid->exec(); 2931 bool ok = lid->exec();
2859 if (!ok || item.isEmpty()) return; 2935 if (!ok || item.isEmpty()) return;
2860 2936
2861 settings.setValue("lastimageexportregion", deflt); 2937 settings.setValue("lastimageexportregion", deflt);
2862 2938
2863 QImage *image = 0; 2939 QImage *image = 0;
2864 2940
2865 if (item == items[0]) { 2941 if (item == items[0]) {
2866 image = pane->toNewImage(); 2942 image = pane->renderToNewImage();
2867 } else if (item == items[1]) { 2943 } else if (item == items[1]) {
2868 image = pane->toNewImage(pane->getFirstVisibleFrame(), 2944 image = pane->renderPartToNewImage(pane->getFirstVisibleFrame(),
2869 pane->getLastVisibleFrame()); 2945 pane->getLastVisibleFrame());
2870 } else if (haveSelection) { 2946 } else if (haveSelection) {
2871 image = pane->toNewImage(sf0, sf1); 2947 image = pane->renderPartToNewImage(sf0, sf1);
2872 } 2948 }
2873 2949
2874 if (!image) return; 2950 if (!image) return;
2875 2951
2876 if (!image->save(path, "PNG")) { 2952 if (!image->save(path, "PNG")) {
2877 QMessageBox::critical(this, tr("Failed to save image file"), 2953 QMessageBox::critical(this, tr("Failed to save image file"),
2878 tr("Failed to save image file %1").arg(path)); 2954 tr("Failed to save image file %1").arg(path));
2879 } 2955 }
2880 2956
2881 delete image; 2957 delete image;
2958 }
2959
2960 void
2961 MainWindow::exportSVG()
2962 {
2963 Pane *pane = m_paneStack->getCurrentPane();
2964 if (!pane) return;
2965
2966 QString path = getSaveFileName(FileFinder::SVGFile);
2967 if (path == "") return;
2968 if (QFileInfo(path).suffix() == "") path += ".svg";
2969
2970 bool haveSelection = m_viewManager && !m_viewManager->getSelections().empty();
2971
2972 sv_frame_t sf0 = 0, sf1 = 0;
2973
2974 if (haveSelection) {
2975 MultiSelection::SelectionList selections = m_viewManager->getSelections();
2976 sf0 = selections.begin()->getStartFrame();
2977 MultiSelection::SelectionList::iterator e = selections.end();
2978 --e;
2979 sf1 = e->getEndFrame();
2980 }
2981
2982 QStringList items;
2983 items << tr("Export the whole pane");
2984 items << tr("Export the visible area only");
2985 items << tr("Export the selection extent");
2986
2987 QSettings settings;
2988 settings.beginGroup("MainWindow");
2989 int deflt = settings.value("lastsvgexportregion", 0).toInt();
2990 if (deflt == 2 && !haveSelection) deflt = 1;
2991
2992 ListInputDialog *lid = new ListInputDialog
2993 (this, tr("Select region to export"),
2994 tr("Which region of the current pane do you want to export as a scalable SVG image?"),
2995 items, deflt);
2996
2997 if (!haveSelection) {
2998 lid->setItemAvailability(2, false);
2999 }
3000
3001 bool ok = lid->exec();
3002 QString item = lid->getCurrentString();
3003 delete lid;
3004
3005 if (!ok || item.isEmpty()) return;
3006
3007 settings.setValue("lastsvgexportregion", deflt);
3008
3009 bool result = false;
3010
3011 if (item == items[0]) {
3012 result = pane->renderToSvgFile(path );
3013 } else if (item == items[1]) {
3014 result = pane->renderPartToSvgFile(path,
3015 pane->getFirstVisibleFrame(),
3016 pane->getLastVisibleFrame());
3017 } else if (haveSelection) {
3018 result = pane->renderPartToSvgFile(path, sf0, sf1);
3019 }
3020
3021 if (!result) {
3022 QMessageBox::critical(this, tr("Failed to save SVG file"),
3023 tr("Failed to save SVG file %1").arg(path));
3024 }
3025 }
3026
3027 void
3028 MainWindow::browseRecordedAudio()
3029 {
3030 if (!m_recordTarget) return;
3031
3032 QString path = m_recordTarget->getRecordContainerFolder();
3033 if (path == "") path = m_recordTarget->getRecordFolder();
3034 if (path == "") return;
3035
3036 openLocalFolder(path);
2882 } 3037 }
2883 3038
2884 void 3039 void
2885 MainWindow::newSession() 3040 MainWindow::newSession()
2886 { 3041 {
3028 tr("<b>Audio required</b><p>Unable to load layer data from \"%1\" without an audio file.<br>Please load at least one audio file before importing annotations.").arg(text)); 3183 tr("<b>Audio required</b><p>Unable to load layer data from \"%1\" without an audio file.<br>Please load at least one audio file before importing annotations.").arg(text));
3029 } 3184 }
3030 } 3185 }
3031 3186
3032 void 3187 void
3033 MainWindow::openRecentFile() 3188 MainWindow::openRecentFile(const QString& path)
3034 { 3189 {
3190 /* F. Nicol patch 13 Aug. 2016 */
3191 #if 0
3035 QObject *obj = sender(); 3192 QObject *obj = sender();
3036 QAction *action = dynamic_cast<QAction *>(obj); 3193 QAction *action = dynamic_cast<QAction *>(obj);
3037 3194
3038 if (!action) { 3195 if (!action) {
3039 cerr << "WARNING: MainWindow::openRecentFile: sender is not an action" 3196 cerr << "WARNING: MainWindow::openRecentFile: sender is not an action"
3040 << endl; 3197 << endl;
3041 return; 3198 return;
3042 } 3199 }
3043 3200
3044 QString path = action->text(); 3201 QString path = action->text();
3202 #endif
3203 /* End of F. Nicol patch 13 Aug. 2016 */
3204
3045 if (path == "") return; 3205 if (path == "") return;
3046 3206
3047 FileOpenStatus status = openPath(path, ReplaceSession); 3207 FileOpenStatus status = openPath(path, ReplaceSession);
3048 3208
3049 if (status == FileOpenFailed) { 3209 if (status == FileOpenFailed) {
3123 if (QMessageBox::warning(this, 3283 if (QMessageBox::warning(this,
3124 tr("Template file exists"), 3284 tr("Template file exists"),
3125 tr("<b>Template file exists</b><p>The template \"%1\" already exists.<br>Overwrite it?").arg(name), 3285 tr("<b>Template file exists</b><p>The template \"%1\" already exists.<br>Overwrite it?").arg(name),
3126 QMessageBox::Ok | QMessageBox::Cancel, 3286 QMessageBox::Ok | QMessageBox::Cancel,
3127 QMessageBox::Cancel) != QMessageBox::Ok) { 3287 QMessageBox::Cancel) != QMessageBox::Ok) {
3288 delete d;
3128 return; 3289 return;
3129 } 3290 }
3130 } 3291 }
3131 3292
3132 if (saveSessionTemplate(filename)) { 3293 if (saveSessionTemplate(filename)) {
3133 if (makeDefault->isChecked()) { 3294 if (makeDefault->isChecked()) {
3134 setDefaultSessionTemplate(name); 3295 setDefaultSessionTemplate(name);
3135 } 3296 }
3136 } 3297 }
3137 } 3298 }
3299
3300 delete d;
3138 } 3301 }
3139 3302
3140 void 3303 void
3141 MainWindow::manageSavedTemplates() 3304 MainWindow::manageSavedTemplates()
3142 { 3305 {
3239 settings.endGroup(); 3402 settings.endGroup();
3240 3403
3241 if (m_preferencesDialog && 3404 if (m_preferencesDialog &&
3242 m_preferencesDialog->isVisible()) { 3405 m_preferencesDialog->isVisible()) {
3243 closeSession(); // otherwise we'll have to wait for prefs changes 3406 closeSession(); // otherwise we'll have to wait for prefs changes
3244 m_preferencesDialog->applicationClosing(false); 3407 m_preferencesDialog->applicationClosing(true);
3245 } 3408 }
3246 3409
3247 closeSession(); 3410 closeSession();
3248 3411
3249 e->accept(); 3412 e->accept();
3418 void 3581 void
3419 MainWindow::preferenceChanged(PropertyContainer::PropertyName name) 3582 MainWindow::preferenceChanged(PropertyContainer::PropertyName name)
3420 { 3583 {
3421 MainWindowBase::preferenceChanged(name); 3584 MainWindowBase::preferenceChanged(name);
3422 3585
3423 if (name == "Background Mode" && m_viewManager) { 3586 if (name == "Background Mode") {
3424 if (m_viewManager->getGlobalDarkBackground()) { 3587 coloursChanged();
3425 m_panLayer->setBaseColour
3426 (ColourDatabase::getInstance()->getColourIndex(tr("Bright Green")));
3427 } else {
3428 m_panLayer->setBaseColour
3429 (ColourDatabase::getInstance()->getColourIndex(tr("Green")));
3430 }
3431 } 3588 }
3589 }
3590
3591 void
3592 MainWindow::coloursChanged()
3593 {
3594 QSettings settings;
3595 settings.beginGroup("Preferences");
3596 QString defaultColourName(tr("Green"));
3597 if (m_viewManager && m_viewManager->getGlobalDarkBackground()) {
3598 defaultColourName = tr("Bright Green");
3599 }
3600 ColourDatabase *cdb = ColourDatabase::getInstance();
3601 QColor colour = QColor
3602 (settings.value("overview-colour",
3603 cdb->getColour(defaultColourName).name()).toString());
3604 settings.endGroup();
3605
3606 int index = cdb->getColourIndex(colour);
3607 if (index >= 0) {
3608 m_panLayer->setBaseColour(index);
3609 }
3432 } 3610 }
3433 3611
3434 void 3612 void
3435 MainWindow::propertyStacksResized(int width) 3613 MainWindow::propertyStacksResized(int width)
3436 { 3614 {
4057 break; 4235 break;
4058 } 4236 }
4059 } 4237 }
4060 4238
4061 void 4239 void
4062 MainWindow::outputLevelsChanged(float left, float right) 4240 MainWindow::monitoringLevelsChanged(float left, float right)
4063 { 4241 {
4064 m_fader->setPeakLeft(left); 4242 m_mainLevelPan->setMonitoringLevels(left, right);
4065 m_fader->setPeakRight(right);
4066 } 4243 }
4067 4244
4068 void 4245 void
4069 MainWindow::sampleRateMismatch(sv_samplerate_t requested, 4246 MainWindow::sampleRateMismatch(sv_samplerate_t requested,
4070 sv_samplerate_t actual, 4247 sv_samplerate_t actual,
4096 if (shownOnce) return; 4273 if (shownOnce) return;
4097 QMessageBox::information 4274 QMessageBox::information
4098 (this, tr("Audio processing overload"), 4275 (this, tr("Audio processing overload"),
4099 tr("<b>Overloaded</b><p>Audio playback speed processing has been reduced to a single channel, due to a processing overload.")); 4276 tr("<b>Overloaded</b><p>Audio playback speed processing has been reduced to a single channel, due to a processing overload."));
4100 shownOnce = true; 4277 shownOnce = true;
4278 }
4279
4280 void
4281 MainWindow::betaReleaseWarning()
4282 {
4283 QMessageBox::information
4284 (this, tr("Beta release"),
4285 tr("<b>This is a beta release of Sonic Visualiser</b><p>Please see the \"What's New\" option in the Help menu for a list of changes since the last proper release.</p>"));
4286 }
4287
4288 void
4289 MainWindow::pluginPopulationWarning()
4290 {
4291 QString scanWarning = PluginScan::getInstance()->getStartupFailureReport();
4292 QString factWarning = TransformFactory::getInstance()->getStartupFailureReport();
4293 QString warning;
4294 if (factWarning != "") {
4295 // The order of events on startup implies that, if scanWarning
4296 // and factWarning are both present, then we have already been
4297 // called once for scanWarning so don't want to report it again
4298 warning = factWarning;
4299 } else if (scanWarning != "") {
4300 warning = scanWarning;
4301 }
4302 if (warning != "") {
4303 emit hideSplash();
4304 QMessageBox::warning(this, tr("Problems loading plugins"), warning);
4305 }
4101 } 4306 }
4102 4307
4103 void 4308 void
4104 MainWindow::midiEventsAvailable() 4309 MainWindow::midiEventsAvailable()
4105 { 4310 {
4235 { 4440 {
4236 m_panLayer->setModel(model); 4441 m_panLayer->setModel(model);
4237 4442
4238 MainWindowBase::mainModelChanged(model); 4443 MainWindowBase::mainModelChanged(model);
4239 4444
4445 if (m_playTarget || m_audioIO) {
4446 connect(m_mainLevelPan, SIGNAL(levelChanged(float)),
4447 this, SLOT(mainModelGainChanged(float)));
4448 connect(m_mainLevelPan, SIGNAL(panChanged(float)),
4449 this, SLOT(mainModelPanChanged(float)));
4450 }
4451 }
4452
4453 void
4454 MainWindow::mainModelGainChanged(float gain)
4455 {
4240 if (m_playTarget) { 4456 if (m_playTarget) {
4241 connect(m_fader, SIGNAL(valueChanged(float)), 4457 m_playTarget->setOutputGain(gain);
4242 m_playTarget, SLOT(setOutputGain(float))); 4458 } else if (m_audioIO) {
4459 m_audioIO->setOutputGain(gain);
4460 }
4461 }
4462
4463 void
4464 MainWindow::mainModelPanChanged(float balance)
4465 {
4466 // this is indeed stereo balance rather than pan
4467 if (m_playTarget) {
4468 m_playTarget->setOutputBalance(balance);
4469 } else if (m_audioIO) {
4470 m_audioIO->setOutputBalance(balance);
4243 } 4471 }
4244 } 4472 }
4245 4473
4246 void 4474 void
4247 MainWindow::modelAboutToBeDeleted(Model *model) 4475 MainWindow::modelAboutToBeDeleted(Model *model)
4299 4527
4300 void 4528 void
4301 MainWindow::resetInstantsCounters() 4529 MainWindow::resetInstantsCounters()
4302 { 4530 {
4303 if (m_labeller) m_labeller->resetCounters(); 4531 if (m_labeller) m_labeller->resetCounters();
4532 }
4533
4534 void
4535 MainWindow::subdivideInstants()
4536 {
4537 QSettings settings;
4538 settings.beginGroup("MainWindow");
4539 int n = settings.value("subdivisions", 4).toInt();
4540
4541 bool ok;
4542
4543 n = QInputDialog::getInt(this,
4544 tr("Subdivide instants"),
4545 tr("Number of subdivisions:"),
4546 n, 2, 96, 1, &ok);
4547
4548 if (ok) {
4549 settings.setValue("subdivisions", n);
4550 subdivideInstantsBy(n);
4551 }
4552
4553 settings.endGroup();
4554 }
4555
4556 void
4557 MainWindow::winnowInstants()
4558 {
4559 QSettings settings;
4560 settings.beginGroup("MainWindow");
4561 int n = settings.value("winnow-subdivisions", 4).toInt();
4562
4563 bool ok;
4564
4565 n = QInputDialog::getInt(this,
4566 tr("Winnow instants"),
4567 tr("Remove all instants apart from multiples of:"),
4568 n, 2, 96, 1, &ok);
4569
4570 if (ok) {
4571 settings.setValue("winnow-subdivisions", n);
4572 winnowInstantsBy(n);
4573 }
4574
4575 settings.endGroup();
4304 } 4576 }
4305 4577
4306 void 4578 void
4307 MainWindow::modelGenerationFailed(QString transformName, QString message) 4579 MainWindow::modelGenerationFailed(QString transformName, QString message)
4308 { 4580 {
4374 QMessageBox::warning 4646 QMessageBox::warning
4375 (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); 4647 (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);
4376 } 4648 }
4377 4649
4378 void 4650 void
4379 MainWindow::alignmentFailed(QString transformName, QString message) 4651 MainWindow::alignmentFailed(QString message)
4380 { 4652 {
4381 emit hideSplash();
4382
4383 QMessageBox::warning 4653 QMessageBox::warning
4384 (this, 4654 (this,
4385 tr("Failed to calculate alignment"), 4655 tr("Failed to calculate alignment"),
4386 tr("<b>Alignment calculation failed</b><p>Failed to calculate an audio alignment using transform \"%1\":<p>%2") 4656 tr("<b>Alignment calculation failed</b><p>Failed to calculate an audio alignment:<p>%1")
4387 .arg(transformName).arg(message), 4657 .arg(message),
4388 QMessageBox::Ok); 4658 QMessageBox::Ok);
4389 } 4659 }
4390 4660
4391 void 4661 void
4392 MainWindow::rightButtonMenuRequested(Pane *pane, QPoint position) 4662 MainWindow::rightButtonMenuRequested(Pane *pane, QPoint position)
4440 return; 4710 return;
4441 } 4711 }
4442 4712
4443 m_preferencesDialog = new PreferencesDialog(this); 4713 m_preferencesDialog = new PreferencesDialog(this);
4444 4714
4715 connect(m_preferencesDialog, SIGNAL(audioDeviceChanged()),
4716 this, SLOT(recreateAudioIO()));
4717 connect(m_preferencesDialog, SIGNAL(coloursChanged()),
4718 this, SLOT(coloursChanged()));
4719
4445 // DeleteOnClose is safe here, because m_preferencesDialog is a 4720 // DeleteOnClose is safe here, because m_preferencesDialog is a
4446 // QPointer that will be zeroed when the dialog is deleted. We 4721 // QPointer that will be zeroed when the dialog is deleted. We
4447 // use it in preference to leaving the dialog lying around because 4722 // use it in preference to leaving the dialog lying around because
4448 // if you Cancel the dialog, it resets the preferences state 4723 // if you Cancel the dialog, it resets the preferences state
4449 // without resetting its own widgets, so its state will be 4724 // without resetting its own widgets, so its state will be
4460 MainWindow::mouseEnteredWidget() 4735 MainWindow::mouseEnteredWidget()
4461 { 4736 {
4462 QWidget *w = dynamic_cast<QWidget *>(sender()); 4737 QWidget *w = dynamic_cast<QWidget *>(sender());
4463 if (!w) return; 4738 if (!w) return;
4464 4739
4465 if (w == m_fader) { 4740 if (w == m_mainLevelPan) {
4466 contextHelpChanged(tr("Adjust the master playback level")); 4741 contextHelpChanged(tr("Adjust the master playback level and pan"));
4467 } else if (w == m_playSpeed) { 4742 } else if (w == m_playSpeed) {
4468 contextHelpChanged(tr("Adjust the master playback speed")); 4743 contextHelpChanged(tr("Adjust the master playback speed"));
4469 } 4744 }
4470 } 4745 }
4471 4746
4483 4758
4484 void 4759 void
4485 MainWindow::help() 4760 MainWindow::help()
4486 { 4761 {
4487 openHelpUrl(tr("http://www.sonicvisualiser.org/doc/reference/%1/en/").arg(SV_VERSION)); 4762 openHelpUrl(tr("http://www.sonicvisualiser.org/doc/reference/%1/en/").arg(SV_VERSION));
4763 }
4764
4765 void
4766 MainWindow::whatsNew()
4767 {
4768 QFile changelog(":CHANGELOG");
4769 changelog.open(QFile::ReadOnly);
4770 QByteArray content = changelog.readAll();
4771 QString text = QString::fromUtf8(content);
4772
4773 QDialog *d = new QDialog(this);
4774 d->setWindowTitle(tr("What's New"));
4775
4776 QGridLayout *layout = new QGridLayout;
4777 d->setLayout(layout);
4778
4779 int row = 0;
4780
4781 QLabel *iconLabel = new QLabel;
4782 iconLabel->setPixmap(QApplication::windowIcon().pixmap(64, 64));
4783 layout->addWidget(iconLabel, row, 0);
4784
4785 layout->addWidget
4786 (new QLabel(tr("<h3>What's New in %1</h3>")
4787 .arg(QApplication::applicationName())),
4788 row++, 1);
4789 layout->setColumnStretch(2, 10);
4790
4791 QTextEdit *textEdit = new QTextEdit;
4792 layout->addWidget(textEdit, row++, 1, 1, 2);
4793
4794 if (m_newerVersionIs != "") {
4795 layout->addWidget(new QLabel(tr("<b>Note:</b> A newer version of Sonic Visualiser is available.<br>(Version %1 is available; you are using version %2)").arg(m_newerVersionIs).arg(SV_VERSION)), row++, 1, 1, 2);
4796 }
4797
4798 QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Ok);
4799 layout->addWidget(bb, row++, 0, 1, 3);
4800 connect(bb, SIGNAL(accepted()), d, SLOT(accept()));
4801
4802 text.replace(QRegExp("(.)\n +(.)"), "\\1 \\2");
4803 text.replace(QRegExp("\n - ([^\n]+)"), "\n<li>\\1</li>");
4804 text.replace(QRegExp(": *\n"), ":\n<ul>\n");
4805 text.replace(QRegExp("</li>\n\\s*\n"), "</li>\n</ul>\n\n");
4806 text.replace(QRegExp("\n(\\w[^:\n]+:)"), "\n<p><b>\\1</b></p>");
4807 // text.replace(QRegExp("<li>([^,.\n]+)([,.] +\\w)"), "<li><b>\\1</b>\\2");
4808
4809 textEdit->setHtml(text);
4810 textEdit->setReadOnly(true);
4811
4812 d->setMinimumSize(m_viewManager->scalePixelSize(520),
4813 m_viewManager->scalePixelSize(450));
4814
4815 d->exec();
4816
4817 delete d;
4488 } 4818 }
4489 4819
4490 void 4820 void
4491 MainWindow::about() 4821 MainWindow::about()
4492 { 4822 {
4510 4840
4511 QString aboutText; 4841 QString aboutText;
4512 4842
4513 aboutText += tr("<h3>About Sonic Visualiser</h3>"); 4843 aboutText += tr("<h3>About Sonic Visualiser</h3>");
4514 aboutText += tr("<p>Sonic Visualiser is a program for viewing and exploring audio data for semantic music analysis and annotation.<br><a href=\"http://www.sonicvisualiser.org/\">http://www.sonicvisualiser.org/</a></p>"); 4844 aboutText += tr("<p>Sonic Visualiser is a program for viewing and exploring audio data for semantic music analysis and annotation.<br><a href=\"http://www.sonicvisualiser.org/\">http://www.sonicvisualiser.org/</a></p>");
4515 aboutText += tr("<p><small>%1 : %2 configuration</small></p>") 4845 aboutText += tr("<p><small>%1 : %2 configuration, %3-bit build</small></p>")
4516 .arg(version) 4846 .arg(version)
4517 .arg(debug ? tr("Debug") : tr("Release")); 4847 .arg(debug ? tr("Debug") : tr("Release"))
4518 4848 .arg(sizeof(void *) * 8);
4519 aboutText += "<small>"; 4849
4520 4850 if (m_oscQueue && m_oscQueue->isOK()) {
4521 aboutText += tr("With Qt v%1 &copy; Nokia Corporation").arg(QT_VERSION_STR); 4851 aboutText += tr("</small><p><small>The OSC URL for this instance is: \"%1\"").arg(m_oscQueue->getOSCURL());
4852 }
4853
4854 aboutText += "</small><p><small>";
4855
4856 aboutText += tr("With Qt v%1 &copy; The Qt Company").arg(QT_VERSION_STR);
4857
4858 aboutText += "</small><small>";
4522 4859
4523 #ifdef HAVE_JACK 4860 #ifdef HAVE_JACK
4524 #ifdef JACK_VERSION 4861 #ifdef JACK_VERSION
4525 aboutText += tr("<br>With JACK audio output library v%1 &copy; Paul Davis and Jack O'Quin").arg(JACK_VERSION); 4862 aboutText += tr("<br>With JACK audio output library v%1 &copy; Paul Davis and Jack O'Quin").arg(JACK_VERSION);
4526 #else // !JACK_VERSION 4863 #else // !JACK_VERSION
4572 aboutText += tr("<br>With FFTW3 &copy; Matteo Frigo and MIT"); 4909 aboutText += tr("<br>With FFTW3 &copy; Matteo Frigo and MIT");
4573 #endif // FFTW3_VERSION 4910 #endif // FFTW3_VERSION
4574 #endif // HAVE_FFTW3F 4911 #endif // HAVE_FFTW3F
4575 #ifdef HAVE_RUBBERBAND 4912 #ifdef HAVE_RUBBERBAND
4576 #ifdef RUBBERBAND_VERSION 4913 #ifdef RUBBERBAND_VERSION
4577 aboutText += tr("<br>With Rubber Band v%1 &copy; Chris Cannam").arg(RUBBERBAND_VERSION); 4914 aboutText += tr("<br>With Rubber Band Library v%1 &copy; Particular Programs Ltd").arg(RUBBERBAND_VERSION);
4578 #else // !RUBBERBAND_VERSION 4915 #else // !RUBBERBAND_VERSION
4579 aboutText += tr("<br>With Rubber Band &copy; Chris Cannam"); 4916 aboutText += tr("<br>With Rubber Band Library &copy; Particular Programs Ltd");
4580 #endif // RUBBERBAND_VERSION 4917 #endif // RUBBERBAND_VERSION
4581 #endif // HAVE_RUBBERBAND 4918 #endif // HAVE_RUBBERBAND
4582 #ifdef HAVE_VAMP 4919 aboutText += tr("<br>With Vamp plugin support (API v%1, host SDK v%2) &copy; Chris Cannam and QMUL").arg(VAMP_API_VERSION).arg(VAMP_SDK_VERSION);
4583 aboutText += tr("<br>With Vamp plugin support (API v%1, host SDK v%2) &copy; Chris Cannam").arg(VAMP_API_VERSION).arg(VAMP_SDK_VERSION);
4584 #endif // !HAVE_VAMP
4585 aboutText += tr("<br>With LADSPA plugin support (API v%1) &copy; Richard Furse, Paul Davis, Stefan Westerfeld").arg(LADSPA_VERSION); 4920 aboutText += tr("<br>With LADSPA plugin support (API v%1) &copy; Richard Furse, Paul Davis, Stefan Westerfeld").arg(LADSPA_VERSION);
4586 aboutText += tr("<br>With DSSI plugin support (API v%1) &copy; Chris Cannam, Steve Harris, Sean Bolton").arg(DSSI_VERSION); 4921 aboutText += tr("<br>With DSSI plugin support (API v%1) &copy; Chris Cannam, Steve Harris, Sean Bolton").arg(DSSI_VERSION);
4587 #ifdef REDLAND_VERSION 4922 #ifdef REDLAND_VERSION
4588 aboutText += tr("<br>With Redland RDF datastore v%1 &copy; Dave Beckett and the University of Bristol").arg(REDLAND_VERSION); 4923 aboutText += tr("<br>With Redland RDF datastore v%1 &copy; Dave Beckett and the University of Bristol").arg(REDLAND_VERSION);
4589 #else // !REDLAND_VERSION 4924 #else // !REDLAND_VERSION
4590 aboutText += tr("<br>With Redland RDF datastore &copy; Dave Beckett and the University of Bristol"); 4925 aboutText += tr("<br>With Redland RDF datastore &copy; Dave Beckett and the University of Bristol");
4591 #endif // REDLAND_VERSION 4926 #endif // REDLAND_VERSION
4592 aboutText += tr("<br>With Serd and Sord RDF parser and store &copy; David Robillard"); 4927 aboutText += tr("<br>With Serd and Sord RDF parser and store &copy; David Robillard");
4593 aboutText += tr("<br>With Dataquay Qt/RDF library &copy; Chris Cannam"); 4928 aboutText += tr("<br>With Dataquay Qt/RDF library &copy; Particular Programs Ltd");
4594 4929 aboutText += tr("<br>With Cap'n Proto serialisation &copy; Sandstorm Development Group");
4595 aboutText += tr("<br>With RtMidi &copy; Gary P. Scavone"); 4930 aboutText += tr("<br>With RtMidi &copy; Gary P. Scavone");
4596 4931
4597 #ifdef HAVE_LIBLO 4932 #ifdef HAVE_LIBLO
4598 #ifdef LIBLO_VERSION 4933 #ifdef LIBLO_VERSION
4599 aboutText += tr("<br>With liblo Lite OSC library v%1 &copy; Steve Harris").arg(LIBLO_VERSION); 4934 aboutText += tr("<br>With liblo Lite OSC library v%1 &copy; Steve Harris").arg(LIBLO_VERSION);
4600 #else // !LIBLO_VERSION 4935 #else // !LIBLO_VERSION
4601 aboutText += tr("<br>With liblo Lite OSC library &copy; Steve Harris"); 4936 aboutText += tr("<br>With liblo Lite OSC library &copy; Steve Harris");
4602 #endif // LIBLO_VERSION 4937 #endif // LIBLO_VERSION
4603 4938
4604 if (m_oscQueue && m_oscQueue->isOK()) {
4605 aboutText += tr("</small><p><small>The OSC URL for this instance is: \"%1\"").arg(m_oscQueue->getOSCURL());
4606 }
4607
4608 aboutText += "</small></p>"; 4939 aboutText += "</small></p>";
4609 #endif // HAVE_LIBLO 4940 #endif // HAVE_LIBLO
4610 4941
4611 #ifndef BUILD_STATIC
4612 aboutText.replace(tr("With "), tr("Using "));
4613 #endif
4614
4615 aboutText += 4942 aboutText +=
4616 "<p><small>Sonic Visualiser Copyright &copy; 2005&ndash;2015 Chris Cannam and " 4943 "<p><small>Sonic Visualiser Copyright &copy; 2005&ndash;2017 Chris Cannam and "
4617 "Queen Mary, University of London.</small></p>" 4944 "Queen Mary, University of London.</small></p>"
4618 "<p><small>This program is free software; you can redistribute it and/or " 4945 "<p><small>This program is free software; you can redistribute it and/or "
4619 "modify it under the terms of the GNU General Public License as " 4946 "modify it under the terms of the GNU General Public License as "
4620 "published by the Free Software Foundation; either version 2 of the " 4947 "published by the Free Software Foundation; either version 2 of the "
4621 "License, or (at your option) any later version.<br>See the file " 4948 "License, or (at your option) any later version.<br>See the file "
4622 "COPYING included with this distribution for more information.</small></p>"; 4949 "COPYING included with this distribution for more information.</small></p>";
4950
4951 // use our own dialog so we can influence the size
4952
4953 QDialog *d = new QDialog(this);
4954
4955 d->setWindowTitle(tr("About %1").arg(QApplication::applicationName()));
4956
4957 QGridLayout *layout = new QGridLayout;
4958 d->setLayout(layout);
4959
4960 int row = 0;
4623 4961
4624 QMessageBox::about(this, tr("About Sonic Visualiser"), aboutText); 4962 QLabel *iconLabel = new QLabel;
4963 iconLabel->setPixmap(QApplication::windowIcon().pixmap(64, 64));
4964 layout->addWidget(iconLabel, row, 0, Qt::AlignTop);
4965
4966 QLabel *mainText = new QLabel();
4967 layout->addWidget(mainText, row, 1, 1, 2);
4968
4969 layout->setRowStretch(row, 10);
4970 layout->setColumnStretch(1, 10);
4971
4972 ++row;
4973
4974 QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Ok);
4975 layout->addWidget(bb, row++, 0, 1, 3);
4976 connect(bb, SIGNAL(accepted()), d, SLOT(accept()));
4977
4978 // mainText->setHtml(aboutText);
4979 // mainText->setReadOnly(true);
4980 mainText->setWordWrap(true);
4981 mainText->setOpenExternalLinks(true);
4982 mainText->setText(aboutText);
4983
4984 d->setMinimumSize(m_viewManager->scalePixelSize(420),
4985 m_viewManager->scalePixelSize(200));
4986
4987 d->exec();
4988
4989 delete d;
4990 /*
4991 QMessageBox about(QMessageBox::Information,
4992 tr("About Sonic Visualiser"),
4993 aboutText,
4994 QMessageBox::StandardButtons(QMessageBox::Ok),
4995 this);
4996
4997 QIcon icon = QApplication::windowIcon();
4998 QSize size = icon.actualSize(QSize(64, 64));
4999 about.setIconPixmap(icon.pixmap(size));
5000
5001 about.setMinimumSize(m_viewManager->scalePixelSize(400),
5002 m_viewManager->scalePixelSize(400));
5003
5004 about.exec();
5005 */
4625 } 5006 }
4626 5007
4627 void 5008 void
4628 MainWindow::keyReference() 5009 MainWindow::keyReference()
4629 { 5010 {
4631 } 5012 }
4632 5013
4633 void 5014 void
4634 MainWindow::newerVersionAvailable(QString version) 5015 MainWindow::newerVersionAvailable(QString version)
4635 { 5016 {
5017 m_newerVersionIs = version;
5018
4636 QSettings settings; 5019 QSettings settings;
4637 settings.beginGroup("NewerVersionWarning"); 5020 settings.beginGroup("NewerVersionWarning");
4638 QString tag = QString("version-%1-available-show").arg(version); 5021 QString tag = QString("version-%1-available-show").arg(version);
4639 if (settings.value(tag, true).toBool()) { 5022 if (settings.value(tag, true).toBool()) {
4640 QString title(tr("Newer version available")); 5023 QString title(tr("Newer version available"));