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