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