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