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@619
|
1869 delete dialog;
|
Chris@109
|
1870 }
|
Chris@109
|
1871
|
Chris@45
|
1872 if (model) {
|
Chris@45
|
1873
|
Chris@233
|
1874 SVDEBUG << "MainWindowBase::openLayer: Have model" << endl;
|
Chris@45
|
1875
|
Chris@164
|
1876 emit activity(tr("Import MIDI file \"%1\"").arg(source.getLocation()));
|
Chris@164
|
1877
|
Chris@45
|
1878 Layer *newLayer = m_document->createImportedLayer(model);
|
Chris@45
|
1879
|
Chris@45
|
1880 if (newLayer) {
|
Chris@45
|
1881
|
Chris@45
|
1882 m_document->addLayerToView(pane, newLayer);
|
Chris@88
|
1883 m_paneStack->setCurrentLayer(pane, newLayer);
|
Chris@88
|
1884
|
Chris@45
|
1885 m_recentFiles.addFile(source.getLocation());
|
Chris@45
|
1886
|
Chris@45
|
1887 if (!source.isRemote()) {
|
Chris@45
|
1888 registerLastOpenedFilePath
|
Chris@45
|
1889 (FileFinder::LayerFile,
|
Chris@45
|
1890 path); // for file dialog
|
Chris@45
|
1891 }
|
Chris@88
|
1892
|
Chris@45
|
1893 return FileOpenSucceeded;
|
Chris@45
|
1894 }
|
Chris@45
|
1895 }
|
Chris@45
|
1896 } catch (DataFileReaderFactory::Exception e) {
|
Chris@45
|
1897 if (e == DataFileReaderFactory::ImportCancelled) {
|
Chris@45
|
1898 return FileOpenCancelled;
|
Chris@45
|
1899 }
|
Chris@45
|
1900 }
|
Chris@45
|
1901 }
|
Chris@45
|
1902
|
Chris@45
|
1903 return FileOpenFailed;
|
Chris@45
|
1904 }
|
Chris@45
|
1905
|
Chris@45
|
1906 MainWindowBase::FileOpenStatus
|
Chris@45
|
1907 MainWindowBase::openImage(FileSource source)
|
Chris@45
|
1908 {
|
Chris@233
|
1909 SVDEBUG << "MainWindowBase::openImage(" << source.getLocation() << ")" << endl;
|
Chris@135
|
1910
|
Chris@45
|
1911 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@45
|
1912
|
Chris@45
|
1913 if (!pane) {
|
Chris@595
|
1914 // shouldn't happen, as the menu action should have been disabled
|
Chris@595
|
1915 cerr << "WARNING: MainWindowBase::openImage: no current pane" << endl;
|
Chris@595
|
1916 return FileOpenWrongMode;
|
Chris@45
|
1917 }
|
Chris@45
|
1918
|
Chris@45
|
1919 if (!m_document->getMainModel()) {
|
Chris@45
|
1920 return FileOpenWrongMode;
|
Chris@45
|
1921 }
|
Chris@45
|
1922
|
Chris@45
|
1923 bool newLayer = false;
|
Chris@45
|
1924
|
Chris@45
|
1925 ImageLayer *il = dynamic_cast<ImageLayer *>(pane->getSelectedLayer());
|
Chris@45
|
1926 if (!il) {
|
Chris@45
|
1927 for (int i = pane->getLayerCount()-1; i >= 0; --i) {
|
Chris@45
|
1928 il = dynamic_cast<ImageLayer *>(pane->getLayer(i));
|
Chris@45
|
1929 if (il) break;
|
Chris@45
|
1930 }
|
Chris@45
|
1931 }
|
Chris@45
|
1932 if (!il) {
|
Chris@45
|
1933 il = dynamic_cast<ImageLayer *>
|
Chris@45
|
1934 (m_document->createEmptyLayer(LayerFactory::Image));
|
Chris@45
|
1935 if (!il) return FileOpenFailed;
|
Chris@45
|
1936 newLayer = true;
|
Chris@45
|
1937 }
|
Chris@45
|
1938
|
Chris@45
|
1939 // We don't put the image file in Recent Files
|
Chris@45
|
1940
|
Chris@293
|
1941 cerr << "openImage: trying location \"" << source.getLocation() << "\" in image layer" << endl;
|
Chris@45
|
1942
|
Chris@45
|
1943 if (!il->addImage(m_viewManager->getGlobalCentreFrame(), source.getLocation())) {
|
Chris@45
|
1944 if (newLayer) {
|
Chris@52
|
1945 m_document->deleteLayer(il); // also releases its model
|
Chris@45
|
1946 }
|
Chris@45
|
1947 return FileOpenFailed;
|
Chris@45
|
1948 } else {
|
Chris@45
|
1949 if (newLayer) {
|
Chris@45
|
1950 m_document->addLayerToView(pane, il);
|
Chris@45
|
1951 }
|
Chris@45
|
1952 m_paneStack->setCurrentLayer(pane, il);
|
Chris@45
|
1953 }
|
Chris@45
|
1954
|
Chris@45
|
1955 return FileOpenSucceeded;
|
Chris@45
|
1956 }
|
Chris@45
|
1957
|
Chris@45
|
1958 MainWindowBase::FileOpenStatus
|
Chris@427
|
1959 MainWindowBase::openDirOfAudio(QString dirPath)
|
Chris@427
|
1960 {
|
Chris@427
|
1961 QDir dir(dirPath);
|
Chris@427
|
1962 QStringList files = dir.entryList(QDir::Files | QDir::Readable);
|
Chris@427
|
1963 files.sort();
|
Chris@427
|
1964
|
Chris@427
|
1965 FileOpenStatus status = FileOpenFailed;
|
Chris@427
|
1966 bool first = true;
|
Chris@427
|
1967 bool cancelled = false;
|
Chris@427
|
1968
|
Chris@427
|
1969 foreach (QString file, files) {
|
Chris@427
|
1970
|
Chris@427
|
1971 FileSource source(dir.filePath(file));
|
Chris@427
|
1972 if (!source.isAvailable()) {
|
Chris@427
|
1973 continue;
|
Chris@427
|
1974 }
|
Chris@427
|
1975
|
Chris@427
|
1976 if (AudioFileReaderFactory::getKnownExtensions().contains
|
Chris@427
|
1977 (source.getExtension().toLower())) {
|
Chris@427
|
1978
|
Chris@427
|
1979 AudioFileOpenMode mode = CreateAdditionalModel;
|
Chris@427
|
1980 if (first) mode = ReplaceSession;
|
Chris@427
|
1981
|
Chris@427
|
1982 switch (openAudio(source, mode)) {
|
Chris@427
|
1983 case FileOpenSucceeded:
|
Chris@427
|
1984 status = FileOpenSucceeded;
|
Chris@427
|
1985 first = false;
|
Chris@427
|
1986 break;
|
Chris@427
|
1987 case FileOpenFailed:
|
Chris@427
|
1988 break;
|
Chris@427
|
1989 case FileOpenCancelled:
|
Chris@427
|
1990 cancelled = true;
|
Chris@427
|
1991 break;
|
Chris@427
|
1992 case FileOpenWrongMode:
|
Chris@427
|
1993 break;
|
Chris@427
|
1994 }
|
Chris@427
|
1995 }
|
Chris@427
|
1996
|
Chris@427
|
1997 if (cancelled) break;
|
Chris@427
|
1998 }
|
Chris@427
|
1999
|
Chris@427
|
2000 return status;
|
Chris@427
|
2001 }
|
Chris@427
|
2002
|
Chris@427
|
2003 MainWindowBase::FileOpenStatus
|
Chris@373
|
2004 MainWindowBase::openSessionPath(QString fileOrUrl)
|
Chris@45
|
2005 {
|
Chris@134
|
2006 ProgressDialog dialog(tr("Opening session..."), true, 2000, this);
|
Chris@134
|
2007 connect(&dialog, SIGNAL(showing()), this, SIGNAL(hideSplash()));
|
Chris@109
|
2008 return openSession(FileSource(fileOrUrl, &dialog));
|
Chris@45
|
2009 }
|
Chris@45
|
2010
|
Chris@45
|
2011 MainWindowBase::FileOpenStatus
|
Chris@45
|
2012 MainWindowBase::openSession(FileSource source)
|
Chris@45
|
2013 {
|
Chris@233
|
2014 SVDEBUG << "MainWindowBase::openSession(" << source.getLocation() << ")" << endl;
|
Chris@135
|
2015
|
Chris@45
|
2016 if (!source.isAvailable()) return FileOpenFailed;
|
Chris@145
|
2017 source.waitForData();
|
Chris@141
|
2018
|
Chris@341
|
2019 QString sessionExt =
|
Chris@341
|
2020 InteractiveFileFinder::getInstance()->getApplicationSessionExtension();
|
Chris@341
|
2021
|
Chris@341
|
2022 if (source.getExtension().toLower() != sessionExt) {
|
Chris@145
|
2023
|
Chris@145
|
2024 RDFImporter::RDFDocumentType rdfType =
|
Chris@145
|
2025 RDFImporter::identifyDocumentType
|
Chris@145
|
2026 (QUrl::fromLocalFile(source.getLocalFilename()).toString());
|
Chris@145
|
2027
|
Chris@293
|
2028 // cerr << "RDF type: " << (int)rdfType << endl;
|
Chris@148
|
2029
|
Chris@145
|
2030 if (rdfType == RDFImporter::AudioRefAndAnnotations ||
|
Chris@145
|
2031 rdfType == RDFImporter::AudioRef) {
|
Chris@145
|
2032 return openSessionFromRDF(source);
|
Chris@145
|
2033 } else if (rdfType != RDFImporter::NotRDF) {
|
Chris@145
|
2034 return FileOpenFailed;
|
Chris@145
|
2035 }
|
Chris@145
|
2036
|
Chris@152
|
2037 if (source.getExtension().toLower() == "xml") {
|
Chris@140
|
2038 if (SVFileReader::identifyXmlFile(source.getLocalFilename()) ==
|
Chris@140
|
2039 SVFileReader::SVSessionFile) {
|
Chris@293
|
2040 cerr << "This XML file looks like a session file, attempting to open it as a session" << endl;
|
Chris@140
|
2041 } else {
|
Chris@140
|
2042 return FileOpenFailed;
|
Chris@140
|
2043 }
|
Chris@140
|
2044 } else {
|
Chris@140
|
2045 return FileOpenFailed;
|
Chris@140
|
2046 }
|
Chris@140
|
2047 }
|
Chris@45
|
2048
|
Chris@140
|
2049 QXmlInputSource *inputSource = 0;
|
Chris@140
|
2050 BZipFileDevice *bzFile = 0;
|
Chris@140
|
2051 QFile *rawFile = 0;
|
Chris@140
|
2052
|
Chris@341
|
2053 if (source.getExtension().toLower() == sessionExt) {
|
Chris@140
|
2054 bzFile = new BZipFileDevice(source.getLocalFilename());
|
Chris@140
|
2055 if (!bzFile->open(QIODevice::ReadOnly)) {
|
Chris@140
|
2056 delete bzFile;
|
Chris@140
|
2057 return FileOpenFailed;
|
Chris@140
|
2058 }
|
Chris@140
|
2059 inputSource = new QXmlInputSource(bzFile);
|
Chris@140
|
2060 } else {
|
Chris@140
|
2061 rawFile = new QFile(source.getLocalFilename());
|
Chris@140
|
2062 inputSource = new QXmlInputSource(rawFile);
|
Chris@140
|
2063 }
|
Chris@140
|
2064
|
Chris@140
|
2065 if (!checkSaveModified()) {
|
Chris@140
|
2066 if (bzFile) bzFile->close();
|
Chris@140
|
2067 delete inputSource;
|
Chris@140
|
2068 delete bzFile;
|
Chris@140
|
2069 delete rawFile;
|
Chris@140
|
2070 return FileOpenCancelled;
|
Chris@140
|
2071 }
|
Chris@45
|
2072
|
Chris@45
|
2073 QString error;
|
Chris@45
|
2074 closeSession();
|
Chris@45
|
2075 createDocument();
|
Chris@45
|
2076
|
Chris@45
|
2077 PaneCallback callback(this);
|
Chris@45
|
2078 m_viewManager->clearSelections();
|
Chris@45
|
2079
|
Chris@45
|
2080 SVFileReader reader(m_document, callback, source.getLocation());
|
Chris@79
|
2081 connect
|
Chris@79
|
2082 (&reader, SIGNAL(modelRegenerationFailed(QString, QString, QString)),
|
Chris@79
|
2083 this, SLOT(modelRegenerationFailed(QString, QString, QString)));
|
Chris@79
|
2084 connect
|
Chris@79
|
2085 (&reader, SIGNAL(modelRegenerationWarning(QString, QString, QString)),
|
Chris@79
|
2086 this, SLOT(modelRegenerationWarning(QString, QString, QString)));
|
Chris@140
|
2087
|
Chris@140
|
2088 reader.parse(*inputSource);
|
Chris@45
|
2089
|
Chris@45
|
2090 if (!reader.isOK()) {
|
Chris@45
|
2091 error = tr("SV XML file read error:\n%1").arg(reader.getErrorString());
|
Chris@45
|
2092 }
|
Chris@45
|
2093
|
Chris@140
|
2094 if (bzFile) bzFile->close();
|
Chris@140
|
2095
|
Chris@140
|
2096 delete inputSource;
|
Chris@140
|
2097 delete bzFile;
|
Chris@140
|
2098 delete rawFile;
|
Chris@45
|
2099
|
Chris@45
|
2100 bool ok = (error == "");
|
Chris@45
|
2101
|
Chris@45
|
2102 if (ok) {
|
Chris@45
|
2103
|
Chris@164
|
2104 emit activity(tr("Import session file \"%1\"").arg(source.getLocation()));
|
Chris@164
|
2105
|
Chris@595
|
2106 setWindowTitle(tr("%1: %2")
|
Chris@57
|
2107 .arg(QApplication::applicationName())
|
Chris@595
|
2108 .arg(source.getLocation()));
|
Chris@595
|
2109
|
Chris@601
|
2110 if (!source.isRemote() && !m_document->isIncomplete()) {
|
Chris@601
|
2111 // Setting the session file path enables the Save (as
|
Chris@601
|
2112 // opposed to Save As...) option. We can't do this if we
|
Chris@601
|
2113 // don't have a local path to save to, but we also don't
|
Chris@601
|
2114 // want to do it if we failed to find an audio file or
|
Chris@601
|
2115 // similar on load, as the audio reference would then end
|
Chris@601
|
2116 // up being lost from any saved or auto-saved-on-exit copy
|
Chris@601
|
2117 m_sessionFile = source.getLocalFilename();
|
Chris@602
|
2118 } else {
|
Chris@602
|
2119 QMessageBox::warning
|
Chris@602
|
2120 (this,
|
Chris@602
|
2121 tr("Incomplete session loaded"),
|
Chris@603
|
2122 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
|
2123 QMessageBox::Ok);
|
Chris@601
|
2124 }
|
Chris@595
|
2125
|
Chris@595
|
2126 setupMenus();
|
Chris@577
|
2127 findTimeRulerLayer();
|
Chris@45
|
2128
|
Chris@595
|
2129 CommandHistory::getInstance()->clear();
|
Chris@595
|
2130 CommandHistory::getInstance()->documentSaved();
|
Chris@595
|
2131 m_documentModified = false;
|
Chris@595
|
2132 updateMenuStates();
|
Chris@45
|
2133
|
Chris@227
|
2134 m_recentFiles.addFile(source.getLocation());
|
Chris@45
|
2135
|
Chris@45
|
2136 if (!source.isRemote()) {
|
Chris@45
|
2137 // for file dialog
|
Chris@45
|
2138 registerLastOpenedFilePath(FileFinder::SessionFile,
|
Chris@227
|
2139 source.getLocalFilename());
|
Chris@45
|
2140 }
|
Chris@45
|
2141
|
Chris@342
|
2142 emit sessionLoaded();
|
Chris@342
|
2143
|
Chris@45
|
2144 } else {
|
Chris@595
|
2145 setWindowTitle(QApplication::applicationName());
|
Chris@45
|
2146 }
|
Chris@45
|
2147
|
Chris@45
|
2148 return ok ? FileOpenSucceeded : FileOpenFailed;
|
Chris@45
|
2149 }
|
Chris@45
|
2150
|
Chris@141
|
2151 MainWindowBase::FileOpenStatus
|
Chris@230
|
2152 MainWindowBase::openSessionTemplate(QString templateName)
|
Chris@230
|
2153 {
|
Chris@230
|
2154 // Template in the user's template directory takes
|
Chris@230
|
2155 // priority over a bundled one; we don't unbundle, but
|
Chris@230
|
2156 // open directly from the bundled file (where applicable)
|
Chris@230
|
2157 ResourceFinder rf;
|
Chris@230
|
2158 QString tfile = rf.getResourcePath("templates", templateName + ".svt");
|
Chris@230
|
2159 if (tfile != "") {
|
Chris@294
|
2160 cerr << "SV loading template file " << tfile << endl;
|
Chris@230
|
2161 return openSessionTemplate(FileSource("file:" + tfile));
|
Chris@230
|
2162 } else {
|
Chris@230
|
2163 return FileOpenFailed;
|
Chris@230
|
2164 }
|
Chris@230
|
2165 }
|
Chris@230
|
2166
|
Chris@230
|
2167 MainWindowBase::FileOpenStatus
|
Chris@227
|
2168 MainWindowBase::openSessionTemplate(FileSource source)
|
Chris@227
|
2169 {
|
Chris@294
|
2170 cerr << "MainWindowBase::openSessionTemplate(" << source.getLocation() << ")" << endl;
|
Chris@227
|
2171
|
Chris@227
|
2172 if (!source.isAvailable()) return FileOpenFailed;
|
Chris@227
|
2173 source.waitForData();
|
Chris@227
|
2174
|
Chris@227
|
2175 QXmlInputSource *inputSource = 0;
|
Chris@227
|
2176 QFile *file = 0;
|
Chris@227
|
2177
|
Chris@227
|
2178 file = new QFile(source.getLocalFilename());
|
Chris@227
|
2179 inputSource = new QXmlInputSource(file);
|
Chris@227
|
2180
|
Chris@227
|
2181 if (!checkSaveModified()) {
|
Chris@227
|
2182 delete inputSource;
|
Chris@227
|
2183 delete file;
|
Chris@227
|
2184 return FileOpenCancelled;
|
Chris@227
|
2185 }
|
Chris@227
|
2186
|
Chris@227
|
2187 QString error;
|
Chris@227
|
2188 closeSession();
|
Chris@227
|
2189 createDocument();
|
Chris@227
|
2190
|
Chris@227
|
2191 PaneCallback callback(this);
|
Chris@227
|
2192 m_viewManager->clearSelections();
|
Chris@227
|
2193
|
Chris@227
|
2194 SVFileReader reader(m_document, callback, source.getLocation());
|
Chris@227
|
2195 connect
|
Chris@227
|
2196 (&reader, SIGNAL(modelRegenerationFailed(QString, QString, QString)),
|
Chris@227
|
2197 this, SLOT(modelRegenerationFailed(QString, QString, QString)));
|
Chris@227
|
2198 connect
|
Chris@227
|
2199 (&reader, SIGNAL(modelRegenerationWarning(QString, QString, QString)),
|
Chris@227
|
2200 this, SLOT(modelRegenerationWarning(QString, QString, QString)));
|
Chris@227
|
2201
|
Chris@227
|
2202 reader.parse(*inputSource);
|
Chris@227
|
2203
|
Chris@227
|
2204 if (!reader.isOK()) {
|
Chris@227
|
2205 error = tr("SV XML file read error:\n%1").arg(reader.getErrorString());
|
Chris@227
|
2206 }
|
Chris@227
|
2207
|
Chris@227
|
2208 delete inputSource;
|
Chris@227
|
2209 delete file;
|
Chris@227
|
2210
|
Chris@227
|
2211 bool ok = (error == "");
|
Chris@227
|
2212
|
Chris@227
|
2213 setWindowTitle(QApplication::applicationName());
|
Chris@227
|
2214
|
Chris@227
|
2215 if (ok) {
|
Chris@227
|
2216
|
Chris@227
|
2217 emit activity(tr("Open session template \"%1\"").arg(source.getLocation()));
|
Chris@227
|
2218
|
Chris@595
|
2219 setupMenus();
|
Chris@577
|
2220 findTimeRulerLayer();
|
Chris@227
|
2221
|
Chris@595
|
2222 CommandHistory::getInstance()->clear();
|
Chris@595
|
2223 CommandHistory::getInstance()->documentSaved();
|
Chris@595
|
2224 m_documentModified = false;
|
Chris@595
|
2225 updateMenuStates();
|
Chris@342
|
2226
|
Chris@342
|
2227 emit sessionLoaded();
|
Chris@227
|
2228 }
|
Chris@227
|
2229
|
Chris@227
|
2230 return ok ? FileOpenSucceeded : FileOpenFailed;
|
Chris@227
|
2231 }
|
Chris@227
|
2232
|
Chris@227
|
2233 MainWindowBase::FileOpenStatus
|
Chris@141
|
2234 MainWindowBase::openSessionFromRDF(FileSource source)
|
Chris@141
|
2235 {
|
Chris@233
|
2236 SVDEBUG << "MainWindowBase::openSessionFromRDF(" << source.getLocation() << ")" << endl;
|
Chris@141
|
2237
|
Chris@141
|
2238 if (!source.isAvailable()) return FileOpenFailed;
|
Chris@141
|
2239 source.waitForData();
|
Chris@141
|
2240
|
Chris@145
|
2241 if (!checkSaveModified()) {
|
Chris@145
|
2242 return FileOpenCancelled;
|
Chris@141
|
2243 }
|
Chris@143
|
2244
|
Chris@145
|
2245 closeSession();
|
Chris@145
|
2246 createDocument();
|
Chris@145
|
2247
|
Chris@145
|
2248 FileOpenStatus status = openLayersFromRDF(source);
|
Chris@141
|
2249
|
Chris@141
|
2250 setupMenus();
|
Chris@577
|
2251 findTimeRulerLayer();
|
Chris@141
|
2252
|
Chris@141
|
2253 setWindowTitle(tr("%1: %2")
|
Chris@141
|
2254 .arg(QApplication::applicationName())
|
Chris@141
|
2255 .arg(source.getLocation()));
|
Chris@141
|
2256 CommandHistory::getInstance()->clear();
|
Chris@141
|
2257 CommandHistory::getInstance()->documentSaved();
|
Chris@141
|
2258 m_documentModified = false;
|
Chris@145
|
2259
|
Chris@342
|
2260 emit sessionLoaded();
|
Chris@342
|
2261
|
Chris@145
|
2262 return status;
|
Chris@145
|
2263 }
|
Chris@145
|
2264
|
Chris@145
|
2265 MainWindowBase::FileOpenStatus
|
Chris@145
|
2266 MainWindowBase::openLayersFromRDF(FileSource source)
|
Chris@145
|
2267 {
|
Chris@435
|
2268 sv_samplerate_t rate = 0;
|
Chris@145
|
2269
|
Chris@233
|
2270 SVDEBUG << "MainWindowBase::openLayersFromRDF" << endl;
|
Chris@186
|
2271
|
Chris@145
|
2272 ProgressDialog dialog(tr("Importing from RDF..."), true, 2000, this);
|
Chris@145
|
2273 connect(&dialog, SIGNAL(showing()), this, SIGNAL(hideSplash()));
|
Chris@145
|
2274
|
Chris@145
|
2275 if (getMainModel()) {
|
Chris@145
|
2276 rate = getMainModel()->getSampleRate();
|
Chris@145
|
2277 } else if (Preferences::getInstance()->getResampleOnLoad()) {
|
Chris@552
|
2278 if (getMainModel()) {
|
Chris@552
|
2279 rate = getMainModel()->getSampleRate();
|
Chris@552
|
2280 }
|
Chris@145
|
2281 }
|
Chris@145
|
2282
|
Chris@145
|
2283 RDFImporter importer
|
Chris@145
|
2284 (QUrl::fromLocalFile(source.getLocalFilename()).toString(), rate);
|
Chris@145
|
2285
|
Chris@145
|
2286 if (!importer.isOK()) {
|
Chris@147
|
2287 if (importer.getErrorString() != "") {
|
Chris@147
|
2288 QMessageBox::critical
|
Chris@147
|
2289 (this, tr("Failed to import RDF"),
|
Chris@147
|
2290 tr("<b>Failed to import RDF</b><p>Importing data from RDF document at \"%1\" failed: %2</p>")
|
Chris@147
|
2291 .arg(source.getLocation()).arg(importer.getErrorString()));
|
Chris@147
|
2292 }
|
Chris@145
|
2293 return FileOpenFailed;
|
Chris@145
|
2294 }
|
Chris@145
|
2295
|
Chris@145
|
2296 std::vector<Model *> models = importer.getDataModels(&dialog);
|
Chris@145
|
2297
|
Chris@145
|
2298 dialog.setMessage(tr("Importing from RDF..."));
|
Chris@145
|
2299
|
Chris@145
|
2300 if (models.empty()) {
|
Chris@186
|
2301 QMessageBox::critical
|
Chris@186
|
2302 (this, tr("Failed to import RDF"),
|
Chris@186
|
2303 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
|
2304 return FileOpenFailed;
|
Chris@145
|
2305 }
|
Chris@145
|
2306
|
Chris@164
|
2307 emit activity(tr("Import RDF document \"%1\"").arg(source.getLocation()));
|
Chris@164
|
2308
|
Chris@145
|
2309 std::set<Model *> added;
|
Chris@145
|
2310
|
Chris@221
|
2311 for (int i = 0; i < (int)models.size(); ++i) {
|
Chris@145
|
2312
|
Chris@145
|
2313 Model *m = models[i];
|
Chris@145
|
2314 WaveFileModel *w = dynamic_cast<WaveFileModel *>(m);
|
Chris@145
|
2315
|
Chris@145
|
2316 if (w) {
|
Chris@145
|
2317
|
Chris@145
|
2318 Pane *pane = addPaneToStack();
|
Chris@145
|
2319 Layer *layer = 0;
|
Chris@145
|
2320
|
Chris@145
|
2321 if (m_timeRulerLayer) {
|
Chris@145
|
2322 m_document->addLayerToView(pane, m_timeRulerLayer);
|
Chris@145
|
2323 }
|
Chris@145
|
2324
|
Chris@145
|
2325 if (!getMainModel()) {
|
Chris@145
|
2326 m_document->setMainModel(w);
|
Chris@145
|
2327 layer = m_document->createMainModelLayer(LayerFactory::Waveform);
|
Chris@145
|
2328 } else {
|
Chris@145
|
2329 layer = m_document->createImportedLayer(w);
|
Chris@145
|
2330 }
|
Chris@145
|
2331
|
Chris@145
|
2332 m_document->addLayerToView(pane, layer);
|
Chris@145
|
2333
|
Chris@145
|
2334 added.insert(w);
|
Chris@145
|
2335
|
Chris@221
|
2336 for (int j = 0; j < (int)models.size(); ++j) {
|
Chris@145
|
2337
|
Chris@145
|
2338 Model *dm = models[j];
|
Chris@145
|
2339
|
Chris@145
|
2340 if (dm == m) continue;
|
Chris@145
|
2341 if (dm->getSourceModel() != m) continue;
|
Chris@145
|
2342
|
Chris@145
|
2343 layer = m_document->createImportedLayer(dm);
|
Chris@145
|
2344
|
Chris@145
|
2345 if (layer->isLayerOpaque() ||
|
Chris@145
|
2346 dynamic_cast<Colour3DPlotLayer *>(layer)) {
|
Chris@145
|
2347
|
Chris@156
|
2348 // these always go in a new pane, with nothing
|
Chris@156
|
2349 // else going in the same pane
|
Chris@156
|
2350
|
Chris@145
|
2351 Pane *singleLayerPane = addPaneToStack();
|
Chris@145
|
2352 if (m_timeRulerLayer) {
|
Chris@145
|
2353 m_document->addLayerToView(singleLayerPane, m_timeRulerLayer);
|
Chris@145
|
2354 }
|
Chris@145
|
2355 m_document->addLayerToView(singleLayerPane, layer);
|
Chris@145
|
2356
|
Chris@156
|
2357 } else if (layer->getLayerColourSignificance() ==
|
Chris@156
|
2358 Layer::ColourHasMeaningfulValue) {
|
Chris@156
|
2359
|
Chris@156
|
2360 // these can go in a pane with something else, but
|
Chris@156
|
2361 // only if none of the something elses also have
|
Chris@156
|
2362 // this quality
|
Chris@156
|
2363
|
Chris@156
|
2364 bool needNewPane = false;
|
Chris@156
|
2365 for (int i = 0; i < pane->getLayerCount(); ++i) {
|
Chris@156
|
2366 Layer *otherLayer = pane->getLayer(i);
|
Chris@156
|
2367 if (otherLayer &&
|
Chris@156
|
2368 (otherLayer->getLayerColourSignificance() ==
|
Chris@156
|
2369 Layer::ColourHasMeaningfulValue)) {
|
Chris@156
|
2370 needNewPane = true;
|
Chris@156
|
2371 break;
|
Chris@156
|
2372 }
|
Chris@156
|
2373 }
|
Chris@156
|
2374 if (needNewPane) {
|
Chris@156
|
2375 pane = addPaneToStack();
|
Chris@156
|
2376 }
|
Chris@156
|
2377
|
Chris@156
|
2378 m_document->addLayerToView(pane, layer);
|
Chris@156
|
2379
|
Chris@145
|
2380 } else {
|
Chris@145
|
2381
|
Chris@145
|
2382 if (pane->getLayerCount() > 4) {
|
Chris@145
|
2383 pane = addPaneToStack();
|
Chris@145
|
2384 }
|
Chris@145
|
2385
|
Chris@145
|
2386 m_document->addLayerToView(pane, layer);
|
Chris@145
|
2387 }
|
Chris@145
|
2388
|
Chris@145
|
2389 added.insert(dm);
|
Chris@145
|
2390 }
|
Chris@145
|
2391 }
|
Chris@145
|
2392 }
|
Chris@145
|
2393
|
Chris@221
|
2394 for (int i = 0; i < (int)models.size(); ++i) {
|
Chris@145
|
2395
|
Chris@145
|
2396 Model *m = models[i];
|
Chris@145
|
2397
|
Chris@145
|
2398 if (added.find(m) == added.end()) {
|
Chris@145
|
2399
|
Chris@145
|
2400 Layer *layer = m_document->createImportedLayer(m);
|
Chris@145
|
2401 if (!layer) return FileOpenFailed;
|
Chris@145
|
2402
|
Chris@145
|
2403 Pane *singleLayerPane = addPaneToStack();
|
Chris@145
|
2404 if (m_timeRulerLayer) {
|
Chris@145
|
2405 m_document->addLayerToView(singleLayerPane, m_timeRulerLayer);
|
Chris@145
|
2406 }
|
Chris@145
|
2407 m_document->addLayerToView(singleLayerPane, layer);
|
Chris@145
|
2408 }
|
Chris@145
|
2409 }
|
Chris@145
|
2410
|
Chris@145
|
2411 m_recentFiles.addFile(source.getLocation());
|
Chris@145
|
2412 return FileOpenSucceeded;
|
Chris@141
|
2413 }
|
Chris@141
|
2414
|
Chris@584
|
2415 class AudioLogCallback : public breakfastquay::AudioFactory::LogCallback
|
Chris@584
|
2416 {
|
Chris@584
|
2417 public:
|
Chris@584
|
2418 void log(std::string message) const override {
|
Chris@584
|
2419 SVDEBUG << message << endl;
|
Chris@584
|
2420 }
|
Chris@584
|
2421 };
|
Chris@584
|
2422
|
Chris@45
|
2423 void
|
Chris@475
|
2424 MainWindowBase::createAudioIO()
|
Chris@45
|
2425 {
|
Chris@475
|
2426 if (m_playTarget || m_audioIO) return;
|
Chris@475
|
2427
|
Chris@584
|
2428 static AudioLogCallback audioLogCallback;
|
Chris@584
|
2429 breakfastquay::AudioFactory::setLogCallback(&audioLogCallback);
|
Chris@584
|
2430
|
Chris@475
|
2431 if (!(m_soundOptions & WithAudioOutput)) return;
|
Chris@45
|
2432
|
Chris@126
|
2433 QSettings settings;
|
Chris@126
|
2434 settings.beginGroup("Preferences");
|
Chris@547
|
2435 QString implementation = settings.value
|
Chris@547
|
2436 ("audio-target", "").toString();
|
Chris@547
|
2437 QString suffix;
|
Chris@547
|
2438 if (implementation != "") suffix = "-" + implementation;
|
Chris@547
|
2439 QString recordDevice = settings.value
|
Chris@547
|
2440 ("audio-record-device" + suffix, "").toString();
|
Chris@547
|
2441 QString playbackDevice = settings.value
|
Chris@547
|
2442 ("audio-playback-device" + suffix, "").toString();
|
Chris@126
|
2443 settings.endGroup();
|
Chris@547
|
2444
|
Chris@547
|
2445 if (implementation == "auto") {
|
Chris@547
|
2446 implementation = "";
|
Chris@547
|
2447 }
|
Chris@468
|
2448
|
Chris@547
|
2449 breakfastquay::AudioFactory::Preference preference;
|
Chris@547
|
2450 preference.implementation = implementation.toStdString();
|
Chris@547
|
2451 preference.recordDevice = recordDevice.toStdString();
|
Chris@547
|
2452 preference.playbackDevice = playbackDevice.toStdString();
|
Chris@547
|
2453
|
Chris@547
|
2454 SVCERR << "createAudioIO: Preferred implementation = \""
|
Chris@547
|
2455 << preference.implementation << "\"" << endl;
|
Chris@547
|
2456 SVCERR << "createAudioIO: Preferred playback device = \""
|
Chris@547
|
2457 << preference.playbackDevice << "\"" << endl;
|
Chris@547
|
2458 SVCERR << "createAudioIO: Preferred record device = \""
|
Chris@547
|
2459 << preference.recordDevice << "\"" << endl;
|
Chris@475
|
2460
|
Chris@551
|
2461 if (!m_resamplerWrapper) {
|
Chris@551
|
2462 m_resamplerWrapper = new breakfastquay::ResamplerWrapper(m_playSource);
|
Chris@551
|
2463 m_playSource->setResamplerWrapper(m_resamplerWrapper);
|
Chris@551
|
2464 }
|
Chris@569
|
2465
|
Chris@569
|
2466 std::string errorString;
|
Chris@551
|
2467
|
Chris@475
|
2468 if (m_soundOptions & WithAudioInput) {
|
Chris@475
|
2469 m_audioIO = breakfastquay::AudioFactory::
|
Chris@569
|
2470 createCallbackIO(m_recordTarget, m_resamplerWrapper,
|
Chris@569
|
2471 preference, errorString);
|
Chris@525
|
2472 if (m_audioIO) {
|
Chris@611
|
2473 SVCERR << "MainWindowBase::createAudioIO: Suspending on creation" << endl;
|
Chris@525
|
2474 m_audioIO->suspend(); // start in suspended state
|
Chris@525
|
2475 m_playSource->setSystemPlaybackTarget(m_audioIO);
|
Chris@586
|
2476 } else {
|
Chris@586
|
2477 // Failed to create audio I/O; this may just mean there is
|
Chris@586
|
2478 // no record device, so fall through to see what happens
|
Chris@586
|
2479 // next. We only report complete failure if we end up with
|
Chris@586
|
2480 // neither m_audioIO nor m_playTarget.
|
Chris@525
|
2481 }
|
Chris@586
|
2482 }
|
Chris@586
|
2483
|
Chris@586
|
2484 if (!m_audioIO) {
|
Chris@475
|
2485 m_playTarget = breakfastquay::AudioFactory::
|
Chris@569
|
2486 createCallbackPlayTarget(m_resamplerWrapper,
|
Chris@569
|
2487 preference, errorString);
|
Chris@525
|
2488 if (m_playTarget) {
|
Chris@611
|
2489 SVCERR << "MainWindowBase::createAudioIO: Suspending on creation" << endl;
|
Chris@525
|
2490 m_playTarget->suspend(); // start in suspended state
|
Chris@525
|
2491 m_playSource->setSystemPlaybackTarget(m_playTarget);
|
Chris@525
|
2492 }
|
Chris@475
|
2493 }
|
Chris@475
|
2494
|
Chris@475
|
2495 if (!m_playTarget && !m_audioIO) {
|
Chris@104
|
2496 emit hideSplash();
|
Chris@569
|
2497 QString message;
|
Chris@569
|
2498 QString error = errorString.c_str();
|
Chris@569
|
2499 QString firstBit, secondBit;
|
Chris@547
|
2500 if (implementation == "") {
|
Chris@569
|
2501 if (error == "") {
|
Chris@569
|
2502 firstBit = tr("<b>No audio available</b><p>Could not open an audio device.</p>");
|
Chris@569
|
2503 } else {
|
Chris@569
|
2504 firstBit = tr("<b>No audio available</b><p>Could not open audio device: %1</p>").arg(error);
|
Chris@569
|
2505 }
|
Chris@569
|
2506 if (m_soundOptions & WithAudioInput) {
|
Chris@569
|
2507 secondBit = tr("<p>Automatic audio device detection failed. Audio playback and recording will not be available during this session.</p>");
|
Chris@569
|
2508 } else {
|
Chris@569
|
2509 secondBit = tr("<p>Automatic audio device detection failed. Audio playback will not be available during this session.</p>");
|
Chris@569
|
2510 }
|
Chris@126
|
2511 } else {
|
Chris@569
|
2512 QString driverName = breakfastquay::AudioFactory::
|
Chris@569
|
2513 getImplementationDescription(implementation.toStdString())
|
Chris@569
|
2514 .c_str();
|
Chris@569
|
2515 if (error == "") {
|
Chris@569
|
2516 firstBit = tr("<b>No audio available</b><p>Failed to open your preferred audio driver (\"%1\").</p>").arg(driverName);
|
Chris@569
|
2517 } else {
|
Chris@569
|
2518 firstBit = tr("<b>No audio available</b><p>Failed to open your preferred audio driver (\"%1\"): %2.</p>").arg(driverName).arg(error);
|
Chris@569
|
2519 }
|
Chris@569
|
2520 if (m_soundOptions & WithAudioInput) {
|
Chris@569
|
2521 secondBit = tr("<p>Audio playback and recording will not be available during this session.</p>");
|
Chris@569
|
2522 } else {
|
Chris@569
|
2523 secondBit = tr("<p>Audio playback will not be available during this session.</p>");
|
Chris@569
|
2524 }
|
Chris@126
|
2525 }
|
Chris@570
|
2526 SVDEBUG << "createAudioIO: ERROR: Failed to open audio device \""
|
Chris@570
|
2527 << implementation << "\": error is: " << error << endl;
|
Chris@569
|
2528 QMessageBox::warning(this, tr("Couldn't open audio device"),
|
Chris@569
|
2529 firstBit + secondBit, QMessageBox::Ok);
|
Chris@45
|
2530 }
|
Chris@45
|
2531 }
|
Chris@45
|
2532
|
Chris@556
|
2533 void
|
Chris@556
|
2534 MainWindowBase::deleteAudioIO()
|
Chris@556
|
2535 {
|
Chris@556
|
2536 // First prevent this trying to call target.
|
Chris@559
|
2537 if (m_playSource) {
|
Chris@559
|
2538 m_playSource->setSystemPlaybackTarget(0);
|
Chris@559
|
2539 m_playSource->setResamplerWrapper(0);
|
Chris@559
|
2540 }
|
Chris@556
|
2541
|
Chris@556
|
2542 // Then delete the breakfastquay::System object.
|
Chris@556
|
2543 // Only one of these two exists!
|
Chris@556
|
2544 delete m_audioIO;
|
Chris@556
|
2545 delete m_playTarget;
|
Chris@556
|
2546
|
Chris@559
|
2547 // And the breakfastquay resampler wrapper. We need to
|
Chris@559
|
2548 // delete/recreate this if the channel count changes, which is one
|
Chris@559
|
2549 // of the use cases for recreateAudioIO() calling this
|
Chris@559
|
2550 delete m_resamplerWrapper;
|
Chris@559
|
2551
|
Chris@556
|
2552 m_audioIO = 0;
|
Chris@556
|
2553 m_playTarget = 0;
|
Chris@559
|
2554 m_resamplerWrapper = 0;
|
Chris@556
|
2555 }
|
Chris@556
|
2556
|
Chris@556
|
2557 void
|
Chris@556
|
2558 MainWindowBase::recreateAudioIO()
|
Chris@556
|
2559 {
|
Chris@556
|
2560 deleteAudioIO();
|
Chris@556
|
2561 createAudioIO();
|
Chris@556
|
2562 }
|
Chris@556
|
2563
|
Chris@570
|
2564 void
|
Chris@570
|
2565 MainWindowBase::audioChannelCountIncreased(int)
|
Chris@570
|
2566 {
|
Chris@611
|
2567 SVCERR << "MainWindowBase::audioChannelCountIncreased" << endl;
|
Chris@570
|
2568 recreateAudioIO();
|
Chris@610
|
2569
|
Chris@610
|
2570 if (m_recordTarget &&
|
Chris@610
|
2571 m_recordTarget->isRecording() &&
|
Chris@610
|
2572 m_audioIO) {
|
Chris@610
|
2573 SVCERR << "MainWindowBase::audioChannelCountIncreased: we were recording already, so resuming IO now" << endl;
|
Chris@610
|
2574 m_audioIO->resume();
|
Chris@610
|
2575 }
|
Chris@570
|
2576 }
|
Chris@570
|
2577
|
Chris@45
|
2578 WaveFileModel *
|
Chris@45
|
2579 MainWindowBase::getMainModel()
|
Chris@45
|
2580 {
|
Chris@45
|
2581 if (!m_document) return 0;
|
Chris@45
|
2582 return m_document->getMainModel();
|
Chris@45
|
2583 }
|
Chris@45
|
2584
|
Chris@45
|
2585 const WaveFileModel *
|
Chris@45
|
2586 MainWindowBase::getMainModel() const
|
Chris@45
|
2587 {
|
Chris@45
|
2588 if (!m_document) return 0;
|
Chris@45
|
2589 return m_document->getMainModel();
|
Chris@45
|
2590 }
|
Chris@45
|
2591
|
Chris@45
|
2592 void
|
Chris@45
|
2593 MainWindowBase::createDocument()
|
Chris@45
|
2594 {
|
Chris@45
|
2595 m_document = new Document;
|
Chris@45
|
2596
|
Chris@45
|
2597 connect(m_document, SIGNAL(layerAdded(Layer *)),
|
Chris@595
|
2598 this, SLOT(layerAdded(Layer *)));
|
Chris@45
|
2599 connect(m_document, SIGNAL(layerRemoved(Layer *)),
|
Chris@595
|
2600 this, SLOT(layerRemoved(Layer *)));
|
Chris@45
|
2601 connect(m_document, SIGNAL(layerAboutToBeDeleted(Layer *)),
|
Chris@595
|
2602 this, SLOT(layerAboutToBeDeleted(Layer *)));
|
Chris@45
|
2603 connect(m_document, SIGNAL(layerInAView(Layer *, bool)),
|
Chris@595
|
2604 this, SLOT(layerInAView(Layer *, bool)));
|
Chris@45
|
2605
|
Chris@45
|
2606 connect(m_document, SIGNAL(modelAdded(Model *)),
|
Chris@595
|
2607 this, SLOT(modelAdded(Model *)));
|
Chris@45
|
2608 connect(m_document, SIGNAL(mainModelChanged(WaveFileModel *)),
|
Chris@595
|
2609 this, SLOT(mainModelChanged(WaveFileModel *)));
|
Chris@45
|
2610 connect(m_document, SIGNAL(modelAboutToBeDeleted(Model *)),
|
Chris@595
|
2611 this, SLOT(modelAboutToBeDeleted(Model *)));
|
Chris@45
|
2612
|
Chris@78
|
2613 connect(m_document, SIGNAL(modelGenerationFailed(QString, QString)),
|
Chris@78
|
2614 this, SLOT(modelGenerationFailed(QString, QString)));
|
Chris@78
|
2615 connect(m_document, SIGNAL(modelRegenerationWarning(QString, QString, QString)),
|
Chris@78
|
2616 this, SLOT(modelRegenerationWarning(QString, QString, QString)));
|
Chris@429
|
2617 connect(m_document, SIGNAL(alignmentComplete(AlignmentModel *)),
|
Chris@429
|
2618 this, SLOT(alignmentComplete(AlignmentModel *)));
|
Chris@423
|
2619 connect(m_document, SIGNAL(alignmentFailed(QString)),
|
Chris@423
|
2620 this, SLOT(alignmentFailed(QString)));
|
Chris@160
|
2621
|
Chris@160
|
2622 emit replacedDocument();
|
Chris@45
|
2623 }
|
Chris@45
|
2624
|
Chris@45
|
2625 bool
|
Chris@45
|
2626 MainWindowBase::saveSessionFile(QString path)
|
Chris@45
|
2627 {
|
Chris@217
|
2628 try {
|
Chris@217
|
2629
|
Chris@217
|
2630 TempWriteFile temp(path);
|
Chris@217
|
2631
|
Chris@217
|
2632 BZipFileDevice bzFile(temp.getTemporaryFilename());
|
Chris@217
|
2633 if (!bzFile.open(QIODevice::WriteOnly)) {
|
Chris@293
|
2634 cerr << "Failed to open session file \""
|
Chris@294
|
2635 << temp.getTemporaryFilename()
|
Chris@217
|
2636 << "\" for writing: "
|
Chris@293
|
2637 << bzFile.errorString() << endl;
|
Chris@217
|
2638 return false;
|
Chris@217
|
2639 }
|
Chris@217
|
2640
|
Chris@217
|
2641 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
Chris@217
|
2642
|
Chris@217
|
2643 QTextStream out(&bzFile);
|
Chris@432
|
2644 out.setCodec(QTextCodec::codecForName("UTF-8"));
|
Chris@226
|
2645 toXml(out, false);
|
Chris@217
|
2646 out.flush();
|
Chris@217
|
2647
|
Chris@217
|
2648 QApplication::restoreOverrideCursor();
|
Chris@217
|
2649
|
Chris@217
|
2650 if (!bzFile.isOK()) {
|
Chris@217
|
2651 QMessageBox::critical(this, tr("Failed to write file"),
|
Chris@217
|
2652 tr("<b>Save failed</b><p>Failed to write to file \"%1\": %2")
|
Chris@217
|
2653 .arg(path).arg(bzFile.errorString()));
|
Chris@217
|
2654 bzFile.close();
|
Chris@217
|
2655 return false;
|
Chris@217
|
2656 }
|
Chris@217
|
2657
|
Chris@217
|
2658 bzFile.close();
|
Chris@217
|
2659 temp.moveToTarget();
|
Chris@217
|
2660 return true;
|
Chris@217
|
2661
|
Chris@217
|
2662 } catch (FileOperationFailed &f) {
|
Chris@217
|
2663
|
Chris@217
|
2664 QMessageBox::critical(this, tr("Failed to write file"),
|
Chris@217
|
2665 tr("<b>Save failed</b><p>Failed to write to file \"%1\": %2")
|
Chris@217
|
2666 .arg(path).arg(f.what()));
|
Chris@45
|
2667 return false;
|
Chris@45
|
2668 }
|
Chris@45
|
2669 }
|
Chris@45
|
2670
|
Chris@224
|
2671 bool
|
Chris@224
|
2672 MainWindowBase::saveSessionTemplate(QString path)
|
Chris@224
|
2673 {
|
Chris@224
|
2674 try {
|
Chris@224
|
2675
|
Chris@224
|
2676 TempWriteFile temp(path);
|
Chris@224
|
2677
|
Chris@224
|
2678 QFile file(temp.getTemporaryFilename());
|
Chris@224
|
2679 if (!file.open(QIODevice::WriteOnly)) {
|
Chris@293
|
2680 cerr << "Failed to open session template file \""
|
Chris@294
|
2681 << temp.getTemporaryFilename()
|
Chris@224
|
2682 << "\" for writing: "
|
Chris@294
|
2683 << file.errorString() << endl;
|
Chris@224
|
2684 return false;
|
Chris@224
|
2685 }
|
Chris@224
|
2686
|
Chris@224
|
2687 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
Chris@224
|
2688
|
Chris@224
|
2689 QTextStream out(&file);
|
Chris@432
|
2690 out.setCodec(QTextCodec::codecForName("UTF-8"));
|
Chris@226
|
2691 toXml(out, true);
|
Chris@224
|
2692 out.flush();
|
Chris@224
|
2693
|
Chris@224
|
2694 QApplication::restoreOverrideCursor();
|
Chris@224
|
2695
|
Chris@224
|
2696 file.close();
|
Chris@224
|
2697 temp.moveToTarget();
|
Chris@224
|
2698 return true;
|
Chris@224
|
2699
|
Chris@224
|
2700 } catch (FileOperationFailed &f) {
|
Chris@224
|
2701
|
Chris@224
|
2702 QMessageBox::critical(this, tr("Failed to write file"),
|
Chris@224
|
2703 tr("<b>Save failed</b><p>Failed to write to file \"%1\": %2")
|
Chris@224
|
2704 .arg(path).arg(f.what()));
|
Chris@224
|
2705 return false;
|
Chris@224
|
2706 }
|
Chris@224
|
2707 }
|
Chris@224
|
2708
|
Chris@45
|
2709 void
|
Chris@226
|
2710 MainWindowBase::toXml(QTextStream &out, bool asTemplate)
|
Chris@45
|
2711 {
|
Chris@45
|
2712 QString indent(" ");
|
Chris@45
|
2713
|
Chris@45
|
2714 out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
Chris@45
|
2715 out << "<!DOCTYPE sonic-visualiser>\n";
|
Chris@45
|
2716 out << "<sv>\n";
|
Chris@45
|
2717
|
Chris@226
|
2718 if (asTemplate) {
|
Chris@226
|
2719 m_document->toXmlAsTemplate(out, "", "");
|
Chris@226
|
2720 } else {
|
Chris@226
|
2721 m_document->toXml(out, "", "");
|
Chris@226
|
2722 }
|
Chris@45
|
2723
|
Chris@45
|
2724 out << "<display>\n";
|
Chris@45
|
2725
|
Chris@45
|
2726 out << QString(" <window width=\"%1\" height=\"%2\"/>\n")
|
Chris@595
|
2727 .arg(width()).arg(height());
|
Chris@45
|
2728
|
Chris@45
|
2729 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@45
|
2730
|
Chris@595
|
2731 Pane *pane = m_paneStack->getPane(i);
|
Chris@595
|
2732
|
Chris@595
|
2733 if (pane) {
|
Chris@45
|
2734 pane->toXml(out, indent);
|
Chris@595
|
2735 }
|
Chris@45
|
2736 }
|
Chris@45
|
2737
|
Chris@45
|
2738 out << "</display>\n";
|
Chris@45
|
2739
|
Chris@45
|
2740 m_viewManager->getSelection().toXml(out);
|
Chris@45
|
2741
|
Chris@45
|
2742 out << "</sv>\n";
|
Chris@45
|
2743 }
|
Chris@45
|
2744
|
Chris@45
|
2745 Pane *
|
Chris@45
|
2746 MainWindowBase::addPaneToStack()
|
Chris@45
|
2747 {
|
Chris@342
|
2748 cerr << "MainWindowBase::addPaneToStack()" << endl;
|
Chris@45
|
2749 AddPaneCommand *command = new AddPaneCommand(this);
|
Chris@45
|
2750 CommandHistory::getInstance()->addCommand(command);
|
Chris@57
|
2751 Pane *pane = command->getPane();
|
Chris@57
|
2752 return pane;
|
Chris@45
|
2753 }
|
Chris@45
|
2754
|
Chris@45
|
2755 void
|
Chris@45
|
2756 MainWindowBase::zoomIn()
|
Chris@45
|
2757 {
|
Chris@45
|
2758 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@45
|
2759 if (currentPane) currentPane->zoom(true);
|
Chris@45
|
2760 }
|
Chris@45
|
2761
|
Chris@45
|
2762 void
|
Chris@45
|
2763 MainWindowBase::zoomOut()
|
Chris@45
|
2764 {
|
Chris@45
|
2765 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@45
|
2766 if (currentPane) currentPane->zoom(false);
|
Chris@45
|
2767 }
|
Chris@45
|
2768
|
Chris@45
|
2769 void
|
Chris@45
|
2770 MainWindowBase::zoomToFit()
|
Chris@45
|
2771 {
|
Chris@45
|
2772 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@45
|
2773 if (!currentPane) return;
|
Chris@45
|
2774
|
Chris@45
|
2775 Model *model = getMainModel();
|
Chris@45
|
2776 if (!model) return;
|
Chris@45
|
2777
|
Chris@434
|
2778 sv_frame_t start = model->getStartFrame();
|
Chris@434
|
2779 sv_frame_t end = model->getEndFrame();
|
Chris@60
|
2780 if (m_playSource) end = std::max(end, m_playSource->getPlayEndFrame());
|
Chris@366
|
2781 int pixels = currentPane->width();
|
Chris@366
|
2782
|
Chris@366
|
2783 int sw = currentPane->getVerticalScaleWidth();
|
Chris@45
|
2784 if (pixels > sw * 2) pixels -= sw * 2;
|
Chris@45
|
2785 else pixels = 1;
|
Chris@45
|
2786 if (pixels > 4) pixels -= 4;
|
Chris@45
|
2787
|
Chris@436
|
2788 int zoomLevel = int((end - start) / pixels);
|
Chris@150
|
2789 if (zoomLevel < 1) zoomLevel = 1;
|
Chris@45
|
2790
|
Chris@45
|
2791 currentPane->setZoomLevel(zoomLevel);
|
Chris@45
|
2792 currentPane->setCentreFrame((start + end) / 2);
|
Chris@45
|
2793 }
|
Chris@45
|
2794
|
Chris@45
|
2795 void
|
Chris@45
|
2796 MainWindowBase::zoomDefault()
|
Chris@45
|
2797 {
|
Chris@45
|
2798 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@302
|
2799 QSettings settings;
|
Chris@302
|
2800 settings.beginGroup("MainWindow");
|
Chris@302
|
2801 int zoom = settings.value("zoom-default", 1024).toInt();
|
Chris@302
|
2802 settings.endGroup();
|
Chris@302
|
2803 if (currentPane) currentPane->setZoomLevel(zoom);
|
Chris@45
|
2804 }
|
Chris@45
|
2805
|
Chris@45
|
2806 void
|
Chris@45
|
2807 MainWindowBase::scrollLeft()
|
Chris@45
|
2808 {
|
Chris@45
|
2809 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@45
|
2810 if (currentPane) currentPane->scroll(false, false);
|
Chris@45
|
2811 }
|
Chris@45
|
2812
|
Chris@45
|
2813 void
|
Chris@45
|
2814 MainWindowBase::jumpLeft()
|
Chris@45
|
2815 {
|
Chris@45
|
2816 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@45
|
2817 if (currentPane) currentPane->scroll(false, true);
|
Chris@45
|
2818 }
|
Chris@45
|
2819
|
Chris@45
|
2820 void
|
Chris@162
|
2821 MainWindowBase::peekLeft()
|
Chris@162
|
2822 {
|
Chris@162
|
2823 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@162
|
2824 if (currentPane) currentPane->scroll(false, false, false);
|
Chris@162
|
2825 }
|
Chris@162
|
2826
|
Chris@162
|
2827 void
|
Chris@45
|
2828 MainWindowBase::scrollRight()
|
Chris@45
|
2829 {
|
Chris@45
|
2830 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@45
|
2831 if (currentPane) currentPane->scroll(true, false);
|
Chris@45
|
2832 }
|
Chris@45
|
2833
|
Chris@45
|
2834 void
|
Chris@45
|
2835 MainWindowBase::jumpRight()
|
Chris@45
|
2836 {
|
Chris@45
|
2837 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@45
|
2838 if (currentPane) currentPane->scroll(true, true);
|
Chris@45
|
2839 }
|
Chris@45
|
2840
|
Chris@45
|
2841 void
|
Chris@162
|
2842 MainWindowBase::peekRight()
|
Chris@162
|
2843 {
|
Chris@162
|
2844 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@162
|
2845 if (currentPane) currentPane->scroll(true, false, false);
|
Chris@162
|
2846 }
|
Chris@162
|
2847
|
Chris@162
|
2848 void
|
Chris@45
|
2849 MainWindowBase::showNoOverlays()
|
Chris@45
|
2850 {
|
Chris@45
|
2851 m_viewManager->setOverlayMode(ViewManager::NoOverlays);
|
Chris@45
|
2852 }
|
Chris@45
|
2853
|
Chris@45
|
2854 void
|
Chris@45
|
2855 MainWindowBase::showMinimalOverlays()
|
Chris@45
|
2856 {
|
Chris@335
|
2857 m_viewManager->setOverlayMode(ViewManager::StandardOverlays);
|
Chris@45
|
2858 }
|
Chris@45
|
2859
|
Chris@45
|
2860 void
|
Chris@45
|
2861 MainWindowBase::showAllOverlays()
|
Chris@45
|
2862 {
|
Chris@45
|
2863 m_viewManager->setOverlayMode(ViewManager::AllOverlays);
|
Chris@45
|
2864 }
|
Chris@45
|
2865
|
Chris@45
|
2866 void
|
Chris@577
|
2867 MainWindowBase::findTimeRulerLayer()
|
Chris@577
|
2868 {
|
Chris@577
|
2869 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@577
|
2870 Pane *pane = m_paneStack->getPane(i);
|
Chris@577
|
2871 if (!pane) continue;
|
Chris@577
|
2872 for (int j = 0; j < pane->getLayerCount(); ++j) {
|
Chris@577
|
2873 Layer *layer = pane->getLayer(j);
|
Chris@577
|
2874 if (!dynamic_cast<TimeRulerLayer *>(layer)) continue;
|
Chris@577
|
2875 m_timeRulerLayer = layer;
|
Chris@577
|
2876 return;
|
Chris@577
|
2877 }
|
Chris@577
|
2878 }
|
Chris@577
|
2879 if (m_timeRulerLayer) {
|
Chris@577
|
2880 SVCERR << "WARNING: Time ruler layer was not reset to 0 before session template loaded?" << endl;
|
Chris@577
|
2881 delete m_timeRulerLayer;
|
Chris@577
|
2882 m_timeRulerLayer = 0;
|
Chris@577
|
2883 }
|
Chris@577
|
2884 }
|
Chris@577
|
2885
|
Chris@577
|
2886 void
|
Chris@211
|
2887 MainWindowBase::toggleTimeRulers()
|
Chris@211
|
2888 {
|
Chris@211
|
2889 bool haveRulers = false;
|
Chris@211
|
2890 bool someHidden = false;
|
Chris@211
|
2891
|
Chris@211
|
2892 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@211
|
2893
|
Chris@211
|
2894 Pane *pane = m_paneStack->getPane(i);
|
Chris@211
|
2895 if (!pane) continue;
|
Chris@211
|
2896
|
Chris@211
|
2897 for (int j = 0; j < pane->getLayerCount(); ++j) {
|
Chris@211
|
2898
|
Chris@211
|
2899 Layer *layer = pane->getLayer(j);
|
Chris@211
|
2900 if (!dynamic_cast<TimeRulerLayer *>(layer)) continue;
|
Chris@211
|
2901
|
Chris@211
|
2902 haveRulers = true;
|
Chris@211
|
2903 if (layer->isLayerDormant(pane)) someHidden = true;
|
Chris@211
|
2904 }
|
Chris@211
|
2905 }
|
Chris@211
|
2906
|
Chris@211
|
2907 if (haveRulers) {
|
Chris@211
|
2908
|
Chris@211
|
2909 bool show = someHidden;
|
Chris@211
|
2910
|
Chris@211
|
2911 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@211
|
2912
|
Chris@211
|
2913 Pane *pane = m_paneStack->getPane(i);
|
Chris@211
|
2914 if (!pane) continue;
|
Chris@211
|
2915
|
Chris@211
|
2916 for (int j = 0; j < pane->getLayerCount(); ++j) {
|
Chris@211
|
2917
|
Chris@211
|
2918 Layer *layer = pane->getLayer(j);
|
Chris@211
|
2919 if (!dynamic_cast<TimeRulerLayer *>(layer)) continue;
|
Chris@211
|
2920
|
Chris@211
|
2921 layer->showLayer(pane, show);
|
Chris@211
|
2922 }
|
Chris@211
|
2923 }
|
Chris@211
|
2924 }
|
Chris@211
|
2925 }
|
Chris@211
|
2926
|
Chris@211
|
2927 void
|
Chris@45
|
2928 MainWindowBase::toggleZoomWheels()
|
Chris@45
|
2929 {
|
Chris@45
|
2930 if (m_viewManager->getZoomWheelsEnabled()) {
|
Chris@45
|
2931 m_viewManager->setZoomWheelsEnabled(false);
|
Chris@45
|
2932 } else {
|
Chris@45
|
2933 m_viewManager->setZoomWheelsEnabled(true);
|
Chris@45
|
2934 }
|
Chris@45
|
2935 }
|
Chris@45
|
2936
|
Chris@45
|
2937 void
|
Chris@45
|
2938 MainWindowBase::togglePropertyBoxes()
|
Chris@45
|
2939 {
|
Chris@45
|
2940 if (m_paneStack->getLayoutStyle() == PaneStack::NoPropertyStacks) {
|
Chris@45
|
2941 if (Preferences::getInstance()->getPropertyBoxLayout() ==
|
Chris@45
|
2942 Preferences::VerticallyStacked) {
|
Chris@45
|
2943 m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout);
|
Chris@45
|
2944 } else {
|
Chris@45
|
2945 m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout);
|
Chris@45
|
2946 }
|
Chris@45
|
2947 } else {
|
Chris@45
|
2948 m_paneStack->setLayoutStyle(PaneStack::NoPropertyStacks);
|
Chris@45
|
2949 }
|
Chris@45
|
2950 }
|
Chris@45
|
2951
|
Chris@378
|
2952 QLabel *
|
Chris@378
|
2953 MainWindowBase::getStatusLabel() const
|
Chris@378
|
2954 {
|
Chris@378
|
2955 if (!m_statusLabel) {
|
Chris@378
|
2956 m_statusLabel = new QLabel();
|
Chris@378
|
2957 statusBar()->addWidget(m_statusLabel, 1);
|
Chris@378
|
2958 }
|
Chris@379
|
2959
|
Chris@379
|
2960 QList<QFrame *> frames = statusBar()->findChildren<QFrame *>();
|
Chris@379
|
2961 foreach (QFrame *f, frames) {
|
Chris@379
|
2962 f->setFrameStyle(QFrame::NoFrame);
|
Chris@379
|
2963 }
|
Chris@379
|
2964
|
Chris@378
|
2965 return m_statusLabel;
|
Chris@378
|
2966 }
|
Chris@378
|
2967
|
Chris@45
|
2968 void
|
Chris@45
|
2969 MainWindowBase::toggleStatusBar()
|
Chris@45
|
2970 {
|
Chris@45
|
2971 QSettings settings;
|
Chris@45
|
2972 settings.beginGroup("MainWindow");
|
Chris@45
|
2973 bool sb = settings.value("showstatusbar", true).toBool();
|
Chris@45
|
2974
|
Chris@45
|
2975 if (sb) {
|
Chris@45
|
2976 statusBar()->hide();
|
Chris@45
|
2977 } else {
|
Chris@45
|
2978 statusBar()->show();
|
Chris@45
|
2979 }
|
Chris@45
|
2980
|
Chris@45
|
2981 settings.setValue("showstatusbar", !sb);
|
Chris@45
|
2982
|
Chris@45
|
2983 settings.endGroup();
|
Chris@45
|
2984 }
|
Chris@45
|
2985
|
Chris@45
|
2986 void
|
Chris@256
|
2987 MainWindowBase::toggleCentreLine()
|
Chris@256
|
2988 {
|
Chris@256
|
2989 if (m_viewManager->shouldShowCentreLine()) {
|
Chris@256
|
2990 m_viewManager->setShowCentreLine(false);
|
Chris@256
|
2991 } else {
|
Chris@256
|
2992 m_viewManager->setShowCentreLine(true);
|
Chris@256
|
2993 }
|
Chris@256
|
2994 }
|
Chris@256
|
2995
|
Chris@256
|
2996 void
|
Chris@45
|
2997 MainWindowBase::preferenceChanged(PropertyContainer::PropertyName name)
|
Chris@45
|
2998 {
|
Chris@45
|
2999 if (name == "Property Box Layout") {
|
Chris@45
|
3000 if (m_paneStack->getLayoutStyle() != PaneStack::NoPropertyStacks) {
|
Chris@45
|
3001 if (Preferences::getInstance()->getPropertyBoxLayout() ==
|
Chris@45
|
3002 Preferences::VerticallyStacked) {
|
Chris@45
|
3003 m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout);
|
Chris@45
|
3004 } else {
|
Chris@45
|
3005 m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout);
|
Chris@45
|
3006 }
|
Chris@45
|
3007 }
|
Chris@45
|
3008 } else if (name == "Background Mode" && m_viewManager) {
|
Chris@45
|
3009 Preferences::BackgroundMode mode =
|
Chris@45
|
3010 Preferences::getInstance()->getBackgroundMode();
|
Chris@45
|
3011 if (mode == Preferences::BackgroundFromTheme) {
|
Chris@45
|
3012 m_viewManager->setGlobalDarkBackground(m_initialDarkBackground);
|
Chris@45
|
3013 } else if (mode == Preferences::DarkBackground) {
|
Chris@45
|
3014 m_viewManager->setGlobalDarkBackground(true);
|
Chris@45
|
3015 } else {
|
Chris@45
|
3016 m_viewManager->setGlobalDarkBackground(false);
|
Chris@45
|
3017 }
|
Chris@45
|
3018 }
|
Chris@45
|
3019 }
|
Chris@45
|
3020
|
Chris@45
|
3021 void
|
Chris@45
|
3022 MainWindowBase::play()
|
Chris@45
|
3023 {
|
Chris@516
|
3024 if ((m_recordTarget && m_recordTarget->isRecording()) ||
|
Chris@516
|
3025 (m_playSource && m_playSource->isPlaying())) {
|
Chris@45
|
3026 stop();
|
Chris@479
|
3027 QAction *action = qobject_cast<QAction *>(sender());
|
Chris@479
|
3028 if (action) action->setChecked(false);
|
Chris@45
|
3029 } else {
|
Chris@487
|
3030 if (m_audioIO) m_audioIO->resume();
|
Chris@509
|
3031 else if (m_playTarget) m_playTarget->resume();
|
Chris@45
|
3032 playbackFrameChanged(m_viewManager->getPlaybackFrame());
|
Chris@595
|
3033 m_playSource->play(m_viewManager->getPlaybackFrame());
|
Chris@45
|
3034 }
|
Chris@45
|
3035 }
|
Chris@45
|
3036
|
Chris@45
|
3037 void
|
Chris@477
|
3038 MainWindowBase::record()
|
Chris@477
|
3039 {
|
Chris@586
|
3040 QAction *action = qobject_cast<QAction *>(sender());
|
Chris@586
|
3041
|
Chris@478
|
3042 if (!(m_soundOptions & WithAudioInput)) {
|
Chris@586
|
3043 if (action) action->setChecked(false);
|
Chris@478
|
3044 return;
|
Chris@478
|
3045 }
|
Chris@478
|
3046
|
Chris@477
|
3047 if (!m_recordTarget) {
|
Chris@586
|
3048 if (action) action->setChecked(false);
|
Chris@477
|
3049 return;
|
Chris@477
|
3050 }
|
Chris@477
|
3051
|
Chris@478
|
3052 if (!m_audioIO) {
|
Chris@611
|
3053 SVDEBUG << "MainWindowBase::record: about to create audio IO" << endl;
|
Chris@478
|
3054 createAudioIO();
|
Chris@478
|
3055 }
|
Chris@492
|
3056
|
Chris@492
|
3057 if (!m_audioIO) {
|
Chris@586
|
3058 if (!m_playTarget) {
|
Chris@586
|
3059 // Don't need to report this, createAudioIO should have
|
Chris@586
|
3060 if (action) action->setChecked(false);
|
Chris@586
|
3061 return;
|
Chris@586
|
3062 } else {
|
Chris@586
|
3063 // Need to report this: if the play target exists instead
|
Chris@586
|
3064 // of the audio IO, then that means we failed to open a
|
Chris@586
|
3065 // capture device. The record control should be disabled
|
Chris@586
|
3066 // in that situation, so if it happens here, that must
|
Chris@586
|
3067 // mean this is the first time we ever tried to open the
|
Chris@586
|
3068 // audio device, hence the need to report the problem here
|
Chris@586
|
3069 QMessageBox::critical
|
Chris@586
|
3070 (this, tr("No record device available"),
|
Chris@586
|
3071 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
|
3072 if (action) action->setChecked(false);
|
Chris@586
|
3073 updateMenuStates();
|
Chris@586
|
3074 return;
|
Chris@586
|
3075 }
|
Chris@492
|
3076 }
|
Chris@478
|
3077
|
Chris@477
|
3078 if (m_recordTarget->isRecording()) {
|
Chris@492
|
3079 stop();
|
Chris@477
|
3080 return;
|
Chris@477
|
3081 }
|
Chris@490
|
3082
|
Chris@483
|
3083 if (m_audioRecordMode == RecordReplaceSession) {
|
Chris@490
|
3084 if (!checkSaveModified()) {
|
Chris@490
|
3085 if (action) action->setChecked(false);
|
Chris@490
|
3086 return;
|
Chris@490
|
3087 }
|
Chris@483
|
3088 }
|
Chris@487
|
3089
|
Chris@557
|
3090 if (m_viewManager) m_viewManager->setGlobalCentreFrame(0);
|
Chris@557
|
3091
|
Chris@611
|
3092 SVCERR << "MainWindowBase::record: about to resume" << endl;
|
Chris@492
|
3093 m_audioIO->resume();
|
Chris@509
|
3094
|
Chris@477
|
3095 WritableWaveFileModel *model = m_recordTarget->startRecording();
|
Chris@477
|
3096 if (!model) {
|
Chris@586
|
3097 SVCERR << "ERROR: MainWindowBase::record: Recording failed" << endl;
|
Chris@586
|
3098 QMessageBox::critical
|
Chris@586
|
3099 (this, tr("Recording failed"),
|
Chris@586
|
3100 tr("<b>Recording failed</b><p>Failed to switch to record mode (some internal problem?)</p>"));
|
Chris@490
|
3101 if (action) action->setChecked(false);
|
Chris@477
|
3102 return;
|
Chris@477
|
3103 }
|
Chris@477
|
3104
|
Chris@477
|
3105 if (!model->isOK()) {
|
Chris@611
|
3106 SVCERR << "MainWindowBase::record: Model not OK, stopping and suspending" << endl;
|
Chris@477
|
3107 m_recordTarget->stopRecording();
|
Chris@492
|
3108 m_audioIO->suspend();
|
Chris@586
|
3109 if (action) action->setChecked(false);
|
Chris@477
|
3110 delete model;
|
Chris@477
|
3111 return;
|
Chris@477
|
3112 }
|
Chris@611
|
3113
|
Chris@611
|
3114 SVCERR << "MainWindowBase::record: Model is OK, continuing..." << endl;
|
Chris@487
|
3115
|
Chris@478
|
3116 PlayParameterRepository::getInstance()->addPlayable(model);
|
Chris@483
|
3117
|
Chris@483
|
3118 if (m_audioRecordMode == RecordReplaceSession || !getMainModel()) {
|
Chris@478
|
3119
|
Chris@479
|
3120 //!!! duplication with openAudio here
|
Chris@479
|
3121
|
Chris@479
|
3122 QString templateName = getDefaultSessionTemplate();
|
Chris@479
|
3123 bool loadedTemplate = false;
|
Chris@479
|
3124
|
Chris@479
|
3125 if (templateName != "") {
|
Chris@479
|
3126 FileOpenStatus tplStatus = openSessionTemplate(templateName);
|
Chris@479
|
3127 if (tplStatus == FileOpenCancelled) {
|
Chris@611
|
3128 SVCERR << "MainWindowBase::record: Session template open cancelled, stopping and suspending" << endl;
|
Chris@490
|
3129 m_recordTarget->stopRecording();
|
Chris@492
|
3130 m_audioIO->suspend();
|
Chris@490
|
3131 PlayParameterRepository::getInstance()->removePlayable(model);
|
Chris@479
|
3132 return;
|
Chris@479
|
3133 }
|
Chris@479
|
3134 if (tplStatus != FileOpenFailed) {
|
Chris@479
|
3135 loadedTemplate = true;
|
Chris@479
|
3136 }
|
Chris@479
|
3137 }
|
Chris@479
|
3138
|
Chris@479
|
3139 if (!loadedTemplate) {
|
Chris@479
|
3140 closeSession();
|
Chris@479
|
3141 createDocument();
|
Chris@479
|
3142 }
|
Chris@479
|
3143
|
Chris@479
|
3144 Model *prevMain = getMainModel();
|
Chris@479
|
3145 if (prevMain) {
|
Chris@479
|
3146 m_playSource->removeModel(prevMain);
|
Chris@479
|
3147 PlayParameterRepository::getInstance()->removePlayable(prevMain);
|
Chris@479
|
3148 }
|
Chris@479
|
3149
|
Chris@478
|
3150 m_document->setMainModel(model);
|
Chris@478
|
3151 setupMenus();
|
Chris@577
|
3152 findTimeRulerLayer();
|
Chris@478
|
3153
|
Chris@595
|
3154 if (loadedTemplate || (m_sessionFile == "")) {
|
Chris@479
|
3155 //!!! shouldn't be dealing directly with title from here -- call a method
|
Chris@595
|
3156 setWindowTitle(tr("%1: %2")
|
Chris@479
|
3157 .arg(QApplication::applicationName())
|
Chris@479
|
3158 .arg(model->getLocation()));
|
Chris@595
|
3159 CommandHistory::getInstance()->clear();
|
Chris@595
|
3160 CommandHistory::getInstance()->documentSaved();
|
Chris@595
|
3161 m_documentModified = false;
|
Chris@595
|
3162 } else {
|
Chris@595
|
3163 setWindowTitle(tr("%1: %2 [%3]")
|
Chris@479
|
3164 .arg(QApplication::applicationName())
|
Chris@595
|
3165 .arg(QFileInfo(m_sessionFile).fileName())
|
Chris@595
|
3166 .arg(model->getLocation()));
|
Chris@595
|
3167 if (m_documentModified) {
|
Chris@595
|
3168 m_documentModified = false;
|
Chris@595
|
3169 documentModified(); // so as to restore "(modified)" window title
|
Chris@595
|
3170 }
|
Chris@595
|
3171 }
|
Chris@479
|
3172
|
Chris@478
|
3173 } else {
|
Chris@478
|
3174
|
Chris@478
|
3175 CommandHistory::getInstance()->startCompoundOperation
|
Chris@478
|
3176 (tr("Import Recorded Audio"), true);
|
Chris@478
|
3177
|
Chris@478
|
3178 m_document->addImportedModel(model);
|
Chris@478
|
3179
|
Chris@478
|
3180 AddPaneCommand *command = new AddPaneCommand(this);
|
Chris@478
|
3181 CommandHistory::getInstance()->addCommand(command);
|
Chris@478
|
3182
|
Chris@478
|
3183 Pane *pane = command->getPane();
|
Chris@478
|
3184
|
Chris@478
|
3185 if (m_timeRulerLayer) {
|
Chris@478
|
3186 m_document->addLayerToView(pane, m_timeRulerLayer);
|
Chris@478
|
3187 }
|
Chris@478
|
3188
|
Chris@478
|
3189 Layer *newLayer = m_document->createImportedLayer(model);
|
Chris@478
|
3190
|
Chris@478
|
3191 if (newLayer) {
|
Chris@478
|
3192 m_document->addLayerToView(pane, newLayer);
|
Chris@478
|
3193 }
|
Chris@595
|
3194
|
Chris@478
|
3195 CommandHistory::getInstance()->endCompoundOperation();
|
Chris@477
|
3196 }
|
Chris@479
|
3197
|
Chris@479
|
3198 updateMenuStates();
|
Chris@479
|
3199 m_recentFiles.addFile(model->getLocation());
|
Chris@479
|
3200 currentPaneChanged(m_paneStack->getCurrentPane());
|
Chris@611
|
3201
|
Chris@496
|
3202 emit audioFileLoaded();
|
Chris@477
|
3203 }
|
Chris@477
|
3204
|
Chris@477
|
3205 void
|
Chris@45
|
3206 MainWindowBase::ffwd()
|
Chris@45
|
3207 {
|
Chris@45
|
3208 if (!getMainModel()) return;
|
Chris@45
|
3209
|
Chris@435
|
3210 sv_frame_t frame = m_viewManager->getPlaybackFrame();
|
Chris@45
|
3211 ++frame;
|
Chris@45
|
3212
|
Chris@85
|
3213 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@45
|
3214 Layer *layer = getSnapLayer();
|
Chris@435
|
3215 sv_samplerate_t sr = getMainModel()->getSampleRate();
|
Chris@45
|
3216
|
Chris@45
|
3217 if (!layer) {
|
Chris@45
|
3218
|
Chris@45
|
3219 frame = RealTime::realTime2Frame
|
Chris@357
|
3220 (RealTime::frame2RealTime(frame, sr) + m_defaultFfwdRwdStep, sr);
|
Chris@435
|
3221 if (frame > getMainModel()->getEndFrame()) {
|
Chris@45
|
3222 frame = getMainModel()->getEndFrame();
|
Chris@45
|
3223 }
|
Chris@45
|
3224
|
Chris@45
|
3225 } else {
|
Chris@45
|
3226
|
Chris@366
|
3227 int resolution = 0;
|
Chris@166
|
3228 if (pane) frame = pane->alignFromReference(frame);
|
Chris@85
|
3229 if (layer->snapToFeatureFrame(m_paneStack->getCurrentPane(),
|
Chris@85
|
3230 frame, resolution, Layer::SnapRight)) {
|
Chris@85
|
3231 if (pane) frame = pane->alignToReference(frame);
|
Chris@85
|
3232 } else {
|
Chris@45
|
3233 frame = getMainModel()->getEndFrame();
|
Chris@45
|
3234 }
|
Chris@45
|
3235 }
|
Chris@45
|
3236
|
Chris@45
|
3237 if (frame < 0) frame = 0;
|
Chris@45
|
3238
|
Chris@45
|
3239 if (m_viewManager->getPlaySelectionMode()) {
|
Chris@435
|
3240 frame = m_viewManager->constrainFrameToSelection(frame);
|
Chris@45
|
3241 }
|
Chris@45
|
3242
|
Chris@45
|
3243 m_viewManager->setPlaybackFrame(frame);
|
Chris@166
|
3244
|
Chris@435
|
3245 if (frame == getMainModel()->getEndFrame() &&
|
Chris@166
|
3246 m_playSource &&
|
Chris@166
|
3247 m_playSource->isPlaying() &&
|
Chris@166
|
3248 !m_viewManager->getPlayLoopMode()) {
|
Chris@166
|
3249 stop();
|
Chris@166
|
3250 }
|
Chris@45
|
3251 }
|
Chris@45
|
3252
|
Chris@45
|
3253 void
|
Chris@45
|
3254 MainWindowBase::ffwdEnd()
|
Chris@45
|
3255 {
|
Chris@45
|
3256 if (!getMainModel()) return;
|
Chris@45
|
3257
|
Chris@139
|
3258 if (m_playSource &&
|
Chris@139
|
3259 m_playSource->isPlaying() &&
|
Chris@139
|
3260 !m_viewManager->getPlayLoopMode()) {
|
Chris@139
|
3261 stop();
|
Chris@139
|
3262 }
|
Chris@139
|
3263
|
Chris@435
|
3264 sv_frame_t frame = getMainModel()->getEndFrame();
|
Chris@45
|
3265
|
Chris@45
|
3266 if (m_viewManager->getPlaySelectionMode()) {
|
Chris@45
|
3267 frame = m_viewManager->constrainFrameToSelection(frame);
|
Chris@45
|
3268 }
|
Chris@45
|
3269
|
Chris@45
|
3270 m_viewManager->setPlaybackFrame(frame);
|
Chris@45
|
3271 }
|
Chris@45
|
3272
|
Chris@45
|
3273 void
|
Chris@166
|
3274 MainWindowBase::ffwdSimilar()
|
Chris@166
|
3275 {
|
Chris@166
|
3276 if (!getMainModel()) return;
|
Chris@166
|
3277
|
Chris@166
|
3278 Layer *layer = getSnapLayer();
|
Chris@166
|
3279 if (!layer) { ffwd(); return; }
|
Chris@166
|
3280
|
Chris@166
|
3281 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@435
|
3282 sv_frame_t frame = m_viewManager->getPlaybackFrame();
|
Chris@166
|
3283
|
Chris@366
|
3284 int resolution = 0;
|
Chris@166
|
3285 if (pane) frame = pane->alignFromReference(frame);
|
Chris@166
|
3286 if (layer->snapToSimilarFeature(m_paneStack->getCurrentPane(),
|
Chris@166
|
3287 frame, resolution, Layer::SnapRight)) {
|
Chris@166
|
3288 if (pane) frame = pane->alignToReference(frame);
|
Chris@166
|
3289 } else {
|
Chris@166
|
3290 frame = getMainModel()->getEndFrame();
|
Chris@166
|
3291 }
|
Chris@166
|
3292
|
Chris@166
|
3293 if (frame < 0) frame = 0;
|
Chris@166
|
3294
|
Chris@166
|
3295 if (m_viewManager->getPlaySelectionMode()) {
|
Chris@435
|
3296 frame = m_viewManager->constrainFrameToSelection(frame);
|
Chris@166
|
3297 }
|
Chris@166
|
3298
|
Chris@166
|
3299 m_viewManager->setPlaybackFrame(frame);
|
Chris@166
|
3300
|
Chris@435
|
3301 if (frame == getMainModel()->getEndFrame() &&
|
Chris@166
|
3302 m_playSource &&
|
Chris@166
|
3303 m_playSource->isPlaying() &&
|
Chris@166
|
3304 !m_viewManager->getPlayLoopMode()) {
|
Chris@166
|
3305 stop();
|
Chris@166
|
3306 }
|
Chris@166
|
3307 }
|
Chris@166
|
3308
|
Chris@166
|
3309 void
|
Chris@45
|
3310 MainWindowBase::rewind()
|
Chris@45
|
3311 {
|
Chris@45
|
3312 if (!getMainModel()) return;
|
Chris@45
|
3313
|
Chris@435
|
3314 sv_frame_t frame = m_viewManager->getPlaybackFrame();
|
Chris@45
|
3315 if (frame > 0) --frame;
|
Chris@45
|
3316
|
Chris@85
|
3317 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@45
|
3318 Layer *layer = getSnapLayer();
|
Chris@435
|
3319 sv_samplerate_t sr = getMainModel()->getSampleRate();
|
Chris@45
|
3320
|
Chris@45
|
3321 // when rewinding during playback, we want to allow a period
|
Chris@45
|
3322 // following a rewind target point at which the rewind will go to
|
Chris@45
|
3323 // the prior point instead of the immediately neighbouring one
|
Chris@45
|
3324 if (m_playSource && m_playSource->isPlaying()) {
|
Chris@45
|
3325 RealTime ct = RealTime::frame2RealTime(frame, sr);
|
Chris@357
|
3326 ct = ct - RealTime::fromSeconds(0.15);
|
Chris@45
|
3327 if (ct < RealTime::zeroTime) ct = RealTime::zeroTime;
|
Chris@45
|
3328 frame = RealTime::realTime2Frame(ct, sr);
|
Chris@45
|
3329 }
|
Chris@45
|
3330
|
Chris@45
|
3331 if (!layer) {
|
Chris@45
|
3332
|
Chris@45
|
3333 frame = RealTime::realTime2Frame
|
Chris@357
|
3334 (RealTime::frame2RealTime(frame, sr) - m_defaultFfwdRwdStep, sr);
|
Chris@435
|
3335 if (frame < getMainModel()->getStartFrame()) {
|
Chris@45
|
3336 frame = getMainModel()->getStartFrame();
|
Chris@45
|
3337 }
|
Chris@45
|
3338
|
Chris@45
|
3339 } else {
|
Chris@45
|
3340
|
Chris@366
|
3341 int resolution = 0;
|
Chris@166
|
3342 if (pane) frame = pane->alignFromReference(frame);
|
Chris@85
|
3343 if (layer->snapToFeatureFrame(m_paneStack->getCurrentPane(),
|
Chris@85
|
3344 frame, resolution, Layer::SnapLeft)) {
|
Chris@85
|
3345 if (pane) frame = pane->alignToReference(frame);
|
Chris@85
|
3346 } else {
|
Chris@45
|
3347 frame = getMainModel()->getStartFrame();
|
Chris@45
|
3348 }
|
Chris@45
|
3349 }
|
Chris@45
|
3350
|
Chris@45
|
3351 if (frame < 0) frame = 0;
|
Chris@45
|
3352
|
Chris@45
|
3353 if (m_viewManager->getPlaySelectionMode()) {
|
Chris@435
|
3354 frame = m_viewManager->constrainFrameToSelection(frame);
|
Chris@45
|
3355 }
|
Chris@45
|
3356
|
Chris@45
|
3357 m_viewManager->setPlaybackFrame(frame);
|
Chris@45
|
3358 }
|
Chris@45
|
3359
|
Chris@45
|
3360 void
|
Chris@45
|
3361 MainWindowBase::rewindStart()
|
Chris@45
|
3362 {
|
Chris@45
|
3363 if (!getMainModel()) return;
|
Chris@45
|
3364
|
Chris@435
|
3365 sv_frame_t frame = getMainModel()->getStartFrame();
|
Chris@45
|
3366
|
Chris@45
|
3367 if (m_viewManager->getPlaySelectionMode()) {
|
Chris@45
|
3368 frame = m_viewManager->constrainFrameToSelection(frame);
|
Chris@45
|
3369 }
|
Chris@45
|
3370
|
Chris@45
|
3371 m_viewManager->setPlaybackFrame(frame);
|
Chris@45
|
3372 }
|
Chris@45
|
3373
|
Chris@166
|
3374 void
|
Chris@166
|
3375 MainWindowBase::rewindSimilar()
|
Chris@166
|
3376 {
|
Chris@166
|
3377 if (!getMainModel()) return;
|
Chris@166
|
3378
|
Chris@166
|
3379 Layer *layer = getSnapLayer();
|
Chris@166
|
3380 if (!layer) { rewind(); return; }
|
Chris@166
|
3381
|
Chris@166
|
3382 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@435
|
3383 sv_frame_t frame = m_viewManager->getPlaybackFrame();
|
Chris@166
|
3384
|
Chris@366
|
3385 int resolution = 0;
|
Chris@166
|
3386 if (pane) frame = pane->alignFromReference(frame);
|
Chris@166
|
3387 if (layer->snapToSimilarFeature(m_paneStack->getCurrentPane(),
|
Chris@166
|
3388 frame, resolution, Layer::SnapLeft)) {
|
Chris@166
|
3389 if (pane) frame = pane->alignToReference(frame);
|
Chris@166
|
3390 } else {
|
Chris@166
|
3391 frame = getMainModel()->getStartFrame();
|
Chris@166
|
3392 }
|
Chris@166
|
3393
|
Chris@166
|
3394 if (frame < 0) frame = 0;
|
Chris@166
|
3395
|
Chris@166
|
3396 if (m_viewManager->getPlaySelectionMode()) {
|
Chris@435
|
3397 frame = m_viewManager->constrainFrameToSelection(frame);
|
Chris@166
|
3398 }
|
Chris@166
|
3399
|
Chris@166
|
3400 m_viewManager->setPlaybackFrame(frame);
|
Chris@166
|
3401 }
|
Chris@166
|
3402
|
Chris@45
|
3403 Layer *
|
Chris@45
|
3404 MainWindowBase::getSnapLayer() const
|
Chris@45
|
3405 {
|
Chris@45
|
3406 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@45
|
3407 if (!pane) return 0;
|
Chris@45
|
3408
|
Chris@45
|
3409 Layer *layer = pane->getSelectedLayer();
|
Chris@45
|
3410
|
Chris@45
|
3411 if (!dynamic_cast<TimeInstantLayer *>(layer) &&
|
Chris@45
|
3412 !dynamic_cast<TimeValueLayer *>(layer) &&
|
Chris@194
|
3413 !dynamic_cast<RegionLayer *>(layer) &&
|
Chris@45
|
3414 !dynamic_cast<TimeRulerLayer *>(layer)) {
|
Chris@45
|
3415
|
Chris@45
|
3416 layer = 0;
|
Chris@45
|
3417
|
Chris@45
|
3418 for (int i = pane->getLayerCount(); i > 0; --i) {
|
Chris@45
|
3419 Layer *l = pane->getLayer(i-1);
|
Chris@45
|
3420 if (dynamic_cast<TimeRulerLayer *>(l)) {
|
Chris@45
|
3421 layer = l;
|
Chris@45
|
3422 break;
|
Chris@45
|
3423 }
|
Chris@45
|
3424 }
|
Chris@45
|
3425 }
|
Chris@45
|
3426
|
Chris@45
|
3427 return layer;
|
Chris@45
|
3428 }
|
Chris@45
|
3429
|
Chris@45
|
3430 void
|
Chris@45
|
3431 MainWindowBase::stop()
|
Chris@45
|
3432 {
|
Chris@516
|
3433 if (m_recordTarget &&
|
Chris@516
|
3434 m_recordTarget->isRecording()) {
|
Chris@477
|
3435 m_recordTarget->stopRecording();
|
Chris@477
|
3436 }
|
Chris@516
|
3437
|
Chris@516
|
3438 if (!m_playSource) return;
|
Chris@516
|
3439
|
Chris@45
|
3440 m_playSource->stop();
|
Chris@45
|
3441
|
Chris@611
|
3442 SVCERR << "MainWindowBase::stop: suspending" << endl;
|
Chris@611
|
3443
|
Chris@487
|
3444 if (m_audioIO) m_audioIO->suspend();
|
Chris@509
|
3445 else if (m_playTarget) m_playTarget->suspend();
|
Chris@487
|
3446
|
Chris@45
|
3447 if (m_paneStack && m_paneStack->getCurrentPane()) {
|
Chris@45
|
3448 updateVisibleRangeDisplay(m_paneStack->getCurrentPane());
|
Chris@45
|
3449 } else {
|
Chris@45
|
3450 m_myStatusMessage = "";
|
Chris@378
|
3451 getStatusLabel()->setText("");
|
Chris@45
|
3452 }
|
Chris@45
|
3453 }
|
Chris@45
|
3454
|
Chris@45
|
3455 MainWindowBase::AddPaneCommand::AddPaneCommand(MainWindowBase *mw) :
|
Chris@45
|
3456 m_mw(mw),
|
Chris@45
|
3457 m_pane(0),
|
Chris@45
|
3458 m_prevCurrentPane(0),
|
Chris@45
|
3459 m_added(false)
|
Chris@45
|
3460 {
|
Chris@45
|
3461 }
|
Chris@45
|
3462
|
Chris@45
|
3463 MainWindowBase::AddPaneCommand::~AddPaneCommand()
|
Chris@45
|
3464 {
|
Chris@45
|
3465 if (m_pane && !m_added) {
|
Chris@595
|
3466 m_mw->m_paneStack->deletePane(m_pane);
|
Chris@45
|
3467 }
|
Chris@45
|
3468 }
|
Chris@45
|
3469
|
Chris@45
|
3470 QString
|
Chris@45
|
3471 MainWindowBase::AddPaneCommand::getName() const
|
Chris@45
|
3472 {
|
Chris@45
|
3473 return tr("Add Pane");
|
Chris@45
|
3474 }
|
Chris@45
|
3475
|
Chris@45
|
3476 void
|
Chris@45
|
3477 MainWindowBase::AddPaneCommand::execute()
|
Chris@45
|
3478 {
|
Chris@45
|
3479 if (!m_pane) {
|
Chris@595
|
3480 m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane();
|
Chris@595
|
3481 m_pane = m_mw->m_paneStack->addPane();
|
Chris@45
|
3482
|
Chris@45
|
3483 connect(m_pane, SIGNAL(contextHelpChanged(const QString &)),
|
Chris@45
|
3484 m_mw, SLOT(contextHelpChanged(const QString &)));
|
Chris@45
|
3485 } else {
|
Chris@595
|
3486 m_mw->m_paneStack->showPane(m_pane);
|
Chris@45
|
3487 }
|
Chris@45
|
3488
|
Chris@45
|
3489 m_mw->m_paneStack->setCurrentPane(m_pane);
|
Chris@45
|
3490 m_added = true;
|
Chris@45
|
3491 }
|
Chris@45
|
3492
|
Chris@45
|
3493 void
|
Chris@45
|
3494 MainWindowBase::AddPaneCommand::unexecute()
|
Chris@45
|
3495 {
|
Chris@45
|
3496 m_mw->m_paneStack->hidePane(m_pane);
|
Chris@45
|
3497 m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane);
|
Chris@45
|
3498 m_added = false;
|
Chris@45
|
3499 }
|
Chris@45
|
3500
|
Chris@45
|
3501 MainWindowBase::RemovePaneCommand::RemovePaneCommand(MainWindowBase *mw, Pane *pane) :
|
Chris@45
|
3502 m_mw(mw),
|
Chris@45
|
3503 m_pane(pane),
|
Chris@409
|
3504 m_prevCurrentPane(0),
|
Chris@45
|
3505 m_added(true)
|
Chris@45
|
3506 {
|
Chris@45
|
3507 }
|
Chris@45
|
3508
|
Chris@45
|
3509 MainWindowBase::RemovePaneCommand::~RemovePaneCommand()
|
Chris@45
|
3510 {
|
Chris@45
|
3511 if (m_pane && !m_added) {
|
Chris@595
|
3512 m_mw->m_paneStack->deletePane(m_pane);
|
Chris@45
|
3513 }
|
Chris@45
|
3514 }
|
Chris@45
|
3515
|
Chris@45
|
3516 QString
|
Chris@45
|
3517 MainWindowBase::RemovePaneCommand::getName() const
|
Chris@45
|
3518 {
|
Chris@45
|
3519 return tr("Remove Pane");
|
Chris@45
|
3520 }
|
Chris@45
|
3521
|
Chris@45
|
3522 void
|
Chris@45
|
3523 MainWindowBase::RemovePaneCommand::execute()
|
Chris@45
|
3524 {
|
Chris@45
|
3525 m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane();
|
Chris@45
|
3526 m_mw->m_paneStack->hidePane(m_pane);
|
Chris@45
|
3527 m_added = false;
|
Chris@45
|
3528 }
|
Chris@45
|
3529
|
Chris@45
|
3530 void
|
Chris@45
|
3531 MainWindowBase::RemovePaneCommand::unexecute()
|
Chris@45
|
3532 {
|
Chris@45
|
3533 m_mw->m_paneStack->showPane(m_pane);
|
Chris@45
|
3534 m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane);
|
Chris@45
|
3535 m_added = true;
|
Chris@45
|
3536 }
|
Chris@45
|
3537
|
Chris@45
|
3538 void
|
Chris@45
|
3539 MainWindowBase::deleteCurrentPane()
|
Chris@45
|
3540 {
|
Chris@45
|
3541 CommandHistory::getInstance()->startCompoundOperation
|
Chris@595
|
3542 (tr("Delete Pane"), true);
|
Chris@45
|
3543
|
Chris@45
|
3544 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@45
|
3545 if (pane) {
|
Chris@595
|
3546 while (pane->getLayerCount() > 0) {
|
Chris@595
|
3547 Layer *layer = pane->getLayer(0);
|
Chris@595
|
3548 if (layer) {
|
Chris@595
|
3549 m_document->removeLayerFromView(pane, layer);
|
Chris@595
|
3550 } else {
|
Chris@595
|
3551 break;
|
Chris@595
|
3552 }
|
Chris@595
|
3553 }
|
Chris@595
|
3554
|
Chris@595
|
3555 RemovePaneCommand *command = new RemovePaneCommand(this, pane);
|
Chris@595
|
3556 CommandHistory::getInstance()->addCommand(command);
|
Chris@45
|
3557 }
|
Chris@45
|
3558
|
Chris@45
|
3559 CommandHistory::getInstance()->endCompoundOperation();
|
Chris@45
|
3560
|
Chris@45
|
3561 updateMenuStates();
|
Chris@45
|
3562 }
|
Chris@45
|
3563
|
Chris@45
|
3564 void
|
Chris@45
|
3565 MainWindowBase::deleteCurrentLayer()
|
Chris@45
|
3566 {
|
Chris@45
|
3567 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@45
|
3568 if (pane) {
|
Chris@595
|
3569 Layer *layer = pane->getSelectedLayer();
|
Chris@595
|
3570 if (layer) {
|
Chris@595
|
3571 m_document->removeLayerFromView(pane, layer);
|
Chris@595
|
3572 }
|
Chris@45
|
3573 }
|
Chris@45
|
3574 updateMenuStates();
|
Chris@45
|
3575 }
|
Chris@45
|
3576
|
Chris@45
|
3577 void
|
Chris@123
|
3578 MainWindowBase::editCurrentLayer()
|
Chris@123
|
3579 {
|
Chris@123
|
3580 Layer *layer = 0;
|
Chris@123
|
3581 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@123
|
3582 if (pane) layer = pane->getSelectedLayer();
|
Chris@123
|
3583 if (!layer) return;
|
Chris@123
|
3584
|
Chris@123
|
3585 Model *model = layer->getModel();
|
Chris@123
|
3586 if (!model) return;
|
Chris@123
|
3587
|
Chris@124
|
3588 TabularModel *tabular = dynamic_cast<TabularModel *>(model);
|
Chris@124
|
3589 if (!tabular) {
|
Chris@124
|
3590 //!!! how to prevent this function from being active if not
|
Chris@124
|
3591 //appropriate model type? or will we ultimately support
|
Chris@124
|
3592 //tabular display for all editable models?
|
Chris@233
|
3593 SVDEBUG << "NOTE: Not a tabular model" << endl;
|
Chris@124
|
3594 return;
|
Chris@124
|
3595 }
|
Chris@124
|
3596
|
Chris@123
|
3597 if (m_layerDataDialogMap.find(layer) != m_layerDataDialogMap.end()) {
|
Chris@126
|
3598 if (!m_layerDataDialogMap[layer].isNull()) {
|
Chris@126
|
3599 m_layerDataDialogMap[layer]->show();
|
Chris@126
|
3600 m_layerDataDialogMap[layer]->raise();
|
Chris@126
|
3601 return;
|
Chris@126
|
3602 }
|
Chris@123
|
3603 }
|
Chris@123
|
3604
|
Chris@125
|
3605 QString title = layer->getLayerPresentationName();
|
Chris@125
|
3606
|
Chris@125
|
3607 ModelDataTableDialog *dialog = new ModelDataTableDialog(tabular, title, this);
|
Chris@128
|
3608 dialog->setAttribute(Qt::WA_DeleteOnClose);
|
Chris@128
|
3609
|
Chris@128
|
3610 connectLayerEditDialog(dialog);
|
Chris@123
|
3611
|
Chris@128
|
3612 m_layerDataDialogMap[layer] = dialog;
|
Chris@128
|
3613 m_viewDataDialogMap[pane].insert(dialog);
|
Chris@128
|
3614
|
Chris@128
|
3615 dialog->show();
|
Chris@128
|
3616 }
|
Chris@128
|
3617
|
Chris@128
|
3618 void
|
Chris@128
|
3619 MainWindowBase::connectLayerEditDialog(ModelDataTableDialog *dialog)
|
Chris@128
|
3620 {
|
Chris@123
|
3621 connect(m_viewManager,
|
Chris@435
|
3622 SIGNAL(globalCentreFrameChanged(sv_frame_t)),
|
Chris@123
|
3623 dialog,
|
Chris@435
|
3624 SLOT(userScrolledToFrame(sv_frame_t)));
|
Chris@127
|
3625
|
Chris@127
|
3626 connect(m_viewManager,
|
Chris@435
|
3627 SIGNAL(playbackFrameChanged(sv_frame_t)),
|
Chris@127
|
3628 dialog,
|
Chris@435
|
3629 SLOT(playbackScrolledToFrame(sv_frame_t)));
|
Chris@127
|
3630
|
Chris@123
|
3631 connect(dialog,
|
Chris@435
|
3632 SIGNAL(scrollToFrame(sv_frame_t)),
|
Chris@123
|
3633 m_viewManager,
|
Chris@435
|
3634 SLOT(setGlobalCentreFrame(sv_frame_t)));
|
Chris@129
|
3635
|
Chris@129
|
3636 connect(dialog,
|
Chris@435
|
3637 SIGNAL(scrollToFrame(sv_frame_t)),
|
Chris@129
|
3638 m_viewManager,
|
Chris@435
|
3639 SLOT(setPlaybackFrame(sv_frame_t)));
|
Chris@128
|
3640 }
|
Chris@123
|
3641
|
Chris@123
|
3642 void
|
Chris@73
|
3643 MainWindowBase::previousPane()
|
Chris@73
|
3644 {
|
Chris@73
|
3645 if (!m_paneStack) return;
|
Chris@73
|
3646
|
Chris@73
|
3647 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@73
|
3648 if (!currentPane) return;
|
Chris@73
|
3649
|
Chris@73
|
3650 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@73
|
3651 if (m_paneStack->getPane(i) == currentPane) {
|
Chris@73
|
3652 if (i == 0) return;
|
Chris@73
|
3653 m_paneStack->setCurrentPane(m_paneStack->getPane(i-1));
|
Chris@73
|
3654 updateMenuStates();
|
Chris@73
|
3655 return;
|
Chris@73
|
3656 }
|
Chris@73
|
3657 }
|
Chris@73
|
3658 }
|
Chris@73
|
3659
|
Chris@73
|
3660 void
|
Chris@73
|
3661 MainWindowBase::nextPane()
|
Chris@73
|
3662 {
|
Chris@73
|
3663 if (!m_paneStack) return;
|
Chris@73
|
3664
|
Chris@73
|
3665 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@73
|
3666 if (!currentPane) return;
|
Chris@73
|
3667
|
Chris@73
|
3668 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@73
|
3669 if (m_paneStack->getPane(i) == currentPane) {
|
Chris@73
|
3670 if (i == m_paneStack->getPaneCount()-1) return;
|
Chris@73
|
3671 m_paneStack->setCurrentPane(m_paneStack->getPane(i+1));
|
Chris@73
|
3672 updateMenuStates();
|
Chris@73
|
3673 return;
|
Chris@73
|
3674 }
|
Chris@73
|
3675 }
|
Chris@73
|
3676 }
|
Chris@73
|
3677
|
Chris@73
|
3678 void
|
Chris@73
|
3679 MainWindowBase::previousLayer()
|
Chris@73
|
3680 {
|
Chris@73
|
3681 if (!m_paneStack) return;
|
Chris@73
|
3682
|
Chris@73
|
3683 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@73
|
3684 if (!currentPane) return;
|
Chris@73
|
3685
|
Chris@403
|
3686 int count = currentPane->getLayerCount();
|
Chris@403
|
3687 if (count == 0) return;
|
Chris@403
|
3688
|
Chris@73
|
3689 Layer *currentLayer = currentPane->getSelectedLayer();
|
Chris@403
|
3690
|
Chris@403
|
3691 if (!currentLayer) {
|
Chris@403
|
3692 // The pane itself is current
|
Chris@403
|
3693 m_paneStack->setCurrentLayer
|
Chris@403
|
3694 (currentPane, currentPane->getFixedOrderLayer(count-1));
|
Chris@403
|
3695 } else {
|
Chris@403
|
3696 for (int i = 0; i < count; ++i) {
|
Chris@403
|
3697 if (currentPane->getFixedOrderLayer(i) == currentLayer) {
|
Chris@403
|
3698 if (i == 0) {
|
Chris@403
|
3699 m_paneStack->setCurrentLayer
|
Chris@403
|
3700 (currentPane, 0); // pane
|
Chris@403
|
3701 } else {
|
Chris@403
|
3702 m_paneStack->setCurrentLayer
|
Chris@403
|
3703 (currentPane, currentPane->getFixedOrderLayer(i-1));
|
Chris@403
|
3704 }
|
Chris@403
|
3705 break;
|
Chris@403
|
3706 }
|
Chris@73
|
3707 }
|
Chris@73
|
3708 }
|
Chris@403
|
3709
|
Chris@403
|
3710 updateMenuStates();
|
Chris@73
|
3711 }
|
Chris@73
|
3712
|
Chris@73
|
3713 void
|
Chris@73
|
3714 MainWindowBase::nextLayer()
|
Chris@73
|
3715 {
|
Chris@73
|
3716 if (!m_paneStack) return;
|
Chris@73
|
3717
|
Chris@73
|
3718 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@73
|
3719 if (!currentPane) return;
|
Chris@73
|
3720
|
Chris@403
|
3721 int count = currentPane->getLayerCount();
|
Chris@403
|
3722 if (count == 0) return;
|
Chris@403
|
3723
|
Chris@73
|
3724 Layer *currentLayer = currentPane->getSelectedLayer();
|
Chris@403
|
3725
|
Chris@403
|
3726 if (!currentLayer) {
|
Chris@403
|
3727 // The pane itself is current
|
Chris@403
|
3728 m_paneStack->setCurrentLayer
|
Chris@403
|
3729 (currentPane, currentPane->getFixedOrderLayer(0));
|
Chris@403
|
3730 } else {
|
Chris@403
|
3731 for (int i = 0; i < count; ++i) {
|
Chris@403
|
3732 if (currentPane->getFixedOrderLayer(i) == currentLayer) {
|
Chris@403
|
3733 if (i == currentPane->getLayerCount()-1) {
|
Chris@403
|
3734 m_paneStack->setCurrentLayer
|
Chris@403
|
3735 (currentPane, 0); // pane
|
Chris@403
|
3736 } else {
|
Chris@403
|
3737 m_paneStack->setCurrentLayer
|
Chris@403
|
3738 (currentPane, currentPane->getFixedOrderLayer(i+1));
|
Chris@403
|
3739 }
|
Chris@403
|
3740 break;
|
Chris@403
|
3741 }
|
Chris@73
|
3742 }
|
Chris@73
|
3743 }
|
Chris@403
|
3744
|
Chris@403
|
3745 updateMenuStates();
|
Chris@73
|
3746 }
|
Chris@73
|
3747
|
Chris@73
|
3748 void
|
Chris@435
|
3749 MainWindowBase::playbackFrameChanged(sv_frame_t frame)
|
Chris@45
|
3750 {
|
Chris@45
|
3751 if (!(m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
|
Chris@45
|
3752
|
Chris@187
|
3753 updatePositionStatusDisplays();
|
Chris@187
|
3754
|
Chris@45
|
3755 RealTime now = RealTime::frame2RealTime
|
Chris@45
|
3756 (frame, getMainModel()->getSampleRate());
|
Chris@45
|
3757
|
Chris@45
|
3758 if (now.sec == m_lastPlayStatusSec) return;
|
Chris@45
|
3759
|
Chris@45
|
3760 RealTime then = RealTime::frame2RealTime
|
Chris@45
|
3761 (m_playSource->getPlayEndFrame(), getMainModel()->getSampleRate());
|
Chris@45
|
3762
|
Chris@45
|
3763 QString nowStr;
|
Chris@45
|
3764 QString thenStr;
|
Chris@45
|
3765 QString remainingStr;
|
Chris@45
|
3766
|
Chris@45
|
3767 if (then.sec > 10) {
|
Chris@45
|
3768 nowStr = now.toSecText().c_str();
|
Chris@45
|
3769 thenStr = then.toSecText().c_str();
|
Chris@45
|
3770 remainingStr = (then - now).toSecText().c_str();
|
Chris@45
|
3771 m_lastPlayStatusSec = now.sec;
|
Chris@45
|
3772 } else {
|
Chris@45
|
3773 nowStr = now.toText(true).c_str();
|
Chris@45
|
3774 thenStr = then.toText(true).c_str();
|
Chris@45
|
3775 remainingStr = (then - now).toText(true).c_str();
|
Chris@45
|
3776 }
|
Chris@45
|
3777
|
Chris@45
|
3778 m_myStatusMessage = tr("Playing: %1 of %2 (%3 remaining)")
|
Chris@45
|
3779 .arg(nowStr).arg(thenStr).arg(remainingStr);
|
Chris@45
|
3780
|
Chris@378
|
3781 getStatusLabel()->setText(m_myStatusMessage);
|
Chris@45
|
3782 }
|
Chris@45
|
3783
|
Chris@45
|
3784 void
|
Chris@486
|
3785 MainWindowBase::recordDurationChanged(sv_frame_t frame, sv_samplerate_t rate)
|
Chris@486
|
3786 {
|
Chris@486
|
3787 RealTime duration = RealTime::frame2RealTime(frame, rate);
|
Chris@486
|
3788 QString durStr = duration.toSecText().c_str();
|
Chris@486
|
3789
|
Chris@486
|
3790 m_myStatusMessage = tr("Recording: %1").arg(durStr);
|
Chris@486
|
3791
|
Chris@486
|
3792 getStatusLabel()->setText(m_myStatusMessage);
|
Chris@486
|
3793 }
|
Chris@486
|
3794
|
Chris@486
|
3795 void
|
Chris@435
|
3796 MainWindowBase::globalCentreFrameChanged(sv_frame_t )
|
Chris@45
|
3797 {
|
Chris@45
|
3798 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
|
Chris@45
|
3799 Pane *p = 0;
|
Chris@45
|
3800 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
|
Chris@45
|
3801 if (!p->getFollowGlobalPan()) return;
|
Chris@45
|
3802 updateVisibleRangeDisplay(p);
|
Chris@45
|
3803 }
|
Chris@45
|
3804
|
Chris@45
|
3805 void
|
Chris@435
|
3806 MainWindowBase::viewCentreFrameChanged(View *v, sv_frame_t frame)
|
Chris@45
|
3807 {
|
Chris@233
|
3808 // SVDEBUG << "MainWindowBase::viewCentreFrameChanged(" << v << "," << frame << ")" << endl;
|
Chris@123
|
3809
|
Chris@123
|
3810 if (m_viewDataDialogMap.find(v) != m_viewDataDialogMap.end()) {
|
Chris@123
|
3811 for (DataDialogSet::iterator i = m_viewDataDialogMap[v].begin();
|
Chris@123
|
3812 i != m_viewDataDialogMap[v].end(); ++i) {
|
Chris@127
|
3813 (*i)->userScrolledToFrame(frame);
|
Chris@123
|
3814 }
|
Chris@123
|
3815 }
|
Chris@45
|
3816 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
|
Chris@45
|
3817 Pane *p = 0;
|
Chris@45
|
3818 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
|
Chris@45
|
3819 if (v == p) updateVisibleRangeDisplay(p);
|
Chris@45
|
3820 }
|
Chris@45
|
3821
|
Chris@45
|
3822 void
|
Chris@366
|
3823 MainWindowBase::viewZoomLevelChanged(View *v, int , bool )
|
Chris@45
|
3824 {
|
Chris@45
|
3825 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
|
Chris@45
|
3826 Pane *p = 0;
|
Chris@45
|
3827 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
|
Chris@45
|
3828 if (v == p) updateVisibleRangeDisplay(p);
|
Chris@45
|
3829 }
|
Chris@45
|
3830
|
Chris@45
|
3831 void
|
Chris@45
|
3832 MainWindowBase::layerAdded(Layer *)
|
Chris@45
|
3833 {
|
Chris@233
|
3834 // SVDEBUG << "MainWindowBase::layerAdded(" << layer << ")" << endl;
|
Chris@45
|
3835 updateMenuStates();
|
Chris@45
|
3836 }
|
Chris@45
|
3837
|
Chris@45
|
3838 void
|
Chris@45
|
3839 MainWindowBase::layerRemoved(Layer *)
|
Chris@45
|
3840 {
|
Chris@233
|
3841 // SVDEBUG << "MainWindowBase::layerRemoved(" << layer << ")" << endl;
|
Chris@45
|
3842 updateMenuStates();
|
Chris@45
|
3843 }
|
Chris@45
|
3844
|
Chris@45
|
3845 void
|
Chris@45
|
3846 MainWindowBase::layerAboutToBeDeleted(Layer *layer)
|
Chris@45
|
3847 {
|
Chris@233
|
3848 // SVDEBUG << "MainWindowBase::layerAboutToBeDeleted(" << layer << ")" << endl;
|
Chris@123
|
3849
|
Chris@128
|
3850 removeLayerEditDialog(layer);
|
Chris@123
|
3851
|
Chris@47
|
3852 if (m_timeRulerLayer && (layer == m_timeRulerLayer)) {
|
Chris@595
|
3853 // cerr << "(this is the time ruler layer)" << endl;
|
Chris@595
|
3854 m_timeRulerLayer = 0;
|
Chris@45
|
3855 }
|
Chris@45
|
3856 }
|
Chris@45
|
3857
|
Chris@45
|
3858 void
|
Chris@45
|
3859 MainWindowBase::layerInAView(Layer *layer, bool inAView)
|
Chris@45
|
3860 {
|
Chris@233
|
3861 // SVDEBUG << "MainWindowBase::layerInAView(" << layer << "," << inAView << ")" << endl;
|
Chris@128
|
3862
|
Chris@128
|
3863 if (!inAView) removeLayerEditDialog(layer);
|
Chris@45
|
3864
|
Chris@45
|
3865 // Check whether we need to add or remove model from play source
|
Chris@45
|
3866 Model *model = layer->getModel();
|
Chris@45
|
3867 if (model) {
|
Chris@45
|
3868 if (inAView) {
|
Chris@45
|
3869 m_playSource->addModel(model);
|
Chris@45
|
3870 } else {
|
Chris@45
|
3871 bool found = false;
|
Chris@45
|
3872 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@45
|
3873 Pane *pane = m_paneStack->getPane(i);
|
Chris@45
|
3874 if (!pane) continue;
|
Chris@45
|
3875 for (int j = 0; j < pane->getLayerCount(); ++j) {
|
Chris@45
|
3876 Layer *pl = pane->getLayer(j);
|
Chris@183
|
3877 if (pl &&
|
Chris@183
|
3878 !dynamic_cast<TimeRulerLayer *>(pl) &&
|
Chris@183
|
3879 (pl->getModel() == model)) {
|
Chris@45
|
3880 found = true;
|
Chris@45
|
3881 break;
|
Chris@45
|
3882 }
|
Chris@45
|
3883 }
|
Chris@45
|
3884 if (found) break;
|
Chris@45
|
3885 }
|
Chris@173
|
3886 if (!found) {
|
Chris@173
|
3887 m_playSource->removeModel(model);
|
Chris@173
|
3888 }
|
Chris@45
|
3889 }
|
Chris@45
|
3890 }
|
Chris@45
|
3891
|
Chris@45
|
3892 updateMenuStates();
|
Chris@45
|
3893 }
|
Chris@45
|
3894
|
Chris@45
|
3895 void
|
Chris@128
|
3896 MainWindowBase::removeLayerEditDialog(Layer *layer)
|
Chris@128
|
3897 {
|
Chris@128
|
3898 if (m_layerDataDialogMap.find(layer) != m_layerDataDialogMap.end()) {
|
Chris@128
|
3899
|
Chris@128
|
3900 ModelDataTableDialog *dialog = m_layerDataDialogMap[layer];
|
Chris@128
|
3901
|
Chris@128
|
3902 for (ViewDataDialogMap::iterator vi = m_viewDataDialogMap.begin();
|
Chris@128
|
3903 vi != m_viewDataDialogMap.end(); ++vi) {
|
Chris@128
|
3904 vi->second.erase(dialog);
|
Chris@128
|
3905 }
|
Chris@128
|
3906
|
Chris@128
|
3907 m_layerDataDialogMap.erase(layer);
|
Chris@128
|
3908 delete dialog;
|
Chris@128
|
3909 }
|
Chris@128
|
3910 }
|
Chris@128
|
3911
|
Chris@128
|
3912 void
|
Chris@45
|
3913 MainWindowBase::modelAdded(Model *model)
|
Chris@45
|
3914 {
|
Chris@233
|
3915 // SVDEBUG << "MainWindowBase::modelAdded(" << model << ")" << endl;
|
Chris@595
|
3916 std::cerr << "\nAdding model " << model->getTypeName() << " to playsource " << std::endl;
|
Chris@45
|
3917 m_playSource->addModel(model);
|
Chris@45
|
3918 }
|
Chris@45
|
3919
|
Chris@45
|
3920 void
|
Chris@45
|
3921 MainWindowBase::mainModelChanged(WaveFileModel *model)
|
Chris@45
|
3922 {
|
Chris@233
|
3923 // SVDEBUG << "MainWindowBase::mainModelChanged(" << model << ")" << endl;
|
Chris@45
|
3924 updateDescriptionLabel();
|
Chris@45
|
3925 if (model) m_viewManager->setMainModelSampleRate(model->getSampleRate());
|
Chris@475
|
3926 if (model && !(m_playTarget || m_audioIO) &&
|
Chris@475
|
3927 (m_soundOptions & WithAudioOutput)) {
|
Chris@475
|
3928 createAudioIO();
|
Chris@360
|
3929 }
|
Chris@45
|
3930 }
|
Chris@45
|
3931
|
Chris@45
|
3932 void
|
Chris@45
|
3933 MainWindowBase::modelAboutToBeDeleted(Model *model)
|
Chris@45
|
3934 {
|
Chris@233
|
3935 // SVDEBUG << "MainWindowBase::modelAboutToBeDeleted(" << model << ")" << endl;
|
Chris@45
|
3936 if (model == m_viewManager->getPlaybackModel()) {
|
Chris@45
|
3937 m_viewManager->setPlaybackModel(0);
|
Chris@45
|
3938 }
|
Chris@45
|
3939 m_playSource->removeModel(model);
|
Chris@45
|
3940 }
|
Chris@45
|
3941
|
Chris@45
|
3942 void
|
Chris@55
|
3943 MainWindowBase::paneDeleteButtonClicked(Pane *pane)
|
Chris@55
|
3944 {
|
Chris@55
|
3945 bool found = false;
|
Chris@55
|
3946 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@55
|
3947 if (m_paneStack->getPane(i) == pane) {
|
Chris@55
|
3948 found = true;
|
Chris@55
|
3949 break;
|
Chris@55
|
3950 }
|
Chris@55
|
3951 }
|
Chris@55
|
3952 if (!found) {
|
Chris@233
|
3953 SVDEBUG << "MainWindowBase::paneDeleteButtonClicked: Unknown pane "
|
Chris@229
|
3954 << pane << endl;
|
Chris@55
|
3955 return;
|
Chris@55
|
3956 }
|
Chris@55
|
3957
|
Chris@55
|
3958 CommandHistory::getInstance()->startCompoundOperation
|
Chris@595
|
3959 (tr("Delete Pane"), true);
|
Chris@55
|
3960
|
Chris@55
|
3961 while (pane->getLayerCount() > 0) {
|
Chris@55
|
3962 Layer *layer = pane->getLayer(0);
|
Chris@55
|
3963 if (layer) {
|
Chris@55
|
3964 m_document->removeLayerFromView(pane, layer);
|
Chris@55
|
3965 } else {
|
Chris@55
|
3966 break;
|
Chris@55
|
3967 }
|
Chris@55
|
3968 }
|
Chris@55
|
3969
|
Chris@55
|
3970 RemovePaneCommand *command = new RemovePaneCommand(this, pane);
|
Chris@55
|
3971 CommandHistory::getInstance()->addCommand(command);
|
Chris@55
|
3972
|
Chris@55
|
3973 CommandHistory::getInstance()->endCompoundOperation();
|
Chris@55
|
3974
|
Chris@55
|
3975 updateMenuStates();
|
Chris@55
|
3976 }
|
Chris@55
|
3977
|
Chris@55
|
3978 void
|
Chris@429
|
3979 MainWindowBase::alignmentComplete(AlignmentModel *model)
|
Chris@429
|
3980 {
|
Chris@429
|
3981 cerr << "MainWindowBase::alignmentComplete(" << model << ")" << endl;
|
Chris@429
|
3982 }
|
Chris@429
|
3983
|
Chris@429
|
3984 void
|
Chris@45
|
3985 MainWindowBase::pollOSC()
|
Chris@45
|
3986 {
|
Chris@45
|
3987 if (!m_oscQueue || m_oscQueue->isEmpty()) return;
|
Chris@233
|
3988 SVDEBUG << "MainWindowBase::pollOSC: have " << m_oscQueue->getMessagesAvailable() << " messages" << endl;
|
Chris@45
|
3989
|
Chris@45
|
3990 if (m_openingAudioFile) return;
|
Chris@45
|
3991
|
Chris@45
|
3992 OSCMessage message = m_oscQueue->readMessage();
|
Chris@45
|
3993
|
Chris@45
|
3994 if (message.getTarget() != 0) {
|
Chris@45
|
3995 return; //!!! for now -- this class is target 0, others not handled yet
|
Chris@45
|
3996 }
|
Chris@45
|
3997
|
Chris@45
|
3998 handleOSCMessage(message);
|
Chris@45
|
3999 }
|
Chris@45
|
4000
|
Chris@45
|
4001 void
|
Chris@45
|
4002 MainWindowBase::inProgressSelectionChanged()
|
Chris@45
|
4003 {
|
Chris@45
|
4004 Pane *currentPane = 0;
|
Chris@45
|
4005 if (m_paneStack) currentPane = m_paneStack->getCurrentPane();
|
justin@331
|
4006 if (currentPane) {
|
justin@331
|
4007 //cerr << "JTEST: mouse event on selection pane" << endl;
|
justin@331
|
4008 updateVisibleRangeDisplay(currentPane);
|
justin@331
|
4009 }
|
Chris@45
|
4010 }
|
Chris@45
|
4011
|
Chris@45
|
4012 void
|
Chris@45
|
4013 MainWindowBase::contextHelpChanged(const QString &s)
|
Chris@45
|
4014 {
|
Chris@378
|
4015 QLabel *lab = getStatusLabel();
|
Chris@375
|
4016
|
Chris@45
|
4017 if (s == "" && m_myStatusMessage != "") {
|
Chris@378
|
4018 if (lab->text() != m_myStatusMessage) {
|
Chris@378
|
4019 lab->setText(m_myStatusMessage);
|
Chris@375
|
4020 }
|
Chris@45
|
4021 return;
|
Chris@45
|
4022 }
|
Chris@375
|
4023
|
Chris@378
|
4024 lab->setText(s);
|
Chris@45
|
4025 }
|
Chris@45
|
4026
|
Chris@45
|
4027 void
|
Chris@45
|
4028 MainWindowBase::openHelpUrl(QString url)
|
Chris@45
|
4029 {
|
Chris@45
|
4030 // This method mostly lifted from Qt Assistant source code
|
Chris@45
|
4031
|
Chris@45
|
4032 QProcess *process = new QProcess(this);
|
Chris@45
|
4033 connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater()));
|
Chris@45
|
4034
|
Chris@45
|
4035 QStringList args;
|
Chris@45
|
4036
|
Chris@45
|
4037 #ifdef Q_OS_MAC
|
Chris@45
|
4038 args.append(url);
|
Chris@45
|
4039 process->start("open", args);
|
Chris@45
|
4040 #else
|
Chris@45
|
4041 #ifdef Q_OS_WIN32
|
Chris@599
|
4042 std::string pfiles;
|
Chris@599
|
4043 (void)getEnvUtf8("ProgramFiles", pfiles);
|
Chris@599
|
4044 QString command =
|
Chris@599
|
4045 QString::fromStdString(pfiles) +
|
Chris@599
|
4046 QString("\\Internet Explorer\\IEXPLORE.EXE");
|
Chris@358
|
4047
|
Chris@358
|
4048 args.append(url);
|
Chris@358
|
4049 process->start(command, args);
|
Chris@45
|
4050 #else
|
Chris@45
|
4051 if (!qgetenv("KDE_FULL_SESSION").isEmpty()) {
|
Chris@45
|
4052 args.append("exec");
|
Chris@45
|
4053 args.append(url);
|
Chris@45
|
4054 process->start("kfmclient", args);
|
Chris@45
|
4055 } else if (!qgetenv("BROWSER").isEmpty()) {
|
Chris@45
|
4056 args.append(url);
|
Chris@45
|
4057 process->start(qgetenv("BROWSER"), args);
|
Chris@45
|
4058 } else {
|
Chris@45
|
4059 args.append(url);
|
Chris@45
|
4060 process->start("firefox", args);
|
Chris@45
|
4061 }
|
Chris@45
|
4062 #endif
|
Chris@45
|
4063 #endif
|
Chris@45
|
4064 }
|
Chris@45
|
4065
|
Chris@483
|
4066 void
|
Chris@483
|
4067 MainWindowBase::openLocalFolder(QString path)
|
Chris@483
|
4068 {
|
Chris@483
|
4069 QDir d(path);
|
Chris@483
|
4070 if (d.exists()) {
|
Chris@483
|
4071 QStringList args;
|
Chris@483
|
4072 QString path = d.canonicalPath();
|
Chris@483
|
4073 #if defined Q_OS_WIN32
|
Chris@483
|
4074 // Although the Win32 API is quite happy to have
|
Chris@483
|
4075 // forward slashes as directory separators, Windows
|
Chris@483
|
4076 // Explorer is not
|
Chris@483
|
4077 path = path.replace('/', '\\');
|
Chris@483
|
4078 args << path;
|
Chris@483
|
4079 QProcess::execute("c:/windows/explorer.exe", args);
|
Chris@483
|
4080 #else
|
Chris@483
|
4081 args << path;
|
Chris@605
|
4082 QProcess process;
|
Chris@605
|
4083 QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
Chris@606
|
4084 env.insert("LD_LIBRARY_PATH", "");
|
Chris@605
|
4085 process.setProcessEnvironment(env);
|
Chris@605
|
4086 process.start(
|
Chris@483
|
4087 #if defined Q_OS_MAC
|
Chris@483
|
4088 "/usr/bin/open",
|
Chris@483
|
4089 #else
|
Chris@483
|
4090 "/usr/bin/xdg-open",
|
Chris@483
|
4091 #endif
|
Chris@483
|
4092 args);
|
Chris@608
|
4093 process.waitForFinished();
|
Chris@483
|
4094 #endif
|
Chris@483
|
4095 }
|
Chris@483
|
4096 }
|
Chris@483
|
4097
|