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