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