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