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