Chris@0
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@0
|
2
|
Chris@0
|
3 /*
|
Chris@0
|
4 Sonic Visualiser
|
Chris@0
|
5 An audio file viewer and annotation editor.
|
Chris@0
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@200
|
7 This file copyright 2006-2007 Chris Cannam and QMUL.
|
Chris@0
|
8
|
Chris@0
|
9 This program is free software; you can redistribute it and/or
|
Chris@0
|
10 modify it under the terms of the GNU General Public License as
|
Chris@0
|
11 published by the Free Software Foundation; either version 2 of the
|
Chris@0
|
12 License, or (at your option) any later version. See the file
|
Chris@0
|
13 COPYING included with this distribution for more information.
|
Chris@0
|
14 */
|
Chris@0
|
15
|
Chris@144
|
16 #include "../version.h"
|
Chris@0
|
17
|
Chris@0
|
18 #include "MainWindow.h"
|
Chris@0
|
19 #include "PreferencesDialog.h"
|
Chris@0
|
20
|
Chris@1
|
21 #include "view/Pane.h"
|
Chris@1
|
22 #include "view/PaneStack.h"
|
Chris@1
|
23 #include "data/model/WaveFileModel.h"
|
Chris@1
|
24 #include "data/model/SparseOneDimensionalModel.h"
|
Chris@415
|
25 #include "data/model/RangeSummarisableTimeValueModel.h"
|
Chris@185
|
26 #include "data/model/NoteModel.h"
|
Chris@189
|
27 #include "data/model/Labeller.h"
|
Chris@222
|
28 #include "data/osc/OSCQueue.h"
|
Chris@216
|
29 #include "framework/Document.h"
|
Chris@357
|
30 #include "framework/TransformUserConfigurator.h"
|
Chris@1
|
31 #include "view/ViewManager.h"
|
Chris@0
|
32 #include "base/Preferences.h"
|
Chris@423
|
33 #include "base/ResourceFinder.h"
|
Chris@0
|
34 #include "layer/WaveformLayer.h"
|
Chris@0
|
35 #include "layer/TimeRulerLayer.h"
|
Chris@0
|
36 #include "layer/TimeInstantLayer.h"
|
Chris@0
|
37 #include "layer/TimeValueLayer.h"
|
Chris@307
|
38 #include "layer/NoteLayer.h"
|
Chris@0
|
39 #include "layer/Colour3DPlotLayer.h"
|
Chris@95
|
40 #include "layer/SliceLayer.h"
|
Chris@95
|
41 #include "layer/SliceableLayer.h"
|
Chris@193
|
42 #include "layer/ImageLayer.h"
|
Chris@340
|
43 #include "layer/RegionLayer.h"
|
Chris@0
|
44 #include "widgets/Fader.h"
|
Chris@65
|
45 #include "view/Overview.h"
|
Chris@0
|
46 #include "widgets/PropertyBox.h"
|
Chris@0
|
47 #include "widgets/PropertyStack.h"
|
Chris@0
|
48 #include "widgets/AudioDial.h"
|
Chris@168
|
49 #include "widgets/IconLoader.h"
|
Chris@219
|
50 #include "widgets/LayerTreeDialog.h"
|
Chris@0
|
51 #include "widgets/ListInputDialog.h"
|
Chris@36
|
52 #include "widgets/SubdividingMenu.h"
|
Chris@90
|
53 #include "widgets/NotifyingPushButton.h"
|
Chris@162
|
54 #include "widgets/KeyReference.h"
|
Chris@273
|
55 #include "widgets/TransformFinder.h"
|
Chris@192
|
56 #include "widgets/LabelCounterInputDialog.h"
|
Chris@302
|
57 #include "widgets/ActivityLog.h"
|
Chris@0
|
58 #include "audioio/AudioCallbackPlaySource.h"
|
Chris@0
|
59 #include "audioio/AudioCallbackPlayTarget.h"
|
Chris@0
|
60 #include "audioio/AudioTargetFactory.h"
|
Chris@59
|
61 #include "audioio/PlaySpeedRangeMapper.h"
|
Chris@1
|
62 #include "data/fileio/DataFileReaderFactory.h"
|
Chris@180
|
63 #include "data/fileio/PlaylistFileReader.h"
|
Chris@1
|
64 #include "data/fileio/WavFileWriter.h"
|
Chris@1
|
65 #include "data/fileio/CSVFileWriter.h"
|
Chris@185
|
66 #include "data/fileio/MIDIFileWriter.h"
|
Chris@1
|
67 #include "data/fileio/BZipFileDevice.h"
|
Chris@198
|
68 #include "data/fileio/FileSource.h"
|
Chris@91
|
69 #include "data/fft/FFTDataServer.h"
|
Chris@304
|
70 #include "data/midi/MIDIInput.h"
|
Chris@1
|
71 #include "base/RecentFiles.h"
|
Chris@249
|
72 #include "transform/TransformFactory.h"
|
Chris@249
|
73 #include "transform/ModelTransformerFactory.h"
|
Chris@0
|
74 #include "base/PlayParameterRepository.h"
|
Chris@0
|
75 #include "base/XmlExportable.h"
|
Chris@248
|
76 #include "widgets/CommandHistory.h"
|
Chris@0
|
77 #include "base/Profiler.h"
|
Chris@0
|
78 #include "base/Clipboard.h"
|
Chris@165
|
79 #include "base/UnitDatabase.h"
|
Chris@248
|
80 #include "layer/ColourDatabase.h"
|
Chris@265
|
81 #include "widgets/ModelDataTableDialog.h"
|
Chris@289
|
82 #include "rdf/PluginRDFIndexer.h"
|
Chris@291
|
83 #include "rdf/RDFExporter.h"
|
Chris@276
|
84
|
Chris@662
|
85 #include "Surveyer.h"
|
Chris@663
|
86 #include "NetworkPermissionTester.h"
|
Chris@334
|
87 #include "framework/VersionTester.h"
|
Chris@333
|
88
|
Chris@0
|
89 // For version information
|
Chris@280
|
90 #include <vamp/vamp.h>
|
Chris@280
|
91 #include <vamp-hostsdk/PluginBase.h>
|
Chris@0
|
92 #include "plugin/api/ladspa.h"
|
Chris@0
|
93 #include "plugin/api/dssi.h"
|
Chris@0
|
94
|
Chris@0
|
95 #include <QApplication>
|
Chris@0
|
96 #include <QMessageBox>
|
Chris@0
|
97 #include <QGridLayout>
|
Chris@0
|
98 #include <QLabel>
|
Chris@0
|
99 #include <QAction>
|
Chris@0
|
100 #include <QMenuBar>
|
Chris@0
|
101 #include <QToolBar>
|
Chris@0
|
102 #include <QInputDialog>
|
Chris@0
|
103 #include <QStatusBar>
|
Chris@0
|
104 #include <QTreeView>
|
Chris@0
|
105 #include <QFile>
|
Chris@88
|
106 #include <QFileInfo>
|
Chris@88
|
107 #include <QDir>
|
Chris@0
|
108 #include <QTextStream>
|
Chris@0
|
109 #include <QProcess>
|
Chris@7
|
110 #include <QShortcut>
|
Chris@5
|
111 #include <QSettings>
|
Chris@11
|
112 #include <QDateTime>
|
Chris@11
|
113 #include <QProcess>
|
Chris@16
|
114 #include <QCheckBox>
|
Chris@55
|
115 #include <QRegExp>
|
Chris@158
|
116 #include <QScrollArea>
|
Chris@425
|
117 #include <QDesktopServices>
|
Chris@483
|
118 #include <QDialogButtonBox>
|
Chris@426
|
119 #include <QFileSystemWatcher>
|
Chris@0
|
120
|
Chris@0
|
121 #include <iostream>
|
Chris@0
|
122 #include <cstdio>
|
Chris@0
|
123 #include <errno.h>
|
Chris@0
|
124
|
Chris@33
|
125 using std::vector;
|
Chris@33
|
126 using std::map;
|
Chris@33
|
127 using std::set;
|
Chris@33
|
128
|
Chris@0
|
129
|
Chris@70
|
130 MainWindow::MainWindow(bool withAudioOutput, bool withOSCSupport) :
|
Chris@686
|
131 MainWindowBase(withAudioOutput, true),
|
Chris@65
|
132 m_overview(0),
|
Chris@0
|
133 m_mainMenusCreated(false),
|
Chris@0
|
134 m_paneMenu(0),
|
Chris@0
|
135 m_layerMenu(0),
|
Chris@34
|
136 m_transformsMenu(0),
|
Chris@155
|
137 m_playbackMenu(0),
|
Chris@0
|
138 m_existingLayersMenu(0),
|
Chris@95
|
139 m_sliceMenu(0),
|
Chris@34
|
140 m_recentFilesMenu(0),
|
Chris@211
|
141 m_recentTransformsMenu(0),
|
Chris@426
|
142 m_templatesMenu(0),
|
Chris@0
|
143 m_rightButtonMenu(0),
|
Chris@0
|
144 m_rightButtonLayerMenu(0),
|
Chris@211
|
145 m_rightButtonTransformsMenu(0),
|
Chris@155
|
146 m_rightButtonPlaybackMenu(0),
|
Chris@207
|
147 m_soloAction(0),
|
Chris@265
|
148 m_rwdStartAction(0),
|
Chris@323
|
149 m_rwdSimilarAction(0),
|
Chris@265
|
150 m_rwdAction(0),
|
Chris@155
|
151 m_ffwdAction(0),
|
Chris@323
|
152 m_ffwdSimilarAction(0),
|
Chris@265
|
153 m_ffwdEndAction(0),
|
Chris@265
|
154 m_playAction(0),
|
Chris@265
|
155 m_playSelectionAction(0),
|
Chris@265
|
156 m_playLoopAction(0),
|
Chris@705
|
157 m_soloModified(false),
|
Chris@705
|
158 m_prevSolo(false),
|
Chris@239
|
159 m_playControlsSpacer(0),
|
Chris@239
|
160 m_playControlsWidth(0),
|
Chris@162
|
161 m_preferencesDialog(0),
|
Chris@219
|
162 m_layerTreeDialog(0),
|
Chris@302
|
163 m_activityLog(new ActivityLog()),
|
Chris@426
|
164 m_keyReference(new KeyReference()),
|
Chris@764
|
165 m_templateWatcher(0),
|
Chris@764
|
166 m_surveyer(0),
|
Chris@764
|
167 m_versionTester(0)
|
Chris@0
|
168 {
|
Chris@253
|
169 Profiler profiler("MainWindow::MainWindow");
|
Chris@253
|
170
|
Chris@518
|
171 setWindowTitle(QApplication::applicationName());
|
Chris@0
|
172
|
Chris@165
|
173 UnitDatabase *udb = UnitDatabase::getInstance();
|
Chris@165
|
174 udb->registerUnit("Hz");
|
Chris@165
|
175 udb->registerUnit("dB");
|
Chris@165
|
176 udb->registerUnit("s");
|
Chris@165
|
177
|
Chris@165
|
178 ColourDatabase *cdb = ColourDatabase::getInstance();
|
Chris@165
|
179 cdb->addColour(Qt::black, tr("Black"));
|
Chris@165
|
180 cdb->addColour(Qt::darkRed, tr("Red"));
|
Chris@165
|
181 cdb->addColour(Qt::darkBlue, tr("Blue"));
|
Chris@165
|
182 cdb->addColour(Qt::darkGreen, tr("Green"));
|
Chris@165
|
183 cdb->addColour(QColor(200, 50, 255), tr("Purple"));
|
Chris@165
|
184 cdb->addColour(QColor(255, 150, 50), tr("Orange"));
|
Chris@166
|
185 cdb->setUseDarkBackground(cdb->addColour(Qt::white, tr("White")), true);
|
Chris@166
|
186 cdb->setUseDarkBackground(cdb->addColour(Qt::red, tr("Bright Red")), true);
|
Chris@166
|
187 cdb->setUseDarkBackground(cdb->addColour(QColor(30, 150, 255), tr("Bright Blue")), true);
|
Chris@166
|
188 cdb->setUseDarkBackground(cdb->addColour(Qt::green, tr("Bright Green")), true);
|
Chris@166
|
189 cdb->setUseDarkBackground(cdb->addColour(QColor(225, 74, 255), tr("Bright Purple")), true);
|
Chris@166
|
190 cdb->setUseDarkBackground(cdb->addColour(QColor(255, 188, 80), tr("Bright Orange")), true);
|
Chris@0
|
191
|
Chris@0
|
192 QFrame *frame = new QFrame;
|
Chris@0
|
193 setCentralWidget(frame);
|
Chris@0
|
194
|
Chris@0
|
195 QGridLayout *layout = new QGridLayout;
|
Chris@180
|
196
|
Chris@519
|
197 m_descriptionLabel = new QLabel;
|
Chris@0
|
198
|
Chris@489
|
199 m_mainScroll = new QScrollArea(frame);
|
Chris@489
|
200 m_mainScroll->setWidgetResizable(true);
|
Chris@489
|
201 m_mainScroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
Chris@489
|
202 m_mainScroll->setFrameShape(QFrame::NoFrame);
|
Chris@489
|
203
|
Chris@489
|
204 m_mainScroll->setWidget(m_paneStack);
|
Chris@159
|
205
|
Chris@65
|
206 m_overview = new Overview(frame);
|
Chris@65
|
207 m_overview->setViewManager(m_viewManager);
|
Chris@65
|
208 m_overview->setFixedHeight(40);
|
Chris@144
|
209 #ifndef _WIN32
|
Chris@144
|
210 // For some reason, the contents of the overview never appear if we
|
Chris@144
|
211 // make this setting on Windows. I have no inclination at the moment
|
Chris@144
|
212 // to track down the reason why.
|
Chris@129
|
213 m_overview->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
|
Chris@144
|
214 #endif
|
Chris@90
|
215 connect(m_overview, SIGNAL(contextHelpChanged(const QString &)),
|
Chris@116
|
216 this, SLOT(contextHelpChanged(const QString &)));
|
Chris@0
|
217
|
Chris@0
|
218 m_panLayer = new WaveformLayer;
|
Chris@0
|
219 m_panLayer->setChannelMode(WaveformLayer::MergeChannels);
|
Chris@0
|
220 m_panLayer->setAggressiveCacheing(true);
|
Chris@65
|
221 m_overview->addLayer(m_panLayer);
|
Chris@174
|
222
|
Chris@174
|
223 if (m_viewManager->getGlobalDarkBackground()) {
|
Chris@174
|
224 m_panLayer->setBaseColour
|
Chris@174
|
225 (ColourDatabase::getInstance()->getColourIndex(tr("Bright Green")));
|
Chris@174
|
226 } else {
|
Chris@174
|
227 m_panLayer->setBaseColour
|
Chris@174
|
228 (ColourDatabase::getInstance()->getColourIndex(tr("Green")));
|
Chris@200
|
229 }
|
Chris@0
|
230
|
Chris@0
|
231 m_fader = new Fader(frame, false);
|
Chris@90
|
232 connect(m_fader, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget()));
|
Chris@90
|
233 connect(m_fader, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget()));
|
Chris@0
|
234
|
Chris@0
|
235 m_playSpeed = new AudioDial(frame);
|
Chris@12
|
236 m_playSpeed->setMinimum(0);
|
Chris@48
|
237 m_playSpeed->setMaximum(200);
|
Chris@25
|
238 m_playSpeed->setValue(100);
|
Chris@261
|
239 m_playSpeed->setFixedWidth(32);
|
Chris@261
|
240 m_playSpeed->setFixedHeight(32);
|
Chris@0
|
241 m_playSpeed->setNotchesVisible(true);
|
Chris@25
|
242 m_playSpeed->setPageStep(10);
|
Chris@60
|
243 m_playSpeed->setObjectName(tr("Playback Speedup"));
|
Chris@25
|
244 m_playSpeed->setDefaultValue(100);
|
Chris@59
|
245 m_playSpeed->setRangeMapper(new PlaySpeedRangeMapper(0, 200));
|
Chris@60
|
246 m_playSpeed->setShowToolTip(true);
|
Chris@0
|
247 connect(m_playSpeed, SIGNAL(valueChanged(int)),
|
Chris@0
|
248 this, SLOT(playSpeedChanged(int)));
|
Chris@90
|
249 connect(m_playSpeed, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget()));
|
Chris@90
|
250 connect(m_playSpeed, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget()));
|
Chris@90
|
251
|
Chris@168
|
252 IconLoader il;
|
Chris@168
|
253
|
Chris@239
|
254 m_playControlsSpacer = new QFrame;
|
Chris@239
|
255
|
Chris@129
|
256 layout->setSpacing(4);
|
Chris@489
|
257 layout->addWidget(m_mainScroll, 0, 0, 1, 5);
|
Chris@239
|
258 layout->addWidget(m_overview, 1, 1);
|
Chris@239
|
259 layout->addWidget(m_playControlsSpacer, 1, 2);
|
Chris@239
|
260 layout->addWidget(m_playSpeed, 1, 3);
|
Chris@239
|
261 layout->addWidget(m_fader, 1, 4);
|
Chris@239
|
262
|
Chris@239
|
263 m_playControlsWidth =
|
Chris@240
|
264 m_fader->width() + m_playSpeed->width() + layout->spacing() * 2;
|
Chris@239
|
265
|
Chris@239
|
266 layout->setColumnMinimumWidth(0, 14);
|
Chris@239
|
267 layout->setColumnStretch(0, 0);
|
Chris@239
|
268
|
Chris@239
|
269 m_paneStack->setPropertyStackMinWidth(m_playControlsWidth
|
Chris@239
|
270 + 2 + layout->spacing());
|
Chris@239
|
271 m_playControlsSpacer->setFixedSize(QSize(2, 2));
|
Chris@239
|
272
|
Chris@239
|
273 layout->setColumnStretch(1, 10);
|
Chris@239
|
274
|
Chris@239
|
275 connect(m_paneStack, SIGNAL(propertyStacksResized(int)),
|
Chris@239
|
276 this, SLOT(propertyStacksResized(int)));
|
Chris@16
|
277
|
Chris@0
|
278 frame->setLayout(layout);
|
Chris@0
|
279
|
Chris@0
|
280 setupMenus();
|
Chris@0
|
281 setupToolbars();
|
Chris@155
|
282 setupHelpMenu();
|
Chris@0
|
283
|
Chris@90
|
284 statusBar();
|
Chris@340
|
285 m_currentLabel = new QLabel;
|
Chris@340
|
286 statusBar()->addPermanentWidget(m_currentLabel);
|
Chris@0
|
287
|
Chris@728
|
288 finaliseMenus();
|
Chris@728
|
289
|
Chris@302
|
290 connect(m_viewManager, SIGNAL(activity(QString)),
|
Chris@302
|
291 m_activityLog, SLOT(activityHappened(QString)));
|
Chris@302
|
292 connect(m_playSource, SIGNAL(activity(QString)),
|
Chris@302
|
293 m_activityLog, SLOT(activityHappened(QString)));
|
Chris@302
|
294 connect(CommandHistory::getInstance(), SIGNAL(activity(QString)),
|
Chris@302
|
295 m_activityLog, SLOT(activityHappened(QString)));
|
Chris@310
|
296 connect(this, SIGNAL(activity(QString)),
|
Chris@310
|
297 m_activityLog, SLOT(activityHappened(QString)));
|
Chris@303
|
298 connect(this, SIGNAL(replacedDocument()), this, SLOT(documentReplaced()));
|
Chris@306
|
299 m_activityLog->hide();
|
Chris@303
|
300
|
Chris@303
|
301 newSession();
|
Chris@303
|
302
|
Chris@304
|
303 connect(m_midiInput, SIGNAL(eventsAvailable()),
|
Chris@304
|
304 this, SLOT(midiEventsAvailable()));
|
Chris@663
|
305
|
Chris@764
|
306 #ifdef BETA_RELEASE
|
Chris@770
|
307 QStringList bits = QString(SV_VERSION).split(".");
|
Chris@770
|
308 QString beta = SV_VERSION;
|
Chris@770
|
309 if (bits.length() == 3) {
|
Chris@770
|
310 beta = QString("%1.%2 beta").arg(bits[0]).arg(bits[1].toInt() + 1);
|
Chris@770
|
311 }
|
Chris@764
|
312 QMessageBox::information
|
Chris@764
|
313 (this, tr("Test release"),
|
Chris@770
|
314 tr("<p>This is a test release of %1 (v%2 / v%3).</p>"
|
Chris@764
|
315 "<p>See the <a href=\"http://code.soundsoftware.ac.uk/projects/sonic-visualiser/repository/entry/CHANGELOG\">changelog</a> for details of what has changed since the last release.</p>"
|
Chris@764
|
316 "<p>Please let us know if you have any problems with this test release, and especially if it crashes. Use the <a href=\"http://sourceforge.net/p/sv1/bugs/\">bug tracker</a> or <a href=\"mailto:cannam+sv@all-day-breakfast.com\">email</a> to report bugs.</p><p>Please do not use this software for real work, and do not distribute it to other people who have real work to do! Use it only if you are prepared to report any bugs you find.</p>")
|
Chris@770
|
317 .arg(QApplication::applicationName())
|
Chris@770
|
318 .arg(SV_VERSION)
|
Chris@770
|
319 .arg(beta));
|
Chris@764
|
320
|
Chris@764
|
321 (void)withOSCSupport; // avoid warning
|
Chris@764
|
322 #else
|
Chris@665
|
323 NetworkPermissionTester tester;
|
Chris@663
|
324 bool networkPermission = tester.havePermission();
|
Chris@663
|
325 if (networkPermission) {
|
Chris@686
|
326 if (withOSCSupport) {
|
Chris@686
|
327 startOSCQueue();
|
Chris@686
|
328 }
|
Chris@663
|
329 TransformFactory::getInstance()->startPopulationThread();
|
Chris@663
|
330 m_surveyer = new Surveyer
|
Chris@663
|
331 ("sonicvisualiser.org", "survey23-present.txt", "survey23.php");
|
Chris@663
|
332 m_versionTester = new VersionTester
|
Chris@663
|
333 ("sonicvisualiser.org", "latest-version.txt", SV_VERSION);
|
Chris@663
|
334 connect(m_versionTester, SIGNAL(newerVersionAvailable(QString)),
|
Chris@663
|
335 this, SLOT(newerVersionAvailable(QString)));
|
Chris@663
|
336 }
|
Chris@764
|
337 #endif
|
Chris@0
|
338 }
|
Chris@0
|
339
|
Chris@0
|
340 MainWindow::~MainWindow()
|
Chris@0
|
341 {
|
Chris@438
|
342 // SVDEBUG << "MainWindow::~MainWindow" << endl;
|
Chris@162
|
343 delete m_keyReference;
|
Chris@504
|
344 delete m_activityLog;
|
Chris@163
|
345 delete m_preferencesDialog;
|
Chris@219
|
346 delete m_layerTreeDialog;
|
Chris@573
|
347 delete m_versionTester;
|
Chris@662
|
348 delete m_surveyer;
|
Chris@0
|
349 Profiles::getInstance()->dump();
|
Chris@438
|
350 // SVDEBUG << "MainWindow::~MainWindow finishing" << endl;
|
Chris@0
|
351 }
|
Chris@0
|
352
|
Chris@81
|
353 void
|
Chris@0
|
354 MainWindow::setupMenus()
|
Chris@0
|
355 {
|
Chris@0
|
356 if (!m_mainMenusCreated) {
|
Chris@0
|
357 m_rightButtonMenu = new QMenu();
|
Chris@104
|
358
|
Chris@104
|
359 // No -- we don't want tear-off enabled on the right-button
|
Chris@104
|
360 // menu. If it is enabled, then simply right-clicking and
|
Chris@104
|
361 // releasing will pop up the menu, activate the tear-off, and
|
Chris@104
|
362 // leave the torn-off menu window in front of the main window.
|
Chris@104
|
363 // That isn't desirable. I'm not sure it ever would be, in a
|
Chris@104
|
364 // context menu -- perhaps technically a Qt bug?
|
Chris@104
|
365 // m_rightButtonMenu->setTearOffEnabled(true);
|
Chris@0
|
366 }
|
Chris@0
|
367
|
Chris@211
|
368 if (m_rightButtonTransformsMenu) {
|
Chris@211
|
369 m_rightButtonTransformsMenu->clear();
|
Chris@34
|
370 } else {
|
Chris@211
|
371 m_rightButtonTransformsMenu = m_rightButtonMenu->addMenu(tr("&Transform"));
|
Chris@211
|
372 m_rightButtonTransformsMenu->setTearOffEnabled(true);
|
Chris@34
|
373 m_rightButtonMenu->addSeparator();
|
Chris@34
|
374 }
|
Chris@34
|
375
|
Chris@346
|
376 // This will be created (if not found) or cleared (if found) in
|
Chris@346
|
377 // setupPaneAndLayerMenus, but we want to ensure it's created
|
Chris@346
|
378 // sooner so it can go nearer the top of the right button menu
|
Chris@346
|
379 if (m_rightButtonLayerMenu) {
|
Chris@346
|
380 m_rightButtonLayerMenu->clear();
|
Chris@346
|
381 } else {
|
Chris@346
|
382 m_rightButtonLayerMenu = m_rightButtonMenu->addMenu(tr("&Layer"));
|
Chris@346
|
383 m_rightButtonLayerMenu->setTearOffEnabled(true);
|
Chris@346
|
384 m_rightButtonMenu->addSeparator();
|
Chris@346
|
385 }
|
Chris@346
|
386
|
Chris@0
|
387 if (!m_mainMenusCreated) {
|
Chris@0
|
388 CommandHistory::getInstance()->registerMenu(m_rightButtonMenu);
|
Chris@0
|
389 m_rightButtonMenu->addSeparator();
|
Chris@66
|
390 }
|
Chris@66
|
391
|
Chris@66
|
392 setupFileMenu();
|
Chris@66
|
393 setupEditMenu();
|
Chris@66
|
394 setupViewMenu();
|
Chris@66
|
395 setupPaneAndLayerMenus();
|
Chris@211
|
396 setupTransformsMenu();
|
Chris@66
|
397
|
Chris@66
|
398 m_mainMenusCreated = true;
|
Chris@66
|
399 }
|
Chris@66
|
400
|
Chris@66
|
401 void
|
Chris@489
|
402 MainWindow::goFullScreen()
|
Chris@489
|
403 {
|
Chris@588
|
404 if (m_viewManager->getZoomWheelsEnabled()) {
|
Chris@588
|
405 // The wheels seem to end up in the wrong place in full-screen mode
|
Chris@588
|
406 toggleZoomWheels();
|
Chris@588
|
407 }
|
Chris@588
|
408
|
Chris@492
|
409 QWidget *ps = m_mainScroll->takeWidget();
|
Chris@492
|
410 ps->setParent(0);
|
Chris@494
|
411
|
Chris@494
|
412 QShortcut *sc;
|
Chris@494
|
413
|
Chris@494
|
414 sc = new QShortcut(QKeySequence("Esc"), ps);
|
Chris@494
|
415 connect(sc, SIGNAL(activated()), this, SLOT(endFullScreen()));
|
Chris@494
|
416
|
Chris@494
|
417 sc = new QShortcut(QKeySequence("F11"), ps);
|
Chris@494
|
418 connect(sc, SIGNAL(activated()), this, SLOT(endFullScreen()));
|
Chris@494
|
419
|
Chris@494
|
420 QAction *acts[] = {
|
Chris@494
|
421 m_playAction, m_zoomInAction, m_zoomOutAction, m_zoomFitAction,
|
Chris@494
|
422 m_scrollLeftAction, m_scrollRightAction, m_showPropertyBoxesAction
|
Chris@494
|
423 };
|
Chris@494
|
424
|
Chris@705
|
425 for (int i = 0; i < int(sizeof(acts)/sizeof(acts[0])); ++i) {
|
Chris@494
|
426 sc = new QShortcut(acts[i]->shortcut(), ps);
|
Chris@494
|
427 connect(sc, SIGNAL(activated()), acts[i], SLOT(trigger()));
|
Chris@494
|
428 }
|
Chris@494
|
429
|
Chris@492
|
430 ps->showFullScreen();
|
Chris@492
|
431 }
|
Chris@492
|
432
|
Chris@492
|
433 void
|
Chris@492
|
434 MainWindow::endFullScreen()
|
Chris@492
|
435 {
|
Chris@494
|
436 // these were only created in goFullScreen:
|
Chris@494
|
437 QObjectList cl = m_paneStack->children();
|
Chris@494
|
438 foreach (QObject *o, cl) {
|
Chris@494
|
439 QShortcut *sc = qobject_cast<QShortcut *>(o);
|
Chris@494
|
440 if (sc) delete sc;
|
Chris@494
|
441 }
|
Chris@494
|
442
|
Chris@588
|
443 m_paneStack->showNormal();
|
Chris@492
|
444 m_mainScroll->setWidget(m_paneStack);
|
Chris@489
|
445 }
|
Chris@489
|
446
|
Chris@489
|
447 void
|
Chris@66
|
448 MainWindow::setupFileMenu()
|
Chris@66
|
449 {
|
Chris@66
|
450 if (m_mainMenusCreated) return;
|
Chris@66
|
451
|
Chris@66
|
452 QMenu *menu = menuBar()->addMenu(tr("&File"));
|
Chris@97
|
453 menu->setTearOffEnabled(true);
|
Chris@66
|
454 QToolBar *toolbar = addToolBar(tr("File Toolbar"));
|
Chris@66
|
455
|
Chris@162
|
456 m_keyReference->setCategory(tr("File and Session Management"));
|
Chris@162
|
457
|
Chris@168
|
458 IconLoader il;
|
Chris@168
|
459
|
Chris@168
|
460 QIcon icon = il.load("filenew");
|
Chris@168
|
461 icon.addPixmap(il.loadPixmap("filenew-22"));
|
Chris@66
|
462 QAction *action = new QAction(icon, tr("&New Session"), this);
|
Chris@66
|
463 action->setShortcut(tr("Ctrl+N"));
|
Chris@518
|
464 action->setStatusTip(tr("Abandon the current %1 session and start a new one").arg(QApplication::applicationName()));
|
Chris@66
|
465 connect(action, SIGNAL(triggered()), this, SLOT(newSession()));
|
Chris@162
|
466 m_keyReference->registerShortcut(action);
|
Chris@66
|
467 menu->addAction(action);
|
Chris@66
|
468 toolbar->addAction(action);
|
Chris@518
|
469
|
Chris@168
|
470 icon = il.load("fileopen");
|
Chris@168
|
471 icon.addPixmap(il.loadPixmap("fileopen-22"));
|
Chris@66
|
472 action = new QAction(icon, tr("&Open..."), this);
|
Chris@418
|
473 action->setShortcut(tr("Ctrl+O"));
|
Chris@66
|
474 action->setStatusTip(tr("Open a session file, audio file, or layer"));
|
Chris@66
|
475 connect(action, SIGNAL(triggered()), this, SLOT(openSomething()));
|
Chris@705
|
476 m_keyReference->registerShortcut(action);
|
Chris@66
|
477 toolbar->addAction(action);
|
Chris@418
|
478 menu->addAction(action);
|
Chris@418
|
479
|
Chris@418
|
480 // We want this one to go on the toolbar now, if we add it at all,
|
Chris@418
|
481 // but on the menu later
|
Chris@418
|
482 QAction *iaction = new QAction(tr("&Import More Audio..."), this);
|
Chris@418
|
483 iaction->setShortcut(tr("Ctrl+I"));
|
Chris@418
|
484 iaction->setStatusTip(tr("Import an extra audio file into a new pane"));
|
Chris@418
|
485 connect(iaction, SIGNAL(triggered()), this, SLOT(importMoreAudio()));
|
Chris@418
|
486 connect(this, SIGNAL(canImportMoreAudio(bool)), iaction, SLOT(setEnabled(bool)));
|
Chris@418
|
487 m_keyReference->registerShortcut(iaction);
|
Chris@418
|
488
|
Chris@508
|
489 // We want this one to go on the toolbar now, if we add it at all,
|
Chris@508
|
490 // but on the menu later
|
Chris@508
|
491 QAction *raction = new QAction(tr("Replace &Main Audio..."), this);
|
Chris@508
|
492 raction->setStatusTip(tr("Replace the main audio file of the session with a different file"));
|
Chris@508
|
493 connect(raction, SIGNAL(triggered()), this, SLOT(replaceMainAudio()));
|
Chris@508
|
494 connect(this, SIGNAL(canReplaceMainAudio(bool)), raction, SLOT(setEnabled(bool)));
|
Chris@508
|
495
|
Chris@418
|
496 action = new QAction(tr("Open Lo&cation..."), this);
|
Chris@418
|
497 action->setShortcut(tr("Ctrl+Shift+O"));
|
Chris@418
|
498 action->setStatusTip(tr("Open or import a file from a remote URL"));
|
Chris@418
|
499 connect(action, SIGNAL(triggered()), this, SLOT(openLocation()));
|
Chris@418
|
500 m_keyReference->registerShortcut(action);
|
Chris@418
|
501 menu->addAction(action);
|
Chris@418
|
502
|
Chris@420
|
503 m_recentFilesMenu = menu->addMenu(tr("Open &Recent"));
|
Chris@418
|
504 m_recentFilesMenu->setTearOffEnabled(true);
|
Chris@418
|
505 setupRecentFilesMenu();
|
Chris@418
|
506 connect(&m_recentFiles, SIGNAL(recentChanged()),
|
Chris@418
|
507 this, SLOT(setupRecentFilesMenu()));
|
Chris@418
|
508
|
Chris@418
|
509 menu->addSeparator();
|
Chris@415
|
510
|
Chris@168
|
511 icon = il.load("filesave");
|
Chris@168
|
512 icon.addPixmap(il.loadPixmap("filesave-22"));
|
Chris@66
|
513 action = new QAction(icon, tr("&Save Session"), this);
|
Chris@66
|
514 action->setShortcut(tr("Ctrl+S"));
|
Chris@518
|
515 action->setStatusTip(tr("Save the current session into a %1 session file").arg(QApplication::applicationName()));
|
Chris@66
|
516 connect(action, SIGNAL(triggered()), this, SLOT(saveSession()));
|
Chris@66
|
517 connect(this, SIGNAL(canSave(bool)), action, SLOT(setEnabled(bool)));
|
Chris@162
|
518 m_keyReference->registerShortcut(action);
|
Chris@66
|
519 menu->addAction(action);
|
Chris@66
|
520 toolbar->addAction(action);
|
Chris@0
|
521
|
Chris@168
|
522 icon = il.load("filesaveas");
|
Chris@168
|
523 icon.addPixmap(il.loadPixmap("filesaveas-22"));
|
Chris@66
|
524 action = new QAction(icon, tr("Save Session &As..."), this);
|
Chris@336
|
525 action->setShortcut(tr("Ctrl+Shift+S"));
|
Chris@518
|
526 action->setStatusTip(tr("Save the current session into a new %1 session file").arg(QApplication::applicationName()));
|
Chris@66
|
527 connect(action, SIGNAL(triggered()), this, SLOT(saveSessionAs()));
|
Chris@66
|
528 menu->addAction(action);
|
Chris@66
|
529 toolbar->addAction(action);
|
Chris@66
|
530
|
Chris@66
|
531 menu->addSeparator();
|
Chris@66
|
532
|
Chris@418
|
533 /*
|
Chris@168
|
534 icon = il.load("fileopenaudio");
|
Chris@138
|
535 action = new QAction(icon, tr("&Import Audio File..."), this);
|
Chris@66
|
536 action->setShortcut(tr("Ctrl+I"));
|
Chris@66
|
537 action->setStatusTip(tr("Import an existing audio file"));
|
Chris@66
|
538 connect(action, SIGNAL(triggered()), this, SLOT(importAudio()));
|
Chris@162
|
539 m_keyReference->registerShortcut(action);
|
Chris@66
|
540 menu->addAction(action);
|
Chris@418
|
541 */
|
Chris@418
|
542
|
Chris@508
|
543 // the Replace action we made earlier
|
Chris@508
|
544 menu->addAction(raction);
|
Chris@508
|
545
|
Chris@418
|
546 // the Import action we made earlier
|
Chris@418
|
547 menu->addAction(iaction);
|
Chris@66
|
548
|
Chris@66
|
549 action = new QAction(tr("&Export Audio File..."), this);
|
Chris@66
|
550 action->setStatusTip(tr("Export selection as an audio file"));
|
Chris@66
|
551 connect(action, SIGNAL(triggered()), this, SLOT(exportAudio()));
|
Chris@66
|
552 connect(this, SIGNAL(canExportAudio(bool)), action, SLOT(setEnabled(bool)));
|
Chris@66
|
553 menu->addAction(action);
|
Chris@66
|
554
|
Chris@674
|
555 action = new QAction(tr("Export Audio Data..."), this);
|
Chris@631
|
556 action->setStatusTip(tr("Export audio from selection into a data file"));
|
Chris@631
|
557 connect(action, SIGNAL(triggered()), this, SLOT(exportAudioData()));
|
Chris@631
|
558 connect(this, SIGNAL(canExportAudio(bool)), action, SLOT(setEnabled(bool)));
|
Chris@631
|
559 menu->addAction(action);
|
Chris@631
|
560
|
Chris@66
|
561 menu->addSeparator();
|
Chris@66
|
562
|
Chris@66
|
563 action = new QAction(tr("Import Annotation &Layer..."), this);
|
Chris@66
|
564 action->setShortcut(tr("Ctrl+L"));
|
Chris@66
|
565 action->setStatusTip(tr("Import layer data from an existing file"));
|
Chris@66
|
566 connect(action, SIGNAL(triggered()), this, SLOT(importLayer()));
|
Chris@66
|
567 connect(this, SIGNAL(canImportLayer(bool)), action, SLOT(setEnabled(bool)));
|
Chris@162
|
568 m_keyReference->registerShortcut(action);
|
Chris@66
|
569 menu->addAction(action);
|
Chris@66
|
570
|
Chris@66
|
571 action = new QAction(tr("Export Annotation Layer..."), this);
|
Chris@66
|
572 action->setStatusTip(tr("Export layer data to a file"));
|
Chris@66
|
573 connect(action, SIGNAL(triggered()), this, SLOT(exportLayer()));
|
Chris@66
|
574 connect(this, SIGNAL(canExportLayer(bool)), action, SLOT(setEnabled(bool)));
|
Chris@66
|
575 menu->addAction(action);
|
Chris@66
|
576
|
Chris@66
|
577 menu->addSeparator();
|
Chris@86
|
578
|
Chris@121
|
579 action = new QAction(tr("Export Image File..."), this);
|
Chris@121
|
580 action->setStatusTip(tr("Export a single pane to an image file"));
|
Chris@121
|
581 connect(action, SIGNAL(triggered()), this, SLOT(exportImage()));
|
Chris@121
|
582 connect(this, SIGNAL(canExportImage(bool)), action, SLOT(setEnabled(bool)));
|
Chris@121
|
583 menu->addAction(action);
|
Chris@121
|
584
|
Chris@121
|
585 menu->addSeparator();
|
Chris@121
|
586
|
Chris@435
|
587 QString templatesMenuLabel = tr("Apply Session Template");
|
Chris@425
|
588 m_templatesMenu = menu->addMenu(templatesMenuLabel);
|
Chris@425
|
589 m_templatesMenu->setTearOffEnabled(true);
|
Chris@436
|
590 // We need to have a main model for this option to be useful:
|
Chris@436
|
591 // canExportAudio captures that
|
Chris@436
|
592 connect(this, SIGNAL(canExportAudio(bool)), m_templatesMenu, SLOT(setEnabled(bool)));
|
Chris@436
|
593
|
Chris@436
|
594 // Set up the menu in a moment, after m_manageTemplatesAction constructed
|
Chris@435
|
595
|
Chris@435
|
596 action = new QAction(tr("Export Session as Template..."), this);
|
Chris@435
|
597 connect(action, SIGNAL(triggered()), this, SLOT(saveSessionAsTemplate()));
|
Chris@436
|
598 // We need to have something in the session for this to be useful:
|
Chris@436
|
599 // canDeleteCurrentLayer captures that
|
Chris@436
|
600 connect(this, SIGNAL(canExportAudio(bool)), action, SLOT(setEnabled(bool)));
|
Chris@435
|
601 menu->addAction(action);
|
Chris@435
|
602
|
Chris@436
|
603 m_manageTemplatesAction = new QAction(tr("Manage Exported Templates"), this);
|
Chris@436
|
604 connect(m_manageTemplatesAction, SIGNAL(triggered()), this, SLOT(manageSavedTemplates()));
|
Chris@436
|
605 menu->addAction(m_manageTemplatesAction);
|
Chris@436
|
606
|
Chris@436
|
607 setupTemplatesMenu();
|
Chris@425
|
608
|
Chris@66
|
609 action = new QAction(tr("&Preferences..."), this);
|
Chris@66
|
610 action->setStatusTip(tr("Adjust the application preferences"));
|
Chris@66
|
611 connect(action, SIGNAL(triggered()), this, SLOT(preferences()));
|
Chris@66
|
612 menu->addAction(action);
|
Chris@0
|
613
|
Chris@66
|
614 menu->addSeparator();
|
Chris@168
|
615 action = new QAction(il.load("exit"),
|
Chris@66
|
616 tr("&Quit"), this);
|
Chris@66
|
617 action->setShortcut(tr("Ctrl+Q"));
|
Chris@518
|
618 action->setStatusTip(tr("Exit %1").arg(QApplication::applicationName()));
|
Chris@500
|
619 connect(action, SIGNAL(triggered()), qApp, SLOT(closeAllWindows()));
|
Chris@162
|
620 m_keyReference->registerShortcut(action);
|
Chris@66
|
621 menu->addAction(action);
|
Chris@66
|
622 }
|
Chris@66
|
623
|
Chris@66
|
624 void
|
Chris@66
|
625 MainWindow::setupEditMenu()
|
Chris@66
|
626 {
|
Chris@66
|
627 if (m_mainMenusCreated) return;
|
Chris@66
|
628
|
Chris@66
|
629 QMenu *menu = menuBar()->addMenu(tr("&Edit"));
|
Chris@97
|
630 menu->setTearOffEnabled(true);
|
Chris@66
|
631 CommandHistory::getInstance()->registerMenu(menu);
|
Chris@66
|
632
|
Chris@162
|
633 m_keyReference->setCategory(tr("Editing"));
|
Chris@162
|
634
|
Chris@66
|
635 menu->addSeparator();
|
Chris@66
|
636
|
Chris@168
|
637 IconLoader il;
|
Chris@168
|
638
|
Chris@168
|
639 QAction *action = new QAction(il.load("editcut"),
|
Chris@66
|
640 tr("Cu&t"), this);
|
Chris@66
|
641 action->setShortcut(tr("Ctrl+X"));
|
Chris@90
|
642 action->setStatusTip(tr("Cut the selection from the current layer to the clipboard"));
|
Chris@66
|
643 connect(action, SIGNAL(triggered()), this, SLOT(cut()));
|
Chris@66
|
644 connect(this, SIGNAL(canEditSelection(bool)), action, SLOT(setEnabled(bool)));
|
Chris@162
|
645 m_keyReference->registerShortcut(action);
|
Chris@66
|
646 menu->addAction(action);
|
Chris@66
|
647 m_rightButtonMenu->addAction(action);
|
Chris@66
|
648
|
Chris@168
|
649 action = new QAction(il.load("editcopy"),
|
Chris@66
|
650 tr("&Copy"), this);
|
Chris@66
|
651 action->setShortcut(tr("Ctrl+C"));
|
Chris@90
|
652 action->setStatusTip(tr("Copy the selection from the current layer to the clipboard"));
|
Chris@66
|
653 connect(action, SIGNAL(triggered()), this, SLOT(copy()));
|
Chris@66
|
654 connect(this, SIGNAL(canEditSelection(bool)), action, SLOT(setEnabled(bool)));
|
Chris@162
|
655 m_keyReference->registerShortcut(action);
|
Chris@66
|
656 menu->addAction(action);
|
Chris@66
|
657 m_rightButtonMenu->addAction(action);
|
Chris@66
|
658
|
Chris@168
|
659 action = new QAction(il.load("editpaste"),
|
Chris@66
|
660 tr("&Paste"), this);
|
Chris@66
|
661 action->setShortcut(tr("Ctrl+V"));
|
Chris@90
|
662 action->setStatusTip(tr("Paste from the clipboard to the current layer"));
|
Chris@66
|
663 connect(action, SIGNAL(triggered()), this, SLOT(paste()));
|
Chris@66
|
664 connect(this, SIGNAL(canPaste(bool)), action, SLOT(setEnabled(bool)));
|
Chris@162
|
665 m_keyReference->registerShortcut(action);
|
Chris@66
|
666 menu->addAction(action);
|
Chris@66
|
667 m_rightButtonMenu->addAction(action);
|
Chris@66
|
668
|
Chris@395
|
669 action = new QAction(tr("Paste at Playback Position"), this);
|
Chris@395
|
670 action->setShortcut(tr("Ctrl+Shift+V"));
|
Chris@395
|
671 action->setStatusTip(tr("Paste from the clipboard to the current layer, placing the first item at the playback position"));
|
Chris@395
|
672 connect(action, SIGNAL(triggered()), this, SLOT(pasteAtPlaybackPosition()));
|
Chris@395
|
673 connect(this, SIGNAL(canPaste(bool)), action, SLOT(setEnabled(bool)));
|
Chris@395
|
674 m_keyReference->registerShortcut(action);
|
Chris@395
|
675 menu->addAction(action);
|
Chris@395
|
676 m_rightButtonMenu->addAction(action);
|
Chris@395
|
677
|
Chris@164
|
678 m_deleteSelectedAction = new QAction(tr("&Delete Selected Items"), this);
|
Chris@164
|
679 m_deleteSelectedAction->setShortcut(tr("Del"));
|
Chris@164
|
680 m_deleteSelectedAction->setStatusTip(tr("Delete items in current selection from the current layer"));
|
Chris@164
|
681 connect(m_deleteSelectedAction, SIGNAL(triggered()), this, SLOT(deleteSelected()));
|
Chris@164
|
682 connect(this, SIGNAL(canDeleteSelection(bool)), m_deleteSelectedAction, SLOT(setEnabled(bool)));
|
Chris@164
|
683 m_keyReference->registerShortcut(m_deleteSelectedAction);
|
Chris@164
|
684 menu->addAction(m_deleteSelectedAction);
|
Chris@164
|
685 m_rightButtonMenu->addAction(m_deleteSelectedAction);
|
Chris@66
|
686
|
Chris@66
|
687 menu->addSeparator();
|
Chris@66
|
688 m_rightButtonMenu->addSeparator();
|
Chris@162
|
689
|
Chris@162
|
690 m_keyReference->setCategory(tr("Selection"));
|
Chris@162
|
691
|
Chris@66
|
692 action = new QAction(tr("Select &All"), this);
|
Chris@66
|
693 action->setShortcut(tr("Ctrl+A"));
|
Chris@90
|
694 action->setStatusTip(tr("Select the whole duration of the current session"));
|
Chris@66
|
695 connect(action, SIGNAL(triggered()), this, SLOT(selectAll()));
|
Chris@66
|
696 connect(this, SIGNAL(canSelect(bool)), action, SLOT(setEnabled(bool)));
|
Chris@162
|
697 m_keyReference->registerShortcut(action);
|
Chris@66
|
698 menu->addAction(action);
|
Chris@66
|
699 m_rightButtonMenu->addAction(action);
|
Chris@0
|
700
|
Chris@66
|
701 action = new QAction(tr("Select &Visible Range"), this);
|
Chris@66
|
702 action->setShortcut(tr("Ctrl+Shift+A"));
|
Chris@90
|
703 action->setStatusTip(tr("Select the time range corresponding to the current window width"));
|
Chris@66
|
704 connect(action, SIGNAL(triggered()), this, SLOT(selectVisible()));
|
Chris@66
|
705 connect(this, SIGNAL(canSelect(bool)), action, SLOT(setEnabled(bool)));
|
Chris@162
|
706 m_keyReference->registerShortcut(action);
|
Chris@66
|
707 menu->addAction(action);
|
Chris@0
|
708
|
Chris@66
|
709 action = new QAction(tr("Select to &Start"), this);
|
Chris@66
|
710 action->setShortcut(tr("Shift+Left"));
|
Chris@90
|
711 action->setStatusTip(tr("Select from the start of the session to the current playback position"));
|
Chris@66
|
712 connect(action, SIGNAL(triggered()), this, SLOT(selectToStart()));
|
Chris@66
|
713 connect(this, SIGNAL(canSelect(bool)), action, SLOT(setEnabled(bool)));
|
Chris@162
|
714 m_keyReference->registerShortcut(action);
|
Chris@66
|
715 menu->addAction(action);
|
Chris@0
|
716
|
Chris@66
|
717 action = new QAction(tr("Select to &End"), this);
|
Chris@66
|
718 action->setShortcut(tr("Shift+Right"));
|
Chris@90
|
719 action->setStatusTip(tr("Select from the current playback position to the end of the session"));
|
Chris@66
|
720 connect(action, SIGNAL(triggered()), this, SLOT(selectToEnd()));
|
Chris@66
|
721 connect(this, SIGNAL(canSelect(bool)), action, SLOT(setEnabled(bool)));
|
Chris@162
|
722 m_keyReference->registerShortcut(action);
|
Chris@66
|
723 menu->addAction(action);
|
Chris@66
|
724
|
Chris@66
|
725 action = new QAction(tr("C&lear Selection"), this);
|
Chris@66
|
726 action->setShortcut(tr("Esc"));
|
Chris@90
|
727 action->setStatusTip(tr("Clear the selection"));
|
Chris@66
|
728 connect(action, SIGNAL(triggered()), this, SLOT(clearSelection()));
|
Chris@66
|
729 connect(this, SIGNAL(canClearSelection(bool)), action, SLOT(setEnabled(bool)));
|
Chris@162
|
730 m_keyReference->registerShortcut(action);
|
Chris@66
|
731 menu->addAction(action);
|
Chris@66
|
732 m_rightButtonMenu->addAction(action);
|
Chris@66
|
733
|
Chris@66
|
734 menu->addSeparator();
|
Chris@66
|
735
|
Chris@162
|
736 m_keyReference->setCategory(tr("Tapping Time Instants"));
|
Chris@162
|
737
|
Chris@66
|
738 action = new QAction(tr("&Insert Instant at Playback Position"), this);
|
Chris@66
|
739 action->setShortcut(tr("Enter"));
|
Chris@90
|
740 action->setStatusTip(tr("Insert a new time instant at the current playback position, in a new layer if necessary"));
|
Chris@66
|
741 connect(action, SIGNAL(triggered()), this, SLOT(insertInstant()));
|
Chris@66
|
742 connect(this, SIGNAL(canInsertInstant(bool)), action, SLOT(setEnabled(bool)));
|
Chris@162
|
743 m_keyReference->registerShortcut(action);
|
Chris@66
|
744 menu->addAction(action);
|
Chris@66
|
745
|
Chris@162
|
746 // Laptop shortcut (no keypad Enter key)
|
Chris@162
|
747 QString shortcut(tr(";"));
|
Chris@162
|
748 connect(new QShortcut(shortcut, this), SIGNAL(activated()),
|
Chris@162
|
749 this, SLOT(insertInstant()));
|
Chris@162
|
750 m_keyReference->registerAlternativeShortcut(action, shortcut);
|
Chris@162
|
751
|
Chris@81
|
752 action = new QAction(tr("Insert Instants at Selection &Boundaries"), this);
|
Chris@81
|
753 action->setShortcut(tr("Shift+Enter"));
|
Chris@163
|
754 action->setStatusTip(tr("Insert new time instants at the start and end of the current selected regions, in a new layer if necessary"));
|
Chris@81
|
755 connect(action, SIGNAL(triggered()), this, SLOT(insertInstantsAtBoundaries()));
|
Chris@81
|
756 connect(this, SIGNAL(canInsertInstantsAtBoundaries(bool)), action, SLOT(setEnabled(bool)));
|
Chris@162
|
757 m_keyReference->registerShortcut(action);
|
Chris@81
|
758 menu->addAction(action);
|
Chris@189
|
759
|
Chris@338
|
760 action = new QAction(tr("Insert Item at Selection"), this);
|
Chris@338
|
761 action->setShortcut(tr("Ctrl+Shift+Enter"));
|
Chris@338
|
762 action->setStatusTip(tr("Insert a new note or region item corresponding to the current selection"));
|
Chris@338
|
763 connect(action, SIGNAL(triggered()), this, SLOT(insertItemAtSelection()));
|
Chris@338
|
764 connect(this, SIGNAL(canInsertItemAtSelection(bool)), action, SLOT(setEnabled(bool)));
|
Chris@338
|
765 m_keyReference->registerShortcut(action);
|
Chris@338
|
766 menu->addAction(action);
|
Chris@338
|
767
|
Chris@338
|
768 menu->addSeparator();
|
Chris@338
|
769
|
Chris@190
|
770 QMenu *numberingMenu = menu->addMenu(tr("Number New Instants with"));
|
Chris@225
|
771 numberingMenu->setTearOffEnabled(true);
|
Chris@189
|
772 QActionGroup *numberingGroup = new QActionGroup(this);
|
Chris@189
|
773
|
Chris@189
|
774 Labeller::TypeNameMap types = m_labeller->getTypeNames();
|
Chris@189
|
775 for (Labeller::TypeNameMap::iterator i = types.begin(); i != types.end(); ++i) {
|
Chris@190
|
776
|
Chris@190
|
777 if (i->first == Labeller::ValueFromLabel ||
|
Chris@190
|
778 i->first == Labeller::ValueFromExistingNeighbour) continue;
|
Chris@190
|
779
|
Chris@189
|
780 action = new QAction(i->second, this);
|
Chris@189
|
781 connect(action, SIGNAL(triggered()), this, SLOT(setInstantsNumbering()));
|
Chris@189
|
782 action->setCheckable(true);
|
Chris@189
|
783 action->setChecked(m_labeller->getType() == i->first);
|
Chris@189
|
784 numberingGroup->addAction(action);
|
Chris@189
|
785 numberingMenu->addAction(action);
|
Chris@189
|
786 m_numberingActions[action] = (int)i->first;
|
Chris@190
|
787
|
Chris@190
|
788 if (i->first == Labeller::ValueFromTwoLevelCounter) {
|
Chris@192
|
789
|
Chris@190
|
790 QMenu *cycleMenu = numberingMenu->addMenu(tr("Cycle size"));
|
Chris@190
|
791 QActionGroup *cycleGroup = new QActionGroup(this);
|
Chris@190
|
792
|
Chris@229
|
793 int cycles[] = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 16 };
|
Chris@200
|
794 for (int i = 0; i < int(sizeof(cycles)/sizeof(cycles[0])); ++i) {
|
Chris@190
|
795 action = new QAction(QString("%1").arg(cycles[i]), this);
|
Chris@190
|
796 connect(action, SIGNAL(triggered()), this, SLOT(setInstantsCounterCycle()));
|
Chris@190
|
797 action->setCheckable(true);
|
Chris@190
|
798 action->setChecked(cycles[i] == m_labeller->getCounterCycleSize());
|
Chris@190
|
799 cycleGroup->addAction(action);
|
Chris@190
|
800 cycleMenu->addAction(action);
|
Chris@190
|
801 }
|
Chris@190
|
802 }
|
Chris@190
|
803
|
Chris@190
|
804 if (i->first == Labeller::ValueNone ||
|
Chris@190
|
805 i->first == Labeller::ValueFromTwoLevelCounter ||
|
Chris@190
|
806 i->first == Labeller::ValueFromRealTime) {
|
Chris@190
|
807 numberingMenu->addSeparator();
|
Chris@190
|
808 }
|
Chris@189
|
809 }
|
Chris@189
|
810
|
Chris@597
|
811 action = new QAction(tr("Reset Numbering Counters"), this);
|
Chris@597
|
812 action->setStatusTip(tr("Reset to 1 all the counters used for counter-based labelling"));
|
Chris@597
|
813 connect(action, SIGNAL(triggered()), this, SLOT(resetInstantsCounters()));
|
Chris@597
|
814 connect(this, SIGNAL(replacedDocument()), action, SLOT(trigger()));
|
Chris@597
|
815 menu->addAction(action);
|
Chris@597
|
816
|
Chris@241
|
817 action = new QAction(tr("Set Numbering Counters..."), this);
|
Chris@241
|
818 action->setStatusTip(tr("Set the counters used for counter-based labelling"));
|
Chris@597
|
819 connect(action, SIGNAL(triggered()), this, SLOT(setInstantsCounters()));
|
Chris@241
|
820 menu->addAction(action);
|
Chris@241
|
821
|
Chris@241
|
822 action = new QAction(tr("Renumber Selected Instants"), this);
|
Chris@241
|
823 action->setStatusTip(tr("Renumber the selected instants using the current labelling scheme"));
|
Chris@189
|
824 connect(action, SIGNAL(triggered()), this, SLOT(renumberInstants()));
|
Chris@189
|
825 connect(this, SIGNAL(canRenumberInstants(bool)), action, SLOT(setEnabled(bool)));
|
Chris@189
|
826 // m_keyReference->registerShortcut(action);
|
Chris@189
|
827 menu->addAction(action);
|
Chris@66
|
828 }
|
Chris@66
|
829
|
Chris@66
|
830 void
|
Chris@66
|
831 MainWindow::setupViewMenu()
|
Chris@66
|
832 {
|
Chris@66
|
833 if (m_mainMenusCreated) return;
|
Chris@66
|
834
|
Chris@168
|
835 IconLoader il;
|
Chris@168
|
836
|
Chris@90
|
837 QAction *action = 0;
|
Chris@90
|
838
|
Chris@162
|
839 m_keyReference->setCategory(tr("Panning and Navigation"));
|
Chris@162
|
840
|
Chris@66
|
841 QMenu *menu = menuBar()->addMenu(tr("&View"));
|
Chris@97
|
842 menu->setTearOffEnabled(true);
|
Chris@494
|
843 m_scrollLeftAction = new QAction(tr("Scroll &Left"), this);
|
Chris@494
|
844 m_scrollLeftAction->setShortcut(tr("Left"));
|
Chris@494
|
845 m_scrollLeftAction->setStatusTip(tr("Scroll the current pane to the left"));
|
Chris@494
|
846 connect(m_scrollLeftAction, SIGNAL(triggered()), this, SLOT(scrollLeft()));
|
Chris@494
|
847 connect(this, SIGNAL(canScroll(bool)), m_scrollLeftAction, SLOT(setEnabled(bool)));
|
Chris@494
|
848 m_keyReference->registerShortcut(m_scrollLeftAction);
|
Chris@494
|
849 menu->addAction(m_scrollLeftAction);
|
Chris@0
|
850
|
Chris@494
|
851 m_scrollRightAction = new QAction(tr("Scroll &Right"), this);
|
Chris@494
|
852 m_scrollRightAction->setShortcut(tr("Right"));
|
Chris@494
|
853 m_scrollRightAction->setStatusTip(tr("Scroll the current pane to the right"));
|
Chris@494
|
854 connect(m_scrollRightAction, SIGNAL(triggered()), this, SLOT(scrollRight()));
|
Chris@494
|
855 connect(this, SIGNAL(canScroll(bool)), m_scrollRightAction, SLOT(setEnabled(bool)));
|
Chris@494
|
856 m_keyReference->registerShortcut(m_scrollRightAction);
|
Chris@494
|
857 menu->addAction(m_scrollRightAction);
|
Chris@0
|
858
|
Chris@90
|
859 action = new QAction(tr("&Jump Left"), this);
|
Chris@66
|
860 action->setShortcut(tr("Ctrl+Left"));
|
Chris@66
|
861 action->setStatusTip(tr("Scroll the current pane a big step to the left"));
|
Chris@66
|
862 connect(action, SIGNAL(triggered()), this, SLOT(jumpLeft()));
|
Chris@66
|
863 connect(this, SIGNAL(canScroll(bool)), action, SLOT(setEnabled(bool)));
|
Chris@162
|
864 m_keyReference->registerShortcut(action);
|
Chris@66
|
865 menu->addAction(action);
|
Chris@0
|
866
|
Chris@90
|
867 action = new QAction(tr("J&ump Right"), this);
|
Chris@66
|
868 action->setShortcut(tr("Ctrl+Right"));
|
Chris@66
|
869 action->setStatusTip(tr("Scroll the current pane a big step to the right"));
|
Chris@66
|
870 connect(action, SIGNAL(triggered()), this, SLOT(jumpRight()));
|
Chris@66
|
871 connect(this, SIGNAL(canScroll(bool)), action, SLOT(setEnabled(bool)));
|
Chris@162
|
872 m_keyReference->registerShortcut(action);
|
Chris@66
|
873 menu->addAction(action);
|
Chris@66
|
874
|
Chris@308
|
875 action = new QAction(tr("Peek Left"), this);
|
Chris@308
|
876 action->setShortcut(tr("Alt+Left"));
|
Chris@308
|
877 action->setStatusTip(tr("Scroll the current pane to the left without moving the playback cursor or other panes"));
|
Chris@308
|
878 connect(action, SIGNAL(triggered()), this, SLOT(peekLeft()));
|
Chris@308
|
879 connect(this, SIGNAL(canScroll(bool)), action, SLOT(setEnabled(bool)));
|
Chris@308
|
880 m_keyReference->registerShortcut(action);
|
Chris@308
|
881 menu->addAction(action);
|
Chris@308
|
882
|
Chris@308
|
883 action = new QAction(tr("Peek Right"), this);
|
Chris@308
|
884 action->setShortcut(tr("Alt+Right"));
|
Chris@308
|
885 action->setStatusTip(tr("Scroll the current pane to the right without moving the playback cursor or other panes"));
|
Chris@308
|
886 connect(action, SIGNAL(triggered()), this, SLOT(peekRight()));
|
Chris@308
|
887 connect(this, SIGNAL(canScroll(bool)), action, SLOT(setEnabled(bool)));
|
Chris@308
|
888 m_keyReference->registerShortcut(action);
|
Chris@308
|
889 menu->addAction(action);
|
Chris@308
|
890
|
Chris@66
|
891 menu->addSeparator();
|
Chris@66
|
892
|
Chris@162
|
893 m_keyReference->setCategory(tr("Zoom"));
|
Chris@162
|
894
|
Chris@494
|
895 m_zoomInAction = new QAction(il.load("zoom-in"),
|
Chris@494
|
896 tr("Zoom &In"), this);
|
Chris@494
|
897 m_zoomInAction->setShortcut(tr("Up"));
|
Chris@494
|
898 m_zoomInAction->setStatusTip(tr("Increase the zoom level"));
|
Chris@494
|
899 connect(m_zoomInAction, SIGNAL(triggered()), this, SLOT(zoomIn()));
|
Chris@494
|
900 connect(this, SIGNAL(canZoom(bool)), m_zoomInAction, SLOT(setEnabled(bool)));
|
Chris@494
|
901 m_keyReference->registerShortcut(m_zoomInAction);
|
Chris@494
|
902 menu->addAction(m_zoomInAction);
|
Chris@0
|
903
|
Chris@494
|
904 m_zoomOutAction = new QAction(il.load("zoom-out"),
|
Chris@494
|
905 tr("Zoom &Out"), this);
|
Chris@494
|
906 m_zoomOutAction->setShortcut(tr("Down"));
|
Chris@494
|
907 m_zoomOutAction->setStatusTip(tr("Decrease the zoom level"));
|
Chris@494
|
908 connect(m_zoomOutAction, SIGNAL(triggered()), this, SLOT(zoomOut()));
|
Chris@494
|
909 connect(this, SIGNAL(canZoom(bool)), m_zoomOutAction, SLOT(setEnabled(bool)));
|
Chris@494
|
910 m_keyReference->registerShortcut(m_zoomOutAction);
|
Chris@494
|
911 menu->addAction(m_zoomOutAction);
|
Chris@0
|
912
|
Chris@66
|
913 action = new QAction(tr("Restore &Default Zoom"), this);
|
Chris@90
|
914 action->setStatusTip(tr("Restore the zoom level to the default"));
|
Chris@66
|
915 connect(action, SIGNAL(triggered()), this, SLOT(zoomDefault()));
|
Chris@66
|
916 connect(this, SIGNAL(canZoom(bool)), action, SLOT(setEnabled(bool)));
|
Chris@66
|
917 menu->addAction(action);
|
Chris@66
|
918
|
Chris@494
|
919 m_zoomFitAction = new QAction(il.load("zoom-fit"),
|
Chris@494
|
920 tr("Zoom to &Fit"), this);
|
Chris@494
|
921 m_zoomFitAction->setShortcut(tr("F"));
|
Chris@494
|
922 m_zoomFitAction->setStatusTip(tr("Zoom to show the whole file"));
|
Chris@494
|
923 connect(m_zoomFitAction, SIGNAL(triggered()), this, SLOT(zoomToFit()));
|
Chris@494
|
924 connect(this, SIGNAL(canZoom(bool)), m_zoomFitAction, SLOT(setEnabled(bool)));
|
Chris@494
|
925 m_keyReference->registerShortcut(m_zoomFitAction);
|
Chris@494
|
926 menu->addAction(m_zoomFitAction);
|
Chris@90
|
927
|
Chris@90
|
928 menu->addSeparator();
|
Chris@90
|
929
|
Chris@162
|
930 m_keyReference->setCategory(tr("Display Features"));
|
Chris@162
|
931
|
Chris@497
|
932 action = new QAction(tr("Show &Centre Line"), this);
|
Chris@497
|
933 action->setShortcut(tr("'"));
|
Chris@497
|
934 action->setStatusTip(tr("Show or hide the centre line"));
|
Chris@497
|
935 connect(action, SIGNAL(triggered()), this, SLOT(toggleCentreLine()));
|
Chris@497
|
936 action->setCheckable(true);
|
Chris@703
|
937 action->setChecked(m_viewManager->shouldShowCentreLine());
|
Chris@497
|
938 m_keyReference->registerShortcut(action);
|
Chris@497
|
939 menu->addAction(action);
|
Chris@497
|
940
|
Chris@497
|
941 action = new QAction(tr("Toggle All Time Rulers"), this);
|
Chris@497
|
942 action->setShortcut(tr("#"));
|
Chris@497
|
943 action->setStatusTip(tr("Show or hide all time rulers"));
|
Chris@497
|
944 connect(action, SIGNAL(triggered()), this, SLOT(toggleTimeRulers()));
|
Chris@497
|
945 m_keyReference->registerShortcut(action);
|
Chris@497
|
946 menu->addAction(action);
|
Chris@497
|
947
|
Chris@497
|
948 menu->addSeparator();
|
Chris@497
|
949
|
Chris@90
|
950 QActionGroup *overlayGroup = new QActionGroup(this);
|
Chris@90
|
951
|
Chris@703
|
952 ViewManager::OverlayMode mode = m_viewManager->getOverlayMode();
|
Chris@703
|
953
|
Chris@90
|
954 action = new QAction(tr("Show &No Overlays"), this);
|
Chris@90
|
955 action->setShortcut(tr("0"));
|
Chris@497
|
956 action->setStatusTip(tr("Hide times, layer names, and scale"));
|
Chris@90
|
957 connect(action, SIGNAL(triggered()), this, SLOT(showNoOverlays()));
|
Chris@90
|
958 action->setCheckable(true);
|
Chris@703
|
959 action->setChecked(mode == ViewManager::NoOverlays);
|
Chris@90
|
960 overlayGroup->addAction(action);
|
Chris@162
|
961 m_keyReference->registerShortcut(action);
|
Chris@90
|
962 menu->addAction(action);
|
Chris@90
|
963
|
Chris@90
|
964 action = new QAction(tr("Show &Minimal Overlays"), this);
|
Chris@90
|
965 action->setShortcut(tr("9"));
|
Chris@497
|
966 action->setStatusTip(tr("Show times and basic scale"));
|
Chris@90
|
967 connect(action, SIGNAL(triggered()), this, SLOT(showMinimalOverlays()));
|
Chris@90
|
968 action->setCheckable(true);
|
Chris@715
|
969 action->setChecked(mode == ViewManager::StandardOverlays);
|
Chris@90
|
970 overlayGroup->addAction(action);
|
Chris@162
|
971 m_keyReference->registerShortcut(action);
|
Chris@90
|
972 menu->addAction(action);
|
Chris@90
|
973
|
Chris@90
|
974 action = new QAction(tr("Show &All Overlays"), this);
|
Chris@497
|
975 action->setShortcut(tr("8"));
|
Chris@497
|
976 action->setStatusTip(tr("Show times, layer names, and scale"));
|
Chris@90
|
977 connect(action, SIGNAL(triggered()), this, SLOT(showAllOverlays()));
|
Chris@90
|
978 action->setCheckable(true);
|
Chris@703
|
979 action->setChecked(mode == ViewManager::AllOverlays);
|
Chris@90
|
980 overlayGroup->addAction(action);
|
Chris@162
|
981 m_keyReference->registerShortcut(action);
|
Chris@90
|
982 menu->addAction(action);
|
Chris@387
|
983
|
Chris@387
|
984 menu->addSeparator();
|
Chris@497
|
985
|
Chris@66
|
986 action = new QAction(tr("Show &Zoom Wheels"), this);
|
Chris@66
|
987 action->setShortcut(tr("Z"));
|
Chris@66
|
988 action->setStatusTip(tr("Show thumbwheels for zooming horizontally and vertically"));
|
Chris@66
|
989 connect(action, SIGNAL(triggered()), this, SLOT(toggleZoomWheels()));
|
Chris@66
|
990 action->setCheckable(true);
|
Chris@66
|
991 action->setChecked(m_viewManager->getZoomWheelsEnabled());
|
Chris@162
|
992 m_keyReference->registerShortcut(action);
|
Chris@66
|
993 menu->addAction(action);
|
Chris@387
|
994
|
Chris@494
|
995 m_showPropertyBoxesAction = new QAction(tr("Show Property Bo&xes"), this);
|
Chris@494
|
996 m_showPropertyBoxesAction->setShortcut(tr("X"));
|
Chris@494
|
997 m_showPropertyBoxesAction->setStatusTip(tr("Show the layer property boxes at the side of the main window"));
|
Chris@494
|
998 connect(m_showPropertyBoxesAction, SIGNAL(triggered()), this, SLOT(togglePropertyBoxes()));
|
Chris@494
|
999 m_showPropertyBoxesAction->setCheckable(true);
|
Chris@494
|
1000 m_showPropertyBoxesAction->setChecked(true);
|
Chris@494
|
1001 m_keyReference->registerShortcut(m_showPropertyBoxesAction);
|
Chris@494
|
1002 menu->addAction(m_showPropertyBoxesAction);
|
Chris@0
|
1003
|
Chris@90
|
1004 action = new QAction(tr("Show Status &Bar"), this);
|
Chris@90
|
1005 action->setStatusTip(tr("Show context help information in the status bar at the bottom of the window"));
|
Chris@90
|
1006 connect(action, SIGNAL(triggered()), this, SLOT(toggleStatusBar()));
|
Chris@90
|
1007 action->setCheckable(true);
|
Chris@90
|
1008 action->setChecked(true);
|
Chris@90
|
1009 menu->addAction(action);
|
Chris@90
|
1010
|
Chris@90
|
1011 QSettings settings;
|
Chris@90
|
1012 settings.beginGroup("MainWindow");
|
Chris@90
|
1013 bool sb = settings.value("showstatusbar", true).toBool();
|
Chris@90
|
1014 if (!sb) {
|
Chris@90
|
1015 action->setChecked(false);
|
Chris@90
|
1016 statusBar()->hide();
|
Chris@90
|
1017 }
|
Chris@90
|
1018 settings.endGroup();
|
Chris@90
|
1019
|
Chris@66
|
1020 menu->addSeparator();
|
Chris@66
|
1021
|
Chris@219
|
1022 action = new QAction(tr("Show La&yer Summary"), this);
|
Chris@219
|
1023 action->setShortcut(tr("Y"));
|
Chris@90
|
1024 action->setStatusTip(tr("Open a window displaying the hierarchy of panes and layers in this session"));
|
Chris@66
|
1025 connect(action, SIGNAL(triggered()), this, SLOT(showLayerTree()));
|
Chris@162
|
1026 m_keyReference->registerShortcut(action);
|
Chris@66
|
1027 menu->addAction(action);
|
Chris@306
|
1028
|
Chris@306
|
1029 action = new QAction(tr("Show Acti&vity Log"), this);
|
Chris@306
|
1030 action->setStatusTip(tr("Open a window listing interactions and other events"));
|
Chris@306
|
1031 connect(action, SIGNAL(triggered()), this, SLOT(showActivityLog()));
|
Chris@306
|
1032 menu->addAction(action);
|
Chris@493
|
1033
|
Chris@494
|
1034 menu->addSeparator();
|
Chris@494
|
1035
|
Chris@493
|
1036 action = new QAction(tr("Go Full-Screen"), this);
|
Chris@494
|
1037 action->setShortcut(tr("F11"));
|
Chris@494
|
1038 action->setStatusTip(tr("Expand the pane area to the whole screen"));
|
Chris@493
|
1039 connect(action, SIGNAL(triggered()), this, SLOT(goFullScreen()));
|
Chris@494
|
1040 m_keyReference->registerShortcut(action);
|
Chris@493
|
1041 menu->addAction(action);
|
Chris@66
|
1042 }
|
Chris@66
|
1043
|
Chris@66
|
1044 void
|
Chris@66
|
1045 MainWindow::setupPaneAndLayerMenus()
|
Chris@66
|
1046 {
|
Chris@0
|
1047 if (m_paneMenu) {
|
Chris@0
|
1048 m_paneActions.clear();
|
Chris@0
|
1049 m_paneMenu->clear();
|
Chris@0
|
1050 } else {
|
Chris@0
|
1051 m_paneMenu = menuBar()->addMenu(tr("&Pane"));
|
Chris@97
|
1052 m_paneMenu->setTearOffEnabled(true);
|
Chris@0
|
1053 }
|
Chris@0
|
1054
|
Chris@0
|
1055 if (m_layerMenu) {
|
Chris@0
|
1056 m_layerActions.clear();
|
Chris@0
|
1057 m_layerMenu->clear();
|
Chris@0
|
1058 } else {
|
Chris@0
|
1059 m_layerMenu = menuBar()->addMenu(tr("&Layer"));
|
Chris@97
|
1060 m_layerMenu->setTearOffEnabled(true);
|
Chris@0
|
1061 }
|
Chris@0
|
1062
|
Chris@345
|
1063 if (m_rightButtonLayerMenu) {
|
Chris@345
|
1064 m_rightButtonLayerMenu->clear();
|
Chris@345
|
1065 } else {
|
Chris@345
|
1066 m_rightButtonLayerMenu = m_rightButtonMenu->addMenu(tr("&Layer"));
|
Chris@345
|
1067 m_rightButtonLayerMenu->setTearOffEnabled(true);
|
Chris@345
|
1068 m_rightButtonMenu->addSeparator();
|
Chris@345
|
1069 }
|
Chris@345
|
1070
|
Chris@66
|
1071 QMenu *menu = m_paneMenu;
|
Chris@66
|
1072
|
Chris@168
|
1073 IconLoader il;
|
Chris@168
|
1074
|
Chris@162
|
1075 m_keyReference->setCategory(tr("Managing Panes and Layers"));
|
Chris@162
|
1076
|
Chris@168
|
1077 QAction *action = new QAction(il.load("pane"), tr("Add &New Pane"), this);
|
Chris@155
|
1078 action->setShortcut(tr("N"));
|
Chris@66
|
1079 action->setStatusTip(tr("Add a new pane containing only a time ruler"));
|
Chris@66
|
1080 connect(action, SIGNAL(triggered()), this, SLOT(addPane()));
|
Chris@66
|
1081 connect(this, SIGNAL(canAddPane(bool)), action, SLOT(setEnabled(bool)));
|
Chris@232
|
1082 m_paneActions[action] = LayerConfiguration(LayerFactory::TimeRuler);
|
Chris@162
|
1083 m_keyReference->registerShortcut(action);
|
Chris@66
|
1084 menu->addAction(action);
|
Chris@66
|
1085
|
Chris@66
|
1086 menu->addSeparator();
|
Chris@66
|
1087
|
Chris@66
|
1088 menu = m_layerMenu;
|
Chris@66
|
1089
|
Chris@66
|
1090 // menu->addSeparator();
|
Chris@66
|
1091
|
Chris@66
|
1092 LayerFactory::LayerTypeSet emptyLayerTypes =
|
Chris@66
|
1093 LayerFactory::getInstance()->getValidEmptyLayerTypes();
|
Chris@66
|
1094
|
Chris@66
|
1095 for (LayerFactory::LayerTypeSet::iterator i = emptyLayerTypes.begin();
|
Chris@66
|
1096 i != emptyLayerTypes.end(); ++i) {
|
Chris@66
|
1097
|
Chris@66
|
1098 QIcon icon;
|
Chris@66
|
1099 QString mainText, tipText, channelText;
|
Chris@66
|
1100 LayerFactory::LayerType type = *i;
|
Chris@66
|
1101 QString name = LayerFactory::getInstance()->getLayerPresentationName(type);
|
Chris@66
|
1102
|
Chris@168
|
1103 icon = il.load(LayerFactory::getInstance()->getLayerIconName(type));
|
Chris@66
|
1104
|
Chris@66
|
1105 mainText = tr("Add New %1 Layer").arg(name);
|
Chris@66
|
1106 tipText = tr("Add a new empty layer of type %1").arg(name);
|
Chris@66
|
1107
|
Chris@66
|
1108 action = new QAction(icon, mainText, this);
|
Chris@66
|
1109 action->setStatusTip(tipText);
|
Chris@66
|
1110
|
Chris@66
|
1111 if (type == LayerFactory::Text) {
|
Chris@155
|
1112 action->setShortcut(tr("T"));
|
Chris@162
|
1113 m_keyReference->registerShortcut(action);
|
Chris@66
|
1114 }
|
Chris@66
|
1115
|
Chris@66
|
1116 connect(action, SIGNAL(triggered()), this, SLOT(addLayer()));
|
Chris@66
|
1117 connect(this, SIGNAL(canAddLayer(bool)), action, SLOT(setEnabled(bool)));
|
Chris@232
|
1118 m_layerActions[action] = LayerConfiguration(type);
|
Chris@66
|
1119 menu->addAction(action);
|
Chris@66
|
1120 m_rightButtonLayerMenu->addAction(action);
|
Chris@66
|
1121 }
|
Chris@66
|
1122
|
Chris@66
|
1123 m_rightButtonLayerMenu->addSeparator();
|
Chris@66
|
1124 menu->addSeparator();
|
Chris@66
|
1125
|
Chris@66
|
1126 LayerFactory::LayerType backgroundTypes[] = {
|
Chris@66
|
1127 LayerFactory::Waveform,
|
Chris@66
|
1128 LayerFactory::Spectrogram,
|
Chris@66
|
1129 LayerFactory::MelodicRangeSpectrogram,
|
Chris@66
|
1130 LayerFactory::PeakFrequencySpectrogram,
|
Chris@66
|
1131 LayerFactory::Spectrum
|
Chris@66
|
1132 };
|
Chris@66
|
1133
|
Chris@66
|
1134 std::vector<Model *> models;
|
Chris@224
|
1135 if (m_document) models = m_document->getTransformInputModels();
|
Chris@66
|
1136 bool plural = (models.size() > 1);
|
Chris@66
|
1137 if (models.empty()) {
|
Chris@67
|
1138 models.push_back(getMainModel()); // probably 0
|
Chris@66
|
1139 }
|
Chris@66
|
1140
|
Chris@66
|
1141 for (unsigned int i = 0;
|
Chris@66
|
1142 i < sizeof(backgroundTypes)/sizeof(backgroundTypes[0]); ++i) {
|
Chris@66
|
1143
|
Chris@231
|
1144 const int paneMenuType = 0, layerMenuType = 1;
|
Chris@231
|
1145
|
Chris@231
|
1146 for (int menuType = paneMenuType; menuType <= layerMenuType; ++menuType) {
|
Chris@231
|
1147
|
Chris@231
|
1148 if (menuType == paneMenuType) menu = m_paneMenu;
|
Chris@66
|
1149 else menu = m_layerMenu;
|
Chris@66
|
1150
|
Chris@66
|
1151 QMenu *submenu = 0;
|
Chris@66
|
1152
|
Chris@66
|
1153 QIcon icon;
|
Chris@66
|
1154 QString mainText, shortcutText, tipText, channelText;
|
Chris@66
|
1155 LayerFactory::LayerType type = backgroundTypes[i];
|
Chris@66
|
1156 bool mono = true;
|
Chris@730
|
1157
|
Chris@730
|
1158 // Avoid warnings/errors with -Wextra because we aren't explicitly
|
Chris@730
|
1159 // handling all layer types (-Wall is OK with this because of the
|
Chris@730
|
1160 // default but the stricter level insists)
|
Chris@730
|
1161 #pragma GCC diagnostic ignored "-Wswitch-enum"
|
Chris@66
|
1162
|
Chris@66
|
1163 switch (type) {
|
Chris@66
|
1164
|
Chris@66
|
1165 case LayerFactory::Waveform:
|
Chris@168
|
1166 icon = il.load("waveform");
|
Chris@66
|
1167 mainText = tr("Add &Waveform");
|
Chris@231
|
1168 if (menuType == paneMenuType) {
|
Chris@155
|
1169 shortcutText = tr("W");
|
Chris@66
|
1170 tipText = tr("Add a new pane showing a waveform view");
|
Chris@66
|
1171 } else {
|
Chris@348
|
1172 shortcutText = tr("Shift+W");
|
Chris@66
|
1173 tipText = tr("Add a new layer showing a waveform view");
|
Chris@66
|
1174 }
|
Chris@66
|
1175 mono = false;
|
Chris@66
|
1176 break;
|
Chris@66
|
1177
|
Chris@66
|
1178 case LayerFactory::Spectrogram:
|
Chris@168
|
1179 icon = il.load("spectrogram");
|
Chris@161
|
1180 mainText = tr("Add Spectro&gram");
|
Chris@231
|
1181 if (menuType == paneMenuType) {
|
Chris@155
|
1182 shortcutText = tr("G");
|
Chris@90
|
1183 tipText = tr("Add a new pane showing a spectrogram");
|
Chris@66
|
1184 } else {
|
Chris@348
|
1185 shortcutText = tr("Shift+G");
|
Chris@90
|
1186 tipText = tr("Add a new layer showing a spectrogram");
|
Chris@66
|
1187 }
|
Chris@66
|
1188 break;
|
Chris@66
|
1189
|
Chris@66
|
1190 case LayerFactory::MelodicRangeSpectrogram:
|
Chris@168
|
1191 icon = il.load("spectrogram");
|
Chris@66
|
1192 mainText = tr("Add &Melodic Range Spectrogram");
|
Chris@231
|
1193 if (menuType == paneMenuType) {
|
Chris@155
|
1194 shortcutText = tr("M");
|
Chris@90
|
1195 tipText = tr("Add a new pane showing a spectrogram set up for an overview of note pitches");
|
Chris@66
|
1196 } else {
|
Chris@348
|
1197 shortcutText = tr("Shift+M");
|
Chris@90
|
1198 tipText = tr("Add a new layer showing a spectrogram set up for an overview of note pitches");
|
Chris@66
|
1199 }
|
Chris@66
|
1200 break;
|
Chris@66
|
1201
|
Chris@66
|
1202 case LayerFactory::PeakFrequencySpectrogram:
|
Chris@168
|
1203 icon = il.load("spectrogram");
|
Chris@155
|
1204 mainText = tr("Add Pea&k Frequency Spectrogram");
|
Chris@231
|
1205 if (menuType == paneMenuType) {
|
Chris@155
|
1206 shortcutText = tr("K");
|
Chris@66
|
1207 tipText = tr("Add a new pane showing a spectrogram set up for tracking frequencies");
|
Chris@66
|
1208 } else {
|
Chris@348
|
1209 shortcutText = tr("Shift+K");
|
Chris@66
|
1210 tipText = tr("Add a new layer showing a spectrogram set up for tracking frequencies");
|
Chris@66
|
1211 }
|
Chris@66
|
1212 break;
|
Chris@66
|
1213
|
Chris@66
|
1214 case LayerFactory::Spectrum:
|
Chris@168
|
1215 icon = il.load("spectrum");
|
Chris@66
|
1216 mainText = tr("Add Spectr&um");
|
Chris@231
|
1217 if (menuType == paneMenuType) {
|
Chris@155
|
1218 shortcutText = tr("U");
|
Chris@66
|
1219 tipText = tr("Add a new pane showing a frequency spectrum");
|
Chris@66
|
1220 } else {
|
Chris@348
|
1221 shortcutText = tr("Shift+U");
|
Chris@66
|
1222 tipText = tr("Add a new layer showing a frequency spectrum");
|
Chris@66
|
1223 }
|
Chris@66
|
1224 break;
|
Chris@66
|
1225
|
Chris@66
|
1226 default: break;
|
Chris@66
|
1227 }
|
Chris@66
|
1228
|
Chris@346
|
1229 std::vector<Model *> candidateModels = models;
|
Chris@66
|
1230
|
Chris@66
|
1231 for (std::vector<Model *>::iterator mi =
|
Chris@66
|
1232 candidateModels.begin();
|
Chris@66
|
1233 mi != candidateModels.end(); ++mi) {
|
Chris@66
|
1234
|
Chris@66
|
1235 Model *model = *mi;
|
Chris@66
|
1236
|
Chris@66
|
1237 int channels = 0;
|
Chris@66
|
1238 if (model) {
|
Chris@66
|
1239 DenseTimeValueModel *dtvm =
|
Chris@66
|
1240 dynamic_cast<DenseTimeValueModel *>(model);
|
Chris@66
|
1241 if (dtvm) channels = dtvm->getChannelCount();
|
Chris@66
|
1242 }
|
Chris@66
|
1243 if (channels < 1 && getMainModel()) {
|
Chris@66
|
1244 channels = getMainModel()->getChannelCount();
|
Chris@66
|
1245 }
|
Chris@66
|
1246 if (channels < 1) channels = 1;
|
Chris@66
|
1247
|
Chris@66
|
1248 for (int c = 0; c <= channels; ++c) {
|
Chris@66
|
1249
|
Chris@66
|
1250 if (c == 1 && channels == 1) continue;
|
Chris@66
|
1251 bool isDefault = (c == 0);
|
Chris@66
|
1252 bool isOnly = (isDefault && (channels == 1));
|
Chris@66
|
1253
|
Chris@346
|
1254 if (isOnly && !plural) {
|
Chris@346
|
1255
|
Chris@346
|
1256 action = new QAction(icon, mainText, this);
|
Chris@67
|
1257
|
Chris@66
|
1258 action->setShortcut(shortcutText);
|
Chris@66
|
1259 action->setStatusTip(tipText);
|
Chris@231
|
1260 if (menuType == paneMenuType) {
|
Chris@66
|
1261 connect(action, SIGNAL(triggered()),
|
Chris@66
|
1262 this, SLOT(addPane()));
|
Chris@66
|
1263 connect(this, SIGNAL(canAddPane(bool)),
|
Chris@66
|
1264 action, SLOT(setEnabled(bool)));
|
Chris@346
|
1265 m_paneActions[action] =
|
Chris@346
|
1266 LayerConfiguration(type, model);
|
Chris@66
|
1267 } else {
|
Chris@66
|
1268 connect(action, SIGNAL(triggered()),
|
Chris@66
|
1269 this, SLOT(addLayer()));
|
Chris@66
|
1270 connect(this, SIGNAL(canAddLayer(bool)),
|
Chris@66
|
1271 action, SLOT(setEnabled(bool)));
|
Chris@346
|
1272 m_layerActions[action] =
|
Chris@346
|
1273 LayerConfiguration(type, model);
|
Chris@66
|
1274 }
|
Chris@162
|
1275 if (shortcutText != "") {
|
Chris@162
|
1276 m_keyReference->registerShortcut(action);
|
Chris@162
|
1277 }
|
Chris@66
|
1278 menu->addAction(action);
|
Chris@66
|
1279
|
Chris@66
|
1280 } else {
|
Chris@66
|
1281
|
Chris@66
|
1282 if (!submenu) {
|
Chris@66
|
1283 submenu = menu->addMenu(mainText);
|
Chris@97
|
1284 submenu->setTearOffEnabled(true);
|
Chris@67
|
1285 } else if (isDefault) {
|
Chris@67
|
1286 submenu->addSeparator();
|
Chris@66
|
1287 }
|
Chris@66
|
1288
|
Chris@66
|
1289 QString actionText;
|
Chris@66
|
1290 if (c == 0) {
|
Chris@66
|
1291 if (mono) {
|
Chris@66
|
1292 actionText = tr("&All Channels Mixed");
|
Chris@66
|
1293 } else {
|
Chris@66
|
1294 actionText = tr("&All Channels");
|
Chris@66
|
1295 }
|
Chris@66
|
1296 } else {
|
Chris@66
|
1297 actionText = tr("Channel &%1").arg(c);
|
Chris@66
|
1298 }
|
Chris@66
|
1299
|
Chris@66
|
1300 if (model) {
|
Chris@66
|
1301 actionText = tr("%1: %2")
|
Chris@66
|
1302 .arg(model->objectName())
|
Chris@66
|
1303 .arg(actionText);
|
Chris@66
|
1304 }
|
Chris@67
|
1305
|
Chris@67
|
1306 if (isDefault) {
|
Chris@67
|
1307 action = new QAction(icon, actionText, this);
|
Chris@67
|
1308 if (!model || model == getMainModel()) {
|
Chris@162
|
1309 action->setShortcut(shortcutText);
|
Chris@67
|
1310 }
|
Chris@67
|
1311 } else {
|
Chris@67
|
1312 action = new QAction(actionText, this);
|
Chris@67
|
1313 }
|
Chris@67
|
1314
|
Chris@66
|
1315 action->setStatusTip(tipText);
|
Chris@66
|
1316
|
Chris@231
|
1317 if (menuType == paneMenuType) {
|
Chris@66
|
1318 connect(action, SIGNAL(triggered()),
|
Chris@66
|
1319 this, SLOT(addPane()));
|
Chris@66
|
1320 connect(this, SIGNAL(canAddPane(bool)),
|
Chris@66
|
1321 action, SLOT(setEnabled(bool)));
|
Chris@66
|
1322 m_paneActions[action] =
|
Chris@232
|
1323 LayerConfiguration(type, model, c - 1);
|
Chris@66
|
1324 } else {
|
Chris@66
|
1325 connect(action, SIGNAL(triggered()),
|
Chris@66
|
1326 this, SLOT(addLayer()));
|
Chris@66
|
1327 connect(this, SIGNAL(canAddLayer(bool)),
|
Chris@66
|
1328 action, SLOT(setEnabled(bool)));
|
Chris@232
|
1329 m_layerActions[action] =
|
Chris@232
|
1330 LayerConfiguration(type, model, c - 1);
|
Chris@66
|
1331 }
|
Chris@66
|
1332
|
Chris@66
|
1333 submenu->addAction(action);
|
Chris@66
|
1334 }
|
Chris@346
|
1335
|
Chris@415
|
1336 if (isDefault && menuType == layerMenuType &&
|
Chris@415
|
1337 mi == candidateModels.begin()) {
|
Chris@415
|
1338 // only add for one model, one channel, one menu on
|
Chris@415
|
1339 // right button -- the action itself will discover
|
Chris@415
|
1340 // which model is the correct one (based on pane)
|
Chris@346
|
1341 action = new QAction(icon, mainText, this);
|
Chris@346
|
1342 action->setStatusTip(tipText);
|
Chris@346
|
1343 connect(action, SIGNAL(triggered()),
|
Chris@346
|
1344 this, SLOT(addLayer()));
|
Chris@346
|
1345 connect(this, SIGNAL(canAddLayer(bool)),
|
Chris@346
|
1346 action, SLOT(setEnabled(bool)));
|
Chris@346
|
1347 m_layerActions[action] = LayerConfiguration(type, 0, 0);
|
Chris@346
|
1348 m_rightButtonLayerMenu->addAction(action);
|
Chris@346
|
1349 }
|
Chris@66
|
1350 }
|
Chris@66
|
1351 }
|
Chris@66
|
1352 }
|
Chris@66
|
1353 }
|
Chris@66
|
1354
|
Chris@347
|
1355 m_rightButtonLayerMenu->addSeparator();
|
Chris@347
|
1356
|
Chris@66
|
1357 menu = m_paneMenu;
|
Chris@225
|
1358 menu->addSeparator();
|
Chris@225
|
1359
|
Chris@225
|
1360 action = new QAction(tr("Switch to Previous Pane"), this);
|
Chris@225
|
1361 action->setShortcut(tr("["));
|
Chris@225
|
1362 action->setStatusTip(tr("Make the next pane up in the pane stack current"));
|
Chris@225
|
1363 connect(action, SIGNAL(triggered()), this, SLOT(previousPane()));
|
Chris@225
|
1364 connect(this, SIGNAL(canSelectPreviousPane(bool)), action, SLOT(setEnabled(bool)));
|
Chris@225
|
1365 m_keyReference->registerShortcut(action);
|
Chris@225
|
1366 menu->addAction(action);
|
Chris@225
|
1367
|
Chris@225
|
1368 action = new QAction(tr("Switch to Next Pane"), this);
|
Chris@225
|
1369 action->setShortcut(tr("]"));
|
Chris@225
|
1370 action->setStatusTip(tr("Make the next pane down in the pane stack current"));
|
Chris@225
|
1371 connect(action, SIGNAL(triggered()), this, SLOT(nextPane()));
|
Chris@225
|
1372 connect(this, SIGNAL(canSelectNextPane(bool)), action, SLOT(setEnabled(bool)));
|
Chris@225
|
1373 m_keyReference->registerShortcut(action);
|
Chris@225
|
1374 menu->addAction(action);
|
Chris@66
|
1375
|
Chris@66
|
1376 menu->addSeparator();
|
Chris@66
|
1377
|
Chris@168
|
1378 action = new QAction(il.load("editdelete"), tr("&Delete Pane"), this);
|
Chris@155
|
1379 action->setShortcut(tr("Ctrl+Shift+D"));
|
Chris@90
|
1380 action->setStatusTip(tr("Delete the currently active pane"));
|
Chris@66
|
1381 connect(action, SIGNAL(triggered()), this, SLOT(deleteCurrentPane()));
|
Chris@66
|
1382 connect(this, SIGNAL(canDeleteCurrentPane(bool)), action, SLOT(setEnabled(bool)));
|
Chris@162
|
1383 m_keyReference->registerShortcut(action);
|
Chris@66
|
1384 menu->addAction(action);
|
Chris@66
|
1385
|
Chris@66
|
1386 menu = m_layerMenu;
|
Chris@66
|
1387
|
Chris@168
|
1388 action = new QAction(il.load("timeruler"), tr("Add &Time Ruler"), this);
|
Chris@66
|
1389 action->setStatusTip(tr("Add a new layer showing a time ruler"));
|
Chris@66
|
1390 connect(action, SIGNAL(triggered()), this, SLOT(addLayer()));
|
Chris@66
|
1391 connect(this, SIGNAL(canAddLayer(bool)), action, SLOT(setEnabled(bool)));
|
Chris@232
|
1392 m_layerActions[action] = LayerConfiguration(LayerFactory::TimeRuler);
|
Chris@66
|
1393 menu->addAction(action);
|
Chris@66
|
1394
|
Chris@66
|
1395 menu->addSeparator();
|
Chris@66
|
1396
|
Chris@66
|
1397 m_existingLayersMenu = menu->addMenu(tr("Add &Existing Layer"));
|
Chris@97
|
1398 m_existingLayersMenu->setTearOffEnabled(true);
|
Chris@66
|
1399 m_rightButtonLayerMenu->addMenu(m_existingLayersMenu);
|
Chris@95
|
1400
|
Chris@95
|
1401 m_sliceMenu = menu->addMenu(tr("Add S&lice of Layer"));
|
Chris@97
|
1402 m_sliceMenu->setTearOffEnabled(true);
|
Chris@95
|
1403 m_rightButtonLayerMenu->addMenu(m_sliceMenu);
|
Chris@95
|
1404
|
Chris@95
|
1405 setupExistingLayersMenus();
|
Chris@66
|
1406
|
Chris@225
|
1407 /*!!! These don't work correctly -- fix or omit
|
Chris@225
|
1408 menu->addSeparator();
|
Chris@225
|
1409
|
Chris@225
|
1410 action = new QAction(tr("Switch to Previous Layer"), this);
|
Chris@225
|
1411 action->setShortcut(tr("{"));
|
Chris@225
|
1412 action->setStatusTip(tr("Make the previous layer in the pane current"));
|
Chris@225
|
1413 connect(action, SIGNAL(triggered()), this, SLOT(previousLayer()));
|
Chris@225
|
1414 connect(this, SIGNAL(canSelectPreviousLayer(bool)), action, SLOT(setEnabled(bool)));
|
Chris@225
|
1415 m_keyReference->registerShortcut(action);
|
Chris@225
|
1416 menu->addAction(action);
|
Chris@225
|
1417
|
Chris@225
|
1418 action = new QAction(tr("Switch to Next Layer"), this);
|
Chris@225
|
1419 action->setShortcut(tr("}"));
|
Chris@225
|
1420 action->setStatusTip(tr("Make the next layer in the pane current"));
|
Chris@225
|
1421 connect(action, SIGNAL(triggered()), this, SLOT(nextLayer()));
|
Chris@225
|
1422 connect(this, SIGNAL(canSelectNextLayer(bool)), action, SLOT(setEnabled(bool)));
|
Chris@225
|
1423 m_keyReference->registerShortcut(action);
|
Chris@225
|
1424 menu->addAction(action);
|
Chris@225
|
1425 */
|
Chris@66
|
1426 m_rightButtonLayerMenu->addSeparator();
|
Chris@66
|
1427 menu->addSeparator();
|
Chris@66
|
1428
|
Chris@163
|
1429 QAction *raction = new QAction(tr("&Rename Layer..."), this);
|
Chris@163
|
1430 raction->setShortcut(tr("R"));
|
Chris@163
|
1431 raction->setStatusTip(tr("Rename the currently active layer"));
|
Chris@163
|
1432 connect(raction, SIGNAL(triggered()), this, SLOT(renameCurrentLayer()));
|
Chris@163
|
1433 connect(this, SIGNAL(canRenameLayer(bool)), raction, SLOT(setEnabled(bool)));
|
Chris@163
|
1434 menu->addAction(raction);
|
Chris@163
|
1435 m_rightButtonLayerMenu->addAction(raction);
|
Chris@66
|
1436
|
Chris@258
|
1437 QAction *eaction = new QAction(tr("Edit Layer Data"), this);
|
Chris@258
|
1438 eaction->setShortcut(tr("E"));
|
Chris@258
|
1439 eaction->setStatusTip(tr("Edit the currently active layer as a data grid"));
|
Chris@258
|
1440 connect(eaction, SIGNAL(triggered()), this, SLOT(editCurrentLayer()));
|
Chris@291
|
1441 connect(this, SIGNAL(canEditLayerTabular(bool)), eaction, SLOT(setEnabled(bool)));
|
Chris@258
|
1442 menu->addAction(eaction);
|
Chris@258
|
1443 m_rightButtonLayerMenu->addAction(eaction);
|
Chris@258
|
1444
|
Chris@168
|
1445 action = new QAction(il.load("editdelete"), tr("&Delete Layer"), this);
|
Chris@155
|
1446 action->setShortcut(tr("Ctrl+D"));
|
Chris@66
|
1447 action->setStatusTip(tr("Delete the currently active layer"));
|
Chris@66
|
1448 connect(action, SIGNAL(triggered()), this, SLOT(deleteCurrentLayer()));
|
Chris@66
|
1449 connect(this, SIGNAL(canDeleteCurrentLayer(bool)), action, SLOT(setEnabled(bool)));
|
Chris@162
|
1450 m_keyReference->registerShortcut(action);
|
Chris@66
|
1451 menu->addAction(action);
|
Chris@66
|
1452 m_rightButtonLayerMenu->addAction(action);
|
Chris@163
|
1453
|
Chris@163
|
1454 m_keyReference->registerShortcut(raction); // rename after delete, so delete layer goes next to delete pane
|
Chris@258
|
1455 m_keyReference->registerShortcut(eaction); // edit also after delete
|
Chris@755
|
1456
|
Chris@755
|
1457 finaliseMenus();
|
Chris@66
|
1458 }
|
Chris@66
|
1459
|
Chris@66
|
1460 void
|
Chris@211
|
1461 MainWindow::setupTransformsMenu()
|
Chris@66
|
1462 {
|
Chris@34
|
1463 if (m_transformsMenu) {
|
Chris@34
|
1464 m_transformActions.clear();
|
Chris@34
|
1465 m_transformActionsReverse.clear();
|
Chris@34
|
1466 m_transformsMenu->clear();
|
Chris@34
|
1467 } else {
|
Chris@97
|
1468 m_transformsMenu = menuBar()->addMenu(tr("&Transform"));
|
Chris@97
|
1469 m_transformsMenu->setTearOffEnabled(true);
|
Chris@286
|
1470 m_transformsMenu->setSeparatorsCollapsible(true);
|
Chris@272
|
1471 }
|
Chris@34
|
1472
|
Chris@288
|
1473 TransformFactory *factory = TransformFactory::getInstance();
|
Chris@288
|
1474
|
Chris@288
|
1475 TransformList transforms = factory->getAllTransformDescriptions();
|
Chris@288
|
1476 vector<TransformDescription::Type> types = factory->getAllTransformTypes();
|
Chris@288
|
1477
|
Chris@288
|
1478 map<TransformDescription::Type, map<QString, SubdividingMenu *> > categoryMenus;
|
Chris@288
|
1479 map<TransformDescription::Type, map<QString, SubdividingMenu *> > makerMenus;
|
Chris@288
|
1480
|
Chris@288
|
1481 map<TransformDescription::Type, SubdividingMenu *> byPluginNameMenus;
|
Chris@288
|
1482 map<TransformDescription::Type, map<QString, QMenu *> > pluginNameMenus;
|
Chris@33
|
1483
|
Chris@37
|
1484 set<SubdividingMenu *> pendingMenus;
|
Chris@37
|
1485
|
Chris@211
|
1486 m_recentTransformsMenu = m_transformsMenu->addMenu(tr("&Recent Transforms"));
|
Chris@211
|
1487 m_recentTransformsMenu->setTearOffEnabled(true);
|
Chris@211
|
1488 m_rightButtonTransformsMenu->addMenu(m_recentTransformsMenu);
|
Chris@211
|
1489 connect(&m_recentTransforms, SIGNAL(recentChanged()),
|
Chris@211
|
1490 this, SLOT(setupRecentTransformsMenu()));
|
Chris@34
|
1491
|
Chris@34
|
1492 m_transformsMenu->addSeparator();
|
Chris@211
|
1493 m_rightButtonTransformsMenu->addSeparator();
|
Chris@34
|
1494
|
Chris@288
|
1495 for (vector<TransformDescription::Type>::iterator i = types.begin();
|
Chris@288
|
1496 i != types.end(); ++i) {
|
Chris@33
|
1497
|
Chris@33
|
1498 if (i != types.begin()) {
|
Chris@34
|
1499 m_transformsMenu->addSeparator();
|
Chris@211
|
1500 m_rightButtonTransformsMenu->addSeparator();
|
Chris@33
|
1501 }
|
Chris@33
|
1502
|
Chris@288
|
1503 QString byCategoryLabel = tr("%1 by Category")
|
Chris@288
|
1504 .arg(factory->getTransformTypeName(*i));
|
Chris@37
|
1505 SubdividingMenu *byCategoryMenu = new SubdividingMenu(byCategoryLabel,
|
Chris@37
|
1506 20, 40);
|
Chris@97
|
1507 byCategoryMenu->setTearOffEnabled(true);
|
Chris@37
|
1508 m_transformsMenu->addMenu(byCategoryMenu);
|
Chris@211
|
1509 m_rightButtonTransformsMenu->addMenu(byCategoryMenu);
|
Chris@37
|
1510 pendingMenus.insert(byCategoryMenu);
|
Chris@33
|
1511
|
Chris@288
|
1512 vector<QString> categories = factory->getTransformCategories(*i);
|
Chris@33
|
1513
|
Chris@33
|
1514 for (vector<QString>::iterator j = categories.begin();
|
Chris@33
|
1515 j != categories.end(); ++j) {
|
Chris@33
|
1516
|
Chris@33
|
1517 QString category = *j;
|
Chris@33
|
1518 if (category == "") category = tr("Unclassified");
|
Chris@33
|
1519
|
Chris@33
|
1520 if (categories.size() < 2) {
|
Chris@33
|
1521 categoryMenus[*i][category] = byCategoryMenu;
|
Chris@33
|
1522 continue;
|
Chris@33
|
1523 }
|
Chris@33
|
1524
|
Chris@33
|
1525 QStringList components = category.split(" > ");
|
Chris@33
|
1526 QString key;
|
Chris@33
|
1527
|
Chris@33
|
1528 for (QStringList::iterator k = components.begin();
|
Chris@33
|
1529 k != components.end(); ++k) {
|
Chris@33
|
1530
|
Chris@33
|
1531 QString parentKey = key;
|
Chris@33
|
1532 if (key != "") key += " > ";
|
Chris@33
|
1533 key += *k;
|
Chris@33
|
1534
|
Chris@33
|
1535 if (categoryMenus[*i].find(key) == categoryMenus[*i].end()) {
|
Chris@37
|
1536 SubdividingMenu *m = new SubdividingMenu(*k, 20, 40);
|
Chris@97
|
1537 m->setTearOffEnabled(true);
|
Chris@37
|
1538 pendingMenus.insert(m);
|
Chris@37
|
1539 categoryMenus[*i][key] = m;
|
Chris@33
|
1540 if (parentKey == "") {
|
Chris@37
|
1541 byCategoryMenu->addMenu(m);
|
Chris@33
|
1542 } else {
|
Chris@37
|
1543 categoryMenus[*i][parentKey]->addMenu(m);
|
Chris@33
|
1544 }
|
Chris@33
|
1545 }
|
Chris@33
|
1546 }
|
Chris@33
|
1547 }
|
Chris@33
|
1548
|
Chris@288
|
1549 QString byPluginNameLabel = tr("%1 by Plugin Name")
|
Chris@288
|
1550 .arg(factory->getTransformTypeName(*i));
|
Chris@36
|
1551 byPluginNameMenus[*i] = new SubdividingMenu(byPluginNameLabel);
|
Chris@97
|
1552 byPluginNameMenus[*i]->setTearOffEnabled(true);
|
Chris@36
|
1553 m_transformsMenu->addMenu(byPluginNameMenus[*i]);
|
Chris@211
|
1554 m_rightButtonTransformsMenu->addMenu(byPluginNameMenus[*i]);
|
Chris@37
|
1555 pendingMenus.insert(byPluginNameMenus[*i]);
|
Chris@34
|
1556
|
Chris@288
|
1557 QString byMakerLabel = tr("%1 by Maker")
|
Chris@288
|
1558 .arg(factory->getTransformTypeName(*i));
|
Chris@37
|
1559 SubdividingMenu *byMakerMenu = new SubdividingMenu(byMakerLabel, 20, 40);
|
Chris@97
|
1560 byMakerMenu->setTearOffEnabled(true);
|
Chris@37
|
1561 m_transformsMenu->addMenu(byMakerMenu);
|
Chris@211
|
1562 m_rightButtonTransformsMenu->addMenu(byMakerMenu);
|
Chris@37
|
1563 pendingMenus.insert(byMakerMenu);
|
Chris@33
|
1564
|
Chris@288
|
1565 vector<QString> makers = factory->getTransformMakers(*i);
|
Chris@37
|
1566
|
Chris@33
|
1567 for (vector<QString>::iterator j = makers.begin();
|
Chris@33
|
1568 j != makers.end(); ++j) {
|
Chris@33
|
1569
|
Chris@33
|
1570 QString maker = *j;
|
Chris@33
|
1571 if (maker == "") maker = tr("Unknown");
|
Chris@55
|
1572 maker.replace(QRegExp(tr(" [\\(<].*$")), "");
|
Chris@55
|
1573
|
Chris@37
|
1574 makerMenus[*i][maker] = new SubdividingMenu(maker, 30, 40);
|
Chris@97
|
1575 makerMenus[*i][maker]->setTearOffEnabled(true);
|
Chris@37
|
1576 byMakerMenu->addMenu(makerMenus[*i][maker]);
|
Chris@37
|
1577 pendingMenus.insert(makerMenus[*i][maker]);
|
Chris@33
|
1578 }
|
Chris@0
|
1579 }
|
Chris@0
|
1580
|
Chris@230
|
1581 // Names should only be duplicated here if they have the same
|
Chris@230
|
1582 // plugin name, output name and maker but are in different library
|
Chris@230
|
1583 // .so names -- that won't happen often I hope
|
Chris@230
|
1584 std::map<QString, QString> idNameSonameMap;
|
Chris@230
|
1585 std::set<QString> seenNames, duplicateNames;
|
Chris@230
|
1586 for (unsigned int i = 0; i < transforms.size(); ++i) {
|
Chris@230
|
1587 QString name = transforms[i].name;
|
Chris@230
|
1588 if (seenNames.find(name) != seenNames.end()) {
|
Chris@230
|
1589 duplicateNames.insert(name);
|
Chris@230
|
1590 } else {
|
Chris@230
|
1591 seenNames.insert(name);
|
Chris@230
|
1592 }
|
Chris@230
|
1593 }
|
Chris@230
|
1594
|
Chris@0
|
1595 for (unsigned int i = 0; i < transforms.size(); ++i) {
|
Chris@0
|
1596
|
Chris@107
|
1597 QString name = transforms[i].name;
|
Chris@107
|
1598 if (name == "") name = transforms[i].identifier;
|
Chris@107
|
1599
|
Chris@665
|
1600 // cerr << "Plugin Name: " << name << endl;
|
Chris@80
|
1601
|
Chris@288
|
1602 TransformDescription::Type type = transforms[i].type;
|
Chris@288
|
1603 QString typeStr = factory->getTransformTypeName(type);
|
Chris@33
|
1604
|
Chris@33
|
1605 QString category = transforms[i].category;
|
Chris@33
|
1606 if (category == "") category = tr("Unclassified");
|
Chris@33
|
1607
|
Chris@33
|
1608 QString maker = transforms[i].maker;
|
Chris@33
|
1609 if (maker == "") maker = tr("Unknown");
|
Chris@55
|
1610 maker.replace(QRegExp(tr(" [\\(<].*$")), "");
|
Chris@33
|
1611
|
Chris@107
|
1612 QString pluginName = name.section(": ", 0, 0);
|
Chris@107
|
1613 QString output = name.section(": ", 1);
|
Chris@107
|
1614
|
Chris@230
|
1615 if (duplicateNames.find(pluginName) != duplicateNames.end()) {
|
Chris@230
|
1616 pluginName = QString("%1 <%2>")
|
Chris@230
|
1617 .arg(pluginName)
|
Chris@230
|
1618 .arg(transforms[i].identifier.section(':', 1, 1));
|
Chris@230
|
1619 if (output == "") name = pluginName;
|
Chris@230
|
1620 else name = QString("%1: %2")
|
Chris@230
|
1621 .arg(pluginName)
|
Chris@230
|
1622 .arg(output);
|
Chris@230
|
1623 }
|
Chris@230
|
1624
|
Chris@107
|
1625 QAction *action = new QAction(tr("%1...").arg(name), this);
|
Chris@0
|
1626 connect(action, SIGNAL(triggered()), this, SLOT(addLayer()));
|
Chris@107
|
1627 m_transformActions[action] = transforms[i].identifier;
|
Chris@107
|
1628 m_transformActionsReverse[transforms[i].identifier] = action;
|
Chris@0
|
1629 connect(this, SIGNAL(canAddLayer(bool)), action, SLOT(setEnabled(bool)));
|
Chris@33
|
1630
|
Chris@272
|
1631 action->setStatusTip(transforms[i].longDescription);
|
Chris@90
|
1632
|
Chris@33
|
1633 if (categoryMenus[type].find(category) == categoryMenus[type].end()) {
|
Chris@665
|
1634 cerr << "WARNING: MainWindow::setupMenus: Internal error: "
|
Chris@33
|
1635 << "No category menu for transform \""
|
Chris@432
|
1636 << name << "\" (category = \""
|
Chris@665
|
1637 << category << "\")" << endl;
|
Chris@33
|
1638 } else {
|
Chris@33
|
1639 categoryMenus[type][category]->addAction(action);
|
Chris@33
|
1640 }
|
Chris@33
|
1641
|
Chris@33
|
1642 if (makerMenus[type].find(maker) == makerMenus[type].end()) {
|
Chris@665
|
1643 cerr << "WARNING: MainWindow::setupMenus: Internal error: "
|
Chris@33
|
1644 << "No maker menu for transform \""
|
Chris@432
|
1645 << name << "\" (maker = \""
|
Chris@665
|
1646 << maker << "\")" << endl;
|
Chris@33
|
1647 } else {
|
Chris@80
|
1648 makerMenus[type][maker]->addAction(action);
|
Chris@33
|
1649 }
|
Chris@33
|
1650
|
Chris@33
|
1651 action = new QAction(tr("%1...").arg(output == "" ? pluginName : output), this);
|
Chris@33
|
1652 connect(action, SIGNAL(triggered()), this, SLOT(addLayer()));
|
Chris@107
|
1653 m_transformActions[action] = transforms[i].identifier;
|
Chris@33
|
1654 connect(this, SIGNAL(canAddLayer(bool)), action, SLOT(setEnabled(bool)));
|
Chris@272
|
1655 action->setStatusTip(transforms[i].longDescription);
|
Chris@33
|
1656
|
Chris@432
|
1657 // cerr << "Transform: \"" << name << "\": plugin name \"" << pluginName << "\"" << endl;
|
Chris@34
|
1658
|
Chris@33
|
1659 if (pluginNameMenus[type].find(pluginName) ==
|
Chris@33
|
1660 pluginNameMenus[type].end()) {
|
Chris@33
|
1661
|
Chris@36
|
1662 SubdividingMenu *parentMenu = byPluginNameMenus[type];
|
Chris@97
|
1663 parentMenu->setTearOffEnabled(true);
|
Chris@34
|
1664
|
Chris@33
|
1665 if (output == "") {
|
Chris@36
|
1666 parentMenu->addAction(pluginName, action);
|
Chris@33
|
1667 } else {
|
Chris@34
|
1668 pluginNameMenus[type][pluginName] =
|
Chris@34
|
1669 parentMenu->addMenu(pluginName);
|
Chris@33
|
1670 connect(this, SIGNAL(canAddLayer(bool)),
|
Chris@33
|
1671 pluginNameMenus[type][pluginName],
|
Chris@33
|
1672 SLOT(setEnabled(bool)));
|
Chris@33
|
1673 }
|
Chris@33
|
1674 }
|
Chris@33
|
1675
|
Chris@33
|
1676 if (pluginNameMenus[type].find(pluginName) !=
|
Chris@33
|
1677 pluginNameMenus[type].end()) {
|
Chris@33
|
1678 pluginNameMenus[type][pluginName]->addAction(action);
|
Chris@33
|
1679 }
|
Chris@0
|
1680 }
|
Chris@0
|
1681
|
Chris@37
|
1682 for (set<SubdividingMenu *>::iterator i = pendingMenus.begin();
|
Chris@37
|
1683 i != pendingMenus.end(); ++i) {
|
Chris@37
|
1684 (*i)->entriesAdded();
|
Chris@37
|
1685 }
|
Chris@37
|
1686
|
Chris@273
|
1687 m_transformsMenu->addSeparator();
|
Chris@273
|
1688 m_rightButtonTransformsMenu->addSeparator();
|
Chris@273
|
1689
|
Chris@273
|
1690 QAction *action = new QAction(tr("Find a Transform..."), this);
|
Chris@273
|
1691 action->setStatusTip(tr("Search for a transform from the installed plugins, by name or description"));
|
Chris@275
|
1692 action->setShortcut(tr("Ctrl+M"));
|
Chris@273
|
1693 connect(action, SIGNAL(triggered()), this, SLOT(findTransform()));
|
Chris@287
|
1694 // connect(this, SIGNAL(canAddLayer(bool)), action, SLOT(setEnabled(bool)));
|
Chris@275
|
1695 m_keyReference->registerShortcut(action);
|
Chris@273
|
1696 m_transformsMenu->addAction(action);
|
Chris@273
|
1697 m_rightButtonTransformsMenu->addAction(action);
|
Chris@273
|
1698
|
Chris@211
|
1699 setupRecentTransformsMenu();
|
Chris@66
|
1700 }
|
Chris@66
|
1701
|
Chris@66
|
1702 void
|
Chris@66
|
1703 MainWindow::setupHelpMenu()
|
Chris@66
|
1704 {
|
Chris@66
|
1705 QMenu *menu = menuBar()->addMenu(tr("&Help"));
|
Chris@97
|
1706 menu->setTearOffEnabled(true);
|
Chris@66
|
1707
|
Chris@162
|
1708 m_keyReference->setCategory(tr("Help"));
|
Chris@162
|
1709
|
Chris@168
|
1710 IconLoader il;
|
Chris@168
|
1711
|
Chris@518
|
1712 QString name = QApplication::applicationName();
|
Chris@518
|
1713
|
Chris@168
|
1714 QAction *action = new QAction(il.load("help"),
|
Chris@138
|
1715 tr("&Help Reference"), this);
|
Chris@162
|
1716 action->setShortcut(tr("F1"));
|
Chris@518
|
1717 action->setStatusTip(tr("Open the %1 reference manual").arg(name));
|
Chris@66
|
1718 connect(action, SIGNAL(triggered()), this, SLOT(help()));
|
Chris@162
|
1719 m_keyReference->registerShortcut(action);
|
Chris@0
|
1720 menu->addAction(action);
|
Chris@162
|
1721
|
Chris@163
|
1722 action = new QAction(tr("&Key and Mouse Reference"), this);
|
Chris@162
|
1723 action->setShortcut(tr("F2"));
|
Chris@518
|
1724 action->setStatusTip(tr("Open a window showing the keystrokes you can use in %1").arg(name));
|
Chris@162
|
1725 connect(action, SIGNAL(triggered()), this, SLOT(keyReference()));
|
Chris@162
|
1726 m_keyReference->registerShortcut(action);
|
Chris@162
|
1727 menu->addAction(action);
|
Chris@66
|
1728
|
Chris@518
|
1729 action = new QAction(tr("%1 on the &Web").arg(name), this);
|
Chris@518
|
1730 action->setStatusTip(tr("Open the %1 website").arg(name));
|
Chris@164
|
1731 connect(action, SIGNAL(triggered()), this, SLOT(website()));
|
Chris@164
|
1732 menu->addAction(action);
|
Chris@164
|
1733
|
Chris@518
|
1734 action = new QAction(tr("&About %1").arg(name), this);
|
Chris@518
|
1735 action->setStatusTip(tr("Show information about %1").arg(name));
|
Chris@66
|
1736 connect(action, SIGNAL(triggered()), this, SLOT(about()));
|
Chris@0
|
1737 menu->addAction(action);
|
Chris@0
|
1738 }
|
Chris@0
|
1739
|
Chris@0
|
1740 void
|
Chris@0
|
1741 MainWindow::setupRecentFilesMenu()
|
Chris@0
|
1742 {
|
Chris@0
|
1743 m_recentFilesMenu->clear();
|
Chris@34
|
1744 vector<QString> files = m_recentFiles.getRecent();
|
Chris@0
|
1745 for (size_t i = 0; i < files.size(); ++i) {
|
Chris@0
|
1746 QAction *action = new QAction(files[i], this);
|
Chris@0
|
1747 connect(action, SIGNAL(triggered()), this, SLOT(openRecentFile()));
|
Chris@162
|
1748 if (i == 0) {
|
Chris@162
|
1749 action->setShortcut(tr("Ctrl+R"));
|
Chris@162
|
1750 m_keyReference->registerShortcut
|
Chris@163
|
1751 (tr("Re-open"),
|
Chris@528
|
1752 action->shortcut().toString(),
|
Chris@163
|
1753 tr("Re-open the current or most recently opened file"));
|
Chris@162
|
1754 }
|
Chris@0
|
1755 m_recentFilesMenu->addAction(action);
|
Chris@0
|
1756 }
|
Chris@0
|
1757 }
|
Chris@0
|
1758
|
Chris@0
|
1759 void
|
Chris@423
|
1760 MainWindow::setupTemplatesMenu()
|
Chris@423
|
1761 {
|
Chris@423
|
1762 m_templatesMenu->clear();
|
Chris@423
|
1763
|
Chris@455
|
1764 QAction *defaultAction = new QAction(tr("Standard Waveform"), this);
|
Chris@435
|
1765 defaultAction->setObjectName("default");
|
Chris@435
|
1766 connect(defaultAction, SIGNAL(triggered()), this, SLOT(applyTemplate()));
|
Chris@435
|
1767 m_templatesMenu->addAction(defaultAction);
|
Chris@435
|
1768
|
Chris@435
|
1769 m_templatesMenu->addSeparator();
|
Chris@435
|
1770
|
Chris@435
|
1771 QAction *action = 0;
|
Chris@435
|
1772
|
Chris@435
|
1773 QStringList templates = ResourceFinder().getResourceFiles("templates", "svt");
|
Chris@435
|
1774
|
Chris@436
|
1775 bool havePersonal = false;
|
Chris@436
|
1776
|
Chris@435
|
1777 // (ordered by name)
|
Chris@435
|
1778 std::set<QString> byName;
|
Chris@435
|
1779 foreach (QString t, templates) {
|
Chris@436
|
1780 if (!t.startsWith(":")) havePersonal = true;
|
Chris@435
|
1781 byName.insert(QFileInfo(t).baseName());
|
Chris@435
|
1782 }
|
Chris@435
|
1783
|
Chris@435
|
1784 foreach (QString t, byName) {
|
Chris@435
|
1785 if (t.toLower() == "default") continue;
|
Chris@435
|
1786 action = new QAction(t, this);
|
Chris@435
|
1787 connect(action, SIGNAL(triggered()), this, SLOT(applyTemplate()));
|
Chris@435
|
1788 m_templatesMenu->addAction(action);
|
Chris@435
|
1789 }
|
Chris@435
|
1790
|
Chris@435
|
1791 if (!templates.empty()) m_templatesMenu->addSeparator();
|
Chris@435
|
1792
|
Chris@435
|
1793 if (!m_templateWatcher) {
|
Chris@435
|
1794 m_templateWatcher = new QFileSystemWatcher(this);
|
Chris@435
|
1795 m_templateWatcher->addPath(ResourceFinder().getResourceSaveDir("templates"));
|
Chris@435
|
1796 connect(m_templateWatcher, SIGNAL(directoryChanged(const QString &)),
|
Chris@435
|
1797 this, SLOT(setupTemplatesMenu()));
|
Chris@435
|
1798 }
|
Chris@436
|
1799
|
Chris@436
|
1800 QAction *setDefaultAction = new QAction(tr("Choose Default Template..."), this);
|
Chris@436
|
1801 setDefaultAction->setObjectName("set_default_template");
|
Chris@436
|
1802 connect(setDefaultAction, SIGNAL(triggered()), this, SLOT(preferences()));
|
Chris@436
|
1803 m_templatesMenu->addSeparator();
|
Chris@436
|
1804 m_templatesMenu->addAction(setDefaultAction);
|
Chris@436
|
1805
|
Chris@436
|
1806 m_manageTemplatesAction->setEnabled(havePersonal);
|
Chris@435
|
1807 }
|
Chris@435
|
1808
|
Chris@423
|
1809
|
Chris@423
|
1810 void
|
Chris@211
|
1811 MainWindow::setupRecentTransformsMenu()
|
Chris@34
|
1812 {
|
Chris@211
|
1813 m_recentTransformsMenu->clear();
|
Chris@211
|
1814 vector<QString> transforms = m_recentTransforms.getRecent();
|
Chris@34
|
1815 for (size_t i = 0; i < transforms.size(); ++i) {
|
Chris@211
|
1816 TransformActionReverseMap::iterator ti =
|
Chris@34
|
1817 m_transformActionsReverse.find(transforms[i]);
|
Chris@34
|
1818 if (ti == m_transformActionsReverse.end()) {
|
Chris@665
|
1819 cerr << "WARNING: MainWindow::setupRecentTransformsMenu: "
|
Chris@665
|
1820 << "Unknown transform \"" << transforms[i]
|
Chris@665
|
1821 << "\" in recent transforms list" << endl;
|
Chris@34
|
1822 continue;
|
Chris@34
|
1823 }
|
Chris@162
|
1824 if (i == 0) {
|
Chris@162
|
1825 ti->second->setShortcut(tr("Ctrl+T"));
|
Chris@162
|
1826 m_keyReference->registerShortcut
|
Chris@211
|
1827 (tr("Repeat Transform"),
|
Chris@528
|
1828 ti->second->shortcut().toString(),
|
Chris@163
|
1829 tr("Re-select the most recently run transform"));
|
Chris@216
|
1830 } else {
|
Chris@216
|
1831 ti->second->setShortcut(QString(""));
|
Chris@162
|
1832 }
|
Chris@211
|
1833 m_recentTransformsMenu->addAction(ti->second);
|
Chris@34
|
1834 }
|
Chris@34
|
1835 }
|
Chris@34
|
1836
|
Chris@34
|
1837 void
|
Chris@95
|
1838 MainWindow::setupExistingLayersMenus()
|
Chris@0
|
1839 {
|
Chris@0
|
1840 if (!m_existingLayersMenu) return; // should have been created by setupMenus
|
Chris@0
|
1841
|
Chris@438
|
1842 // SVDEBUG << "MainWindow::setupExistingLayersMenu" << endl;
|
Chris@0
|
1843
|
Chris@0
|
1844 m_existingLayersMenu->clear();
|
Chris@0
|
1845 m_existingLayerActions.clear();
|
Chris@0
|
1846
|
Chris@95
|
1847 m_sliceMenu->clear();
|
Chris@95
|
1848 m_sliceActions.clear();
|
Chris@95
|
1849
|
Chris@168
|
1850 IconLoader il;
|
Chris@168
|
1851
|
Chris@33
|
1852 vector<Layer *> orderedLayers;
|
Chris@33
|
1853 set<Layer *> observedLayers;
|
Chris@95
|
1854 set<Layer *> sliceableLayers;
|
Chris@95
|
1855
|
Chris@95
|
1856 LayerFactory *factory = LayerFactory::getInstance();
|
Chris@0
|
1857
|
Chris@0
|
1858 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@0
|
1859
|
Chris@0
|
1860 Pane *pane = m_paneStack->getPane(i);
|
Chris@0
|
1861 if (!pane) continue;
|
Chris@0
|
1862
|
Chris@0
|
1863 for (int j = 0; j < pane->getLayerCount(); ++j) {
|
Chris@0
|
1864
|
Chris@0
|
1865 Layer *layer = pane->getLayer(j);
|
Chris@0
|
1866 if (!layer) continue;
|
Chris@0
|
1867 if (observedLayers.find(layer) != observedLayers.end()) {
|
Chris@665
|
1868 // cerr << "found duplicate layer " << layer << endl;
|
Chris@0
|
1869 continue;
|
Chris@0
|
1870 }
|
Chris@0
|
1871
|
Chris@665
|
1872 // cerr << "found new layer " << layer << " (name = "
|
Chris@665
|
1873 // << layer->getLayerPresentationName() << ")" << endl;
|
Chris@0
|
1874
|
Chris@0
|
1875 orderedLayers.push_back(layer);
|
Chris@0
|
1876 observedLayers.insert(layer);
|
Chris@95
|
1877
|
Chris@95
|
1878 if (factory->isLayerSliceable(layer)) {
|
Chris@95
|
1879 sliceableLayers.insert(layer);
|
Chris@95
|
1880 }
|
Chris@0
|
1881 }
|
Chris@0
|
1882 }
|
Chris@0
|
1883
|
Chris@33
|
1884 map<QString, int> observedNames;
|
Chris@0
|
1885
|
Chris@137
|
1886 for (size_t i = 0; i < orderedLayers.size(); ++i) {
|
Chris@0
|
1887
|
Chris@95
|
1888 Layer *layer = orderedLayers[i];
|
Chris@95
|
1889
|
Chris@95
|
1890 QString name = layer->getLayerPresentationName();
|
Chris@0
|
1891 int n = ++observedNames[name];
|
Chris@0
|
1892 if (n > 1) name = QString("%1 <%2>").arg(name).arg(n);
|
Chris@0
|
1893
|
Chris@168
|
1894 QIcon icon = il.load(factory->getLayerIconName
|
Chris@168
|
1895 (factory->getLayerType(layer)));
|
Chris@95
|
1896
|
Chris@95
|
1897 QAction *action = new QAction(icon, name, this);
|
Chris@0
|
1898 connect(action, SIGNAL(triggered()), this, SLOT(addLayer()));
|
Chris@0
|
1899 connect(this, SIGNAL(canAddLayer(bool)), action, SLOT(setEnabled(bool)));
|
Chris@95
|
1900 m_existingLayerActions[action] = layer;
|
Chris@0
|
1901
|
Chris@0
|
1902 m_existingLayersMenu->addAction(action);
|
Chris@95
|
1903
|
Chris@95
|
1904 if (sliceableLayers.find(layer) != sliceableLayers.end()) {
|
Chris@95
|
1905 action = new QAction(icon, name, this);
|
Chris@95
|
1906 connect(action, SIGNAL(triggered()), this, SLOT(addLayer()));
|
Chris@95
|
1907 connect(this, SIGNAL(canAddLayer(bool)), action, SLOT(setEnabled(bool)));
|
Chris@95
|
1908 m_sliceActions[action] = layer;
|
Chris@95
|
1909 m_sliceMenu->addAction(action);
|
Chris@95
|
1910 }
|
Chris@0
|
1911 }
|
Chris@95
|
1912
|
Chris@95
|
1913 m_sliceMenu->setEnabled(!m_sliceActions.empty());
|
Chris@0
|
1914 }
|
Chris@0
|
1915
|
Chris@0
|
1916 void
|
Chris@0
|
1917 MainWindow::setupToolbars()
|
Chris@0
|
1918 {
|
Chris@162
|
1919 m_keyReference->setCategory(tr("Playback and Transport Controls"));
|
Chris@162
|
1920
|
Chris@168
|
1921 IconLoader il;
|
Chris@168
|
1922
|
Chris@155
|
1923 QMenu *menu = m_playbackMenu = menuBar()->addMenu(tr("Play&back"));
|
Chris@155
|
1924 menu->setTearOffEnabled(true);
|
Chris@155
|
1925 m_rightButtonMenu->addSeparator();
|
Chris@155
|
1926 m_rightButtonPlaybackMenu = m_rightButtonMenu->addMenu(tr("Playback"));
|
Chris@155
|
1927
|
Chris@155
|
1928 QToolBar *toolbar = addToolBar(tr("Playback Toolbar"));
|
Chris@155
|
1929
|
Chris@265
|
1930 m_rwdStartAction = toolbar->addAction(il.load("rewind-start"),
|
Chris@265
|
1931 tr("Rewind to Start"));
|
Chris@265
|
1932 m_rwdStartAction->setShortcut(tr("Home"));
|
Chris@265
|
1933 m_rwdStartAction->setStatusTip(tr("Rewind to the start"));
|
Chris@265
|
1934 connect(m_rwdStartAction, SIGNAL(triggered()), this, SLOT(rewindStart()));
|
Chris@265
|
1935 connect(this, SIGNAL(canPlay(bool)), m_rwdStartAction, SLOT(setEnabled(bool)));
|
Chris@265
|
1936
|
Chris@265
|
1937 m_rwdAction = toolbar->addAction(il.load("rewind"), tr("Rewind"));
|
Chris@155
|
1938 m_rwdAction->setShortcut(tr("PgUp"));
|
Chris@163
|
1939 m_rwdAction->setStatusTip(tr("Rewind to the previous time instant or time ruler notch"));
|
Chris@155
|
1940 connect(m_rwdAction, SIGNAL(triggered()), this, SLOT(rewind()));
|
Chris@155
|
1941 connect(this, SIGNAL(canRewind(bool)), m_rwdAction, SLOT(setEnabled(bool)));
|
Chris@155
|
1942
|
Chris@323
|
1943 m_rwdSimilarAction = new QAction(tr("Rewind to Similar Point"), this);
|
Chris@323
|
1944 m_rwdSimilarAction->setShortcut(tr("Shift+PgUp"));
|
Chris@323
|
1945 m_rwdSimilarAction->setStatusTip(tr("Rewind to the previous similarly valued time instant"));
|
Chris@323
|
1946 connect(m_rwdSimilarAction, SIGNAL(triggered()), this, SLOT(rewindSimilar()));
|
Chris@323
|
1947 connect(this, SIGNAL(canRewind(bool)), m_rwdSimilarAction, SLOT(setEnabled(bool)));
|
Chris@323
|
1948
|
Chris@265
|
1949 m_playAction = toolbar->addAction(il.load("playpause"),
|
Chris@265
|
1950 tr("Play / Pause"));
|
Chris@265
|
1951 m_playAction->setCheckable(true);
|
Chris@265
|
1952 m_playAction->setShortcut(tr("Space"));
|
Chris@265
|
1953 m_playAction->setStatusTip(tr("Start or stop playback from the current position"));
|
Chris@265
|
1954 connect(m_playAction, SIGNAL(triggered()), this, SLOT(play()));
|
Chris@0
|
1955 connect(m_playSource, SIGNAL(playStatusChanged(bool)),
|
Chris@265
|
1956 m_playAction, SLOT(setChecked(bool)));
|
Chris@305
|
1957 connect(m_playSource, SIGNAL(playStatusChanged(bool)),
|
Chris@305
|
1958 this, SLOT(playStatusChanged(bool)));
|
Chris@265
|
1959 connect(this, SIGNAL(canPlay(bool)), m_playAction, SLOT(setEnabled(bool)));
|
Chris@155
|
1960
|
Chris@168
|
1961 m_ffwdAction = toolbar->addAction(il.load("ffwd"),
|
Chris@286
|
1962 tr("Fast Forward"));
|
Chris@155
|
1963 m_ffwdAction->setShortcut(tr("PgDown"));
|
Chris@163
|
1964 m_ffwdAction->setStatusTip(tr("Fast-forward to the next time instant or time ruler notch"));
|
Chris@155
|
1965 connect(m_ffwdAction, SIGNAL(triggered()), this, SLOT(ffwd()));
|
Chris@155
|
1966 connect(this, SIGNAL(canFfwd(bool)), m_ffwdAction, SLOT(setEnabled(bool)));
|
Chris@155
|
1967
|
Chris@323
|
1968 m_ffwdSimilarAction = new QAction(tr("Fast Forward to Similar Point"), this);
|
Chris@323
|
1969 m_ffwdSimilarAction->setShortcut(tr("Shift+PgDown"));
|
Chris@323
|
1970 m_ffwdSimilarAction->setStatusTip(tr("Fast-forward to the next similarly valued time instant"));
|
Chris@323
|
1971 connect(m_ffwdSimilarAction, SIGNAL(triggered()), this, SLOT(ffwdSimilar()));
|
Chris@323
|
1972 connect(this, SIGNAL(canFfwd(bool)), m_ffwdSimilarAction, SLOT(setEnabled(bool)));
|
Chris@323
|
1973
|
Chris@265
|
1974 m_ffwdEndAction = toolbar->addAction(il.load("ffwd-end"),
|
Chris@265
|
1975 tr("Fast Forward to End"));
|
Chris@265
|
1976 m_ffwdEndAction->setShortcut(tr("End"));
|
Chris@265
|
1977 m_ffwdEndAction->setStatusTip(tr("Fast-forward to the end"));
|
Chris@265
|
1978 connect(m_ffwdEndAction, SIGNAL(triggered()), this, SLOT(ffwdEnd()));
|
Chris@265
|
1979 connect(this, SIGNAL(canPlay(bool)), m_ffwdEndAction, SLOT(setEnabled(bool)));
|
Chris@0
|
1980
|
Chris@0
|
1981 toolbar = addToolBar(tr("Play Mode Toolbar"));
|
Chris@0
|
1982
|
Chris@265
|
1983 m_playSelectionAction = toolbar->addAction(il.load("playselection"),
|
Chris@265
|
1984 tr("Constrain Playback to Selection"));
|
Chris@265
|
1985 m_playSelectionAction->setCheckable(true);
|
Chris@265
|
1986 m_playSelectionAction->setChecked(m_viewManager->getPlaySelectionMode());
|
Chris@265
|
1987 m_playSelectionAction->setShortcut(tr("s"));
|
Chris@265
|
1988 m_playSelectionAction->setStatusTip(tr("Constrain playback to the selected regions"));
|
Chris@69
|
1989 connect(m_viewManager, SIGNAL(playSelectionModeChanged(bool)),
|
Chris@265
|
1990 m_playSelectionAction, SLOT(setChecked(bool)));
|
Chris@265
|
1991 connect(m_playSelectionAction, SIGNAL(triggered()), this, SLOT(playSelectionToggled()));
|
Chris@265
|
1992 connect(this, SIGNAL(canPlaySelection(bool)), m_playSelectionAction, SLOT(setEnabled(bool)));
|
Chris@265
|
1993
|
Chris@265
|
1994 m_playLoopAction = toolbar->addAction(il.load("playloop"),
|
Chris@265
|
1995 tr("Loop Playback"));
|
Chris@265
|
1996 m_playLoopAction->setCheckable(true);
|
Chris@265
|
1997 m_playLoopAction->setChecked(m_viewManager->getPlayLoopMode());
|
Chris@265
|
1998 m_playLoopAction->setShortcut(tr("l"));
|
Chris@265
|
1999 m_playLoopAction->setStatusTip(tr("Loop playback"));
|
Chris@69
|
2000 connect(m_viewManager, SIGNAL(playLoopModeChanged(bool)),
|
Chris@265
|
2001 m_playLoopAction, SLOT(setChecked(bool)));
|
Chris@265
|
2002 connect(m_playLoopAction, SIGNAL(triggered()), this, SLOT(playLoopToggled()));
|
Chris@265
|
2003 connect(this, SIGNAL(canPlay(bool)), m_playLoopAction, SLOT(setEnabled(bool)));
|
Chris@155
|
2004
|
Chris@207
|
2005 m_soloAction = toolbar->addAction(il.load("solo"),
|
Chris@323
|
2006 tr("Solo Current Pane"));
|
Chris@207
|
2007 m_soloAction->setCheckable(true);
|
Chris@207
|
2008 m_soloAction->setChecked(m_viewManager->getPlaySoloMode());
|
Chris@207
|
2009 m_prevSolo = m_viewManager->getPlaySoloMode();
|
Chris@207
|
2010 m_soloAction->setShortcut(tr("o"));
|
Chris@207
|
2011 m_soloAction->setStatusTip(tr("Solo the current pane during playback"));
|
Chris@180
|
2012 connect(m_viewManager, SIGNAL(playSoloModeChanged(bool)),
|
Chris@207
|
2013 m_soloAction, SLOT(setChecked(bool)));
|
Chris@207
|
2014 connect(m_soloAction, SIGNAL(triggered()), this, SLOT(playSoloToggled()));
|
Chris@207
|
2015 connect(this, SIGNAL(canChangeSolo(bool)), m_soloAction, SLOT(setEnabled(bool)));
|
Chris@180
|
2016
|
Chris@208
|
2017 QAction *alAction = 0;
|
Chris@208
|
2018 if (Document::canAlign()) {
|
Chris@208
|
2019 alAction = toolbar->addAction(il.load("align"),
|
Chris@208
|
2020 tr("Align File Timelines"));
|
Chris@208
|
2021 alAction->setCheckable(true);
|
Chris@208
|
2022 alAction->setChecked(m_viewManager->getAlignMode());
|
Chris@208
|
2023 alAction->setStatusTip(tr("Treat multiple audio files as versions of the same work, and align their timelines"));
|
Chris@208
|
2024 connect(m_viewManager, SIGNAL(alignModeChanged(bool)),
|
Chris@208
|
2025 alAction, SLOT(setChecked(bool)));
|
Chris@208
|
2026 connect(alAction, SIGNAL(triggered()), this, SLOT(alignToggled()));
|
Chris@208
|
2027 connect(this, SIGNAL(canAlign(bool)), alAction, SLOT(setEnabled(bool)));
|
Chris@208
|
2028 }
|
Chris@206
|
2029
|
Chris@265
|
2030 m_keyReference->registerShortcut(m_playAction);
|
Chris@265
|
2031 m_keyReference->registerShortcut(m_playSelectionAction);
|
Chris@265
|
2032 m_keyReference->registerShortcut(m_playLoopAction);
|
Chris@207
|
2033 m_keyReference->registerShortcut(m_soloAction);
|
Chris@208
|
2034 if (alAction) m_keyReference->registerShortcut(alAction);
|
Chris@162
|
2035 m_keyReference->registerShortcut(m_rwdAction);
|
Chris@162
|
2036 m_keyReference->registerShortcut(m_ffwdAction);
|
Chris@323
|
2037 m_keyReference->registerShortcut(m_rwdSimilarAction);
|
Chris@323
|
2038 m_keyReference->registerShortcut(m_ffwdSimilarAction);
|
Chris@265
|
2039 m_keyReference->registerShortcut(m_rwdStartAction);
|
Chris@265
|
2040 m_keyReference->registerShortcut(m_ffwdEndAction);
|
Chris@265
|
2041
|
Chris@265
|
2042 menu->addAction(m_playAction);
|
Chris@265
|
2043 menu->addAction(m_playSelectionAction);
|
Chris@265
|
2044 menu->addAction(m_playLoopAction);
|
Chris@207
|
2045 menu->addAction(m_soloAction);
|
Chris@208
|
2046 if (alAction) menu->addAction(alAction);
|
Chris@155
|
2047 menu->addSeparator();
|
Chris@155
|
2048 menu->addAction(m_rwdAction);
|
Chris@155
|
2049 menu->addAction(m_ffwdAction);
|
Chris@155
|
2050 menu->addSeparator();
|
Chris@323
|
2051 menu->addAction(m_rwdSimilarAction);
|
Chris@323
|
2052 menu->addAction(m_ffwdSimilarAction);
|
Chris@323
|
2053 menu->addSeparator();
|
Chris@265
|
2054 menu->addAction(m_rwdStartAction);
|
Chris@265
|
2055 menu->addAction(m_ffwdEndAction);
|
Chris@155
|
2056 menu->addSeparator();
|
Chris@155
|
2057
|
Chris@265
|
2058 m_rightButtonPlaybackMenu->addAction(m_playAction);
|
Chris@265
|
2059 m_rightButtonPlaybackMenu->addAction(m_playSelectionAction);
|
Chris@265
|
2060 m_rightButtonPlaybackMenu->addAction(m_playLoopAction);
|
Chris@207
|
2061 m_rightButtonPlaybackMenu->addAction(m_soloAction);
|
Chris@208
|
2062 if (alAction) m_rightButtonPlaybackMenu->addAction(alAction);
|
Chris@155
|
2063 m_rightButtonPlaybackMenu->addSeparator();
|
Chris@155
|
2064 m_rightButtonPlaybackMenu->addAction(m_rwdAction);
|
Chris@155
|
2065 m_rightButtonPlaybackMenu->addAction(m_ffwdAction);
|
Chris@155
|
2066 m_rightButtonPlaybackMenu->addSeparator();
|
Chris@265
|
2067 m_rightButtonPlaybackMenu->addAction(m_rwdStartAction);
|
Chris@265
|
2068 m_rightButtonPlaybackMenu->addAction(m_ffwdEndAction);
|
Chris@155
|
2069 m_rightButtonPlaybackMenu->addSeparator();
|
Chris@155
|
2070
|
Chris@155
|
2071 QAction *fastAction = menu->addAction(tr("Speed Up"));
|
Chris@155
|
2072 fastAction->setShortcut(tr("Ctrl+PgUp"));
|
Chris@163
|
2073 fastAction->setStatusTip(tr("Time-stretch playback to speed it up without changing pitch"));
|
Chris@155
|
2074 connect(fastAction, SIGNAL(triggered()), this, SLOT(speedUpPlayback()));
|
Chris@155
|
2075 connect(this, SIGNAL(canSpeedUpPlayback(bool)), fastAction, SLOT(setEnabled(bool)));
|
Chris@155
|
2076
|
Chris@155
|
2077 QAction *slowAction = menu->addAction(tr("Slow Down"));
|
Chris@155
|
2078 slowAction->setShortcut(tr("Ctrl+PgDown"));
|
Chris@163
|
2079 slowAction->setStatusTip(tr("Time-stretch playback to slow it down without changing pitch"));
|
Chris@155
|
2080 connect(slowAction, SIGNAL(triggered()), this, SLOT(slowDownPlayback()));
|
Chris@155
|
2081 connect(this, SIGNAL(canSlowDownPlayback(bool)), slowAction, SLOT(setEnabled(bool)));
|
Chris@155
|
2082
|
Chris@155
|
2083 QAction *normalAction = menu->addAction(tr("Restore Normal Speed"));
|
Chris@155
|
2084 normalAction->setShortcut(tr("Ctrl+Home"));
|
Chris@163
|
2085 normalAction->setStatusTip(tr("Restore non-time-stretched playback"));
|
Chris@155
|
2086 connect(normalAction, SIGNAL(triggered()), this, SLOT(restoreNormalPlayback()));
|
Chris@155
|
2087 connect(this, SIGNAL(canChangePlaybackSpeed(bool)), normalAction, SLOT(setEnabled(bool)));
|
Chris@155
|
2088
|
Chris@162
|
2089 m_keyReference->registerShortcut(fastAction);
|
Chris@162
|
2090 m_keyReference->registerShortcut(slowAction);
|
Chris@162
|
2091 m_keyReference->registerShortcut(normalAction);
|
Chris@162
|
2092
|
Chris@155
|
2093 m_rightButtonPlaybackMenu->addAction(fastAction);
|
Chris@155
|
2094 m_rightButtonPlaybackMenu->addAction(slowAction);
|
Chris@155
|
2095 m_rightButtonPlaybackMenu->addAction(normalAction);
|
Chris@0
|
2096
|
Chris@0
|
2097 toolbar = addToolBar(tr("Edit Toolbar"));
|
Chris@0
|
2098 CommandHistory::getInstance()->registerToolbar(toolbar);
|
Chris@0
|
2099
|
Chris@0
|
2100 toolbar = addToolBar(tr("Tools Toolbar"));
|
Chris@0
|
2101 QActionGroup *group = new QActionGroup(this);
|
Chris@0
|
2102
|
Chris@705
|
2103 m_keyReference->setCategory(tr("Tool Selection"));
|
Chris@168
|
2104 QAction *action = toolbar->addAction(il.load("navigate"),
|
Chris@155
|
2105 tr("Navigate"));
|
Chris@0
|
2106 action->setCheckable(true);
|
Chris@0
|
2107 action->setChecked(true);
|
Chris@0
|
2108 action->setShortcut(tr("1"));
|
Chris@90
|
2109 action->setStatusTip(tr("Navigate"));
|
Chris@0
|
2110 connect(action, SIGNAL(triggered()), this, SLOT(toolNavigateSelected()));
|
Chris@596
|
2111 connect(this, SIGNAL(replacedDocument()), action, SLOT(trigger()));
|
Chris@0
|
2112 group->addAction(action);
|
Chris@162
|
2113 m_keyReference->registerShortcut(action);
|
Chris@0
|
2114 m_toolActions[ViewManager::NavigateMode] = action;
|
Chris@705
|
2115
|
Chris@705
|
2116 m_keyReference->setCategory
|
Chris@705
|
2117 (tr("Navigate Tool Mouse Actions"));
|
Chris@705
|
2118 m_keyReference->registerShortcut
|
Chris@705
|
2119 (tr("Navigate"), tr("Left"),
|
Chris@705
|
2120 tr("Click left button and drag to move around"));
|
Chris@705
|
2121 m_keyReference->registerShortcut
|
Chris@705
|
2122 (tr("Zoom to Area"), tr("Shift+Left"),
|
Chris@705
|
2123 tr("Shift-click left button and drag to zoom to a rectangular area"));
|
Chris@705
|
2124 m_keyReference->registerShortcut
|
Chris@705
|
2125 (tr("Relocate"), tr("Double-Click Left"),
|
Chris@705
|
2126 tr("Double-click left button to jump to clicked location"));
|
Chris@705
|
2127 m_keyReference->registerShortcut
|
Chris@705
|
2128 (tr("Edit"), tr("Double-Click Left"),
|
Chris@705
|
2129 tr("Double-click left button on an item to edit it"));
|
Chris@705
|
2130
|
Chris@705
|
2131 m_keyReference->setCategory(tr("Tool Selection"));
|
Chris@168
|
2132 action = toolbar->addAction(il.load("select"),
|
Chris@0
|
2133 tr("Select"));
|
Chris@0
|
2134 action->setCheckable(true);
|
Chris@0
|
2135 action->setShortcut(tr("2"));
|
Chris@90
|
2136 action->setStatusTip(tr("Select ranges"));
|
Chris@0
|
2137 connect(action, SIGNAL(triggered()), this, SLOT(toolSelectSelected()));
|
Chris@0
|
2138 group->addAction(action);
|
Chris@162
|
2139 m_keyReference->registerShortcut(action);
|
Chris@0
|
2140 m_toolActions[ViewManager::SelectMode] = action;
|
Chris@705
|
2141
|
Chris@705
|
2142 m_keyReference->setCategory
|
Chris@705
|
2143 (tr("Select Tool Mouse Actions"));
|
Chris@705
|
2144 m_keyReference->registerShortcut
|
Chris@705
|
2145 (tr("Select"), tr("Left"),
|
Chris@705
|
2146 tr("Click left button and drag to select region; drag region edge to resize"));
|
Chris@705
|
2147 #ifdef Q_OS_MAC
|
Chris@705
|
2148 m_keyReference->registerShortcut
|
Chris@705
|
2149 (tr("Multi Select"), tr("Ctrl+Left"),
|
Chris@705
|
2150 tr("Cmd-click left button and drag to select an additional region"));
|
Chris@705
|
2151 #else
|
Chris@705
|
2152 m_keyReference->registerShortcut
|
Chris@705
|
2153 (tr("Multi Select"), tr("Ctrl+Left"),
|
Chris@705
|
2154 tr("Ctrl-click left button and drag to select an additional region"));
|
Chris@705
|
2155 #endif
|
Chris@705
|
2156 m_keyReference->registerShortcut
|
Chris@705
|
2157 (tr("Fine Select"), tr("Shift+Left"),
|
Chris@705
|
2158 tr("Shift-click left button and drag to select without snapping to items or grid"));
|
Chris@705
|
2159
|
Chris@705
|
2160 m_keyReference->setCategory(tr("Tool Selection"));
|
Chris@168
|
2161 action = toolbar->addAction(il.load("move"),
|
Chris@0
|
2162 tr("Edit"));
|
Chris@0
|
2163 action->setCheckable(true);
|
Chris@0
|
2164 action->setShortcut(tr("3"));
|
Chris@90
|
2165 action->setStatusTip(tr("Edit items in layer"));
|
Chris@0
|
2166 connect(action, SIGNAL(triggered()), this, SLOT(toolEditSelected()));
|
Chris@0
|
2167 connect(this, SIGNAL(canEditLayer(bool)), action, SLOT(setEnabled(bool)));
|
Chris@0
|
2168 group->addAction(action);
|
Chris@162
|
2169 m_keyReference->registerShortcut(action);
|
Chris@0
|
2170 m_toolActions[ViewManager::EditMode] = action;
|
Chris@705
|
2171
|
Chris@705
|
2172 m_keyReference->setCategory
|
Chris@705
|
2173 (tr("Edit Tool Mouse Actions"));
|
Chris@705
|
2174 m_keyReference->registerShortcut
|
Chris@705
|
2175 (tr("Move"), tr("Left"),
|
Chris@705
|
2176 tr("Click left button on an item or selected region and drag to move"));
|
Chris@705
|
2177 m_keyReference->registerShortcut
|
Chris@705
|
2178 (tr("Edit"), tr("Double-Click Left"),
|
Chris@705
|
2179 tr("Double-click left button on an item to edit it"));
|
Chris@705
|
2180
|
Chris@705
|
2181 m_keyReference->setCategory(tr("Tool Selection"));
|
Chris@168
|
2182 action = toolbar->addAction(il.load("draw"),
|
Chris@0
|
2183 tr("Draw"));
|
Chris@0
|
2184 action->setCheckable(true);
|
Chris@0
|
2185 action->setShortcut(tr("4"));
|
Chris@90
|
2186 action->setStatusTip(tr("Draw new items in layer"));
|
Chris@0
|
2187 connect(action, SIGNAL(triggered()), this, SLOT(toolDrawSelected()));
|
Chris@0
|
2188 connect(this, SIGNAL(canEditLayer(bool)), action, SLOT(setEnabled(bool)));
|
Chris@0
|
2189 group->addAction(action);
|
Chris@162
|
2190 m_keyReference->registerShortcut(action);
|
Chris@0
|
2191 m_toolActions[ViewManager::DrawMode] = action;
|
Chris@0
|
2192
|
Chris@705
|
2193 m_keyReference->setCategory
|
Chris@705
|
2194 (tr("Draw Tool Mouse Actions"));
|
Chris@705
|
2195 m_keyReference->registerShortcut
|
Chris@705
|
2196 (tr("Draw"), tr("Left"),
|
Chris@705
|
2197 tr("Click left button and drag to create new item"));
|
Chris@705
|
2198
|
Chris@705
|
2199 m_keyReference->setCategory(tr("Tool Selection"));
|
Chris@217
|
2200 action = toolbar->addAction(il.load("erase"),
|
Chris@217
|
2201 tr("Erase"));
|
Chris@217
|
2202 action->setCheckable(true);
|
Chris@217
|
2203 action->setShortcut(tr("5"));
|
Chris@217
|
2204 action->setStatusTip(tr("Erase items from layer"));
|
Chris@217
|
2205 connect(action, SIGNAL(triggered()), this, SLOT(toolEraseSelected()));
|
Chris@217
|
2206 connect(this, SIGNAL(canEditLayer(bool)), action, SLOT(setEnabled(bool)));
|
Chris@217
|
2207 group->addAction(action);
|
Chris@217
|
2208 m_keyReference->registerShortcut(action);
|
Chris@217
|
2209 m_toolActions[ViewManager::EraseMode] = action;
|
Chris@217
|
2210
|
Chris@705
|
2211 m_keyReference->setCategory
|
Chris@705
|
2212 (tr("Erase Tool Mouse Actions"));
|
Chris@705
|
2213 m_keyReference->registerShortcut
|
Chris@705
|
2214 (tr("Erase"), tr("Left"),
|
Chris@705
|
2215 tr("Click left button on an item to remove it from the layer"));
|
Chris@705
|
2216
|
Chris@705
|
2217 m_keyReference->setCategory(tr("Tool Selection"));
|
Chris@265
|
2218 action = toolbar->addAction(il.load("measure"), tr("Measure"));
|
Chris@151
|
2219 action->setCheckable(true);
|
Chris@217
|
2220 action->setShortcut(tr("6"));
|
Chris@151
|
2221 action->setStatusTip(tr("Make measurements in layer"));
|
Chris@151
|
2222 connect(action, SIGNAL(triggered()), this, SLOT(toolMeasureSelected()));
|
Chris@169
|
2223 connect(this, SIGNAL(canMeasureLayer(bool)), action, SLOT(setEnabled(bool)));
|
Chris@151
|
2224 group->addAction(action);
|
Chris@162
|
2225 m_keyReference->registerShortcut(action);
|
Chris@151
|
2226 m_toolActions[ViewManager::MeasureMode] = action;
|
Chris@151
|
2227
|
Chris@705
|
2228 m_keyReference->setCategory
|
Chris@705
|
2229 (tr("Measure Tool Mouse Actions"));
|
Chris@705
|
2230 m_keyReference->registerShortcut
|
Chris@705
|
2231 (tr("Measure Area"), tr("Left"),
|
Chris@705
|
2232 tr("Click left button and drag to measure a rectangular area"));
|
Chris@705
|
2233 m_keyReference->registerShortcut
|
Chris@705
|
2234 (tr("Measure Item"), tr("Double-Click Left"),
|
Chris@705
|
2235 tr("Click left button and drag to measure extents of an item or shape"));
|
Chris@705
|
2236 m_keyReference->registerShortcut
|
Chris@705
|
2237 (tr("Zoom to Area"), tr("Shift+Left"),
|
Chris@705
|
2238 tr("Shift-click left button and drag to zoom to a rectangular area"));
|
Chris@705
|
2239
|
Chris@0
|
2240 toolNavigateSelected();
|
Chris@163
|
2241
|
Chris@163
|
2242 Pane::registerShortcuts(*m_keyReference);
|
Chris@0
|
2243 }
|
Chris@0
|
2244
|
Chris@0
|
2245 void
|
Chris@265
|
2246 MainWindow::connectLayerEditDialog(ModelDataTableDialog *dialog)
|
Chris@265
|
2247 {
|
Chris@265
|
2248 MainWindowBase::connectLayerEditDialog(dialog);
|
Chris@265
|
2249 QToolBar *toolbar = dialog->getPlayToolbar();
|
Chris@265
|
2250 if (toolbar) {
|
Chris@265
|
2251 toolbar->addAction(m_rwdStartAction);
|
Chris@265
|
2252 toolbar->addAction(m_rwdAction);
|
Chris@265
|
2253 toolbar->addAction(m_playAction);
|
Chris@265
|
2254 toolbar->addAction(m_ffwdAction);
|
Chris@265
|
2255 toolbar->addAction(m_ffwdEndAction);
|
Chris@265
|
2256 }
|
Chris@265
|
2257 }
|
Chris@265
|
2258
|
Chris@265
|
2259 void
|
Chris@0
|
2260 MainWindow::updateMenuStates()
|
Chris@0
|
2261 {
|
Chris@200
|
2262 MainWindowBase::updateMenuStates();
|
Chris@200
|
2263
|
Chris@117
|
2264 Pane *currentPane = 0;
|
Chris@117
|
2265 Layer *currentLayer = 0;
|
Chris@117
|
2266
|
Chris@117
|
2267 if (m_paneStack) currentPane = m_paneStack->getCurrentPane();
|
Chris@117
|
2268 if (currentPane) currentLayer = currentPane->getSelectedLayer();
|
Chris@117
|
2269
|
Chris@0
|
2270 bool haveCurrentPane =
|
Chris@117
|
2271 (currentPane != 0);
|
Chris@0
|
2272 bool haveCurrentLayer =
|
Chris@117
|
2273 (haveCurrentPane &&
|
Chris@117
|
2274 (currentLayer != 0));
|
Chris@206
|
2275 bool havePlayTarget =
|
Chris@206
|
2276 (m_playTarget != 0);
|
Chris@0
|
2277 bool haveSelection =
|
Chris@0
|
2278 (m_viewManager &&
|
Chris@0
|
2279 !m_viewManager->getSelections().empty());
|
Chris@0
|
2280 bool haveCurrentEditableLayer =
|
Chris@0
|
2281 (haveCurrentLayer &&
|
Chris@117
|
2282 currentLayer->isLayerEditable());
|
Chris@0
|
2283 bool haveCurrentTimeInstantsLayer =
|
Chris@0
|
2284 (haveCurrentLayer &&
|
Chris@117
|
2285 dynamic_cast<TimeInstantLayer *>(currentLayer));
|
Chris@0
|
2286 bool haveCurrentTimeValueLayer =
|
Chris@0
|
2287 (haveCurrentLayer &&
|
Chris@117
|
2288 dynamic_cast<TimeValueLayer *>(currentLayer));
|
Chris@207
|
2289
|
Chris@314
|
2290 bool alignMode = m_viewManager && m_viewManager->getAlignMode();
|
Chris@314
|
2291 emit canChangeSolo(havePlayTarget && !alignMode);
|
Chris@207
|
2292 emit canAlign(havePlayTarget && m_document && m_document->canAlign());
|
Chris@206
|
2293
|
Chris@200
|
2294 emit canChangePlaybackSpeed(true);
|
Chris@200
|
2295 int v = m_playSpeed->value();
|
Chris@200
|
2296 emit canSpeedUpPlayback(v < m_playSpeed->maximum());
|
Chris@200
|
2297 emit canSlowDownPlayback(v > m_playSpeed->minimum());
|
Chris@155
|
2298
|
Chris@164
|
2299 if (m_viewManager &&
|
Chris@164
|
2300 (m_viewManager->getToolMode() == ViewManager::MeasureMode)) {
|
Chris@164
|
2301 emit canDeleteSelection(haveCurrentLayer);
|
Chris@164
|
2302 m_deleteSelectedAction->setText(tr("&Delete Current Measurement"));
|
Chris@164
|
2303 m_deleteSelectedAction->setStatusTip(tr("Delete the measurement currently under the mouse pointer"));
|
Chris@164
|
2304 } else {
|
Chris@164
|
2305 emit canDeleteSelection(haveSelection && haveCurrentEditableLayer);
|
Chris@164
|
2306 m_deleteSelectedAction->setText(tr("&Delete Selected Items"));
|
Chris@164
|
2307 m_deleteSelectedAction->setStatusTip(tr("Delete items in current selection from the current layer"));
|
Chris@164
|
2308 }
|
Chris@164
|
2309
|
Chris@155
|
2310 if (m_ffwdAction && m_rwdAction) {
|
Chris@155
|
2311 if (haveCurrentTimeInstantsLayer) {
|
Chris@155
|
2312 m_ffwdAction->setText(tr("Fast Forward to Next Instant"));
|
Chris@155
|
2313 m_ffwdAction->setStatusTip(tr("Fast forward to the next time instant in the current layer"));
|
Chris@155
|
2314 m_rwdAction->setText(tr("Rewind to Previous Instant"));
|
Chris@155
|
2315 m_rwdAction->setStatusTip(tr("Rewind to the previous time instant in the current layer"));
|
Chris@155
|
2316 } else if (haveCurrentTimeValueLayer) {
|
Chris@155
|
2317 m_ffwdAction->setText(tr("Fast Forward to Next Point"));
|
Chris@155
|
2318 m_ffwdAction->setStatusTip(tr("Fast forward to the next point in the current layer"));
|
Chris@155
|
2319 m_rwdAction->setText(tr("Rewind to Previous Point"));
|
Chris@155
|
2320 m_rwdAction->setStatusTip(tr("Rewind to the previous point in the current layer"));
|
Chris@155
|
2321 } else {
|
Chris@155
|
2322 m_ffwdAction->setText(tr("Fast Forward"));
|
Chris@155
|
2323 m_ffwdAction->setStatusTip(tr("Fast forward"));
|
Chris@155
|
2324 m_rwdAction->setText(tr("Rewind"));
|
Chris@155
|
2325 m_rwdAction->setStatusTip(tr("Rewind"));
|
Chris@155
|
2326 }
|
Chris@155
|
2327 }
|
Chris@0
|
2328 }
|
Chris@0
|
2329
|
Chris@0
|
2330 void
|
Chris@0
|
2331 MainWindow::updateDescriptionLabel()
|
Chris@0
|
2332 {
|
Chris@0
|
2333 if (!getMainModel()) {
|
Chris@0
|
2334 m_descriptionLabel->setText(tr("No audio file loaded."));
|
Chris@0
|
2335 return;
|
Chris@0
|
2336 }
|
Chris@0
|
2337
|
Chris@0
|
2338 QString description;
|
Chris@0
|
2339
|
Chris@730
|
2340 int ssr = getMainModel()->getSampleRate();
|
Chris@730
|
2341 int tsr = ssr;
|
Chris@0
|
2342 if (m_playSource) tsr = m_playSource->getTargetSampleRate();
|
Chris@0
|
2343
|
Chris@0
|
2344 if (ssr != tsr) {
|
Chris@0
|
2345 description = tr("%1Hz (resampling to %2Hz)").arg(ssr).arg(tsr);
|
Chris@0
|
2346 } else {
|
Chris@0
|
2347 description = QString("%1Hz").arg(ssr);
|
Chris@0
|
2348 }
|
Chris@0
|
2349
|
Chris@0
|
2350 description = QString("%1 - %2")
|
Chris@0
|
2351 .arg(RealTime::frame2RealTime(getMainModel()->getEndFrame(), ssr)
|
Chris@0
|
2352 .toText(false).c_str())
|
Chris@0
|
2353 .arg(description);
|
Chris@0
|
2354
|
Chris@0
|
2355 m_descriptionLabel->setText(description);
|
Chris@0
|
2356 }
|
Chris@0
|
2357
|
Chris@0
|
2358 void
|
Chris@0
|
2359 MainWindow::documentModified()
|
Chris@0
|
2360 {
|
Chris@200
|
2361 //!!!
|
Chris@200
|
2362 MainWindowBase::documentModified();
|
Chris@0
|
2363 }
|
Chris@0
|
2364
|
Chris@0
|
2365 void
|
Chris@0
|
2366 MainWindow::documentRestored()
|
Chris@0
|
2367 {
|
Chris@200
|
2368 //!!!
|
Chris@200
|
2369 MainWindowBase::documentRestored();
|
Chris@0
|
2370 }
|
Chris@0
|
2371
|
Chris@0
|
2372 void
|
Chris@0
|
2373 MainWindow::toolNavigateSelected()
|
Chris@0
|
2374 {
|
Chris@0
|
2375 m_viewManager->setToolMode(ViewManager::NavigateMode);
|
Chris@0
|
2376 }
|
Chris@0
|
2377
|
Chris@0
|
2378 void
|
Chris@0
|
2379 MainWindow::toolSelectSelected()
|
Chris@0
|
2380 {
|
Chris@0
|
2381 m_viewManager->setToolMode(ViewManager::SelectMode);
|
Chris@0
|
2382 }
|
Chris@0
|
2383
|
Chris@0
|
2384 void
|
Chris@0
|
2385 MainWindow::toolEditSelected()
|
Chris@0
|
2386 {
|
Chris@0
|
2387 m_viewManager->setToolMode(ViewManager::EditMode);
|
Chris@0
|
2388 }
|
Chris@0
|
2389
|
Chris@0
|
2390 void
|
Chris@0
|
2391 MainWindow::toolDrawSelected()
|
Chris@0
|
2392 {
|
Chris@0
|
2393 m_viewManager->setToolMode(ViewManager::DrawMode);
|
Chris@0
|
2394 }
|
Chris@0
|
2395
|
Chris@151
|
2396 void
|
Chris@217
|
2397 MainWindow::toolEraseSelected()
|
Chris@217
|
2398 {
|
Chris@217
|
2399 m_viewManager->setToolMode(ViewManager::EraseMode);
|
Chris@217
|
2400 }
|
Chris@217
|
2401
|
Chris@217
|
2402 void
|
Chris@151
|
2403 MainWindow::toolMeasureSelected()
|
Chris@151
|
2404 {
|
Chris@151
|
2405 m_viewManager->setToolMode(ViewManager::MeasureMode);
|
Chris@151
|
2406 }
|
Chris@151
|
2407
|
Chris@0
|
2408 void
|
Chris@0
|
2409 MainWindow::importAudio()
|
Chris@0
|
2410 {
|
Chris@88
|
2411 QString path = getOpenFileName(FileFinder::AudioFile);
|
Chris@0
|
2412
|
Chris@0
|
2413 if (path != "") {
|
Chris@417
|
2414 if (openAudio(path, ReplaceSession) == FileOpenFailed) {
|
Chris@247
|
2415 emit hideSplash();
|
Chris@0
|
2416 QMessageBox::critical(this, tr("Failed to open file"),
|
Chris@193
|
2417 tr("<b>File open failed</b><p>Audio file \"%1\" could not be opened").arg(path));
|
Chris@0
|
2418 }
|
Chris@0
|
2419 }
|
Chris@0
|
2420 }
|
Chris@0
|
2421
|
Chris@0
|
2422 void
|
Chris@0
|
2423 MainWindow::importMoreAudio()
|
Chris@0
|
2424 {
|
Chris@88
|
2425 QString path = getOpenFileName(FileFinder::AudioFile);
|
Chris@0
|
2426
|
Chris@0
|
2427 if (path != "") {
|
Chris@197
|
2428 if (openAudio(path, CreateAdditionalModel) == FileOpenFailed) {
|
Chris@247
|
2429 emit hideSplash();
|
Chris@0
|
2430 QMessageBox::critical(this, tr("Failed to open file"),
|
Chris@193
|
2431 tr("<b>File open failed</b><p>Audio file \"%1\" could not be opened").arg(path));
|
Chris@0
|
2432 }
|
Chris@0
|
2433 }
|
Chris@0
|
2434 }
|
Chris@0
|
2435
|
Chris@0
|
2436 void
|
Chris@508
|
2437 MainWindow::replaceMainAudio()
|
Chris@508
|
2438 {
|
Chris@508
|
2439 QString path = getOpenFileName(FileFinder::AudioFile);
|
Chris@508
|
2440
|
Chris@508
|
2441 if (path != "") {
|
Chris@508
|
2442 if (openAudio(path, ReplaceMainModel) == FileOpenFailed) {
|
Chris@508
|
2443 emit hideSplash();
|
Chris@508
|
2444 QMessageBox::critical(this, tr("Failed to open file"),
|
Chris@508
|
2445 tr("<b>File open failed</b><p>Audio file \"%1\" could not be opened").arg(path));
|
Chris@508
|
2446 }
|
Chris@508
|
2447 }
|
Chris@508
|
2448 }
|
Chris@508
|
2449
|
Chris@508
|
2450 void
|
Chris@0
|
2451 MainWindow::exportAudio()
|
Chris@0
|
2452 {
|
Chris@631
|
2453 exportAudio(false);
|
Chris@631
|
2454 }
|
Chris@631
|
2455
|
Chris@631
|
2456 void
|
Chris@631
|
2457 MainWindow::exportAudioData()
|
Chris@631
|
2458 {
|
Chris@631
|
2459 exportAudio(true);
|
Chris@631
|
2460 }
|
Chris@631
|
2461
|
Chris@631
|
2462 void
|
Chris@631
|
2463 MainWindow::exportAudio(bool asData)
|
Chris@631
|
2464 {
|
Chris@0
|
2465 if (!getMainModel()) return;
|
Chris@0
|
2466
|
Chris@320
|
2467 RangeSummarisableTimeValueModel *model = getMainModel();
|
Chris@320
|
2468 std::set<RangeSummarisableTimeValueModel *> otherModels;
|
Chris@320
|
2469 RangeSummarisableTimeValueModel *current = model;
|
Chris@320
|
2470 if (m_paneStack) {
|
Chris@320
|
2471 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@320
|
2472 Pane *pane = m_paneStack->getPane(i);
|
Chris@320
|
2473 if (!pane) continue;
|
Chris@320
|
2474 for (int j = 0; j < pane->getLayerCount(); ++j) {
|
Chris@320
|
2475 Layer *layer = pane->getLayer(j);
|
Chris@320
|
2476 if (!layer) continue;
|
Chris@432
|
2477 cerr << "layer = " << layer->objectName() << endl;
|
Chris@320
|
2478 Model *m = layer->getModel();
|
Chris@320
|
2479 RangeSummarisableTimeValueModel *wm =
|
Chris@320
|
2480 dynamic_cast<RangeSummarisableTimeValueModel *>(m);
|
Chris@320
|
2481 if (wm) {
|
Chris@432
|
2482 cerr << "found: " << wm->objectName() << endl;
|
Chris@320
|
2483 otherModels.insert(wm);
|
Chris@320
|
2484 if (pane == m_paneStack->getCurrentPane()) {
|
Chris@320
|
2485 current = wm;
|
Chris@320
|
2486 }
|
Chris@320
|
2487 }
|
Chris@320
|
2488 }
|
Chris@320
|
2489 }
|
Chris@320
|
2490 }
|
Chris@320
|
2491 if (!otherModels.empty()) {
|
Chris@320
|
2492 std::map<QString, RangeSummarisableTimeValueModel *> m;
|
Chris@320
|
2493 m[tr("1. %2").arg(model->objectName())] = model;
|
Chris@320
|
2494 int n = 2;
|
Chris@320
|
2495 int c = 0;
|
Chris@320
|
2496 for (std::set<RangeSummarisableTimeValueModel *>::const_iterator i
|
Chris@320
|
2497 = otherModels.begin();
|
Chris@320
|
2498 i != otherModels.end(); ++i) {
|
Chris@320
|
2499 if (*i == model) continue;
|
Chris@320
|
2500 m[tr("%1. %2").arg(n).arg((*i)->objectName())] = *i;
|
Chris@320
|
2501 ++n;
|
Chris@320
|
2502 if (*i == current) c = n-1;
|
Chris@320
|
2503 }
|
Chris@320
|
2504 QStringList items;
|
Chris@320
|
2505 for (std::map<QString, RangeSummarisableTimeValueModel *>
|
Chris@320
|
2506 ::const_iterator i = m.begin();
|
Chris@320
|
2507 i != m.end(); ++i) {
|
Chris@320
|
2508 items << i->first;
|
Chris@320
|
2509 }
|
Chris@325
|
2510 if (items.size() > 1) {
|
Chris@325
|
2511 bool ok = false;
|
Chris@325
|
2512 QString item = QInputDialog::getItem
|
Chris@325
|
2513 (this, tr("Select audio file to export"),
|
Chris@325
|
2514 tr("Which audio file do you want to export from?"),
|
Chris@325
|
2515 items, c, false, &ok);
|
Chris@325
|
2516 if (!ok || item.isEmpty()) return;
|
Chris@325
|
2517 if (m.find(item) == m.end()) {
|
Chris@665
|
2518 cerr << "WARNING: Model " << item
|
Chris@325
|
2519 << " not found in list!" << endl;
|
Chris@325
|
2520 } else {
|
Chris@325
|
2521 model = m[item];
|
Chris@325
|
2522 }
|
Chris@320
|
2523 }
|
Chris@320
|
2524 }
|
Chris@320
|
2525
|
Chris@631
|
2526 QString path;
|
Chris@631
|
2527 if (asData) {
|
Chris@631
|
2528 path = getSaveFileName(FileFinder::CSVFile);
|
Chris@631
|
2529 } else {
|
Chris@631
|
2530 path = getSaveFileName(FileFinder::AudioFile);
|
Chris@631
|
2531 }
|
Chris@0
|
2532 if (path == "") return;
|
Chris@0
|
2533
|
Chris@0
|
2534 bool ok = false;
|
Chris@0
|
2535 QString error;
|
Chris@0
|
2536
|
Chris@0
|
2537 MultiSelection ms = m_viewManager->getSelection();
|
Chris@0
|
2538 MultiSelection::SelectionList selections = m_viewManager->getSelections();
|
Chris@0
|
2539
|
Chris@0
|
2540 bool multiple = false;
|
Chris@0
|
2541
|
Chris@38
|
2542 MultiSelection *selectionToWrite = 0;
|
Chris@38
|
2543
|
Chris@38
|
2544 if (selections.size() == 1) {
|
Chris@0
|
2545
|
Chris@0
|
2546 QStringList items;
|
Chris@0
|
2547 items << tr("Export the selected region only")
|
Chris@0
|
2548 << tr("Export the whole audio file");
|
Chris@0
|
2549
|
Chris@0
|
2550 bool ok = false;
|
Chris@0
|
2551 QString item = ListInputDialog::getItem
|
Chris@0
|
2552 (this, tr("Select region to export"),
|
Chris@0
|
2553 tr("Which region from the original audio file do you want to export?"),
|
Chris@0
|
2554 items, 0, &ok);
|
Chris@0
|
2555
|
Chris@0
|
2556 if (!ok || item.isEmpty()) return;
|
Chris@0
|
2557
|
Chris@38
|
2558 if (item == items[0]) selectionToWrite = &ms;
|
Chris@38
|
2559
|
Chris@38
|
2560 } else if (selections.size() > 1) {
|
Chris@0
|
2561
|
Chris@631
|
2562 bool multiple = false;
|
Chris@631
|
2563
|
Chris@631
|
2564 if (!asData) { // Multi-file export not supported for data
|
Chris@631
|
2565
|
Chris@631
|
2566 QStringList items;
|
Chris@631
|
2567 items << tr("Export the selected regions into a single file")
|
Chris@631
|
2568 << tr("Export the selected regions into separate files")
|
Chris@631
|
2569 << tr("Export the whole file");
|
Chris@631
|
2570
|
Chris@631
|
2571 QString item = ListInputDialog::getItem
|
Chris@631
|
2572 (this, tr("Select region to export"),
|
Chris@631
|
2573 tr("Multiple regions of the original audio file are selected.\nWhat do you want to export?"),
|
Chris@631
|
2574 items, 0, &ok);
|
Chris@0
|
2575
|
Chris@631
|
2576 if (!ok || item.isEmpty()) return;
|
Chris@631
|
2577
|
Chris@631
|
2578 if (item == items[0]) {
|
Chris@631
|
2579 selectionToWrite = &ms;
|
Chris@631
|
2580 } else if (item == items[1]) {
|
Chris@631
|
2581 multiple = true;
|
Chris@631
|
2582 }
|
Chris@631
|
2583
|
Chris@631
|
2584 } else { // asData
|
Chris@38
|
2585 selectionToWrite = &ms;
|
Chris@631
|
2586 }
|
Chris@631
|
2587
|
Chris@631
|
2588 if (multiple) { // Can only happen when asData false
|
Chris@0
|
2589
|
Chris@0
|
2590 int n = 1;
|
Chris@0
|
2591 QString base = path;
|
Chris@0
|
2592 base.replace(".wav", "");
|
Chris@0
|
2593
|
Chris@0
|
2594 for (MultiSelection::SelectionList::iterator i = selections.begin();
|
Chris@0
|
2595 i != selections.end(); ++i) {
|
Chris@0
|
2596
|
Chris@0
|
2597 MultiSelection subms;
|
Chris@0
|
2598 subms.setSelection(*i);
|
Chris@0
|
2599
|
Chris@0
|
2600 QString subpath = QString("%1.%2.wav").arg(base).arg(n);
|
Chris@0
|
2601 ++n;
|
Chris@0
|
2602
|
Chris@0
|
2603 if (QFileInfo(subpath).exists()) {
|
Chris@0
|
2604 error = tr("Fragment file %1 already exists, aborting").arg(subpath);
|
Chris@0
|
2605 break;
|
Chris@0
|
2606 }
|
Chris@0
|
2607
|
Chris@38
|
2608 WavFileWriter subwriter(subpath,
|
Chris@320
|
2609 model->getSampleRate(),
|
Chris@428
|
2610 model->getChannelCount(),
|
Chris@428
|
2611 WavFileWriter::WriteToTemporary);
|
Chris@320
|
2612 subwriter.writeModel(model, &subms);
|
Chris@0
|
2613 ok = subwriter.isOK();
|
Chris@0
|
2614
|
Chris@0
|
2615 if (!ok) {
|
Chris@0
|
2616 error = subwriter.getError();
|
Chris@0
|
2617 break;
|
Chris@0
|
2618 }
|
Chris@0
|
2619 }
|
Chris@0
|
2620 }
|
Chris@0
|
2621 }
|
Chris@0
|
2622
|
Chris@38
|
2623 if (!multiple) {
|
Chris@631
|
2624 if (asData) {
|
Chris@631
|
2625 CSVFileWriter writer(path, model,
|
Chris@631
|
2626 ((QFileInfo(path).suffix() == "csv") ?
|
Chris@631
|
2627 "," : "\t"));
|
Chris@631
|
2628 if (selectionToWrite) {
|
Chris@631
|
2629 writer.writeSelection(selectionToWrite);
|
Chris@631
|
2630 } else {
|
Chris@631
|
2631 writer.write();
|
Chris@631
|
2632 }
|
Chris@631
|
2633 ok = writer.isOK();
|
Chris@631
|
2634 error = writer.getError();
|
Chris@631
|
2635 } else {
|
Chris@631
|
2636 WavFileWriter writer(path,
|
Chris@631
|
2637 model->getSampleRate(),
|
Chris@631
|
2638 model->getChannelCount(),
|
Chris@631
|
2639 WavFileWriter::WriteToTemporary);
|
Chris@631
|
2640 writer.writeModel(model, selectionToWrite);
|
Chris@631
|
2641 ok = writer.isOK();
|
Chris@631
|
2642 error = writer.getError();
|
Chris@631
|
2643 }
|
Chris@0
|
2644 }
|
Chris@0
|
2645
|
Chris@0
|
2646 if (ok) {
|
Chris@310
|
2647 if (multiple) {
|
Chris@310
|
2648 emit activity(tr("Export multiple audio files"));
|
Chris@310
|
2649 } else {
|
Chris@310
|
2650 emit activity(tr("Export audio to \"%1\"").arg(path));
|
Chris@34
|
2651 m_recentFiles.addFile(path);
|
Chris@0
|
2652 }
|
Chris@0
|
2653 } else {
|
Chris@0
|
2654 QMessageBox::critical(this, tr("Failed to write file"), error);
|
Chris@0
|
2655 }
|
Chris@0
|
2656 }
|
Chris@0
|
2657
|
Chris@0
|
2658 void
|
Chris@0
|
2659 MainWindow::importLayer()
|
Chris@0
|
2660 {
|
Chris@0
|
2661 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@0
|
2662
|
Chris@0
|
2663 if (!pane) {
|
Chris@0
|
2664 // shouldn't happen, as the menu action should have been disabled
|
Chris@665
|
2665 cerr << "WARNING: MainWindow::importLayer: no current pane" << endl;
|
Chris@0
|
2666 return;
|
Chris@0
|
2667 }
|
Chris@0
|
2668
|
Chris@0
|
2669 if (!getMainModel()) {
|
Chris@0
|
2670 // shouldn't happen, as the menu action should have been disabled
|
Chris@665
|
2671 cerr << "WARNING: MainWindow::importLayer: No main model -- hence no default sample rate available" << endl;
|
Chris@0
|
2672 return;
|
Chris@0
|
2673 }
|
Chris@0
|
2674
|
Chris@88
|
2675 QString path = getOpenFileName(FileFinder::LayerFile);
|
Chris@0
|
2676
|
Chris@0
|
2677 if (path != "") {
|
Chris@0
|
2678
|
Chris@197
|
2679 FileOpenStatus status = openLayer(path);
|
Chris@193
|
2680
|
Chris@193
|
2681 if (status == FileOpenFailed) {
|
Chris@247
|
2682 emit hideSplash();
|
Chris@0
|
2683 QMessageBox::critical(this, tr("Failed to open file"),
|
Chris@193
|
2684 tr("<b>File open failed</b><p>Layer file %1 could not be opened.").arg(path));
|
Chris@0
|
2685 return;
|
Chris@193
|
2686 } else if (status == FileOpenWrongMode) {
|
Chris@247
|
2687 emit hideSplash();
|
Chris@193
|
2688 QMessageBox::critical(this, tr("Failed to open file"),
|
Chris@294
|
2689 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(path));
|
Chris@0
|
2690 }
|
Chris@0
|
2691 }
|
Chris@0
|
2692 }
|
Chris@0
|
2693
|
Chris@0
|
2694 void
|
Chris@0
|
2695 MainWindow::exportLayer()
|
Chris@0
|
2696 {
|
Chris@0
|
2697 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@0
|
2698 if (!pane) return;
|
Chris@0
|
2699
|
Chris@0
|
2700 Layer *layer = pane->getSelectedLayer();
|
Chris@0
|
2701 if (!layer) return;
|
Chris@0
|
2702
|
Chris@0
|
2703 Model *model = layer->getModel();
|
Chris@0
|
2704 if (!model) return;
|
Chris@0
|
2705
|
Chris@185
|
2706 FileFinder::FileType type = FileFinder::LayerFileNoMidi;
|
Chris@185
|
2707
|
Chris@185
|
2708 if (dynamic_cast<NoteModel *>(model)) type = FileFinder::LayerFile;
|
Chris@185
|
2709
|
Chris@185
|
2710 QString path = getSaveFileName(type);
|
Chris@0
|
2711
|
Chris@0
|
2712 if (path == "") return;
|
Chris@0
|
2713
|
Chris@0
|
2714 if (QFileInfo(path).suffix() == "") path += ".svl";
|
Chris@0
|
2715
|
Chris@185
|
2716 QString suffix = QFileInfo(path).suffix().toLower();
|
Chris@185
|
2717
|
Chris@0
|
2718 QString error;
|
Chris@0
|
2719
|
Chris@185
|
2720 if (suffix == "xml" || suffix == "svl") {
|
Chris@0
|
2721
|
Chris@0
|
2722 QFile file(path);
|
Chris@0
|
2723 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
Chris@0
|
2724 error = tr("Failed to open file %1 for writing").arg(path);
|
Chris@0
|
2725 } else {
|
Chris@0
|
2726 QTextStream out(&file);
|
Chris@0
|
2727 out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
Chris@0
|
2728 << "<!DOCTYPE sonic-visualiser>\n"
|
Chris@0
|
2729 << "<sv>\n"
|
Chris@0
|
2730 << " <data>\n";
|
Chris@0
|
2731
|
Chris@0
|
2732 model->toXml(out, " ");
|
Chris@0
|
2733
|
Chris@0
|
2734 out << " </data>\n"
|
Chris@0
|
2735 << " <display>\n";
|
Chris@0
|
2736
|
Chris@0
|
2737 layer->toXml(out, " ");
|
Chris@0
|
2738
|
Chris@0
|
2739 out << " </display>\n"
|
Chris@0
|
2740 << "</sv>\n";
|
Chris@0
|
2741 }
|
Chris@0
|
2742
|
Chris@185
|
2743 } else if (suffix == "mid" || suffix == "midi") {
|
Chris@185
|
2744
|
Chris@185
|
2745 NoteModel *nm = dynamic_cast<NoteModel *>(model);
|
Chris@185
|
2746
|
Chris@185
|
2747 if (!nm) {
|
Chris@185
|
2748 error = tr("Can't export non-note layers to MIDI");
|
Chris@185
|
2749 } else {
|
Chris@694
|
2750 MIDIFileWriter writer(path, nm, nm->getSampleRate());
|
Chris@185
|
2751 writer.write();
|
Chris@185
|
2752 if (!writer.isOK()) {
|
Chris@185
|
2753 error = writer.getError();
|
Chris@185
|
2754 }
|
Chris@185
|
2755 }
|
Chris@185
|
2756
|
Chris@291
|
2757 } else if (suffix == "ttl" || suffix == "n3") {
|
Chris@291
|
2758
|
Chris@522
|
2759 if (!RDFExporter::canExportModel(model)) {
|
Chris@522
|
2760 error = tr("Sorry, cannot export this layer type to RDF (supported types are: region, note, text, time instants, time values)");
|
Chris@522
|
2761 } else {
|
Chris@522
|
2762 RDFExporter exporter(path, model);
|
Chris@522
|
2763 exporter.write();
|
Chris@522
|
2764 if (!exporter.isOK()) {
|
Chris@522
|
2765 error = exporter.getError();
|
Chris@522
|
2766 }
|
Chris@291
|
2767 }
|
Chris@291
|
2768
|
Chris@0
|
2769 } else {
|
Chris@0
|
2770
|
Chris@0
|
2771 CSVFileWriter writer(path, model,
|
Chris@185
|
2772 ((suffix == "csv") ? "," : "\t"));
|
Chris@0
|
2773 writer.write();
|
Chris@0
|
2774
|
Chris@0
|
2775 if (!writer.isOK()) {
|
Chris@0
|
2776 error = writer.getError();
|
Chris@0
|
2777 }
|
Chris@0
|
2778 }
|
Chris@0
|
2779
|
Chris@0
|
2780 if (error != "") {
|
Chris@0
|
2781 QMessageBox::critical(this, tr("Failed to write file"), error);
|
Chris@0
|
2782 } else {
|
Chris@34
|
2783 m_recentFiles.addFile(path);
|
Chris@310
|
2784 emit activity(tr("Export layer to \"%1\"").arg(path));
|
Chris@0
|
2785 }
|
Chris@0
|
2786 }
|
Chris@0
|
2787
|
Chris@121
|
2788 void
|
Chris@121
|
2789 MainWindow::exportImage()
|
Chris@121
|
2790 {
|
Chris@121
|
2791 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@121
|
2792 if (!pane) return;
|
Chris@121
|
2793
|
Chris@121
|
2794 QString path = getSaveFileName(FileFinder::ImageFile);
|
Chris@121
|
2795
|
Chris@121
|
2796 if (path == "") return;
|
Chris@121
|
2797
|
Chris@121
|
2798 if (QFileInfo(path).suffix() == "") path += ".png";
|
Chris@121
|
2799
|
Chris@123
|
2800 bool haveSelection = m_viewManager && !m_viewManager->getSelections().empty();
|
Chris@123
|
2801
|
Chris@123
|
2802 QSize total, visible, selected;
|
Chris@123
|
2803 total = pane->getImageSize();
|
Chris@123
|
2804 visible = pane->getImageSize(pane->getFirstVisibleFrame(),
|
Chris@123
|
2805 pane->getLastVisibleFrame());
|
Chris@123
|
2806
|
Chris@730
|
2807 int sf0 = 0, sf1 = 0;
|
Chris@123
|
2808
|
Chris@123
|
2809 if (haveSelection) {
|
Chris@123
|
2810 MultiSelection::SelectionList selections = m_viewManager->getSelections();
|
Chris@123
|
2811 sf0 = selections.begin()->getStartFrame();
|
Chris@123
|
2812 MultiSelection::SelectionList::iterator e = selections.end();
|
Chris@123
|
2813 --e;
|
Chris@123
|
2814 sf1 = e->getEndFrame();
|
Chris@123
|
2815 selected = pane->getImageSize(sf0, sf1);
|
Chris@123
|
2816 }
|
Chris@123
|
2817
|
Chris@123
|
2818 QStringList items;
|
Chris@125
|
2819 items << tr("Export the whole pane (%1x%2 pixels)")
|
Chris@123
|
2820 .arg(total.width()).arg(total.height());
|
Chris@123
|
2821 items << tr("Export the visible area only (%1x%2 pixels)")
|
Chris@123
|
2822 .arg(visible.width()).arg(visible.height());
|
Chris@123
|
2823 if (haveSelection) {
|
Chris@123
|
2824 items << tr("Export the selection extent (%1x%2 pixels)")
|
Chris@123
|
2825 .arg(selected.width()).arg(selected.height());
|
Chris@124
|
2826 } else {
|
Chris@124
|
2827 items << tr("Export the selection extent");
|
Chris@123
|
2828 }
|
Chris@123
|
2829
|
Chris@123
|
2830 QSettings settings;
|
Chris@123
|
2831 settings.beginGroup("MainWindow");
|
Chris@123
|
2832 int deflt = settings.value("lastimageexportregion", 0).toInt();
|
Chris@123
|
2833 if (deflt == 2 && !haveSelection) deflt = 1;
|
Chris@124
|
2834 if (deflt == 0 && total.width() > 32767) deflt = 1;
|
Chris@124
|
2835
|
Chris@124
|
2836 ListInputDialog *lid = new ListInputDialog
|
Chris@123
|
2837 (this, tr("Select region to export"),
|
Chris@123
|
2838 tr("Which region of the current pane do you want to export as an image?"),
|
Chris@124
|
2839 items, deflt);
|
Chris@124
|
2840
|
Chris@124
|
2841 if (!haveSelection) {
|
Chris@124
|
2842 lid->setItemAvailability(2, false);
|
Chris@124
|
2843 }
|
Chris@124
|
2844 if (total.width() > 32767) { // appears to be the limit of a QImage
|
Chris@124
|
2845 lid->setItemAvailability(0, false);
|
Chris@124
|
2846 lid->setFootnote(tr("Note: the whole pane is too wide to be exported as a single image."));
|
Chris@124
|
2847 }
|
Chris@124
|
2848
|
Chris@124
|
2849 bool ok = lid->exec();
|
Chris@124
|
2850 QString item = lid->getCurrentString();
|
Chris@124
|
2851 delete lid;
|
Chris@123
|
2852
|
Chris@123
|
2853 if (!ok || item.isEmpty()) return;
|
Chris@123
|
2854
|
Chris@123
|
2855 settings.setValue("lastimageexportregion", deflt);
|
Chris@123
|
2856
|
Chris@123
|
2857 QImage *image = 0;
|
Chris@123
|
2858
|
Chris@123
|
2859 if (item == items[0]) {
|
Chris@123
|
2860 image = pane->toNewImage();
|
Chris@123
|
2861 } else if (item == items[1]) {
|
Chris@123
|
2862 image = pane->toNewImage(pane->getFirstVisibleFrame(),
|
Chris@123
|
2863 pane->getLastVisibleFrame());
|
Chris@123
|
2864 } else if (haveSelection) {
|
Chris@123
|
2865 image = pane->toNewImage(sf0, sf1);
|
Chris@123
|
2866 }
|
Chris@123
|
2867
|
Chris@121
|
2868 if (!image) return;
|
Chris@121
|
2869
|
Chris@121
|
2870 if (!image->save(path, "PNG")) {
|
Chris@121
|
2871 QMessageBox::critical(this, tr("Failed to save image file"),
|
Chris@121
|
2872 tr("Failed to save image file %1").arg(path));
|
Chris@121
|
2873 }
|
Chris@121
|
2874
|
Chris@121
|
2875 delete image;
|
Chris@121
|
2876 }
|
Chris@121
|
2877
|
Chris@0
|
2878 void
|
Chris@0
|
2879 MainWindow::newSession()
|
Chris@0
|
2880 {
|
Chris@0
|
2881 if (!checkSaveModified()) return;
|
Chris@0
|
2882
|
Chris@0
|
2883 closeSession();
|
Chris@0
|
2884 createDocument();
|
Chris@0
|
2885
|
Chris@0
|
2886 Pane *pane = m_paneStack->addPane();
|
Chris@0
|
2887
|
Chris@90
|
2888 connect(pane, SIGNAL(contextHelpChanged(const QString &)),
|
Chris@116
|
2889 this, SLOT(contextHelpChanged(const QString &)));
|
Chris@90
|
2890
|
Chris@0
|
2891 if (!m_timeRulerLayer) {
|
Chris@0
|
2892 m_timeRulerLayer = m_document->createMainModelLayer
|
Chris@0
|
2893 (LayerFactory::TimeRuler);
|
Chris@0
|
2894 }
|
Chris@0
|
2895
|
Chris@0
|
2896 m_document->addLayerToView(pane, m_timeRulerLayer);
|
Chris@0
|
2897
|
Chris@0
|
2898 Layer *waveform = m_document->createMainModelLayer(LayerFactory::Waveform);
|
Chris@0
|
2899 m_document->addLayerToView(pane, waveform);
|
Chris@0
|
2900
|
Chris@65
|
2901 m_overview->registerView(pane);
|
Chris@0
|
2902
|
Chris@0
|
2903 CommandHistory::getInstance()->clear();
|
Chris@0
|
2904 CommandHistory::getInstance()->documentSaved();
|
Chris@0
|
2905 documentRestored();
|
Chris@0
|
2906 updateMenuStates();
|
Chris@0
|
2907 }
|
Chris@0
|
2908
|
Chris@0
|
2909 void
|
Chris@303
|
2910 MainWindow::documentReplaced()
|
Chris@303
|
2911 {
|
Chris@303
|
2912 if (m_document) {
|
Chris@303
|
2913 connect(m_document, SIGNAL(activity(QString)),
|
Chris@303
|
2914 m_activityLog, SLOT(activityHappened(QString)));
|
Chris@303
|
2915 }
|
Chris@303
|
2916 }
|
Chris@303
|
2917
|
Chris@303
|
2918 void
|
Chris@0
|
2919 MainWindow::closeSession()
|
Chris@0
|
2920 {
|
Chris@0
|
2921 if (!checkSaveModified()) return;
|
Chris@0
|
2922
|
Chris@0
|
2923 while (m_paneStack->getPaneCount() > 0) {
|
Chris@0
|
2924
|
Chris@0
|
2925 Pane *pane = m_paneStack->getPane(m_paneStack->getPaneCount() - 1);
|
Chris@0
|
2926
|
Chris@0
|
2927 while (pane->getLayerCount() > 0) {
|
Chris@0
|
2928 m_document->removeLayerFromView
|
Chris@0
|
2929 (pane, pane->getLayer(pane->getLayerCount() - 1));
|
Chris@0
|
2930 }
|
Chris@0
|
2931
|
Chris@65
|
2932 m_overview->unregisterView(pane);
|
Chris@0
|
2933 m_paneStack->deletePane(pane);
|
Chris@0
|
2934 }
|
Chris@0
|
2935
|
Chris@0
|
2936 while (m_paneStack->getHiddenPaneCount() > 0) {
|
Chris@0
|
2937
|
Chris@0
|
2938 Pane *pane = m_paneStack->getHiddenPane
|
Chris@0
|
2939 (m_paneStack->getHiddenPaneCount() - 1);
|
Chris@0
|
2940
|
Chris@0
|
2941 while (pane->getLayerCount() > 0) {
|
Chris@0
|
2942 m_document->removeLayerFromView
|
Chris@0
|
2943 (pane, pane->getLayer(pane->getLayerCount() - 1));
|
Chris@0
|
2944 }
|
Chris@0
|
2945
|
Chris@65
|
2946 m_overview->unregisterView(pane);
|
Chris@0
|
2947 m_paneStack->deletePane(pane);
|
Chris@0
|
2948 }
|
Chris@0
|
2949
|
Chris@504
|
2950 delete m_layerTreeDialog.data();
|
Chris@504
|
2951 delete m_preferencesDialog.data();
|
Chris@504
|
2952
|
Chris@504
|
2953 m_activityLog->hide();
|
Chris@504
|
2954 m_keyReference->hide();
|
Chris@504
|
2955
|
Chris@0
|
2956 delete m_document;
|
Chris@0
|
2957 m_document = 0;
|
Chris@0
|
2958 m_viewManager->clearSelections();
|
Chris@0
|
2959 m_timeRulerLayer = 0; // document owned this
|
Chris@0
|
2960
|
Chris@0
|
2961 m_sessionFile = "";
|
Chris@518
|
2962 setWindowTitle(QApplication::applicationName());
|
Chris@0
|
2963
|
Chris@0
|
2964 CommandHistory::getInstance()->clear();
|
Chris@0
|
2965 CommandHistory::getInstance()->documentSaved();
|
Chris@0
|
2966 documentRestored();
|
Chris@0
|
2967 }
|
Chris@0
|
2968
|
Chris@0
|
2969 void
|
Chris@0
|
2970 MainWindow::openSomething()
|
Chris@0
|
2971 {
|
Chris@0
|
2972 QString orig = m_audioFile;
|
Chris@0
|
2973 if (orig == "") orig = ".";
|
Chris@0
|
2974 else orig = QFileInfo(orig).absoluteDir().canonicalPath();
|
Chris@0
|
2975
|
Chris@88
|
2976 QString path = getOpenFileName(FileFinder::AnyFile);
|
Chris@0
|
2977
|
Chris@0
|
2978 if (path.isEmpty()) return;
|
Chris@0
|
2979
|
Chris@422
|
2980 FileOpenStatus status = open(path, ReplaceSession);
|
Chris@193
|
2981
|
Chris@193
|
2982 if (status == FileOpenFailed) {
|
Chris@247
|
2983 emit hideSplash();
|
Chris@193
|
2984 QMessageBox::critical(this, tr("Failed to open file"),
|
Chris@193
|
2985 tr("<b>File open failed</b><p>File \"%1\" could not be opened").arg(path));
|
Chris@193
|
2986 } else if (status == FileOpenWrongMode) {
|
Chris@247
|
2987 emit hideSplash();
|
Chris@193
|
2988 QMessageBox::critical(this, tr("Failed to open file"),
|
Chris@294
|
2989 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(path));
|
Chris@0
|
2990 }
|
Chris@0
|
2991 }
|
Chris@0
|
2992
|
Chris@0
|
2993 void
|
Chris@86
|
2994 MainWindow::openLocation()
|
Chris@86
|
2995 {
|
Chris@103
|
2996 QSettings settings;
|
Chris@103
|
2997 settings.beginGroup("MainWindow");
|
Chris@103
|
2998 QString lastLocation = settings.value("lastremote", "").toString();
|
Chris@103
|
2999
|
Chris@86
|
3000 bool ok = false;
|
Chris@86
|
3001 QString text = QInputDialog::getText
|
Chris@86
|
3002 (this, tr("Open Location"),
|
Chris@86
|
3003 tr("Please enter the URL of the location to open:"),
|
Chris@103
|
3004 QLineEdit::Normal, lastLocation, &ok);
|
Chris@103
|
3005
|
Chris@103
|
3006 if (!ok) return;
|
Chris@103
|
3007
|
Chris@103
|
3008 settings.setValue("lastremote", text);
|
Chris@103
|
3009
|
Chris@103
|
3010 if (text.isEmpty()) return;
|
Chris@86
|
3011
|
Chris@419
|
3012 FileOpenStatus status = open(text, AskUser);
|
Chris@193
|
3013
|
Chris@193
|
3014 if (status == FileOpenFailed) {
|
Chris@247
|
3015 emit hideSplash();
|
Chris@86
|
3016 QMessageBox::critical(this, tr("Failed to open location"),
|
Chris@193
|
3017 tr("<b>Open failed</b><p>URL \"%1\" could not be opened").arg(text));
|
Chris@193
|
3018 } else if (status == FileOpenWrongMode) {
|
Chris@247
|
3019 emit hideSplash();
|
Chris@193
|
3020 QMessageBox::critical(this, tr("Failed to open location"),
|
Chris@294
|
3021 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));
|
Chris@86
|
3022 }
|
Chris@86
|
3023 }
|
Chris@86
|
3024
|
Chris@86
|
3025 void
|
Chris@0
|
3026 MainWindow::openRecentFile()
|
Chris@0
|
3027 {
|
Chris@0
|
3028 QObject *obj = sender();
|
Chris@0
|
3029 QAction *action = dynamic_cast<QAction *>(obj);
|
Chris@0
|
3030
|
Chris@0
|
3031 if (!action) {
|
Chris@665
|
3032 cerr << "WARNING: MainWindow::openRecentFile: sender is not an action"
|
Chris@665
|
3033 << endl;
|
Chris@0
|
3034 return;
|
Chris@0
|
3035 }
|
Chris@0
|
3036
|
Chris@0
|
3037 QString path = action->text();
|
Chris@0
|
3038 if (path == "") return;
|
Chris@0
|
3039
|
Chris@422
|
3040 FileOpenStatus status = open(path, ReplaceSession);
|
Chris@193
|
3041
|
Chris@193
|
3042 if (status == FileOpenFailed) {
|
Chris@247
|
3043 emit hideSplash();
|
Chris@193
|
3044 QMessageBox::critical(this, tr("Failed to open location"),
|
Chris@193
|
3045 tr("<b>Open failed</b><p>File or URL \"%1\" could not be opened").arg(path));
|
Chris@193
|
3046 } else if (status == FileOpenWrongMode) {
|
Chris@247
|
3047 emit hideSplash();
|
Chris@193
|
3048 QMessageBox::critical(this, tr("Failed to open location"),
|
Chris@294
|
3049 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(path));
|
Chris@0
|
3050 }
|
Chris@0
|
3051 }
|
Chris@0
|
3052
|
Chris@0
|
3053 void
|
Chris@435
|
3054 MainWindow::applyTemplate()
|
Chris@435
|
3055 {
|
Chris@435
|
3056 QObject *s = sender();
|
Chris@435
|
3057 QAction *action = qobject_cast<QAction *>(s);
|
Chris@435
|
3058
|
Chris@435
|
3059 if (!action) {
|
Chris@665
|
3060 cerr << "WARNING: MainWindow::applyTemplate: sender is not an action"
|
Chris@665
|
3061 << endl;
|
Chris@435
|
3062 return;
|
Chris@435
|
3063 }
|
Chris@435
|
3064
|
Chris@435
|
3065 QString n = action->objectName();
|
Chris@435
|
3066 if (n == "") n = action->text();
|
Chris@435
|
3067
|
Chris@435
|
3068 if (n == "") {
|
Chris@665
|
3069 cerr << "WARNING: MainWindow::applyTemplate: sender has no name"
|
Chris@665
|
3070 << endl;
|
Chris@435
|
3071 return;
|
Chris@435
|
3072 }
|
Chris@435
|
3073
|
Chris@435
|
3074 QString mainModelLocation;
|
Chris@435
|
3075 WaveFileModel *mm = getMainModel();
|
Chris@435
|
3076 if (mm) mainModelLocation = mm->getLocation();
|
Chris@435
|
3077 if (mainModelLocation != "") {
|
Chris@435
|
3078 openAudio(mainModelLocation, ReplaceSession, n);
|
Chris@435
|
3079 } else {
|
Chris@435
|
3080 openSessionTemplate(n);
|
Chris@435
|
3081 }
|
Chris@435
|
3082 }
|
Chris@435
|
3083
|
Chris@435
|
3084 void
|
Chris@425
|
3085 MainWindow::saveSessionAsTemplate()
|
Chris@425
|
3086 {
|
Chris@762
|
3087 QDialog *d = new QDialog(this);
|
Chris@483
|
3088 d->setWindowTitle(tr("Enter template name"));
|
Chris@483
|
3089
|
Chris@483
|
3090 QGridLayout *layout = new QGridLayout;
|
Chris@483
|
3091 d->setLayout(layout);
|
Chris@483
|
3092
|
Chris@483
|
3093 layout->addWidget(new QLabel(tr("Please enter a name for the saved template:")),
|
Chris@483
|
3094 0, 0);
|
Chris@483
|
3095 QLineEdit *lineEdit = new QLineEdit;
|
Chris@483
|
3096 layout->addWidget(lineEdit, 1, 0);
|
Chris@483
|
3097 QCheckBox *makeDefault = new QCheckBox(tr("Set as default template for future audio files"));
|
Chris@483
|
3098 layout->addWidget(makeDefault, 2, 0);
|
Chris@425
|
3099
|
Chris@483
|
3100 QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Ok |
|
Chris@483
|
3101 QDialogButtonBox::Cancel);
|
Chris@483
|
3102 layout->addWidget(bb, 3, 0);
|
Chris@483
|
3103 connect(bb, SIGNAL(accepted()), d, SLOT(accept()));
|
Chris@483
|
3104 connect(bb, SIGNAL(accepted()), d, SLOT(accept()));
|
Chris@483
|
3105 connect(bb, SIGNAL(rejected()), d, SLOT(reject()));
|
Chris@483
|
3106
|
Chris@483
|
3107 if (d->exec() == QDialog::Accepted) {
|
Chris@483
|
3108
|
Chris@483
|
3109 QString name = lineEdit->text();
|
Chris@483
|
3110 name.replace(QRegExp("[^\\w\\s\\.\"'-]"), "_");
|
Chris@483
|
3111
|
Chris@483
|
3112 ResourceFinder rf;
|
Chris@483
|
3113 QString dir = rf.getResourceSaveDir("templates");
|
Chris@483
|
3114 QString filename = QString("%1/%2.svt").arg(dir).arg(name);
|
Chris@483
|
3115 if (QFile(filename).exists()) {
|
Chris@483
|
3116 if (QMessageBox::warning(this,
|
Chris@483
|
3117 tr("Template file exists"),
|
Chris@483
|
3118 tr("<b>Template file exists</b><p>The template \"%1\" already exists.<br>Overwrite it?").arg(name),
|
Chris@483
|
3119 QMessageBox::Ok | QMessageBox::Cancel,
|
Chris@483
|
3120 QMessageBox::Cancel) != QMessageBox::Ok) {
|
Chris@483
|
3121 return;
|
Chris@483
|
3122 }
|
Chris@483
|
3123 }
|
Chris@483
|
3124
|
Chris@483
|
3125 if (saveSessionTemplate(filename)) {
|
Chris@483
|
3126 if (makeDefault->isChecked()) {
|
Chris@483
|
3127 setDefaultSessionTemplate(name);
|
Chris@483
|
3128 }
|
Chris@431
|
3129 }
|
Chris@431
|
3130 }
|
Chris@425
|
3131 }
|
Chris@425
|
3132
|
Chris@425
|
3133 void
|
Chris@425
|
3134 MainWindow::manageSavedTemplates()
|
Chris@425
|
3135 {
|
Chris@425
|
3136 ResourceFinder rf;
|
Chris@425
|
3137 QDesktopServices::openUrl("file:" + rf.getResourceSaveDir("templates"));
|
Chris@423
|
3138 }
|
Chris@423
|
3139
|
Chris@423
|
3140 void
|
Chris@200
|
3141 MainWindow::paneAdded(Pane *pane)
|
Chris@200
|
3142 {
|
Chris@200
|
3143 if (m_overview) m_overview->registerView(pane);
|
Chris@200
|
3144 }
|
Chris@200
|
3145
|
Chris@200
|
3146 void
|
Chris@200
|
3147 MainWindow::paneHidden(Pane *pane)
|
Chris@200
|
3148 {
|
Chris@200
|
3149 if (m_overview) m_overview->unregisterView(pane);
|
Chris@200
|
3150 }
|
Chris@200
|
3151
|
Chris@200
|
3152 void
|
Chris@200
|
3153 MainWindow::paneAboutToBeDeleted(Pane *pane)
|
Chris@200
|
3154 {
|
Chris@200
|
3155 if (m_overview) m_overview->unregisterView(pane);
|
Chris@200
|
3156 }
|
Chris@200
|
3157
|
Chris@200
|
3158 void
|
Chris@193
|
3159 MainWindow::paneDropAccepted(Pane *pane, QStringList uriList)
|
Chris@193
|
3160 {
|
Chris@193
|
3161 if (pane) m_paneStack->setCurrentPane(pane);
|
Chris@193
|
3162
|
Chris@193
|
3163 for (QStringList::iterator i = uriList.begin(); i != uriList.end(); ++i) {
|
Chris@193
|
3164
|
Chris@295
|
3165 FileOpenStatus status;
|
Chris@295
|
3166
|
Chris@295
|
3167 if (i == uriList.begin()) {
|
Chris@295
|
3168 status = open(*i, ReplaceCurrentPane);
|
Chris@295
|
3169 } else {
|
Chris@295
|
3170 status = open(*i, CreateAdditionalModel);
|
Chris@295
|
3171 }
|
Chris@193
|
3172
|
Chris@193
|
3173 if (status == FileOpenFailed) {
|
Chris@247
|
3174 emit hideSplash();
|
Chris@193
|
3175 QMessageBox::critical(this, tr("Failed to open dropped URL"),
|
Chris@193
|
3176 tr("<b>Open failed</b><p>Dropped URL \"%1\" could not be opened").arg(*i));
|
Chris@295
|
3177 break;
|
Chris@193
|
3178 } else if (status == FileOpenWrongMode) {
|
Chris@247
|
3179 emit hideSplash();
|
Chris@193
|
3180 QMessageBox::critical(this, tr("Failed to open dropped URL"),
|
Chris@294
|
3181 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(*i));
|
Chris@295
|
3182 break;
|
Chris@295
|
3183 } else if (status == FileOpenCancelled) {
|
Chris@295
|
3184 break;
|
Chris@193
|
3185 }
|
Chris@193
|
3186 }
|
Chris@193
|
3187 }
|
Chris@193
|
3188
|
Chris@193
|
3189 void
|
Chris@193
|
3190 MainWindow::paneDropAccepted(Pane *pane, QString text)
|
Chris@193
|
3191 {
|
Chris@193
|
3192 if (pane) m_paneStack->setCurrentPane(pane);
|
Chris@193
|
3193
|
Chris@193
|
3194 QUrl testUrl(text);
|
Chris@193
|
3195 if (testUrl.scheme() == "file" ||
|
Chris@193
|
3196 testUrl.scheme() == "http" ||
|
Chris@193
|
3197 testUrl.scheme() == "ftp") {
|
Chris@193
|
3198 QStringList list;
|
Chris@193
|
3199 list.push_back(text);
|
Chris@193
|
3200 paneDropAccepted(pane, list);
|
Chris@193
|
3201 return;
|
Chris@193
|
3202 }
|
Chris@193
|
3203
|
Chris@193
|
3204 //!!! open as text -- but by importing as if a CSV, or just adding
|
Chris@193
|
3205 //to a text layer?
|
Chris@193
|
3206 }
|
Chris@193
|
3207
|
Chris@193
|
3208 void
|
Chris@0
|
3209 MainWindow::closeEvent(QCloseEvent *e)
|
Chris@0
|
3210 {
|
Chris@665
|
3211 // cerr << "MainWindow::closeEvent" << endl;
|
Chris@118
|
3212
|
Chris@136
|
3213 if (m_openingAudioFile) {
|
Chris@665
|
3214 // cerr << "Busy - ignoring close event" << endl;
|
Chris@136
|
3215 e->ignore();
|
Chris@136
|
3216 return;
|
Chris@136
|
3217 }
|
Chris@136
|
3218
|
Chris@70
|
3219 if (!m_abandoning && !checkSaveModified()) {
|
Chris@665
|
3220 // cerr << "Close refused by user - ignoring close event" << endl;
|
Chris@0
|
3221 e->ignore();
|
Chris@0
|
3222 return;
|
Chris@0
|
3223 }
|
Chris@0
|
3224
|
Chris@5
|
3225 QSettings settings;
|
Chris@5
|
3226 settings.beginGroup("MainWindow");
|
Chris@624
|
3227 settings.setValue("maximised", isMaximized());
|
Chris@624
|
3228 if (!isMaximized()) {
|
Chris@624
|
3229 settings.setValue("size", size());
|
Chris@624
|
3230 settings.setValue("position", pos());
|
Chris@624
|
3231 }
|
Chris@5
|
3232 settings.endGroup();
|
Chris@5
|
3233
|
Chris@163
|
3234 if (m_preferencesDialog &&
|
Chris@163
|
3235 m_preferencesDialog->isVisible()) {
|
Chris@164
|
3236 closeSession(); // otherwise we'll have to wait for prefs changes
|
Chris@163
|
3237 m_preferencesDialog->applicationClosing(false);
|
Chris@163
|
3238 }
|
Chris@163
|
3239
|
Chris@200
|
3240 closeSession();
|
Chris@200
|
3241
|
Chris@0
|
3242 e->accept();
|
Chris@489
|
3243
|
Chris@0
|
3244 return;
|
Chris@0
|
3245 }
|
Chris@0
|
3246
|
Chris@0
|
3247 bool
|
Chris@11
|
3248 MainWindow::commitData(bool mayAskUser)
|
Chris@11
|
3249 {
|
Chris@11
|
3250 if (mayAskUser) {
|
Chris@163
|
3251 bool rv = checkSaveModified();
|
Chris@163
|
3252 if (rv) {
|
Chris@163
|
3253 if (m_preferencesDialog &&
|
Chris@163
|
3254 m_preferencesDialog->isVisible()) {
|
Chris@163
|
3255 m_preferencesDialog->applicationClosing(false);
|
Chris@163
|
3256 }
|
Chris@163
|
3257 }
|
Chris@163
|
3258 return rv;
|
Chris@11
|
3259 } else {
|
Chris@163
|
3260 if (m_preferencesDialog &&
|
Chris@163
|
3261 m_preferencesDialog->isVisible()) {
|
Chris@163
|
3262 m_preferencesDialog->applicationClosing(true);
|
Chris@163
|
3263 }
|
Chris@11
|
3264 if (!m_documentModified) return true;
|
Chris@11
|
3265
|
Chris@11
|
3266 // If we can't check with the user first, then we can't save
|
Chris@11
|
3267 // to the original session file (even if we have it) -- have
|
Chris@11
|
3268 // to use a temporary file
|
Chris@11
|
3269
|
Chris@11
|
3270 QString svDirBase = ".sv1";
|
Chris@11
|
3271 QString svDir = QDir::home().filePath(svDirBase);
|
Chris@11
|
3272
|
Chris@11
|
3273 if (!QFileInfo(svDir).exists()) {
|
Chris@11
|
3274 if (!QDir::home().mkdir(svDirBase)) return false;
|
Chris@11
|
3275 } else {
|
Chris@11
|
3276 if (!QFileInfo(svDir).isDir()) return false;
|
Chris@11
|
3277 }
|
Chris@11
|
3278
|
Chris@11
|
3279 // This name doesn't have to be unguessable
|
Chris@93
|
3280 #ifndef _WIN32
|
Chris@11
|
3281 QString fname = QString("tmp-%1-%2.sv")
|
Chris@11
|
3282 .arg(QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz"))
|
Chris@11
|
3283 .arg(QProcess().pid());
|
Chris@93
|
3284 #else
|
Chris@93
|
3285 QString fname = QString("tmp-%1.sv")
|
Chris@93
|
3286 .arg(QDateTime::currentDateTime().toString("yyyyMMddhhmmsszzz"));
|
Chris@93
|
3287 #endif
|
Chris@11
|
3288 QString fpath = QDir(svDir).filePath(fname);
|
Chris@11
|
3289 if (saveSessionFile(fpath)) {
|
Chris@34
|
3290 m_recentFiles.addFile(fpath);
|
Chris@310
|
3291 emit activity(tr("Export image to \"%1\"").arg(fpath));
|
Chris@11
|
3292 return true;
|
Chris@11
|
3293 } else {
|
Chris@11
|
3294 return false;
|
Chris@11
|
3295 }
|
Chris@11
|
3296 }
|
Chris@11
|
3297 }
|
Chris@11
|
3298
|
Chris@11
|
3299 bool
|
Chris@0
|
3300 MainWindow::checkSaveModified()
|
Chris@0
|
3301 {
|
Chris@0
|
3302 // Called before some destructive operation (e.g. new session,
|
Chris@0
|
3303 // exit program). Return true if we can safely proceed, false to
|
Chris@0
|
3304 // cancel.
|
Chris@0
|
3305
|
Chris@0
|
3306 if (!m_documentModified) return true;
|
Chris@0
|
3307
|
Chris@247
|
3308 emit hideSplash();
|
Chris@247
|
3309
|
Chris@0
|
3310 int button =
|
Chris@0
|
3311 QMessageBox::warning(this,
|
Chris@0
|
3312 tr("Session modified"),
|
Chris@207
|
3313 tr("<b>Session modified</b><p>The current session has been modified.<br>Do you want to save it?"),
|
Chris@165
|
3314 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
|
Chris@165
|
3315 QMessageBox::Yes);
|
Chris@0
|
3316
|
Chris@0
|
3317 if (button == QMessageBox::Yes) {
|
Chris@0
|
3318 saveSession();
|
Chris@0
|
3319 if (m_documentModified) { // save failed -- don't proceed!
|
Chris@0
|
3320 return false;
|
Chris@0
|
3321 } else {
|
Chris@0
|
3322 return true; // saved, so it's safe to continue now
|
Chris@0
|
3323 }
|
Chris@0
|
3324 } else if (button == QMessageBox::No) {
|
Chris@0
|
3325 m_documentModified = false; // so we know to abandon it
|
Chris@0
|
3326 return true;
|
Chris@0
|
3327 }
|
Chris@0
|
3328
|
Chris@0
|
3329 // else cancel
|
Chris@0
|
3330 return false;
|
Chris@0
|
3331 }
|
Chris@0
|
3332
|
Chris@290
|
3333 bool
|
Chris@294
|
3334 MainWindow::shouldCreateNewSessionForRDFAudio(bool *cancel)
|
Chris@290
|
3335 {
|
Chris@294
|
3336 //!!! This is very similar to part of MainWindowBase::openAudio --
|
Chris@294
|
3337 //!!! make them a bit more uniform
|
Chris@294
|
3338
|
Chris@294
|
3339 QSettings settings;
|
Chris@294
|
3340 settings.beginGroup("MainWindow");
|
Chris@294
|
3341 bool prevNewSession = settings.value("newsessionforrdfaudio", true).toBool();
|
Chris@294
|
3342 settings.endGroup();
|
Chris@294
|
3343 bool newSession = true;
|
Chris@294
|
3344
|
Chris@294
|
3345 QStringList items;
|
Chris@294
|
3346 items << tr("Close the current session and create a new one")
|
Chris@294
|
3347 << tr("Add this data to the current session");
|
Chris@294
|
3348
|
Chris@294
|
3349 bool ok = false;
|
Chris@294
|
3350 QString item = ListInputDialog::getItem
|
Chris@294
|
3351 (this, tr("Select target for import"),
|
Chris@294
|
3352 tr("<b>Select a target for import</b><p>This RDF document refers to one or more audio files.<br>You already have an audio waveform loaded.<br>What would you like to do with the new data?"),
|
Chris@294
|
3353 items, prevNewSession ? 0 : 1, &ok);
|
Chris@294
|
3354
|
Chris@294
|
3355 if (!ok || item.isEmpty()) {
|
Chris@294
|
3356 *cancel = true;
|
Chris@290
|
3357 return false;
|
Chris@290
|
3358 }
|
Chris@294
|
3359
|
Chris@294
|
3360 newSession = (item == items[0]);
|
Chris@294
|
3361 settings.beginGroup("MainWindow");
|
Chris@294
|
3362 settings.setValue("newsessionforrdfaudio", newSession);
|
Chris@294
|
3363 settings.endGroup();
|
Chris@294
|
3364
|
Chris@294
|
3365 if (newSession) return true;
|
Chris@294
|
3366 else return false;
|
Chris@290
|
3367 }
|
Chris@290
|
3368
|
Chris@0
|
3369 void
|
Chris@0
|
3370 MainWindow::saveSession()
|
Chris@0
|
3371 {
|
Chris@0
|
3372 if (m_sessionFile != "") {
|
Chris@0
|
3373 if (!saveSessionFile(m_sessionFile)) {
|
Chris@0
|
3374 QMessageBox::critical(this, tr("Failed to save file"),
|
Chris@193
|
3375 tr("<b>Save failed</b><p>Session file \"%1\" could not be saved.").arg(m_sessionFile));
|
Chris@0
|
3376 } else {
|
Chris@0
|
3377 CommandHistory::getInstance()->documentSaved();
|
Chris@0
|
3378 documentRestored();
|
Chris@0
|
3379 }
|
Chris@0
|
3380 } else {
|
Chris@0
|
3381 saveSessionAs();
|
Chris@0
|
3382 }
|
Chris@0
|
3383 }
|
Chris@0
|
3384
|
Chris@0
|
3385 void
|
Chris@0
|
3386 MainWindow::saveSessionAs()
|
Chris@0
|
3387 {
|
Chris@0
|
3388 QString orig = m_audioFile;
|
Chris@0
|
3389 if (orig == "") orig = ".";
|
Chris@0
|
3390 else orig = QFileInfo(orig).absoluteDir().canonicalPath();
|
Chris@0
|
3391
|
Chris@88
|
3392 QString path = getSaveFileName(FileFinder::SessionFile);
|
Chris@81
|
3393
|
Chris@81
|
3394 if (path == "") return;
|
Chris@0
|
3395
|
Chris@0
|
3396 if (!saveSessionFile(path)) {
|
Chris@0
|
3397 QMessageBox::critical(this, tr("Failed to save file"),
|
Chris@193
|
3398 tr("<b>Save failed</b><p>Session file \"%1\" could not be saved.").arg(path));
|
Chris@0
|
3399 } else {
|
Chris@518
|
3400 setWindowTitle(tr("%1: %1")
|
Chris@518
|
3401 .arg(QApplication::applicationName())
|
Chris@0
|
3402 .arg(QFileInfo(path).fileName()));
|
Chris@0
|
3403 m_sessionFile = path;
|
Chris@0
|
3404 CommandHistory::getInstance()->documentSaved();
|
Chris@0
|
3405 documentRestored();
|
Chris@34
|
3406 m_recentFiles.addFile(path);
|
Chris@310
|
3407 emit activity(tr("Save session as \"%1\"").arg(path));
|
Chris@0
|
3408 }
|
Chris@0
|
3409 }
|
Chris@0
|
3410
|
Chris@90
|
3411 void
|
Chris@72
|
3412 MainWindow::preferenceChanged(PropertyContainer::PropertyName name)
|
Chris@72
|
3413 {
|
Chris@200
|
3414 MainWindowBase::preferenceChanged(name);
|
Chris@200
|
3415
|
Chris@200
|
3416 if (name == "Background Mode" && m_viewManager) {
|
Chris@180
|
3417 if (m_viewManager->getGlobalDarkBackground()) {
|
Chris@180
|
3418 m_panLayer->setBaseColour
|
Chris@180
|
3419 (ColourDatabase::getInstance()->getColourIndex(tr("Bright Green")));
|
Chris@180
|
3420 } else {
|
Chris@180
|
3421 m_panLayer->setBaseColour
|
Chris@180
|
3422 (ColourDatabase::getInstance()->getColourIndex(tr("Green")));
|
Chris@180
|
3423 }
|
Chris@200
|
3424 }
|
Chris@0
|
3425 }
|
Chris@0
|
3426
|
Chris@0
|
3427 void
|
Chris@239
|
3428 MainWindow::propertyStacksResized(int width)
|
Chris@239
|
3429 {
|
Chris@438
|
3430 // SVDEBUG << "MainWindow::propertyStacksResized(" << width << ")" << endl;
|
Chris@239
|
3431
|
Chris@239
|
3432 if (!m_playControlsSpacer) return;
|
Chris@239
|
3433
|
Chris@239
|
3434 int spacerWidth = width - m_playControlsWidth - 4;
|
Chris@239
|
3435
|
Chris@438
|
3436 // SVDEBUG << "resizing spacer from " << m_playControlsSpacer->width() << " to " << spacerWidth << endl;
|
Chris@239
|
3437
|
Chris@239
|
3438 m_playControlsSpacer->setFixedSize(QSize(spacerWidth, 2));
|
Chris@239
|
3439 }
|
Chris@239
|
3440
|
Chris@239
|
3441 void
|
Chris@0
|
3442 MainWindow::addPane()
|
Chris@0
|
3443 {
|
Chris@0
|
3444 QObject *s = sender();
|
Chris@0
|
3445 QAction *action = dynamic_cast<QAction *>(s);
|
Chris@753
|
3446
|
Chris@753
|
3447 cerr << "addPane: sender is " << s << ", action is " << action << ", name " << action->text() << endl;
|
Chris@0
|
3448
|
Chris@0
|
3449 if (!action) {
|
Chris@665
|
3450 cerr << "WARNING: MainWindow::addPane: sender is not an action"
|
Chris@665
|
3451 << endl;
|
Chris@0
|
3452 return;
|
Chris@0
|
3453 }
|
Chris@0
|
3454
|
Chris@0
|
3455 PaneActionMap::iterator i = m_paneActions.find(action);
|
Chris@0
|
3456
|
Chris@0
|
3457 if (i == m_paneActions.end()) {
|
Chris@665
|
3458 cerr << "WARNING: MainWindow::addPane: unknown action "
|
Chris@665
|
3459 << action->objectName() << endl;
|
Chris@753
|
3460 cerr << "known actions are:" << endl;
|
Chris@753
|
3461 for (PaneActionMap::const_iterator i = m_paneActions.begin();
|
Chris@753
|
3462 i != m_paneActions.end(); ++i) {
|
Chris@753
|
3463 cerr << i->first << ", name " << i->first->text() << endl;
|
Chris@753
|
3464 }
|
Chris@0
|
3465 return;
|
Chris@0
|
3466 }
|
Chris@0
|
3467
|
Chris@69
|
3468 addPane(i->second, action->text());
|
Chris@69
|
3469 }
|
Chris@69
|
3470
|
Chris@69
|
3471 void
|
Chris@232
|
3472 MainWindow::addPane(const LayerConfiguration &configuration, QString text)
|
Chris@69
|
3473 {
|
Chris@69
|
3474 CommandHistory::getInstance()->startCompoundOperation(text, true);
|
Chris@0
|
3475
|
Chris@0
|
3476 AddPaneCommand *command = new AddPaneCommand(this);
|
Chris@0
|
3477 CommandHistory::getInstance()->addCommand(command);
|
Chris@0
|
3478
|
Chris@0
|
3479 Pane *pane = command->getPane();
|
Chris@0
|
3480
|
Chris@69
|
3481 if (configuration.layer == LayerFactory::Spectrum) {
|
Chris@109
|
3482 pane->setPlaybackFollow(PlaybackScrollContinuous);
|
Chris@110
|
3483 pane->setFollowGlobalZoom(false);
|
Chris@112
|
3484 pane->setZoomLevel(512);
|
Chris@7
|
3485 }
|
Chris@7
|
3486
|
Chris@69
|
3487 if (configuration.layer != LayerFactory::TimeRuler &&
|
Chris@69
|
3488 configuration.layer != LayerFactory::Spectrum) {
|
Chris@8
|
3489
|
Chris@0
|
3490 if (!m_timeRulerLayer) {
|
Chris@665
|
3491 // cerr << "no time ruler layer, creating one" << endl;
|
Chris@0
|
3492 m_timeRulerLayer = m_document->createMainModelLayer
|
Chris@0
|
3493 (LayerFactory::TimeRuler);
|
Chris@0
|
3494 }
|
Chris@0
|
3495
|
Chris@438
|
3496 // SVDEBUG << "adding time ruler layer " << m_timeRulerLayer << endl;
|
Chris@0
|
3497
|
Chris@0
|
3498 m_document->addLayerToView(pane, m_timeRulerLayer);
|
Chris@0
|
3499 }
|
Chris@0
|
3500
|
Chris@69
|
3501 Layer *newLayer = m_document->createLayer(configuration.layer);
|
Chris@69
|
3502
|
Chris@69
|
3503 Model *suggestedModel = configuration.sourceModel;
|
Chris@66
|
3504 Model *model = 0;
|
Chris@66
|
3505
|
Chris@66
|
3506 if (suggestedModel) {
|
Chris@66
|
3507
|
Chris@66
|
3508 // check its validity
|
Chris@224
|
3509 std::vector<Model *> inputModels = m_document->getTransformInputModels();
|
Chris@66
|
3510 for (size_t j = 0; j < inputModels.size(); ++j) {
|
Chris@66
|
3511 if (inputModels[j] == suggestedModel) {
|
Chris@66
|
3512 model = suggestedModel;
|
Chris@66
|
3513 break;
|
Chris@66
|
3514 }
|
Chris@66
|
3515 }
|
Chris@66
|
3516
|
Chris@66
|
3517 if (!model) {
|
Chris@665
|
3518 cerr << "WARNING: Model " << (void *)suggestedModel
|
Chris@66
|
3519 << " appears in pane action map, but is not reported "
|
Chris@665
|
3520 << "by document as a valid transform source" << endl;
|
Chris@66
|
3521 }
|
Chris@66
|
3522 }
|
Chris@66
|
3523
|
Chris@346
|
3524 if (!model) {
|
Chris@346
|
3525 model = m_document->getMainModel();
|
Chris@346
|
3526 }
|
Chris@66
|
3527
|
Chris@66
|
3528 m_document->setModel(newLayer, model);
|
Chris@66
|
3529
|
Chris@69
|
3530 m_document->setChannel(newLayer, configuration.channel);
|
Chris@0
|
3531 m_document->addLayerToView(pane, newLayer);
|
Chris@0
|
3532
|
Chris@0
|
3533 m_paneStack->setCurrentPane(pane);
|
Chris@70
|
3534 m_paneStack->setCurrentLayer(pane, newLayer);
|
Chris@0
|
3535
|
Chris@438
|
3536 // SVDEBUG << "MainWindow::addPane: global centre frame is "
|
Chris@433
|
3537 // << m_viewManager->getGlobalCentreFrame() << endl;
|
Chris@130
|
3538 // pane->setCentreFrame(m_viewManager->getGlobalCentreFrame());
|
Chris@73
|
3539
|
Chris@0
|
3540 CommandHistory::getInstance()->endCompoundOperation();
|
Chris@0
|
3541
|
Chris@0
|
3542 updateMenuStates();
|
Chris@0
|
3543 }
|
Chris@0
|
3544
|
Chris@0
|
3545 void
|
Chris@0
|
3546 MainWindow::addLayer()
|
Chris@0
|
3547 {
|
Chris@0
|
3548 QObject *s = sender();
|
Chris@0
|
3549 QAction *action = dynamic_cast<QAction *>(s);
|
Chris@0
|
3550
|
Chris@0
|
3551 if (!action) {
|
Chris@665
|
3552 cerr << "WARNING: MainWindow::addLayer: sender is not an action"
|
Chris@665
|
3553 << endl;
|
Chris@0
|
3554 return;
|
Chris@0
|
3555 }
|
Chris@0
|
3556
|
Chris@0
|
3557 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@0
|
3558
|
Chris@0
|
3559 if (!pane) {
|
Chris@665
|
3560 cerr << "WARNING: MainWindow::addLayer: no current pane" << endl;
|
Chris@0
|
3561 return;
|
Chris@0
|
3562 }
|
Chris@0
|
3563
|
Chris@0
|
3564 ExistingLayerActionMap::iterator ei = m_existingLayerActions.find(action);
|
Chris@0
|
3565
|
Chris@0
|
3566 if (ei != m_existingLayerActions.end()) {
|
Chris@0
|
3567 Layer *newLayer = ei->second;
|
Chris@0
|
3568 m_document->addLayerToView(pane, newLayer);
|
Chris@0
|
3569 m_paneStack->setCurrentLayer(pane, newLayer);
|
Chris@0
|
3570 return;
|
Chris@0
|
3571 }
|
Chris@0
|
3572
|
Chris@95
|
3573 ei = m_sliceActions.find(action);
|
Chris@95
|
3574
|
Chris@95
|
3575 if (ei != m_sliceActions.end()) {
|
Chris@95
|
3576 Layer *newLayer = m_document->createLayer(LayerFactory::Slice);
|
Chris@95
|
3577 // document->setModel(newLayer, ei->second->getModel());
|
Chris@95
|
3578 SliceableLayer *source = dynamic_cast<SliceableLayer *>(ei->second);
|
Chris@95
|
3579 SliceLayer *dest = dynamic_cast<SliceLayer *>(newLayer);
|
Chris@95
|
3580 if (source && dest) {
|
Chris@205
|
3581 //!!!???
|
Chris@95
|
3582 dest->setSliceableModel(source->getSliceableModel());
|
Chris@95
|
3583 connect(source, SIGNAL(sliceableModelReplaced(const Model *, const Model *)),
|
Chris@95
|
3584 dest, SLOT(sliceableModelReplaced(const Model *, const Model *)));
|
Chris@95
|
3585 connect(m_document, SIGNAL(modelAboutToBeDeleted(Model *)),
|
Chris@95
|
3586 dest, SLOT(modelAboutToBeDeleted(Model *)));
|
Chris@95
|
3587 }
|
Chris@95
|
3588 m_document->addLayerToView(pane, newLayer);
|
Chris@95
|
3589 m_paneStack->setCurrentLayer(pane, newLayer);
|
Chris@95
|
3590 return;
|
Chris@95
|
3591 }
|
Chris@95
|
3592
|
Chris@211
|
3593 TransformActionMap::iterator i = m_transformActions.find(action);
|
Chris@34
|
3594
|
Chris@34
|
3595 if (i == m_transformActions.end()) {
|
Chris@0
|
3596
|
Chris@0
|
3597 LayerActionMap::iterator i = m_layerActions.find(action);
|
Chris@0
|
3598
|
Chris@0
|
3599 if (i == m_layerActions.end()) {
|
Chris@665
|
3600 cerr << "WARNING: MainWindow::addLayer: unknown action "
|
Chris@665
|
3601 << action->objectName() << endl;
|
Chris@0
|
3602 return;
|
Chris@0
|
3603 }
|
Chris@0
|
3604
|
Chris@232
|
3605 LayerFactory::LayerType type = i->second.layer;
|
Chris@0
|
3606
|
Chris@0
|
3607 LayerFactory::LayerTypeSet emptyTypes =
|
Chris@0
|
3608 LayerFactory::getInstance()->getValidEmptyLayerTypes();
|
Chris@0
|
3609
|
Chris@499
|
3610 Layer *newLayer = 0;
|
Chris@0
|
3611
|
Chris@0
|
3612 if (emptyTypes.find(type) != emptyTypes.end()) {
|
Chris@0
|
3613
|
Chris@0
|
3614 newLayer = m_document->createEmptyLayer(type);
|
Chris@217
|
3615 if (newLayer) {
|
Chris@217
|
3616 m_toolActions[ViewManager::DrawMode]->trigger();
|
Chris@217
|
3617 }
|
Chris@0
|
3618
|
Chris@0
|
3619 } else {
|
Chris@0
|
3620
|
Chris@346
|
3621 Model *model = i->second.sourceModel;
|
Chris@346
|
3622
|
Chris@415
|
3623 cerr << "model = "<< model << endl;
|
Chris@415
|
3624
|
Chris@346
|
3625 if (!model) {
|
Chris@346
|
3626 if (type == LayerFactory::TimeRuler) {
|
Chris@346
|
3627 newLayer = m_document->createMainModelLayer(type);
|
Chris@346
|
3628 } else {
|
Chris@346
|
3629 // if model is unspecified and this is not a
|
Chris@415
|
3630 // time-ruler layer, use any plausible model from
|
Chris@415
|
3631 // the current pane -- this is the case for
|
Chris@415
|
3632 // right-button menu layer additions
|
Chris@415
|
3633 Pane::ModelSet ms = pane->getModels();
|
Chris@415
|
3634 foreach (Model *m, ms) {
|
Chris@415
|
3635 RangeSummarisableTimeValueModel *r =
|
Chris@415
|
3636 dynamic_cast<RangeSummarisableTimeValueModel *>(m);
|
Chris@415
|
3637 if (r) model = m;
|
Chris@346
|
3638 }
|
Chris@346
|
3639 if (!model) model = getMainModel();
|
Chris@346
|
3640 }
|
Chris@346
|
3641 }
|
Chris@346
|
3642
|
Chris@346
|
3643 if (model) {
|
Chris@238
|
3644 newLayer = m_document->createLayer(type);
|
Chris@346
|
3645 if (m_document->isKnownModel(model)) {
|
Chris@238
|
3646 m_document->setChannel(newLayer, i->second.channel);
|
Chris@346
|
3647 m_document->setModel(newLayer, model);
|
Chris@238
|
3648 } else {
|
Chris@665
|
3649 cerr << "WARNING: MainWindow::addLayer: unknown model "
|
Chris@346
|
3650 << model
|
Chris@238
|
3651 << " (\""
|
Chris@665
|
3652 << (model ? model->objectName() : "")
|
Chris@238
|
3653 << "\") in layer action map"
|
Chris@665
|
3654 << endl;
|
Chris@238
|
3655 }
|
Chris@232
|
3656 }
|
Chris@238
|
3657 }
|
Chris@0
|
3658
|
Chris@217
|
3659 if (newLayer) {
|
Chris@217
|
3660 m_document->addLayerToView(pane, newLayer);
|
Chris@217
|
3661 m_paneStack->setCurrentLayer(pane, newLayer);
|
Chris@217
|
3662 }
|
Chris@0
|
3663
|
Chris@0
|
3664 return;
|
Chris@0
|
3665 }
|
Chris@0
|
3666
|
Chris@224
|
3667 //!!! want to do something like this, but it's not supported in
|
Chris@224
|
3668 //ModelTransformerFactory yet
|
Chris@224
|
3669 /*
|
Chris@0
|
3670 int channel = -1;
|
Chris@0
|
3671 // pick up the default channel from any existing layers on the same pane
|
Chris@0
|
3672 for (int j = 0; j < pane->getLayerCount(); ++j) {
|
Chris@0
|
3673 int c = LayerFactory::getInstance()->getChannel(pane->getLayer(j));
|
Chris@0
|
3674 if (c != -1) {
|
Chris@0
|
3675 channel = c;
|
Chris@0
|
3676 break;
|
Chris@0
|
3677 }
|
Chris@0
|
3678 }
|
Chris@224
|
3679 */
|
Chris@0
|
3680
|
Chris@33
|
3681 // We always ask for configuration, even if the plugin isn't
|
Chris@33
|
3682 // supposed to be configurable, because we need to let the user
|
Chris@33
|
3683 // change the execution context (block size etc).
|
Chris@0
|
3684
|
Chris@224
|
3685 QString transformId = i->second;
|
Chris@274
|
3686
|
Chris@274
|
3687 addLayer(transformId);
|
Chris@274
|
3688 }
|
Chris@274
|
3689
|
Chris@274
|
3690 void
|
Chris@274
|
3691 MainWindow::addLayer(QString transformId)
|
Chris@274
|
3692 {
|
Chris@274
|
3693 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@274
|
3694 if (!pane) {
|
Chris@665
|
3695 cerr << "WARNING: MainWindow::addLayer: no current pane" << endl;
|
Chris@274
|
3696 return;
|
Chris@274
|
3697 }
|
Chris@274
|
3698
|
Chris@224
|
3699 Transform transform = TransformFactory::getInstance()->
|
Chris@224
|
3700 getDefaultTransformFor(transformId);
|
Chris@27
|
3701
|
Chris@66
|
3702 std::vector<Model *> candidateInputModels =
|
Chris@224
|
3703 m_document->getTransformInputModels();
|
Chris@53
|
3704
|
Chris@219
|
3705 Model *defaultInputModel = 0;
|
Chris@219
|
3706 for (int j = 0; j < pane->getLayerCount(); ++j) {
|
Chris@219
|
3707 Layer *layer = pane->getLayer(j);
|
Chris@219
|
3708 if (!layer) continue;
|
Chris@243
|
3709 if (LayerFactory::getInstance()->getLayerType(layer) !=
|
Chris@243
|
3710 LayerFactory::Waveform &&
|
Chris@243
|
3711 !layer->isLayerOpaque()) continue;
|
Chris@219
|
3712 Model *model = layer->getModel();
|
Chris@219
|
3713 if (!model) continue;
|
Chris@219
|
3714 for (size_t k = 0; k < candidateInputModels.size(); ++k) {
|
Chris@219
|
3715 if (candidateInputModels[k] == model) {
|
Chris@219
|
3716 defaultInputModel = model;
|
Chris@219
|
3717 break;
|
Chris@219
|
3718 }
|
Chris@219
|
3719 }
|
Chris@219
|
3720 if (defaultInputModel) break;
|
Chris@219
|
3721 }
|
Chris@219
|
3722
|
Chris@730
|
3723 int startFrame = 0, duration = 0;
|
Chris@730
|
3724 int endFrame = 0;
|
Chris@184
|
3725 m_viewManager->getSelection().getExtents(startFrame, endFrame);
|
Chris@184
|
3726 if (endFrame > startFrame) duration = endFrame - startFrame;
|
Chris@184
|
3727 else startFrame = 0;
|
Chris@184
|
3728
|
Chris@357
|
3729 TransformUserConfigurator configurator;
|
Chris@357
|
3730
|
Chris@224
|
3731 ModelTransformer::Input input = ModelTransformerFactory::getInstance()->
|
Chris@224
|
3732 getConfigurationForTransform
|
Chris@211
|
3733 (transform,
|
Chris@211
|
3734 candidateInputModels,
|
Chris@219
|
3735 defaultInputModel,
|
Chris@211
|
3736 m_playSource,
|
Chris@211
|
3737 startFrame,
|
Chris@357
|
3738 duration,
|
Chris@357
|
3739 &configurator);
|
Chris@211
|
3740
|
Chris@224
|
3741 if (!input.getModel()) return;
|
Chris@224
|
3742
|
Chris@438
|
3743 // SVDEBUG << "MainWindow::addLayer: Input model is " << input.getModel() << " \"" << input.getModel()->objectName() << "\"" << endl << "transform:" << endl << transform.toXmlString() << endl;
|
Chris@224
|
3744
|
Chris@224
|
3745 Layer *newLayer = m_document->createDerivedLayer(transform, input);
|
Chris@0
|
3746
|
Chris@0
|
3747 if (newLayer) {
|
Chris@0
|
3748 m_document->addLayerToView(pane, newLayer);
|
Chris@224
|
3749 m_document->setChannel(newLayer, input.getChannel());
|
Chris@224
|
3750 m_recentTransforms.add(transformId);
|
Chris@70
|
3751 m_paneStack->setCurrentLayer(pane, newLayer);
|
Chris@0
|
3752 }
|
Chris@0
|
3753
|
Chris@0
|
3754 updateMenuStates();
|
Chris@0
|
3755 }
|
Chris@0
|
3756
|
Chris@0
|
3757 void
|
Chris@0
|
3758 MainWindow::renameCurrentLayer()
|
Chris@0
|
3759 {
|
Chris@0
|
3760 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@0
|
3761 if (pane) {
|
Chris@0
|
3762 Layer *layer = pane->getSelectedLayer();
|
Chris@0
|
3763 if (layer) {
|
Chris@0
|
3764 bool ok = false;
|
Chris@0
|
3765 QString newName = QInputDialog::getText
|
Chris@0
|
3766 (this, tr("Rename Layer"),
|
Chris@0
|
3767 tr("New name for this layer:"),
|
Chris@0
|
3768 QLineEdit::Normal, layer->objectName(), &ok);
|
Chris@0
|
3769 if (ok) {
|
Chris@239
|
3770 layer->setPresentationName(newName);
|
Chris@95
|
3771 setupExistingLayersMenus();
|
Chris@0
|
3772 }
|
Chris@0
|
3773 }
|
Chris@0
|
3774 }
|
Chris@0
|
3775 }
|
Chris@0
|
3776
|
Chris@0
|
3777 void
|
Chris@272
|
3778 MainWindow::findTransform()
|
Chris@272
|
3779 {
|
Chris@274
|
3780 TransformFinder *finder = new TransformFinder(this);
|
Chris@274
|
3781 if (!finder->exec()) {
|
Chris@274
|
3782 delete finder;
|
Chris@274
|
3783 return;
|
Chris@273
|
3784 }
|
Chris@274
|
3785 TransformId transform = finder->getTransform();
|
Chris@274
|
3786 delete finder;
|
Chris@287
|
3787
|
Chris@287
|
3788 if (getMainModel() != 0 && m_paneStack->getCurrentPane() != 0) {
|
Chris@287
|
3789 addLayer(transform);
|
Chris@287
|
3790 }
|
Chris@272
|
3791 }
|
Chris@272
|
3792
|
Chris@272
|
3793 void
|
Chris@207
|
3794 MainWindow::playSoloToggled()
|
Chris@207
|
3795 {
|
Chris@207
|
3796 MainWindowBase::playSoloToggled();
|
Chris@207
|
3797 m_soloModified = true;
|
Chris@207
|
3798 }
|
Chris@207
|
3799
|
Chris@207
|
3800 void
|
Chris@206
|
3801 MainWindow::alignToggled()
|
Chris@206
|
3802 {
|
Chris@206
|
3803 QAction *action = dynamic_cast<QAction *>(sender());
|
Chris@206
|
3804
|
Chris@207
|
3805 if (!m_viewManager) return;
|
Chris@207
|
3806
|
Chris@206
|
3807 if (action) {
|
Chris@206
|
3808 m_viewManager->setAlignMode(action->isChecked());
|
Chris@206
|
3809 } else {
|
Chris@206
|
3810 m_viewManager->setAlignMode(!m_viewManager->getAlignMode());
|
Chris@206
|
3811 }
|
Chris@206
|
3812
|
Chris@206
|
3813 if (m_viewManager->getAlignMode()) {
|
Chris@207
|
3814 m_prevSolo = m_soloAction->isChecked();
|
Chris@208
|
3815 if (!m_soloAction->isChecked()) {
|
Chris@208
|
3816 m_soloAction->setChecked(true);
|
Chris@208
|
3817 MainWindowBase::playSoloToggled();
|
Chris@208
|
3818 }
|
Chris@207
|
3819 m_soloModified = false;
|
Chris@207
|
3820 emit canChangeSolo(false);
|
Chris@206
|
3821 m_document->alignModels();
|
Chris@206
|
3822 m_document->setAutoAlignment(true);
|
Chris@206
|
3823 } else {
|
Chris@207
|
3824 if (!m_soloModified) {
|
Chris@208
|
3825 if (m_soloAction->isChecked() != m_prevSolo) {
|
Chris@208
|
3826 m_soloAction->setChecked(m_prevSolo);
|
Chris@208
|
3827 MainWindowBase::playSoloToggled();
|
Chris@208
|
3828 }
|
Chris@207
|
3829 }
|
Chris@207
|
3830 emit canChangeSolo(true);
|
Chris@206
|
3831 m_document->setAutoAlignment(false);
|
Chris@206
|
3832 }
|
Chris@206
|
3833
|
Chris@206
|
3834 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@206
|
3835
|
Chris@206
|
3836 Pane *pane = m_paneStack->getPane(i);
|
Chris@206
|
3837 if (!pane) continue;
|
Chris@206
|
3838
|
Chris@206
|
3839 pane->update();
|
Chris@206
|
3840 }
|
Chris@206
|
3841 }
|
Chris@206
|
3842
|
Chris@206
|
3843 void
|
Chris@59
|
3844 MainWindow::playSpeedChanged(int position)
|
Chris@0
|
3845 {
|
Chris@59
|
3846 PlaySpeedRangeMapper mapper(0, 200);
|
Chris@60
|
3847
|
Chris@60
|
3848 float percent = m_playSpeed->mappedValue();
|
Chris@60
|
3849 float factor = mapper.getFactorForValue(percent);
|
Chris@60
|
3850
|
Chris@665
|
3851 // cerr << "speed = " << position << " percent = " << percent << " factor = " << factor << endl;
|
Chris@60
|
3852
|
Chris@59
|
3853 bool something = (position != 100);
|
Chris@155
|
3854
|
Chris@59
|
3855 int pc = lrintf(percent);
|
Chris@21
|
3856
|
Chris@155
|
3857 if (!something) {
|
Chris@155
|
3858 contextHelpChanged(tr("Playback speed: Normal"));
|
Chris@155
|
3859 } else {
|
Chris@155
|
3860 contextHelpChanged(tr("Playback speed: %1%2%")
|
Chris@155
|
3861 .arg(position > 100 ? "+" : "")
|
Chris@155
|
3862 .arg(pc));
|
Chris@155
|
3863 }
|
Chris@155
|
3864
|
Chris@240
|
3865 m_playSource->setTimeStretch(factor);
|
Chris@155
|
3866
|
Chris@155
|
3867 updateMenuStates();
|
Chris@16
|
3868 }
|
Chris@16
|
3869
|
Chris@26
|
3870 void
|
Chris@155
|
3871 MainWindow::speedUpPlayback()
|
Chris@155
|
3872 {
|
Chris@155
|
3873 int value = m_playSpeed->value();
|
Chris@155
|
3874 value = value + m_playSpeed->pageStep();
|
Chris@155
|
3875 if (value > m_playSpeed->maximum()) value = m_playSpeed->maximum();
|
Chris@155
|
3876 m_playSpeed->setValue(value);
|
Chris@155
|
3877 }
|
Chris@155
|
3878
|
Chris@155
|
3879 void
|
Chris@155
|
3880 MainWindow::slowDownPlayback()
|
Chris@155
|
3881 {
|
Chris@155
|
3882 int value = m_playSpeed->value();
|
Chris@155
|
3883 value = value - m_playSpeed->pageStep();
|
Chris@155
|
3884 if (value < m_playSpeed->minimum()) value = m_playSpeed->minimum();
|
Chris@155
|
3885 m_playSpeed->setValue(value);
|
Chris@155
|
3886 }
|
Chris@155
|
3887
|
Chris@155
|
3888 void
|
Chris@155
|
3889 MainWindow::restoreNormalPlayback()
|
Chris@155
|
3890 {
|
Chris@155
|
3891 m_playSpeed->setValue(m_playSpeed->defaultValue());
|
Chris@155
|
3892 }
|
Chris@155
|
3893
|
Chris@155
|
3894 void
|
Chris@227
|
3895 MainWindow::currentPaneChanged(Pane *pane)
|
Chris@227
|
3896 {
|
Chris@228
|
3897 MainWindowBase::currentPaneChanged(pane);
|
Chris@228
|
3898
|
Chris@227
|
3899 if (!pane || !m_panLayer) return;
|
Chris@761
|
3900
|
Chris@761
|
3901 // If this pane contains the main model, it usually makes sense to
|
Chris@761
|
3902 // show the main model in the pan layer even if it isn't the top
|
Chris@761
|
3903 // layer in the pane (e.g. if the top layer is one derived from
|
Chris@761
|
3904 // the main model).
|
Chris@761
|
3905 bool containsMainModel = false;
|
Chris@761
|
3906 for (int i = pane->getLayerCount(); i > 0; ) {
|
Chris@761
|
3907 --i;
|
Chris@761
|
3908 Layer *layer = pane->getLayer(i);
|
Chris@761
|
3909 if (layer &&
|
Chris@761
|
3910 LayerFactory::getInstance()->getLayerType(layer) ==
|
Chris@761
|
3911 LayerFactory::Waveform &&
|
Chris@761
|
3912 layer->getModel() == getMainModel()) {
|
Chris@761
|
3913 containsMainModel = true;
|
Chris@761
|
3914 break;
|
Chris@761
|
3915 }
|
Chris@761
|
3916 }
|
Chris@761
|
3917
|
Chris@761
|
3918 if (containsMainModel) {
|
Chris@761
|
3919 m_panLayer->setModel(getMainModel());
|
Chris@761
|
3920 return;
|
Chris@761
|
3921 }
|
Chris@761
|
3922
|
Chris@227
|
3923 for (int i = pane->getLayerCount(); i > 0; ) {
|
Chris@227
|
3924 --i;
|
Chris@227
|
3925 Layer *layer = pane->getLayer(i);
|
Chris@227
|
3926 if (LayerFactory::getInstance()->getLayerType(layer) ==
|
Chris@227
|
3927 LayerFactory::Waveform) {
|
Chris@227
|
3928 RangeSummarisableTimeValueModel *tvm =
|
Chris@227
|
3929 dynamic_cast<RangeSummarisableTimeValueModel *>(layer->getModel());
|
Chris@227
|
3930 if (tvm) {
|
Chris@227
|
3931 m_panLayer->setModel(tvm);
|
Chris@227
|
3932 return;
|
Chris@227
|
3933 }
|
Chris@227
|
3934 }
|
Chris@227
|
3935 }
|
Chris@227
|
3936 }
|
Chris@227
|
3937
|
Chris@227
|
3938 void
|
Chris@116
|
3939 MainWindow::updateVisibleRangeDisplay(Pane *p) const
|
Chris@116
|
3940 {
|
Chris@116
|
3941 if (!getMainModel() || !p) {
|
Chris@116
|
3942 return;
|
Chris@116
|
3943 }
|
Chris@116
|
3944
|
Chris@117
|
3945 bool haveSelection = false;
|
Chris@730
|
3946 int startFrame = 0, endFrame = 0;
|
Chris@117
|
3947
|
Chris@117
|
3948 if (m_viewManager && m_viewManager->haveInProgressSelection()) {
|
Chris@117
|
3949
|
Chris@117
|
3950 bool exclusive = false;
|
Chris@117
|
3951 Selection s = m_viewManager->getInProgressSelection(exclusive);
|
Chris@117
|
3952
|
Chris@117
|
3953 if (!s.isEmpty()) {
|
Chris@117
|
3954 haveSelection = true;
|
Chris@117
|
3955 startFrame = s.getStartFrame();
|
Chris@117
|
3956 endFrame = s.getEndFrame();
|
Chris@117
|
3957 }
|
Chris@117
|
3958 }
|
Chris@117
|
3959
|
Chris@117
|
3960 if (!haveSelection) {
|
Chris@117
|
3961 startFrame = p->getFirstVisibleFrame();
|
Chris@117
|
3962 endFrame = p->getLastVisibleFrame();
|
Chris@117
|
3963 }
|
Chris@117
|
3964
|
Chris@116
|
3965 RealTime start = RealTime::frame2RealTime
|
Chris@117
|
3966 (startFrame, getMainModel()->getSampleRate());
|
Chris@116
|
3967
|
Chris@116
|
3968 RealTime end = RealTime::frame2RealTime
|
Chris@117
|
3969 (endFrame, getMainModel()->getSampleRate());
|
Chris@116
|
3970
|
Chris@116
|
3971 RealTime duration = end - start;
|
Chris@116
|
3972
|
Chris@116
|
3973 QString startStr, endStr, durationStr;
|
Chris@116
|
3974 startStr = start.toText(true).c_str();
|
Chris@116
|
3975 endStr = end.toText(true).c_str();
|
Chris@116
|
3976 durationStr = duration.toText(true).c_str();
|
Chris@116
|
3977
|
Chris@117
|
3978 if (haveSelection) {
|
Chris@117
|
3979 m_myStatusMessage = tr("Selection: %1 to %2 (duration %3)")
|
Chris@117
|
3980 .arg(startStr).arg(endStr).arg(durationStr);
|
Chris@117
|
3981 } else {
|
Chris@117
|
3982 m_myStatusMessage = tr("Visible: %1 to %2 (duration %3)")
|
Chris@117
|
3983 .arg(startStr).arg(endStr).arg(durationStr);
|
Chris@117
|
3984 }
|
Chris@116
|
3985
|
Chris@739
|
3986 if (getStatusLabel()->text() != m_myStatusMessage) {
|
Chris@739
|
3987 getStatusLabel()->setText(m_myStatusMessage);
|
Chris@737
|
3988 }
|
Chris@340
|
3989
|
Chris@340
|
3990 updatePositionStatusDisplays();
|
Chris@340
|
3991 }
|
Chris@340
|
3992
|
Chris@340
|
3993 void
|
Chris@340
|
3994 MainWindow::updatePositionStatusDisplays() const
|
Chris@340
|
3995 {
|
Chris@340
|
3996 if (!statusBar()->isVisible()) return;
|
Chris@340
|
3997
|
Chris@340
|
3998 Pane *pane = 0;
|
Chris@730
|
3999 int frame = m_viewManager->getPlaybackFrame();
|
Chris@340
|
4000
|
Chris@340
|
4001 if (m_paneStack) pane = m_paneStack->getCurrentPane();
|
Chris@340
|
4002 if (!pane) return;
|
Chris@340
|
4003
|
Chris@340
|
4004 int layers = pane->getLayerCount();
|
Chris@340
|
4005 if (layers == 0) m_currentLabel->setText("");
|
Chris@340
|
4006
|
Chris@340
|
4007 for (int i = layers-1; i >= 0; --i) {
|
Chris@340
|
4008 Layer *layer = pane->getLayer(i);
|
Chris@340
|
4009 if (!layer) continue;
|
Chris@340
|
4010 if (!layer->isLayerEditable()) continue;
|
Chris@340
|
4011 QString label = layer->getLabelPreceding
|
Chris@340
|
4012 (pane->alignFromReference(frame));
|
Chris@340
|
4013 m_currentLabel->setText(label);
|
Chris@340
|
4014 break;
|
Chris@340
|
4015 }
|
Chris@116
|
4016 }
|
Chris@116
|
4017
|
Chris@116
|
4018 void
|
Chris@0
|
4019 MainWindow::outputLevelsChanged(float left, float right)
|
Chris@0
|
4020 {
|
Chris@0
|
4021 m_fader->setPeakLeft(left);
|
Chris@0
|
4022 m_fader->setPeakRight(right);
|
Chris@0
|
4023 }
|
Chris@0
|
4024
|
Chris@0
|
4025 void
|
Chris@730
|
4026 MainWindow::sampleRateMismatch(int requested, int actual,
|
Chris@0
|
4027 bool willResample)
|
Chris@0
|
4028 {
|
Chris@0
|
4029 if (!willResample) {
|
Chris@247
|
4030 emit hideSplash();
|
Chris@0
|
4031 QMessageBox::information
|
Chris@0
|
4032 (this, tr("Sample rate mismatch"),
|
Chris@193
|
4033 tr("<b>Wrong sample rate</b><p>The sample rate of this audio file (%1 Hz) does not match\nthe current playback rate (%2 Hz).<p>The file will play at the wrong speed and pitch.<p>Change the <i>Resample mismatching files on import</i> option under <i>File</i> -> <i>Preferences</i> if you want to alter this behaviour.")
|
Chris@0
|
4034 .arg(requested).arg(actual));
|
Chris@0
|
4035 }
|
Chris@0
|
4036
|
Chris@0
|
4037 updateDescriptionLabel();
|
Chris@0
|
4038 }
|
Chris@0
|
4039
|
Chris@0
|
4040 void
|
Chris@42
|
4041 MainWindow::audioOverloadPluginDisabled()
|
Chris@42
|
4042 {
|
Chris@42
|
4043 QMessageBox::information
|
Chris@42
|
4044 (this, tr("Audio processing overload"),
|
Chris@193
|
4045 tr("<b>Overloaded</b><p>Audio effects plugin auditioning has been disabled due to a processing overload."));
|
Chris@42
|
4046 }
|
Chris@42
|
4047
|
Chris@42
|
4048 void
|
Chris@266
|
4049 MainWindow::audioTimeStretchMultiChannelDisabled()
|
Chris@266
|
4050 {
|
Chris@266
|
4051 static bool shownOnce = false;
|
Chris@266
|
4052 if (shownOnce) return;
|
Chris@266
|
4053 QMessageBox::information
|
Chris@266
|
4054 (this, tr("Audio processing overload"),
|
Chris@266
|
4055 tr("<b>Overloaded</b><p>Audio playback speed processing has been reduced to a single channel, due to a processing overload."));
|
Chris@266
|
4056 shownOnce = true;
|
Chris@266
|
4057 }
|
Chris@266
|
4058
|
Chris@266
|
4059 void
|
Chris@304
|
4060 MainWindow::midiEventsAvailable()
|
Chris@304
|
4061 {
|
Chris@307
|
4062 Pane *currentPane = 0;
|
Chris@307
|
4063 NoteLayer *currentNoteLayer = 0;
|
Chris@309
|
4064 TimeValueLayer *currentTimeValueLayer = 0;
|
Chris@307
|
4065
|
Chris@307
|
4066 if (m_paneStack) currentPane = m_paneStack->getCurrentPane();
|
Chris@307
|
4067 if (currentPane) {
|
Chris@307
|
4068 currentNoteLayer = dynamic_cast<NoteLayer *>
|
Chris@307
|
4069 (currentPane->getSelectedLayer());
|
Chris@309
|
4070 currentTimeValueLayer = dynamic_cast<TimeValueLayer *>
|
Chris@309
|
4071 (currentPane->getSelectedLayer());
|
Chris@307
|
4072 }
|
Chris@307
|
4073
|
Chris@305
|
4074 // This is called through a serialised signal/slot invocation
|
Chris@305
|
4075 // (across threads). It could happen quite some time after the
|
Chris@305
|
4076 // event was actually received, which is why event timestamping
|
Chris@305
|
4077 // happens in the MIDI input class and not here.
|
Chris@307
|
4078
|
Chris@305
|
4079 while (m_midiInput->getEventsAvailable() > 0) {
|
Chris@308
|
4080
|
Chris@305
|
4081 MIDIEvent ev(m_midiInput->readEvent());
|
Chris@307
|
4082
|
Chris@730
|
4083 int frame = currentPane->alignFromReference(ev.getTime());
|
Chris@309
|
4084
|
Chris@308
|
4085 bool noteOn = (ev.getMessageType() == MIDIConstants::MIDI_NOTE_ON &&
|
Chris@308
|
4086 ev.getVelocity() > 0);
|
Chris@308
|
4087
|
Chris@308
|
4088 bool noteOff = (ev.getMessageType() == MIDIConstants::MIDI_NOTE_OFF ||
|
Chris@308
|
4089 (ev.getMessageType() == MIDIConstants::MIDI_NOTE_ON &&
|
Chris@308
|
4090 ev.getVelocity() == 0));
|
Chris@308
|
4091
|
Chris@307
|
4092 if (currentNoteLayer) {
|
Chris@307
|
4093
|
Chris@310
|
4094 if (!m_playSource || !m_playSource->isPlaying()) continue;
|
Chris@310
|
4095
|
Chris@308
|
4096 if (noteOn) {
|
Chris@307
|
4097
|
Chris@309
|
4098 currentNoteLayer->addNoteOn(frame,
|
Chris@307
|
4099 ev.getPitch(),
|
Chris@307
|
4100 ev.getVelocity());
|
Chris@307
|
4101
|
Chris@308
|
4102 } else if (noteOff) {
|
Chris@307
|
4103
|
Chris@309
|
4104 currentNoteLayer->addNoteOff(frame,
|
Chris@307
|
4105 ev.getPitch());
|
Chris@307
|
4106
|
Chris@307
|
4107 }
|
Chris@307
|
4108
|
Chris@309
|
4109 continue;
|
Chris@309
|
4110 }
|
Chris@309
|
4111
|
Chris@309
|
4112 if (currentTimeValueLayer) {
|
Chris@308
|
4113
|
Chris@308
|
4114 if (!noteOn) continue;
|
Chris@310
|
4115
|
Chris@310
|
4116 if (!m_playSource || !m_playSource->isPlaying()) continue;
|
Chris@310
|
4117
|
Chris@309
|
4118 Model *model = static_cast<Layer *>(currentTimeValueLayer)->getModel();
|
Chris@309
|
4119 SparseTimeValueModel *tvm =
|
Chris@309
|
4120 dynamic_cast<SparseTimeValueModel *>(model);
|
Chris@309
|
4121 if (tvm) {
|
Chris@309
|
4122 SparseTimeValueModel::Point point(frame, ev.getPitch() % 12, "");
|
Chris@309
|
4123 SparseTimeValueModel::AddPointCommand *command =
|
Chris@309
|
4124 new SparseTimeValueModel::AddPointCommand
|
Chris@309
|
4125 (tvm, point, tr("Add Point"));
|
Chris@309
|
4126 CommandHistory::getInstance()->addCommand(command);
|
Chris@309
|
4127 }
|
Chris@309
|
4128 continue;
|
Chris@309
|
4129
|
Chris@305
|
4130 }
|
Chris@309
|
4131
|
Chris@309
|
4132 if (!noteOn) continue;
|
Chris@309
|
4133 insertInstantAt(ev.getTime());
|
Chris@304
|
4134 }
|
Chris@304
|
4135 }
|
Chris@304
|
4136
|
Chris@304
|
4137 void
|
Chris@730
|
4138 MainWindow::playStatusChanged(bool )
|
Chris@305
|
4139 {
|
Chris@307
|
4140 Pane *currentPane = 0;
|
Chris@307
|
4141 NoteLayer *currentNoteLayer = 0;
|
Chris@307
|
4142
|
Chris@307
|
4143 if (m_paneStack) currentPane = m_paneStack->getCurrentPane();
|
Chris@307
|
4144 if (currentPane) {
|
Chris@307
|
4145 currentNoteLayer = dynamic_cast<NoteLayer *>(currentPane->getSelectedLayer());
|
Chris@307
|
4146 }
|
Chris@307
|
4147
|
Chris@307
|
4148 if (currentNoteLayer) {
|
Chris@307
|
4149 currentNoteLayer->abandonNoteOns();
|
Chris@307
|
4150 }
|
Chris@305
|
4151 }
|
Chris@305
|
4152
|
Chris@305
|
4153 void
|
Chris@200
|
4154 MainWindow::layerRemoved(Layer *layer)
|
Chris@0
|
4155 {
|
Chris@95
|
4156 setupExistingLayersMenus();
|
Chris@200
|
4157 MainWindowBase::layerRemoved(layer);
|
Chris@0
|
4158 }
|
Chris@0
|
4159
|
Chris@0
|
4160 void
|
Chris@0
|
4161 MainWindow::layerInAView(Layer *layer, bool inAView)
|
Chris@0
|
4162 {
|
Chris@95
|
4163 setupExistingLayersMenus();
|
Chris@200
|
4164 MainWindowBase::layerInAView(layer, inAView);
|
Chris@0
|
4165 }
|
Chris@0
|
4166
|
Chris@0
|
4167 void
|
Chris@0
|
4168 MainWindow::modelAdded(Model *model)
|
Chris@0
|
4169 {
|
Chris@200
|
4170 MainWindowBase::modelAdded(model);
|
Chris@66
|
4171 if (dynamic_cast<DenseTimeValueModel *>(model)) {
|
Chris@66
|
4172 setupPaneAndLayerMenus();
|
Chris@66
|
4173 }
|
Chris@0
|
4174 }
|
Chris@0
|
4175
|
Chris@0
|
4176 void
|
Chris@0
|
4177 MainWindow::mainModelChanged(WaveFileModel *model)
|
Chris@0
|
4178 {
|
Chris@0
|
4179 m_panLayer->setModel(model);
|
Chris@200
|
4180
|
Chris@200
|
4181 MainWindowBase::mainModelChanged(model);
|
Chris@200
|
4182
|
Chris@200
|
4183 if (m_playTarget) {
|
Chris@200
|
4184 connect(m_fader, SIGNAL(valueChanged(float)),
|
Chris@200
|
4185 m_playTarget, SLOT(setOutputGain(float)));
|
Chris@200
|
4186 }
|
Chris@0
|
4187 }
|
Chris@0
|
4188
|
Chris@0
|
4189 void
|
Chris@760
|
4190 MainWindow::modelAboutToBeDeleted(Model *model)
|
Chris@760
|
4191 {
|
Chris@760
|
4192 if (model == m_panLayer->getModel()) {
|
Chris@760
|
4193 if (model == getMainModel()) {
|
Chris@760
|
4194 m_panLayer->setModel(0);
|
Chris@760
|
4195 } else {
|
Chris@760
|
4196 m_panLayer->setModel(getMainModel());
|
Chris@760
|
4197 }
|
Chris@760
|
4198 }
|
Chris@760
|
4199 MainWindowBase::modelAboutToBeDeleted(model);
|
Chris@760
|
4200 }
|
Chris@760
|
4201
|
Chris@760
|
4202 void
|
Chris@200
|
4203 MainWindow::setInstantsNumbering()
|
Chris@0
|
4204 {
|
Chris@200
|
4205 QAction *a = dynamic_cast<QAction *>(sender());
|
Chris@200
|
4206 if (!a) return;
|
Chris@200
|
4207
|
Chris@200
|
4208 int type = m_numberingActions[a];
|
Chris@200
|
4209
|
Chris@200
|
4210 if (m_labeller) m_labeller->setType(Labeller::ValueType(type));
|
Chris@200
|
4211
|
Chris@200
|
4212 QSettings settings;
|
Chris@200
|
4213 settings.beginGroup("MainWindow");
|
Chris@200
|
4214 settings.setValue("labellertype", type);
|
Chris@200
|
4215 settings.endGroup();
|
Chris@200
|
4216 }
|
Chris@200
|
4217
|
Chris@200
|
4218 void
|
Chris@200
|
4219 MainWindow::setInstantsCounterCycle()
|
Chris@200
|
4220 {
|
Chris@200
|
4221 QAction *a = dynamic_cast<QAction *>(sender());
|
Chris@200
|
4222 if (!a) return;
|
Chris@200
|
4223
|
Chris@200
|
4224 int cycle = a->text().toInt();
|
Chris@200
|
4225 if (cycle == 0) return;
|
Chris@200
|
4226
|
Chris@200
|
4227 if (m_labeller) m_labeller->setCounterCycleSize(cycle);
|
Chris@200
|
4228
|
Chris@200
|
4229 QSettings settings;
|
Chris@200
|
4230 settings.beginGroup("MainWindow");
|
Chris@200
|
4231 settings.setValue("labellercycle", cycle);
|
Chris@200
|
4232 settings.endGroup();
|
Chris@200
|
4233 }
|
Chris@200
|
4234
|
Chris@200
|
4235 void
|
Chris@597
|
4236 MainWindow::setInstantsCounters()
|
Chris@200
|
4237 {
|
Chris@200
|
4238 LabelCounterInputDialog dialog(m_labeller, this);
|
Chris@241
|
4239 dialog.setWindowTitle(tr("Reset Counters"));
|
Chris@200
|
4240 dialog.exec();
|
Chris@0
|
4241 }
|
Chris@0
|
4242
|
Chris@0
|
4243 void
|
Chris@597
|
4244 MainWindow::resetInstantsCounters()
|
Chris@597
|
4245 {
|
Chris@597
|
4246 if (m_labeller) m_labeller->resetCounters();
|
Chris@597
|
4247 }
|
Chris@597
|
4248
|
Chris@597
|
4249 void
|
Chris@233
|
4250 MainWindow::modelGenerationFailed(QString transformName, QString message)
|
Chris@233
|
4251 {
|
Chris@247
|
4252 emit hideSplash();
|
Chris@247
|
4253
|
Chris@233
|
4254 if (message != "") {
|
Chris@233
|
4255
|
Chris@233
|
4256 QMessageBox::warning
|
Chris@233
|
4257 (this,
|
Chris@233
|
4258 tr("Failed to generate layer"),
|
Chris@233
|
4259 tr("<b>Layer generation failed</b><p>Failed to generate derived layer.<p>The layer transform \"%1\" failed:<p>%2")
|
Chris@233
|
4260 .arg(transformName).arg(message),
|
Chris@233
|
4261 QMessageBox::Ok);
|
Chris@233
|
4262 } else {
|
Chris@233
|
4263 QMessageBox::warning
|
Chris@233
|
4264 (this,
|
Chris@233
|
4265 tr("Failed to generate layer"),
|
Chris@233
|
4266 tr("<b>Layer generation failed</b><p>Failed to generate a derived layer.<p>The layer transform \"%1\" failed.<p>No error information is available.")
|
Chris@233
|
4267 .arg(transformName),
|
Chris@233
|
4268 QMessageBox::Ok);
|
Chris@233
|
4269 }
|
Chris@233
|
4270 }
|
Chris@233
|
4271
|
Chris@233
|
4272 void
|
Chris@730
|
4273 MainWindow::modelGenerationWarning(QString /* transformName */, QString message)
|
Chris@233
|
4274 {
|
Chris@247
|
4275 emit hideSplash();
|
Chris@247
|
4276
|
Chris@233
|
4277 QMessageBox::warning
|
Chris@233
|
4278 (this, tr("Warning"), message, QMessageBox::Ok);
|
Chris@233
|
4279 }
|
Chris@233
|
4280
|
Chris@233
|
4281 void
|
Chris@233
|
4282 MainWindow::modelRegenerationFailed(QString layerName,
|
Chris@233
|
4283 QString transformName, QString message)
|
Chris@233
|
4284 {
|
Chris@247
|
4285 emit hideSplash();
|
Chris@247
|
4286
|
Chris@233
|
4287 if (message != "") {
|
Chris@233
|
4288
|
Chris@233
|
4289 QMessageBox::warning
|
Chris@233
|
4290 (this,
|
Chris@233
|
4291 tr("Failed to regenerate layer"),
|
Chris@233
|
4292 tr("<b>Layer generation failed</b><p>Failed to regenerate derived layer \"%1\" using new data model as input.<p>The layer transform \"%2\" failed:<p>%3")
|
Chris@233
|
4293 .arg(layerName).arg(transformName).arg(message),
|
Chris@233
|
4294 QMessageBox::Ok);
|
Chris@233
|
4295 } else {
|
Chris@233
|
4296 QMessageBox::warning
|
Chris@233
|
4297 (this,
|
Chris@233
|
4298 tr("Failed to regenerate layer"),
|
Chris@233
|
4299 tr("<b>Layer generation failed</b><p>Failed to regenerate derived layer \"%1\" using new data model as input.<p>The layer transform \"%2\" failed.<p>No error information is available.")
|
Chris@233
|
4300 .arg(layerName).arg(transformName),
|
Chris@233
|
4301 QMessageBox::Ok);
|
Chris@233
|
4302 }
|
Chris@233
|
4303 }
|
Chris@233
|
4304
|
Chris@233
|
4305 void
|
Chris@233
|
4306 MainWindow::modelRegenerationWarning(QString layerName,
|
Chris@730
|
4307 QString /* transformName */,
|
Chris@730
|
4308 QString message)
|
Chris@233
|
4309 {
|
Chris@247
|
4310 emit hideSplash();
|
Chris@247
|
4311
|
Chris@233
|
4312 QMessageBox::warning
|
Chris@233
|
4313 (this, tr("Warning"), tr("<b>Warning when regenerating layer</b><p>When regenerating the derived layer \"%1\" using new data model as input:<p>%2").arg(layerName).arg(message), QMessageBox::Ok);
|
Chris@233
|
4314 }
|
Chris@233
|
4315
|
Chris@233
|
4316 void
|
Chris@233
|
4317 MainWindow::alignmentFailed(QString transformName, QString message)
|
Chris@0
|
4318 {
|
Chris@247
|
4319 emit hideSplash();
|
Chris@247
|
4320
|
Chris@0
|
4321 QMessageBox::warning
|
Chris@0
|
4322 (this,
|
Chris@233
|
4323 tr("Failed to calculate alignment"),
|
Chris@233
|
4324 tr("<b>Alignment calculation failed</b><p>Failed to calculate an audio alignment using transform \"%1\":<p>%2")
|
Chris@233
|
4325 .arg(transformName).arg(message),
|
Chris@165
|
4326 QMessageBox::Ok);
|
Chris@0
|
4327 }
|
Chris@0
|
4328
|
Chris@0
|
4329 void
|
Chris@0
|
4330 MainWindow::rightButtonMenuRequested(Pane *pane, QPoint position)
|
Chris@0
|
4331 {
|
Chris@438
|
4332 // SVDEBUG << "MainWindow::rightButtonMenuRequested(" << pane << ", " << position.x() << ", " << position.y() << ")" << endl;
|
Chris@0
|
4333 m_paneStack->setCurrentPane(pane);
|
Chris@0
|
4334 m_rightButtonMenu->popup(position);
|
Chris@0
|
4335 }
|
Chris@0
|
4336
|
Chris@0
|
4337 void
|
Chris@0
|
4338 MainWindow::showLayerTree()
|
Chris@0
|
4339 {
|
Chris@219
|
4340 if (!m_layerTreeDialog.isNull()) {
|
Chris@219
|
4341 m_layerTreeDialog->show();
|
Chris@219
|
4342 m_layerTreeDialog->raise();
|
Chris@177
|
4343 return;
|
Chris@177
|
4344 }
|
Chris@177
|
4345
|
Chris@762
|
4346 m_layerTreeDialog = new LayerTreeDialog(m_paneStack, this);
|
Chris@232
|
4347 m_layerTreeDialog->setAttribute(Qt::WA_DeleteOnClose); // see below
|
Chris@219
|
4348 m_layerTreeDialog->show();
|
Chris@0
|
4349 }
|
Chris@0
|
4350
|
Chris@0
|
4351 void
|
Chris@306
|
4352 MainWindow::showActivityLog()
|
Chris@306
|
4353 {
|
Chris@306
|
4354 m_activityLog->show();
|
Chris@306
|
4355 m_activityLog->raise();
|
Chris@306
|
4356 m_activityLog->scrollToEnd();
|
Chris@306
|
4357 }
|
Chris@306
|
4358
|
Chris@306
|
4359 void
|
Chris@0
|
4360 MainWindow::preferences()
|
Chris@0
|
4361 {
|
Chris@436
|
4362 bool goToTemplateTab =
|
Chris@436
|
4363 (sender() && sender()->objectName() == "set_default_template");
|
Chris@436
|
4364
|
Chris@0
|
4365 if (!m_preferencesDialog.isNull()) {
|
Chris@0
|
4366 m_preferencesDialog->show();
|
Chris@0
|
4367 m_preferencesDialog->raise();
|
Chris@436
|
4368 if (goToTemplateTab) {
|
Chris@436
|
4369 m_preferencesDialog->switchToTab(PreferencesDialog::TemplateTab);
|
Chris@436
|
4370 }
|
Chris@0
|
4371 return;
|
Chris@0
|
4372 }
|
Chris@0
|
4373
|
Chris@0
|
4374 m_preferencesDialog = new PreferencesDialog(this);
|
Chris@0
|
4375
|
Chris@0
|
4376 // DeleteOnClose is safe here, because m_preferencesDialog is a
|
Chris@0
|
4377 // QPointer that will be zeroed when the dialog is deleted. We
|
Chris@0
|
4378 // use it in preference to leaving the dialog lying around because
|
Chris@0
|
4379 // if you Cancel the dialog, it resets the preferences state
|
Chris@0
|
4380 // without resetting its own widgets, so its state will be
|
Chris@0
|
4381 // incorrect when next shown unless we construct it afresh
|
Chris@0
|
4382 m_preferencesDialog->setAttribute(Qt::WA_DeleteOnClose);
|
Chris@0
|
4383
|
Chris@0
|
4384 m_preferencesDialog->show();
|
Chris@436
|
4385 if (goToTemplateTab) {
|
Chris@436
|
4386 m_preferencesDialog->switchToTab(PreferencesDialog::TemplateTab);
|
Chris@436
|
4387 }
|
Chris@0
|
4388 }
|
Chris@0
|
4389
|
Chris@0
|
4390 void
|
Chris@90
|
4391 MainWindow::mouseEnteredWidget()
|
Chris@90
|
4392 {
|
Chris@90
|
4393 QWidget *w = dynamic_cast<QWidget *>(sender());
|
Chris@90
|
4394 if (!w) return;
|
Chris@90
|
4395
|
Chris@90
|
4396 if (w == m_fader) {
|
Chris@116
|
4397 contextHelpChanged(tr("Adjust the master playback level"));
|
Chris@90
|
4398 } else if (w == m_playSpeed) {
|
Chris@116
|
4399 contextHelpChanged(tr("Adjust the master playback speed"));
|
Chris@90
|
4400 }
|
Chris@90
|
4401 }
|
Chris@90
|
4402
|
Chris@90
|
4403 void
|
Chris@90
|
4404 MainWindow::mouseLeftWidget()
|
Chris@90
|
4405 {
|
Chris@116
|
4406 contextHelpChanged("");
|
Chris@116
|
4407 }
|
Chris@116
|
4408
|
Chris@116
|
4409 void
|
Chris@0
|
4410 MainWindow::website()
|
Chris@0
|
4411 {
|
Chris@0
|
4412 openHelpUrl(tr("http://www.sonicvisualiser.org/"));
|
Chris@0
|
4413 }
|
Chris@0
|
4414
|
Chris@0
|
4415 void
|
Chris@0
|
4416 MainWindow::help()
|
Chris@0
|
4417 {
|
Chris@318
|
4418 openHelpUrl(tr("http://www.sonicvisualiser.org/doc/reference/%1/en/").arg(SV_VERSION));
|
Chris@0
|
4419 }
|
Chris@0
|
4420
|
Chris@0
|
4421 void
|
Chris@0
|
4422 MainWindow::about()
|
Chris@0
|
4423 {
|
Chris@0
|
4424 bool debug = false;
|
Chris@0
|
4425 QString version = "(unknown version)";
|
Chris@0
|
4426
|
Chris@0
|
4427 #ifdef BUILD_DEBUG
|
Chris@0
|
4428 debug = true;
|
Chris@285
|
4429 #endif // BUILD_DEBUG
|
Chris@0
|
4430 #ifdef SV_VERSION
|
Chris@0
|
4431 #ifdef SVNREV
|
Chris@0
|
4432 version = tr("Release %1 : Revision %2").arg(SV_VERSION).arg(SVNREV);
|
Chris@285
|
4433 #else // !SVNREV
|
Chris@0
|
4434 version = tr("Release %1").arg(SV_VERSION);
|
Chris@285
|
4435 #endif // SVNREV
|
Chris@285
|
4436 #else // !SV_VERSION
|
Chris@0
|
4437 #ifdef SVNREV
|
Chris@0
|
4438 version = tr("Unreleased : Revision %1").arg(SVNREV);
|
Chris@285
|
4439 #endif // SVNREV
|
Chris@285
|
4440 #endif // SV_VERSION
|
Chris@0
|
4441
|
Chris@0
|
4442 QString aboutText;
|
Chris@0
|
4443
|
Chris@0
|
4444 aboutText += tr("<h3>About Sonic Visualiser</h3>");
|
Chris@285
|
4445 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>");
|
Chris@285
|
4446 aboutText += tr("<p><small>%1 : %2 configuration</small></p>")
|
Chris@0
|
4447 .arg(version)
|
Chris@0
|
4448 .arg(debug ? tr("Debug") : tr("Release"));
|
Chris@0
|
4449
|
Chris@285
|
4450 aboutText += "<small>";
|
Chris@285
|
4451
|
Chris@285
|
4452 aboutText += tr("With Qt v%1 © Nokia Corporation").arg(QT_VERSION_STR);
|
Chris@285
|
4453
|
Chris@0
|
4454 #ifdef HAVE_JACK
|
Chris@93
|
4455 #ifdef JACK_VERSION
|
Chris@285
|
4456 aboutText += tr("<br>With JACK audio output library v%1 © Paul Davis and Jack O'Quin").arg(JACK_VERSION);
|
Chris@285
|
4457 #else // !JACK_VERSION
|
Chris@257
|
4458 aboutText += tr("<br>With JACK audio output library © Paul Davis and Jack O'Quin");
|
Chris@285
|
4459 #endif // JACK_VERSION
|
Chris@285
|
4460 #endif // HAVE_JACK
|
Chris@0
|
4461 #ifdef HAVE_PORTAUDIO
|
Chris@257
|
4462 aboutText += tr("<br>With PortAudio audio output library © Ross Bencina and Phil Burk");
|
Chris@285
|
4463 #endif // HAVE_PORTAUDIO
|
Chris@257
|
4464 #ifdef HAVE_LIBPULSE
|
Chris@285
|
4465 #ifdef LIBPULSE_VERSION
|
Chris@285
|
4466 aboutText += tr("<br>With PulseAudio audio output library v%1 © Lennart Poettering and Pierre Ossman").arg(LIBPULSE_VERSION);
|
Chris@285
|
4467 #else // !LIBPULSE_VERSION
|
Chris@257
|
4468 aboutText += tr("<br>With PulseAudio audio output library © Lennart Poettering and Pierre Ossman");
|
Chris@285
|
4469 #endif // LIBPULSE_VERSION
|
Chris@285
|
4470 #endif // HAVE_LIBPULSE
|
Chris@0
|
4471 #ifdef HAVE_OGGZ
|
Chris@93
|
4472 #ifdef OGGZ_VERSION
|
Chris@0
|
4473 aboutText += tr("<br>With Ogg file decoder (oggz v%1, fishsound v%2) © CSIRO Australia").arg(OGGZ_VERSION).arg(FISHSOUND_VERSION);
|
Chris@285
|
4474 #else // !OGGZ_VERSION
|
Chris@93
|
4475 aboutText += tr("<br>With Ogg file decoder © CSIRO Australia");
|
Chris@285
|
4476 #endif // OGGZ_VERSION
|
Chris@285
|
4477 #endif // HAVE_OGGZ
|
Chris@0
|
4478 #ifdef HAVE_MAD
|
Chris@93
|
4479 #ifdef MAD_VERSION
|
Chris@285
|
4480 aboutText += tr("<br>With MAD mp3 decoder v%1 © Underbit Technologies Inc").arg(MAD_VERSION);
|
Chris@285
|
4481 #else // !MAD_VERSION
|
Chris@93
|
4482 aboutText += tr("<br>With MAD mp3 decoder © Underbit Technologies Inc");
|
Chris@285
|
4483 #endif // MAD_VERSION
|
Chris@285
|
4484 #endif // HAVE_MAD
|
Chris@0
|
4485 #ifdef HAVE_SAMPLERATE
|
Chris@93
|
4486 #ifdef SAMPLERATE_VERSION
|
Chris@285
|
4487 aboutText += tr("<br>With libsamplerate v%1 © Erik de Castro Lopo").arg(SAMPLERATE_VERSION);
|
Chris@285
|
4488 #else // !SAMPLERATE_VERSION
|
Chris@93
|
4489 aboutText += tr("<br>With libsamplerate © Erik de Castro Lopo");
|
Chris@285
|
4490 #endif // SAMPLERATE_VERSION
|
Chris@285
|
4491 #endif // HAVE_SAMPLERATE
|
Chris@0
|
4492 #ifdef HAVE_SNDFILE
|
Chris@93
|
4493 #ifdef SNDFILE_VERSION
|
Chris@285
|
4494 aboutText += tr("<br>With libsndfile v%1 © Erik de Castro Lopo").arg(SNDFILE_VERSION);
|
Chris@285
|
4495 #else // !SNDFILE_VERSION
|
Chris@93
|
4496 aboutText += tr("<br>With libsndfile © Erik de Castro Lopo");
|
Chris@285
|
4497 #endif // SNDFILE_VERSION
|
Chris@285
|
4498 #endif // HAVE_SNDFILE
|
Chris@127
|
4499 #ifdef HAVE_FFTW3F
|
Chris@93
|
4500 #ifdef FFTW3_VERSION
|
Chris@285
|
4501 aboutText += tr("<br>With FFTW3 v%1 © Matteo Frigo and MIT").arg(FFTW3_VERSION);
|
Chris@285
|
4502 #else // !FFTW3_VERSION
|
Chris@93
|
4503 aboutText += tr("<br>With FFTW3 © Matteo Frigo and MIT");
|
Chris@285
|
4504 #endif // FFTW3_VERSION
|
Chris@285
|
4505 #endif // HAVE_FFTW3F
|
Chris@267
|
4506 #ifdef HAVE_RUBBERBAND
|
Chris@267
|
4507 #ifdef RUBBERBAND_VERSION
|
Chris@285
|
4508 aboutText += tr("<br>With Rubber Band v%1 © Chris Cannam").arg(RUBBERBAND_VERSION);
|
Chris@285
|
4509 #else // !RUBBERBAND_VERSION
|
Chris@267
|
4510 aboutText += tr("<br>With Rubber Band © Chris Cannam");
|
Chris@285
|
4511 #endif // RUBBERBAND_VERSION
|
Chris@285
|
4512 #endif // HAVE_RUBBERBAND
|
Chris@0
|
4513 #ifdef HAVE_VAMP
|
Chris@114
|
4514 aboutText += tr("<br>With Vamp plugin support (API v%1, host SDK v%2) © Chris Cannam").arg(VAMP_API_VERSION).arg(VAMP_SDK_VERSION);
|
Chris@285
|
4515 #endif // !HAVE_VAMP
|
Chris@0
|
4516 aboutText += tr("<br>With LADSPA plugin support (API v%1) © Richard Furse, Paul Davis, Stefan Westerfeld").arg(LADSPA_VERSION);
|
Chris@0
|
4517 aboutText += tr("<br>With DSSI plugin support (API v%1) © Chris Cannam, Steve Harris, Sean Bolton").arg(DSSI_VERSION);
|
Chris@285
|
4518 #ifdef REDLAND_VERSION
|
Chris@285
|
4519 aboutText += tr("<br>With Redland RDF datastore v%1 © Dave Beckett and the University of Bristol").arg(REDLAND_VERSION);
|
Chris@285
|
4520 #else // !REDLAND_VERSION
|
Chris@285
|
4521 aboutText += tr("<br>With Redland RDF datastore © Dave Beckett and the University of Bristol");
|
Chris@285
|
4522 #endif // REDLAND_VERSION
|
Chris@523
|
4523 aboutText += tr("<br>With Serd and Sord RDF parser and store © David Robillard");
|
Chris@523
|
4524 aboutText += tr("<br>With Dataquay Qt/RDF library © Chris Cannam");
|
Chris@285
|
4525
|
Chris@300
|
4526 aboutText += tr("<br>With RtMidi © Gary P. Scavone");
|
Chris@300
|
4527
|
Chris@69
|
4528 #ifdef HAVE_LIBLO
|
Chris@93
|
4529 #ifdef LIBLO_VERSION
|
Chris@285
|
4530 aboutText += tr("<br>With liblo Lite OSC library v%1 © Steve Harris").arg(LIBLO_VERSION);
|
Chris@285
|
4531 #else // !LIBLO_VERSION
|
Chris@327
|
4532 aboutText += tr("<br>With liblo Lite OSC library © Steve Harris");
|
Chris@285
|
4533 #endif // LIBLO_VERSION
|
Chris@285
|
4534
|
Chris@285
|
4535 if (m_oscQueue && m_oscQueue->isOK()) {
|
Chris@285
|
4536 aboutText += tr("</small><p><small>The OSC URL for this instance is: \"%1\"").arg(m_oscQueue->getOSCURL());
|
Chris@285
|
4537 }
|
Chris@285
|
4538
|
Chris@285
|
4539 aboutText += "</small></p>";
|
Chris@285
|
4540 #endif // HAVE_LIBLO
|
Chris@285
|
4541
|
Chris@285
|
4542 #ifndef BUILD_STATIC
|
Chris@285
|
4543 aboutText.replace(tr("With "), tr("Using "));
|
Chris@93
|
4544 #endif
|
Chris@0
|
4545
|
Chris@0
|
4546 aboutText +=
|
Chris@523
|
4547 "<p><small>Sonic Visualiser Copyright © 2005–2013 Chris Cannam and "
|
Chris@285
|
4548 "Queen Mary, University of London.</small></p>"
|
Chris@285
|
4549 "<p><small>This program is free software; you can redistribute it and/or "
|
Chris@231
|
4550 "modify it under the terms of the GNU General Public License as "
|
Chris@231
|
4551 "published by the Free Software Foundation; either version 2 of the "
|
Chris@0
|
4552 "License, or (at your option) any later version.<br>See the file "
|
Chris@285
|
4553 "COPYING included with this distribution for more information.</small></p>";
|
Chris@0
|
4554
|
Chris@0
|
4555 QMessageBox::about(this, tr("About Sonic Visualiser"), aboutText);
|
Chris@0
|
4556 }
|
Chris@0
|
4557
|
Chris@162
|
4558 void
|
Chris@162
|
4559 MainWindow::keyReference()
|
Chris@162
|
4560 {
|
Chris@162
|
4561 m_keyReference->show();
|
Chris@162
|
4562 }
|
Chris@162
|
4563
|
Chris@333
|
4564 void
|
Chris@333
|
4565 MainWindow::newerVersionAvailable(QString version)
|
Chris@333
|
4566 {
|
Chris@334
|
4567 QSettings settings;
|
Chris@334
|
4568 settings.beginGroup("NewerVersionWarning");
|
Chris@334
|
4569 QString tag = QString("version-%1-available-show").arg(version);
|
Chris@334
|
4570 if (settings.value(tag, true).toBool()) {
|
Chris@334
|
4571 QString title(tr("Newer version available"));
|
Chris@663
|
4572 QString text(tr("<h3>Newer version available</h3><p>You are using version %1 of Sonic Visualiser, but version %2 is now available.</p><p>Please see the <a href=\"http://sonicvisualiser.org/\">Sonic Visualiser website</a> for more information.</p>").arg(SV_VERSION).arg(version));
|
Chris@334
|
4573 QMessageBox::information(this, title, text);
|
Chris@334
|
4574 settings.setValue(tag, false);
|
Chris@334
|
4575 }
|
Chris@334
|
4576 settings.endGroup();
|
Chris@333
|
4577 }
|
Chris@333
|
4578
|
Chris@333
|
4579
|