Chris@45
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@45
|
2
|
Chris@45
|
3 /*
|
Chris@45
|
4 Sonic Visualiser
|
Chris@45
|
5 An audio file viewer and annotation editor.
|
Chris@45
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@45
|
7 This file copyright 2006-2007 Chris Cannam and QMUL.
|
Chris@45
|
8
|
Chris@45
|
9 This program is free software; you can redistribute it and/or
|
Chris@45
|
10 modify it under the terms of the GNU General Public License as
|
Chris@45
|
11 published by the Free Software Foundation; either version 2 of the
|
Chris@45
|
12 License, or (at your option) any later version. See the file
|
Chris@45
|
13 COPYING included with this distribution for more information.
|
Chris@45
|
14 */
|
Chris@45
|
15
|
Chris@45
|
16 #include "MainWindowBase.h"
|
Chris@46
|
17 #include "Document.h"
|
Chris@45
|
18
|
Chris@45
|
19 #include "view/Pane.h"
|
Chris@45
|
20 #include "view/PaneStack.h"
|
Chris@479
|
21 #include "data/model/ReadOnlyWaveFileModel.h"
|
Chris@477
|
22 #include "data/model/WritableWaveFileModel.h"
|
Chris@45
|
23 #include "data/model/SparseOneDimensionalModel.h"
|
Chris@45
|
24 #include "data/model/NoteModel.h"
|
matthiasm@267
|
25 #include "data/model/FlexiNoteModel.h"
|
Chris@45
|
26 #include "data/model/Labeller.h"
|
Chris@124
|
27 #include "data/model/TabularModel.h"
|
Chris@45
|
28 #include "view/ViewManager.h"
|
Chris@45
|
29
|
Chris@45
|
30 #include "layer/WaveformLayer.h"
|
Chris@45
|
31 #include "layer/TimeRulerLayer.h"
|
Chris@45
|
32 #include "layer/TimeInstantLayer.h"
|
Chris@45
|
33 #include "layer/TimeValueLayer.h"
|
Chris@45
|
34 #include "layer/Colour3DPlotLayer.h"
|
Chris@45
|
35 #include "layer/SliceLayer.h"
|
Chris@45
|
36 #include "layer/SliceableLayer.h"
|
Chris@45
|
37 #include "layer/ImageLayer.h"
|
Chris@184
|
38 #include "layer/NoteLayer.h"
|
matthiasm@267
|
39 #include "layer/FlexiNoteLayer.h"
|
Chris@184
|
40 #include "layer/RegionLayer.h"
|
Chris@45
|
41
|
Chris@45
|
42 #include "widgets/ListInputDialog.h"
|
Chris@105
|
43 #include "widgets/CommandHistory.h"
|
Chris@109
|
44 #include "widgets/ProgressDialog.h"
|
Chris@109
|
45 #include "widgets/MIDIFileImportDialog.h"
|
Chris@109
|
46 #include "widgets/CSVFormatDialog.h"
|
Chris@123
|
47 #include "widgets/ModelDataTableDialog.h"
|
Chris@341
|
48 #include "widgets/InteractiveFileFinder.h"
|
Chris@45
|
49
|
Chris@468
|
50 #include "audio/AudioCallbackPlaySource.h"
|
Chris@574
|
51 #include "audio/AudioCallbackRecordTarget.h"
|
Chris@468
|
52 #include "audio/PlaySpeedRangeMapper.h"
|
Chris@475
|
53
|
Chris@45
|
54 #include "data/fileio/DataFileReaderFactory.h"
|
Chris@45
|
55 #include "data/fileio/PlaylistFileReader.h"
|
Chris@45
|
56 #include "data/fileio/WavFileWriter.h"
|
Chris@45
|
57 #include "data/fileio/MIDIFileWriter.h"
|
Chris@45
|
58 #include "data/fileio/BZipFileDevice.h"
|
Chris@45
|
59 #include "data/fileio/FileSource.h"
|
Chris@152
|
60 #include "data/fileio/AudioFileReaderFactory.h"
|
Chris@134
|
61 #include "rdf/RDFImporter.h"
|
Chris@45
|
62
|
Chris@45
|
63 #include "base/RecentFiles.h"
|
Chris@45
|
64
|
Chris@45
|
65 #include "base/PlayParameterRepository.h"
|
Chris@45
|
66 #include "base/XmlExportable.h"
|
Chris@45
|
67 #include "base/Profiler.h"
|
Chris@45
|
68 #include "base/Preferences.h"
|
Chris@217
|
69 #include "base/TempWriteFile.h"
|
Chris@217
|
70 #include "base/Exceptions.h"
|
Chris@223
|
71 #include "base/ResourceFinder.h"
|
Chris@45
|
72
|
Chris@45
|
73 #include "data/osc/OSCQueue.h"
|
Chris@157
|
74 #include "data/midi/MIDIInput.h"
|
Chris@45
|
75
|
Chris@599
|
76 #include "system/System.h"
|
Chris@599
|
77
|
Chris@468
|
78 #include <bqaudioio/SystemPlaybackTarget.h>
|
Chris@475
|
79 #include <bqaudioio/SystemAudioIO.h>
|
Chris@468
|
80 #include <bqaudioio/AudioFactory.h>
|
Chris@551
|
81 #include <bqaudioio/ResamplerWrapper.h>
|
Chris@468
|
82
|
Chris@45
|
83 #include <QApplication>
|
Chris@45
|
84 #include <QMessageBox>
|
Chris@45
|
85 #include <QGridLayout>
|
Chris@45
|
86 #include <QLabel>
|
Chris@45
|
87 #include <QAction>
|
Chris@45
|
88 #include <QMenuBar>
|
Chris@45
|
89 #include <QToolBar>
|
Chris@45
|
90 #include <QInputDialog>
|
Chris@45
|
91 #include <QStatusBar>
|
Chris@45
|
92 #include <QTreeView>
|
Chris@45
|
93 #include <QFile>
|
Chris@45
|
94 #include <QFileInfo>
|
Chris@45
|
95 #include <QDir>
|
Chris@45
|
96 #include <QTextStream>
|
Chris@432
|
97 #include <QTextCodec>
|
Chris@45
|
98 #include <QProcess>
|
Chris@45
|
99 #include <QShortcut>
|
Chris@45
|
100 #include <QSettings>
|
Chris@45
|
101 #include <QDateTime>
|
Chris@45
|
102 #include <QProcess>
|
Chris@45
|
103 #include <QCheckBox>
|
Chris@45
|
104 #include <QRegExp>
|
Chris@45
|
105 #include <QScrollArea>
|
Chris@168
|
106 #include <QDesktopWidget>
|
Chris@354
|
107 #include <QSignalMapper>
|
Chris@45
|
108
|
Chris@45
|
109 #include <iostream>
|
Chris@45
|
110 #include <cstdio>
|
Chris@45
|
111 #include <errno.h>
|
Chris@45
|
112
|
Chris@45
|
113 using std::vector;
|
Chris@45
|
114 using std::map;
|
Chris@45
|
115 using std::set;
|
Chris@45
|
116
|
Chris@255
|
117 #ifdef Q_WS_X11
|
Chris@255
|
118 #define Window X11Window
|
Chris@255
|
119 #include <X11/Xlib.h>
|
Chris@255
|
120 #include <X11/Xutil.h>
|
Chris@255
|
121 #include <X11/Xatom.h>
|
Chris@255
|
122 #include <X11/SM/SMlib.h>
|
Chris@255
|
123
|
Chris@255
|
124 static int handle_x11_error(Display *dpy, XErrorEvent *err)
|
Chris@255
|
125 {
|
Chris@255
|
126 char errstr[256];
|
Chris@255
|
127 XGetErrorText(dpy, err->error_code, errstr, 256);
|
Chris@255
|
128 if (err->error_code != BadWindow) {
|
Chris@595
|
129 cerr << "Sonic Visualiser: X Error: "
|
Chris@595
|
130 << errstr << " " << int(err->error_code)
|
Chris@595
|
131 << "\nin major opcode: "
|
Chris@595
|
132 << int(err->request_code) << endl;
|
Chris@255
|
133 }
|
Chris@255
|
134 return 0;
|
Chris@255
|
135 }
|
Chris@255
|
136 #undef Window
|
Chris@255
|
137 #endif
|
Chris@45
|
138
|
Chris@475
|
139 MainWindowBase::MainWindowBase(SoundOptions options) :
|
Chris@45
|
140 m_document(0),
|
Chris@45
|
141 m_paneStack(0),
|
Chris@45
|
142 m_viewManager(0),
|
Chris@45
|
143 m_timeRulerLayer(0),
|
Chris@475
|
144 m_soundOptions(options),
|
Chris@45
|
145 m_playSource(0),
|
Chris@475
|
146 m_recordTarget(0),
|
Chris@551
|
147 m_resamplerWrapper(0),
|
Chris@45
|
148 m_playTarget(0),
|
Chris@475
|
149 m_audioIO(0),
|
Chris@113
|
150 m_oscQueue(0),
|
Chris@113
|
151 m_oscQueueStarter(0),
|
Chris@157
|
152 m_midiInput(0),
|
Chris@45
|
153 m_recentFiles("RecentFiles", 20),
|
Chris@54
|
154 m_recentTransforms("RecentTransforms", 20),
|
Chris@45
|
155 m_documentModified(false),
|
Chris@45
|
156 m_openingAudioFile(false),
|
Chris@45
|
157 m_abandoning(false),
|
Chris@121
|
158 m_labeller(0),
|
Chris@357
|
159 m_lastPlayStatusSec(0),
|
Chris@357
|
160 m_initialDarkBackground(false),
|
Chris@378
|
161 m_defaultFfwdRwdStep(2, 0),
|
Chris@483
|
162 m_audioRecordMode(RecordCreateAdditionalModel),
|
Chris@390
|
163 m_statusLabel(0),
|
Chris@426
|
164 m_iconsVisibleInMenus(true),
|
Chris@390
|
165 m_menuShortcutMapper(0)
|
Chris@45
|
166 {
|
Chris@113
|
167 Profiler profiler("MainWindowBase::MainWindowBase");
|
Chris@113
|
168
|
Chris@591
|
169 SVDEBUG << "MainWindowBase::MainWindowBase" << endl;
|
Chris@591
|
170
|
Chris@475
|
171 if (options & WithAudioInput) {
|
Chris@475
|
172 if (!(options & WithAudioOutput)) {
|
Chris@591
|
173 SVCERR << "WARNING: MainWindowBase: WithAudioInput requires WithAudioOutput -- recording will not work" << endl;
|
Chris@475
|
174 }
|
Chris@475
|
175 }
|
Chris@475
|
176
|
Chris@438
|
177 qRegisterMetaType<sv_frame_t>("sv_frame_t");
|
Chris@438
|
178 qRegisterMetaType<sv_samplerate_t>("sv_samplerate_t");
|
Chris@438
|
179
|
Chris@255
|
180 #ifdef Q_WS_X11
|
Chris@255
|
181 XSetErrorHandler(handle_x11_error);
|
Chris@255
|
182 #endif
|
Chris@255
|
183
|
Chris@452
|
184 connect(this, SIGNAL(hideSplash()), this, SLOT(emitHideSplash()));
|
Chris@452
|
185
|
Chris@45
|
186 connect(CommandHistory::getInstance(), SIGNAL(commandExecuted()),
|
Chris@595
|
187 this, SLOT(documentModified()));
|
Chris@45
|
188 connect(CommandHistory::getInstance(), SIGNAL(documentRestored()),
|
Chris@595
|
189 this, SLOT(documentRestored()));
|
Chris@45
|
190
|
Chris@591
|
191 SVDEBUG << "MainWindowBase: Creating view manager" << endl;
|
Chris@591
|
192
|
Chris@45
|
193 m_viewManager = new ViewManager();
|
Chris@45
|
194 connect(m_viewManager, SIGNAL(selectionChanged()),
|
Chris@595
|
195 this, SLOT(updateMenuStates()));
|
Chris@45
|
196 connect(m_viewManager, SIGNAL(inProgressSelectionChanged()),
|
Chris@595
|
197 this, SLOT(inProgressSelectionChanged()));
|
Chris@45
|
198
|
Chris@591
|
199 SVDEBUG << "MainWindowBase: Calculating view font size" << endl;
|
Chris@591
|
200
|
Chris@105
|
201 // set a sensible default font size for views -- cannot do this
|
Chris@105
|
202 // in Preferences, which is in base and not supposed to use QtGui
|
Chris@436
|
203 int viewFontSize = int(QApplication::font().pointSize() * 0.9);
|
Chris@105
|
204 QSettings settings;
|
Chris@105
|
205 settings.beginGroup("Preferences");
|
Chris@105
|
206 viewFontSize = settings.value("view-font-size", viewFontSize).toInt();
|
Chris@105
|
207 settings.setValue("view-font-size", viewFontSize);
|
Chris@105
|
208 settings.endGroup();
|
Chris@105
|
209
|
Chris@591
|
210 SVDEBUG << "MainWindowBase: View font size is " << viewFontSize << endl;
|
Chris@591
|
211
|
Chris@511
|
212 #ifdef NOT_DEFINED // This no longer works correctly on any platform AFAICS
|
Chris@45
|
213 Preferences::BackgroundMode mode =
|
Chris@45
|
214 Preferences::getInstance()->getBackgroundMode();
|
Chris@45
|
215 m_initialDarkBackground = m_viewManager->getGlobalDarkBackground();
|
Chris@45
|
216 if (mode != Preferences::BackgroundFromTheme) {
|
Chris@45
|
217 m_viewManager->setGlobalDarkBackground
|
Chris@45
|
218 (mode == Preferences::DarkBackground);
|
Chris@45
|
219 }
|
Chris@511
|
220 #endif
|
Chris@45
|
221
|
Chris@45
|
222 m_paneStack = new PaneStack(0, m_viewManager);
|
Chris@45
|
223 connect(m_paneStack, SIGNAL(currentPaneChanged(Pane *)),
|
Chris@595
|
224 this, SLOT(currentPaneChanged(Pane *)));
|
Chris@45
|
225 connect(m_paneStack, SIGNAL(currentLayerChanged(Pane *, Layer *)),
|
Chris@595
|
226 this, SLOT(currentLayerChanged(Pane *, Layer *)));
|
Chris@45
|
227 connect(m_paneStack, SIGNAL(rightButtonMenuRequested(Pane *, QPoint)),
|
Chris@45
|
228 this, SLOT(rightButtonMenuRequested(Pane *, QPoint)));
|
Chris@45
|
229 connect(m_paneStack, SIGNAL(contextHelpChanged(const QString &)),
|
Chris@45
|
230 this, SLOT(contextHelpChanged(const QString &)));
|
Chris@45
|
231 connect(m_paneStack, SIGNAL(paneAdded(Pane *)),
|
Chris@45
|
232 this, SLOT(paneAdded(Pane *)));
|
Chris@45
|
233 connect(m_paneStack, SIGNAL(paneHidden(Pane *)),
|
Chris@45
|
234 this, SLOT(paneHidden(Pane *)));
|
Chris@45
|
235 connect(m_paneStack, SIGNAL(paneAboutToBeDeleted(Pane *)),
|
Chris@45
|
236 this, SLOT(paneAboutToBeDeleted(Pane *)));
|
Chris@45
|
237 connect(m_paneStack, SIGNAL(dropAccepted(Pane *, QStringList)),
|
Chris@45
|
238 this, SLOT(paneDropAccepted(Pane *, QStringList)));
|
Chris@45
|
239 connect(m_paneStack, SIGNAL(dropAccepted(Pane *, QString)),
|
Chris@45
|
240 this, SLOT(paneDropAccepted(Pane *, QString)));
|
Chris@55
|
241 connect(m_paneStack, SIGNAL(paneDeleteButtonClicked(Pane *)),
|
Chris@55
|
242 this, SLOT(paneDeleteButtonClicked(Pane *)));
|
Chris@591
|
243
|
Chris@591
|
244 SVDEBUG << "MainWindowBase: Creating play source" << endl;
|
Chris@571
|
245
|
Chris@574
|
246 m_playSource = new AudioCallbackPlaySource
|
Chris@574
|
247 (m_viewManager, QApplication::applicationName());
|
Chris@574
|
248
|
Chris@475
|
249 if (m_soundOptions & WithAudioInput) {
|
Chris@591
|
250 SVDEBUG << "MainWindowBase: Creating record target" << endl;
|
Chris@574
|
251 m_recordTarget = new AudioCallbackRecordTarget
|
Chris@574
|
252 (m_viewManager, QApplication::applicationName());
|
Chris@572
|
253 connect(m_recordTarget,
|
Chris@572
|
254 SIGNAL(recordDurationChanged(sv_frame_t, sv_samplerate_t)),
|
Chris@572
|
255 this,
|
Chris@572
|
256 SLOT(recordDurationChanged(sv_frame_t, sv_samplerate_t)));
|
Chris@475
|
257 }
|
Chris@45
|
258
|
Chris@436
|
259 connect(m_playSource, SIGNAL(sampleRateMismatch(sv_samplerate_t, sv_samplerate_t, bool)),
|
Chris@591
|
260 this, SLOT(sampleRateMismatch(sv_samplerate_t, sv_samplerate_t, bool)));
|
Chris@570
|
261 connect(m_playSource, SIGNAL(channelCountIncreased(int)),
|
Chris@570
|
262 this, SLOT(audioChannelCountIncreased(int)));
|
Chris@45
|
263 connect(m_playSource, SIGNAL(audioOverloadPluginDisabled()),
|
Chris@45
|
264 this, SLOT(audioOverloadPluginDisabled()));
|
Chris@130
|
265 connect(m_playSource, SIGNAL(audioTimeStretchMultiChannelDisabled()),
|
Chris@130
|
266 this, SLOT(audioTimeStretchMultiChannelDisabled()));
|
Chris@45
|
267
|
Chris@574
|
268 connect(m_viewManager, SIGNAL(monitoringLevelsChanged(float, float)),
|
Chris@595
|
269 this, SLOT(monitoringLevelsChanged(float, float)));
|
Chris@45
|
270
|
Chris@435
|
271 connect(m_viewManager, SIGNAL(playbackFrameChanged(sv_frame_t)),
|
Chris@435
|
272 this, SLOT(playbackFrameChanged(sv_frame_t)));
|
Chris@435
|
273
|
Chris@435
|
274 connect(m_viewManager, SIGNAL(globalCentreFrameChanged(sv_frame_t)),
|
Chris@435
|
275 this, SLOT(globalCentreFrameChanged(sv_frame_t)));
|
Chris@435
|
276
|
Chris@435
|
277 connect(m_viewManager, SIGNAL(viewCentreFrameChanged(View *, sv_frame_t)),
|
Chris@435
|
278 this, SLOT(viewCentreFrameChanged(View *, sv_frame_t)));
|
Chris@366
|
279
|
Chris@366
|
280 connect(m_viewManager, SIGNAL(viewZoomLevelChanged(View *, int, bool)),
|
Chris@366
|
281 this, SLOT(viewZoomLevelChanged(View *, int, bool)));
|
Chris@45
|
282
|
Chris@45
|
283 connect(Preferences::getInstance(),
|
Chris@45
|
284 SIGNAL(propertyChanged(PropertyContainer::PropertyName)),
|
Chris@45
|
285 this,
|
Chris@45
|
286 SLOT(preferenceChanged(PropertyContainer::PropertyName)));
|
Chris@45
|
287
|
Chris@591
|
288 SVDEBUG << "MainWindowBase: Creating labeller" << endl;
|
Chris@591
|
289
|
Chris@45
|
290 Labeller::ValueType labellerType = Labeller::ValueFromTwoLevelCounter;
|
Chris@45
|
291 settings.beginGroup("MainWindow");
|
Chris@230
|
292
|
Chris@45
|
293 labellerType = (Labeller::ValueType)
|
Chris@45
|
294 settings.value("labellertype", (int)labellerType).toInt();
|
Chris@45
|
295 int cycle = settings.value("labellercycle", 4).toInt();
|
Chris@230
|
296
|
Chris@45
|
297 settings.endGroup();
|
Chris@45
|
298
|
Chris@45
|
299 m_labeller = new Labeller(labellerType);
|
Chris@45
|
300 m_labeller->setCounterCycleSize(cycle);
|
Chris@113
|
301
|
Chris@475
|
302 if (m_soundOptions & WithMIDIInput) {
|
Chris@591
|
303 SVDEBUG << "MainWindowBase: Creating MIDI input" << endl;
|
Chris@161
|
304 m_midiInput = new MIDIInput(QApplication::applicationName(), this);
|
Chris@161
|
305 }
|
Chris@452
|
306
|
Chris@452
|
307 QTimer::singleShot(1500, this, SIGNAL(hideSplash()));
|
Chris@591
|
308
|
Chris@591
|
309 SVDEBUG << "MainWindowBase: Constructor done" << endl;
|
Chris@45
|
310 }
|
Chris@45
|
311
|
Chris@45
|
312 MainWindowBase::~MainWindowBase()
|
Chris@45
|
313 {
|
Chris@233
|
314 SVDEBUG << "MainWindowBase::~MainWindowBase" << endl;
|
Chris@540
|
315
|
Chris@540
|
316 // We have to delete the breakfastquay::SystemPlaybackTarget or
|
Chris@540
|
317 // breakfastquay::SystemAudioIO object (whichever we have -- it
|
Chris@540
|
318 // depends on whether we handle recording or not) before we delete
|
Chris@540
|
319 // the ApplicationPlaybackSource and ApplicationRecordTarget that
|
Chris@540
|
320 // they refer to.
|
Chris@556
|
321
|
Chris@556
|
322 deleteAudioIO();
|
Chris@540
|
323
|
Chris@540
|
324 // Then delete the Application objects.
|
Chris@45
|
325 delete m_playSource;
|
Chris@475
|
326 delete m_recordTarget;
|
Chris@540
|
327
|
Chris@45
|
328 delete m_viewManager;
|
Chris@45
|
329 delete m_oscQueue;
|
Chris@304
|
330 delete m_oscQueueStarter;
|
Chris@157
|
331 delete m_midiInput;
|
Chris@45
|
332 Profiles::getInstance()->dump();
|
Chris@45
|
333 }
|
Chris@45
|
334
|
Chris@113
|
335 void
|
Chris@452
|
336 MainWindowBase::emitHideSplash()
|
Chris@452
|
337 {
|
Chris@591
|
338 SVDEBUG << "MainWindowBase: Hiding splash screen" << endl;
|
Chris@452
|
339 emit hideSplash(this);
|
Chris@452
|
340 }
|
Chris@452
|
341
|
Chris@452
|
342 void
|
Chris@354
|
343 MainWindowBase::finaliseMenus()
|
Chris@354
|
344 {
|
Chris@591
|
345 SVDEBUG << "MainWindowBase::finaliseMenus called" << endl;
|
Chris@591
|
346
|
Chris@390
|
347 delete m_menuShortcutMapper;
|
Chris@390
|
348 m_menuShortcutMapper = 0;
|
Chris@390
|
349
|
Chris@391
|
350 foreach (QShortcut *sc, m_appShortcuts) {
|
Chris@391
|
351 delete sc;
|
Chris@391
|
352 }
|
Chris@391
|
353 m_appShortcuts.clear();
|
Chris@391
|
354
|
Chris@354
|
355 QMenuBar *mb = menuBar();
|
Chris@394
|
356
|
Chris@396
|
357 // This used to find all children of QMenu type, and call
|
Chris@396
|
358 // finaliseMenu on those. But it seems we are getting hold of some
|
Chris@396
|
359 // menus that way that are not actually active in the menu bar and
|
Chris@396
|
360 // are not returned in their parent menu's actions() list, and if
|
Chris@396
|
361 // we finalise those, we end up with duplicate shortcuts in the
|
Chris@396
|
362 // app shortcut mapper. So we should do this by descending the
|
Chris@396
|
363 // menu tree through only those menus accessible via actions()
|
Chris@396
|
364 // from their parents instead.
|
Chris@396
|
365
|
Chris@394
|
366 QList<QMenu *> menus = mb->findChildren<QMenu *>
|
Chris@394
|
367 (QString(), Qt::FindDirectChildrenOnly);
|
Chris@394
|
368
|
Chris@354
|
369 foreach (QMenu *menu, menus) {
|
Chris@354
|
370 if (menu) finaliseMenu(menu);
|
Chris@354
|
371 }
|
Chris@591
|
372
|
Chris@591
|
373 SVDEBUG << "MainWindowBase::finaliseMenus done" << endl;
|
Chris@354
|
374 }
|
Chris@354
|
375
|
Chris@354
|
376 void
|
Chris@426
|
377 MainWindowBase::finaliseMenu(QMenu *menu)
|
Chris@354
|
378 {
|
Chris@426
|
379 foreach (QAction *a, menu->actions()) {
|
Chris@426
|
380 a->setIconVisibleInMenu(m_iconsVisibleInMenus);
|
Chris@426
|
381 }
|
Chris@426
|
382
|
Chris@354
|
383 #ifdef Q_OS_MAC
|
Chris@354
|
384 // See https://bugreports.qt-project.org/browse/QTBUG-38256 and
|
Chris@354
|
385 // our issue #890 http://code.soundsoftware.ac.uk/issues/890 --
|
Chris@354
|
386 // single-key shortcuts that are associated only with a menu
|
Chris@384
|
387 // action (and not with a toolbar button) do not work with Qt 5.x
|
Chris@384
|
388 // under OS/X.
|
Chris@354
|
389 //
|
Chris@354
|
390 // Apparently Cocoa never handled them as a matter of course, but
|
Chris@354
|
391 // earlier versions of Qt picked them up as widget shortcuts and
|
Chris@354
|
392 // handled them anyway. That behaviour was removed to fix a crash
|
Chris@354
|
393 // when invoking a menu while its window was overridden by a modal
|
Chris@354
|
394 // dialog (https://bugreports.qt-project.org/browse/QTBUG-30657).
|
Chris@354
|
395 //
|
Chris@354
|
396 // This workaround restores the single-key shortcut behaviour by
|
Chris@384
|
397 // searching in menus for single-key shortcuts that are associated
|
Chris@384
|
398 // only with the menu and not with a toolbar button, and
|
Chris@384
|
399 // augmenting them with global application shortcuts that invoke
|
Chris@384
|
400 // the relevant actions, testing whether the actions are enabled
|
Chris@384
|
401 // on invocation.
|
Chris@354
|
402 //
|
Chris@384
|
403 // (Previously this acted on all single-key shortcuts in menus,
|
Chris@384
|
404 // and it removed the shortcut from the action when it created
|
Chris@384
|
405 // each new global one, in order to avoid an "ambiguous shortcut"
|
Chris@384
|
406 // error in the case where the action was also associated with a
|
Chris@384
|
407 // toolbar button. But that has the unwelcome side-effect of
|
Chris@384
|
408 // removing the shortcut hint from the menu entry. So now we leave
|
Chris@384
|
409 // the shortcut in the menu action as well as creating a global
|
Chris@384
|
410 // one, and we only act on shortcuts that have no toolbar button,
|
Chris@384
|
411 // i.e. that will not otherwise work. The downside is that if this
|
Chris@384
|
412 // bug is fixed in a future Qt release, we will start getting
|
Chris@384
|
413 // "ambiguous shortcut" errors from the menu entry actions and
|
Chris@384
|
414 // will need to update the code.)
|
Chris@354
|
415
|
Chris@443
|
416 // Update: The bug was fixed in Qt 5.4 for shortcuts with no
|
Chris@443
|
417 // modifier, and I believe it is fixed in Qt 5.5 for shortcuts
|
Chris@443
|
418 // with Shift modifiers. The below reflects that
|
Chris@443
|
419
|
Chris@443
|
420 #if (QT_VERSION < QT_VERSION_CHECK(5, 5, 0))
|
Chris@443
|
421
|
Chris@390
|
422 if (!m_menuShortcutMapper) {
|
Chris@390
|
423 m_menuShortcutMapper = new QSignalMapper(this);
|
Chris@392
|
424 connect(m_menuShortcutMapper, SIGNAL(mapped(QObject *)),
|
Chris@392
|
425 this, SLOT(menuActionMapperInvoked(QObject *)));
|
Chris@390
|
426 }
|
Chris@390
|
427
|
Chris@354
|
428 foreach (QAction *a, menu->actions()) {
|
Chris@394
|
429
|
Chris@394
|
430 if (a->isSeparator()) {
|
Chris@394
|
431 continue;
|
Chris@394
|
432 } else if (a->menu()) {
|
Chris@394
|
433 finaliseMenu(a->menu());
|
Chris@394
|
434 } else {
|
Chris@394
|
435
|
Chris@394
|
436 QWidgetList ww = a->associatedWidgets();
|
Chris@394
|
437 bool hasButton = false;
|
Chris@394
|
438 foreach (QWidget *w, ww) {
|
Chris@394
|
439 if (qobject_cast<QAbstractButton *>(w)) {
|
Chris@394
|
440 hasButton = true;
|
Chris@394
|
441 break;
|
Chris@394
|
442 }
|
Chris@394
|
443 }
|
Chris@394
|
444 if (hasButton) continue;
|
Chris@394
|
445 QKeySequence sc = a->shortcut();
|
Chris@399
|
446
|
Chris@399
|
447 // Note that the set of "single-key shortcuts" that aren't
|
Chris@399
|
448 // working and that we need to handle here includes those
|
Chris@399
|
449 // with the Shift modifier mask as well as those with no
|
Chris@399
|
450 // modifier at all
|
Chris@443
|
451 #if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
|
Chris@443
|
452 // Nothing needed
|
Chris@443
|
453 if (false) {
|
Chris@443
|
454 #elif (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
|
Chris@443
|
455 if (sc.count() == 1 &&
|
Chris@443
|
456 (sc[0] & Qt::KeyboardModifierMask) == Qt::ShiftModifier) {
|
Chris@443
|
457 #else
|
Chris@399
|
458 if (sc.count() == 1 &&
|
Chris@399
|
459 ((sc[0] & Qt::KeyboardModifierMask) == Qt::NoModifier ||
|
Chris@399
|
460 (sc[0] & Qt::KeyboardModifierMask) == Qt::ShiftModifier)) {
|
Chris@443
|
461 #endif
|
Chris@394
|
462 QShortcut *newSc = new QShortcut(sc, a->parentWidget());
|
Chris@394
|
463 QObject::connect(newSc, SIGNAL(activated()),
|
Chris@394
|
464 m_menuShortcutMapper, SLOT(map()));
|
Chris@394
|
465 m_menuShortcutMapper->setMapping(newSc, a);
|
Chris@394
|
466 m_appShortcuts.push_back(newSc);
|
Chris@384
|
467 }
|
Chris@384
|
468 }
|
Chris@354
|
469 }
|
Chris@354
|
470 #endif
|
Chris@443
|
471 #endif
|
Chris@354
|
472 }
|
Chris@354
|
473
|
Chris@354
|
474 void
|
Chris@354
|
475 MainWindowBase::menuActionMapperInvoked(QObject *o)
|
Chris@354
|
476 {
|
Chris@354
|
477 QAction *a = qobject_cast<QAction *>(o);
|
Chris@354
|
478 if (a && a->isEnabled()) {
|
Chris@354
|
479 a->trigger();
|
Chris@354
|
480 }
|
Chris@354
|
481 }
|
Chris@354
|
482
|
Chris@354
|
483 void
|
Chris@168
|
484 MainWindowBase::resizeConstrained(QSize size)
|
Chris@168
|
485 {
|
Chris@168
|
486 QDesktopWidget *desktop = QApplication::desktop();
|
Chris@168
|
487 QRect available = desktop->availableGeometry();
|
Chris@168
|
488 QSize actual(std::min(size.width(), available.width()),
|
Chris@168
|
489 std::min(size.height(), available.height()));
|
Chris@168
|
490 resize(actual);
|
Chris@168
|
491 }
|
Chris@168
|
492
|
Chris@168
|
493 void
|
Chris@304
|
494 MainWindowBase::startOSCQueue()
|
Chris@304
|
495 {
|
Chris@304
|
496 m_oscQueueStarter = new OSCQueueStarter(this);
|
Chris@304
|
497 connect(m_oscQueueStarter, SIGNAL(finished()), this, SLOT(oscReady()));
|
Chris@304
|
498 m_oscQueueStarter->start();
|
Chris@304
|
499 }
|
Chris@304
|
500
|
Chris@304
|
501 void
|
Chris@113
|
502 MainWindowBase::oscReady()
|
Chris@113
|
503 {
|
Chris@113
|
504 if (m_oscQueue && m_oscQueue->isOK()) {
|
Chris@113
|
505 connect(m_oscQueue, SIGNAL(messagesAvailable()), this, SLOT(pollOSC()));
|
Chris@113
|
506 QTimer *oscTimer = new QTimer(this);
|
Chris@113
|
507 connect(oscTimer, SIGNAL(timeout()), this, SLOT(pollOSC()));
|
Chris@113
|
508 oscTimer->start(1000);
|
Chris@571
|
509 SVCERR << "Finished setting up OSC interface" << endl;
|
Chris@113
|
510 }
|
Chris@113
|
511 }
|
Chris@113
|
512
|
Chris@45
|
513 QString
|
Chris@45
|
514 MainWindowBase::getOpenFileName(FileFinder::FileType type)
|
Chris@45
|
515 {
|
Chris@45
|
516 FileFinder *ff = FileFinder::getInstance();
|
Chris@358
|
517
|
Chris@358
|
518 if (type == FileFinder::AnyFile) {
|
Chris@45
|
519 if (getMainModel() != 0 &&
|
Chris@45
|
520 m_paneStack != 0 &&
|
Chris@45
|
521 m_paneStack->getCurrentPane() != 0) { // can import a layer
|
Chris@45
|
522 return ff->getOpenFileName(FileFinder::AnyFile, m_sessionFile);
|
Chris@45
|
523 } else {
|
Chris@45
|
524 return ff->getOpenFileName(FileFinder::SessionOrAudioFile,
|
Chris@45
|
525 m_sessionFile);
|
Chris@45
|
526 }
|
Chris@358
|
527 }
|
Chris@358
|
528
|
Chris@358
|
529 QString lastPath = m_sessionFile;
|
Chris@358
|
530
|
Chris@358
|
531 if (type == FileFinder::AudioFile) {
|
Chris@358
|
532 lastPath = m_audioFile;
|
Chris@45
|
533 }
|
Chris@358
|
534
|
Chris@358
|
535 return ff->getOpenFileName(type, lastPath);
|
Chris@45
|
536 }
|
Chris@45
|
537
|
Chris@45
|
538 QString
|
Chris@45
|
539 MainWindowBase::getSaveFileName(FileFinder::FileType type)
|
Chris@45
|
540 {
|
Chris@358
|
541 QString lastPath = m_sessionFile;
|
Chris@358
|
542
|
Chris@358
|
543 if (type == FileFinder::AudioFile) {
|
Chris@358
|
544 lastPath = m_audioFile;
|
Chris@358
|
545 }
|
Chris@358
|
546
|
Chris@45
|
547 FileFinder *ff = FileFinder::getInstance();
|
Chris@358
|
548 return ff->getSaveFileName(type, lastPath);
|
Chris@45
|
549 }
|
Chris@45
|
550
|
Chris@45
|
551 void
|
Chris@45
|
552 MainWindowBase::registerLastOpenedFilePath(FileFinder::FileType type, QString path)
|
Chris@45
|
553 {
|
Chris@45
|
554 FileFinder *ff = FileFinder::getInstance();
|
Chris@45
|
555 ff->registerLastOpenedFilePath(type, path);
|
Chris@45
|
556 }
|
Chris@45
|
557
|
Chris@222
|
558 QString
|
Chris@222
|
559 MainWindowBase::getDefaultSessionTemplate() const
|
Chris@222
|
560 {
|
Chris@231
|
561 QSettings settings;
|
Chris@231
|
562 settings.beginGroup("MainWindow");
|
Chris@231
|
563 QString templateName = settings.value("sessiontemplate", "").toString();
|
Chris@231
|
564 if (templateName == "") templateName = "default";
|
Chris@231
|
565 return templateName;
|
Chris@222
|
566 }
|
Chris@222
|
567
|
Chris@222
|
568 void
|
Chris@251
|
569 MainWindowBase::setDefaultSessionTemplate(QString n)
|
Chris@251
|
570 {
|
Chris@251
|
571 QSettings settings;
|
Chris@251
|
572 settings.beginGroup("MainWindow");
|
Chris@251
|
573 settings.setValue("sessiontemplate", n);
|
Chris@251
|
574 }
|
Chris@251
|
575
|
Chris@251
|
576 void
|
Chris@45
|
577 MainWindowBase::updateMenuStates()
|
Chris@45
|
578 {
|
Chris@45
|
579 Pane *currentPane = 0;
|
Chris@45
|
580 Layer *currentLayer = 0;
|
Chris@45
|
581
|
Chris@45
|
582 if (m_paneStack) currentPane = m_paneStack->getCurrentPane();
|
Chris@45
|
583 if (currentPane) currentLayer = currentPane->getSelectedLayer();
|
Chris@45
|
584
|
Chris@73
|
585 bool havePrevPane = false, haveNextPane = false;
|
Chris@73
|
586 bool havePrevLayer = false, haveNextLayer = false;
|
Chris@73
|
587
|
Chris@73
|
588 if (currentPane) {
|
Chris@73
|
589 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@73
|
590 if (m_paneStack->getPane(i) == currentPane) {
|
Chris@73
|
591 if (i > 0) havePrevPane = true;
|
Chris@73
|
592 if (i < m_paneStack->getPaneCount()-1) haveNextPane = true;
|
Chris@73
|
593 break;
|
Chris@73
|
594 }
|
Chris@73
|
595 }
|
Chris@403
|
596 // the prev/next layer commands actually include the pane
|
Chris@403
|
597 // itself as one of the selectables -- so we always have a
|
Chris@403
|
598 // prev and next layer, as long as we have a pane with at
|
Chris@403
|
599 // least one layer in it
|
Chris@403
|
600 if (currentPane->getLayerCount() > 0) {
|
Chris@403
|
601 havePrevLayer = true;
|
Chris@403
|
602 haveNextLayer = true;
|
Chris@73
|
603 }
|
Chris@73
|
604 }
|
Chris@73
|
605
|
Chris@45
|
606 bool haveCurrentPane =
|
Chris@45
|
607 (currentPane != 0);
|
Chris@45
|
608 bool haveCurrentLayer =
|
Chris@45
|
609 (haveCurrentPane &&
|
Chris@45
|
610 (currentLayer != 0));
|
Chris@45
|
611 bool haveMainModel =
|
Chris@595
|
612 (getMainModel() != 0);
|
Chris@45
|
613 bool havePlayTarget =
|
Chris@595
|
614 (m_playTarget != 0 || m_audioIO != 0);
|
Chris@45
|
615 bool haveSelection =
|
Chris@595
|
616 (m_viewManager &&
|
Chris@595
|
617 !m_viewManager->getSelections().empty());
|
Chris@45
|
618 bool haveCurrentEditableLayer =
|
Chris@595
|
619 (haveCurrentLayer &&
|
Chris@595
|
620 currentLayer->isLayerEditable());
|
Chris@45
|
621 bool haveCurrentTimeInstantsLayer =
|
Chris@595
|
622 (haveCurrentLayer &&
|
Chris@595
|
623 dynamic_cast<TimeInstantLayer *>(currentLayer));
|
Chris@184
|
624 bool haveCurrentDurationLayer =
|
Chris@595
|
625 (haveCurrentLayer &&
|
Chris@595
|
626 (dynamic_cast<NoteLayer *>(currentLayer) ||
|
Chris@595
|
627 dynamic_cast<FlexiNoteLayer *>(currentLayer) ||
|
Chris@184
|
628 dynamic_cast<RegionLayer *>(currentLayer)));
|
Chris@45
|
629 bool haveCurrentColour3DPlot =
|
Chris@45
|
630 (haveCurrentLayer &&
|
Chris@45
|
631 dynamic_cast<Colour3DPlotLayer *>(currentLayer));
|
Chris@45
|
632 bool haveClipboardContents =
|
Chris@45
|
633 (m_viewManager &&
|
Chris@45
|
634 !m_viewManager->getClipboard().empty());
|
Chris@146
|
635 bool haveTabularLayer =
|
Chris@146
|
636 (haveCurrentLayer &&
|
Chris@146
|
637 dynamic_cast<TabularModel *>(currentLayer->getModel()));
|
Chris@45
|
638
|
Chris@45
|
639 emit canAddPane(haveMainModel);
|
Chris@45
|
640 emit canDeleteCurrentPane(haveCurrentPane);
|
Chris@45
|
641 emit canZoom(haveMainModel && haveCurrentPane);
|
Chris@45
|
642 emit canScroll(haveMainModel && haveCurrentPane);
|
Chris@45
|
643 emit canAddLayer(haveMainModel && haveCurrentPane);
|
Chris@45
|
644 emit canImportMoreAudio(haveMainModel);
|
Chris@259
|
645 emit canReplaceMainAudio(haveMainModel);
|
Chris@45
|
646 emit canImportLayer(haveMainModel && haveCurrentPane);
|
Chris@45
|
647 emit canExportAudio(haveMainModel);
|
Chris@289
|
648 emit canChangeSessionTemplate(haveMainModel);
|
Chris@45
|
649 emit canExportLayer(haveMainModel &&
|
Chris@45
|
650 (haveCurrentEditableLayer || haveCurrentColour3DPlot));
|
Chris@45
|
651 emit canExportImage(haveMainModel && haveCurrentPane);
|
Chris@45
|
652 emit canDeleteCurrentLayer(haveCurrentLayer);
|
Chris@45
|
653 emit canRenameLayer(haveCurrentLayer);
|
Chris@45
|
654 emit canEditLayer(haveCurrentEditableLayer);
|
Chris@146
|
655 emit canEditLayerTabular(haveCurrentEditableLayer || haveTabularLayer);
|
Chris@45
|
656 emit canMeasureLayer(haveCurrentLayer);
|
Chris@45
|
657 emit canSelect(haveMainModel && haveCurrentPane);
|
Chris@188
|
658 emit canPlay(haveMainModel && havePlayTarget);
|
Chris@453
|
659 emit canFfwd(haveMainModel);
|
Chris@453
|
660 emit canRewind(haveMainModel);
|
Chris@87
|
661 emit canPaste(haveClipboardContents);
|
Chris@45
|
662 emit canInsertInstant(haveCurrentPane);
|
Chris@45
|
663 emit canInsertInstantsAtBoundaries(haveCurrentPane && haveSelection);
|
Chris@184
|
664 emit canInsertItemAtSelection(haveCurrentPane && haveSelection && haveCurrentDurationLayer);
|
Chris@45
|
665 emit canRenumberInstants(haveCurrentTimeInstantsLayer && haveSelection);
|
Chris@537
|
666 emit canSubdivideInstants(haveCurrentTimeInstantsLayer && haveSelection);
|
Chris@538
|
667 emit canWinnowInstants(haveCurrentTimeInstantsLayer && haveSelection);
|
Chris@45
|
668 emit canPlaySelection(haveMainModel && havePlayTarget && haveSelection);
|
Chris@45
|
669 emit canClearSelection(haveSelection);
|
Chris@45
|
670 emit canEditSelection(haveSelection && haveCurrentEditableLayer);
|
Chris@45
|
671 emit canSave(m_sessionFile != "" && m_documentModified);
|
Chris@601
|
672 emit canSaveAs(haveMainModel); // possibly used only in Tony, not SV
|
Chris@73
|
673 emit canSelectPreviousPane(havePrevPane);
|
Chris@73
|
674 emit canSelectNextPane(haveNextPane);
|
Chris@73
|
675 emit canSelectPreviousLayer(havePrevLayer);
|
Chris@73
|
676 emit canSelectNextLayer(haveNextLayer);
|
Chris@586
|
677
|
Chris@586
|
678 // This is quite subtle -- whereas we can play back only if a
|
Chris@586
|
679 // system play target or I/O exists, we can record even if no
|
Chris@586
|
680 // record source (i.e. audioIO) exists because we can record into
|
Chris@586
|
681 // an empty session before the audio device has been
|
Chris@586
|
682 // opened. However, if there is no record *target* then recording
|
Chris@586
|
683 // was actively disabled (flag not set in m_soundOptions). And if
|
Chris@586
|
684 // we have a play target instead of an audioIO, then we must have
|
Chris@586
|
685 // tried to open the device but failed to find any capture source.
|
Chris@586
|
686 bool recordDisabled = (m_recordTarget == nullptr);
|
Chris@586
|
687 bool recordDeviceFailed = (m_playTarget != nullptr && m_audioIO == nullptr);
|
Chris@586
|
688 emit canRecord(!recordDisabled && !recordDeviceFailed);
|
Chris@45
|
689 }
|
Chris@45
|
690
|
Chris@45
|
691 void
|
Chris@45
|
692 MainWindowBase::documentModified()
|
Chris@45
|
693 {
|
Chris@233
|
694 // SVDEBUG << "MainWindowBase::documentModified" << endl;
|
Chris@45
|
695
|
Chris@45
|
696 if (!m_documentModified) {
|
Chris@45
|
697 //!!! this in subclass implementation?
|
Chris@595
|
698 setWindowTitle(tr("%1 (modified)").arg(windowTitle()));
|
Chris@45
|
699 }
|
Chris@45
|
700
|
Chris@45
|
701 m_documentModified = true;
|
Chris@45
|
702 updateMenuStates();
|
Chris@45
|
703 }
|
Chris@45
|
704
|
Chris@45
|
705 void
|
Chris@45
|
706 MainWindowBase::documentRestored()
|
Chris@45
|
707 {
|
Chris@233
|
708 // SVDEBUG << "MainWindowBase::documentRestored" << endl;
|
Chris@45
|
709
|
Chris@45
|
710 if (m_documentModified) {
|
Chris@45
|
711 //!!! this in subclass implementation?
|
Chris@595
|
712 QString wt(windowTitle());
|
Chris@595
|
713 wt.replace(tr(" (modified)"), "");
|
Chris@595
|
714 setWindowTitle(wt);
|
Chris@45
|
715 }
|
Chris@45
|
716
|
Chris@45
|
717 m_documentModified = false;
|
Chris@45
|
718 updateMenuStates();
|
Chris@45
|
719 }
|
Chris@45
|
720
|
Chris@45
|
721 void
|
Chris@45
|
722 MainWindowBase::playLoopToggled()
|
Chris@45
|
723 {
|
Chris@45
|
724 QAction *action = dynamic_cast<QAction *>(sender());
|
Chris@45
|
725
|
Chris@45
|
726 if (action) {
|
Chris@595
|
727 m_viewManager->setPlayLoopMode(action->isChecked());
|
Chris@45
|
728 } else {
|
Chris@595
|
729 m_viewManager->setPlayLoopMode(!m_viewManager->getPlayLoopMode());
|
Chris@45
|
730 }
|
Chris@45
|
731 }
|
Chris@45
|
732
|
Chris@45
|
733 void
|
Chris@45
|
734 MainWindowBase::playSelectionToggled()
|
Chris@45
|
735 {
|
Chris@45
|
736 QAction *action = dynamic_cast<QAction *>(sender());
|
Chris@45
|
737
|
Chris@45
|
738 if (action) {
|
Chris@595
|
739 m_viewManager->setPlaySelectionMode(action->isChecked());
|
Chris@45
|
740 } else {
|
Chris@595
|
741 m_viewManager->setPlaySelectionMode(!m_viewManager->getPlaySelectionMode());
|
Chris@45
|
742 }
|
Chris@45
|
743 }
|
Chris@45
|
744
|
Chris@45
|
745 void
|
Chris@45
|
746 MainWindowBase::playSoloToggled()
|
Chris@45
|
747 {
|
Chris@45
|
748 QAction *action = dynamic_cast<QAction *>(sender());
|
Chris@45
|
749
|
Chris@45
|
750 if (action) {
|
Chris@595
|
751 m_viewManager->setPlaySoloMode(action->isChecked());
|
Chris@45
|
752 } else {
|
Chris@595
|
753 m_viewManager->setPlaySoloMode(!m_viewManager->getPlaySoloMode());
|
Chris@45
|
754 }
|
Chris@45
|
755
|
Chris@45
|
756 if (m_viewManager->getPlaySoloMode()) {
|
Chris@45
|
757 currentPaneChanged(m_paneStack->getCurrentPane());
|
Chris@45
|
758 } else {
|
Chris@45
|
759 m_viewManager->setPlaybackModel(0);
|
Chris@45
|
760 if (m_playSource) {
|
Chris@45
|
761 m_playSource->clearSoloModelSet();
|
Chris@45
|
762 }
|
Chris@45
|
763 }
|
Chris@45
|
764 }
|
Chris@45
|
765
|
Chris@45
|
766 void
|
Chris@45
|
767 MainWindowBase::currentPaneChanged(Pane *p)
|
Chris@45
|
768 {
|
Chris@45
|
769 updateMenuStates();
|
Chris@45
|
770 updateVisibleRangeDisplay(p);
|
Chris@45
|
771
|
Chris@45
|
772 if (!p) return;
|
Chris@45
|
773
|
Chris@45
|
774 if (!(m_viewManager &&
|
Chris@45
|
775 m_playSource &&
|
Chris@45
|
776 m_viewManager->getPlaySoloMode())) {
|
Chris@45
|
777 if (m_viewManager) m_viewManager->setPlaybackModel(0);
|
Chris@45
|
778 return;
|
Chris@45
|
779 }
|
Chris@45
|
780
|
Chris@45
|
781 Model *prevPlaybackModel = m_viewManager->getPlaybackModel();
|
Chris@60
|
782
|
Chris@93
|
783 // What we want here is not the currently playing frame (unless we
|
Chris@93
|
784 // are about to clear out the audio playback buffers -- which may
|
Chris@93
|
785 // or may not be possible, depending on the audio driver). What
|
Chris@93
|
786 // we want is the frame that was last committed to the soundcard
|
Chris@93
|
787 // buffers, as the audio driver will continue playing up to that
|
Chris@93
|
788 // frame before switching to whichever one we decide we want to
|
Chris@93
|
789 // switch to, regardless of our efforts.
|
Chris@93
|
790
|
Chris@435
|
791 sv_frame_t frame = m_playSource->getCurrentBufferedFrame();
|
Chris@93
|
792
|
Chris@388
|
793 cerr << "currentPaneChanged: current frame (in ref model) = " << frame << endl;
|
Chris@45
|
794
|
Chris@45
|
795 View::ModelSet soloModels = p->getModels();
|
Chris@45
|
796
|
Chris@57
|
797 View::ModelSet sources;
|
Chris@57
|
798 for (View::ModelSet::iterator mi = soloModels.begin();
|
Chris@57
|
799 mi != soloModels.end(); ++mi) {
|
Chris@190
|
800 // If a model in this pane is derived from something else,
|
Chris@190
|
801 // then we want to play that model as well -- if the model
|
Chris@190
|
802 // that's derived from it is not something that is itself
|
Chris@190
|
803 // individually playable (e.g. a waveform)
|
Chris@190
|
804 if (*mi &&
|
Chris@190
|
805 !dynamic_cast<RangeSummarisableTimeValueModel *>(*mi) &&
|
Chris@190
|
806 (*mi)->getSourceModel()) {
|
Chris@57
|
807 sources.insert((*mi)->getSourceModel());
|
Chris@57
|
808 }
|
Chris@57
|
809 }
|
Chris@57
|
810 for (View::ModelSet::iterator mi = sources.begin();
|
Chris@57
|
811 mi != sources.end(); ++mi) {
|
Chris@57
|
812 soloModels.insert(*mi);
|
Chris@57
|
813 }
|
Chris@57
|
814
|
Chris@60
|
815 //!!! Need an "atomic" way of telling the play source that the
|
Chris@60
|
816 //playback model has changed, and changing it on ViewManager --
|
Chris@60
|
817 //the play source should be making the setPlaybackModel call to
|
Chris@60
|
818 //ViewManager
|
Chris@60
|
819
|
Chris@45
|
820 for (View::ModelSet::iterator mi = soloModels.begin();
|
Chris@45
|
821 mi != soloModels.end(); ++mi) {
|
Chris@45
|
822 if (dynamic_cast<RangeSummarisableTimeValueModel *>(*mi)) {
|
Chris@45
|
823 m_viewManager->setPlaybackModel(*mi);
|
Chris@45
|
824 }
|
Chris@45
|
825 }
|
Chris@45
|
826
|
Chris@45
|
827 RangeSummarisableTimeValueModel *a =
|
Chris@45
|
828 dynamic_cast<RangeSummarisableTimeValueModel *>(prevPlaybackModel);
|
Chris@45
|
829 RangeSummarisableTimeValueModel *b =
|
Chris@45
|
830 dynamic_cast<RangeSummarisableTimeValueModel *>(m_viewManager->
|
Chris@45
|
831 getPlaybackModel());
|
Chris@45
|
832
|
Chris@45
|
833 m_playSource->setSoloModelSet(soloModels);
|
Chris@45
|
834
|
Chris@45
|
835 if (a && b && (a != b)) {
|
Chris@60
|
836 if (m_playSource->isPlaying()) m_playSource->play(frame);
|
Chris@45
|
837 }
|
Chris@45
|
838 }
|
Chris@45
|
839
|
Chris@45
|
840 void
|
Chris@45
|
841 MainWindowBase::currentLayerChanged(Pane *p, Layer *)
|
Chris@45
|
842 {
|
Chris@45
|
843 updateMenuStates();
|
Chris@45
|
844 updateVisibleRangeDisplay(p);
|
Chris@45
|
845 }
|
Chris@45
|
846
|
Chris@597
|
847 sv_frame_t
|
Chris@597
|
848 MainWindowBase::getModelsStartFrame() const
|
Chris@597
|
849 {
|
Chris@597
|
850 sv_frame_t startFrame = 0;
|
Chris@597
|
851 if (!m_paneStack) return startFrame;
|
Chris@597
|
852 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@597
|
853 sv_frame_t thisStart = m_paneStack->getPane(i)->getModelsStartFrame();
|
Chris@597
|
854 if (i == 0 || thisStart < startFrame) {
|
Chris@597
|
855 startFrame = thisStart;
|
Chris@597
|
856 }
|
Chris@597
|
857 }
|
Chris@597
|
858 return startFrame;
|
Chris@597
|
859 }
|
Chris@597
|
860
|
Chris@597
|
861 sv_frame_t
|
Chris@597
|
862 MainWindowBase::getModelsEndFrame() const
|
Chris@597
|
863 {
|
Chris@597
|
864 sv_frame_t endFrame = 0;
|
Chris@597
|
865 if (!m_paneStack) return endFrame;
|
Chris@597
|
866 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@597
|
867 sv_frame_t thisEnd = m_paneStack->getPane(i)->getModelsEndFrame();
|
Chris@597
|
868 if (i == 0 || thisEnd > endFrame) {
|
Chris@597
|
869 endFrame = thisEnd;
|
Chris@597
|
870 }
|
Chris@597
|
871 }
|
Chris@597
|
872 return endFrame;
|
Chris@597
|
873 }
|
Chris@597
|
874
|
Chris@45
|
875 void
|
Chris@45
|
876 MainWindowBase::selectAll()
|
Chris@45
|
877 {
|
Chris@45
|
878 if (!getMainModel()) return;
|
Chris@597
|
879 m_viewManager->setSelection(Selection(getModelsStartFrame(),
|
Chris@597
|
880 getModelsEndFrame()));
|
Chris@45
|
881 }
|
Chris@45
|
882
|
Chris@45
|
883 void
|
Chris@45
|
884 MainWindowBase::selectToStart()
|
Chris@45
|
885 {
|
Chris@45
|
886 if (!getMainModel()) return;
|
Chris@45
|
887 m_viewManager->setSelection(Selection(getMainModel()->getStartFrame(),
|
Chris@595
|
888 m_viewManager->getGlobalCentreFrame()));
|
Chris@45
|
889 }
|
Chris@45
|
890
|
Chris@45
|
891 void
|
Chris@45
|
892 MainWindowBase::selectToEnd()
|
Chris@45
|
893 {
|
Chris@45
|
894 if (!getMainModel()) return;
|
Chris@45
|
895 m_viewManager->setSelection(Selection(m_viewManager->getGlobalCentreFrame(),
|
Chris@595
|
896 getMainModel()->getEndFrame()));
|
Chris@45
|
897 }
|
Chris@45
|
898
|
Chris@45
|
899 void
|
Chris@45
|
900 MainWindowBase::selectVisible()
|
Chris@45
|
901 {
|
Chris@45
|
902 Model *model = getMainModel();
|
Chris@45
|
903 if (!model) return;
|
Chris@45
|
904
|
Chris@45
|
905 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@45
|
906 if (!currentPane) return;
|
Chris@45
|
907
|
Chris@435
|
908 sv_frame_t startFrame, endFrame;
|
Chris@45
|
909
|
Chris@45
|
910 if (currentPane->getStartFrame() < 0) startFrame = 0;
|
Chris@45
|
911 else startFrame = currentPane->getStartFrame();
|
Chris@45
|
912
|
Chris@45
|
913 if (currentPane->getEndFrame() > model->getEndFrame()) endFrame = model->getEndFrame();
|
Chris@45
|
914 else endFrame = currentPane->getEndFrame();
|
Chris@45
|
915
|
Chris@45
|
916 m_viewManager->setSelection(Selection(startFrame, endFrame));
|
Chris@45
|
917 }
|
Chris@45
|
918
|
Chris@45
|
919 void
|
Chris@45
|
920 MainWindowBase::clearSelection()
|
Chris@45
|
921 {
|
Chris@45
|
922 m_viewManager->clearSelections();
|
Chris@45
|
923 }
|
Chris@45
|
924
|
Chris@45
|
925 void
|
Chris@45
|
926 MainWindowBase::cut()
|
Chris@45
|
927 {
|
Chris@45
|
928 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@45
|
929 if (!currentPane) return;
|
Chris@45
|
930
|
Chris@45
|
931 Layer *layer = currentPane->getSelectedLayer();
|
Chris@45
|
932 if (!layer) return;
|
Chris@45
|
933
|
Chris@45
|
934 Clipboard &clipboard = m_viewManager->getClipboard();
|
Chris@45
|
935 clipboard.clear();
|
Chris@45
|
936
|
Chris@45
|
937 MultiSelection::SelectionList selections = m_viewManager->getSelections();
|
Chris@45
|
938
|
Chris@45
|
939 CommandHistory::getInstance()->startCompoundOperation(tr("Cut"), true);
|
Chris@45
|
940
|
Chris@45
|
941 for (MultiSelection::SelectionList::iterator i = selections.begin();
|
Chris@45
|
942 i != selections.end(); ++i) {
|
Chris@86
|
943 layer->copy(currentPane, *i, clipboard);
|
Chris@45
|
944 layer->deleteSelection(*i);
|
Chris@45
|
945 }
|
Chris@45
|
946
|
Chris@45
|
947 CommandHistory::getInstance()->endCompoundOperation();
|
Chris@45
|
948 }
|
Chris@45
|
949
|
Chris@45
|
950 void
|
Chris@45
|
951 MainWindowBase::copy()
|
Chris@45
|
952 {
|
Chris@45
|
953 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@45
|
954 if (!currentPane) return;
|
Chris@45
|
955
|
Chris@45
|
956 Layer *layer = currentPane->getSelectedLayer();
|
Chris@45
|
957 if (!layer) return;
|
Chris@45
|
958
|
Chris@45
|
959 Clipboard &clipboard = m_viewManager->getClipboard();
|
Chris@45
|
960 clipboard.clear();
|
Chris@45
|
961
|
Chris@45
|
962 MultiSelection::SelectionList selections = m_viewManager->getSelections();
|
Chris@45
|
963
|
Chris@45
|
964 for (MultiSelection::SelectionList::iterator i = selections.begin();
|
Chris@45
|
965 i != selections.end(); ++i) {
|
Chris@86
|
966 layer->copy(currentPane, *i, clipboard);
|
Chris@45
|
967 }
|
Chris@45
|
968 }
|
Chris@45
|
969
|
Chris@45
|
970 void
|
Chris@45
|
971 MainWindowBase::paste()
|
Chris@45
|
972 {
|
Chris@215
|
973 pasteRelative(0);
|
Chris@215
|
974 }
|
Chris@215
|
975
|
Chris@215
|
976 void
|
Chris@215
|
977 MainWindowBase::pasteAtPlaybackPosition()
|
Chris@215
|
978 {
|
Chris@435
|
979 sv_frame_t pos = getFrame();
|
Chris@215
|
980 Clipboard &clipboard = m_viewManager->getClipboard();
|
Chris@215
|
981 if (!clipboard.empty()) {
|
Chris@435
|
982 sv_frame_t firstEventFrame = clipboard.getPoints()[0].getFrame();
|
Chris@435
|
983 sv_frame_t offset = 0;
|
Chris@215
|
984 if (firstEventFrame < 0) {
|
Chris@366
|
985 offset = pos - firstEventFrame;
|
Chris@354
|
986 } else if (firstEventFrame < pos) {
|
Chris@366
|
987 offset = pos - firstEventFrame;
|
Chris@215
|
988 } else {
|
Chris@366
|
989 offset = -(firstEventFrame - pos);
|
Chris@215
|
990 }
|
Chris@215
|
991 pasteRelative(offset);
|
Chris@215
|
992 }
|
Chris@215
|
993 }
|
Chris@215
|
994
|
Chris@215
|
995 void
|
Chris@435
|
996 MainWindowBase::pasteRelative(sv_frame_t offset)
|
Chris@215
|
997 {
|
Chris@45
|
998 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@45
|
999 if (!currentPane) return;
|
Chris@45
|
1000
|
Chris@45
|
1001 Layer *layer = currentPane->getSelectedLayer();
|
Chris@45
|
1002
|
Chris@45
|
1003 Clipboard &clipboard = m_viewManager->getClipboard();
|
Chris@87
|
1004
|
Chris@98
|
1005 bool inCompound = false;
|
Chris@87
|
1006
|
Chris@87
|
1007 if (!layer || !layer->isLayerEditable()) {
|
Chris@87
|
1008
|
Chris@87
|
1009 CommandHistory::getInstance()->startCompoundOperation
|
Chris@87
|
1010 (tr("Paste"), true);
|
Chris@87
|
1011
|
Chris@87
|
1012 // no suitable current layer: create one of the most
|
Chris@87
|
1013 // appropriate sort
|
Chris@87
|
1014 LayerFactory::LayerType type =
|
Chris@87
|
1015 LayerFactory::getInstance()->getLayerTypeForClipboardContents(clipboard);
|
Chris@87
|
1016 layer = m_document->createEmptyLayer(type);
|
Chris@87
|
1017
|
Chris@87
|
1018 if (!layer) {
|
Chris@87
|
1019 CommandHistory::getInstance()->endCompoundOperation();
|
Chris@87
|
1020 return;
|
Chris@45
|
1021 }
|
Chris@87
|
1022
|
Chris@87
|
1023 m_document->addLayerToView(currentPane, layer);
|
Chris@87
|
1024 m_paneStack->setCurrentLayer(currentPane, layer);
|
Chris@87
|
1025
|
Chris@87
|
1026 inCompound = true;
|
Chris@45
|
1027 }
|
Chris@45
|
1028
|
Chris@215
|
1029 layer->paste(currentPane, clipboard, offset, true);
|
Chris@45
|
1030
|
Chris@87
|
1031 if (inCompound) CommandHistory::getInstance()->endCompoundOperation();
|
Chris@45
|
1032 }
|
Chris@45
|
1033
|
Chris@45
|
1034 void
|
Chris@45
|
1035 MainWindowBase::deleteSelected()
|
Chris@45
|
1036 {
|
Chris@45
|
1037 if (m_paneStack->getCurrentPane() &&
|
Chris@595
|
1038 m_paneStack->getCurrentPane()->getSelectedLayer()) {
|
Chris@45
|
1039
|
Chris@45
|
1040 Layer *layer = m_paneStack->getCurrentPane()->getSelectedLayer();
|
Chris@45
|
1041
|
Chris@409
|
1042 if (m_viewManager) {
|
Chris@409
|
1043
|
Chris@409
|
1044 if (m_viewManager->getToolMode() == ViewManager::MeasureMode) {
|
Chris@409
|
1045
|
Chris@409
|
1046 layer->deleteCurrentMeasureRect();
|
Chris@45
|
1047
|
Chris@409
|
1048 } else {
|
Chris@409
|
1049
|
Chris@409
|
1050 MultiSelection::SelectionList selections =
|
Chris@409
|
1051 m_viewManager->getSelections();
|
Chris@409
|
1052
|
Chris@409
|
1053 for (MultiSelection::SelectionList::iterator i = selections.begin();
|
Chris@409
|
1054 i != selections.end(); ++i) {
|
Chris@409
|
1055 layer->deleteSelection(*i);
|
Chris@409
|
1056 }
|
Chris@45
|
1057 }
|
Chris@595
|
1058 }
|
Chris@45
|
1059 }
|
Chris@45
|
1060 }
|
Chris@45
|
1061
|
Chris@161
|
1062 // FrameTimer method
|
Chris@161
|
1063
|
Chris@435
|
1064 sv_frame_t
|
Chris@161
|
1065 MainWindowBase::getFrame() const
|
Chris@161
|
1066 {
|
Chris@161
|
1067 if (m_playSource && m_playSource->isPlaying()) {
|
Chris@161
|
1068 return m_playSource->getCurrentPlayingFrame();
|
Chris@161
|
1069 } else {
|
Chris@161
|
1070 return m_viewManager->getPlaybackFrame();
|
Chris@161
|
1071 }
|
Chris@161
|
1072 }
|
Chris@161
|
1073
|
Chris@45
|
1074 void
|
Chris@45
|
1075 MainWindowBase::insertInstant()
|
Chris@45
|
1076 {
|
Chris@161
|
1077 insertInstantAt(getFrame());
|
Chris@45
|
1078 }
|
Chris@45
|
1079
|
Chris@45
|
1080 void
|
Chris@45
|
1081 MainWindowBase::insertInstantsAtBoundaries()
|
Chris@45
|
1082 {
|
Chris@45
|
1083 MultiSelection::SelectionList selections = m_viewManager->getSelections();
|
Chris@45
|
1084 for (MultiSelection::SelectionList::iterator i = selections.begin();
|
Chris@45
|
1085 i != selections.end(); ++i) {
|
Chris@435
|
1086 sv_frame_t start = i->getStartFrame();
|
Chris@435
|
1087 sv_frame_t end = i->getEndFrame();
|
Chris@45
|
1088 if (start != end) {
|
Chris@184
|
1089 insertInstantAt(start);
|
Chris@184
|
1090 insertInstantAt(end);
|
Chris@45
|
1091 }
|
Chris@45
|
1092 }
|
Chris@45
|
1093 }
|
Chris@45
|
1094
|
Chris@45
|
1095 void
|
Chris@435
|
1096 MainWindowBase::insertInstantAt(sv_frame_t frame)
|
Chris@45
|
1097 {
|
Chris@45
|
1098 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@45
|
1099 if (!pane) {
|
Chris@45
|
1100 return;
|
Chris@45
|
1101 }
|
Chris@45
|
1102
|
Chris@74
|
1103 frame = pane->alignFromReference(frame);
|
Chris@74
|
1104
|
Chris@45
|
1105 Layer *layer = dynamic_cast<TimeInstantLayer *>
|
Chris@45
|
1106 (pane->getSelectedLayer());
|
Chris@45
|
1107
|
Chris@45
|
1108 if (!layer) {
|
Chris@45
|
1109 for (int i = pane->getLayerCount(); i > 0; --i) {
|
Chris@45
|
1110 layer = dynamic_cast<TimeInstantLayer *>(pane->getLayer(i - 1));
|
Chris@45
|
1111 if (layer) break;
|
Chris@45
|
1112 }
|
Chris@45
|
1113
|
Chris@45
|
1114 if (!layer) {
|
Chris@45
|
1115 CommandHistory::getInstance()->startCompoundOperation
|
Chris@45
|
1116 (tr("Add Point"), true);
|
Chris@45
|
1117 layer = m_document->createEmptyLayer(LayerFactory::TimeInstants);
|
Chris@45
|
1118 if (layer) {
|
Chris@45
|
1119 m_document->addLayerToView(pane, layer);
|
Chris@45
|
1120 m_paneStack->setCurrentLayer(pane, layer);
|
Chris@45
|
1121 }
|
Chris@45
|
1122 CommandHistory::getInstance()->endCompoundOperation();
|
Chris@45
|
1123 }
|
Chris@45
|
1124 }
|
Chris@45
|
1125
|
Chris@45
|
1126 if (layer) {
|
Chris@45
|
1127
|
Chris@45
|
1128 Model *model = layer->getModel();
|
Chris@45
|
1129 SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *>
|
Chris@45
|
1130 (model);
|
Chris@45
|
1131
|
Chris@45
|
1132 if (sodm) {
|
Chris@45
|
1133 SparseOneDimensionalModel::Point point(frame, "");
|
Chris@45
|
1134
|
Chris@45
|
1135 SparseOneDimensionalModel::Point prevPoint(0);
|
Chris@45
|
1136 bool havePrevPoint = false;
|
Chris@45
|
1137
|
Chris@45
|
1138 SparseOneDimensionalModel::EditCommand *command =
|
Chris@45
|
1139 new SparseOneDimensionalModel::EditCommand(sodm, tr("Add Point"));
|
Chris@45
|
1140
|
Chris@409
|
1141 if (m_labeller) {
|
Chris@409
|
1142
|
Chris@409
|
1143 if (m_labeller->requiresPrevPoint()) {
|
Chris@409
|
1144
|
Chris@409
|
1145 SparseOneDimensionalModel::PointList prevPoints =
|
Chris@409
|
1146 sodm->getPreviousPoints(frame);
|
Chris@409
|
1147
|
Chris@409
|
1148 if (!prevPoints.empty()) {
|
Chris@409
|
1149 prevPoint = *prevPoints.begin();
|
Chris@409
|
1150 havePrevPoint = true;
|
Chris@409
|
1151 }
|
Chris@45
|
1152 }
|
Chris@45
|
1153
|
Chris@45
|
1154 m_labeller->setSampleRate(sodm->getSampleRate());
|
Chris@45
|
1155
|
Chris@352
|
1156 if (m_labeller->actingOnPrevPoint() && havePrevPoint) {
|
Chris@45
|
1157 command->deletePoint(prevPoint);
|
Chris@45
|
1158 }
|
Chris@45
|
1159
|
Chris@45
|
1160 m_labeller->label<SparseOneDimensionalModel::Point>
|
Chris@45
|
1161 (point, havePrevPoint ? &prevPoint : 0);
|
Chris@45
|
1162
|
Chris@352
|
1163 if (m_labeller->actingOnPrevPoint() && havePrevPoint) {
|
Chris@45
|
1164 command->addPoint(prevPoint);
|
Chris@45
|
1165 }
|
Chris@45
|
1166 }
|
Chris@45
|
1167
|
Chris@45
|
1168 command->addPoint(point);
|
Chris@45
|
1169
|
Chris@45
|
1170 command->setName(tr("Add Point at %1 s")
|
Chris@45
|
1171 .arg(RealTime::frame2RealTime
|
Chris@45
|
1172 (frame,
|
Chris@45
|
1173 sodm->getSampleRate())
|
Chris@45
|
1174 .toText(false).c_str()));
|
Chris@45
|
1175
|
Chris@108
|
1176 Command *c = command->finish();
|
Chris@108
|
1177 if (c) CommandHistory::getInstance()->addCommand(c, false);
|
Chris@45
|
1178 }
|
Chris@45
|
1179 }
|
Chris@45
|
1180 }
|
Chris@45
|
1181
|
Chris@45
|
1182 void
|
Chris@184
|
1183 MainWindowBase::insertItemAtSelection()
|
Chris@184
|
1184 {
|
Chris@184
|
1185 MultiSelection::SelectionList selections = m_viewManager->getSelections();
|
Chris@184
|
1186 for (MultiSelection::SelectionList::iterator i = selections.begin();
|
Chris@184
|
1187 i != selections.end(); ++i) {
|
Chris@435
|
1188 sv_frame_t start = i->getStartFrame();
|
Chris@435
|
1189 sv_frame_t end = i->getEndFrame();
|
Chris@184
|
1190 if (start < end) {
|
Chris@184
|
1191 insertItemAt(start, end - start);
|
Chris@184
|
1192 }
|
Chris@184
|
1193 }
|
Chris@184
|
1194 }
|
Chris@184
|
1195
|
Chris@184
|
1196 void
|
Chris@435
|
1197 MainWindowBase::insertItemAt(sv_frame_t frame, sv_frame_t duration)
|
Chris@184
|
1198 {
|
Chris@184
|
1199 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@184
|
1200 if (!pane) {
|
Chris@184
|
1201 return;
|
Chris@184
|
1202 }
|
Chris@184
|
1203
|
Chris@184
|
1204 // ugh!
|
Chris@184
|
1205
|
Chris@435
|
1206 sv_frame_t alignedStart = pane->alignFromReference(frame);
|
Chris@435
|
1207 sv_frame_t alignedEnd = pane->alignFromReference(frame + duration);
|
Chris@184
|
1208 if (alignedStart >= alignedEnd) return;
|
Chris@435
|
1209 sv_frame_t alignedDuration = alignedEnd - alignedStart;
|
Chris@184
|
1210
|
Chris@184
|
1211 Command *c = 0;
|
Chris@184
|
1212
|
Chris@184
|
1213 QString name = tr("Add Item at %1 s")
|
Chris@184
|
1214 .arg(RealTime::frame2RealTime
|
Chris@184
|
1215 (alignedStart,
|
Chris@184
|
1216 getMainModel()->getSampleRate())
|
Chris@184
|
1217 .toText(false).c_str());
|
Chris@184
|
1218
|
Chris@184
|
1219 Layer *layer = pane->getSelectedLayer();
|
Chris@184
|
1220 if (!layer) return;
|
Chris@184
|
1221
|
Chris@184
|
1222 RegionModel *rm = dynamic_cast<RegionModel *>(layer->getModel());
|
Chris@184
|
1223 if (rm) {
|
Chris@184
|
1224 RegionModel::Point point(alignedStart,
|
Chris@185
|
1225 rm->getValueMaximum() + 1,
|
Chris@184
|
1226 alignedDuration,
|
Chris@184
|
1227 "");
|
Chris@184
|
1228 RegionModel::EditCommand *command =
|
Chris@184
|
1229 new RegionModel::EditCommand(rm, tr("Add Point"));
|
Chris@184
|
1230 command->addPoint(point);
|
Chris@184
|
1231 command->setName(name);
|
Chris@184
|
1232 c = command->finish();
|
Chris@184
|
1233 }
|
Chris@184
|
1234
|
Chris@184
|
1235 if (c) {
|
Chris@184
|
1236 CommandHistory::getInstance()->addCommand(c, false);
|
Chris@184
|
1237 return;
|
Chris@184
|
1238 }
|
Chris@184
|
1239
|
Chris@184
|
1240 NoteModel *nm = dynamic_cast<NoteModel *>(layer->getModel());
|
Chris@184
|
1241 if (nm) {
|
Chris@184
|
1242 NoteModel::Point point(alignedStart,
|
Chris@409
|
1243 nm->getValueMinimum(),
|
Chris@184
|
1244 alignedDuration,
|
Chris@184
|
1245 1.f,
|
Chris@184
|
1246 "");
|
Chris@184
|
1247 NoteModel::EditCommand *command =
|
Chris@184
|
1248 new NoteModel::EditCommand(nm, tr("Add Point"));
|
Chris@184
|
1249 command->addPoint(point);
|
Chris@184
|
1250 command->setName(name);
|
Chris@184
|
1251 c = command->finish();
|
Chris@184
|
1252 }
|
Chris@184
|
1253
|
Chris@184
|
1254 if (c) {
|
Chris@184
|
1255 CommandHistory::getInstance()->addCommand(c, false);
|
Chris@184
|
1256 return;
|
Chris@184
|
1257 }
|
matthiasm@267
|
1258
|
matthiasm@268
|
1259 FlexiNoteModel *fnm = dynamic_cast<FlexiNoteModel *>(layer->getModel());
|
matthiasm@268
|
1260 if (fnm) {
|
matthiasm@267
|
1261 FlexiNoteModel::Point point(alignedStart,
|
Chris@409
|
1262 fnm->getValueMinimum(),
|
Chris@409
|
1263 alignedDuration,
|
Chris@409
|
1264 1.f,
|
Chris@409
|
1265 "");
|
matthiasm@267
|
1266 FlexiNoteModel::EditCommand *command =
|
matthiasm@268
|
1267 new FlexiNoteModel::EditCommand(fnm, tr("Add Point"));
|
matthiasm@267
|
1268 command->addPoint(point);
|
matthiasm@267
|
1269 command->setName(name);
|
matthiasm@267
|
1270 c = command->finish();
|
matthiasm@267
|
1271 }
|
Chris@409
|
1272
|
matthiasm@267
|
1273 if (c) {
|
matthiasm@267
|
1274 CommandHistory::getInstance()->addCommand(c, false);
|
matthiasm@267
|
1275 return;
|
matthiasm@267
|
1276 }
|
Chris@184
|
1277 }
|
Chris@184
|
1278
|
Chris@184
|
1279 void
|
Chris@45
|
1280 MainWindowBase::renumberInstants()
|
Chris@45
|
1281 {
|
Chris@45
|
1282 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@45
|
1283 if (!pane) return;
|
Chris@45
|
1284
|
Chris@45
|
1285 Layer *layer = dynamic_cast<TimeInstantLayer *>(pane->getSelectedLayer());
|
Chris@45
|
1286 if (!layer) return;
|
Chris@45
|
1287
|
Chris@45
|
1288 MultiSelection ms(m_viewManager->getSelection());
|
Chris@45
|
1289
|
Chris@45
|
1290 Model *model = layer->getModel();
|
Chris@45
|
1291 SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *>
|
Chris@45
|
1292 (model);
|
Chris@45
|
1293 if (!sodm) return;
|
Chris@45
|
1294
|
Chris@45
|
1295 if (!m_labeller) return;
|
Chris@45
|
1296
|
Chris@45
|
1297 Labeller labeller(*m_labeller);
|
Chris@45
|
1298 labeller.setSampleRate(sodm->getSampleRate());
|
Chris@45
|
1299
|
Chris@537
|
1300 Command *c = labeller.labelAll<SparseOneDimensionalModel::Point>(*sodm, &ms);
|
Chris@537
|
1301 if (c) CommandHistory::getInstance()->addCommand(c, false);
|
Chris@537
|
1302 }
|
Chris@537
|
1303
|
Chris@537
|
1304 void
|
Chris@537
|
1305 MainWindowBase::subdivideInstantsBy(int n)
|
Chris@537
|
1306 {
|
Chris@537
|
1307 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@537
|
1308 if (!pane) return;
|
Chris@537
|
1309
|
Chris@537
|
1310 Layer *layer = dynamic_cast<TimeInstantLayer *>(pane->getSelectedLayer());
|
Chris@537
|
1311 if (!layer) return;
|
Chris@537
|
1312
|
Chris@537
|
1313 MultiSelection ms(m_viewManager->getSelection());
|
Chris@537
|
1314
|
Chris@537
|
1315 Model *model = layer->getModel();
|
Chris@537
|
1316 SparseOneDimensionalModel *sodm =
|
Chris@537
|
1317 dynamic_cast<SparseOneDimensionalModel *>(model);
|
Chris@537
|
1318 if (!sodm) return;
|
Chris@537
|
1319
|
Chris@537
|
1320 if (!m_labeller) return;
|
Chris@537
|
1321
|
Chris@537
|
1322 Labeller labeller(*m_labeller);
|
Chris@537
|
1323 labeller.setSampleRate(sodm->getSampleRate());
|
Chris@537
|
1324
|
Chris@537
|
1325 Command *c = labeller.subdivide<SparseOneDimensionalModel::Point>
|
Chris@537
|
1326 (*sodm, &ms, n);
|
Chris@537
|
1327 if (c) CommandHistory::getInstance()->addCommand(c, false);
|
Chris@45
|
1328 }
|
Chris@45
|
1329
|
Chris@538
|
1330 void
|
Chris@538
|
1331 MainWindowBase::winnowInstantsBy(int n)
|
Chris@538
|
1332 {
|
Chris@538
|
1333 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@538
|
1334 if (!pane) return;
|
Chris@538
|
1335
|
Chris@538
|
1336 Layer *layer = dynamic_cast<TimeInstantLayer *>(pane->getSelectedLayer());
|
Chris@538
|
1337 if (!layer) return;
|
Chris@538
|
1338
|
Chris@538
|
1339 MultiSelection ms(m_viewManager->getSelection());
|
Chris@538
|
1340
|
Chris@538
|
1341 Model *model = layer->getModel();
|
Chris@538
|
1342 SparseOneDimensionalModel *sodm =
|
Chris@538
|
1343 dynamic_cast<SparseOneDimensionalModel *>(model);
|
Chris@538
|
1344 if (!sodm) return;
|
Chris@538
|
1345
|
Chris@538
|
1346 if (!m_labeller) return;
|
Chris@538
|
1347
|
Chris@538
|
1348 Labeller labeller(*m_labeller);
|
Chris@538
|
1349 labeller.setSampleRate(sodm->getSampleRate());
|
Chris@538
|
1350
|
Chris@538
|
1351 Command *c = labeller.winnow<SparseOneDimensionalModel::Point>
|
Chris@538
|
1352 (*sodm, &ms, n);
|
Chris@538
|
1353 if (c) CommandHistory::getInstance()->addCommand(c, false);
|
Chris@538
|
1354 }
|
Chris@538
|
1355
|
Chris@45
|
1356 MainWindowBase::FileOpenStatus
|
Chris@373
|
1357 MainWindowBase::openPath(QString fileOrUrl, AudioFileOpenMode mode)
|
Chris@45
|
1358 {
|
Chris@134
|
1359 ProgressDialog dialog(tr("Opening file or URL..."), true, 2000, this);
|
Chris@134
|
1360 connect(&dialog, SIGNAL(showing()), this, SIGNAL(hideSplash()));
|
Chris@109
|
1361 return open(FileSource(fileOrUrl, &dialog), mode);
|
Chris@45
|
1362 }
|
Chris@45
|
1363
|
Chris@45
|
1364 MainWindowBase::FileOpenStatus
|
Chris@45
|
1365 MainWindowBase::open(FileSource source, AudioFileOpenMode mode)
|
Chris@45
|
1366 {
|
Chris@45
|
1367 FileOpenStatus status;
|
Chris@45
|
1368
|
Chris@45
|
1369 if (!source.isAvailable()) return FileOpenFailed;
|
Chris@45
|
1370 source.waitForData();
|
Chris@45
|
1371
|
Chris@45
|
1372 bool canImportLayer = (getMainModel() != 0 &&
|
Chris@45
|
1373 m_paneStack != 0 &&
|
Chris@45
|
1374 m_paneStack->getCurrentPane() != 0);
|
Chris@45
|
1375
|
Chris@152
|
1376 bool rdf = (source.getExtension().toLower() == "rdf" ||
|
Chris@152
|
1377 source.getExtension().toLower() == "n3" ||
|
Chris@152
|
1378 source.getExtension().toLower() == "ttl");
|
Chris@152
|
1379
|
Chris@152
|
1380 bool audio = AudioFileReaderFactory::getKnownExtensions().contains
|
Chris@152
|
1381 (source.getExtension().toLower());
|
Chris@145
|
1382
|
Chris@145
|
1383 bool rdfSession = false;
|
Chris@145
|
1384 if (rdf) {
|
Chris@145
|
1385 RDFImporter::RDFDocumentType rdfType =
|
Chris@145
|
1386 RDFImporter::identifyDocumentType
|
Chris@145
|
1387 (QUrl::fromLocalFile(source.getLocalFilename()).toString());
|
Chris@145
|
1388 if (rdfType == RDFImporter::AudioRefAndAnnotations ||
|
Chris@145
|
1389 rdfType == RDFImporter::AudioRef) {
|
Chris@145
|
1390 rdfSession = true;
|
Chris@145
|
1391 } else if (rdfType == RDFImporter::NotRDF) {
|
Chris@145
|
1392 rdf = false;
|
Chris@145
|
1393 }
|
Chris@145
|
1394 }
|
Chris@145
|
1395
|
Chris@579
|
1396 try {
|
Chris@579
|
1397 if (rdf) {
|
Chris@579
|
1398 if (rdfSession) {
|
Chris@579
|
1399 bool cancel = false;
|
Chris@579
|
1400 if (!canImportLayer || shouldCreateNewSessionForRDFAudio(&cancel)) {
|
Chris@579
|
1401 return openSession(source);
|
Chris@579
|
1402 } else if (cancel) {
|
Chris@579
|
1403 return FileOpenCancelled;
|
Chris@579
|
1404 } else {
|
Chris@579
|
1405 return openLayer(source);
|
Chris@579
|
1406 }
|
Chris@145
|
1407 } else {
|
Chris@579
|
1408 if ((status = openSession(source)) != FileOpenFailed) {
|
Chris@579
|
1409 return status;
|
Chris@579
|
1410 } else if (!canImportLayer) {
|
Chris@579
|
1411 return FileOpenWrongMode;
|
Chris@579
|
1412 } else if ((status = openLayer(source)) != FileOpenFailed) {
|
Chris@579
|
1413 return status;
|
Chris@579
|
1414 } else {
|
Chris@579
|
1415 return FileOpenFailed;
|
Chris@579
|
1416 }
|
Chris@145
|
1417 }
|
Chris@145
|
1418 }
|
Chris@579
|
1419
|
Chris@579
|
1420 if (audio && (status = openAudio(source, mode)) != FileOpenFailed) {
|
Chris@579
|
1421 return status;
|
Chris@579
|
1422 } else if ((status = openSession(source)) != FileOpenFailed) {
|
Chris@579
|
1423 return status;
|
Chris@579
|
1424 } else if ((status = openPlaylist(source, mode)) != FileOpenFailed) {
|
Chris@579
|
1425 return status;
|
Chris@579
|
1426 } else if (!canImportLayer) {
|
Chris@579
|
1427 return FileOpenWrongMode;
|
Chris@579
|
1428 } else if ((status = openImage(source)) != FileOpenFailed) {
|
Chris@579
|
1429 return status;
|
Chris@579
|
1430 } else if ((status = openLayer(source)) != FileOpenFailed) {
|
Chris@579
|
1431 return status;
|
Chris@579
|
1432 } else {
|
Chris@579
|
1433 return FileOpenFailed;
|
Chris@579
|
1434 }
|
Chris@579
|
1435 } catch (const InsufficientDiscSpace &e) {
|
Chris@579
|
1436 emit hideSplash();
|
Chris@579
|
1437 m_openingAudioFile = false;
|
Chris@594
|
1438 SVCERR << "MainWindowBase: Caught InsufficientDiscSpace in file open" << endl;
|
Chris@579
|
1439 QMessageBox::critical
|
Chris@579
|
1440 (this, tr("Not enough disc space"),
|
Chris@579
|
1441 tr("<b>Not enough disc space</b><p>There doesn't appear to be enough spare disc space to accommodate any necessary temporary files.</p><p>Please clear some space and try again.</p>").arg(e.what()));
|
Chris@579
|
1442 return FileOpenFailed;
|
Chris@592
|
1443 } catch (const std::bad_alloc &e) { // reader may have rethrown this after cleaning up
|
Chris@592
|
1444 emit hideSplash();
|
Chris@592
|
1445 m_openingAudioFile = false;
|
Chris@594
|
1446 SVCERR << "MainWindowBase: Caught bad_alloc in file open" << endl;
|
Chris@592
|
1447 QMessageBox::critical
|
Chris@592
|
1448 (this, tr("Not enough memory"),
|
Chris@592
|
1449 tr("<b>Not enough memory</b><p>There doesn't appear to be enough memory to accommodate any necessary temporary data.</p>"));
|
Chris@592
|
1450 return FileOpenFailed;
|
Chris@45
|
1451 }
|
Chris@45
|
1452 }
|
Chris@45
|
1453
|
Chris@45
|
1454 MainWindowBase::FileOpenStatus
|
Chris@227
|
1455 MainWindowBase::openAudio(FileSource source, AudioFileOpenMode mode,
|
Chris@227
|
1456 QString templateName)
|
Chris@45
|
1457 {
|
Chris@386
|
1458 SVDEBUG << "MainWindowBase::openAudio(" << source.getLocation() << ") with mode " << mode << " and template " << templateName << endl;
|
Chris@45
|
1459
|
Chris@222
|
1460 if (templateName == "") {
|
Chris@231
|
1461 templateName = getDefaultSessionTemplate();
|
Chris@577
|
1462 SVDEBUG << "(Default template is: \"" << templateName << "\")" << endl;
|
Chris@222
|
1463 }
|
Chris@220
|
1464
|
Chris@374
|
1465 // cerr << "template is: \"" << templateName << "\"" << endl;
|
Chris@223
|
1466
|
Chris@413
|
1467 if (!source.isAvailable()) {
|
Chris@413
|
1468 if (source.wasCancelled()) {
|
Chris@413
|
1469 return FileOpenCancelled;
|
Chris@413
|
1470 } else {
|
Chris@413
|
1471 return FileOpenFailed;
|
Chris@413
|
1472 }
|
Chris@413
|
1473 }
|
Chris@413
|
1474
|
Chris@45
|
1475 source.waitForData();
|
Chris@45
|
1476
|
Chris@45
|
1477 m_openingAudioFile = true;
|
Chris@45
|
1478
|
Chris@435
|
1479 sv_samplerate_t rate = 0;
|
Chris@45
|
1480
|
Chris@360
|
1481 if (Preferences::getInstance()->getFixedSampleRate() != 0) {
|
Chris@360
|
1482 rate = Preferences::getInstance()->getFixedSampleRate();
|
Chris@360
|
1483 } else if (Preferences::getInstance()->getResampleOnLoad()) {
|
Chris@552
|
1484 if (getMainModel()) {
|
Chris@552
|
1485 rate = getMainModel()->getSampleRate();
|
Chris@552
|
1486 }
|
Chris@45
|
1487 }
|
Chris@45
|
1488
|
Chris@479
|
1489 ReadOnlyWaveFileModel *newModel = new ReadOnlyWaveFileModel(source, rate);
|
Chris@45
|
1490
|
Chris@45
|
1491 if (!newModel->isOK()) {
|
Chris@595
|
1492 delete newModel;
|
Chris@45
|
1493 m_openingAudioFile = false;
|
Chris@413
|
1494 if (source.wasCancelled()) {
|
Chris@413
|
1495 return FileOpenCancelled;
|
Chris@413
|
1496 } else {
|
Chris@413
|
1497 return FileOpenFailed;
|
Chris@413
|
1498 }
|
Chris@45
|
1499 }
|
Chris@45
|
1500
|
Chris@604
|
1501 return addOpenedAudioModel(source, newModel, mode, templateName, true);
|
Chris@604
|
1502 }
|
Chris@604
|
1503
|
Chris@604
|
1504 MainWindowBase::FileOpenStatus
|
Chris@604
|
1505 MainWindowBase::addOpenedAudioModel(FileSource source,
|
Chris@604
|
1506 WaveFileModel *newModel,
|
Chris@604
|
1507 AudioFileOpenMode mode,
|
Chris@604
|
1508 QString templateName,
|
Chris@604
|
1509 bool registerSource)
|
Chris@604
|
1510 {
|
Chris@45
|
1511 if (mode == AskUser) {
|
Chris@45
|
1512 if (getMainModel()) {
|
Chris@45
|
1513
|
Chris@147
|
1514 QSettings settings;
|
Chris@147
|
1515 settings.beginGroup("MainWindow");
|
Chris@221
|
1516 int lastMode = settings.value("lastaudioopenmode", 0).toBool();
|
Chris@147
|
1517 settings.endGroup();
|
Chris@221
|
1518 int imode = 0;
|
Chris@45
|
1519
|
Chris@45
|
1520 QStringList items;
|
Chris@221
|
1521 items << tr("Close the current session and start a new one")
|
Chris@221
|
1522 << tr("Replace the main audio file in this session")
|
Chris@221
|
1523 << tr("Add the audio file to this session");
|
Chris@45
|
1524
|
Chris@45
|
1525 bool ok = false;
|
Chris@45
|
1526 QString item = ListInputDialog::getItem
|
Chris@45
|
1527 (this, tr("Select target for import"),
|
Chris@221
|
1528 tr("<b>Select a target for import</b><p>You already have an audio file loaded.<br>What would you like to do with the new audio file?"),
|
Chris@221
|
1529 items, lastMode, &ok);
|
Chris@45
|
1530
|
Chris@45
|
1531 if (!ok || item.isEmpty()) {
|
Chris@45
|
1532 delete newModel;
|
Chris@45
|
1533 m_openingAudioFile = false;
|
Chris@45
|
1534 return FileOpenCancelled;
|
Chris@45
|
1535 }
|
Chris@45
|
1536
|
Chris@221
|
1537 for (int i = 0; i < items.size(); ++i) {
|
Chris@221
|
1538 if (item == items[i]) imode = i;
|
Chris@221
|
1539 }
|
Chris@221
|
1540
|
Chris@147
|
1541 settings.beginGroup("MainWindow");
|
Chris@221
|
1542 settings.setValue("lastaudioopenmode", imode);
|
Chris@147
|
1543 settings.endGroup();
|
Chris@45
|
1544
|
Chris@221
|
1545 mode = (AudioFileOpenMode)imode;
|
Chris@45
|
1546
|
Chris@45
|
1547 } else {
|
Chris@221
|
1548 // no main model: make a new session
|
Chris@221
|
1549 mode = ReplaceSession;
|
Chris@45
|
1550 }
|
Chris@45
|
1551 }
|
Chris@45
|
1552
|
Chris@45
|
1553 if (mode == ReplaceCurrentPane) {
|
Chris@45
|
1554
|
Chris@45
|
1555 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@45
|
1556 if (pane) {
|
Chris@45
|
1557 if (getMainModel()) {
|
Chris@45
|
1558 View::ModelSet models(pane->getModels());
|
Chris@45
|
1559 if (models.find(getMainModel()) != models.end()) {
|
Chris@221
|
1560 // Current pane contains main model: replace that
|
Chris@45
|
1561 mode = ReplaceMainModel;
|
Chris@45
|
1562 }
|
Chris@221
|
1563 // Otherwise the current pane has a non-default model,
|
Chris@221
|
1564 // which we will deal with later
|
Chris@45
|
1565 } else {
|
Chris@221
|
1566 // We have no main model, so start a new session with
|
Chris@221
|
1567 // optional template
|
Chris@221
|
1568 mode = ReplaceSession;
|
Chris@45
|
1569 }
|
Chris@45
|
1570 } else {
|
Chris@221
|
1571 // We seem to have no current pane! Oh well
|
Chris@45
|
1572 mode = CreateAdditionalModel;
|
Chris@45
|
1573 }
|
Chris@45
|
1574 }
|
Chris@45
|
1575
|
Chris@45
|
1576 if (mode == CreateAdditionalModel && !getMainModel()) {
|
Chris@386
|
1577 SVDEBUG << "Mode is CreateAdditionalModel but we have no main model, switching to ReplaceSession mode" << endl;
|
Chris@221
|
1578 mode = ReplaceSession;
|
Chris@221
|
1579 }
|
Chris@221
|
1580
|
Chris@221
|
1581 bool loadedTemplate = false;
|
Chris@221
|
1582
|
Chris@221
|
1583 if (mode == ReplaceSession) {
|
Chris@258
|
1584
|
Chris@258
|
1585 if (!checkSaveModified()) return FileOpenCancelled;
|
Chris@258
|
1586
|
Chris@386
|
1587 SVDEBUG << "SV looking for template " << templateName << endl;
|
Chris@230
|
1588 if (templateName != "") {
|
Chris@230
|
1589 FileOpenStatus tplStatus = openSessionTemplate(templateName);
|
Chris@258
|
1590 if (tplStatus == FileOpenCancelled) {
|
Chris@577
|
1591 SVDEBUG << "Template load cancelled" << endl;
|
Chris@258
|
1592 return FileOpenCancelled;
|
Chris@258
|
1593 }
|
Chris@230
|
1594 if (tplStatus != FileOpenFailed) {
|
Chris@577
|
1595 SVDEBUG << "Template load succeeded" << endl;
|
Chris@230
|
1596 loadedTemplate = true;
|
Chris@221
|
1597 }
|
Chris@221
|
1598 }
|
Chris@221
|
1599
|
Chris@221
|
1600 if (!loadedTemplate) {
|
Chris@386
|
1601 SVDEBUG << "No template found: closing session, creating new empty document" << endl;
|
Chris@221
|
1602 closeSession();
|
Chris@221
|
1603 createDocument();
|
Chris@221
|
1604 }
|
Chris@221
|
1605
|
Chris@386
|
1606 SVDEBUG << "Now switching to ReplaceMainModel mode" << endl;
|
Chris@45
|
1607 mode = ReplaceMainModel;
|
Chris@45
|
1608 }
|
Chris@45
|
1609
|
Chris@164
|
1610 emit activity(tr("Import audio file \"%1\"").arg(source.getLocation()));
|
Chris@164
|
1611
|
Chris@45
|
1612 if (mode == ReplaceMainModel) {
|
Chris@45
|
1613
|
Chris@45
|
1614 Model *prevMain = getMainModel();
|
Chris@45
|
1615 if (prevMain) {
|
Chris@45
|
1616 m_playSource->removeModel(prevMain);
|
Chris@108
|
1617 PlayParameterRepository::getInstance()->removePlayable(prevMain);
|
Chris@45
|
1618 }
|
Chris@108
|
1619 PlayParameterRepository::getInstance()->addPlayable(newModel);
|
Chris@45
|
1620
|
Chris@248
|
1621 SVDEBUG << "SV about to call setMainModel(" << newModel << "): prevMain is " << prevMain << endl;
|
Chris@248
|
1622
|
Chris@595
|
1623 m_document->setMainModel(newModel);
|
Chris@595
|
1624
|
Chris@595
|
1625 setupMenus();
|
Chris@595
|
1626
|
Chris@595
|
1627 if (loadedTemplate || (m_sessionFile == "")) {
|
Chris@45
|
1628 //!!! shouldn't be dealing directly with title from here -- call a method
|
Chris@595
|
1629 setWindowTitle(tr("%1: %2")
|
Chris@57
|
1630 .arg(QApplication::applicationName())
|
Chris@45
|
1631 .arg(source.getLocation()));
|
Chris@595
|
1632 CommandHistory::getInstance()->clear();
|
Chris@595
|
1633 CommandHistory::getInstance()->documentSaved();
|
Chris@595
|
1634 m_documentModified = false;
|
Chris@595
|
1635 } else {
|
Chris@595
|
1636 setWindowTitle(tr("%1: %2 [%3]")
|
Chris@57
|
1637 .arg(QApplication::applicationName())
|
Chris@595
|
1638 .arg(QFileInfo(m_sessionFile).fileName())
|
Chris@595
|
1639 .arg(source.getLocation()));
|
Chris@595
|
1640 if (m_documentModified) {
|
Chris@595
|
1641 m_documentModified = false;
|
Chris@595
|
1642 documentModified(); // so as to restore "(modified)" window title
|
Chris@595
|
1643 }
|
Chris@595
|
1644 }
|
Chris@45
|
1645
|
Chris@604
|
1646 if (!source.isRemote() && registerSource) {
|
Chris@604
|
1647 m_audioFile = source.getLocalFilename();
|
Chris@604
|
1648 }
|
Chris@45
|
1649
|
Chris@45
|
1650 } else if (mode == CreateAdditionalModel) {
|
Chris@45
|
1651
|
Chris@577
|
1652 SVCERR << "Mode is CreateAdditionalModel" << endl;
|
Chris@577
|
1653
|
Chris@595
|
1654 CommandHistory::getInstance()->startCompoundOperation
|
Chris@595
|
1655 (tr("Import \"%1\"").arg(source.getBasename()), true);
|
Chris@595
|
1656
|
Chris@595
|
1657 m_document->addImportedModel(newModel);
|
Chris@595
|
1658
|
Chris@595
|
1659 AddPaneCommand *command = new AddPaneCommand(this);
|
Chris@595
|
1660 CommandHistory::getInstance()->addCommand(command);
|
Chris@595
|
1661
|
Chris@595
|
1662 Pane *pane = command->getPane();
|
Chris@45
|
1663
|
Chris@47
|
1664 if (m_timeRulerLayer) {
|
Chris@577
|
1665 SVCERR << "Have time ruler, adding it" << endl;
|
Chris@47
|
1666 m_document->addLayerToView(pane, m_timeRulerLayer);
|
Chris@577
|
1667 } else {
|
Chris@577
|
1668 SVCERR << "Do not have time ruler" << endl;
|
Chris@47
|
1669 }
|
Chris@45
|
1670
|
Chris@595
|
1671 Layer *newLayer = m_document->createImportedLayer(newModel);
|
Chris@595
|
1672
|
Chris@595
|
1673 if (newLayer) {
|
Chris@595
|
1674 m_document->addLayerToView(pane, newLayer);
|
Chris@595
|
1675 }
|
Chris@595
|
1676
|
Chris@595
|
1677 CommandHistory::getInstance()->endCompoundOperation();
|
Chris@45
|
1678
|
Chris@45
|
1679 } else if (mode == ReplaceCurrentPane) {
|
Chris@45
|
1680
|
Chris@45
|
1681 // We know there is a current pane, otherwise we would have
|
Chris@45
|
1682 // reset the mode to CreateAdditionalModel above; and we know
|
Chris@45
|
1683 // the current pane does not contain the main model, otherwise
|
Chris@45
|
1684 // we would have reset it to ReplaceMainModel. But we don't
|
Chris@45
|
1685 // know whether the pane contains a waveform model at all.
|
Chris@45
|
1686
|
Chris@45
|
1687 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@45
|
1688 Layer *replace = 0;
|
Chris@45
|
1689
|
Chris@45
|
1690 for (int i = 0; i < pane->getLayerCount(); ++i) {
|
Chris@45
|
1691 Layer *layer = pane->getLayer(i);
|
Chris@45
|
1692 if (dynamic_cast<WaveformLayer *>(layer)) {
|
Chris@45
|
1693 replace = layer;
|
Chris@45
|
1694 break;
|
Chris@45
|
1695 }
|
Chris@45
|
1696 }
|
Chris@45
|
1697
|
Chris@595
|
1698 CommandHistory::getInstance()->startCompoundOperation
|
Chris@595
|
1699 (tr("Import \"%1\"").arg(source.getBasename()), true);
|
Chris@595
|
1700
|
Chris@595
|
1701 m_document->addImportedModel(newModel);
|
Chris@45
|
1702
|
Chris@45
|
1703 if (replace) {
|
Chris@45
|
1704 m_document->removeLayerFromView(pane, replace);
|
Chris@45
|
1705 }
|
Chris@45
|
1706
|
Chris@595
|
1707 Layer *newLayer = m_document->createImportedLayer(newModel);
|
Chris@595
|
1708
|
Chris@595
|
1709 if (newLayer) {
|
Chris@595
|
1710 m_document->addLayerToView(pane, newLayer);
|
Chris@595
|
1711 }
|
Chris@595
|
1712
|
Chris@595
|
1713 CommandHistory::getInstance()->endCompoundOperation();
|
Chris@45
|
1714 }
|
Chris@45
|
1715
|
Chris@45
|
1716 updateMenuStates();
|
Chris@45
|
1717 m_recentFiles.addFile(source.getLocation());
|
Chris@604
|
1718 if (!source.isRemote() && registerSource) {
|
Chris@45
|
1719 // for file dialog
|
Chris@45
|
1720 registerLastOpenedFilePath(FileFinder::AudioFile,
|
Chris@45
|
1721 source.getLocalFilename());
|
Chris@45
|
1722 }
|
Chris@45
|
1723 m_openingAudioFile = false;
|
Chris@45
|
1724
|
Chris@45
|
1725 currentPaneChanged(m_paneStack->getCurrentPane());
|
Chris@45
|
1726
|
Chris@342
|
1727 emit audioFileLoaded();
|
Chris@342
|
1728
|
Chris@45
|
1729 return FileOpenSucceeded;
|
Chris@45
|
1730 }
|
Chris@45
|
1731
|
Chris@45
|
1732 MainWindowBase::FileOpenStatus
|
Chris@45
|
1733 MainWindowBase::openPlaylist(FileSource source, AudioFileOpenMode mode)
|
Chris@45
|
1734 {
|
Chris@233
|
1735 SVDEBUG << "MainWindowBase::openPlaylist(" << source.getLocation() << ")" << endl;
|
Chris@135
|
1736
|
Chris@45
|
1737 std::set<QString> extensions;
|
Chris@45
|
1738 PlaylistFileReader::getSupportedExtensions(extensions);
|
Chris@152
|
1739 QString extension = source.getExtension().toLower();
|
Chris@45
|
1740 if (extensions.find(extension) == extensions.end()) return FileOpenFailed;
|
Chris@45
|
1741
|
Chris@45
|
1742 if (!source.isAvailable()) return FileOpenFailed;
|
Chris@45
|
1743 source.waitForData();
|
Chris@45
|
1744
|
Chris@45
|
1745 PlaylistFileReader reader(source.getLocalFilename());
|
Chris@45
|
1746 if (!reader.isOK()) return FileOpenFailed;
|
Chris@45
|
1747
|
Chris@45
|
1748 PlaylistFileReader::Playlist playlist = reader.load();
|
Chris@45
|
1749
|
Chris@45
|
1750 bool someSuccess = false;
|
Chris@45
|
1751
|
Chris@45
|
1752 for (PlaylistFileReader::Playlist::const_iterator i = playlist.begin();
|
Chris@45
|
1753 i != playlist.end(); ++i) {
|
Chris@45
|
1754
|
Chris@134
|
1755 ProgressDialog dialog(tr("Opening playlist..."), true, 2000, this);
|
Chris@134
|
1756 connect(&dialog, SIGNAL(showing()), this, SIGNAL(hideSplash()));
|
Chris@109
|
1757 FileOpenStatus status = openAudio(FileSource(*i, &dialog), mode);
|
Chris@45
|
1758
|
Chris@45
|
1759 if (status == FileOpenCancelled) {
|
Chris@45
|
1760 return FileOpenCancelled;
|
Chris@45
|
1761 }
|
Chris@45
|
1762
|
Chris@45
|
1763 if (status == FileOpenSucceeded) {
|
Chris@45
|
1764 someSuccess = true;
|
Chris@45
|
1765 mode = CreateAdditionalModel;
|
Chris@45
|
1766 }
|
Chris@45
|
1767 }
|
Chris@45
|
1768
|
Chris@45
|
1769 if (someSuccess) return FileOpenSucceeded;
|
Chris@45
|
1770 else return FileOpenFailed;
|
Chris@45
|
1771 }
|
Chris@45
|
1772
|
Chris@45
|
1773 MainWindowBase::FileOpenStatus
|
Chris@45
|
1774 MainWindowBase::openLayer(FileSource source)
|
Chris@45
|
1775 {
|
Chris@233
|
1776 SVDEBUG << "MainWindowBase::openLayer(" << source.getLocation() << ")" << endl;
|
Chris@135
|
1777
|
Chris@45
|
1778 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@45
|
1779
|
Chris@45
|
1780 if (!pane) {
|
Chris@595
|
1781 // shouldn't happen, as the menu action should have been disabled
|
Chris@595
|
1782 cerr << "WARNING: MainWindowBase::openLayer: no current pane" << endl;
|
Chris@595
|
1783 return FileOpenWrongMode;
|
Chris@45
|
1784 }
|
Chris@45
|
1785
|
Chris@45
|
1786 if (!getMainModel()) {
|
Chris@595
|
1787 // shouldn't happen, as the menu action should have been disabled
|
Chris@595
|
1788 cerr << "WARNING: MainWindowBase::openLayer: No main model -- hence no default sample rate available" << endl;
|
Chris@595
|
1789 return FileOpenWrongMode;
|
Chris@45
|
1790 }
|
Chris@45
|
1791
|
Chris@45
|
1792 if (!source.isAvailable()) return FileOpenFailed;
|
Chris@45
|
1793 source.waitForData();
|
Chris@45
|
1794
|
Chris@45
|
1795 QString path = source.getLocalFilename();
|
Chris@45
|
1796
|
Chris@145
|
1797 RDFImporter::RDFDocumentType rdfType =
|
Chris@145
|
1798 RDFImporter::identifyDocumentType(QUrl::fromLocalFile(path).toString());
|
Chris@145
|
1799
|
Chris@293
|
1800 // cerr << "RDF type: (in layer) " << (int) rdfType << endl;
|
Chris@148
|
1801
|
Chris@145
|
1802 if (rdfType != RDFImporter::NotRDF) {
|
Chris@145
|
1803
|
Chris@145
|
1804 return openLayersFromRDF(source);
|
Chris@134
|
1805
|
Chris@152
|
1806 } else if (source.getExtension().toLower() == "svl" ||
|
Chris@152
|
1807 (source.getExtension().toLower() == "xml" &&
|
Chris@140
|
1808 (SVFileReader::identifyXmlFile(source.getLocalFilename())
|
Chris@140
|
1809 == SVFileReader::SVLayerFile))) {
|
Chris@45
|
1810
|
Chris@45
|
1811 PaneCallback callback(this);
|
Chris@45
|
1812 QFile file(path);
|
Chris@45
|
1813
|
Chris@45
|
1814 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
Chris@293
|
1815 cerr << "ERROR: MainWindowBase::openLayer("
|
Chris@294
|
1816 << source.getLocation()
|
Chris@293
|
1817 << "): Failed to open file for reading" << endl;
|
Chris@45
|
1818 return FileOpenFailed;
|
Chris@45
|
1819 }
|
Chris@45
|
1820
|
Chris@45
|
1821 SVFileReader reader(m_document, callback, source.getLocation());
|
Chris@79
|
1822 connect
|
Chris@79
|
1823 (&reader, SIGNAL(modelRegenerationFailed(QString, QString, QString)),
|
Chris@79
|
1824 this, SLOT(modelRegenerationFailed(QString, QString, QString)));
|
Chris@79
|
1825 connect
|
Chris@79
|
1826 (&reader, SIGNAL(modelRegenerationWarning(QString, QString, QString)),
|
Chris@79
|
1827 this, SLOT(modelRegenerationWarning(QString, QString, QString)));
|
Chris@45
|
1828 reader.setCurrentPane(pane);
|
Chris@45
|
1829
|
Chris@45
|
1830 QXmlInputSource inputSource(&file);
|
Chris@45
|
1831 reader.parse(inputSource);
|
Chris@45
|
1832
|
Chris@45
|
1833 if (!reader.isOK()) {
|
Chris@293
|
1834 cerr << "ERROR: MainWindowBase::openLayer("
|
Chris@294
|
1835 << source.getLocation()
|
Chris@45
|
1836 << "): Failed to read XML file: "
|
Chris@293
|
1837 << reader.getErrorString() << endl;
|
Chris@45
|
1838 return FileOpenFailed;
|
Chris@45
|
1839 }
|
Chris@45
|
1840
|
Chris@164
|
1841 emit activity(tr("Import layer XML file \"%1\"").arg(source.getLocation()));
|
Chris@164
|
1842
|
Chris@45
|
1843 m_recentFiles.addFile(source.getLocation());
|
Chris@45
|
1844
|
Chris@45
|
1845 if (!source.isRemote()) {
|
Chris@45
|
1846 registerLastOpenedFilePath(FileFinder::LayerFile, path); // for file dialog
|
Chris@45
|
1847 }
|
Chris@45
|
1848
|
Chris@75
|
1849 return FileOpenSucceeded;
|
Chris@75
|
1850
|
Chris@45
|
1851 } else {
|
Chris@45
|
1852
|
Chris@45
|
1853 try {
|
Chris@45
|
1854
|
Chris@109
|
1855 MIDIFileImportDialog midiDlg(this);
|
Chris@109
|
1856
|
Chris@109
|
1857 Model *model = DataFileReaderFactory::loadNonCSV
|
Chris@109
|
1858 (path, &midiDlg, getMainModel()->getSampleRate());
|
Chris@45
|
1859
|
Chris@109
|
1860 if (!model) {
|
Chris@196
|
1861 CSVFormat format(path);
|
Chris@196
|
1862 format.setSampleRate(getMainModel()->getSampleRate());
|
Chris@196
|
1863 CSVFormatDialog *dialog = new CSVFormatDialog(this, format);
|
Chris@109
|
1864 if (dialog->exec() == QDialog::Accepted) {
|
Chris@109
|
1865 model = DataFileReaderFactory::loadCSV
|
Chris@109
|
1866 (path, dialog->getFormat(),
|
Chris@109
|
1867 getMainModel()->getSampleRate());
|
Chris@109
|
1868 }
|
Chris@109
|
1869 }
|
Chris@109
|
1870
|
Chris@45
|
1871 if (model) {
|
Chris@45
|
1872
|
Chris@233
|
1873 SVDEBUG << "MainWindowBase::openLayer: Have model" << endl;
|
Chris@45
|
1874
|
Chris@164
|
1875 emit activity(tr("Import MIDI file \"%1\"").arg(source.getLocation()));
|
Chris@164
|
1876
|
Chris@45
|
1877 Layer *newLayer = m_document->createImportedLayer(model);
|
Chris@45
|
1878
|
Chris@45
|
1879 if (newLayer) {
|
Chris@45
|
1880
|
Chris@45
|
1881 m_document->addLayerToView(pane, newLayer);
|
Chris@88
|
1882 m_paneStack->setCurrentLayer(pane, newLayer);
|
Chris@88
|
1883
|
Chris@45
|
1884 m_recentFiles.addFile(source.getLocation());
|
Chris@45
|
1885
|
Chris@45
|
1886 if (!source.isRemote()) {
|
Chris@45
|
1887 registerLastOpenedFilePath
|
Chris@45
|
1888 (FileFinder::LayerFile,
|
Chris@45
|
1889 path); // for file dialog
|
Chris@45
|
1890 }
|
Chris@88
|
1891
|
Chris@45
|
1892 return FileOpenSucceeded;
|
Chris@45
|
1893 }
|
Chris@45
|
1894 }
|
Chris@45
|
1895 } catch (DataFileReaderFactory::Exception e) {
|
Chris@45
|
1896 if (e == DataFileReaderFactory::ImportCancelled) {
|
Chris@45
|
1897 return FileOpenCancelled;
|
Chris@45
|
1898 }
|
Chris@45
|
1899 }
|
Chris@45
|
1900 }
|
Chris@45
|
1901
|
Chris@45
|
1902 return FileOpenFailed;
|
Chris@45
|
1903 }
|
Chris@45
|
1904
|
Chris@45
|
1905 MainWindowBase::FileOpenStatus
|
Chris@45
|
1906 MainWindowBase::openImage(FileSource source)
|
Chris@45
|
1907 {
|
Chris@233
|
1908 SVDEBUG << "MainWindowBase::openImage(" << source.getLocation() << ")" << endl;
|
Chris@135
|
1909
|
Chris@45
|
1910 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@45
|
1911
|
Chris@45
|
1912 if (!pane) {
|
Chris@595
|
1913 // shouldn't happen, as the menu action should have been disabled
|
Chris@595
|
1914 cerr << "WARNING: MainWindowBase::openImage: no current pane" << endl;
|
Chris@595
|
1915 return FileOpenWrongMode;
|
Chris@45
|
1916 }
|
Chris@45
|
1917
|
Chris@45
|
1918 if (!m_document->getMainModel()) {
|
Chris@45
|
1919 return FileOpenWrongMode;
|
Chris@45
|
1920 }
|
Chris@45
|
1921
|
Chris@45
|
1922 bool newLayer = false;
|
Chris@45
|
1923
|
Chris@45
|
1924 ImageLayer *il = dynamic_cast<ImageLayer *>(pane->getSelectedLayer());
|
Chris@45
|
1925 if (!il) {
|
Chris@45
|
1926 for (int i = pane->getLayerCount()-1; i >= 0; --i) {
|
Chris@45
|
1927 il = dynamic_cast<ImageLayer *>(pane->getLayer(i));
|
Chris@45
|
1928 if (il) break;
|
Chris@45
|
1929 }
|
Chris@45
|
1930 }
|
Chris@45
|
1931 if (!il) {
|
Chris@45
|
1932 il = dynamic_cast<ImageLayer *>
|
Chris@45
|
1933 (m_document->createEmptyLayer(LayerFactory::Image));
|
Chris@45
|
1934 if (!il) return FileOpenFailed;
|
Chris@45
|
1935 newLayer = true;
|
Chris@45
|
1936 }
|
Chris@45
|
1937
|
Chris@45
|
1938 // We don't put the image file in Recent Files
|
Chris@45
|
1939
|
Chris@293
|
1940 cerr << "openImage: trying location \"" << source.getLocation() << "\" in image layer" << endl;
|
Chris@45
|
1941
|
Chris@45
|
1942 if (!il->addImage(m_viewManager->getGlobalCentreFrame(), source.getLocation())) {
|
Chris@45
|
1943 if (newLayer) {
|
Chris@52
|
1944 m_document->deleteLayer(il); // also releases its model
|
Chris@45
|
1945 }
|
Chris@45
|
1946 return FileOpenFailed;
|
Chris@45
|
1947 } else {
|
Chris@45
|
1948 if (newLayer) {
|
Chris@45
|
1949 m_document->addLayerToView(pane, il);
|
Chris@45
|
1950 }
|
Chris@45
|
1951 m_paneStack->setCurrentLayer(pane, il);
|
Chris@45
|
1952 }
|
Chris@45
|
1953
|
Chris@45
|
1954 return FileOpenSucceeded;
|
Chris@45
|
1955 }
|
Chris@45
|
1956
|
Chris@45
|
1957 MainWindowBase::FileOpenStatus
|
Chris@427
|
1958 MainWindowBase::openDirOfAudio(QString dirPath)
|
Chris@427
|
1959 {
|
Chris@427
|
1960 QDir dir(dirPath);
|
Chris@427
|
1961 QStringList files = dir.entryList(QDir::Files | QDir::Readable);
|
Chris@427
|
1962 files.sort();
|
Chris@427
|
1963
|
Chris@427
|
1964 FileOpenStatus status = FileOpenFailed;
|
Chris@427
|
1965 bool first = true;
|
Chris@427
|
1966 bool cancelled = false;
|
Chris@427
|
1967
|
Chris@427
|
1968 foreach (QString file, files) {
|
Chris@427
|
1969
|
Chris@427
|
1970 FileSource source(dir.filePath(file));
|
Chris@427
|
1971 if (!source.isAvailable()) {
|
Chris@427
|
1972 continue;
|
Chris@427
|
1973 }
|
Chris@427
|
1974
|
Chris@427
|
1975 if (AudioFileReaderFactory::getKnownExtensions().contains
|
Chris@427
|
1976 (source.getExtension().toLower())) {
|
Chris@427
|
1977
|
Chris@427
|
1978 AudioFileOpenMode mode = CreateAdditionalModel;
|
Chris@427
|
1979 if (first) mode = ReplaceSession;
|
Chris@427
|
1980
|
Chris@427
|
1981 switch (openAudio(source, mode)) {
|
Chris@427
|
1982 case FileOpenSucceeded:
|
Chris@427
|
1983 status = FileOpenSucceeded;
|
Chris@427
|
1984 first = false;
|
Chris@427
|
1985 break;
|
Chris@427
|
1986 case FileOpenFailed:
|
Chris@427
|
1987 break;
|
Chris@427
|
1988 case FileOpenCancelled:
|
Chris@427
|
1989 cancelled = true;
|
Chris@427
|
1990 break;
|
Chris@427
|
1991 case FileOpenWrongMode:
|
Chris@427
|
1992 break;
|
Chris@427
|
1993 }
|
Chris@427
|
1994 }
|
Chris@427
|
1995
|
Chris@427
|
1996 if (cancelled) break;
|
Chris@427
|
1997 }
|
Chris@427
|
1998
|
Chris@427
|
1999 return status;
|
Chris@427
|
2000 }
|
Chris@427
|
2001
|
Chris@427
|
2002 MainWindowBase::FileOpenStatus
|
Chris@373
|
2003 MainWindowBase::openSessionPath(QString fileOrUrl)
|
Chris@45
|
2004 {
|
Chris@134
|
2005 ProgressDialog dialog(tr("Opening session..."), true, 2000, this);
|
Chris@134
|
2006 connect(&dialog, SIGNAL(showing()), this, SIGNAL(hideSplash()));
|
Chris@109
|
2007 return openSession(FileSource(fileOrUrl, &dialog));
|
Chris@45
|
2008 }
|
Chris@45
|
2009
|
Chris@45
|
2010 MainWindowBase::FileOpenStatus
|
Chris@45
|
2011 MainWindowBase::openSession(FileSource source)
|
Chris@45
|
2012 {
|
Chris@233
|
2013 SVDEBUG << "MainWindowBase::openSession(" << source.getLocation() << ")" << endl;
|
Chris@135
|
2014
|
Chris@45
|
2015 if (!source.isAvailable()) return FileOpenFailed;
|
Chris@145
|
2016 source.waitForData();
|
Chris@141
|
2017
|
Chris@341
|
2018 QString sessionExt =
|
Chris@341
|
2019 InteractiveFileFinder::getInstance()->getApplicationSessionExtension();
|
Chris@341
|
2020
|
Chris@341
|
2021 if (source.getExtension().toLower() != sessionExt) {
|
Chris@145
|
2022
|
Chris@145
|
2023 RDFImporter::RDFDocumentType rdfType =
|
Chris@145
|
2024 RDFImporter::identifyDocumentType
|
Chris@145
|
2025 (QUrl::fromLocalFile(source.getLocalFilename()).toString());
|
Chris@145
|
2026
|
Chris@293
|
2027 // cerr << "RDF type: " << (int)rdfType << endl;
|
Chris@148
|
2028
|
Chris@145
|
2029 if (rdfType == RDFImporter::AudioRefAndAnnotations ||
|
Chris@145
|
2030 rdfType == RDFImporter::AudioRef) {
|
Chris@145
|
2031 return openSessionFromRDF(source);
|
Chris@145
|
2032 } else if (rdfType != RDFImporter::NotRDF) {
|
Chris@145
|
2033 return FileOpenFailed;
|
Chris@145
|
2034 }
|
Chris@145
|
2035
|
Chris@152
|
2036 if (source.getExtension().toLower() == "xml") {
|
Chris@140
|
2037 if (SVFileReader::identifyXmlFile(source.getLocalFilename()) ==
|
Chris@140
|
2038 SVFileReader::SVSessionFile) {
|
Chris@293
|
2039 cerr << "This XML file looks like a session file, attempting to open it as a session" << endl;
|
Chris@140
|
2040 } else {
|
Chris@140
|
2041 return FileOpenFailed;
|
Chris@140
|
2042 }
|
Chris@140
|
2043 } else {
|
Chris@140
|
2044 return FileOpenFailed;
|
Chris@140
|
2045 }
|
Chris@140
|
2046 }
|
Chris@45
|
2047
|
Chris@140
|
2048 QXmlInputSource *inputSource = 0;
|
Chris@140
|
2049 BZipFileDevice *bzFile = 0;
|
Chris@140
|
2050 QFile *rawFile = 0;
|
Chris@140
|
2051
|
Chris@341
|
2052 if (source.getExtension().toLower() == sessionExt) {
|
Chris@140
|
2053 bzFile = new BZipFileDevice(source.getLocalFilename());
|
Chris@140
|
2054 if (!bzFile->open(QIODevice::ReadOnly)) {
|
Chris@140
|
2055 delete bzFile;
|
Chris@140
|
2056 return FileOpenFailed;
|
Chris@140
|
2057 }
|
Chris@140
|
2058 inputSource = new QXmlInputSource(bzFile);
|
Chris@140
|
2059 } else {
|
Chris@140
|
2060 rawFile = new QFile(source.getLocalFilename());
|
Chris@140
|
2061 inputSource = new QXmlInputSource(rawFile);
|
Chris@140
|
2062 }
|
Chris@140
|
2063
|
Chris@140
|
2064 if (!checkSaveModified()) {
|
Chris@140
|
2065 if (bzFile) bzFile->close();
|
Chris@140
|
2066 delete inputSource;
|
Chris@140
|
2067 delete bzFile;
|
Chris@140
|
2068 delete rawFile;
|
Chris@140
|
2069 return FileOpenCancelled;
|
Chris@140
|
2070 }
|
Chris@45
|
2071
|
Chris@45
|
2072 QString error;
|
Chris@45
|
2073 closeSession();
|
Chris@45
|
2074 createDocument();
|
Chris@45
|
2075
|
Chris@45
|
2076 PaneCallback callback(this);
|
Chris@45
|
2077 m_viewManager->clearSelections();
|
Chris@45
|
2078
|
Chris@45
|
2079 SVFileReader reader(m_document, callback, source.getLocation());
|
Chris@79
|
2080 connect
|
Chris@79
|
2081 (&reader, SIGNAL(modelRegenerationFailed(QString, QString, QString)),
|
Chris@79
|
2082 this, SLOT(modelRegenerationFailed(QString, QString, QString)));
|
Chris@79
|
2083 connect
|
Chris@79
|
2084 (&reader, SIGNAL(modelRegenerationWarning(QString, QString, QString)),
|
Chris@79
|
2085 this, SLOT(modelRegenerationWarning(QString, QString, QString)));
|
Chris@140
|
2086
|
Chris@140
|
2087 reader.parse(*inputSource);
|
Chris@45
|
2088
|
Chris@45
|
2089 if (!reader.isOK()) {
|
Chris@45
|
2090 error = tr("SV XML file read error:\n%1").arg(reader.getErrorString());
|
Chris@45
|
2091 }
|
Chris@45
|
2092
|
Chris@140
|
2093 if (bzFile) bzFile->close();
|
Chris@140
|
2094
|
Chris@140
|
2095 delete inputSource;
|
Chris@140
|
2096 delete bzFile;
|
Chris@140
|
2097 delete rawFile;
|
Chris@45
|
2098
|
Chris@45
|
2099 bool ok = (error == "");
|
Chris@45
|
2100
|
Chris@45
|
2101 if (ok) {
|
Chris@45
|
2102
|
Chris@164
|
2103 emit activity(tr("Import session file \"%1\"").arg(source.getLocation()));
|
Chris@164
|
2104
|
Chris@595
|
2105 setWindowTitle(tr("%1: %2")
|
Chris@57
|
2106 .arg(QApplication::applicationName())
|
Chris@595
|
2107 .arg(source.getLocation()));
|
Chris@595
|
2108
|
Chris@601
|
2109 if (!source.isRemote() && !m_document->isIncomplete()) {
|
Chris@601
|
2110 // Setting the session file path enables the Save (as
|
Chris@601
|
2111 // opposed to Save As...) option. We can't do this if we
|
Chris@601
|
2112 // don't have a local path to save to, but we also don't
|
Chris@601
|
2113 // want to do it if we failed to find an audio file or
|
Chris@601
|
2114 // similar on load, as the audio reference would then end
|
Chris@601
|
2115 // up being lost from any saved or auto-saved-on-exit copy
|
Chris@601
|
2116 m_sessionFile = source.getLocalFilename();
|
Chris@602
|
2117 } else {
|
Chris@602
|
2118 QMessageBox::warning
|
Chris@602
|
2119 (this,
|
Chris@602
|
2120 tr("Incomplete session loaded"),
|
Chris@603
|
2121 tr("Some of the audio content referred to by the original session file could not be loaded.\nIf you save this session, it will be saved without any reference to that audio, and information may be lost."),
|
Chris@602
|
2122 QMessageBox::Ok);
|
Chris@601
|
2123 }
|
Chris@595
|
2124
|
Chris@595
|
2125 setupMenus();
|
Chris@577
|
2126 findTimeRulerLayer();
|
Chris@45
|
2127
|
Chris@595
|
2128 CommandHistory::getInstance()->clear();
|
Chris@595
|
2129 CommandHistory::getInstance()->documentSaved();
|
Chris@595
|
2130 m_documentModified = false;
|
Chris@595
|
2131 updateMenuStates();
|
Chris@45
|
2132
|
Chris@227
|
2133 m_recentFiles.addFile(source.getLocation());
|
Chris@45
|
2134
|
Chris@45
|
2135 if (!source.isRemote()) {
|
Chris@45
|
2136 // for file dialog
|
Chris@45
|
2137 registerLastOpenedFilePath(FileFinder::SessionFile,
|
Chris@227
|
2138 source.getLocalFilename());
|
Chris@45
|
2139 }
|
Chris@45
|
2140
|
Chris@342
|
2141 emit sessionLoaded();
|
Chris@342
|
2142
|
Chris@45
|
2143 } else {
|
Chris@595
|
2144 setWindowTitle(QApplication::applicationName());
|
Chris@45
|
2145 }
|
Chris@45
|
2146
|
Chris@45
|
2147 return ok ? FileOpenSucceeded : FileOpenFailed;
|
Chris@45
|
2148 }
|
Chris@45
|
2149
|
Chris@141
|
2150 MainWindowBase::FileOpenStatus
|
Chris@230
|
2151 MainWindowBase::openSessionTemplate(QString templateName)
|
Chris@230
|
2152 {
|
Chris@230
|
2153 // Template in the user's template directory takes
|
Chris@230
|
2154 // priority over a bundled one; we don't unbundle, but
|
Chris@230
|
2155 // open directly from the bundled file (where applicable)
|
Chris@230
|
2156 ResourceFinder rf;
|
Chris@230
|
2157 QString tfile = rf.getResourcePath("templates", templateName + ".svt");
|
Chris@230
|
2158 if (tfile != "") {
|
Chris@294
|
2159 cerr << "SV loading template file " << tfile << endl;
|
Chris@230
|
2160 return openSessionTemplate(FileSource("file:" + tfile));
|
Chris@230
|
2161 } else {
|
Chris@230
|
2162 return FileOpenFailed;
|
Chris@230
|
2163 }
|
Chris@230
|
2164 }
|
Chris@230
|
2165
|
Chris@230
|
2166 MainWindowBase::FileOpenStatus
|
Chris@227
|
2167 MainWindowBase::openSessionTemplate(FileSource source)
|
Chris@227
|
2168 {
|
Chris@294
|
2169 cerr << "MainWindowBase::openSessionTemplate(" << source.getLocation() << ")" << endl;
|
Chris@227
|
2170
|
Chris@227
|
2171 if (!source.isAvailable()) return FileOpenFailed;
|
Chris@227
|
2172 source.waitForData();
|
Chris@227
|
2173
|
Chris@227
|
2174 QXmlInputSource *inputSource = 0;
|
Chris@227
|
2175 QFile *file = 0;
|
Chris@227
|
2176
|
Chris@227
|
2177 file = new QFile(source.getLocalFilename());
|
Chris@227
|
2178 inputSource = new QXmlInputSource(file);
|
Chris@227
|
2179
|
Chris@227
|
2180 if (!checkSaveModified()) {
|
Chris@227
|
2181 delete inputSource;
|
Chris@227
|
2182 delete file;
|
Chris@227
|
2183 return FileOpenCancelled;
|
Chris@227
|
2184 }
|
Chris@227
|
2185
|
Chris@227
|
2186 QString error;
|
Chris@227
|
2187 closeSession();
|
Chris@227
|
2188 createDocument();
|
Chris@227
|
2189
|
Chris@227
|
2190 PaneCallback callback(this);
|
Chris@227
|
2191 m_viewManager->clearSelections();
|
Chris@227
|
2192
|
Chris@227
|
2193 SVFileReader reader(m_document, callback, source.getLocation());
|
Chris@227
|
2194 connect
|
Chris@227
|
2195 (&reader, SIGNAL(modelRegenerationFailed(QString, QString, QString)),
|
Chris@227
|
2196 this, SLOT(modelRegenerationFailed(QString, QString, QString)));
|
Chris@227
|
2197 connect
|
Chris@227
|
2198 (&reader, SIGNAL(modelRegenerationWarning(QString, QString, QString)),
|
Chris@227
|
2199 this, SLOT(modelRegenerationWarning(QString, QString, QString)));
|
Chris@227
|
2200
|
Chris@227
|
2201 reader.parse(*inputSource);
|
Chris@227
|
2202
|
Chris@227
|
2203 if (!reader.isOK()) {
|
Chris@227
|
2204 error = tr("SV XML file read error:\n%1").arg(reader.getErrorString());
|
Chris@227
|
2205 }
|
Chris@227
|
2206
|
Chris@227
|
2207 delete inputSource;
|
Chris@227
|
2208 delete file;
|
Chris@227
|
2209
|
Chris@227
|
2210 bool ok = (error == "");
|
Chris@227
|
2211
|
Chris@227
|
2212 setWindowTitle(QApplication::applicationName());
|
Chris@227
|
2213
|
Chris@227
|
2214 if (ok) {
|
Chris@227
|
2215
|
Chris@227
|
2216 emit activity(tr("Open session template \"%1\"").arg(source.getLocation()));
|
Chris@227
|
2217
|
Chris@595
|
2218 setupMenus();
|
Chris@577
|
2219 findTimeRulerLayer();
|
Chris@227
|
2220
|
Chris@595
|
2221 CommandHistory::getInstance()->clear();
|
Chris@595
|
2222 CommandHistory::getInstance()->documentSaved();
|
Chris@595
|
2223 m_documentModified = false;
|
Chris@595
|
2224 updateMenuStates();
|
Chris@342
|
2225
|
Chris@342
|
2226 emit sessionLoaded();
|
Chris@227
|
2227 }
|
Chris@227
|
2228
|
Chris@227
|
2229 return ok ? FileOpenSucceeded : FileOpenFailed;
|
Chris@227
|
2230 }
|
Chris@227
|
2231
|
Chris@227
|
2232 MainWindowBase::FileOpenStatus
|
Chris@141
|
2233 MainWindowBase::openSessionFromRDF(FileSource source)
|
Chris@141
|
2234 {
|
Chris@233
|
2235 SVDEBUG << "MainWindowBase::openSessionFromRDF(" << source.getLocation() << ")" << endl;
|
Chris@141
|
2236
|
Chris@141
|
2237 if (!source.isAvailable()) return FileOpenFailed;
|
Chris@141
|
2238 source.waitForData();
|
Chris@141
|
2239
|
Chris@145
|
2240 if (!checkSaveModified()) {
|
Chris@145
|
2241 return FileOpenCancelled;
|
Chris@141
|
2242 }
|
Chris@143
|
2243
|
Chris@145
|
2244 closeSession();
|
Chris@145
|
2245 createDocument();
|
Chris@145
|
2246
|
Chris@145
|
2247 FileOpenStatus status = openLayersFromRDF(source);
|
Chris@141
|
2248
|
Chris@141
|
2249 setupMenus();
|
Chris@577
|
2250 findTimeRulerLayer();
|
Chris@141
|
2251
|
Chris@141
|
2252 setWindowTitle(tr("%1: %2")
|
Chris@141
|
2253 .arg(QApplication::applicationName())
|
Chris@141
|
2254 .arg(source.getLocation()));
|
Chris@141
|
2255 CommandHistory::getInstance()->clear();
|
Chris@141
|
2256 CommandHistory::getInstance()->documentSaved();
|
Chris@141
|
2257 m_documentModified = false;
|
Chris@145
|
2258
|
Chris@342
|
2259 emit sessionLoaded();
|
Chris@342
|
2260
|
Chris@145
|
2261 return status;
|
Chris@145
|
2262 }
|
Chris@145
|
2263
|
Chris@145
|
2264 MainWindowBase::FileOpenStatus
|
Chris@145
|
2265 MainWindowBase::openLayersFromRDF(FileSource source)
|
Chris@145
|
2266 {
|
Chris@435
|
2267 sv_samplerate_t rate = 0;
|
Chris@145
|
2268
|
Chris@233
|
2269 SVDEBUG << "MainWindowBase::openLayersFromRDF" << endl;
|
Chris@186
|
2270
|
Chris@145
|
2271 ProgressDialog dialog(tr("Importing from RDF..."), true, 2000, this);
|
Chris@145
|
2272 connect(&dialog, SIGNAL(showing()), this, SIGNAL(hideSplash()));
|
Chris@145
|
2273
|
Chris@145
|
2274 if (getMainModel()) {
|
Chris@145
|
2275 rate = getMainModel()->getSampleRate();
|
Chris@145
|
2276 } else if (Preferences::getInstance()->getResampleOnLoad()) {
|
Chris@552
|
2277 if (getMainModel()) {
|
Chris@552
|
2278 rate = getMainModel()->getSampleRate();
|
Chris@552
|
2279 }
|
Chris@145
|
2280 }
|
Chris@145
|
2281
|
Chris@145
|
2282 RDFImporter importer
|
Chris@145
|
2283 (QUrl::fromLocalFile(source.getLocalFilename()).toString(), rate);
|
Chris@145
|
2284
|
Chris@145
|
2285 if (!importer.isOK()) {
|
Chris@147
|
2286 if (importer.getErrorString() != "") {
|
Chris@147
|
2287 QMessageBox::critical
|
Chris@147
|
2288 (this, tr("Failed to import RDF"),
|
Chris@147
|
2289 tr("<b>Failed to import RDF</b><p>Importing data from RDF document at \"%1\" failed: %2</p>")
|
Chris@147
|
2290 .arg(source.getLocation()).arg(importer.getErrorString()));
|
Chris@147
|
2291 }
|
Chris@145
|
2292 return FileOpenFailed;
|
Chris@145
|
2293 }
|
Chris@145
|
2294
|
Chris@145
|
2295 std::vector<Model *> models = importer.getDataModels(&dialog);
|
Chris@145
|
2296
|
Chris@145
|
2297 dialog.setMessage(tr("Importing from RDF..."));
|
Chris@145
|
2298
|
Chris@145
|
2299 if (models.empty()) {
|
Chris@186
|
2300 QMessageBox::critical
|
Chris@186
|
2301 (this, tr("Failed to import RDF"),
|
Chris@186
|
2302 tr("<b>Failed to import RDF</b><p>No suitable data models found for import from RDF document at \"%1\"</p>").arg(source.getLocation()));
|
Chris@145
|
2303 return FileOpenFailed;
|
Chris@145
|
2304 }
|
Chris@145
|
2305
|
Chris@164
|
2306 emit activity(tr("Import RDF document \"%1\"").arg(source.getLocation()));
|
Chris@164
|
2307
|
Chris@145
|
2308 std::set<Model *> added;
|
Chris@145
|
2309
|
Chris@221
|
2310 for (int i = 0; i < (int)models.size(); ++i) {
|
Chris@145
|
2311
|
Chris@145
|
2312 Model *m = models[i];
|
Chris@145
|
2313 WaveFileModel *w = dynamic_cast<WaveFileModel *>(m);
|
Chris@145
|
2314
|
Chris@145
|
2315 if (w) {
|
Chris@145
|
2316
|
Chris@145
|
2317 Pane *pane = addPaneToStack();
|
Chris@145
|
2318 Layer *layer = 0;
|
Chris@145
|
2319
|
Chris@145
|
2320 if (m_timeRulerLayer) {
|
Chris@145
|
2321 m_document->addLayerToView(pane, m_timeRulerLayer);
|
Chris@145
|
2322 }
|
Chris@145
|
2323
|
Chris@145
|
2324 if (!getMainModel()) {
|
Chris@145
|
2325 m_document->setMainModel(w);
|
Chris@145
|
2326 layer = m_document->createMainModelLayer(LayerFactory::Waveform);
|
Chris@145
|
2327 } else {
|
Chris@145
|
2328 layer = m_document->createImportedLayer(w);
|
Chris@145
|
2329 }
|
Chris@145
|
2330
|
Chris@145
|
2331 m_document->addLayerToView(pane, layer);
|
Chris@145
|
2332
|
Chris@145
|
2333 added.insert(w);
|
Chris@145
|
2334
|
Chris@221
|
2335 for (int j = 0; j < (int)models.size(); ++j) {
|
Chris@145
|
2336
|
Chris@145
|
2337 Model *dm = models[j];
|
Chris@145
|
2338
|
Chris@145
|
2339 if (dm == m) continue;
|
Chris@145
|
2340 if (dm->getSourceModel() != m) continue;
|
Chris@145
|
2341
|
Chris@145
|
2342 layer = m_document->createImportedLayer(dm);
|
Chris@145
|
2343
|
Chris@145
|
2344 if (layer->isLayerOpaque() ||
|
Chris@145
|
2345 dynamic_cast<Colour3DPlotLayer *>(layer)) {
|
Chris@145
|
2346
|
Chris@156
|
2347 // these always go in a new pane, with nothing
|
Chris@156
|
2348 // else going in the same pane
|
Chris@156
|
2349
|
Chris@145
|
2350 Pane *singleLayerPane = addPaneToStack();
|
Chris@145
|
2351 if (m_timeRulerLayer) {
|
Chris@145
|
2352 m_document->addLayerToView(singleLayerPane, m_timeRulerLayer);
|
Chris@145
|
2353 }
|
Chris@145
|
2354 m_document->addLayerToView(singleLayerPane, layer);
|
Chris@145
|
2355
|
Chris@156
|
2356 } else if (layer->getLayerColourSignificance() ==
|
Chris@156
|
2357 Layer::ColourHasMeaningfulValue) {
|
Chris@156
|
2358
|
Chris@156
|
2359 // these can go in a pane with something else, but
|
Chris@156
|
2360 // only if none of the something elses also have
|
Chris@156
|
2361 // this quality
|
Chris@156
|
2362
|
Chris@156
|
2363 bool needNewPane = false;
|
Chris@156
|
2364 for (int i = 0; i < pane->getLayerCount(); ++i) {
|
Chris@156
|
2365 Layer *otherLayer = pane->getLayer(i);
|
Chris@156
|
2366 if (otherLayer &&
|
Chris@156
|
2367 (otherLayer->getLayerColourSignificance() ==
|
Chris@156
|
2368 Layer::ColourHasMeaningfulValue)) {
|
Chris@156
|
2369 needNewPane = true;
|
Chris@156
|
2370 break;
|
Chris@156
|
2371 }
|
Chris@156
|
2372 }
|
Chris@156
|
2373 if (needNewPane) {
|
Chris@156
|
2374 pane = addPaneToStack();
|
Chris@156
|
2375 }
|
Chris@156
|
2376
|
Chris@156
|
2377 m_document->addLayerToView(pane, layer);
|
Chris@156
|
2378
|
Chris@145
|
2379 } else {
|
Chris@145
|
2380
|
Chris@145
|
2381 if (pane->getLayerCount() > 4) {
|
Chris@145
|
2382 pane = addPaneToStack();
|
Chris@145
|
2383 }
|
Chris@145
|
2384
|
Chris@145
|
2385 m_document->addLayerToView(pane, layer);
|
Chris@145
|
2386 }
|
Chris@145
|
2387
|
Chris@145
|
2388 added.insert(dm);
|
Chris@145
|
2389 }
|
Chris@145
|
2390 }
|
Chris@145
|
2391 }
|
Chris@145
|
2392
|
Chris@221
|
2393 for (int i = 0; i < (int)models.size(); ++i) {
|
Chris@145
|
2394
|
Chris@145
|
2395 Model *m = models[i];
|
Chris@145
|
2396
|
Chris@145
|
2397 if (added.find(m) == added.end()) {
|
Chris@145
|
2398
|
Chris@145
|
2399 Layer *layer = m_document->createImportedLayer(m);
|
Chris@145
|
2400 if (!layer) return FileOpenFailed;
|
Chris@145
|
2401
|
Chris@145
|
2402 Pane *singleLayerPane = addPaneToStack();
|
Chris@145
|
2403 if (m_timeRulerLayer) {
|
Chris@145
|
2404 m_document->addLayerToView(singleLayerPane, m_timeRulerLayer);
|
Chris@145
|
2405 }
|
Chris@145
|
2406 m_document->addLayerToView(singleLayerPane, layer);
|
Chris@145
|
2407 }
|
Chris@145
|
2408 }
|
Chris@145
|
2409
|
Chris@145
|
2410 m_recentFiles.addFile(source.getLocation());
|
Chris@145
|
2411 return FileOpenSucceeded;
|
Chris@141
|
2412 }
|
Chris@141
|
2413
|
Chris@584
|
2414 class AudioLogCallback : public breakfastquay::AudioFactory::LogCallback
|
Chris@584
|
2415 {
|
Chris@584
|
2416 public:
|
Chris@584
|
2417 void log(std::string message) const override {
|
Chris@584
|
2418 SVDEBUG << message << endl;
|
Chris@584
|
2419 }
|
Chris@584
|
2420 };
|
Chris@584
|
2421
|
Chris@45
|
2422 void
|
Chris@475
|
2423 MainWindowBase::createAudioIO()
|
Chris@45
|
2424 {
|
Chris@475
|
2425 if (m_playTarget || m_audioIO) return;
|
Chris@475
|
2426
|
Chris@584
|
2427 static AudioLogCallback audioLogCallback;
|
Chris@584
|
2428 breakfastquay::AudioFactory::setLogCallback(&audioLogCallback);
|
Chris@584
|
2429
|
Chris@475
|
2430 if (!(m_soundOptions & WithAudioOutput)) return;
|
Chris@45
|
2431
|
Chris@126
|
2432 QSettings settings;
|
Chris@126
|
2433 settings.beginGroup("Preferences");
|
Chris@547
|
2434 QString implementation = settings.value
|
Chris@547
|
2435 ("audio-target", "").toString();
|
Chris@547
|
2436 QString suffix;
|
Chris@547
|
2437 if (implementation != "") suffix = "-" + implementation;
|
Chris@547
|
2438 QString recordDevice = settings.value
|
Chris@547
|
2439 ("audio-record-device" + suffix, "").toString();
|
Chris@547
|
2440 QString playbackDevice = settings.value
|
Chris@547
|
2441 ("audio-playback-device" + suffix, "").toString();
|
Chris@126
|
2442 settings.endGroup();
|
Chris@547
|
2443
|
Chris@547
|
2444 if (implementation == "auto") {
|
Chris@547
|
2445 implementation = "";
|
Chris@547
|
2446 }
|
Chris@468
|
2447
|
Chris@547
|
2448 breakfastquay::AudioFactory::Preference preference;
|
Chris@547
|
2449 preference.implementation = implementation.toStdString();
|
Chris@547
|
2450 preference.recordDevice = recordDevice.toStdString();
|
Chris@547
|
2451 preference.playbackDevice = playbackDevice.toStdString();
|
Chris@547
|
2452
|
Chris@547
|
2453 SVCERR << "createAudioIO: Preferred implementation = \""
|
Chris@547
|
2454 << preference.implementation << "\"" << endl;
|
Chris@547
|
2455 SVCERR << "createAudioIO: Preferred playback device = \""
|
Chris@547
|
2456 << preference.playbackDevice << "\"" << endl;
|
Chris@547
|
2457 SVCERR << "createAudioIO: Preferred record device = \""
|
Chris@547
|
2458 << preference.recordDevice << "\"" << endl;
|
Chris@475
|
2459
|
Chris@551
|
2460 if (!m_resamplerWrapper) {
|
Chris@551
|
2461 m_resamplerWrapper = new breakfastquay::ResamplerWrapper(m_playSource);
|
Chris@551
|
2462 m_playSource->setResamplerWrapper(m_resamplerWrapper);
|
Chris@551
|
2463 }
|
Chris@569
|
2464
|
Chris@569
|
2465 std::string errorString;
|
Chris@551
|
2466
|
Chris@475
|
2467 if (m_soundOptions & WithAudioInput) {
|
Chris@475
|
2468 m_audioIO = breakfastquay::AudioFactory::
|
Chris@569
|
2469 createCallbackIO(m_recordTarget, m_resamplerWrapper,
|
Chris@569
|
2470 preference, errorString);
|
Chris@525
|
2471 if (m_audioIO) {
|
Chris@611
|
2472 SVCERR << "MainWindowBase::createAudioIO: Suspending on creation" << endl;
|
Chris@525
|
2473 m_audioIO->suspend(); // start in suspended state
|
Chris@525
|
2474 m_playSource->setSystemPlaybackTarget(m_audioIO);
|
Chris@586
|
2475 } else {
|
Chris@586
|
2476 // Failed to create audio I/O; this may just mean there is
|
Chris@586
|
2477 // no record device, so fall through to see what happens
|
Chris@586
|
2478 // next. We only report complete failure if we end up with
|
Chris@586
|
2479 // neither m_audioIO nor m_playTarget.
|
Chris@525
|
2480 }
|
Chris@586
|
2481 }
|
Chris@586
|
2482
|
Chris@586
|
2483 if (!m_audioIO) {
|
Chris@475
|
2484 m_playTarget = breakfastquay::AudioFactory::
|
Chris@569
|
2485 createCallbackPlayTarget(m_resamplerWrapper,
|
Chris@569
|
2486 preference, errorString);
|
Chris@525
|
2487 if (m_playTarget) {
|
Chris@611
|
2488 SVCERR << "MainWindowBase::createAudioIO: Suspending on creation" << endl;
|
Chris@525
|
2489 m_playTarget->suspend(); // start in suspended state
|
Chris@525
|
2490 m_playSource->setSystemPlaybackTarget(m_playTarget);
|
Chris@525
|
2491 }
|
Chris@475
|
2492 }
|
Chris@475
|
2493
|
Chris@475
|
2494 if (!m_playTarget && !m_audioIO) {
|
Chris@104
|
2495 emit hideSplash();
|
Chris@569
|
2496 QString message;
|
Chris@569
|
2497 QString error = errorString.c_str();
|
Chris@569
|
2498 QString firstBit, secondBit;
|
Chris@547
|
2499 if (implementation == "") {
|
Chris@569
|
2500 if (error == "") {
|
Chris@569
|
2501 firstBit = tr("<b>No audio available</b><p>Could not open an audio device.</p>");
|
Chris@569
|
2502 } else {
|
Chris@569
|
2503 firstBit = tr("<b>No audio available</b><p>Could not open audio device: %1</p>").arg(error);
|
Chris@569
|
2504 }
|
Chris@569
|
2505 if (m_soundOptions & WithAudioInput) {
|
Chris@569
|
2506 secondBit = tr("<p>Automatic audio device detection failed. Audio playback and recording will not be available during this session.</p>");
|
Chris@569
|
2507 } else {
|
Chris@569
|
2508 secondBit = tr("<p>Automatic audio device detection failed. Audio playback will not be available during this session.</p>");
|
Chris@569
|
2509 }
|
Chris@126
|
2510 } else {
|
Chris@569
|
2511 QString driverName = breakfastquay::AudioFactory::
|
Chris@569
|
2512 getImplementationDescription(implementation.toStdString())
|
Chris@569
|
2513 .c_str();
|
Chris@569
|
2514 if (error == "") {
|
Chris@569
|
2515 firstBit = tr("<b>No audio available</b><p>Failed to open your preferred audio driver (\"%1\").</p>").arg(driverName);
|
Chris@569
|
2516 } else {
|
Chris@569
|
2517 firstBit = tr("<b>No audio available</b><p>Failed to open your preferred audio driver (\"%1\"): %2.</p>").arg(driverName).arg(error);
|
Chris@569
|
2518 }
|
Chris@569
|
2519 if (m_soundOptions & WithAudioInput) {
|
Chris@569
|
2520 secondBit = tr("<p>Audio playback and recording will not be available during this session.</p>");
|
Chris@569
|
2521 } else {
|
Chris@569
|
2522 secondBit = tr("<p>Audio playback will not be available during this session.</p>");
|
Chris@569
|
2523 }
|
Chris@126
|
2524 }
|
Chris@570
|
2525 SVDEBUG << "createAudioIO: ERROR: Failed to open audio device \""
|
Chris@570
|
2526 << implementation << "\": error is: " << error << endl;
|
Chris@569
|
2527 QMessageBox::warning(this, tr("Couldn't open audio device"),
|
Chris@569
|
2528 firstBit + secondBit, QMessageBox::Ok);
|
Chris@45
|
2529 }
|
Chris@45
|
2530 }
|
Chris@45
|
2531
|
Chris@556
|
2532 void
|
Chris@556
|
2533 MainWindowBase::deleteAudioIO()
|
Chris@556
|
2534 {
|
Chris@556
|
2535 // First prevent this trying to call target.
|
Chris@559
|
2536 if (m_playSource) {
|
Chris@559
|
2537 m_playSource->setSystemPlaybackTarget(0);
|
Chris@559
|
2538 m_playSource->setResamplerWrapper(0);
|
Chris@559
|
2539 }
|
Chris@556
|
2540
|
Chris@556
|
2541 // Then delete the breakfastquay::System object.
|
Chris@556
|
2542 // Only one of these two exists!
|
Chris@556
|
2543 delete m_audioIO;
|
Chris@556
|
2544 delete m_playTarget;
|
Chris@556
|
2545
|
Chris@559
|
2546 // And the breakfastquay resampler wrapper. We need to
|
Chris@559
|
2547 // delete/recreate this if the channel count changes, which is one
|
Chris@559
|
2548 // of the use cases for recreateAudioIO() calling this
|
Chris@559
|
2549 delete m_resamplerWrapper;
|
Chris@559
|
2550
|
Chris@556
|
2551 m_audioIO = 0;
|
Chris@556
|
2552 m_playTarget = 0;
|
Chris@559
|
2553 m_resamplerWrapper = 0;
|
Chris@556
|
2554 }
|
Chris@556
|
2555
|
Chris@556
|
2556 void
|
Chris@556
|
2557 MainWindowBase::recreateAudioIO()
|
Chris@556
|
2558 {
|
Chris@556
|
2559 deleteAudioIO();
|
Chris@556
|
2560 createAudioIO();
|
Chris@556
|
2561 }
|
Chris@556
|
2562
|
Chris@570
|
2563 void
|
Chris@570
|
2564 MainWindowBase::audioChannelCountIncreased(int)
|
Chris@570
|
2565 {
|
Chris@611
|
2566 SVCERR << "MainWindowBase::audioChannelCountIncreased" << endl;
|
Chris@570
|
2567 recreateAudioIO();
|
Chris@610
|
2568
|
Chris@610
|
2569 if (m_recordTarget &&
|
Chris@610
|
2570 m_recordTarget->isRecording() &&
|
Chris@610
|
2571 m_audioIO) {
|
Chris@610
|
2572 SVCERR << "MainWindowBase::audioChannelCountIncreased: we were recording already, so resuming IO now" << endl;
|
Chris@610
|
2573 m_audioIO->resume();
|
Chris@610
|
2574 }
|
Chris@570
|
2575 }
|
Chris@570
|
2576
|
Chris@45
|
2577 WaveFileModel *
|
Chris@45
|
2578 MainWindowBase::getMainModel()
|
Chris@45
|
2579 {
|
Chris@45
|
2580 if (!m_document) return 0;
|
Chris@45
|
2581 return m_document->getMainModel();
|
Chris@45
|
2582 }
|
Chris@45
|
2583
|
Chris@45
|
2584 const WaveFileModel *
|
Chris@45
|
2585 MainWindowBase::getMainModel() const
|
Chris@45
|
2586 {
|
Chris@45
|
2587 if (!m_document) return 0;
|
Chris@45
|
2588 return m_document->getMainModel();
|
Chris@45
|
2589 }
|
Chris@45
|
2590
|
Chris@45
|
2591 void
|
Chris@45
|
2592 MainWindowBase::createDocument()
|
Chris@45
|
2593 {
|
Chris@45
|
2594 m_document = new Document;
|
Chris@45
|
2595
|
Chris@45
|
2596 connect(m_document, SIGNAL(layerAdded(Layer *)),
|
Chris@595
|
2597 this, SLOT(layerAdded(Layer *)));
|
Chris@45
|
2598 connect(m_document, SIGNAL(layerRemoved(Layer *)),
|
Chris@595
|
2599 this, SLOT(layerRemoved(Layer *)));
|
Chris@45
|
2600 connect(m_document, SIGNAL(layerAboutToBeDeleted(Layer *)),
|
Chris@595
|
2601 this, SLOT(layerAboutToBeDeleted(Layer *)));
|
Chris@45
|
2602 connect(m_document, SIGNAL(layerInAView(Layer *, bool)),
|
Chris@595
|
2603 this, SLOT(layerInAView(Layer *, bool)));
|
Chris@45
|
2604
|
Chris@45
|
2605 connect(m_document, SIGNAL(modelAdded(Model *)),
|
Chris@595
|
2606 this, SLOT(modelAdded(Model *)));
|
Chris@45
|
2607 connect(m_document, SIGNAL(mainModelChanged(WaveFileModel *)),
|
Chris@595
|
2608 this, SLOT(mainModelChanged(WaveFileModel *)));
|
Chris@45
|
2609 connect(m_document, SIGNAL(modelAboutToBeDeleted(Model *)),
|
Chris@595
|
2610 this, SLOT(modelAboutToBeDeleted(Model *)));
|
Chris@45
|
2611
|
Chris@78
|
2612 connect(m_document, SIGNAL(modelGenerationFailed(QString, QString)),
|
Chris@78
|
2613 this, SLOT(modelGenerationFailed(QString, QString)));
|
Chris@78
|
2614 connect(m_document, SIGNAL(modelRegenerationWarning(QString, QString, QString)),
|
Chris@78
|
2615 this, SLOT(modelRegenerationWarning(QString, QString, QString)));
|
Chris@429
|
2616 connect(m_document, SIGNAL(alignmentComplete(AlignmentModel *)),
|
Chris@429
|
2617 this, SLOT(alignmentComplete(AlignmentModel *)));
|
Chris@423
|
2618 connect(m_document, SIGNAL(alignmentFailed(QString)),
|
Chris@423
|
2619 this, SLOT(alignmentFailed(QString)));
|
Chris@160
|
2620
|
Chris@160
|
2621 emit replacedDocument();
|
Chris@45
|
2622 }
|
Chris@45
|
2623
|
Chris@45
|
2624 bool
|
Chris@45
|
2625 MainWindowBase::saveSessionFile(QString path)
|
Chris@45
|
2626 {
|
Chris@217
|
2627 try {
|
Chris@217
|
2628
|
Chris@217
|
2629 TempWriteFile temp(path);
|
Chris@217
|
2630
|
Chris@217
|
2631 BZipFileDevice bzFile(temp.getTemporaryFilename());
|
Chris@217
|
2632 if (!bzFile.open(QIODevice::WriteOnly)) {
|
Chris@293
|
2633 cerr << "Failed to open session file \""
|
Chris@294
|
2634 << temp.getTemporaryFilename()
|
Chris@217
|
2635 << "\" for writing: "
|
Chris@293
|
2636 << bzFile.errorString() << endl;
|
Chris@217
|
2637 return false;
|
Chris@217
|
2638 }
|
Chris@217
|
2639
|
Chris@217
|
2640 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
Chris@217
|
2641
|
Chris@217
|
2642 QTextStream out(&bzFile);
|
Chris@432
|
2643 out.setCodec(QTextCodec::codecForName("UTF-8"));
|
Chris@226
|
2644 toXml(out, false);
|
Chris@217
|
2645 out.flush();
|
Chris@217
|
2646
|
Chris@217
|
2647 QApplication::restoreOverrideCursor();
|
Chris@217
|
2648
|
Chris@217
|
2649 if (!bzFile.isOK()) {
|
Chris@217
|
2650 QMessageBox::critical(this, tr("Failed to write file"),
|
Chris@217
|
2651 tr("<b>Save failed</b><p>Failed to write to file \"%1\": %2")
|
Chris@217
|
2652 .arg(path).arg(bzFile.errorString()));
|
Chris@217
|
2653 bzFile.close();
|
Chris@217
|
2654 return false;
|
Chris@217
|
2655 }
|
Chris@217
|
2656
|
Chris@217
|
2657 bzFile.close();
|
Chris@217
|
2658 temp.moveToTarget();
|
Chris@217
|
2659 return true;
|
Chris@217
|
2660
|
Chris@217
|
2661 } catch (FileOperationFailed &f) {
|
Chris@217
|
2662
|
Chris@217
|
2663 QMessageBox::critical(this, tr("Failed to write file"),
|
Chris@217
|
2664 tr("<b>Save failed</b><p>Failed to write to file \"%1\": %2")
|
Chris@217
|
2665 .arg(path).arg(f.what()));
|
Chris@45
|
2666 return false;
|
Chris@45
|
2667 }
|
Chris@45
|
2668 }
|
Chris@45
|
2669
|
Chris@224
|
2670 bool
|
Chris@224
|
2671 MainWindowBase::saveSessionTemplate(QString path)
|
Chris@224
|
2672 {
|
Chris@224
|
2673 try {
|
Chris@224
|
2674
|
Chris@224
|
2675 TempWriteFile temp(path);
|
Chris@224
|
2676
|
Chris@224
|
2677 QFile file(temp.getTemporaryFilename());
|
Chris@224
|
2678 if (!file.open(QIODevice::WriteOnly)) {
|
Chris@293
|
2679 cerr << "Failed to open session template file \""
|
Chris@294
|
2680 << temp.getTemporaryFilename()
|
Chris@224
|
2681 << "\" for writing: "
|
Chris@294
|
2682 << file.errorString() << endl;
|
Chris@224
|
2683 return false;
|
Chris@224
|
2684 }
|
Chris@224
|
2685
|
Chris@224
|
2686 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
Chris@224
|
2687
|
Chris@224
|
2688 QTextStream out(&file);
|
Chris@432
|
2689 out.setCodec(QTextCodec::codecForName("UTF-8"));
|
Chris@226
|
2690 toXml(out, true);
|
Chris@224
|
2691 out.flush();
|
Chris@224
|
2692
|
Chris@224
|
2693 QApplication::restoreOverrideCursor();
|
Chris@224
|
2694
|
Chris@224
|
2695 file.close();
|
Chris@224
|
2696 temp.moveToTarget();
|
Chris@224
|
2697 return true;
|
Chris@224
|
2698
|
Chris@224
|
2699 } catch (FileOperationFailed &f) {
|
Chris@224
|
2700
|
Chris@224
|
2701 QMessageBox::critical(this, tr("Failed to write file"),
|
Chris@224
|
2702 tr("<b>Save failed</b><p>Failed to write to file \"%1\": %2")
|
Chris@224
|
2703 .arg(path).arg(f.what()));
|
Chris@224
|
2704 return false;
|
Chris@224
|
2705 }
|
Chris@224
|
2706 }
|
Chris@224
|
2707
|
Chris@45
|
2708 void
|
Chris@226
|
2709 MainWindowBase::toXml(QTextStream &out, bool asTemplate)
|
Chris@45
|
2710 {
|
Chris@45
|
2711 QString indent(" ");
|
Chris@45
|
2712
|
Chris@45
|
2713 out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
Chris@45
|
2714 out << "<!DOCTYPE sonic-visualiser>\n";
|
Chris@45
|
2715 out << "<sv>\n";
|
Chris@45
|
2716
|
Chris@226
|
2717 if (asTemplate) {
|
Chris@226
|
2718 m_document->toXmlAsTemplate(out, "", "");
|
Chris@226
|
2719 } else {
|
Chris@226
|
2720 m_document->toXml(out, "", "");
|
Chris@226
|
2721 }
|
Chris@45
|
2722
|
Chris@45
|
2723 out << "<display>\n";
|
Chris@45
|
2724
|
Chris@45
|
2725 out << QString(" <window width=\"%1\" height=\"%2\"/>\n")
|
Chris@595
|
2726 .arg(width()).arg(height());
|
Chris@45
|
2727
|
Chris@45
|
2728 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@45
|
2729
|
Chris@595
|
2730 Pane *pane = m_paneStack->getPane(i);
|
Chris@595
|
2731
|
Chris@595
|
2732 if (pane) {
|
Chris@45
|
2733 pane->toXml(out, indent);
|
Chris@595
|
2734 }
|
Chris@45
|
2735 }
|
Chris@45
|
2736
|
Chris@45
|
2737 out << "</display>\n";
|
Chris@45
|
2738
|
Chris@45
|
2739 m_viewManager->getSelection().toXml(out);
|
Chris@45
|
2740
|
Chris@45
|
2741 out << "</sv>\n";
|
Chris@45
|
2742 }
|
Chris@45
|
2743
|
Chris@45
|
2744 Pane *
|
Chris@45
|
2745 MainWindowBase::addPaneToStack()
|
Chris@45
|
2746 {
|
Chris@342
|
2747 cerr << "MainWindowBase::addPaneToStack()" << endl;
|
Chris@45
|
2748 AddPaneCommand *command = new AddPaneCommand(this);
|
Chris@45
|
2749 CommandHistory::getInstance()->addCommand(command);
|
Chris@57
|
2750 Pane *pane = command->getPane();
|
Chris@57
|
2751 return pane;
|
Chris@45
|
2752 }
|
Chris@45
|
2753
|
Chris@45
|
2754 void
|
Chris@45
|
2755 MainWindowBase::zoomIn()
|
Chris@45
|
2756 {
|
Chris@45
|
2757 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@45
|
2758 if (currentPane) currentPane->zoom(true);
|
Chris@45
|
2759 }
|
Chris@45
|
2760
|
Chris@45
|
2761 void
|
Chris@45
|
2762 MainWindowBase::zoomOut()
|
Chris@45
|
2763 {
|
Chris@45
|
2764 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@45
|
2765 if (currentPane) currentPane->zoom(false);
|
Chris@45
|
2766 }
|
Chris@45
|
2767
|
Chris@45
|
2768 void
|
Chris@45
|
2769 MainWindowBase::zoomToFit()
|
Chris@45
|
2770 {
|
Chris@45
|
2771 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@45
|
2772 if (!currentPane) return;
|
Chris@45
|
2773
|
Chris@45
|
2774 Model *model = getMainModel();
|
Chris@45
|
2775 if (!model) return;
|
Chris@45
|
2776
|
Chris@434
|
2777 sv_frame_t start = model->getStartFrame();
|
Chris@434
|
2778 sv_frame_t end = model->getEndFrame();
|
Chris@60
|
2779 if (m_playSource) end = std::max(end, m_playSource->getPlayEndFrame());
|
Chris@366
|
2780 int pixels = currentPane->width();
|
Chris@366
|
2781
|
Chris@366
|
2782 int sw = currentPane->getVerticalScaleWidth();
|
Chris@45
|
2783 if (pixels > sw * 2) pixels -= sw * 2;
|
Chris@45
|
2784 else pixels = 1;
|
Chris@45
|
2785 if (pixels > 4) pixels -= 4;
|
Chris@45
|
2786
|
Chris@436
|
2787 int zoomLevel = int((end - start) / pixels);
|
Chris@150
|
2788 if (zoomLevel < 1) zoomLevel = 1;
|
Chris@45
|
2789
|
Chris@45
|
2790 currentPane->setZoomLevel(zoomLevel);
|
Chris@45
|
2791 currentPane->setCentreFrame((start + end) / 2);
|
Chris@45
|
2792 }
|
Chris@45
|
2793
|
Chris@45
|
2794 void
|
Chris@45
|
2795 MainWindowBase::zoomDefault()
|
Chris@45
|
2796 {
|
Chris@45
|
2797 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@302
|
2798 QSettings settings;
|
Chris@302
|
2799 settings.beginGroup("MainWindow");
|
Chris@302
|
2800 int zoom = settings.value("zoom-default", 1024).toInt();
|
Chris@302
|
2801 settings.endGroup();
|
Chris@302
|
2802 if (currentPane) currentPane->setZoomLevel(zoom);
|
Chris@45
|
2803 }
|
Chris@45
|
2804
|
Chris@45
|
2805 void
|
Chris@45
|
2806 MainWindowBase::scrollLeft()
|
Chris@45
|
2807 {
|
Chris@45
|
2808 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@45
|
2809 if (currentPane) currentPane->scroll(false, false);
|
Chris@45
|
2810 }
|
Chris@45
|
2811
|
Chris@45
|
2812 void
|
Chris@45
|
2813 MainWindowBase::jumpLeft()
|
Chris@45
|
2814 {
|
Chris@45
|
2815 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@45
|
2816 if (currentPane) currentPane->scroll(false, true);
|
Chris@45
|
2817 }
|
Chris@45
|
2818
|
Chris@45
|
2819 void
|
Chris@162
|
2820 MainWindowBase::peekLeft()
|
Chris@162
|
2821 {
|
Chris@162
|
2822 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@162
|
2823 if (currentPane) currentPane->scroll(false, false, false);
|
Chris@162
|
2824 }
|
Chris@162
|
2825
|
Chris@162
|
2826 void
|
Chris@45
|
2827 MainWindowBase::scrollRight()
|
Chris@45
|
2828 {
|
Chris@45
|
2829 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@45
|
2830 if (currentPane) currentPane->scroll(true, false);
|
Chris@45
|
2831 }
|
Chris@45
|
2832
|
Chris@45
|
2833 void
|
Chris@45
|
2834 MainWindowBase::jumpRight()
|
Chris@45
|
2835 {
|
Chris@45
|
2836 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@45
|
2837 if (currentPane) currentPane->scroll(true, true);
|
Chris@45
|
2838 }
|
Chris@45
|
2839
|
Chris@45
|
2840 void
|
Chris@162
|
2841 MainWindowBase::peekRight()
|
Chris@162
|
2842 {
|
Chris@162
|
2843 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@162
|
2844 if (currentPane) currentPane->scroll(true, false, false);
|
Chris@162
|
2845 }
|
Chris@162
|
2846
|
Chris@162
|
2847 void
|
Chris@45
|
2848 MainWindowBase::showNoOverlays()
|
Chris@45
|
2849 {
|
Chris@45
|
2850 m_viewManager->setOverlayMode(ViewManager::NoOverlays);
|
Chris@45
|
2851 }
|
Chris@45
|
2852
|
Chris@45
|
2853 void
|
Chris@45
|
2854 MainWindowBase::showMinimalOverlays()
|
Chris@45
|
2855 {
|
Chris@335
|
2856 m_viewManager->setOverlayMode(ViewManager::StandardOverlays);
|
Chris@45
|
2857 }
|
Chris@45
|
2858
|
Chris@45
|
2859 void
|
Chris@45
|
2860 MainWindowBase::showAllOverlays()
|
Chris@45
|
2861 {
|
Chris@45
|
2862 m_viewManager->setOverlayMode(ViewManager::AllOverlays);
|
Chris@45
|
2863 }
|
Chris@45
|
2864
|
Chris@45
|
2865 void
|
Chris@577
|
2866 MainWindowBase::findTimeRulerLayer()
|
Chris@577
|
2867 {
|
Chris@577
|
2868 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@577
|
2869 Pane *pane = m_paneStack->getPane(i);
|
Chris@577
|
2870 if (!pane) continue;
|
Chris@577
|
2871 for (int j = 0; j < pane->getLayerCount(); ++j) {
|
Chris@577
|
2872 Layer *layer = pane->getLayer(j);
|
Chris@577
|
2873 if (!dynamic_cast<TimeRulerLayer *>(layer)) continue;
|
Chris@577
|
2874 m_timeRulerLayer = layer;
|
Chris@577
|
2875 return;
|
Chris@577
|
2876 }
|
Chris@577
|
2877 }
|
Chris@577
|
2878 if (m_timeRulerLayer) {
|
Chris@577
|
2879 SVCERR << "WARNING: Time ruler layer was not reset to 0 before session template loaded?" << endl;
|
Chris@577
|
2880 delete m_timeRulerLayer;
|
Chris@577
|
2881 m_timeRulerLayer = 0;
|
Chris@577
|
2882 }
|
Chris@577
|
2883 }
|
Chris@577
|
2884
|
Chris@577
|
2885 void
|
Chris@211
|
2886 MainWindowBase::toggleTimeRulers()
|
Chris@211
|
2887 {
|
Chris@211
|
2888 bool haveRulers = false;
|
Chris@211
|
2889 bool someHidden = false;
|
Chris@211
|
2890
|
Chris@211
|
2891 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@211
|
2892
|
Chris@211
|
2893 Pane *pane = m_paneStack->getPane(i);
|
Chris@211
|
2894 if (!pane) continue;
|
Chris@211
|
2895
|
Chris@211
|
2896 for (int j = 0; j < pane->getLayerCount(); ++j) {
|
Chris@211
|
2897
|
Chris@211
|
2898 Layer *layer = pane->getLayer(j);
|
Chris@211
|
2899 if (!dynamic_cast<TimeRulerLayer *>(layer)) continue;
|
Chris@211
|
2900
|
Chris@211
|
2901 haveRulers = true;
|
Chris@211
|
2902 if (layer->isLayerDormant(pane)) someHidden = true;
|
Chris@211
|
2903 }
|
Chris@211
|
2904 }
|
Chris@211
|
2905
|
Chris@211
|
2906 if (haveRulers) {
|
Chris@211
|
2907
|
Chris@211
|
2908 bool show = someHidden;
|
Chris@211
|
2909
|
Chris@211
|
2910 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@211
|
2911
|
Chris@211
|
2912 Pane *pane = m_paneStack->getPane(i);
|
Chris@211
|
2913 if (!pane) continue;
|
Chris@211
|
2914
|
Chris@211
|
2915 for (int j = 0; j < pane->getLayerCount(); ++j) {
|
Chris@211
|
2916
|
Chris@211
|
2917 Layer *layer = pane->getLayer(j);
|
Chris@211
|
2918 if (!dynamic_cast<TimeRulerLayer *>(layer)) continue;
|
Chris@211
|
2919
|
Chris@211
|
2920 layer->showLayer(pane, show);
|
Chris@211
|
2921 }
|
Chris@211
|
2922 }
|
Chris@211
|
2923 }
|
Chris@211
|
2924 }
|
Chris@211
|
2925
|
Chris@211
|
2926 void
|
Chris@45
|
2927 MainWindowBase::toggleZoomWheels()
|
Chris@45
|
2928 {
|
Chris@45
|
2929 if (m_viewManager->getZoomWheelsEnabled()) {
|
Chris@45
|
2930 m_viewManager->setZoomWheelsEnabled(false);
|
Chris@45
|
2931 } else {
|
Chris@45
|
2932 m_viewManager->setZoomWheelsEnabled(true);
|
Chris@45
|
2933 }
|
Chris@45
|
2934 }
|
Chris@45
|
2935
|
Chris@45
|
2936 void
|
Chris@45
|
2937 MainWindowBase::togglePropertyBoxes()
|
Chris@45
|
2938 {
|
Chris@45
|
2939 if (m_paneStack->getLayoutStyle() == PaneStack::NoPropertyStacks) {
|
Chris@45
|
2940 if (Preferences::getInstance()->getPropertyBoxLayout() ==
|
Chris@45
|
2941 Preferences::VerticallyStacked) {
|
Chris@45
|
2942 m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout);
|
Chris@45
|
2943 } else {
|
Chris@45
|
2944 m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout);
|
Chris@45
|
2945 }
|
Chris@45
|
2946 } else {
|
Chris@45
|
2947 m_paneStack->setLayoutStyle(PaneStack::NoPropertyStacks);
|
Chris@45
|
2948 }
|
Chris@45
|
2949 }
|
Chris@45
|
2950
|
Chris@378
|
2951 QLabel *
|
Chris@378
|
2952 MainWindowBase::getStatusLabel() const
|
Chris@378
|
2953 {
|
Chris@378
|
2954 if (!m_statusLabel) {
|
Chris@378
|
2955 m_statusLabel = new QLabel();
|
Chris@378
|
2956 statusBar()->addWidget(m_statusLabel, 1);
|
Chris@378
|
2957 }
|
Chris@379
|
2958
|
Chris@379
|
2959 QList<QFrame *> frames = statusBar()->findChildren<QFrame *>();
|
Chris@379
|
2960 foreach (QFrame *f, frames) {
|
Chris@379
|
2961 f->setFrameStyle(QFrame::NoFrame);
|
Chris@379
|
2962 }
|
Chris@379
|
2963
|
Chris@378
|
2964 return m_statusLabel;
|
Chris@378
|
2965 }
|
Chris@378
|
2966
|
Chris@45
|
2967 void
|
Chris@45
|
2968 MainWindowBase::toggleStatusBar()
|
Chris@45
|
2969 {
|
Chris@45
|
2970 QSettings settings;
|
Chris@45
|
2971 settings.beginGroup("MainWindow");
|
Chris@45
|
2972 bool sb = settings.value("showstatusbar", true).toBool();
|
Chris@45
|
2973
|
Chris@45
|
2974 if (sb) {
|
Chris@45
|
2975 statusBar()->hide();
|
Chris@45
|
2976 } else {
|
Chris@45
|
2977 statusBar()->show();
|
Chris@45
|
2978 }
|
Chris@45
|
2979
|
Chris@45
|
2980 settings.setValue("showstatusbar", !sb);
|
Chris@45
|
2981
|
Chris@45
|
2982 settings.endGroup();
|
Chris@45
|
2983 }
|
Chris@45
|
2984
|
Chris@45
|
2985 void
|
Chris@256
|
2986 MainWindowBase::toggleCentreLine()
|
Chris@256
|
2987 {
|
Chris@256
|
2988 if (m_viewManager->shouldShowCentreLine()) {
|
Chris@256
|
2989 m_viewManager->setShowCentreLine(false);
|
Chris@256
|
2990 } else {
|
Chris@256
|
2991 m_viewManager->setShowCentreLine(true);
|
Chris@256
|
2992 }
|
Chris@256
|
2993 }
|
Chris@256
|
2994
|
Chris@256
|
2995 void
|
Chris@45
|
2996 MainWindowBase::preferenceChanged(PropertyContainer::PropertyName name)
|
Chris@45
|
2997 {
|
Chris@45
|
2998 if (name == "Property Box Layout") {
|
Chris@45
|
2999 if (m_paneStack->getLayoutStyle() != PaneStack::NoPropertyStacks) {
|
Chris@45
|
3000 if (Preferences::getInstance()->getPropertyBoxLayout() ==
|
Chris@45
|
3001 Preferences::VerticallyStacked) {
|
Chris@45
|
3002 m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout);
|
Chris@45
|
3003 } else {
|
Chris@45
|
3004 m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout);
|
Chris@45
|
3005 }
|
Chris@45
|
3006 }
|
Chris@45
|
3007 } else if (name == "Background Mode" && m_viewManager) {
|
Chris@45
|
3008 Preferences::BackgroundMode mode =
|
Chris@45
|
3009 Preferences::getInstance()->getBackgroundMode();
|
Chris@45
|
3010 if (mode == Preferences::BackgroundFromTheme) {
|
Chris@45
|
3011 m_viewManager->setGlobalDarkBackground(m_initialDarkBackground);
|
Chris@45
|
3012 } else if (mode == Preferences::DarkBackground) {
|
Chris@45
|
3013 m_viewManager->setGlobalDarkBackground(true);
|
Chris@45
|
3014 } else {
|
Chris@45
|
3015 m_viewManager->setGlobalDarkBackground(false);
|
Chris@45
|
3016 }
|
Chris@45
|
3017 }
|
Chris@45
|
3018 }
|
Chris@45
|
3019
|
Chris@45
|
3020 void
|
Chris@45
|
3021 MainWindowBase::play()
|
Chris@45
|
3022 {
|
Chris@516
|
3023 if ((m_recordTarget && m_recordTarget->isRecording()) ||
|
Chris@516
|
3024 (m_playSource && m_playSource->isPlaying())) {
|
Chris@45
|
3025 stop();
|
Chris@479
|
3026 QAction *action = qobject_cast<QAction *>(sender());
|
Chris@479
|
3027 if (action) action->setChecked(false);
|
Chris@45
|
3028 } else {
|
Chris@487
|
3029 if (m_audioIO) m_audioIO->resume();
|
Chris@509
|
3030 else if (m_playTarget) m_playTarget->resume();
|
Chris@45
|
3031 playbackFrameChanged(m_viewManager->getPlaybackFrame());
|
Chris@595
|
3032 m_playSource->play(m_viewManager->getPlaybackFrame());
|
Chris@45
|
3033 }
|
Chris@45
|
3034 }
|
Chris@45
|
3035
|
Chris@45
|
3036 void
|
Chris@477
|
3037 MainWindowBase::record()
|
Chris@477
|
3038 {
|
Chris@586
|
3039 QAction *action = qobject_cast<QAction *>(sender());
|
Chris@586
|
3040
|
Chris@478
|
3041 if (!(m_soundOptions & WithAudioInput)) {
|
Chris@586
|
3042 if (action) action->setChecked(false);
|
Chris@478
|
3043 return;
|
Chris@478
|
3044 }
|
Chris@478
|
3045
|
Chris@477
|
3046 if (!m_recordTarget) {
|
Chris@586
|
3047 if (action) action->setChecked(false);
|
Chris@477
|
3048 return;
|
Chris@477
|
3049 }
|
Chris@477
|
3050
|
Chris@478
|
3051 if (!m_audioIO) {
|
Chris@611
|
3052 SVDEBUG << "MainWindowBase::record: about to create audio IO" << endl;
|
Chris@478
|
3053 createAudioIO();
|
Chris@478
|
3054 }
|
Chris@492
|
3055
|
Chris@492
|
3056 if (!m_audioIO) {
|
Chris@586
|
3057 if (!m_playTarget) {
|
Chris@586
|
3058 // Don't need to report this, createAudioIO should have
|
Chris@586
|
3059 if (action) action->setChecked(false);
|
Chris@586
|
3060 return;
|
Chris@586
|
3061 } else {
|
Chris@586
|
3062 // Need to report this: if the play target exists instead
|
Chris@586
|
3063 // of the audio IO, then that means we failed to open a
|
Chris@586
|
3064 // capture device. The record control should be disabled
|
Chris@586
|
3065 // in that situation, so if it happens here, that must
|
Chris@586
|
3066 // mean this is the first time we ever tried to open the
|
Chris@586
|
3067 // audio device, hence the need to report the problem here
|
Chris@586
|
3068 QMessageBox::critical
|
Chris@586
|
3069 (this, tr("No record device available"),
|
Chris@586
|
3070 tr("<b>No record device available</b><p>Failed to find or open an audio device for recording. Only playback will be available.</p>"));
|
Chris@586
|
3071 if (action) action->setChecked(false);
|
Chris@586
|
3072 updateMenuStates();
|
Chris@586
|
3073 return;
|
Chris@586
|
3074 }
|
Chris@492
|
3075 }
|
Chris@478
|
3076
|
Chris@477
|
3077 if (m_recordTarget->isRecording()) {
|
Chris@492
|
3078 stop();
|
Chris@477
|
3079 return;
|
Chris@477
|
3080 }
|
Chris@490
|
3081
|
Chris@483
|
3082 if (m_audioRecordMode == RecordReplaceSession) {
|
Chris@490
|
3083 if (!checkSaveModified()) {
|
Chris@490
|
3084 if (action) action->setChecked(false);
|
Chris@490
|
3085 return;
|
Chris@490
|
3086 }
|
Chris@483
|
3087 }
|
Chris@487
|
3088
|
Chris@557
|
3089 if (m_viewManager) m_viewManager->setGlobalCentreFrame(0);
|
Chris@557
|
3090
|
Chris@611
|
3091 SVCERR << "MainWindowBase::record: about to resume" << endl;
|
Chris@492
|
3092 m_audioIO->resume();
|
Chris@509
|
3093
|
Chris@477
|
3094 WritableWaveFileModel *model = m_recordTarget->startRecording();
|
Chris@477
|
3095 if (!model) {
|
Chris@586
|
3096 SVCERR << "ERROR: MainWindowBase::record: Recording failed" << endl;
|
Chris@586
|
3097 QMessageBox::critical
|
Chris@586
|
3098 (this, tr("Recording failed"),
|
Chris@586
|
3099 tr("<b>Recording failed</b><p>Failed to switch to record mode (some internal problem?)</p>"));
|
Chris@490
|
3100 if (action) action->setChecked(false);
|
Chris@477
|
3101 return;
|
Chris@477
|
3102 }
|
Chris@477
|
3103
|
Chris@477
|
3104 if (!model->isOK()) {
|
Chris@611
|
3105 SVCERR << "MainWindowBase::record: Model not OK, stopping and suspending" << endl;
|
Chris@477
|
3106 m_recordTarget->stopRecording();
|
Chris@492
|
3107 m_audioIO->suspend();
|
Chris@586
|
3108 if (action) action->setChecked(false);
|
Chris@477
|
3109 delete model;
|
Chris@477
|
3110 return;
|
Chris@477
|
3111 }
|
Chris@611
|
3112
|
Chris@611
|
3113 SVCERR << "MainWindowBase::record: Model is OK, continuing..." << endl;
|
Chris@487
|
3114
|
Chris@478
|
3115 PlayParameterRepository::getInstance()->addPlayable(model);
|
Chris@483
|
3116
|
Chris@483
|
3117 if (m_audioRecordMode == RecordReplaceSession || !getMainModel()) {
|
Chris@478
|
3118
|
Chris@479
|
3119 //!!! duplication with openAudio here
|
Chris@479
|
3120
|
Chris@479
|
3121 QString templateName = getDefaultSessionTemplate();
|
Chris@479
|
3122 bool loadedTemplate = false;
|
Chris@479
|
3123
|
Chris@479
|
3124 if (templateName != "") {
|
Chris@479
|
3125 FileOpenStatus tplStatus = openSessionTemplate(templateName);
|
Chris@479
|
3126 if (tplStatus == FileOpenCancelled) {
|
Chris@611
|
3127 SVCERR << "MainWindowBase::record: Session template open cancelled, stopping and suspending" << endl;
|
Chris@490
|
3128 m_recordTarget->stopRecording();
|
Chris@492
|
3129 m_audioIO->suspend();
|
Chris@490
|
3130 PlayParameterRepository::getInstance()->removePlayable(model);
|
Chris@479
|
3131 return;
|
Chris@479
|
3132 }
|
Chris@479
|
3133 if (tplStatus != FileOpenFailed) {
|
Chris@479
|
3134 loadedTemplate = true;
|
Chris@479
|
3135 }
|
Chris@479
|
3136 }
|
Chris@479
|
3137
|
Chris@479
|
3138 if (!loadedTemplate) {
|
Chris@479
|
3139 closeSession();
|
Chris@479
|
3140 createDocument();
|
Chris@479
|
3141 }
|
Chris@479
|
3142
|
Chris@479
|
3143 Model *prevMain = getMainModel();
|
Chris@479
|
3144 if (prevMain) {
|
Chris@479
|
3145 m_playSource->removeModel(prevMain);
|
Chris@479
|
3146 PlayParameterRepository::getInstance()->removePlayable(prevMain);
|
Chris@479
|
3147 }
|
Chris@479
|
3148
|
Chris@478
|
3149 m_document->setMainModel(model);
|
Chris@478
|
3150 setupMenus();
|
Chris@577
|
3151 findTimeRulerLayer();
|
Chris@478
|
3152
|
Chris@595
|
3153 if (loadedTemplate || (m_sessionFile == "")) {
|
Chris@479
|
3154 //!!! shouldn't be dealing directly with title from here -- call a method
|
Chris@595
|
3155 setWindowTitle(tr("%1: %2")
|
Chris@479
|
3156 .arg(QApplication::applicationName())
|
Chris@479
|
3157 .arg(model->getLocation()));
|
Chris@595
|
3158 CommandHistory::getInstance()->clear();
|
Chris@595
|
3159 CommandHistory::getInstance()->documentSaved();
|
Chris@595
|
3160 m_documentModified = false;
|
Chris@595
|
3161 } else {
|
Chris@595
|
3162 setWindowTitle(tr("%1: %2 [%3]")
|
Chris@479
|
3163 .arg(QApplication::applicationName())
|
Chris@595
|
3164 .arg(QFileInfo(m_sessionFile).fileName())
|
Chris@595
|
3165 .arg(model->getLocation()));
|
Chris@595
|
3166 if (m_documentModified) {
|
Chris@595
|
3167 m_documentModified = false;
|
Chris@595
|
3168 documentModified(); // so as to restore "(modified)" window title
|
Chris@595
|
3169 }
|
Chris@595
|
3170 }
|
Chris@479
|
3171
|
Chris@478
|
3172 } else {
|
Chris@478
|
3173
|
Chris@478
|
3174 CommandHistory::getInstance()->startCompoundOperation
|
Chris@478
|
3175 (tr("Import Recorded Audio"), true);
|
Chris@478
|
3176
|
Chris@478
|
3177 m_document->addImportedModel(model);
|
Chris@478
|
3178
|
Chris@478
|
3179 AddPaneCommand *command = new AddPaneCommand(this);
|
Chris@478
|
3180 CommandHistory::getInstance()->addCommand(command);
|
Chris@478
|
3181
|
Chris@478
|
3182 Pane *pane = command->getPane();
|
Chris@478
|
3183
|
Chris@478
|
3184 if (m_timeRulerLayer) {
|
Chris@478
|
3185 m_document->addLayerToView(pane, m_timeRulerLayer);
|
Chris@478
|
3186 }
|
Chris@478
|
3187
|
Chris@478
|
3188 Layer *newLayer = m_document->createImportedLayer(model);
|
Chris@478
|
3189
|
Chris@478
|
3190 if (newLayer) {
|
Chris@478
|
3191 m_document->addLayerToView(pane, newLayer);
|
Chris@478
|
3192 }
|
Chris@595
|
3193
|
Chris@478
|
3194 CommandHistory::getInstance()->endCompoundOperation();
|
Chris@477
|
3195 }
|
Chris@479
|
3196
|
Chris@479
|
3197 updateMenuStates();
|
Chris@479
|
3198 m_recentFiles.addFile(model->getLocation());
|
Chris@479
|
3199 currentPaneChanged(m_paneStack->getCurrentPane());
|
Chris@611
|
3200
|
Chris@496
|
3201 emit audioFileLoaded();
|
Chris@477
|
3202 }
|
Chris@477
|
3203
|
Chris@477
|
3204 void
|
Chris@45
|
3205 MainWindowBase::ffwd()
|
Chris@45
|
3206 {
|
Chris@45
|
3207 if (!getMainModel()) return;
|
Chris@45
|
3208
|
Chris@435
|
3209 sv_frame_t frame = m_viewManager->getPlaybackFrame();
|
Chris@45
|
3210 ++frame;
|
Chris@45
|
3211
|
Chris@85
|
3212 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@45
|
3213 Layer *layer = getSnapLayer();
|
Chris@435
|
3214 sv_samplerate_t sr = getMainModel()->getSampleRate();
|
Chris@45
|
3215
|
Chris@45
|
3216 if (!layer) {
|
Chris@45
|
3217
|
Chris@45
|
3218 frame = RealTime::realTime2Frame
|
Chris@357
|
3219 (RealTime::frame2RealTime(frame, sr) + m_defaultFfwdRwdStep, sr);
|
Chris@435
|
3220 if (frame > getMainModel()->getEndFrame()) {
|
Chris@45
|
3221 frame = getMainModel()->getEndFrame();
|
Chris@45
|
3222 }
|
Chris@45
|
3223
|
Chris@45
|
3224 } else {
|
Chris@45
|
3225
|
Chris@366
|
3226 int resolution = 0;
|
Chris@166
|
3227 if (pane) frame = pane->alignFromReference(frame);
|
Chris@85
|
3228 if (layer->snapToFeatureFrame(m_paneStack->getCurrentPane(),
|
Chris@85
|
3229 frame, resolution, Layer::SnapRight)) {
|
Chris@85
|
3230 if (pane) frame = pane->alignToReference(frame);
|
Chris@85
|
3231 } else {
|
Chris@45
|
3232 frame = getMainModel()->getEndFrame();
|
Chris@45
|
3233 }
|
Chris@45
|
3234 }
|
Chris@45
|
3235
|
Chris@45
|
3236 if (frame < 0) frame = 0;
|
Chris@45
|
3237
|
Chris@45
|
3238 if (m_viewManager->getPlaySelectionMode()) {
|
Chris@435
|
3239 frame = m_viewManager->constrainFrameToSelection(frame);
|
Chris@45
|
3240 }
|
Chris@45
|
3241
|
Chris@45
|
3242 m_viewManager->setPlaybackFrame(frame);
|
Chris@166
|
3243
|
Chris@435
|
3244 if (frame == getMainModel()->getEndFrame() &&
|
Chris@166
|
3245 m_playSource &&
|
Chris@166
|
3246 m_playSource->isPlaying() &&
|
Chris@166
|
3247 !m_viewManager->getPlayLoopMode()) {
|
Chris@166
|
3248 stop();
|
Chris@166
|
3249 }
|
Chris@45
|
3250 }
|
Chris@45
|
3251
|
Chris@45
|
3252 void
|
Chris@45
|
3253 MainWindowBase::ffwdEnd()
|
Chris@45
|
3254 {
|
Chris@45
|
3255 if (!getMainModel()) return;
|
Chris@45
|
3256
|
Chris@139
|
3257 if (m_playSource &&
|
Chris@139
|
3258 m_playSource->isPlaying() &&
|
Chris@139
|
3259 !m_viewManager->getPlayLoopMode()) {
|
Chris@139
|
3260 stop();
|
Chris@139
|
3261 }
|
Chris@139
|
3262
|
Chris@435
|
3263 sv_frame_t frame = getMainModel()->getEndFrame();
|
Chris@45
|
3264
|
Chris@45
|
3265 if (m_viewManager->getPlaySelectionMode()) {
|
Chris@45
|
3266 frame = m_viewManager->constrainFrameToSelection(frame);
|
Chris@45
|
3267 }
|
Chris@45
|
3268
|
Chris@45
|
3269 m_viewManager->setPlaybackFrame(frame);
|
Chris@45
|
3270 }
|
Chris@45
|
3271
|
Chris@45
|
3272 void
|
Chris@166
|
3273 MainWindowBase::ffwdSimilar()
|
Chris@166
|
3274 {
|
Chris@166
|
3275 if (!getMainModel()) return;
|
Chris@166
|
3276
|
Chris@166
|
3277 Layer *layer = getSnapLayer();
|
Chris@166
|
3278 if (!layer) { ffwd(); return; }
|
Chris@166
|
3279
|
Chris@166
|
3280 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@435
|
3281 sv_frame_t frame = m_viewManager->getPlaybackFrame();
|
Chris@166
|
3282
|
Chris@366
|
3283 int resolution = 0;
|
Chris@166
|
3284 if (pane) frame = pane->alignFromReference(frame);
|
Chris@166
|
3285 if (layer->snapToSimilarFeature(m_paneStack->getCurrentPane(),
|
Chris@166
|
3286 frame, resolution, Layer::SnapRight)) {
|
Chris@166
|
3287 if (pane) frame = pane->alignToReference(frame);
|
Chris@166
|
3288 } else {
|
Chris@166
|
3289 frame = getMainModel()->getEndFrame();
|
Chris@166
|
3290 }
|
Chris@166
|
3291
|
Chris@166
|
3292 if (frame < 0) frame = 0;
|
Chris@166
|
3293
|
Chris@166
|
3294 if (m_viewManager->getPlaySelectionMode()) {
|
Chris@435
|
3295 frame = m_viewManager->constrainFrameToSelection(frame);
|
Chris@166
|
3296 }
|
Chris@166
|
3297
|
Chris@166
|
3298 m_viewManager->setPlaybackFrame(frame);
|
Chris@166
|
3299
|
Chris@435
|
3300 if (frame == getMainModel()->getEndFrame() &&
|
Chris@166
|
3301 m_playSource &&
|
Chris@166
|
3302 m_playSource->isPlaying() &&
|
Chris@166
|
3303 !m_viewManager->getPlayLoopMode()) {
|
Chris@166
|
3304 stop();
|
Chris@166
|
3305 }
|
Chris@166
|
3306 }
|
Chris@166
|
3307
|
Chris@166
|
3308 void
|
Chris@45
|
3309 MainWindowBase::rewind()
|
Chris@45
|
3310 {
|
Chris@45
|
3311 if (!getMainModel()) return;
|
Chris@45
|
3312
|
Chris@435
|
3313 sv_frame_t frame = m_viewManager->getPlaybackFrame();
|
Chris@45
|
3314 if (frame > 0) --frame;
|
Chris@45
|
3315
|
Chris@85
|
3316 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@45
|
3317 Layer *layer = getSnapLayer();
|
Chris@435
|
3318 sv_samplerate_t sr = getMainModel()->getSampleRate();
|
Chris@45
|
3319
|
Chris@45
|
3320 // when rewinding during playback, we want to allow a period
|
Chris@45
|
3321 // following a rewind target point at which the rewind will go to
|
Chris@45
|
3322 // the prior point instead of the immediately neighbouring one
|
Chris@45
|
3323 if (m_playSource && m_playSource->isPlaying()) {
|
Chris@45
|
3324 RealTime ct = RealTime::frame2RealTime(frame, sr);
|
Chris@357
|
3325 ct = ct - RealTime::fromSeconds(0.15);
|
Chris@45
|
3326 if (ct < RealTime::zeroTime) ct = RealTime::zeroTime;
|
Chris@45
|
3327 frame = RealTime::realTime2Frame(ct, sr);
|
Chris@45
|
3328 }
|
Chris@45
|
3329
|
Chris@45
|
3330 if (!layer) {
|
Chris@45
|
3331
|
Chris@45
|
3332 frame = RealTime::realTime2Frame
|
Chris@357
|
3333 (RealTime::frame2RealTime(frame, sr) - m_defaultFfwdRwdStep, sr);
|
Chris@435
|
3334 if (frame < getMainModel()->getStartFrame()) {
|
Chris@45
|
3335 frame = getMainModel()->getStartFrame();
|
Chris@45
|
3336 }
|
Chris@45
|
3337
|
Chris@45
|
3338 } else {
|
Chris@45
|
3339
|
Chris@366
|
3340 int resolution = 0;
|
Chris@166
|
3341 if (pane) frame = pane->alignFromReference(frame);
|
Chris@85
|
3342 if (layer->snapToFeatureFrame(m_paneStack->getCurrentPane(),
|
Chris@85
|
3343 frame, resolution, Layer::SnapLeft)) {
|
Chris@85
|
3344 if (pane) frame = pane->alignToReference(frame);
|
Chris@85
|
3345 } else {
|
Chris@45
|
3346 frame = getMainModel()->getStartFrame();
|
Chris@45
|
3347 }
|
Chris@45
|
3348 }
|
Chris@45
|
3349
|
Chris@45
|
3350 if (frame < 0) frame = 0;
|
Chris@45
|
3351
|
Chris@45
|
3352 if (m_viewManager->getPlaySelectionMode()) {
|
Chris@435
|
3353 frame = m_viewManager->constrainFrameToSelection(frame);
|
Chris@45
|
3354 }
|
Chris@45
|
3355
|
Chris@45
|
3356 m_viewManager->setPlaybackFrame(frame);
|
Chris@45
|
3357 }
|
Chris@45
|
3358
|
Chris@45
|
3359 void
|
Chris@45
|
3360 MainWindowBase::rewindStart()
|
Chris@45
|
3361 {
|
Chris@45
|
3362 if (!getMainModel()) return;
|
Chris@45
|
3363
|
Chris@435
|
3364 sv_frame_t frame = getMainModel()->getStartFrame();
|
Chris@45
|
3365
|
Chris@45
|
3366 if (m_viewManager->getPlaySelectionMode()) {
|
Chris@45
|
3367 frame = m_viewManager->constrainFrameToSelection(frame);
|
Chris@45
|
3368 }
|
Chris@45
|
3369
|
Chris@45
|
3370 m_viewManager->setPlaybackFrame(frame);
|
Chris@45
|
3371 }
|
Chris@45
|
3372
|
Chris@166
|
3373 void
|
Chris@166
|
3374 MainWindowBase::rewindSimilar()
|
Chris@166
|
3375 {
|
Chris@166
|
3376 if (!getMainModel()) return;
|
Chris@166
|
3377
|
Chris@166
|
3378 Layer *layer = getSnapLayer();
|
Chris@166
|
3379 if (!layer) { rewind(); return; }
|
Chris@166
|
3380
|
Chris@166
|
3381 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@435
|
3382 sv_frame_t frame = m_viewManager->getPlaybackFrame();
|
Chris@166
|
3383
|
Chris@366
|
3384 int resolution = 0;
|
Chris@166
|
3385 if (pane) frame = pane->alignFromReference(frame);
|
Chris@166
|
3386 if (layer->snapToSimilarFeature(m_paneStack->getCurrentPane(),
|
Chris@166
|
3387 frame, resolution, Layer::SnapLeft)) {
|
Chris@166
|
3388 if (pane) frame = pane->alignToReference(frame);
|
Chris@166
|
3389 } else {
|
Chris@166
|
3390 frame = getMainModel()->getStartFrame();
|
Chris@166
|
3391 }
|
Chris@166
|
3392
|
Chris@166
|
3393 if (frame < 0) frame = 0;
|
Chris@166
|
3394
|
Chris@166
|
3395 if (m_viewManager->getPlaySelectionMode()) {
|
Chris@435
|
3396 frame = m_viewManager->constrainFrameToSelection(frame);
|
Chris@166
|
3397 }
|
Chris@166
|
3398
|
Chris@166
|
3399 m_viewManager->setPlaybackFrame(frame);
|
Chris@166
|
3400 }
|
Chris@166
|
3401
|
Chris@45
|
3402 Layer *
|
Chris@45
|
3403 MainWindowBase::getSnapLayer() const
|
Chris@45
|
3404 {
|
Chris@45
|
3405 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@45
|
3406 if (!pane) return 0;
|
Chris@45
|
3407
|
Chris@45
|
3408 Layer *layer = pane->getSelectedLayer();
|
Chris@45
|
3409
|
Chris@45
|
3410 if (!dynamic_cast<TimeInstantLayer *>(layer) &&
|
Chris@45
|
3411 !dynamic_cast<TimeValueLayer *>(layer) &&
|
Chris@194
|
3412 !dynamic_cast<RegionLayer *>(layer) &&
|
Chris@45
|
3413 !dynamic_cast<TimeRulerLayer *>(layer)) {
|
Chris@45
|
3414
|
Chris@45
|
3415 layer = 0;
|
Chris@45
|
3416
|
Chris@45
|
3417 for (int i = pane->getLayerCount(); i > 0; --i) {
|
Chris@45
|
3418 Layer *l = pane->getLayer(i-1);
|
Chris@45
|
3419 if (dynamic_cast<TimeRulerLayer *>(l)) {
|
Chris@45
|
3420 layer = l;
|
Chris@45
|
3421 break;
|
Chris@45
|
3422 }
|
Chris@45
|
3423 }
|
Chris@45
|
3424 }
|
Chris@45
|
3425
|
Chris@45
|
3426 return layer;
|
Chris@45
|
3427 }
|
Chris@45
|
3428
|
Chris@45
|
3429 void
|
Chris@45
|
3430 MainWindowBase::stop()
|
Chris@45
|
3431 {
|
Chris@516
|
3432 if (m_recordTarget &&
|
Chris@516
|
3433 m_recordTarget->isRecording()) {
|
Chris@477
|
3434 m_recordTarget->stopRecording();
|
Chris@477
|
3435 }
|
Chris@516
|
3436
|
Chris@516
|
3437 if (!m_playSource) return;
|
Chris@516
|
3438
|
Chris@45
|
3439 m_playSource->stop();
|
Chris@45
|
3440
|
Chris@611
|
3441 SVCERR << "MainWindowBase::stop: suspending" << endl;
|
Chris@611
|
3442
|
Chris@487
|
3443 if (m_audioIO) m_audioIO->suspend();
|
Chris@509
|
3444 else if (m_playTarget) m_playTarget->suspend();
|
Chris@487
|
3445
|
Chris@45
|
3446 if (m_paneStack && m_paneStack->getCurrentPane()) {
|
Chris@45
|
3447 updateVisibleRangeDisplay(m_paneStack->getCurrentPane());
|
Chris@45
|
3448 } else {
|
Chris@45
|
3449 m_myStatusMessage = "";
|
Chris@378
|
3450 getStatusLabel()->setText("");
|
Chris@45
|
3451 }
|
Chris@45
|
3452 }
|
Chris@45
|
3453
|
Chris@45
|
3454 MainWindowBase::AddPaneCommand::AddPaneCommand(MainWindowBase *mw) :
|
Chris@45
|
3455 m_mw(mw),
|
Chris@45
|
3456 m_pane(0),
|
Chris@45
|
3457 m_prevCurrentPane(0),
|
Chris@45
|
3458 m_added(false)
|
Chris@45
|
3459 {
|
Chris@45
|
3460 }
|
Chris@45
|
3461
|
Chris@45
|
3462 MainWindowBase::AddPaneCommand::~AddPaneCommand()
|
Chris@45
|
3463 {
|
Chris@45
|
3464 if (m_pane && !m_added) {
|
Chris@595
|
3465 m_mw->m_paneStack->deletePane(m_pane);
|
Chris@45
|
3466 }
|
Chris@45
|
3467 }
|
Chris@45
|
3468
|
Chris@45
|
3469 QString
|
Chris@45
|
3470 MainWindowBase::AddPaneCommand::getName() const
|
Chris@45
|
3471 {
|
Chris@45
|
3472 return tr("Add Pane");
|
Chris@45
|
3473 }
|
Chris@45
|
3474
|
Chris@45
|
3475 void
|
Chris@45
|
3476 MainWindowBase::AddPaneCommand::execute()
|
Chris@45
|
3477 {
|
Chris@45
|
3478 if (!m_pane) {
|
Chris@595
|
3479 m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane();
|
Chris@595
|
3480 m_pane = m_mw->m_paneStack->addPane();
|
Chris@45
|
3481
|
Chris@45
|
3482 connect(m_pane, SIGNAL(contextHelpChanged(const QString &)),
|
Chris@45
|
3483 m_mw, SLOT(contextHelpChanged(const QString &)));
|
Chris@45
|
3484 } else {
|
Chris@595
|
3485 m_mw->m_paneStack->showPane(m_pane);
|
Chris@45
|
3486 }
|
Chris@45
|
3487
|
Chris@45
|
3488 m_mw->m_paneStack->setCurrentPane(m_pane);
|
Chris@45
|
3489 m_added = true;
|
Chris@45
|
3490 }
|
Chris@45
|
3491
|
Chris@45
|
3492 void
|
Chris@45
|
3493 MainWindowBase::AddPaneCommand::unexecute()
|
Chris@45
|
3494 {
|
Chris@45
|
3495 m_mw->m_paneStack->hidePane(m_pane);
|
Chris@45
|
3496 m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane);
|
Chris@45
|
3497 m_added = false;
|
Chris@45
|
3498 }
|
Chris@45
|
3499
|
Chris@45
|
3500 MainWindowBase::RemovePaneCommand::RemovePaneCommand(MainWindowBase *mw, Pane *pane) :
|
Chris@45
|
3501 m_mw(mw),
|
Chris@45
|
3502 m_pane(pane),
|
Chris@409
|
3503 m_prevCurrentPane(0),
|
Chris@45
|
3504 m_added(true)
|
Chris@45
|
3505 {
|
Chris@45
|
3506 }
|
Chris@45
|
3507
|
Chris@45
|
3508 MainWindowBase::RemovePaneCommand::~RemovePaneCommand()
|
Chris@45
|
3509 {
|
Chris@45
|
3510 if (m_pane && !m_added) {
|
Chris@595
|
3511 m_mw->m_paneStack->deletePane(m_pane);
|
Chris@45
|
3512 }
|
Chris@45
|
3513 }
|
Chris@45
|
3514
|
Chris@45
|
3515 QString
|
Chris@45
|
3516 MainWindowBase::RemovePaneCommand::getName() const
|
Chris@45
|
3517 {
|
Chris@45
|
3518 return tr("Remove Pane");
|
Chris@45
|
3519 }
|
Chris@45
|
3520
|
Chris@45
|
3521 void
|
Chris@45
|
3522 MainWindowBase::RemovePaneCommand::execute()
|
Chris@45
|
3523 {
|
Chris@45
|
3524 m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane();
|
Chris@45
|
3525 m_mw->m_paneStack->hidePane(m_pane);
|
Chris@45
|
3526 m_added = false;
|
Chris@45
|
3527 }
|
Chris@45
|
3528
|
Chris@45
|
3529 void
|
Chris@45
|
3530 MainWindowBase::RemovePaneCommand::unexecute()
|
Chris@45
|
3531 {
|
Chris@45
|
3532 m_mw->m_paneStack->showPane(m_pane);
|
Chris@45
|
3533 m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane);
|
Chris@45
|
3534 m_added = true;
|
Chris@45
|
3535 }
|
Chris@45
|
3536
|
Chris@45
|
3537 void
|
Chris@45
|
3538 MainWindowBase::deleteCurrentPane()
|
Chris@45
|
3539 {
|
Chris@45
|
3540 CommandHistory::getInstance()->startCompoundOperation
|
Chris@595
|
3541 (tr("Delete Pane"), true);
|
Chris@45
|
3542
|
Chris@45
|
3543 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@45
|
3544 if (pane) {
|
Chris@595
|
3545 while (pane->getLayerCount() > 0) {
|
Chris@595
|
3546 Layer *layer = pane->getLayer(0);
|
Chris@595
|
3547 if (layer) {
|
Chris@595
|
3548 m_document->removeLayerFromView(pane, layer);
|
Chris@595
|
3549 } else {
|
Chris@595
|
3550 break;
|
Chris@595
|
3551 }
|
Chris@595
|
3552 }
|
Chris@595
|
3553
|
Chris@595
|
3554 RemovePaneCommand *command = new RemovePaneCommand(this, pane);
|
Chris@595
|
3555 CommandHistory::getInstance()->addCommand(command);
|
Chris@45
|
3556 }
|
Chris@45
|
3557
|
Chris@45
|
3558 CommandHistory::getInstance()->endCompoundOperation();
|
Chris@45
|
3559
|
Chris@45
|
3560 updateMenuStates();
|
Chris@45
|
3561 }
|
Chris@45
|
3562
|
Chris@45
|
3563 void
|
Chris@45
|
3564 MainWindowBase::deleteCurrentLayer()
|
Chris@45
|
3565 {
|
Chris@45
|
3566 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@45
|
3567 if (pane) {
|
Chris@595
|
3568 Layer *layer = pane->getSelectedLayer();
|
Chris@595
|
3569 if (layer) {
|
Chris@595
|
3570 m_document->removeLayerFromView(pane, layer);
|
Chris@595
|
3571 }
|
Chris@45
|
3572 }
|
Chris@45
|
3573 updateMenuStates();
|
Chris@45
|
3574 }
|
Chris@45
|
3575
|
Chris@45
|
3576 void
|
Chris@123
|
3577 MainWindowBase::editCurrentLayer()
|
Chris@123
|
3578 {
|
Chris@123
|
3579 Layer *layer = 0;
|
Chris@123
|
3580 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@123
|
3581 if (pane) layer = pane->getSelectedLayer();
|
Chris@123
|
3582 if (!layer) return;
|
Chris@123
|
3583
|
Chris@123
|
3584 Model *model = layer->getModel();
|
Chris@123
|
3585 if (!model) return;
|
Chris@123
|
3586
|
Chris@124
|
3587 TabularModel *tabular = dynamic_cast<TabularModel *>(model);
|
Chris@124
|
3588 if (!tabular) {
|
Chris@124
|
3589 //!!! how to prevent this function from being active if not
|
Chris@124
|
3590 //appropriate model type? or will we ultimately support
|
Chris@124
|
3591 //tabular display for all editable models?
|
Chris@233
|
3592 SVDEBUG << "NOTE: Not a tabular model" << endl;
|
Chris@124
|
3593 return;
|
Chris@124
|
3594 }
|
Chris@124
|
3595
|
Chris@123
|
3596 if (m_layerDataDialogMap.find(layer) != m_layerDataDialogMap.end()) {
|
Chris@126
|
3597 if (!m_layerDataDialogMap[layer].isNull()) {
|
Chris@126
|
3598 m_layerDataDialogMap[layer]->show();
|
Chris@126
|
3599 m_layerDataDialogMap[layer]->raise();
|
Chris@126
|
3600 return;
|
Chris@126
|
3601 }
|
Chris@123
|
3602 }
|
Chris@123
|
3603
|
Chris@125
|
3604 QString title = layer->getLayerPresentationName();
|
Chris@125
|
3605
|
Chris@125
|
3606 ModelDataTableDialog *dialog = new ModelDataTableDialog(tabular, title, this);
|
Chris@128
|
3607 dialog->setAttribute(Qt::WA_DeleteOnClose);
|
Chris@128
|
3608
|
Chris@128
|
3609 connectLayerEditDialog(dialog);
|
Chris@123
|
3610
|
Chris@128
|
3611 m_layerDataDialogMap[layer] = dialog;
|
Chris@128
|
3612 m_viewDataDialogMap[pane].insert(dialog);
|
Chris@128
|
3613
|
Chris@128
|
3614 dialog->show();
|
Chris@128
|
3615 }
|
Chris@128
|
3616
|
Chris@128
|
3617 void
|
Chris@128
|
3618 MainWindowBase::connectLayerEditDialog(ModelDataTableDialog *dialog)
|
Chris@128
|
3619 {
|
Chris@123
|
3620 connect(m_viewManager,
|
Chris@435
|
3621 SIGNAL(globalCentreFrameChanged(sv_frame_t)),
|
Chris@123
|
3622 dialog,
|
Chris@435
|
3623 SLOT(userScrolledToFrame(sv_frame_t)));
|
Chris@127
|
3624
|
Chris@127
|
3625 connect(m_viewManager,
|
Chris@435
|
3626 SIGNAL(playbackFrameChanged(sv_frame_t)),
|
Chris@127
|
3627 dialog,
|
Chris@435
|
3628 SLOT(playbackScrolledToFrame(sv_frame_t)));
|
Chris@127
|
3629
|
Chris@123
|
3630 connect(dialog,
|
Chris@435
|
3631 SIGNAL(scrollToFrame(sv_frame_t)),
|
Chris@123
|
3632 m_viewManager,
|
Chris@435
|
3633 SLOT(setGlobalCentreFrame(sv_frame_t)));
|
Chris@129
|
3634
|
Chris@129
|
3635 connect(dialog,
|
Chris@435
|
3636 SIGNAL(scrollToFrame(sv_frame_t)),
|
Chris@129
|
3637 m_viewManager,
|
Chris@435
|
3638 SLOT(setPlaybackFrame(sv_frame_t)));
|
Chris@128
|
3639 }
|
Chris@123
|
3640
|
Chris@123
|
3641 void
|
Chris@73
|
3642 MainWindowBase::previousPane()
|
Chris@73
|
3643 {
|
Chris@73
|
3644 if (!m_paneStack) return;
|
Chris@73
|
3645
|
Chris@73
|
3646 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@73
|
3647 if (!currentPane) return;
|
Chris@73
|
3648
|
Chris@73
|
3649 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@73
|
3650 if (m_paneStack->getPane(i) == currentPane) {
|
Chris@73
|
3651 if (i == 0) return;
|
Chris@73
|
3652 m_paneStack->setCurrentPane(m_paneStack->getPane(i-1));
|
Chris@73
|
3653 updateMenuStates();
|
Chris@73
|
3654 return;
|
Chris@73
|
3655 }
|
Chris@73
|
3656 }
|
Chris@73
|
3657 }
|
Chris@73
|
3658
|
Chris@73
|
3659 void
|
Chris@73
|
3660 MainWindowBase::nextPane()
|
Chris@73
|
3661 {
|
Chris@73
|
3662 if (!m_paneStack) return;
|
Chris@73
|
3663
|
Chris@73
|
3664 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@73
|
3665 if (!currentPane) return;
|
Chris@73
|
3666
|
Chris@73
|
3667 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@73
|
3668 if (m_paneStack->getPane(i) == currentPane) {
|
Chris@73
|
3669 if (i == m_paneStack->getPaneCount()-1) return;
|
Chris@73
|
3670 m_paneStack->setCurrentPane(m_paneStack->getPane(i+1));
|
Chris@73
|
3671 updateMenuStates();
|
Chris@73
|
3672 return;
|
Chris@73
|
3673 }
|
Chris@73
|
3674 }
|
Chris@73
|
3675 }
|
Chris@73
|
3676
|
Chris@73
|
3677 void
|
Chris@73
|
3678 MainWindowBase::previousLayer()
|
Chris@73
|
3679 {
|
Chris@73
|
3680 if (!m_paneStack) return;
|
Chris@73
|
3681
|
Chris@73
|
3682 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@73
|
3683 if (!currentPane) return;
|
Chris@73
|
3684
|
Chris@403
|
3685 int count = currentPane->getLayerCount();
|
Chris@403
|
3686 if (count == 0) return;
|
Chris@403
|
3687
|
Chris@73
|
3688 Layer *currentLayer = currentPane->getSelectedLayer();
|
Chris@403
|
3689
|
Chris@403
|
3690 if (!currentLayer) {
|
Chris@403
|
3691 // The pane itself is current
|
Chris@403
|
3692 m_paneStack->setCurrentLayer
|
Chris@403
|
3693 (currentPane, currentPane->getFixedOrderLayer(count-1));
|
Chris@403
|
3694 } else {
|
Chris@403
|
3695 for (int i = 0; i < count; ++i) {
|
Chris@403
|
3696 if (currentPane->getFixedOrderLayer(i) == currentLayer) {
|
Chris@403
|
3697 if (i == 0) {
|
Chris@403
|
3698 m_paneStack->setCurrentLayer
|
Chris@403
|
3699 (currentPane, 0); // pane
|
Chris@403
|
3700 } else {
|
Chris@403
|
3701 m_paneStack->setCurrentLayer
|
Chris@403
|
3702 (currentPane, currentPane->getFixedOrderLayer(i-1));
|
Chris@403
|
3703 }
|
Chris@403
|
3704 break;
|
Chris@403
|
3705 }
|
Chris@73
|
3706 }
|
Chris@73
|
3707 }
|
Chris@403
|
3708
|
Chris@403
|
3709 updateMenuStates();
|
Chris@73
|
3710 }
|
Chris@73
|
3711
|
Chris@73
|
3712 void
|
Chris@73
|
3713 MainWindowBase::nextLayer()
|
Chris@73
|
3714 {
|
Chris@73
|
3715 if (!m_paneStack) return;
|
Chris@73
|
3716
|
Chris@73
|
3717 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@73
|
3718 if (!currentPane) return;
|
Chris@73
|
3719
|
Chris@403
|
3720 int count = currentPane->getLayerCount();
|
Chris@403
|
3721 if (count == 0) return;
|
Chris@403
|
3722
|
Chris@73
|
3723 Layer *currentLayer = currentPane->getSelectedLayer();
|
Chris@403
|
3724
|
Chris@403
|
3725 if (!currentLayer) {
|
Chris@403
|
3726 // The pane itself is current
|
Chris@403
|
3727 m_paneStack->setCurrentLayer
|
Chris@403
|
3728 (currentPane, currentPane->getFixedOrderLayer(0));
|
Chris@403
|
3729 } else {
|
Chris@403
|
3730 for (int i = 0; i < count; ++i) {
|
Chris@403
|
3731 if (currentPane->getFixedOrderLayer(i) == currentLayer) {
|
Chris@403
|
3732 if (i == currentPane->getLayerCount()-1) {
|
Chris@403
|
3733 m_paneStack->setCurrentLayer
|
Chris@403
|
3734 (currentPane, 0); // pane
|
Chris@403
|
3735 } else {
|
Chris@403
|
3736 m_paneStack->setCurrentLayer
|
Chris@403
|
3737 (currentPane, currentPane->getFixedOrderLayer(i+1));
|
Chris@403
|
3738 }
|
Chris@403
|
3739 break;
|
Chris@403
|
3740 }
|
Chris@73
|
3741 }
|
Chris@73
|
3742 }
|
Chris@403
|
3743
|
Chris@403
|
3744 updateMenuStates();
|
Chris@73
|
3745 }
|
Chris@73
|
3746
|
Chris@73
|
3747 void
|
Chris@435
|
3748 MainWindowBase::playbackFrameChanged(sv_frame_t frame)
|
Chris@45
|
3749 {
|
Chris@45
|
3750 if (!(m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
|
Chris@45
|
3751
|
Chris@187
|
3752 updatePositionStatusDisplays();
|
Chris@187
|
3753
|
Chris@45
|
3754 RealTime now = RealTime::frame2RealTime
|
Chris@45
|
3755 (frame, getMainModel()->getSampleRate());
|
Chris@45
|
3756
|
Chris@45
|
3757 if (now.sec == m_lastPlayStatusSec) return;
|
Chris@45
|
3758
|
Chris@45
|
3759 RealTime then = RealTime::frame2RealTime
|
Chris@45
|
3760 (m_playSource->getPlayEndFrame(), getMainModel()->getSampleRate());
|
Chris@45
|
3761
|
Chris@45
|
3762 QString nowStr;
|
Chris@45
|
3763 QString thenStr;
|
Chris@45
|
3764 QString remainingStr;
|
Chris@45
|
3765
|
Chris@45
|
3766 if (then.sec > 10) {
|
Chris@45
|
3767 nowStr = now.toSecText().c_str();
|
Chris@45
|
3768 thenStr = then.toSecText().c_str();
|
Chris@45
|
3769 remainingStr = (then - now).toSecText().c_str();
|
Chris@45
|
3770 m_lastPlayStatusSec = now.sec;
|
Chris@45
|
3771 } else {
|
Chris@45
|
3772 nowStr = now.toText(true).c_str();
|
Chris@45
|
3773 thenStr = then.toText(true).c_str();
|
Chris@45
|
3774 remainingStr = (then - now).toText(true).c_str();
|
Chris@45
|
3775 }
|
Chris@45
|
3776
|
Chris@45
|
3777 m_myStatusMessage = tr("Playing: %1 of %2 (%3 remaining)")
|
Chris@45
|
3778 .arg(nowStr).arg(thenStr).arg(remainingStr);
|
Chris@45
|
3779
|
Chris@378
|
3780 getStatusLabel()->setText(m_myStatusMessage);
|
Chris@45
|
3781 }
|
Chris@45
|
3782
|
Chris@45
|
3783 void
|
Chris@486
|
3784 MainWindowBase::recordDurationChanged(sv_frame_t frame, sv_samplerate_t rate)
|
Chris@486
|
3785 {
|
Chris@486
|
3786 RealTime duration = RealTime::frame2RealTime(frame, rate);
|
Chris@486
|
3787 QString durStr = duration.toSecText().c_str();
|
Chris@486
|
3788
|
Chris@486
|
3789 m_myStatusMessage = tr("Recording: %1").arg(durStr);
|
Chris@486
|
3790
|
Chris@486
|
3791 getStatusLabel()->setText(m_myStatusMessage);
|
Chris@486
|
3792 }
|
Chris@486
|
3793
|
Chris@486
|
3794 void
|
Chris@435
|
3795 MainWindowBase::globalCentreFrameChanged(sv_frame_t )
|
Chris@45
|
3796 {
|
Chris@45
|
3797 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
|
Chris@45
|
3798 Pane *p = 0;
|
Chris@45
|
3799 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
|
Chris@45
|
3800 if (!p->getFollowGlobalPan()) return;
|
Chris@45
|
3801 updateVisibleRangeDisplay(p);
|
Chris@45
|
3802 }
|
Chris@45
|
3803
|
Chris@45
|
3804 void
|
Chris@435
|
3805 MainWindowBase::viewCentreFrameChanged(View *v, sv_frame_t frame)
|
Chris@45
|
3806 {
|
Chris@233
|
3807 // SVDEBUG << "MainWindowBase::viewCentreFrameChanged(" << v << "," << frame << ")" << endl;
|
Chris@123
|
3808
|
Chris@123
|
3809 if (m_viewDataDialogMap.find(v) != m_viewDataDialogMap.end()) {
|
Chris@123
|
3810 for (DataDialogSet::iterator i = m_viewDataDialogMap[v].begin();
|
Chris@123
|
3811 i != m_viewDataDialogMap[v].end(); ++i) {
|
Chris@127
|
3812 (*i)->userScrolledToFrame(frame);
|
Chris@123
|
3813 }
|
Chris@123
|
3814 }
|
Chris@45
|
3815 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
|
Chris@45
|
3816 Pane *p = 0;
|
Chris@45
|
3817 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
|
Chris@45
|
3818 if (v == p) updateVisibleRangeDisplay(p);
|
Chris@45
|
3819 }
|
Chris@45
|
3820
|
Chris@45
|
3821 void
|
Chris@366
|
3822 MainWindowBase::viewZoomLevelChanged(View *v, int , bool )
|
Chris@45
|
3823 {
|
Chris@45
|
3824 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
|
Chris@45
|
3825 Pane *p = 0;
|
Chris@45
|
3826 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
|
Chris@45
|
3827 if (v == p) updateVisibleRangeDisplay(p);
|
Chris@45
|
3828 }
|
Chris@45
|
3829
|
Chris@45
|
3830 void
|
Chris@45
|
3831 MainWindowBase::layerAdded(Layer *)
|
Chris@45
|
3832 {
|
Chris@233
|
3833 // SVDEBUG << "MainWindowBase::layerAdded(" << layer << ")" << endl;
|
Chris@45
|
3834 updateMenuStates();
|
Chris@45
|
3835 }
|
Chris@45
|
3836
|
Chris@45
|
3837 void
|
Chris@45
|
3838 MainWindowBase::layerRemoved(Layer *)
|
Chris@45
|
3839 {
|
Chris@233
|
3840 // SVDEBUG << "MainWindowBase::layerRemoved(" << layer << ")" << endl;
|
Chris@45
|
3841 updateMenuStates();
|
Chris@45
|
3842 }
|
Chris@45
|
3843
|
Chris@45
|
3844 void
|
Chris@45
|
3845 MainWindowBase::layerAboutToBeDeleted(Layer *layer)
|
Chris@45
|
3846 {
|
Chris@233
|
3847 // SVDEBUG << "MainWindowBase::layerAboutToBeDeleted(" << layer << ")" << endl;
|
Chris@123
|
3848
|
Chris@128
|
3849 removeLayerEditDialog(layer);
|
Chris@123
|
3850
|
Chris@47
|
3851 if (m_timeRulerLayer && (layer == m_timeRulerLayer)) {
|
Chris@595
|
3852 // cerr << "(this is the time ruler layer)" << endl;
|
Chris@595
|
3853 m_timeRulerLayer = 0;
|
Chris@45
|
3854 }
|
Chris@45
|
3855 }
|
Chris@45
|
3856
|
Chris@45
|
3857 void
|
Chris@45
|
3858 MainWindowBase::layerInAView(Layer *layer, bool inAView)
|
Chris@45
|
3859 {
|
Chris@233
|
3860 // SVDEBUG << "MainWindowBase::layerInAView(" << layer << "," << inAView << ")" << endl;
|
Chris@128
|
3861
|
Chris@128
|
3862 if (!inAView) removeLayerEditDialog(layer);
|
Chris@45
|
3863
|
Chris@45
|
3864 // Check whether we need to add or remove model from play source
|
Chris@45
|
3865 Model *model = layer->getModel();
|
Chris@45
|
3866 if (model) {
|
Chris@45
|
3867 if (inAView) {
|
Chris@45
|
3868 m_playSource->addModel(model);
|
Chris@45
|
3869 } else {
|
Chris@45
|
3870 bool found = false;
|
Chris@45
|
3871 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@45
|
3872 Pane *pane = m_paneStack->getPane(i);
|
Chris@45
|
3873 if (!pane) continue;
|
Chris@45
|
3874 for (int j = 0; j < pane->getLayerCount(); ++j) {
|
Chris@45
|
3875 Layer *pl = pane->getLayer(j);
|
Chris@183
|
3876 if (pl &&
|
Chris@183
|
3877 !dynamic_cast<TimeRulerLayer *>(pl) &&
|
Chris@183
|
3878 (pl->getModel() == model)) {
|
Chris@45
|
3879 found = true;
|
Chris@45
|
3880 break;
|
Chris@45
|
3881 }
|
Chris@45
|
3882 }
|
Chris@45
|
3883 if (found) break;
|
Chris@45
|
3884 }
|
Chris@173
|
3885 if (!found) {
|
Chris@173
|
3886 m_playSource->removeModel(model);
|
Chris@173
|
3887 }
|
Chris@45
|
3888 }
|
Chris@45
|
3889 }
|
Chris@45
|
3890
|
Chris@45
|
3891 updateMenuStates();
|
Chris@45
|
3892 }
|
Chris@45
|
3893
|
Chris@45
|
3894 void
|
Chris@128
|
3895 MainWindowBase::removeLayerEditDialog(Layer *layer)
|
Chris@128
|
3896 {
|
Chris@128
|
3897 if (m_layerDataDialogMap.find(layer) != m_layerDataDialogMap.end()) {
|
Chris@128
|
3898
|
Chris@128
|
3899 ModelDataTableDialog *dialog = m_layerDataDialogMap[layer];
|
Chris@128
|
3900
|
Chris@128
|
3901 for (ViewDataDialogMap::iterator vi = m_viewDataDialogMap.begin();
|
Chris@128
|
3902 vi != m_viewDataDialogMap.end(); ++vi) {
|
Chris@128
|
3903 vi->second.erase(dialog);
|
Chris@128
|
3904 }
|
Chris@128
|
3905
|
Chris@128
|
3906 m_layerDataDialogMap.erase(layer);
|
Chris@128
|
3907 delete dialog;
|
Chris@128
|
3908 }
|
Chris@128
|
3909 }
|
Chris@128
|
3910
|
Chris@128
|
3911 void
|
Chris@45
|
3912 MainWindowBase::modelAdded(Model *model)
|
Chris@45
|
3913 {
|
Chris@233
|
3914 // SVDEBUG << "MainWindowBase::modelAdded(" << model << ")" << endl;
|
Chris@595
|
3915 std::cerr << "\nAdding model " << model->getTypeName() << " to playsource " << std::endl;
|
Chris@45
|
3916 m_playSource->addModel(model);
|
Chris@45
|
3917 }
|
Chris@45
|
3918
|
Chris@45
|
3919 void
|
Chris@45
|
3920 MainWindowBase::mainModelChanged(WaveFileModel *model)
|
Chris@45
|
3921 {
|
Chris@233
|
3922 // SVDEBUG << "MainWindowBase::mainModelChanged(" << model << ")" << endl;
|
Chris@45
|
3923 updateDescriptionLabel();
|
Chris@45
|
3924 if (model) m_viewManager->setMainModelSampleRate(model->getSampleRate());
|
Chris@475
|
3925 if (model && !(m_playTarget || m_audioIO) &&
|
Chris@475
|
3926 (m_soundOptions & WithAudioOutput)) {
|
Chris@475
|
3927 createAudioIO();
|
Chris@360
|
3928 }
|
Chris@45
|
3929 }
|
Chris@45
|
3930
|
Chris@45
|
3931 void
|
Chris@45
|
3932 MainWindowBase::modelAboutToBeDeleted(Model *model)
|
Chris@45
|
3933 {
|
Chris@233
|
3934 // SVDEBUG << "MainWindowBase::modelAboutToBeDeleted(" << model << ")" << endl;
|
Chris@45
|
3935 if (model == m_viewManager->getPlaybackModel()) {
|
Chris@45
|
3936 m_viewManager->setPlaybackModel(0);
|
Chris@45
|
3937 }
|
Chris@45
|
3938 m_playSource->removeModel(model);
|
Chris@45
|
3939 }
|
Chris@45
|
3940
|
Chris@45
|
3941 void
|
Chris@55
|
3942 MainWindowBase::paneDeleteButtonClicked(Pane *pane)
|
Chris@55
|
3943 {
|
Chris@55
|
3944 bool found = false;
|
Chris@55
|
3945 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@55
|
3946 if (m_paneStack->getPane(i) == pane) {
|
Chris@55
|
3947 found = true;
|
Chris@55
|
3948 break;
|
Chris@55
|
3949 }
|
Chris@55
|
3950 }
|
Chris@55
|
3951 if (!found) {
|
Chris@233
|
3952 SVDEBUG << "MainWindowBase::paneDeleteButtonClicked: Unknown pane "
|
Chris@229
|
3953 << pane << endl;
|
Chris@55
|
3954 return;
|
Chris@55
|
3955 }
|
Chris@55
|
3956
|
Chris@55
|
3957 CommandHistory::getInstance()->startCompoundOperation
|
Chris@595
|
3958 (tr("Delete Pane"), true);
|
Chris@55
|
3959
|
Chris@55
|
3960 while (pane->getLayerCount() > 0) {
|
Chris@55
|
3961 Layer *layer = pane->getLayer(0);
|
Chris@55
|
3962 if (layer) {
|
Chris@55
|
3963 m_document->removeLayerFromView(pane, layer);
|
Chris@55
|
3964 } else {
|
Chris@55
|
3965 break;
|
Chris@55
|
3966 }
|
Chris@55
|
3967 }
|
Chris@55
|
3968
|
Chris@55
|
3969 RemovePaneCommand *command = new RemovePaneCommand(this, pane);
|
Chris@55
|
3970 CommandHistory::getInstance()->addCommand(command);
|
Chris@55
|
3971
|
Chris@55
|
3972 CommandHistory::getInstance()->endCompoundOperation();
|
Chris@55
|
3973
|
Chris@55
|
3974 updateMenuStates();
|
Chris@55
|
3975 }
|
Chris@55
|
3976
|
Chris@55
|
3977 void
|
Chris@429
|
3978 MainWindowBase::alignmentComplete(AlignmentModel *model)
|
Chris@429
|
3979 {
|
Chris@429
|
3980 cerr << "MainWindowBase::alignmentComplete(" << model << ")" << endl;
|
Chris@429
|
3981 }
|
Chris@429
|
3982
|
Chris@429
|
3983 void
|
Chris@45
|
3984 MainWindowBase::pollOSC()
|
Chris@45
|
3985 {
|
Chris@45
|
3986 if (!m_oscQueue || m_oscQueue->isEmpty()) return;
|
Chris@233
|
3987 SVDEBUG << "MainWindowBase::pollOSC: have " << m_oscQueue->getMessagesAvailable() << " messages" << endl;
|
Chris@45
|
3988
|
Chris@45
|
3989 if (m_openingAudioFile) return;
|
Chris@45
|
3990
|
Chris@45
|
3991 OSCMessage message = m_oscQueue->readMessage();
|
Chris@45
|
3992
|
Chris@45
|
3993 if (message.getTarget() != 0) {
|
Chris@45
|
3994 return; //!!! for now -- this class is target 0, others not handled yet
|
Chris@45
|
3995 }
|
Chris@45
|
3996
|
Chris@45
|
3997 handleOSCMessage(message);
|
Chris@45
|
3998 }
|
Chris@45
|
3999
|
Chris@45
|
4000 void
|
Chris@45
|
4001 MainWindowBase::inProgressSelectionChanged()
|
Chris@45
|
4002 {
|
Chris@45
|
4003 Pane *currentPane = 0;
|
Chris@45
|
4004 if (m_paneStack) currentPane = m_paneStack->getCurrentPane();
|
justin@331
|
4005 if (currentPane) {
|
justin@331
|
4006 //cerr << "JTEST: mouse event on selection pane" << endl;
|
justin@331
|
4007 updateVisibleRangeDisplay(currentPane);
|
justin@331
|
4008 }
|
Chris@45
|
4009 }
|
Chris@45
|
4010
|
Chris@45
|
4011 void
|
Chris@45
|
4012 MainWindowBase::contextHelpChanged(const QString &s)
|
Chris@45
|
4013 {
|
Chris@378
|
4014 QLabel *lab = getStatusLabel();
|
Chris@375
|
4015
|
Chris@45
|
4016 if (s == "" && m_myStatusMessage != "") {
|
Chris@378
|
4017 if (lab->text() != m_myStatusMessage) {
|
Chris@378
|
4018 lab->setText(m_myStatusMessage);
|
Chris@375
|
4019 }
|
Chris@45
|
4020 return;
|
Chris@45
|
4021 }
|
Chris@375
|
4022
|
Chris@378
|
4023 lab->setText(s);
|
Chris@45
|
4024 }
|
Chris@45
|
4025
|
Chris@45
|
4026 void
|
Chris@45
|
4027 MainWindowBase::openHelpUrl(QString url)
|
Chris@45
|
4028 {
|
Chris@45
|
4029 // This method mostly lifted from Qt Assistant source code
|
Chris@45
|
4030
|
Chris@45
|
4031 QProcess *process = new QProcess(this);
|
Chris@45
|
4032 connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater()));
|
Chris@45
|
4033
|
Chris@45
|
4034 QStringList args;
|
Chris@45
|
4035
|
Chris@45
|
4036 #ifdef Q_OS_MAC
|
Chris@45
|
4037 args.append(url);
|
Chris@45
|
4038 process->start("open", args);
|
Chris@45
|
4039 #else
|
Chris@45
|
4040 #ifdef Q_OS_WIN32
|
Chris@599
|
4041 std::string pfiles;
|
Chris@599
|
4042 (void)getEnvUtf8("ProgramFiles", pfiles);
|
Chris@599
|
4043 QString command =
|
Chris@599
|
4044 QString::fromStdString(pfiles) +
|
Chris@599
|
4045 QString("\\Internet Explorer\\IEXPLORE.EXE");
|
Chris@358
|
4046
|
Chris@358
|
4047 args.append(url);
|
Chris@358
|
4048 process->start(command, args);
|
Chris@45
|
4049 #else
|
Chris@45
|
4050 if (!qgetenv("KDE_FULL_SESSION").isEmpty()) {
|
Chris@45
|
4051 args.append("exec");
|
Chris@45
|
4052 args.append(url);
|
Chris@45
|
4053 process->start("kfmclient", args);
|
Chris@45
|
4054 } else if (!qgetenv("BROWSER").isEmpty()) {
|
Chris@45
|
4055 args.append(url);
|
Chris@45
|
4056 process->start(qgetenv("BROWSER"), args);
|
Chris@45
|
4057 } else {
|
Chris@45
|
4058 args.append(url);
|
Chris@45
|
4059 process->start("firefox", args);
|
Chris@45
|
4060 }
|
Chris@45
|
4061 #endif
|
Chris@45
|
4062 #endif
|
Chris@45
|
4063 }
|
Chris@45
|
4064
|
Chris@483
|
4065 void
|
Chris@483
|
4066 MainWindowBase::openLocalFolder(QString path)
|
Chris@483
|
4067 {
|
Chris@483
|
4068 QDir d(path);
|
Chris@483
|
4069 if (d.exists()) {
|
Chris@483
|
4070 QStringList args;
|
Chris@483
|
4071 QString path = d.canonicalPath();
|
Chris@483
|
4072 #if defined Q_OS_WIN32
|
Chris@483
|
4073 // Although the Win32 API is quite happy to have
|
Chris@483
|
4074 // forward slashes as directory separators, Windows
|
Chris@483
|
4075 // Explorer is not
|
Chris@483
|
4076 path = path.replace('/', '\\');
|
Chris@483
|
4077 args << path;
|
Chris@483
|
4078 QProcess::execute("c:/windows/explorer.exe", args);
|
Chris@483
|
4079 #else
|
Chris@483
|
4080 args << path;
|
Chris@605
|
4081 QProcess process;
|
Chris@605
|
4082 QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
Chris@606
|
4083 env.insert("LD_LIBRARY_PATH", "");
|
Chris@605
|
4084 process.setProcessEnvironment(env);
|
Chris@605
|
4085 process.start(
|
Chris@483
|
4086 #if defined Q_OS_MAC
|
Chris@483
|
4087 "/usr/bin/open",
|
Chris@483
|
4088 #else
|
Chris@483
|
4089 "/usr/bin/xdg-open",
|
Chris@483
|
4090 #endif
|
Chris@483
|
4091 args);
|
Chris@608
|
4092 process.waitForFinished();
|
Chris@483
|
4093 #endif
|
Chris@483
|
4094 }
|
Chris@483
|
4095 }
|
Chris@483
|
4096
|