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@611
|
2462 SVCERR << "MainWindowBase::createAudioIO: Suspending on creation" << endl;
|
Chris@525
|
2463 m_audioIO->suspend(); // start in suspended state
|
Chris@525
|
2464 m_playSource->setSystemPlaybackTarget(m_audioIO);
|
Chris@586
|
2465 } else {
|
Chris@586
|
2466 // Failed to create audio I/O; this may just mean there is
|
Chris@586
|
2467 // no record device, so fall through to see what happens
|
Chris@586
|
2468 // next. We only report complete failure if we end up with
|
Chris@586
|
2469 // neither m_audioIO nor m_playTarget.
|
Chris@525
|
2470 }
|
Chris@586
|
2471 }
|
Chris@586
|
2472
|
Chris@586
|
2473 if (!m_audioIO) {
|
Chris@475
|
2474 m_playTarget = breakfastquay::AudioFactory::
|
Chris@569
|
2475 createCallbackPlayTarget(m_resamplerWrapper,
|
Chris@569
|
2476 preference, errorString);
|
Chris@525
|
2477 if (m_playTarget) {
|
Chris@611
|
2478 SVCERR << "MainWindowBase::createAudioIO: Suspending on creation" << endl;
|
Chris@525
|
2479 m_playTarget->suspend(); // start in suspended state
|
Chris@525
|
2480 m_playSource->setSystemPlaybackTarget(m_playTarget);
|
Chris@525
|
2481 }
|
Chris@475
|
2482 }
|
Chris@475
|
2483
|
Chris@475
|
2484 if (!m_playTarget && !m_audioIO) {
|
Chris@104
|
2485 emit hideSplash();
|
Chris@569
|
2486 QString message;
|
Chris@569
|
2487 QString error = errorString.c_str();
|
Chris@569
|
2488 QString firstBit, secondBit;
|
Chris@547
|
2489 if (implementation == "") {
|
Chris@569
|
2490 if (error == "") {
|
Chris@569
|
2491 firstBit = tr("<b>No audio available</b><p>Could not open an audio device.</p>");
|
Chris@569
|
2492 } else {
|
Chris@569
|
2493 firstBit = tr("<b>No audio available</b><p>Could not open audio device: %1</p>").arg(error);
|
Chris@569
|
2494 }
|
Chris@569
|
2495 if (m_soundOptions & WithAudioInput) {
|
Chris@569
|
2496 secondBit = tr("<p>Automatic audio device detection failed. Audio playback and recording will not be available during this session.</p>");
|
Chris@569
|
2497 } else {
|
Chris@569
|
2498 secondBit = tr("<p>Automatic audio device detection failed. Audio playback will not be available during this session.</p>");
|
Chris@569
|
2499 }
|
Chris@126
|
2500 } else {
|
Chris@569
|
2501 QString driverName = breakfastquay::AudioFactory::
|
Chris@569
|
2502 getImplementationDescription(implementation.toStdString())
|
Chris@569
|
2503 .c_str();
|
Chris@569
|
2504 if (error == "") {
|
Chris@569
|
2505 firstBit = tr("<b>No audio available</b><p>Failed to open your preferred audio driver (\"%1\").</p>").arg(driverName);
|
Chris@569
|
2506 } else {
|
Chris@569
|
2507 firstBit = tr("<b>No audio available</b><p>Failed to open your preferred audio driver (\"%1\"): %2.</p>").arg(driverName).arg(error);
|
Chris@569
|
2508 }
|
Chris@569
|
2509 if (m_soundOptions & WithAudioInput) {
|
Chris@569
|
2510 secondBit = tr("<p>Audio playback and recording will not be available during this session.</p>");
|
Chris@569
|
2511 } else {
|
Chris@569
|
2512 secondBit = tr("<p>Audio playback will not be available during this session.</p>");
|
Chris@569
|
2513 }
|
Chris@126
|
2514 }
|
Chris@570
|
2515 SVDEBUG << "createAudioIO: ERROR: Failed to open audio device \""
|
Chris@570
|
2516 << implementation << "\": error is: " << error << endl;
|
Chris@569
|
2517 QMessageBox::warning(this, tr("Couldn't open audio device"),
|
Chris@569
|
2518 firstBit + secondBit, QMessageBox::Ok);
|
Chris@45
|
2519 }
|
Chris@45
|
2520 }
|
Chris@45
|
2521
|
Chris@556
|
2522 void
|
Chris@556
|
2523 MainWindowBase::deleteAudioIO()
|
Chris@556
|
2524 {
|
Chris@556
|
2525 // First prevent this trying to call target.
|
Chris@559
|
2526 if (m_playSource) {
|
Chris@559
|
2527 m_playSource->setSystemPlaybackTarget(0);
|
Chris@559
|
2528 m_playSource->setResamplerWrapper(0);
|
Chris@559
|
2529 }
|
Chris@556
|
2530
|
Chris@556
|
2531 // Then delete the breakfastquay::System object.
|
Chris@556
|
2532 // Only one of these two exists!
|
Chris@556
|
2533 delete m_audioIO;
|
Chris@556
|
2534 delete m_playTarget;
|
Chris@556
|
2535
|
Chris@559
|
2536 // And the breakfastquay resampler wrapper. We need to
|
Chris@559
|
2537 // delete/recreate this if the channel count changes, which is one
|
Chris@559
|
2538 // of the use cases for recreateAudioIO() calling this
|
Chris@559
|
2539 delete m_resamplerWrapper;
|
Chris@559
|
2540
|
Chris@556
|
2541 m_audioIO = 0;
|
Chris@556
|
2542 m_playTarget = 0;
|
Chris@559
|
2543 m_resamplerWrapper = 0;
|
Chris@556
|
2544 }
|
Chris@556
|
2545
|
Chris@556
|
2546 void
|
Chris@556
|
2547 MainWindowBase::recreateAudioIO()
|
Chris@556
|
2548 {
|
Chris@556
|
2549 deleteAudioIO();
|
Chris@556
|
2550 createAudioIO();
|
Chris@556
|
2551 }
|
Chris@556
|
2552
|
Chris@570
|
2553 void
|
Chris@570
|
2554 MainWindowBase::audioChannelCountIncreased(int)
|
Chris@570
|
2555 {
|
Chris@611
|
2556 SVCERR << "MainWindowBase::audioChannelCountIncreased" << endl;
|
Chris@570
|
2557 recreateAudioIO();
|
Chris@610
|
2558
|
Chris@610
|
2559 if (m_recordTarget &&
|
Chris@610
|
2560 m_recordTarget->isRecording() &&
|
Chris@610
|
2561 m_audioIO) {
|
Chris@610
|
2562 SVCERR << "MainWindowBase::audioChannelCountIncreased: we were recording already, so resuming IO now" << endl;
|
Chris@610
|
2563 m_audioIO->resume();
|
Chris@610
|
2564 }
|
Chris@570
|
2565 }
|
Chris@570
|
2566
|
Chris@45
|
2567 WaveFileModel *
|
Chris@45
|
2568 MainWindowBase::getMainModel()
|
Chris@45
|
2569 {
|
Chris@45
|
2570 if (!m_document) return 0;
|
Chris@45
|
2571 return m_document->getMainModel();
|
Chris@45
|
2572 }
|
Chris@45
|
2573
|
Chris@45
|
2574 const WaveFileModel *
|
Chris@45
|
2575 MainWindowBase::getMainModel() const
|
Chris@45
|
2576 {
|
Chris@45
|
2577 if (!m_document) return 0;
|
Chris@45
|
2578 return m_document->getMainModel();
|
Chris@45
|
2579 }
|
Chris@45
|
2580
|
Chris@45
|
2581 void
|
Chris@45
|
2582 MainWindowBase::createDocument()
|
Chris@45
|
2583 {
|
Chris@45
|
2584 m_document = new Document;
|
Chris@45
|
2585
|
Chris@45
|
2586 connect(m_document, SIGNAL(layerAdded(Layer *)),
|
Chris@595
|
2587 this, SLOT(layerAdded(Layer *)));
|
Chris@45
|
2588 connect(m_document, SIGNAL(layerRemoved(Layer *)),
|
Chris@595
|
2589 this, SLOT(layerRemoved(Layer *)));
|
Chris@45
|
2590 connect(m_document, SIGNAL(layerAboutToBeDeleted(Layer *)),
|
Chris@595
|
2591 this, SLOT(layerAboutToBeDeleted(Layer *)));
|
Chris@45
|
2592 connect(m_document, SIGNAL(layerInAView(Layer *, bool)),
|
Chris@595
|
2593 this, SLOT(layerInAView(Layer *, bool)));
|
Chris@45
|
2594
|
Chris@45
|
2595 connect(m_document, SIGNAL(modelAdded(Model *)),
|
Chris@595
|
2596 this, SLOT(modelAdded(Model *)));
|
Chris@45
|
2597 connect(m_document, SIGNAL(mainModelChanged(WaveFileModel *)),
|
Chris@595
|
2598 this, SLOT(mainModelChanged(WaveFileModel *)));
|
Chris@45
|
2599 connect(m_document, SIGNAL(modelAboutToBeDeleted(Model *)),
|
Chris@595
|
2600 this, SLOT(modelAboutToBeDeleted(Model *)));
|
Chris@45
|
2601
|
Chris@78
|
2602 connect(m_document, SIGNAL(modelGenerationFailed(QString, QString)),
|
Chris@78
|
2603 this, SLOT(modelGenerationFailed(QString, QString)));
|
Chris@78
|
2604 connect(m_document, SIGNAL(modelRegenerationWarning(QString, QString, QString)),
|
Chris@78
|
2605 this, SLOT(modelRegenerationWarning(QString, QString, QString)));
|
Chris@429
|
2606 connect(m_document, SIGNAL(alignmentComplete(AlignmentModel *)),
|
Chris@429
|
2607 this, SLOT(alignmentComplete(AlignmentModel *)));
|
Chris@423
|
2608 connect(m_document, SIGNAL(alignmentFailed(QString)),
|
Chris@423
|
2609 this, SLOT(alignmentFailed(QString)));
|
Chris@160
|
2610
|
Chris@160
|
2611 emit replacedDocument();
|
Chris@45
|
2612 }
|
Chris@45
|
2613
|
Chris@45
|
2614 bool
|
Chris@45
|
2615 MainWindowBase::saveSessionFile(QString path)
|
Chris@45
|
2616 {
|
Chris@217
|
2617 try {
|
Chris@217
|
2618
|
Chris@217
|
2619 TempWriteFile temp(path);
|
Chris@217
|
2620
|
Chris@217
|
2621 BZipFileDevice bzFile(temp.getTemporaryFilename());
|
Chris@217
|
2622 if (!bzFile.open(QIODevice::WriteOnly)) {
|
Chris@293
|
2623 cerr << "Failed to open session file \""
|
Chris@294
|
2624 << temp.getTemporaryFilename()
|
Chris@217
|
2625 << "\" for writing: "
|
Chris@293
|
2626 << bzFile.errorString() << endl;
|
Chris@217
|
2627 return false;
|
Chris@217
|
2628 }
|
Chris@217
|
2629
|
Chris@217
|
2630 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
Chris@217
|
2631
|
Chris@217
|
2632 QTextStream out(&bzFile);
|
Chris@432
|
2633 out.setCodec(QTextCodec::codecForName("UTF-8"));
|
Chris@226
|
2634 toXml(out, false);
|
Chris@217
|
2635 out.flush();
|
Chris@217
|
2636
|
Chris@217
|
2637 QApplication::restoreOverrideCursor();
|
Chris@217
|
2638
|
Chris@217
|
2639 if (!bzFile.isOK()) {
|
Chris@217
|
2640 QMessageBox::critical(this, tr("Failed to write file"),
|
Chris@217
|
2641 tr("<b>Save failed</b><p>Failed to write to file \"%1\": %2")
|
Chris@217
|
2642 .arg(path).arg(bzFile.errorString()));
|
Chris@217
|
2643 bzFile.close();
|
Chris@217
|
2644 return false;
|
Chris@217
|
2645 }
|
Chris@217
|
2646
|
Chris@217
|
2647 bzFile.close();
|
Chris@217
|
2648 temp.moveToTarget();
|
Chris@217
|
2649 return true;
|
Chris@217
|
2650
|
Chris@217
|
2651 } catch (FileOperationFailed &f) {
|
Chris@217
|
2652
|
Chris@217
|
2653 QMessageBox::critical(this, tr("Failed to write file"),
|
Chris@217
|
2654 tr("<b>Save failed</b><p>Failed to write to file \"%1\": %2")
|
Chris@217
|
2655 .arg(path).arg(f.what()));
|
Chris@45
|
2656 return false;
|
Chris@45
|
2657 }
|
Chris@45
|
2658 }
|
Chris@45
|
2659
|
Chris@224
|
2660 bool
|
Chris@224
|
2661 MainWindowBase::saveSessionTemplate(QString path)
|
Chris@224
|
2662 {
|
Chris@224
|
2663 try {
|
Chris@224
|
2664
|
Chris@224
|
2665 TempWriteFile temp(path);
|
Chris@224
|
2666
|
Chris@224
|
2667 QFile file(temp.getTemporaryFilename());
|
Chris@224
|
2668 if (!file.open(QIODevice::WriteOnly)) {
|
Chris@293
|
2669 cerr << "Failed to open session template file \""
|
Chris@294
|
2670 << temp.getTemporaryFilename()
|
Chris@224
|
2671 << "\" for writing: "
|
Chris@294
|
2672 << file.errorString() << endl;
|
Chris@224
|
2673 return false;
|
Chris@224
|
2674 }
|
Chris@224
|
2675
|
Chris@224
|
2676 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
Chris@224
|
2677
|
Chris@224
|
2678 QTextStream out(&file);
|
Chris@432
|
2679 out.setCodec(QTextCodec::codecForName("UTF-8"));
|
Chris@226
|
2680 toXml(out, true);
|
Chris@224
|
2681 out.flush();
|
Chris@224
|
2682
|
Chris@224
|
2683 QApplication::restoreOverrideCursor();
|
Chris@224
|
2684
|
Chris@224
|
2685 file.close();
|
Chris@224
|
2686 temp.moveToTarget();
|
Chris@224
|
2687 return true;
|
Chris@224
|
2688
|
Chris@224
|
2689 } catch (FileOperationFailed &f) {
|
Chris@224
|
2690
|
Chris@224
|
2691 QMessageBox::critical(this, tr("Failed to write file"),
|
Chris@224
|
2692 tr("<b>Save failed</b><p>Failed to write to file \"%1\": %2")
|
Chris@224
|
2693 .arg(path).arg(f.what()));
|
Chris@224
|
2694 return false;
|
Chris@224
|
2695 }
|
Chris@224
|
2696 }
|
Chris@224
|
2697
|
Chris@45
|
2698 void
|
Chris@226
|
2699 MainWindowBase::toXml(QTextStream &out, bool asTemplate)
|
Chris@45
|
2700 {
|
Chris@45
|
2701 QString indent(" ");
|
Chris@45
|
2702
|
Chris@45
|
2703 out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
Chris@45
|
2704 out << "<!DOCTYPE sonic-visualiser>\n";
|
Chris@45
|
2705 out << "<sv>\n";
|
Chris@45
|
2706
|
Chris@226
|
2707 if (asTemplate) {
|
Chris@226
|
2708 m_document->toXmlAsTemplate(out, "", "");
|
Chris@226
|
2709 } else {
|
Chris@226
|
2710 m_document->toXml(out, "", "");
|
Chris@226
|
2711 }
|
Chris@45
|
2712
|
Chris@45
|
2713 out << "<display>\n";
|
Chris@45
|
2714
|
Chris@45
|
2715 out << QString(" <window width=\"%1\" height=\"%2\"/>\n")
|
Chris@595
|
2716 .arg(width()).arg(height());
|
Chris@45
|
2717
|
Chris@45
|
2718 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@45
|
2719
|
Chris@595
|
2720 Pane *pane = m_paneStack->getPane(i);
|
Chris@595
|
2721
|
Chris@595
|
2722 if (pane) {
|
Chris@45
|
2723 pane->toXml(out, indent);
|
Chris@595
|
2724 }
|
Chris@45
|
2725 }
|
Chris@45
|
2726
|
Chris@45
|
2727 out << "</display>\n";
|
Chris@45
|
2728
|
Chris@45
|
2729 m_viewManager->getSelection().toXml(out);
|
Chris@45
|
2730
|
Chris@45
|
2731 out << "</sv>\n";
|
Chris@45
|
2732 }
|
Chris@45
|
2733
|
Chris@45
|
2734 Pane *
|
Chris@45
|
2735 MainWindowBase::addPaneToStack()
|
Chris@45
|
2736 {
|
Chris@342
|
2737 cerr << "MainWindowBase::addPaneToStack()" << endl;
|
Chris@45
|
2738 AddPaneCommand *command = new AddPaneCommand(this);
|
Chris@45
|
2739 CommandHistory::getInstance()->addCommand(command);
|
Chris@57
|
2740 Pane *pane = command->getPane();
|
Chris@57
|
2741 return pane;
|
Chris@45
|
2742 }
|
Chris@45
|
2743
|
Chris@45
|
2744 void
|
Chris@45
|
2745 MainWindowBase::zoomIn()
|
Chris@45
|
2746 {
|
Chris@45
|
2747 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@45
|
2748 if (currentPane) currentPane->zoom(true);
|
Chris@45
|
2749 }
|
Chris@45
|
2750
|
Chris@45
|
2751 void
|
Chris@45
|
2752 MainWindowBase::zoomOut()
|
Chris@45
|
2753 {
|
Chris@45
|
2754 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@45
|
2755 if (currentPane) currentPane->zoom(false);
|
Chris@45
|
2756 }
|
Chris@45
|
2757
|
Chris@45
|
2758 void
|
Chris@45
|
2759 MainWindowBase::zoomToFit()
|
Chris@45
|
2760 {
|
Chris@45
|
2761 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@45
|
2762 if (!currentPane) return;
|
Chris@45
|
2763
|
Chris@45
|
2764 Model *model = getMainModel();
|
Chris@45
|
2765 if (!model) return;
|
Chris@45
|
2766
|
Chris@434
|
2767 sv_frame_t start = model->getStartFrame();
|
Chris@434
|
2768 sv_frame_t end = model->getEndFrame();
|
Chris@60
|
2769 if (m_playSource) end = std::max(end, m_playSource->getPlayEndFrame());
|
Chris@366
|
2770 int pixels = currentPane->width();
|
Chris@366
|
2771
|
Chris@366
|
2772 int sw = currentPane->getVerticalScaleWidth();
|
Chris@45
|
2773 if (pixels > sw * 2) pixels -= sw * 2;
|
Chris@45
|
2774 else pixels = 1;
|
Chris@45
|
2775 if (pixels > 4) pixels -= 4;
|
Chris@45
|
2776
|
Chris@436
|
2777 int zoomLevel = int((end - start) / pixels);
|
Chris@150
|
2778 if (zoomLevel < 1) zoomLevel = 1;
|
Chris@45
|
2779
|
Chris@45
|
2780 currentPane->setZoomLevel(zoomLevel);
|
Chris@45
|
2781 currentPane->setCentreFrame((start + end) / 2);
|
Chris@45
|
2782 }
|
Chris@45
|
2783
|
Chris@45
|
2784 void
|
Chris@45
|
2785 MainWindowBase::zoomDefault()
|
Chris@45
|
2786 {
|
Chris@45
|
2787 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@302
|
2788 QSettings settings;
|
Chris@302
|
2789 settings.beginGroup("MainWindow");
|
Chris@302
|
2790 int zoom = settings.value("zoom-default", 1024).toInt();
|
Chris@302
|
2791 settings.endGroup();
|
Chris@302
|
2792 if (currentPane) currentPane->setZoomLevel(zoom);
|
Chris@45
|
2793 }
|
Chris@45
|
2794
|
Chris@45
|
2795 void
|
Chris@45
|
2796 MainWindowBase::scrollLeft()
|
Chris@45
|
2797 {
|
Chris@45
|
2798 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@45
|
2799 if (currentPane) currentPane->scroll(false, false);
|
Chris@45
|
2800 }
|
Chris@45
|
2801
|
Chris@45
|
2802 void
|
Chris@45
|
2803 MainWindowBase::jumpLeft()
|
Chris@45
|
2804 {
|
Chris@45
|
2805 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@45
|
2806 if (currentPane) currentPane->scroll(false, true);
|
Chris@45
|
2807 }
|
Chris@45
|
2808
|
Chris@45
|
2809 void
|
Chris@162
|
2810 MainWindowBase::peekLeft()
|
Chris@162
|
2811 {
|
Chris@162
|
2812 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@162
|
2813 if (currentPane) currentPane->scroll(false, false, false);
|
Chris@162
|
2814 }
|
Chris@162
|
2815
|
Chris@162
|
2816 void
|
Chris@45
|
2817 MainWindowBase::scrollRight()
|
Chris@45
|
2818 {
|
Chris@45
|
2819 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@45
|
2820 if (currentPane) currentPane->scroll(true, false);
|
Chris@45
|
2821 }
|
Chris@45
|
2822
|
Chris@45
|
2823 void
|
Chris@45
|
2824 MainWindowBase::jumpRight()
|
Chris@45
|
2825 {
|
Chris@45
|
2826 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@45
|
2827 if (currentPane) currentPane->scroll(true, true);
|
Chris@45
|
2828 }
|
Chris@45
|
2829
|
Chris@45
|
2830 void
|
Chris@162
|
2831 MainWindowBase::peekRight()
|
Chris@162
|
2832 {
|
Chris@162
|
2833 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@162
|
2834 if (currentPane) currentPane->scroll(true, false, false);
|
Chris@162
|
2835 }
|
Chris@162
|
2836
|
Chris@162
|
2837 void
|
Chris@45
|
2838 MainWindowBase::showNoOverlays()
|
Chris@45
|
2839 {
|
Chris@45
|
2840 m_viewManager->setOverlayMode(ViewManager::NoOverlays);
|
Chris@45
|
2841 }
|
Chris@45
|
2842
|
Chris@45
|
2843 void
|
Chris@45
|
2844 MainWindowBase::showMinimalOverlays()
|
Chris@45
|
2845 {
|
Chris@335
|
2846 m_viewManager->setOverlayMode(ViewManager::StandardOverlays);
|
Chris@45
|
2847 }
|
Chris@45
|
2848
|
Chris@45
|
2849 void
|
Chris@45
|
2850 MainWindowBase::showAllOverlays()
|
Chris@45
|
2851 {
|
Chris@45
|
2852 m_viewManager->setOverlayMode(ViewManager::AllOverlays);
|
Chris@45
|
2853 }
|
Chris@45
|
2854
|
Chris@45
|
2855 void
|
Chris@577
|
2856 MainWindowBase::findTimeRulerLayer()
|
Chris@577
|
2857 {
|
Chris@577
|
2858 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@577
|
2859 Pane *pane = m_paneStack->getPane(i);
|
Chris@577
|
2860 if (!pane) continue;
|
Chris@577
|
2861 for (int j = 0; j < pane->getLayerCount(); ++j) {
|
Chris@577
|
2862 Layer *layer = pane->getLayer(j);
|
Chris@577
|
2863 if (!dynamic_cast<TimeRulerLayer *>(layer)) continue;
|
Chris@577
|
2864 m_timeRulerLayer = layer;
|
Chris@577
|
2865 return;
|
Chris@577
|
2866 }
|
Chris@577
|
2867 }
|
Chris@577
|
2868 if (m_timeRulerLayer) {
|
Chris@577
|
2869 SVCERR << "WARNING: Time ruler layer was not reset to 0 before session template loaded?" << endl;
|
Chris@577
|
2870 delete m_timeRulerLayer;
|
Chris@577
|
2871 m_timeRulerLayer = 0;
|
Chris@577
|
2872 }
|
Chris@577
|
2873 }
|
Chris@577
|
2874
|
Chris@577
|
2875 void
|
Chris@211
|
2876 MainWindowBase::toggleTimeRulers()
|
Chris@211
|
2877 {
|
Chris@211
|
2878 bool haveRulers = false;
|
Chris@211
|
2879 bool someHidden = false;
|
Chris@211
|
2880
|
Chris@211
|
2881 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@211
|
2882
|
Chris@211
|
2883 Pane *pane = m_paneStack->getPane(i);
|
Chris@211
|
2884 if (!pane) continue;
|
Chris@211
|
2885
|
Chris@211
|
2886 for (int j = 0; j < pane->getLayerCount(); ++j) {
|
Chris@211
|
2887
|
Chris@211
|
2888 Layer *layer = pane->getLayer(j);
|
Chris@211
|
2889 if (!dynamic_cast<TimeRulerLayer *>(layer)) continue;
|
Chris@211
|
2890
|
Chris@211
|
2891 haveRulers = true;
|
Chris@211
|
2892 if (layer->isLayerDormant(pane)) someHidden = true;
|
Chris@211
|
2893 }
|
Chris@211
|
2894 }
|
Chris@211
|
2895
|
Chris@211
|
2896 if (haveRulers) {
|
Chris@211
|
2897
|
Chris@211
|
2898 bool show = someHidden;
|
Chris@211
|
2899
|
Chris@211
|
2900 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@211
|
2901
|
Chris@211
|
2902 Pane *pane = m_paneStack->getPane(i);
|
Chris@211
|
2903 if (!pane) continue;
|
Chris@211
|
2904
|
Chris@211
|
2905 for (int j = 0; j < pane->getLayerCount(); ++j) {
|
Chris@211
|
2906
|
Chris@211
|
2907 Layer *layer = pane->getLayer(j);
|
Chris@211
|
2908 if (!dynamic_cast<TimeRulerLayer *>(layer)) continue;
|
Chris@211
|
2909
|
Chris@211
|
2910 layer->showLayer(pane, show);
|
Chris@211
|
2911 }
|
Chris@211
|
2912 }
|
Chris@211
|
2913 }
|
Chris@211
|
2914 }
|
Chris@211
|
2915
|
Chris@211
|
2916 void
|
Chris@45
|
2917 MainWindowBase::toggleZoomWheels()
|
Chris@45
|
2918 {
|
Chris@45
|
2919 if (m_viewManager->getZoomWheelsEnabled()) {
|
Chris@45
|
2920 m_viewManager->setZoomWheelsEnabled(false);
|
Chris@45
|
2921 } else {
|
Chris@45
|
2922 m_viewManager->setZoomWheelsEnabled(true);
|
Chris@45
|
2923 }
|
Chris@45
|
2924 }
|
Chris@45
|
2925
|
Chris@45
|
2926 void
|
Chris@45
|
2927 MainWindowBase::togglePropertyBoxes()
|
Chris@45
|
2928 {
|
Chris@45
|
2929 if (m_paneStack->getLayoutStyle() == PaneStack::NoPropertyStacks) {
|
Chris@45
|
2930 if (Preferences::getInstance()->getPropertyBoxLayout() ==
|
Chris@45
|
2931 Preferences::VerticallyStacked) {
|
Chris@45
|
2932 m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout);
|
Chris@45
|
2933 } else {
|
Chris@45
|
2934 m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout);
|
Chris@45
|
2935 }
|
Chris@45
|
2936 } else {
|
Chris@45
|
2937 m_paneStack->setLayoutStyle(PaneStack::NoPropertyStacks);
|
Chris@45
|
2938 }
|
Chris@45
|
2939 }
|
Chris@45
|
2940
|
Chris@378
|
2941 QLabel *
|
Chris@378
|
2942 MainWindowBase::getStatusLabel() const
|
Chris@378
|
2943 {
|
Chris@378
|
2944 if (!m_statusLabel) {
|
Chris@378
|
2945 m_statusLabel = new QLabel();
|
Chris@378
|
2946 statusBar()->addWidget(m_statusLabel, 1);
|
Chris@378
|
2947 }
|
Chris@379
|
2948
|
Chris@379
|
2949 QList<QFrame *> frames = statusBar()->findChildren<QFrame *>();
|
Chris@379
|
2950 foreach (QFrame *f, frames) {
|
Chris@379
|
2951 f->setFrameStyle(QFrame::NoFrame);
|
Chris@379
|
2952 }
|
Chris@379
|
2953
|
Chris@378
|
2954 return m_statusLabel;
|
Chris@378
|
2955 }
|
Chris@378
|
2956
|
Chris@45
|
2957 void
|
Chris@45
|
2958 MainWindowBase::toggleStatusBar()
|
Chris@45
|
2959 {
|
Chris@45
|
2960 QSettings settings;
|
Chris@45
|
2961 settings.beginGroup("MainWindow");
|
Chris@45
|
2962 bool sb = settings.value("showstatusbar", true).toBool();
|
Chris@45
|
2963
|
Chris@45
|
2964 if (sb) {
|
Chris@45
|
2965 statusBar()->hide();
|
Chris@45
|
2966 } else {
|
Chris@45
|
2967 statusBar()->show();
|
Chris@45
|
2968 }
|
Chris@45
|
2969
|
Chris@45
|
2970 settings.setValue("showstatusbar", !sb);
|
Chris@45
|
2971
|
Chris@45
|
2972 settings.endGroup();
|
Chris@45
|
2973 }
|
Chris@45
|
2974
|
Chris@45
|
2975 void
|
Chris@256
|
2976 MainWindowBase::toggleCentreLine()
|
Chris@256
|
2977 {
|
Chris@256
|
2978 if (m_viewManager->shouldShowCentreLine()) {
|
Chris@256
|
2979 m_viewManager->setShowCentreLine(false);
|
Chris@256
|
2980 } else {
|
Chris@256
|
2981 m_viewManager->setShowCentreLine(true);
|
Chris@256
|
2982 }
|
Chris@256
|
2983 }
|
Chris@256
|
2984
|
Chris@256
|
2985 void
|
Chris@45
|
2986 MainWindowBase::preferenceChanged(PropertyContainer::PropertyName name)
|
Chris@45
|
2987 {
|
Chris@45
|
2988 if (name == "Property Box Layout") {
|
Chris@45
|
2989 if (m_paneStack->getLayoutStyle() != PaneStack::NoPropertyStacks) {
|
Chris@45
|
2990 if (Preferences::getInstance()->getPropertyBoxLayout() ==
|
Chris@45
|
2991 Preferences::VerticallyStacked) {
|
Chris@45
|
2992 m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout);
|
Chris@45
|
2993 } else {
|
Chris@45
|
2994 m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout);
|
Chris@45
|
2995 }
|
Chris@45
|
2996 }
|
Chris@45
|
2997 } else if (name == "Background Mode" && m_viewManager) {
|
Chris@45
|
2998 Preferences::BackgroundMode mode =
|
Chris@45
|
2999 Preferences::getInstance()->getBackgroundMode();
|
Chris@45
|
3000 if (mode == Preferences::BackgroundFromTheme) {
|
Chris@45
|
3001 m_viewManager->setGlobalDarkBackground(m_initialDarkBackground);
|
Chris@45
|
3002 } else if (mode == Preferences::DarkBackground) {
|
Chris@45
|
3003 m_viewManager->setGlobalDarkBackground(true);
|
Chris@45
|
3004 } else {
|
Chris@45
|
3005 m_viewManager->setGlobalDarkBackground(false);
|
Chris@45
|
3006 }
|
Chris@45
|
3007 }
|
Chris@45
|
3008 }
|
Chris@45
|
3009
|
Chris@45
|
3010 void
|
Chris@45
|
3011 MainWindowBase::play()
|
Chris@45
|
3012 {
|
Chris@516
|
3013 if ((m_recordTarget && m_recordTarget->isRecording()) ||
|
Chris@516
|
3014 (m_playSource && m_playSource->isPlaying())) {
|
Chris@45
|
3015 stop();
|
Chris@479
|
3016 QAction *action = qobject_cast<QAction *>(sender());
|
Chris@479
|
3017 if (action) action->setChecked(false);
|
Chris@45
|
3018 } else {
|
Chris@487
|
3019 if (m_audioIO) m_audioIO->resume();
|
Chris@509
|
3020 else if (m_playTarget) m_playTarget->resume();
|
Chris@45
|
3021 playbackFrameChanged(m_viewManager->getPlaybackFrame());
|
Chris@595
|
3022 m_playSource->play(m_viewManager->getPlaybackFrame());
|
Chris@45
|
3023 }
|
Chris@45
|
3024 }
|
Chris@45
|
3025
|
Chris@45
|
3026 void
|
Chris@477
|
3027 MainWindowBase::record()
|
Chris@477
|
3028 {
|
Chris@586
|
3029 QAction *action = qobject_cast<QAction *>(sender());
|
Chris@586
|
3030
|
Chris@478
|
3031 if (!(m_soundOptions & WithAudioInput)) {
|
Chris@586
|
3032 if (action) action->setChecked(false);
|
Chris@478
|
3033 return;
|
Chris@478
|
3034 }
|
Chris@478
|
3035
|
Chris@477
|
3036 if (!m_recordTarget) {
|
Chris@586
|
3037 if (action) action->setChecked(false);
|
Chris@477
|
3038 return;
|
Chris@477
|
3039 }
|
Chris@477
|
3040
|
Chris@478
|
3041 if (!m_audioIO) {
|
Chris@611
|
3042 SVDEBUG << "MainWindowBase::record: about to create audio IO" << endl;
|
Chris@478
|
3043 createAudioIO();
|
Chris@478
|
3044 }
|
Chris@492
|
3045
|
Chris@492
|
3046 if (!m_audioIO) {
|
Chris@586
|
3047 if (!m_playTarget) {
|
Chris@586
|
3048 // Don't need to report this, createAudioIO should have
|
Chris@586
|
3049 if (action) action->setChecked(false);
|
Chris@586
|
3050 return;
|
Chris@586
|
3051 } else {
|
Chris@586
|
3052 // Need to report this: if the play target exists instead
|
Chris@586
|
3053 // of the audio IO, then that means we failed to open a
|
Chris@586
|
3054 // capture device. The record control should be disabled
|
Chris@586
|
3055 // in that situation, so if it happens here, that must
|
Chris@586
|
3056 // mean this is the first time we ever tried to open the
|
Chris@586
|
3057 // audio device, hence the need to report the problem here
|
Chris@586
|
3058 QMessageBox::critical
|
Chris@586
|
3059 (this, tr("No record device available"),
|
Chris@586
|
3060 tr("<b>No record device available</b><p>Failed to find or open an audio device for recording. Only playback will be available.</p>"));
|
Chris@586
|
3061 if (action) action->setChecked(false);
|
Chris@586
|
3062 updateMenuStates();
|
Chris@586
|
3063 return;
|
Chris@586
|
3064 }
|
Chris@492
|
3065 }
|
Chris@478
|
3066
|
Chris@477
|
3067 if (m_recordTarget->isRecording()) {
|
Chris@492
|
3068 stop();
|
Chris@477
|
3069 return;
|
Chris@477
|
3070 }
|
Chris@490
|
3071
|
Chris@483
|
3072 if (m_audioRecordMode == RecordReplaceSession) {
|
Chris@490
|
3073 if (!checkSaveModified()) {
|
Chris@490
|
3074 if (action) action->setChecked(false);
|
Chris@490
|
3075 return;
|
Chris@490
|
3076 }
|
Chris@483
|
3077 }
|
Chris@487
|
3078
|
Chris@557
|
3079 if (m_viewManager) m_viewManager->setGlobalCentreFrame(0);
|
Chris@557
|
3080
|
Chris@611
|
3081 SVCERR << "MainWindowBase::record: about to resume" << endl;
|
Chris@492
|
3082 m_audioIO->resume();
|
Chris@509
|
3083
|
Chris@477
|
3084 WritableWaveFileModel *model = m_recordTarget->startRecording();
|
Chris@477
|
3085 if (!model) {
|
Chris@586
|
3086 SVCERR << "ERROR: MainWindowBase::record: Recording failed" << endl;
|
Chris@586
|
3087 QMessageBox::critical
|
Chris@586
|
3088 (this, tr("Recording failed"),
|
Chris@586
|
3089 tr("<b>Recording failed</b><p>Failed to switch to record mode (some internal problem?)</p>"));
|
Chris@490
|
3090 if (action) action->setChecked(false);
|
Chris@477
|
3091 return;
|
Chris@477
|
3092 }
|
Chris@477
|
3093
|
Chris@477
|
3094 if (!model->isOK()) {
|
Chris@611
|
3095 SVCERR << "MainWindowBase::record: Model not OK, stopping and suspending" << endl;
|
Chris@477
|
3096 m_recordTarget->stopRecording();
|
Chris@492
|
3097 m_audioIO->suspend();
|
Chris@586
|
3098 if (action) action->setChecked(false);
|
Chris@477
|
3099 delete model;
|
Chris@477
|
3100 return;
|
Chris@477
|
3101 }
|
Chris@611
|
3102
|
Chris@611
|
3103 SVCERR << "MainWindowBase::record: Model is OK, continuing..." << endl;
|
Chris@487
|
3104
|
Chris@478
|
3105 PlayParameterRepository::getInstance()->addPlayable(model);
|
Chris@483
|
3106
|
Chris@483
|
3107 if (m_audioRecordMode == RecordReplaceSession || !getMainModel()) {
|
Chris@478
|
3108
|
Chris@479
|
3109 //!!! duplication with openAudio here
|
Chris@479
|
3110
|
Chris@479
|
3111 QString templateName = getDefaultSessionTemplate();
|
Chris@479
|
3112 bool loadedTemplate = false;
|
Chris@479
|
3113
|
Chris@479
|
3114 if (templateName != "") {
|
Chris@479
|
3115 FileOpenStatus tplStatus = openSessionTemplate(templateName);
|
Chris@479
|
3116 if (tplStatus == FileOpenCancelled) {
|
Chris@611
|
3117 SVCERR << "MainWindowBase::record: Session template open cancelled, stopping and suspending" << endl;
|
Chris@490
|
3118 m_recordTarget->stopRecording();
|
Chris@492
|
3119 m_audioIO->suspend();
|
Chris@490
|
3120 PlayParameterRepository::getInstance()->removePlayable(model);
|
Chris@479
|
3121 return;
|
Chris@479
|
3122 }
|
Chris@479
|
3123 if (tplStatus != FileOpenFailed) {
|
Chris@479
|
3124 loadedTemplate = true;
|
Chris@479
|
3125 }
|
Chris@479
|
3126 }
|
Chris@479
|
3127
|
Chris@479
|
3128 if (!loadedTemplate) {
|
Chris@479
|
3129 closeSession();
|
Chris@479
|
3130 createDocument();
|
Chris@479
|
3131 }
|
Chris@479
|
3132
|
Chris@479
|
3133 Model *prevMain = getMainModel();
|
Chris@479
|
3134 if (prevMain) {
|
Chris@479
|
3135 m_playSource->removeModel(prevMain);
|
Chris@479
|
3136 PlayParameterRepository::getInstance()->removePlayable(prevMain);
|
Chris@479
|
3137 }
|
Chris@479
|
3138
|
Chris@478
|
3139 m_document->setMainModel(model);
|
Chris@478
|
3140 setupMenus();
|
Chris@577
|
3141 findTimeRulerLayer();
|
Chris@478
|
3142
|
Chris@595
|
3143 if (loadedTemplate || (m_sessionFile == "")) {
|
Chris@479
|
3144 //!!! shouldn't be dealing directly with title from here -- call a method
|
Chris@595
|
3145 setWindowTitle(tr("%1: %2")
|
Chris@479
|
3146 .arg(QApplication::applicationName())
|
Chris@479
|
3147 .arg(model->getLocation()));
|
Chris@595
|
3148 CommandHistory::getInstance()->clear();
|
Chris@595
|
3149 CommandHistory::getInstance()->documentSaved();
|
Chris@595
|
3150 m_documentModified = false;
|
Chris@595
|
3151 } else {
|
Chris@595
|
3152 setWindowTitle(tr("%1: %2 [%3]")
|
Chris@479
|
3153 .arg(QApplication::applicationName())
|
Chris@595
|
3154 .arg(QFileInfo(m_sessionFile).fileName())
|
Chris@595
|
3155 .arg(model->getLocation()));
|
Chris@595
|
3156 if (m_documentModified) {
|
Chris@595
|
3157 m_documentModified = false;
|
Chris@595
|
3158 documentModified(); // so as to restore "(modified)" window title
|
Chris@595
|
3159 }
|
Chris@595
|
3160 }
|
Chris@479
|
3161
|
Chris@478
|
3162 } else {
|
Chris@478
|
3163
|
Chris@478
|
3164 CommandHistory::getInstance()->startCompoundOperation
|
Chris@478
|
3165 (tr("Import Recorded Audio"), true);
|
Chris@478
|
3166
|
Chris@478
|
3167 m_document->addImportedModel(model);
|
Chris@478
|
3168
|
Chris@478
|
3169 AddPaneCommand *command = new AddPaneCommand(this);
|
Chris@478
|
3170 CommandHistory::getInstance()->addCommand(command);
|
Chris@478
|
3171
|
Chris@478
|
3172 Pane *pane = command->getPane();
|
Chris@478
|
3173
|
Chris@478
|
3174 if (m_timeRulerLayer) {
|
Chris@478
|
3175 m_document->addLayerToView(pane, m_timeRulerLayer);
|
Chris@478
|
3176 }
|
Chris@478
|
3177
|
Chris@478
|
3178 Layer *newLayer = m_document->createImportedLayer(model);
|
Chris@478
|
3179
|
Chris@478
|
3180 if (newLayer) {
|
Chris@478
|
3181 m_document->addLayerToView(pane, newLayer);
|
Chris@478
|
3182 }
|
Chris@595
|
3183
|
Chris@478
|
3184 CommandHistory::getInstance()->endCompoundOperation();
|
Chris@477
|
3185 }
|
Chris@479
|
3186
|
Chris@479
|
3187 updateMenuStates();
|
Chris@479
|
3188 m_recentFiles.addFile(model->getLocation());
|
Chris@479
|
3189 currentPaneChanged(m_paneStack->getCurrentPane());
|
Chris@611
|
3190
|
Chris@496
|
3191 emit audioFileLoaded();
|
Chris@477
|
3192 }
|
Chris@477
|
3193
|
Chris@477
|
3194 void
|
Chris@45
|
3195 MainWindowBase::ffwd()
|
Chris@45
|
3196 {
|
Chris@45
|
3197 if (!getMainModel()) return;
|
Chris@45
|
3198
|
Chris@435
|
3199 sv_frame_t frame = m_viewManager->getPlaybackFrame();
|
Chris@45
|
3200 ++frame;
|
Chris@45
|
3201
|
Chris@85
|
3202 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@45
|
3203 Layer *layer = getSnapLayer();
|
Chris@435
|
3204 sv_samplerate_t sr = getMainModel()->getSampleRate();
|
Chris@45
|
3205
|
Chris@45
|
3206 if (!layer) {
|
Chris@45
|
3207
|
Chris@45
|
3208 frame = RealTime::realTime2Frame
|
Chris@357
|
3209 (RealTime::frame2RealTime(frame, sr) + m_defaultFfwdRwdStep, sr);
|
Chris@435
|
3210 if (frame > getMainModel()->getEndFrame()) {
|
Chris@45
|
3211 frame = getMainModel()->getEndFrame();
|
Chris@45
|
3212 }
|
Chris@45
|
3213
|
Chris@45
|
3214 } else {
|
Chris@45
|
3215
|
Chris@366
|
3216 int resolution = 0;
|
Chris@166
|
3217 if (pane) frame = pane->alignFromReference(frame);
|
Chris@85
|
3218 if (layer->snapToFeatureFrame(m_paneStack->getCurrentPane(),
|
Chris@85
|
3219 frame, resolution, Layer::SnapRight)) {
|
Chris@85
|
3220 if (pane) frame = pane->alignToReference(frame);
|
Chris@85
|
3221 } else {
|
Chris@45
|
3222 frame = getMainModel()->getEndFrame();
|
Chris@45
|
3223 }
|
Chris@45
|
3224 }
|
Chris@45
|
3225
|
Chris@45
|
3226 if (frame < 0) frame = 0;
|
Chris@45
|
3227
|
Chris@45
|
3228 if (m_viewManager->getPlaySelectionMode()) {
|
Chris@435
|
3229 frame = m_viewManager->constrainFrameToSelection(frame);
|
Chris@45
|
3230 }
|
Chris@45
|
3231
|
Chris@45
|
3232 m_viewManager->setPlaybackFrame(frame);
|
Chris@166
|
3233
|
Chris@435
|
3234 if (frame == getMainModel()->getEndFrame() &&
|
Chris@166
|
3235 m_playSource &&
|
Chris@166
|
3236 m_playSource->isPlaying() &&
|
Chris@166
|
3237 !m_viewManager->getPlayLoopMode()) {
|
Chris@166
|
3238 stop();
|
Chris@166
|
3239 }
|
Chris@45
|
3240 }
|
Chris@45
|
3241
|
Chris@45
|
3242 void
|
Chris@45
|
3243 MainWindowBase::ffwdEnd()
|
Chris@45
|
3244 {
|
Chris@45
|
3245 if (!getMainModel()) return;
|
Chris@45
|
3246
|
Chris@139
|
3247 if (m_playSource &&
|
Chris@139
|
3248 m_playSource->isPlaying() &&
|
Chris@139
|
3249 !m_viewManager->getPlayLoopMode()) {
|
Chris@139
|
3250 stop();
|
Chris@139
|
3251 }
|
Chris@139
|
3252
|
Chris@435
|
3253 sv_frame_t frame = getMainModel()->getEndFrame();
|
Chris@45
|
3254
|
Chris@45
|
3255 if (m_viewManager->getPlaySelectionMode()) {
|
Chris@45
|
3256 frame = m_viewManager->constrainFrameToSelection(frame);
|
Chris@45
|
3257 }
|
Chris@45
|
3258
|
Chris@45
|
3259 m_viewManager->setPlaybackFrame(frame);
|
Chris@45
|
3260 }
|
Chris@45
|
3261
|
Chris@45
|
3262 void
|
Chris@166
|
3263 MainWindowBase::ffwdSimilar()
|
Chris@166
|
3264 {
|
Chris@166
|
3265 if (!getMainModel()) return;
|
Chris@166
|
3266
|
Chris@166
|
3267 Layer *layer = getSnapLayer();
|
Chris@166
|
3268 if (!layer) { ffwd(); return; }
|
Chris@166
|
3269
|
Chris@166
|
3270 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@435
|
3271 sv_frame_t frame = m_viewManager->getPlaybackFrame();
|
Chris@166
|
3272
|
Chris@366
|
3273 int resolution = 0;
|
Chris@166
|
3274 if (pane) frame = pane->alignFromReference(frame);
|
Chris@166
|
3275 if (layer->snapToSimilarFeature(m_paneStack->getCurrentPane(),
|
Chris@166
|
3276 frame, resolution, Layer::SnapRight)) {
|
Chris@166
|
3277 if (pane) frame = pane->alignToReference(frame);
|
Chris@166
|
3278 } else {
|
Chris@166
|
3279 frame = getMainModel()->getEndFrame();
|
Chris@166
|
3280 }
|
Chris@166
|
3281
|
Chris@166
|
3282 if (frame < 0) frame = 0;
|
Chris@166
|
3283
|
Chris@166
|
3284 if (m_viewManager->getPlaySelectionMode()) {
|
Chris@435
|
3285 frame = m_viewManager->constrainFrameToSelection(frame);
|
Chris@166
|
3286 }
|
Chris@166
|
3287
|
Chris@166
|
3288 m_viewManager->setPlaybackFrame(frame);
|
Chris@166
|
3289
|
Chris@435
|
3290 if (frame == getMainModel()->getEndFrame() &&
|
Chris@166
|
3291 m_playSource &&
|
Chris@166
|
3292 m_playSource->isPlaying() &&
|
Chris@166
|
3293 !m_viewManager->getPlayLoopMode()) {
|
Chris@166
|
3294 stop();
|
Chris@166
|
3295 }
|
Chris@166
|
3296 }
|
Chris@166
|
3297
|
Chris@166
|
3298 void
|
Chris@45
|
3299 MainWindowBase::rewind()
|
Chris@45
|
3300 {
|
Chris@45
|
3301 if (!getMainModel()) return;
|
Chris@45
|
3302
|
Chris@435
|
3303 sv_frame_t frame = m_viewManager->getPlaybackFrame();
|
Chris@45
|
3304 if (frame > 0) --frame;
|
Chris@45
|
3305
|
Chris@85
|
3306 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@45
|
3307 Layer *layer = getSnapLayer();
|
Chris@435
|
3308 sv_samplerate_t sr = getMainModel()->getSampleRate();
|
Chris@45
|
3309
|
Chris@45
|
3310 // when rewinding during playback, we want to allow a period
|
Chris@45
|
3311 // following a rewind target point at which the rewind will go to
|
Chris@45
|
3312 // the prior point instead of the immediately neighbouring one
|
Chris@45
|
3313 if (m_playSource && m_playSource->isPlaying()) {
|
Chris@45
|
3314 RealTime ct = RealTime::frame2RealTime(frame, sr);
|
Chris@357
|
3315 ct = ct - RealTime::fromSeconds(0.15);
|
Chris@45
|
3316 if (ct < RealTime::zeroTime) ct = RealTime::zeroTime;
|
Chris@45
|
3317 frame = RealTime::realTime2Frame(ct, sr);
|
Chris@45
|
3318 }
|
Chris@45
|
3319
|
Chris@45
|
3320 if (!layer) {
|
Chris@45
|
3321
|
Chris@45
|
3322 frame = RealTime::realTime2Frame
|
Chris@357
|
3323 (RealTime::frame2RealTime(frame, sr) - m_defaultFfwdRwdStep, sr);
|
Chris@435
|
3324 if (frame < getMainModel()->getStartFrame()) {
|
Chris@45
|
3325 frame = getMainModel()->getStartFrame();
|
Chris@45
|
3326 }
|
Chris@45
|
3327
|
Chris@45
|
3328 } else {
|
Chris@45
|
3329
|
Chris@366
|
3330 int resolution = 0;
|
Chris@166
|
3331 if (pane) frame = pane->alignFromReference(frame);
|
Chris@85
|
3332 if (layer->snapToFeatureFrame(m_paneStack->getCurrentPane(),
|
Chris@85
|
3333 frame, resolution, Layer::SnapLeft)) {
|
Chris@85
|
3334 if (pane) frame = pane->alignToReference(frame);
|
Chris@85
|
3335 } else {
|
Chris@45
|
3336 frame = getMainModel()->getStartFrame();
|
Chris@45
|
3337 }
|
Chris@45
|
3338 }
|
Chris@45
|
3339
|
Chris@45
|
3340 if (frame < 0) frame = 0;
|
Chris@45
|
3341
|
Chris@45
|
3342 if (m_viewManager->getPlaySelectionMode()) {
|
Chris@435
|
3343 frame = m_viewManager->constrainFrameToSelection(frame);
|
Chris@45
|
3344 }
|
Chris@45
|
3345
|
Chris@45
|
3346 m_viewManager->setPlaybackFrame(frame);
|
Chris@45
|
3347 }
|
Chris@45
|
3348
|
Chris@45
|
3349 void
|
Chris@45
|
3350 MainWindowBase::rewindStart()
|
Chris@45
|
3351 {
|
Chris@45
|
3352 if (!getMainModel()) return;
|
Chris@45
|
3353
|
Chris@435
|
3354 sv_frame_t frame = getMainModel()->getStartFrame();
|
Chris@45
|
3355
|
Chris@45
|
3356 if (m_viewManager->getPlaySelectionMode()) {
|
Chris@45
|
3357 frame = m_viewManager->constrainFrameToSelection(frame);
|
Chris@45
|
3358 }
|
Chris@45
|
3359
|
Chris@45
|
3360 m_viewManager->setPlaybackFrame(frame);
|
Chris@45
|
3361 }
|
Chris@45
|
3362
|
Chris@166
|
3363 void
|
Chris@166
|
3364 MainWindowBase::rewindSimilar()
|
Chris@166
|
3365 {
|
Chris@166
|
3366 if (!getMainModel()) return;
|
Chris@166
|
3367
|
Chris@166
|
3368 Layer *layer = getSnapLayer();
|
Chris@166
|
3369 if (!layer) { rewind(); return; }
|
Chris@166
|
3370
|
Chris@166
|
3371 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@435
|
3372 sv_frame_t frame = m_viewManager->getPlaybackFrame();
|
Chris@166
|
3373
|
Chris@366
|
3374 int resolution = 0;
|
Chris@166
|
3375 if (pane) frame = pane->alignFromReference(frame);
|
Chris@166
|
3376 if (layer->snapToSimilarFeature(m_paneStack->getCurrentPane(),
|
Chris@166
|
3377 frame, resolution, Layer::SnapLeft)) {
|
Chris@166
|
3378 if (pane) frame = pane->alignToReference(frame);
|
Chris@166
|
3379 } else {
|
Chris@166
|
3380 frame = getMainModel()->getStartFrame();
|
Chris@166
|
3381 }
|
Chris@166
|
3382
|
Chris@166
|
3383 if (frame < 0) frame = 0;
|
Chris@166
|
3384
|
Chris@166
|
3385 if (m_viewManager->getPlaySelectionMode()) {
|
Chris@435
|
3386 frame = m_viewManager->constrainFrameToSelection(frame);
|
Chris@166
|
3387 }
|
Chris@166
|
3388
|
Chris@166
|
3389 m_viewManager->setPlaybackFrame(frame);
|
Chris@166
|
3390 }
|
Chris@166
|
3391
|
Chris@45
|
3392 Layer *
|
Chris@45
|
3393 MainWindowBase::getSnapLayer() const
|
Chris@45
|
3394 {
|
Chris@45
|
3395 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@45
|
3396 if (!pane) return 0;
|
Chris@45
|
3397
|
Chris@45
|
3398 Layer *layer = pane->getSelectedLayer();
|
Chris@45
|
3399
|
Chris@45
|
3400 if (!dynamic_cast<TimeInstantLayer *>(layer) &&
|
Chris@45
|
3401 !dynamic_cast<TimeValueLayer *>(layer) &&
|
Chris@194
|
3402 !dynamic_cast<RegionLayer *>(layer) &&
|
Chris@45
|
3403 !dynamic_cast<TimeRulerLayer *>(layer)) {
|
Chris@45
|
3404
|
Chris@45
|
3405 layer = 0;
|
Chris@45
|
3406
|
Chris@45
|
3407 for (int i = pane->getLayerCount(); i > 0; --i) {
|
Chris@45
|
3408 Layer *l = pane->getLayer(i-1);
|
Chris@45
|
3409 if (dynamic_cast<TimeRulerLayer *>(l)) {
|
Chris@45
|
3410 layer = l;
|
Chris@45
|
3411 break;
|
Chris@45
|
3412 }
|
Chris@45
|
3413 }
|
Chris@45
|
3414 }
|
Chris@45
|
3415
|
Chris@45
|
3416 return layer;
|
Chris@45
|
3417 }
|
Chris@45
|
3418
|
Chris@45
|
3419 void
|
Chris@45
|
3420 MainWindowBase::stop()
|
Chris@45
|
3421 {
|
Chris@516
|
3422 if (m_recordTarget &&
|
Chris@516
|
3423 m_recordTarget->isRecording()) {
|
Chris@477
|
3424 m_recordTarget->stopRecording();
|
Chris@477
|
3425 }
|
Chris@516
|
3426
|
Chris@516
|
3427 if (!m_playSource) return;
|
Chris@516
|
3428
|
Chris@45
|
3429 m_playSource->stop();
|
Chris@45
|
3430
|
Chris@611
|
3431 SVCERR << "MainWindowBase::stop: suspending" << endl;
|
Chris@611
|
3432
|
Chris@487
|
3433 if (m_audioIO) m_audioIO->suspend();
|
Chris@509
|
3434 else if (m_playTarget) m_playTarget->suspend();
|
Chris@487
|
3435
|
Chris@45
|
3436 if (m_paneStack && m_paneStack->getCurrentPane()) {
|
Chris@45
|
3437 updateVisibleRangeDisplay(m_paneStack->getCurrentPane());
|
Chris@45
|
3438 } else {
|
Chris@45
|
3439 m_myStatusMessage = "";
|
Chris@378
|
3440 getStatusLabel()->setText("");
|
Chris@45
|
3441 }
|
Chris@45
|
3442 }
|
Chris@45
|
3443
|
Chris@45
|
3444 MainWindowBase::AddPaneCommand::AddPaneCommand(MainWindowBase *mw) :
|
Chris@45
|
3445 m_mw(mw),
|
Chris@45
|
3446 m_pane(0),
|
Chris@45
|
3447 m_prevCurrentPane(0),
|
Chris@45
|
3448 m_added(false)
|
Chris@45
|
3449 {
|
Chris@45
|
3450 }
|
Chris@45
|
3451
|
Chris@45
|
3452 MainWindowBase::AddPaneCommand::~AddPaneCommand()
|
Chris@45
|
3453 {
|
Chris@45
|
3454 if (m_pane && !m_added) {
|
Chris@595
|
3455 m_mw->m_paneStack->deletePane(m_pane);
|
Chris@45
|
3456 }
|
Chris@45
|
3457 }
|
Chris@45
|
3458
|
Chris@45
|
3459 QString
|
Chris@45
|
3460 MainWindowBase::AddPaneCommand::getName() const
|
Chris@45
|
3461 {
|
Chris@45
|
3462 return tr("Add Pane");
|
Chris@45
|
3463 }
|
Chris@45
|
3464
|
Chris@45
|
3465 void
|
Chris@45
|
3466 MainWindowBase::AddPaneCommand::execute()
|
Chris@45
|
3467 {
|
Chris@45
|
3468 if (!m_pane) {
|
Chris@595
|
3469 m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane();
|
Chris@595
|
3470 m_pane = m_mw->m_paneStack->addPane();
|
Chris@45
|
3471
|
Chris@45
|
3472 connect(m_pane, SIGNAL(contextHelpChanged(const QString &)),
|
Chris@45
|
3473 m_mw, SLOT(contextHelpChanged(const QString &)));
|
Chris@45
|
3474 } else {
|
Chris@595
|
3475 m_mw->m_paneStack->showPane(m_pane);
|
Chris@45
|
3476 }
|
Chris@45
|
3477
|
Chris@45
|
3478 m_mw->m_paneStack->setCurrentPane(m_pane);
|
Chris@45
|
3479 m_added = true;
|
Chris@45
|
3480 }
|
Chris@45
|
3481
|
Chris@45
|
3482 void
|
Chris@45
|
3483 MainWindowBase::AddPaneCommand::unexecute()
|
Chris@45
|
3484 {
|
Chris@45
|
3485 m_mw->m_paneStack->hidePane(m_pane);
|
Chris@45
|
3486 m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane);
|
Chris@45
|
3487 m_added = false;
|
Chris@45
|
3488 }
|
Chris@45
|
3489
|
Chris@45
|
3490 MainWindowBase::RemovePaneCommand::RemovePaneCommand(MainWindowBase *mw, Pane *pane) :
|
Chris@45
|
3491 m_mw(mw),
|
Chris@45
|
3492 m_pane(pane),
|
Chris@409
|
3493 m_prevCurrentPane(0),
|
Chris@45
|
3494 m_added(true)
|
Chris@45
|
3495 {
|
Chris@45
|
3496 }
|
Chris@45
|
3497
|
Chris@45
|
3498 MainWindowBase::RemovePaneCommand::~RemovePaneCommand()
|
Chris@45
|
3499 {
|
Chris@45
|
3500 if (m_pane && !m_added) {
|
Chris@595
|
3501 m_mw->m_paneStack->deletePane(m_pane);
|
Chris@45
|
3502 }
|
Chris@45
|
3503 }
|
Chris@45
|
3504
|
Chris@45
|
3505 QString
|
Chris@45
|
3506 MainWindowBase::RemovePaneCommand::getName() const
|
Chris@45
|
3507 {
|
Chris@45
|
3508 return tr("Remove Pane");
|
Chris@45
|
3509 }
|
Chris@45
|
3510
|
Chris@45
|
3511 void
|
Chris@45
|
3512 MainWindowBase::RemovePaneCommand::execute()
|
Chris@45
|
3513 {
|
Chris@45
|
3514 m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane();
|
Chris@45
|
3515 m_mw->m_paneStack->hidePane(m_pane);
|
Chris@45
|
3516 m_added = false;
|
Chris@45
|
3517 }
|
Chris@45
|
3518
|
Chris@45
|
3519 void
|
Chris@45
|
3520 MainWindowBase::RemovePaneCommand::unexecute()
|
Chris@45
|
3521 {
|
Chris@45
|
3522 m_mw->m_paneStack->showPane(m_pane);
|
Chris@45
|
3523 m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane);
|
Chris@45
|
3524 m_added = true;
|
Chris@45
|
3525 }
|
Chris@45
|
3526
|
Chris@45
|
3527 void
|
Chris@45
|
3528 MainWindowBase::deleteCurrentPane()
|
Chris@45
|
3529 {
|
Chris@45
|
3530 CommandHistory::getInstance()->startCompoundOperation
|
Chris@595
|
3531 (tr("Delete Pane"), true);
|
Chris@45
|
3532
|
Chris@45
|
3533 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@45
|
3534 if (pane) {
|
Chris@595
|
3535 while (pane->getLayerCount() > 0) {
|
Chris@595
|
3536 Layer *layer = pane->getLayer(0);
|
Chris@595
|
3537 if (layer) {
|
Chris@595
|
3538 m_document->removeLayerFromView(pane, layer);
|
Chris@595
|
3539 } else {
|
Chris@595
|
3540 break;
|
Chris@595
|
3541 }
|
Chris@595
|
3542 }
|
Chris@595
|
3543
|
Chris@595
|
3544 RemovePaneCommand *command = new RemovePaneCommand(this, pane);
|
Chris@595
|
3545 CommandHistory::getInstance()->addCommand(command);
|
Chris@45
|
3546 }
|
Chris@45
|
3547
|
Chris@45
|
3548 CommandHistory::getInstance()->endCompoundOperation();
|
Chris@45
|
3549
|
Chris@45
|
3550 updateMenuStates();
|
Chris@45
|
3551 }
|
Chris@45
|
3552
|
Chris@45
|
3553 void
|
Chris@45
|
3554 MainWindowBase::deleteCurrentLayer()
|
Chris@45
|
3555 {
|
Chris@45
|
3556 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@45
|
3557 if (pane) {
|
Chris@595
|
3558 Layer *layer = pane->getSelectedLayer();
|
Chris@595
|
3559 if (layer) {
|
Chris@595
|
3560 m_document->removeLayerFromView(pane, layer);
|
Chris@595
|
3561 }
|
Chris@45
|
3562 }
|
Chris@45
|
3563 updateMenuStates();
|
Chris@45
|
3564 }
|
Chris@45
|
3565
|
Chris@45
|
3566 void
|
Chris@123
|
3567 MainWindowBase::editCurrentLayer()
|
Chris@123
|
3568 {
|
Chris@123
|
3569 Layer *layer = 0;
|
Chris@123
|
3570 Pane *pane = m_paneStack->getCurrentPane();
|
Chris@123
|
3571 if (pane) layer = pane->getSelectedLayer();
|
Chris@123
|
3572 if (!layer) return;
|
Chris@123
|
3573
|
Chris@123
|
3574 Model *model = layer->getModel();
|
Chris@123
|
3575 if (!model) return;
|
Chris@123
|
3576
|
Chris@124
|
3577 TabularModel *tabular = dynamic_cast<TabularModel *>(model);
|
Chris@124
|
3578 if (!tabular) {
|
Chris@124
|
3579 //!!! how to prevent this function from being active if not
|
Chris@124
|
3580 //appropriate model type? or will we ultimately support
|
Chris@124
|
3581 //tabular display for all editable models?
|
Chris@233
|
3582 SVDEBUG << "NOTE: Not a tabular model" << endl;
|
Chris@124
|
3583 return;
|
Chris@124
|
3584 }
|
Chris@124
|
3585
|
Chris@123
|
3586 if (m_layerDataDialogMap.find(layer) != m_layerDataDialogMap.end()) {
|
Chris@126
|
3587 if (!m_layerDataDialogMap[layer].isNull()) {
|
Chris@126
|
3588 m_layerDataDialogMap[layer]->show();
|
Chris@126
|
3589 m_layerDataDialogMap[layer]->raise();
|
Chris@126
|
3590 return;
|
Chris@126
|
3591 }
|
Chris@123
|
3592 }
|
Chris@123
|
3593
|
Chris@125
|
3594 QString title = layer->getLayerPresentationName();
|
Chris@125
|
3595
|
Chris@125
|
3596 ModelDataTableDialog *dialog = new ModelDataTableDialog(tabular, title, this);
|
Chris@128
|
3597 dialog->setAttribute(Qt::WA_DeleteOnClose);
|
Chris@128
|
3598
|
Chris@128
|
3599 connectLayerEditDialog(dialog);
|
Chris@123
|
3600
|
Chris@128
|
3601 m_layerDataDialogMap[layer] = dialog;
|
Chris@128
|
3602 m_viewDataDialogMap[pane].insert(dialog);
|
Chris@128
|
3603
|
Chris@128
|
3604 dialog->show();
|
Chris@128
|
3605 }
|
Chris@128
|
3606
|
Chris@128
|
3607 void
|
Chris@128
|
3608 MainWindowBase::connectLayerEditDialog(ModelDataTableDialog *dialog)
|
Chris@128
|
3609 {
|
Chris@123
|
3610 connect(m_viewManager,
|
Chris@435
|
3611 SIGNAL(globalCentreFrameChanged(sv_frame_t)),
|
Chris@123
|
3612 dialog,
|
Chris@435
|
3613 SLOT(userScrolledToFrame(sv_frame_t)));
|
Chris@127
|
3614
|
Chris@127
|
3615 connect(m_viewManager,
|
Chris@435
|
3616 SIGNAL(playbackFrameChanged(sv_frame_t)),
|
Chris@127
|
3617 dialog,
|
Chris@435
|
3618 SLOT(playbackScrolledToFrame(sv_frame_t)));
|
Chris@127
|
3619
|
Chris@123
|
3620 connect(dialog,
|
Chris@435
|
3621 SIGNAL(scrollToFrame(sv_frame_t)),
|
Chris@123
|
3622 m_viewManager,
|
Chris@435
|
3623 SLOT(setGlobalCentreFrame(sv_frame_t)));
|
Chris@129
|
3624
|
Chris@129
|
3625 connect(dialog,
|
Chris@435
|
3626 SIGNAL(scrollToFrame(sv_frame_t)),
|
Chris@129
|
3627 m_viewManager,
|
Chris@435
|
3628 SLOT(setPlaybackFrame(sv_frame_t)));
|
Chris@128
|
3629 }
|
Chris@123
|
3630
|
Chris@123
|
3631 void
|
Chris@73
|
3632 MainWindowBase::previousPane()
|
Chris@73
|
3633 {
|
Chris@73
|
3634 if (!m_paneStack) return;
|
Chris@73
|
3635
|
Chris@73
|
3636 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@73
|
3637 if (!currentPane) return;
|
Chris@73
|
3638
|
Chris@73
|
3639 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@73
|
3640 if (m_paneStack->getPane(i) == currentPane) {
|
Chris@73
|
3641 if (i == 0) return;
|
Chris@73
|
3642 m_paneStack->setCurrentPane(m_paneStack->getPane(i-1));
|
Chris@73
|
3643 updateMenuStates();
|
Chris@73
|
3644 return;
|
Chris@73
|
3645 }
|
Chris@73
|
3646 }
|
Chris@73
|
3647 }
|
Chris@73
|
3648
|
Chris@73
|
3649 void
|
Chris@73
|
3650 MainWindowBase::nextPane()
|
Chris@73
|
3651 {
|
Chris@73
|
3652 if (!m_paneStack) return;
|
Chris@73
|
3653
|
Chris@73
|
3654 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@73
|
3655 if (!currentPane) return;
|
Chris@73
|
3656
|
Chris@73
|
3657 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@73
|
3658 if (m_paneStack->getPane(i) == currentPane) {
|
Chris@73
|
3659 if (i == m_paneStack->getPaneCount()-1) return;
|
Chris@73
|
3660 m_paneStack->setCurrentPane(m_paneStack->getPane(i+1));
|
Chris@73
|
3661 updateMenuStates();
|
Chris@73
|
3662 return;
|
Chris@73
|
3663 }
|
Chris@73
|
3664 }
|
Chris@73
|
3665 }
|
Chris@73
|
3666
|
Chris@73
|
3667 void
|
Chris@73
|
3668 MainWindowBase::previousLayer()
|
Chris@73
|
3669 {
|
Chris@73
|
3670 if (!m_paneStack) return;
|
Chris@73
|
3671
|
Chris@73
|
3672 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@73
|
3673 if (!currentPane) return;
|
Chris@73
|
3674
|
Chris@403
|
3675 int count = currentPane->getLayerCount();
|
Chris@403
|
3676 if (count == 0) return;
|
Chris@403
|
3677
|
Chris@73
|
3678 Layer *currentLayer = currentPane->getSelectedLayer();
|
Chris@403
|
3679
|
Chris@403
|
3680 if (!currentLayer) {
|
Chris@403
|
3681 // The pane itself is current
|
Chris@403
|
3682 m_paneStack->setCurrentLayer
|
Chris@403
|
3683 (currentPane, currentPane->getFixedOrderLayer(count-1));
|
Chris@403
|
3684 } else {
|
Chris@403
|
3685 for (int i = 0; i < count; ++i) {
|
Chris@403
|
3686 if (currentPane->getFixedOrderLayer(i) == currentLayer) {
|
Chris@403
|
3687 if (i == 0) {
|
Chris@403
|
3688 m_paneStack->setCurrentLayer
|
Chris@403
|
3689 (currentPane, 0); // pane
|
Chris@403
|
3690 } else {
|
Chris@403
|
3691 m_paneStack->setCurrentLayer
|
Chris@403
|
3692 (currentPane, currentPane->getFixedOrderLayer(i-1));
|
Chris@403
|
3693 }
|
Chris@403
|
3694 break;
|
Chris@403
|
3695 }
|
Chris@73
|
3696 }
|
Chris@73
|
3697 }
|
Chris@403
|
3698
|
Chris@403
|
3699 updateMenuStates();
|
Chris@73
|
3700 }
|
Chris@73
|
3701
|
Chris@73
|
3702 void
|
Chris@73
|
3703 MainWindowBase::nextLayer()
|
Chris@73
|
3704 {
|
Chris@73
|
3705 if (!m_paneStack) return;
|
Chris@73
|
3706
|
Chris@73
|
3707 Pane *currentPane = m_paneStack->getCurrentPane();
|
Chris@73
|
3708 if (!currentPane) return;
|
Chris@73
|
3709
|
Chris@403
|
3710 int count = currentPane->getLayerCount();
|
Chris@403
|
3711 if (count == 0) return;
|
Chris@403
|
3712
|
Chris@73
|
3713 Layer *currentLayer = currentPane->getSelectedLayer();
|
Chris@403
|
3714
|
Chris@403
|
3715 if (!currentLayer) {
|
Chris@403
|
3716 // The pane itself is current
|
Chris@403
|
3717 m_paneStack->setCurrentLayer
|
Chris@403
|
3718 (currentPane, currentPane->getFixedOrderLayer(0));
|
Chris@403
|
3719 } else {
|
Chris@403
|
3720 for (int i = 0; i < count; ++i) {
|
Chris@403
|
3721 if (currentPane->getFixedOrderLayer(i) == currentLayer) {
|
Chris@403
|
3722 if (i == currentPane->getLayerCount()-1) {
|
Chris@403
|
3723 m_paneStack->setCurrentLayer
|
Chris@403
|
3724 (currentPane, 0); // pane
|
Chris@403
|
3725 } else {
|
Chris@403
|
3726 m_paneStack->setCurrentLayer
|
Chris@403
|
3727 (currentPane, currentPane->getFixedOrderLayer(i+1));
|
Chris@403
|
3728 }
|
Chris@403
|
3729 break;
|
Chris@403
|
3730 }
|
Chris@73
|
3731 }
|
Chris@73
|
3732 }
|
Chris@403
|
3733
|
Chris@403
|
3734 updateMenuStates();
|
Chris@73
|
3735 }
|
Chris@73
|
3736
|
Chris@73
|
3737 void
|
Chris@435
|
3738 MainWindowBase::playbackFrameChanged(sv_frame_t frame)
|
Chris@45
|
3739 {
|
Chris@45
|
3740 if (!(m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
|
Chris@45
|
3741
|
Chris@187
|
3742 updatePositionStatusDisplays();
|
Chris@187
|
3743
|
Chris@45
|
3744 RealTime now = RealTime::frame2RealTime
|
Chris@45
|
3745 (frame, getMainModel()->getSampleRate());
|
Chris@45
|
3746
|
Chris@45
|
3747 if (now.sec == m_lastPlayStatusSec) return;
|
Chris@45
|
3748
|
Chris@45
|
3749 RealTime then = RealTime::frame2RealTime
|
Chris@45
|
3750 (m_playSource->getPlayEndFrame(), getMainModel()->getSampleRate());
|
Chris@45
|
3751
|
Chris@45
|
3752 QString nowStr;
|
Chris@45
|
3753 QString thenStr;
|
Chris@45
|
3754 QString remainingStr;
|
Chris@45
|
3755
|
Chris@45
|
3756 if (then.sec > 10) {
|
Chris@45
|
3757 nowStr = now.toSecText().c_str();
|
Chris@45
|
3758 thenStr = then.toSecText().c_str();
|
Chris@45
|
3759 remainingStr = (then - now).toSecText().c_str();
|
Chris@45
|
3760 m_lastPlayStatusSec = now.sec;
|
Chris@45
|
3761 } else {
|
Chris@45
|
3762 nowStr = now.toText(true).c_str();
|
Chris@45
|
3763 thenStr = then.toText(true).c_str();
|
Chris@45
|
3764 remainingStr = (then - now).toText(true).c_str();
|
Chris@45
|
3765 }
|
Chris@45
|
3766
|
Chris@45
|
3767 m_myStatusMessage = tr("Playing: %1 of %2 (%3 remaining)")
|
Chris@45
|
3768 .arg(nowStr).arg(thenStr).arg(remainingStr);
|
Chris@45
|
3769
|
Chris@378
|
3770 getStatusLabel()->setText(m_myStatusMessage);
|
Chris@45
|
3771 }
|
Chris@45
|
3772
|
Chris@45
|
3773 void
|
Chris@486
|
3774 MainWindowBase::recordDurationChanged(sv_frame_t frame, sv_samplerate_t rate)
|
Chris@486
|
3775 {
|
Chris@486
|
3776 RealTime duration = RealTime::frame2RealTime(frame, rate);
|
Chris@486
|
3777 QString durStr = duration.toSecText().c_str();
|
Chris@486
|
3778
|
Chris@486
|
3779 m_myStatusMessage = tr("Recording: %1").arg(durStr);
|
Chris@486
|
3780
|
Chris@486
|
3781 getStatusLabel()->setText(m_myStatusMessage);
|
Chris@486
|
3782 }
|
Chris@486
|
3783
|
Chris@486
|
3784 void
|
Chris@435
|
3785 MainWindowBase::globalCentreFrameChanged(sv_frame_t )
|
Chris@45
|
3786 {
|
Chris@45
|
3787 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
|
Chris@45
|
3788 Pane *p = 0;
|
Chris@45
|
3789 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
|
Chris@45
|
3790 if (!p->getFollowGlobalPan()) return;
|
Chris@45
|
3791 updateVisibleRangeDisplay(p);
|
Chris@45
|
3792 }
|
Chris@45
|
3793
|
Chris@45
|
3794 void
|
Chris@435
|
3795 MainWindowBase::viewCentreFrameChanged(View *v, sv_frame_t frame)
|
Chris@45
|
3796 {
|
Chris@233
|
3797 // SVDEBUG << "MainWindowBase::viewCentreFrameChanged(" << v << "," << frame << ")" << endl;
|
Chris@123
|
3798
|
Chris@123
|
3799 if (m_viewDataDialogMap.find(v) != m_viewDataDialogMap.end()) {
|
Chris@123
|
3800 for (DataDialogSet::iterator i = m_viewDataDialogMap[v].begin();
|
Chris@123
|
3801 i != m_viewDataDialogMap[v].end(); ++i) {
|
Chris@127
|
3802 (*i)->userScrolledToFrame(frame);
|
Chris@123
|
3803 }
|
Chris@123
|
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@366
|
3812 MainWindowBase::viewZoomLevelChanged(View *v, int , bool )
|
Chris@45
|
3813 {
|
Chris@45
|
3814 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
|
Chris@45
|
3815 Pane *p = 0;
|
Chris@45
|
3816 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
|
Chris@45
|
3817 if (v == p) updateVisibleRangeDisplay(p);
|
Chris@45
|
3818 }
|
Chris@45
|
3819
|
Chris@45
|
3820 void
|
Chris@45
|
3821 MainWindowBase::layerAdded(Layer *)
|
Chris@45
|
3822 {
|
Chris@233
|
3823 // SVDEBUG << "MainWindowBase::layerAdded(" << layer << ")" << endl;
|
Chris@45
|
3824 updateMenuStates();
|
Chris@45
|
3825 }
|
Chris@45
|
3826
|
Chris@45
|
3827 void
|
Chris@45
|
3828 MainWindowBase::layerRemoved(Layer *)
|
Chris@45
|
3829 {
|
Chris@233
|
3830 // SVDEBUG << "MainWindowBase::layerRemoved(" << layer << ")" << endl;
|
Chris@45
|
3831 updateMenuStates();
|
Chris@45
|
3832 }
|
Chris@45
|
3833
|
Chris@45
|
3834 void
|
Chris@45
|
3835 MainWindowBase::layerAboutToBeDeleted(Layer *layer)
|
Chris@45
|
3836 {
|
Chris@233
|
3837 // SVDEBUG << "MainWindowBase::layerAboutToBeDeleted(" << layer << ")" << endl;
|
Chris@123
|
3838
|
Chris@128
|
3839 removeLayerEditDialog(layer);
|
Chris@123
|
3840
|
Chris@47
|
3841 if (m_timeRulerLayer && (layer == m_timeRulerLayer)) {
|
Chris@595
|
3842 // cerr << "(this is the time ruler layer)" << endl;
|
Chris@595
|
3843 m_timeRulerLayer = 0;
|
Chris@45
|
3844 }
|
Chris@45
|
3845 }
|
Chris@45
|
3846
|
Chris@45
|
3847 void
|
Chris@45
|
3848 MainWindowBase::layerInAView(Layer *layer, bool inAView)
|
Chris@45
|
3849 {
|
Chris@233
|
3850 // SVDEBUG << "MainWindowBase::layerInAView(" << layer << "," << inAView << ")" << endl;
|
Chris@128
|
3851
|
Chris@128
|
3852 if (!inAView) removeLayerEditDialog(layer);
|
Chris@45
|
3853
|
Chris@45
|
3854 // Check whether we need to add or remove model from play source
|
Chris@45
|
3855 Model *model = layer->getModel();
|
Chris@45
|
3856 if (model) {
|
Chris@45
|
3857 if (inAView) {
|
Chris@45
|
3858 m_playSource->addModel(model);
|
Chris@45
|
3859 } else {
|
Chris@45
|
3860 bool found = false;
|
Chris@45
|
3861 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@45
|
3862 Pane *pane = m_paneStack->getPane(i);
|
Chris@45
|
3863 if (!pane) continue;
|
Chris@45
|
3864 for (int j = 0; j < pane->getLayerCount(); ++j) {
|
Chris@45
|
3865 Layer *pl = pane->getLayer(j);
|
Chris@183
|
3866 if (pl &&
|
Chris@183
|
3867 !dynamic_cast<TimeRulerLayer *>(pl) &&
|
Chris@183
|
3868 (pl->getModel() == model)) {
|
Chris@45
|
3869 found = true;
|
Chris@45
|
3870 break;
|
Chris@45
|
3871 }
|
Chris@45
|
3872 }
|
Chris@45
|
3873 if (found) break;
|
Chris@45
|
3874 }
|
Chris@173
|
3875 if (!found) {
|
Chris@173
|
3876 m_playSource->removeModel(model);
|
Chris@173
|
3877 }
|
Chris@45
|
3878 }
|
Chris@45
|
3879 }
|
Chris@45
|
3880
|
Chris@45
|
3881 updateMenuStates();
|
Chris@45
|
3882 }
|
Chris@45
|
3883
|
Chris@45
|
3884 void
|
Chris@128
|
3885 MainWindowBase::removeLayerEditDialog(Layer *layer)
|
Chris@128
|
3886 {
|
Chris@128
|
3887 if (m_layerDataDialogMap.find(layer) != m_layerDataDialogMap.end()) {
|
Chris@128
|
3888
|
Chris@128
|
3889 ModelDataTableDialog *dialog = m_layerDataDialogMap[layer];
|
Chris@128
|
3890
|
Chris@128
|
3891 for (ViewDataDialogMap::iterator vi = m_viewDataDialogMap.begin();
|
Chris@128
|
3892 vi != m_viewDataDialogMap.end(); ++vi) {
|
Chris@128
|
3893 vi->second.erase(dialog);
|
Chris@128
|
3894 }
|
Chris@128
|
3895
|
Chris@128
|
3896 m_layerDataDialogMap.erase(layer);
|
Chris@128
|
3897 delete dialog;
|
Chris@128
|
3898 }
|
Chris@128
|
3899 }
|
Chris@128
|
3900
|
Chris@128
|
3901 void
|
Chris@45
|
3902 MainWindowBase::modelAdded(Model *model)
|
Chris@45
|
3903 {
|
Chris@233
|
3904 // SVDEBUG << "MainWindowBase::modelAdded(" << model << ")" << endl;
|
Chris@595
|
3905 std::cerr << "\nAdding model " << model->getTypeName() << " to playsource " << std::endl;
|
Chris@45
|
3906 m_playSource->addModel(model);
|
Chris@45
|
3907 }
|
Chris@45
|
3908
|
Chris@45
|
3909 void
|
Chris@45
|
3910 MainWindowBase::mainModelChanged(WaveFileModel *model)
|
Chris@45
|
3911 {
|
Chris@233
|
3912 // SVDEBUG << "MainWindowBase::mainModelChanged(" << model << ")" << endl;
|
Chris@45
|
3913 updateDescriptionLabel();
|
Chris@45
|
3914 if (model) m_viewManager->setMainModelSampleRate(model->getSampleRate());
|
Chris@475
|
3915 if (model && !(m_playTarget || m_audioIO) &&
|
Chris@475
|
3916 (m_soundOptions & WithAudioOutput)) {
|
Chris@475
|
3917 createAudioIO();
|
Chris@360
|
3918 }
|
Chris@45
|
3919 }
|
Chris@45
|
3920
|
Chris@45
|
3921 void
|
Chris@45
|
3922 MainWindowBase::modelAboutToBeDeleted(Model *model)
|
Chris@45
|
3923 {
|
Chris@233
|
3924 // SVDEBUG << "MainWindowBase::modelAboutToBeDeleted(" << model << ")" << endl;
|
Chris@45
|
3925 if (model == m_viewManager->getPlaybackModel()) {
|
Chris@45
|
3926 m_viewManager->setPlaybackModel(0);
|
Chris@45
|
3927 }
|
Chris@45
|
3928 m_playSource->removeModel(model);
|
Chris@45
|
3929 }
|
Chris@45
|
3930
|
Chris@45
|
3931 void
|
Chris@55
|
3932 MainWindowBase::paneDeleteButtonClicked(Pane *pane)
|
Chris@55
|
3933 {
|
Chris@55
|
3934 bool found = false;
|
Chris@55
|
3935 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
|
Chris@55
|
3936 if (m_paneStack->getPane(i) == pane) {
|
Chris@55
|
3937 found = true;
|
Chris@55
|
3938 break;
|
Chris@55
|
3939 }
|
Chris@55
|
3940 }
|
Chris@55
|
3941 if (!found) {
|
Chris@233
|
3942 SVDEBUG << "MainWindowBase::paneDeleteButtonClicked: Unknown pane "
|
Chris@229
|
3943 << pane << endl;
|
Chris@55
|
3944 return;
|
Chris@55
|
3945 }
|
Chris@55
|
3946
|
Chris@55
|
3947 CommandHistory::getInstance()->startCompoundOperation
|
Chris@595
|
3948 (tr("Delete Pane"), true);
|
Chris@55
|
3949
|
Chris@55
|
3950 while (pane->getLayerCount() > 0) {
|
Chris@55
|
3951 Layer *layer = pane->getLayer(0);
|
Chris@55
|
3952 if (layer) {
|
Chris@55
|
3953 m_document->removeLayerFromView(pane, layer);
|
Chris@55
|
3954 } else {
|
Chris@55
|
3955 break;
|
Chris@55
|
3956 }
|
Chris@55
|
3957 }
|
Chris@55
|
3958
|
Chris@55
|
3959 RemovePaneCommand *command = new RemovePaneCommand(this, pane);
|
Chris@55
|
3960 CommandHistory::getInstance()->addCommand(command);
|
Chris@55
|
3961
|
Chris@55
|
3962 CommandHistory::getInstance()->endCompoundOperation();
|
Chris@55
|
3963
|
Chris@55
|
3964 updateMenuStates();
|
Chris@55
|
3965 }
|
Chris@55
|
3966
|
Chris@55
|
3967 void
|
Chris@429
|
3968 MainWindowBase::alignmentComplete(AlignmentModel *model)
|
Chris@429
|
3969 {
|
Chris@429
|
3970 cerr << "MainWindowBase::alignmentComplete(" << model << ")" << endl;
|
Chris@429
|
3971 }
|
Chris@429
|
3972
|
Chris@429
|
3973 void
|
Chris@45
|
3974 MainWindowBase::pollOSC()
|
Chris@45
|
3975 {
|
Chris@45
|
3976 if (!m_oscQueue || m_oscQueue->isEmpty()) return;
|
Chris@233
|
3977 SVDEBUG << "MainWindowBase::pollOSC: have " << m_oscQueue->getMessagesAvailable() << " messages" << endl;
|
Chris@45
|
3978
|
Chris@45
|
3979 if (m_openingAudioFile) return;
|
Chris@45
|
3980
|
Chris@45
|
3981 OSCMessage message = m_oscQueue->readMessage();
|
Chris@45
|
3982
|
Chris@45
|
3983 if (message.getTarget() != 0) {
|
Chris@45
|
3984 return; //!!! for now -- this class is target 0, others not handled yet
|
Chris@45
|
3985 }
|
Chris@45
|
3986
|
Chris@45
|
3987 handleOSCMessage(message);
|
Chris@45
|
3988 }
|
Chris@45
|
3989
|
Chris@45
|
3990 void
|
Chris@45
|
3991 MainWindowBase::inProgressSelectionChanged()
|
Chris@45
|
3992 {
|
Chris@45
|
3993 Pane *currentPane = 0;
|
Chris@45
|
3994 if (m_paneStack) currentPane = m_paneStack->getCurrentPane();
|
justin@331
|
3995 if (currentPane) {
|
justin@331
|
3996 //cerr << "JTEST: mouse event on selection pane" << endl;
|
justin@331
|
3997 updateVisibleRangeDisplay(currentPane);
|
justin@331
|
3998 }
|
Chris@45
|
3999 }
|
Chris@45
|
4000
|
Chris@45
|
4001 void
|
Chris@45
|
4002 MainWindowBase::contextHelpChanged(const QString &s)
|
Chris@45
|
4003 {
|
Chris@378
|
4004 QLabel *lab = getStatusLabel();
|
Chris@375
|
4005
|
Chris@45
|
4006 if (s == "" && m_myStatusMessage != "") {
|
Chris@378
|
4007 if (lab->text() != m_myStatusMessage) {
|
Chris@378
|
4008 lab->setText(m_myStatusMessage);
|
Chris@375
|
4009 }
|
Chris@45
|
4010 return;
|
Chris@45
|
4011 }
|
Chris@375
|
4012
|
Chris@378
|
4013 lab->setText(s);
|
Chris@45
|
4014 }
|
Chris@45
|
4015
|
Chris@45
|
4016 void
|
Chris@45
|
4017 MainWindowBase::openHelpUrl(QString url)
|
Chris@45
|
4018 {
|
Chris@45
|
4019 // This method mostly lifted from Qt Assistant source code
|
Chris@45
|
4020
|
Chris@45
|
4021 QProcess *process = new QProcess(this);
|
Chris@45
|
4022 connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater()));
|
Chris@45
|
4023
|
Chris@45
|
4024 QStringList args;
|
Chris@45
|
4025
|
Chris@45
|
4026 #ifdef Q_OS_MAC
|
Chris@45
|
4027 args.append(url);
|
Chris@45
|
4028 process->start("open", args);
|
Chris@45
|
4029 #else
|
Chris@45
|
4030 #ifdef Q_OS_WIN32
|
Chris@599
|
4031 std::string pfiles;
|
Chris@599
|
4032 (void)getEnvUtf8("ProgramFiles", pfiles);
|
Chris@599
|
4033 QString command =
|
Chris@599
|
4034 QString::fromStdString(pfiles) +
|
Chris@599
|
4035 QString("\\Internet Explorer\\IEXPLORE.EXE");
|
Chris@358
|
4036
|
Chris@358
|
4037 args.append(url);
|
Chris@358
|
4038 process->start(command, args);
|
Chris@45
|
4039 #else
|
Chris@45
|
4040 if (!qgetenv("KDE_FULL_SESSION").isEmpty()) {
|
Chris@45
|
4041 args.append("exec");
|
Chris@45
|
4042 args.append(url);
|
Chris@45
|
4043 process->start("kfmclient", args);
|
Chris@45
|
4044 } else if (!qgetenv("BROWSER").isEmpty()) {
|
Chris@45
|
4045 args.append(url);
|
Chris@45
|
4046 process->start(qgetenv("BROWSER"), args);
|
Chris@45
|
4047 } else {
|
Chris@45
|
4048 args.append(url);
|
Chris@45
|
4049 process->start("firefox", args);
|
Chris@45
|
4050 }
|
Chris@45
|
4051 #endif
|
Chris@45
|
4052 #endif
|
Chris@45
|
4053 }
|
Chris@45
|
4054
|
Chris@483
|
4055 void
|
Chris@483
|
4056 MainWindowBase::openLocalFolder(QString path)
|
Chris@483
|
4057 {
|
Chris@483
|
4058 QDir d(path);
|
Chris@483
|
4059 if (d.exists()) {
|
Chris@483
|
4060 QStringList args;
|
Chris@483
|
4061 QString path = d.canonicalPath();
|
Chris@483
|
4062 #if defined Q_OS_WIN32
|
Chris@483
|
4063 // Although the Win32 API is quite happy to have
|
Chris@483
|
4064 // forward slashes as directory separators, Windows
|
Chris@483
|
4065 // Explorer is not
|
Chris@483
|
4066 path = path.replace('/', '\\');
|
Chris@483
|
4067 args << path;
|
Chris@483
|
4068 QProcess::execute("c:/windows/explorer.exe", args);
|
Chris@483
|
4069 #else
|
Chris@483
|
4070 args << path;
|
Chris@605
|
4071 QProcess process;
|
Chris@605
|
4072 QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
Chris@606
|
4073 env.insert("LD_LIBRARY_PATH", "");
|
Chris@605
|
4074 process.setProcessEnvironment(env);
|
Chris@605
|
4075 process.start(
|
Chris@483
|
4076 #if defined Q_OS_MAC
|
Chris@483
|
4077 "/usr/bin/open",
|
Chris@483
|
4078 #else
|
Chris@483
|
4079 "/usr/bin/xdg-open",
|
Chris@483
|
4080 #endif
|
Chris@483
|
4081 args);
|
Chris@608
|
4082 process.waitForFinished();
|
Chris@483
|
4083 #endif
|
Chris@483
|
4084 }
|
Chris@483
|
4085 }
|
Chris@483
|
4086
|