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