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