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