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