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