Mercurial > hg > svapp
comparison framework/MainWindowBase.cpp @ 45:9ea770d93fae
* document -> framework (will not compile, path fixes not in yet)
author | Chris Cannam |
---|---|
date | Wed, 24 Oct 2007 16:37:58 +0000 |
parents | |
children | 7fbe1c99d5d8 |
comparison
equal
deleted
inserted
replaced
44:9ebe12983f3e | 45:9ea770d93fae |
---|---|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ | |
2 | |
3 /* | |
4 Sonic Visualiser | |
5 An audio file viewer and annotation editor. | |
6 Centre for Digital Music, Queen Mary, University of London. | |
7 This file copyright 2006-2007 Chris Cannam and QMUL. | |
8 | |
9 This program is free software; you can redistribute it and/or | |
10 modify it under the terms of the GNU General Public License as | |
11 published by the Free Software Foundation; either version 2 of the | |
12 License, or (at your option) any later version. See the file | |
13 COPYING included with this distribution for more information. | |
14 */ | |
15 | |
16 #include "MainWindowBase.h" | |
17 #include "document/Document.h" | |
18 | |
19 | |
20 #include "view/Pane.h" | |
21 #include "view/PaneStack.h" | |
22 #include "data/model/WaveFileModel.h" | |
23 #include "data/model/SparseOneDimensionalModel.h" | |
24 #include "data/model/NoteModel.h" | |
25 #include "data/model/Labeller.h" | |
26 #include "view/ViewManager.h" | |
27 | |
28 #include "layer/WaveformLayer.h" | |
29 #include "layer/TimeRulerLayer.h" | |
30 #include "layer/TimeInstantLayer.h" | |
31 #include "layer/TimeValueLayer.h" | |
32 #include "layer/Colour3DPlotLayer.h" | |
33 #include "layer/SliceLayer.h" | |
34 #include "layer/SliceableLayer.h" | |
35 #include "layer/ImageLayer.h" | |
36 | |
37 #include "widgets/ListInputDialog.h" | |
38 | |
39 #include "audioio/AudioCallbackPlaySource.h" | |
40 #include "audioio/AudioCallbackPlayTarget.h" | |
41 #include "audioio/AudioTargetFactory.h" | |
42 #include "audioio/PlaySpeedRangeMapper.h" | |
43 #include "data/fileio/DataFileReaderFactory.h" | |
44 #include "data/fileio/PlaylistFileReader.h" | |
45 #include "data/fileio/WavFileWriter.h" | |
46 #include "data/fileio/CSVFileWriter.h" | |
47 #include "data/fileio/MIDIFileWriter.h" | |
48 #include "data/fileio/BZipFileDevice.h" | |
49 #include "data/fileio/FileSource.h" | |
50 | |
51 #include "data/fft/FFTDataServer.h" | |
52 | |
53 #include "base/RecentFiles.h" | |
54 | |
55 #include "base/PlayParameterRepository.h" | |
56 #include "base/XmlExportable.h" | |
57 #include "base/CommandHistory.h" | |
58 #include "base/Profiler.h" | |
59 #include "base/Preferences.h" | |
60 | |
61 #include "data/osc/OSCQueue.h" | |
62 | |
63 #include <QApplication> | |
64 #include <QMessageBox> | |
65 #include <QGridLayout> | |
66 #include <QLabel> | |
67 #include <QAction> | |
68 #include <QMenuBar> | |
69 #include <QToolBar> | |
70 #include <QInputDialog> | |
71 #include <QStatusBar> | |
72 #include <QTreeView> | |
73 #include <QFile> | |
74 #include <QFileInfo> | |
75 #include <QDir> | |
76 #include <QTextStream> | |
77 #include <QProcess> | |
78 #include <QShortcut> | |
79 #include <QSettings> | |
80 #include <QDateTime> | |
81 #include <QProcess> | |
82 #include <QCheckBox> | |
83 #include <QRegExp> | |
84 #include <QScrollArea> | |
85 | |
86 #include <iostream> | |
87 #include <cstdio> | |
88 #include <errno.h> | |
89 | |
90 using std::cerr; | |
91 using std::endl; | |
92 | |
93 using std::vector; | |
94 using std::map; | |
95 using std::set; | |
96 | |
97 | |
98 MainWindowBase::MainWindowBase(bool withAudioOutput, bool withOSCSupport) : | |
99 m_document(0), | |
100 m_paneStack(0), | |
101 m_viewManager(0), | |
102 m_timeRulerLayer(0), | |
103 m_audioOutput(withAudioOutput), | |
104 m_playSource(0), | |
105 m_playTarget(0), | |
106 m_oscQueue(withOSCSupport ? new OSCQueue() : 0), | |
107 m_recentFiles("RecentFiles", 20), | |
108 m_recentTransforms("RecentTransforms", 20), | |
109 m_documentModified(false), | |
110 m_openingAudioFile(false), | |
111 m_abandoning(false), | |
112 m_labeller(0) | |
113 { | |
114 connect(CommandHistory::getInstance(), SIGNAL(commandExecuted()), | |
115 this, SLOT(documentModified())); | |
116 connect(CommandHistory::getInstance(), SIGNAL(documentRestored()), | |
117 this, SLOT(documentRestored())); | |
118 | |
119 m_viewManager = new ViewManager(); | |
120 connect(m_viewManager, SIGNAL(selectionChanged()), | |
121 this, SLOT(updateMenuStates())); | |
122 connect(m_viewManager, SIGNAL(inProgressSelectionChanged()), | |
123 this, SLOT(inProgressSelectionChanged())); | |
124 | |
125 Preferences::BackgroundMode mode = | |
126 Preferences::getInstance()->getBackgroundMode(); | |
127 m_initialDarkBackground = m_viewManager->getGlobalDarkBackground(); | |
128 if (mode != Preferences::BackgroundFromTheme) { | |
129 m_viewManager->setGlobalDarkBackground | |
130 (mode == Preferences::DarkBackground); | |
131 } | |
132 | |
133 m_paneStack = new PaneStack(0, m_viewManager); | |
134 connect(m_paneStack, SIGNAL(currentPaneChanged(Pane *)), | |
135 this, SLOT(currentPaneChanged(Pane *))); | |
136 connect(m_paneStack, SIGNAL(currentLayerChanged(Pane *, Layer *)), | |
137 this, SLOT(currentLayerChanged(Pane *, Layer *))); | |
138 connect(m_paneStack, SIGNAL(rightButtonMenuRequested(Pane *, QPoint)), | |
139 this, SLOT(rightButtonMenuRequested(Pane *, QPoint))); | |
140 connect(m_paneStack, SIGNAL(contextHelpChanged(const QString &)), | |
141 this, SLOT(contextHelpChanged(const QString &))); | |
142 connect(m_paneStack, SIGNAL(paneAdded(Pane *)), | |
143 this, SLOT(paneAdded(Pane *))); | |
144 connect(m_paneStack, SIGNAL(paneHidden(Pane *)), | |
145 this, SLOT(paneHidden(Pane *))); | |
146 connect(m_paneStack, SIGNAL(paneAboutToBeDeleted(Pane *)), | |
147 this, SLOT(paneAboutToBeDeleted(Pane *))); | |
148 connect(m_paneStack, SIGNAL(dropAccepted(Pane *, QStringList)), | |
149 this, SLOT(paneDropAccepted(Pane *, QStringList))); | |
150 connect(m_paneStack, SIGNAL(dropAccepted(Pane *, QString)), | |
151 this, SLOT(paneDropAccepted(Pane *, QString))); | |
152 | |
153 m_playSource = new AudioCallbackPlaySource(m_viewManager); | |
154 | |
155 connect(m_playSource, SIGNAL(sampleRateMismatch(size_t, size_t, bool)), | |
156 this, SLOT(sampleRateMismatch(size_t, size_t, bool))); | |
157 connect(m_playSource, SIGNAL(audioOverloadPluginDisabled()), | |
158 this, SLOT(audioOverloadPluginDisabled())); | |
159 | |
160 connect(m_viewManager, SIGNAL(outputLevelsChanged(float, float)), | |
161 this, SLOT(outputLevelsChanged(float, float))); | |
162 | |
163 connect(m_viewManager, SIGNAL(playbackFrameChanged(unsigned long)), | |
164 this, SLOT(playbackFrameChanged(unsigned long))); | |
165 | |
166 connect(m_viewManager, SIGNAL(globalCentreFrameChanged(unsigned long)), | |
167 this, SLOT(globalCentreFrameChanged(unsigned long))); | |
168 | |
169 connect(m_viewManager, SIGNAL(viewCentreFrameChanged(View *, unsigned long)), | |
170 this, SLOT(viewCentreFrameChanged(View *, unsigned long))); | |
171 | |
172 connect(m_viewManager, SIGNAL(viewZoomLevelChanged(View *, unsigned long, bool)), | |
173 this, SLOT(viewZoomLevelChanged(View *, unsigned long, bool))); | |
174 | |
175 connect(Preferences::getInstance(), | |
176 SIGNAL(propertyChanged(PropertyContainer::PropertyName)), | |
177 this, | |
178 SLOT(preferenceChanged(PropertyContainer::PropertyName))); | |
179 | |
180 if (m_oscQueue && m_oscQueue->isOK()) { | |
181 connect(m_oscQueue, SIGNAL(messagesAvailable()), this, SLOT(pollOSC())); | |
182 QTimer *oscTimer = new QTimer(this); | |
183 connect(oscTimer, SIGNAL(timeout()), this, SLOT(pollOSC())); | |
184 oscTimer->start(1000); | |
185 } | |
186 | |
187 Labeller::ValueType labellerType = Labeller::ValueFromTwoLevelCounter; | |
188 QSettings settings; | |
189 settings.beginGroup("MainWindow"); | |
190 labellerType = (Labeller::ValueType) | |
191 settings.value("labellertype", (int)labellerType).toInt(); | |
192 int cycle = settings.value("labellercycle", 4).toInt(); | |
193 settings.endGroup(); | |
194 | |
195 m_labeller = new Labeller(labellerType); | |
196 m_labeller->setCounterCycleSize(cycle); | |
197 } | |
198 | |
199 MainWindowBase::~MainWindowBase() | |
200 { | |
201 delete m_playTarget; | |
202 delete m_playSource; | |
203 delete m_viewManager; | |
204 delete m_oscQueue; | |
205 Profiles::getInstance()->dump(); | |
206 } | |
207 | |
208 QString | |
209 MainWindowBase::getOpenFileName(FileFinder::FileType type) | |
210 { | |
211 FileFinder *ff = FileFinder::getInstance(); | |
212 switch (type) { | |
213 case FileFinder::SessionFile: | |
214 return ff->getOpenFileName(type, m_sessionFile); | |
215 case FileFinder::AudioFile: | |
216 return ff->getOpenFileName(type, m_audioFile); | |
217 case FileFinder::LayerFile: | |
218 return ff->getOpenFileName(type, m_sessionFile); | |
219 case FileFinder::LayerFileNoMidi: | |
220 return ff->getOpenFileName(type, m_sessionFile); | |
221 case FileFinder::SessionOrAudioFile: | |
222 return ff->getOpenFileName(type, m_sessionFile); | |
223 case FileFinder::ImageFile: | |
224 return ff->getOpenFileName(type, m_sessionFile); | |
225 case FileFinder::AnyFile: | |
226 if (getMainModel() != 0 && | |
227 m_paneStack != 0 && | |
228 m_paneStack->getCurrentPane() != 0) { // can import a layer | |
229 return ff->getOpenFileName(FileFinder::AnyFile, m_sessionFile); | |
230 } else { | |
231 return ff->getOpenFileName(FileFinder::SessionOrAudioFile, | |
232 m_sessionFile); | |
233 } | |
234 } | |
235 return ""; | |
236 } | |
237 | |
238 QString | |
239 MainWindowBase::getSaveFileName(FileFinder::FileType type) | |
240 { | |
241 FileFinder *ff = FileFinder::getInstance(); | |
242 switch (type) { | |
243 case FileFinder::SessionFile: | |
244 return ff->getSaveFileName(type, m_sessionFile); | |
245 case FileFinder::AudioFile: | |
246 return ff->getSaveFileName(type, m_audioFile); | |
247 case FileFinder::LayerFile: | |
248 return ff->getSaveFileName(type, m_sessionFile); | |
249 case FileFinder::LayerFileNoMidi: | |
250 return ff->getSaveFileName(type, m_sessionFile); | |
251 case FileFinder::SessionOrAudioFile: | |
252 return ff->getSaveFileName(type, m_sessionFile); | |
253 case FileFinder::ImageFile: | |
254 return ff->getSaveFileName(type, m_sessionFile); | |
255 case FileFinder::AnyFile: | |
256 return ff->getSaveFileName(type, m_sessionFile); | |
257 } | |
258 return ""; | |
259 } | |
260 | |
261 void | |
262 MainWindowBase::registerLastOpenedFilePath(FileFinder::FileType type, QString path) | |
263 { | |
264 FileFinder *ff = FileFinder::getInstance(); | |
265 ff->registerLastOpenedFilePath(type, path); | |
266 } | |
267 | |
268 void | |
269 MainWindowBase::updateMenuStates() | |
270 { | |
271 Pane *currentPane = 0; | |
272 Layer *currentLayer = 0; | |
273 | |
274 if (m_paneStack) currentPane = m_paneStack->getCurrentPane(); | |
275 if (currentPane) currentLayer = currentPane->getSelectedLayer(); | |
276 | |
277 bool haveCurrentPane = | |
278 (currentPane != 0); | |
279 bool haveCurrentLayer = | |
280 (haveCurrentPane && | |
281 (currentLayer != 0)); | |
282 bool haveMainModel = | |
283 (getMainModel() != 0); | |
284 bool havePlayTarget = | |
285 (m_playTarget != 0); | |
286 bool haveSelection = | |
287 (m_viewManager && | |
288 !m_viewManager->getSelections().empty()); | |
289 bool haveCurrentEditableLayer = | |
290 (haveCurrentLayer && | |
291 currentLayer->isLayerEditable()); | |
292 bool haveCurrentTimeInstantsLayer = | |
293 (haveCurrentLayer && | |
294 dynamic_cast<TimeInstantLayer *>(currentLayer)); | |
295 bool haveCurrentColour3DPlot = | |
296 (haveCurrentLayer && | |
297 dynamic_cast<Colour3DPlotLayer *>(currentLayer)); | |
298 bool haveClipboardContents = | |
299 (m_viewManager && | |
300 !m_viewManager->getClipboard().empty()); | |
301 | |
302 emit canAddPane(haveMainModel); | |
303 emit canDeleteCurrentPane(haveCurrentPane); | |
304 emit canZoom(haveMainModel && haveCurrentPane); | |
305 emit canScroll(haveMainModel && haveCurrentPane); | |
306 emit canAddLayer(haveMainModel && haveCurrentPane); | |
307 emit canImportMoreAudio(haveMainModel); | |
308 emit canImportLayer(haveMainModel && haveCurrentPane); | |
309 emit canExportAudio(haveMainModel); | |
310 emit canExportLayer(haveMainModel && | |
311 (haveCurrentEditableLayer || haveCurrentColour3DPlot)); | |
312 emit canExportImage(haveMainModel && haveCurrentPane); | |
313 emit canDeleteCurrentLayer(haveCurrentLayer); | |
314 emit canRenameLayer(haveCurrentLayer); | |
315 emit canEditLayer(haveCurrentEditableLayer); | |
316 emit canMeasureLayer(haveCurrentLayer); | |
317 emit canSelect(haveMainModel && haveCurrentPane); | |
318 emit canPlay(havePlayTarget); | |
319 emit canFfwd(true); | |
320 emit canRewind(true); | |
321 emit canPaste(haveCurrentEditableLayer && haveClipboardContents); | |
322 emit canInsertInstant(haveCurrentPane); | |
323 emit canInsertInstantsAtBoundaries(haveCurrentPane && haveSelection); | |
324 emit canRenumberInstants(haveCurrentTimeInstantsLayer && haveSelection); | |
325 emit canPlaySelection(haveMainModel && havePlayTarget && haveSelection); | |
326 emit canClearSelection(haveSelection); | |
327 emit canEditSelection(haveSelection && haveCurrentEditableLayer); | |
328 emit canSave(m_sessionFile != "" && m_documentModified); | |
329 } | |
330 | |
331 void | |
332 MainWindowBase::documentModified() | |
333 { | |
334 // std::cerr << "MainWindowBase::documentModified" << std::endl; | |
335 | |
336 if (!m_documentModified) { | |
337 //!!! this in subclass implementation? | |
338 setWindowTitle(tr("%1 (modified)").arg(windowTitle())); | |
339 } | |
340 | |
341 m_documentModified = true; | |
342 updateMenuStates(); | |
343 } | |
344 | |
345 void | |
346 MainWindowBase::documentRestored() | |
347 { | |
348 // std::cerr << "MainWindowBase::documentRestored" << std::endl; | |
349 | |
350 if (m_documentModified) { | |
351 //!!! this in subclass implementation? | |
352 QString wt(windowTitle()); | |
353 wt.replace(tr(" (modified)"), ""); | |
354 setWindowTitle(wt); | |
355 } | |
356 | |
357 m_documentModified = false; | |
358 updateMenuStates(); | |
359 } | |
360 | |
361 void | |
362 MainWindowBase::playLoopToggled() | |
363 { | |
364 QAction *action = dynamic_cast<QAction *>(sender()); | |
365 | |
366 if (action) { | |
367 m_viewManager->setPlayLoopMode(action->isChecked()); | |
368 } else { | |
369 m_viewManager->setPlayLoopMode(!m_viewManager->getPlayLoopMode()); | |
370 } | |
371 } | |
372 | |
373 void | |
374 MainWindowBase::playSelectionToggled() | |
375 { | |
376 QAction *action = dynamic_cast<QAction *>(sender()); | |
377 | |
378 if (action) { | |
379 m_viewManager->setPlaySelectionMode(action->isChecked()); | |
380 } else { | |
381 m_viewManager->setPlaySelectionMode(!m_viewManager->getPlaySelectionMode()); | |
382 } | |
383 } | |
384 | |
385 void | |
386 MainWindowBase::playSoloToggled() | |
387 { | |
388 QAction *action = dynamic_cast<QAction *>(sender()); | |
389 | |
390 if (action) { | |
391 m_viewManager->setPlaySoloMode(action->isChecked()); | |
392 } else { | |
393 m_viewManager->setPlaySoloMode(!m_viewManager->getPlaySoloMode()); | |
394 } | |
395 | |
396 if (m_viewManager->getPlaySoloMode()) { | |
397 currentPaneChanged(m_paneStack->getCurrentPane()); | |
398 } else { | |
399 m_viewManager->setPlaybackModel(0); | |
400 if (m_playSource) { | |
401 m_playSource->clearSoloModelSet(); | |
402 } | |
403 } | |
404 } | |
405 | |
406 void | |
407 MainWindowBase::currentPaneChanged(Pane *p) | |
408 { | |
409 updateMenuStates(); | |
410 updateVisibleRangeDisplay(p); | |
411 | |
412 if (!p) return; | |
413 | |
414 if (!(m_viewManager && | |
415 m_playSource && | |
416 m_viewManager->getPlaySoloMode())) { | |
417 if (m_viewManager) m_viewManager->setPlaybackModel(0); | |
418 return; | |
419 } | |
420 | |
421 Model *prevPlaybackModel = m_viewManager->getPlaybackModel(); | |
422 | |
423 View::ModelSet soloModels = p->getModels(); | |
424 | |
425 for (View::ModelSet::iterator mi = soloModels.begin(); | |
426 mi != soloModels.end(); ++mi) { | |
427 if (dynamic_cast<RangeSummarisableTimeValueModel *>(*mi)) { | |
428 m_viewManager->setPlaybackModel(*mi); | |
429 } | |
430 } | |
431 | |
432 RangeSummarisableTimeValueModel *a = | |
433 dynamic_cast<RangeSummarisableTimeValueModel *>(prevPlaybackModel); | |
434 RangeSummarisableTimeValueModel *b = | |
435 dynamic_cast<RangeSummarisableTimeValueModel *>(m_viewManager-> | |
436 getPlaybackModel()); | |
437 | |
438 m_playSource->setSoloModelSet(soloModels); | |
439 | |
440 if (a && b && (a != b)) { | |
441 int frame = m_playSource->getCurrentPlayingFrame(); | |
442 //!!! I don't really believe that these functions are the right way around | |
443 int rframe = a->alignFromReference(frame); | |
444 int bframe = b->alignToReference(rframe); | |
445 if (m_playSource->isPlaying()) m_playSource->play(bframe); | |
446 } | |
447 } | |
448 | |
449 void | |
450 MainWindowBase::currentLayerChanged(Pane *p, Layer *) | |
451 { | |
452 updateMenuStates(); | |
453 updateVisibleRangeDisplay(p); | |
454 } | |
455 | |
456 void | |
457 MainWindowBase::selectAll() | |
458 { | |
459 if (!getMainModel()) return; | |
460 m_viewManager->setSelection(Selection(getMainModel()->getStartFrame(), | |
461 getMainModel()->getEndFrame())); | |
462 } | |
463 | |
464 void | |
465 MainWindowBase::selectToStart() | |
466 { | |
467 if (!getMainModel()) return; | |
468 m_viewManager->setSelection(Selection(getMainModel()->getStartFrame(), | |
469 m_viewManager->getGlobalCentreFrame())); | |
470 } | |
471 | |
472 void | |
473 MainWindowBase::selectToEnd() | |
474 { | |
475 if (!getMainModel()) return; | |
476 m_viewManager->setSelection(Selection(m_viewManager->getGlobalCentreFrame(), | |
477 getMainModel()->getEndFrame())); | |
478 } | |
479 | |
480 void | |
481 MainWindowBase::selectVisible() | |
482 { | |
483 Model *model = getMainModel(); | |
484 if (!model) return; | |
485 | |
486 Pane *currentPane = m_paneStack->getCurrentPane(); | |
487 if (!currentPane) return; | |
488 | |
489 size_t startFrame, endFrame; | |
490 | |
491 if (currentPane->getStartFrame() < 0) startFrame = 0; | |
492 else startFrame = currentPane->getStartFrame(); | |
493 | |
494 if (currentPane->getEndFrame() > model->getEndFrame()) endFrame = model->getEndFrame(); | |
495 else endFrame = currentPane->getEndFrame(); | |
496 | |
497 m_viewManager->setSelection(Selection(startFrame, endFrame)); | |
498 } | |
499 | |
500 void | |
501 MainWindowBase::clearSelection() | |
502 { | |
503 m_viewManager->clearSelections(); | |
504 } | |
505 | |
506 void | |
507 MainWindowBase::cut() | |
508 { | |
509 Pane *currentPane = m_paneStack->getCurrentPane(); | |
510 if (!currentPane) return; | |
511 | |
512 Layer *layer = currentPane->getSelectedLayer(); | |
513 if (!layer) return; | |
514 | |
515 Clipboard &clipboard = m_viewManager->getClipboard(); | |
516 clipboard.clear(); | |
517 | |
518 MultiSelection::SelectionList selections = m_viewManager->getSelections(); | |
519 | |
520 CommandHistory::getInstance()->startCompoundOperation(tr("Cut"), true); | |
521 | |
522 for (MultiSelection::SelectionList::iterator i = selections.begin(); | |
523 i != selections.end(); ++i) { | |
524 layer->copy(*i, clipboard); | |
525 layer->deleteSelection(*i); | |
526 } | |
527 | |
528 CommandHistory::getInstance()->endCompoundOperation(); | |
529 } | |
530 | |
531 void | |
532 MainWindowBase::copy() | |
533 { | |
534 Pane *currentPane = m_paneStack->getCurrentPane(); | |
535 if (!currentPane) return; | |
536 | |
537 Layer *layer = currentPane->getSelectedLayer(); | |
538 if (!layer) return; | |
539 | |
540 Clipboard &clipboard = m_viewManager->getClipboard(); | |
541 clipboard.clear(); | |
542 | |
543 MultiSelection::SelectionList selections = m_viewManager->getSelections(); | |
544 | |
545 for (MultiSelection::SelectionList::iterator i = selections.begin(); | |
546 i != selections.end(); ++i) { | |
547 layer->copy(*i, clipboard); | |
548 } | |
549 } | |
550 | |
551 void | |
552 MainWindowBase::paste() | |
553 { | |
554 Pane *currentPane = m_paneStack->getCurrentPane(); | |
555 if (!currentPane) return; | |
556 | |
557 //!!! if we have no current layer, we should create one of the most | |
558 // appropriate type | |
559 | |
560 Layer *layer = currentPane->getSelectedLayer(); | |
561 if (!layer) return; | |
562 | |
563 Clipboard &clipboard = m_viewManager->getClipboard(); | |
564 Clipboard::PointList contents = clipboard.getPoints(); | |
565 /* | |
566 long minFrame = 0; | |
567 bool have = false; | |
568 for (int i = 0; i < contents.size(); ++i) { | |
569 if (!contents[i].haveFrame()) continue; | |
570 if (!have || contents[i].getFrame() < minFrame) { | |
571 minFrame = contents[i].getFrame(); | |
572 have = true; | |
573 } | |
574 } | |
575 | |
576 long frameOffset = long(m_viewManager->getGlobalCentreFrame()) - minFrame; | |
577 | |
578 layer->paste(clipboard, frameOffset); | |
579 */ | |
580 layer->paste(clipboard, 0, true); | |
581 } | |
582 | |
583 void | |
584 MainWindowBase::deleteSelected() | |
585 { | |
586 if (m_paneStack->getCurrentPane() && | |
587 m_paneStack->getCurrentPane()->getSelectedLayer()) { | |
588 | |
589 Layer *layer = m_paneStack->getCurrentPane()->getSelectedLayer(); | |
590 | |
591 if (m_viewManager && | |
592 (m_viewManager->getToolMode() == ViewManager::MeasureMode)) { | |
593 | |
594 layer->deleteCurrentMeasureRect(); | |
595 | |
596 } else { | |
597 | |
598 MultiSelection::SelectionList selections = | |
599 m_viewManager->getSelections(); | |
600 | |
601 for (MultiSelection::SelectionList::iterator i = selections.begin(); | |
602 i != selections.end(); ++i) { | |
603 layer->deleteSelection(*i); | |
604 } | |
605 } | |
606 } | |
607 } | |
608 | |
609 void | |
610 MainWindowBase::insertInstant() | |
611 { | |
612 int frame = m_viewManager->getPlaybackFrame(); | |
613 insertInstantAt(frame); | |
614 } | |
615 | |
616 void | |
617 MainWindowBase::insertInstantsAtBoundaries() | |
618 { | |
619 MultiSelection::SelectionList selections = m_viewManager->getSelections(); | |
620 for (MultiSelection::SelectionList::iterator i = selections.begin(); | |
621 i != selections.end(); ++i) { | |
622 size_t start = i->getStartFrame(); | |
623 size_t end = i->getEndFrame(); | |
624 if (start != end) { | |
625 insertInstantAt(i->getStartFrame()); | |
626 insertInstantAt(i->getEndFrame()); | |
627 } | |
628 } | |
629 } | |
630 | |
631 void | |
632 MainWindowBase::insertInstantAt(size_t frame) | |
633 { | |
634 Pane *pane = m_paneStack->getCurrentPane(); | |
635 if (!pane) { | |
636 return; | |
637 } | |
638 | |
639 Layer *layer = dynamic_cast<TimeInstantLayer *> | |
640 (pane->getSelectedLayer()); | |
641 | |
642 if (!layer) { | |
643 for (int i = pane->getLayerCount(); i > 0; --i) { | |
644 layer = dynamic_cast<TimeInstantLayer *>(pane->getLayer(i - 1)); | |
645 if (layer) break; | |
646 } | |
647 | |
648 if (!layer) { | |
649 CommandHistory::getInstance()->startCompoundOperation | |
650 (tr("Add Point"), true); | |
651 layer = m_document->createEmptyLayer(LayerFactory::TimeInstants); | |
652 if (layer) { | |
653 m_document->addLayerToView(pane, layer); | |
654 m_paneStack->setCurrentLayer(pane, layer); | |
655 } | |
656 CommandHistory::getInstance()->endCompoundOperation(); | |
657 } | |
658 } | |
659 | |
660 if (layer) { | |
661 | |
662 Model *model = layer->getModel(); | |
663 SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *> | |
664 (model); | |
665 | |
666 if (sodm) { | |
667 SparseOneDimensionalModel::Point point(frame, ""); | |
668 | |
669 SparseOneDimensionalModel::Point prevPoint(0); | |
670 bool havePrevPoint = false; | |
671 | |
672 SparseOneDimensionalModel::EditCommand *command = | |
673 new SparseOneDimensionalModel::EditCommand(sodm, tr("Add Point")); | |
674 | |
675 if (m_labeller->actingOnPrevPoint()) { | |
676 | |
677 SparseOneDimensionalModel::PointList prevPoints = | |
678 sodm->getPreviousPoints(frame); | |
679 | |
680 if (!prevPoints.empty()) { | |
681 prevPoint = *prevPoints.begin(); | |
682 havePrevPoint = true; | |
683 } | |
684 } | |
685 | |
686 if (m_labeller) { | |
687 | |
688 m_labeller->setSampleRate(sodm->getSampleRate()); | |
689 | |
690 if (havePrevPoint) { | |
691 command->deletePoint(prevPoint); | |
692 } | |
693 | |
694 m_labeller->label<SparseOneDimensionalModel::Point> | |
695 (point, havePrevPoint ? &prevPoint : 0); | |
696 | |
697 if (havePrevPoint) { | |
698 command->addPoint(prevPoint); | |
699 } | |
700 } | |
701 | |
702 command->addPoint(point); | |
703 | |
704 command->setName(tr("Add Point at %1 s") | |
705 .arg(RealTime::frame2RealTime | |
706 (frame, | |
707 sodm->getSampleRate()) | |
708 .toText(false).c_str())); | |
709 | |
710 command->finish(); | |
711 } | |
712 } | |
713 } | |
714 | |
715 void | |
716 MainWindowBase::renumberInstants() | |
717 { | |
718 Pane *pane = m_paneStack->getCurrentPane(); | |
719 if (!pane) return; | |
720 | |
721 Layer *layer = dynamic_cast<TimeInstantLayer *>(pane->getSelectedLayer()); | |
722 if (!layer) return; | |
723 | |
724 MultiSelection ms(m_viewManager->getSelection()); | |
725 | |
726 Model *model = layer->getModel(); | |
727 SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *> | |
728 (model); | |
729 if (!sodm) return; | |
730 | |
731 if (!m_labeller) return; | |
732 | |
733 Labeller labeller(*m_labeller); | |
734 labeller.setSampleRate(sodm->getSampleRate()); | |
735 | |
736 // This uses a command | |
737 | |
738 labeller.labelAll<SparseOneDimensionalModel::Point>(*sodm, &ms); | |
739 } | |
740 | |
741 MainWindowBase::FileOpenStatus | |
742 MainWindowBase::open(QString fileOrUrl, AudioFileOpenMode mode) | |
743 { | |
744 return open(FileSource(fileOrUrl), mode); | |
745 } | |
746 | |
747 MainWindowBase::FileOpenStatus | |
748 MainWindowBase::open(FileSource source, AudioFileOpenMode mode) | |
749 { | |
750 FileOpenStatus status; | |
751 | |
752 if (!source.isAvailable()) return FileOpenFailed; | |
753 source.waitForData(); | |
754 | |
755 bool canImportLayer = (getMainModel() != 0 && | |
756 m_paneStack != 0 && | |
757 m_paneStack->getCurrentPane() != 0); | |
758 | |
759 if ((status = openAudio(source, mode)) != FileOpenFailed) { | |
760 return status; | |
761 } else if ((status = openSession(source)) != FileOpenFailed) { | |
762 return status; | |
763 } else if ((status = openPlaylist(source, mode)) != FileOpenFailed) { | |
764 return status; | |
765 } else if (!canImportLayer) { | |
766 return FileOpenWrongMode; | |
767 } else if ((status = openImage(source)) != FileOpenFailed) { | |
768 return status; | |
769 } else if ((status = openLayer(source)) != FileOpenFailed) { | |
770 return status; | |
771 } else { | |
772 return FileOpenFailed; | |
773 } | |
774 } | |
775 | |
776 MainWindowBase::FileOpenStatus | |
777 MainWindowBase::openAudio(FileSource source, AudioFileOpenMode mode) | |
778 { | |
779 std::cerr << "MainWindowBase::openAudio(" << source.getLocation().toStdString() << ")" << std::endl; | |
780 | |
781 if (!source.isAvailable()) return FileOpenFailed; | |
782 source.waitForData(); | |
783 | |
784 m_openingAudioFile = true; | |
785 | |
786 size_t rate = 0; | |
787 | |
788 if (Preferences::getInstance()->getResampleOnLoad()) { | |
789 rate = m_playSource->getSourceSampleRate(); | |
790 } | |
791 | |
792 WaveFileModel *newModel = new WaveFileModel(source, rate); | |
793 | |
794 if (!newModel->isOK()) { | |
795 delete newModel; | |
796 m_openingAudioFile = false; | |
797 return FileOpenFailed; | |
798 } | |
799 | |
800 std::cerr << "mode = " << mode << std::endl; | |
801 | |
802 if (mode == AskUser) { | |
803 if (getMainModel()) { | |
804 | |
805 static bool prevSetAsMain = true; | |
806 bool setAsMain = true; | |
807 | |
808 QStringList items; | |
809 items << tr("Replace the existing main waveform") | |
810 << tr("Load this file into a new waveform pane"); | |
811 | |
812 bool ok = false; | |
813 QString item = ListInputDialog::getItem | |
814 (this, tr("Select target for import"), | |
815 tr("You already have an audio waveform loaded.\nWhat would you like to do with the new audio file?"), | |
816 items, prevSetAsMain ? 0 : 1, &ok); | |
817 | |
818 if (!ok || item.isEmpty()) { | |
819 delete newModel; | |
820 m_openingAudioFile = false; | |
821 return FileOpenCancelled; | |
822 } | |
823 | |
824 setAsMain = (item == items[0]); | |
825 prevSetAsMain = setAsMain; | |
826 | |
827 if (setAsMain) mode = ReplaceMainModel; | |
828 else mode = CreateAdditionalModel; | |
829 | |
830 } else { | |
831 mode = ReplaceMainModel; | |
832 } | |
833 } | |
834 | |
835 if (mode == ReplaceCurrentPane) { | |
836 | |
837 Pane *pane = m_paneStack->getCurrentPane(); | |
838 if (pane) { | |
839 if (getMainModel()) { | |
840 View::ModelSet models(pane->getModels()); | |
841 if (models.find(getMainModel()) != models.end()) { | |
842 mode = ReplaceMainModel; | |
843 } | |
844 } else { | |
845 mode = ReplaceMainModel; | |
846 } | |
847 } else { | |
848 mode = CreateAdditionalModel; | |
849 } | |
850 } | |
851 | |
852 if (mode == CreateAdditionalModel && !getMainModel()) { | |
853 mode = ReplaceMainModel; | |
854 } | |
855 | |
856 if (mode == ReplaceMainModel) { | |
857 | |
858 Model *prevMain = getMainModel(); | |
859 if (prevMain) { | |
860 m_playSource->removeModel(prevMain); | |
861 PlayParameterRepository::getInstance()->removeModel(prevMain); | |
862 } | |
863 PlayParameterRepository::getInstance()->addModel(newModel); | |
864 | |
865 m_document->setMainModel(newModel); | |
866 | |
867 setupMenus(); | |
868 | |
869 if (m_sessionFile == "") { | |
870 //!!! shouldn't be dealing directly with title from here -- call a method | |
871 setWindowTitle(tr("Sonic Visualiser: %1") | |
872 .arg(source.getLocation())); | |
873 CommandHistory::getInstance()->clear(); | |
874 CommandHistory::getInstance()->documentSaved(); | |
875 m_documentModified = false; | |
876 } else { | |
877 setWindowTitle(tr("Sonic Visualiser: %1 [%2]") | |
878 .arg(QFileInfo(m_sessionFile).fileName()) | |
879 .arg(source.getLocation())); | |
880 if (m_documentModified) { | |
881 m_documentModified = false; | |
882 documentModified(); // so as to restore "(modified)" window title | |
883 } | |
884 } | |
885 | |
886 if (!source.isRemote()) m_audioFile = source.getLocalFilename(); | |
887 | |
888 } else if (mode == CreateAdditionalModel) { | |
889 | |
890 CommandHistory::getInstance()->startCompoundOperation | |
891 (tr("Import \"%1\"").arg(source.getLocation()), true); | |
892 | |
893 m_document->addImportedModel(newModel); | |
894 | |
895 AddPaneCommand *command = new AddPaneCommand(this); | |
896 CommandHistory::getInstance()->addCommand(command); | |
897 | |
898 Pane *pane = command->getPane(); | |
899 | |
900 if (!m_timeRulerLayer) { | |
901 m_timeRulerLayer = m_document->createMainModelLayer | |
902 (LayerFactory::TimeRuler); | |
903 } | |
904 | |
905 m_document->addLayerToView(pane, m_timeRulerLayer); | |
906 | |
907 Layer *newLayer = m_document->createImportedLayer(newModel); | |
908 | |
909 if (newLayer) { | |
910 m_document->addLayerToView(pane, newLayer); | |
911 } | |
912 | |
913 CommandHistory::getInstance()->endCompoundOperation(); | |
914 | |
915 } else if (mode == ReplaceCurrentPane) { | |
916 | |
917 // We know there is a current pane, otherwise we would have | |
918 // reset the mode to CreateAdditionalModel above; and we know | |
919 // the current pane does not contain the main model, otherwise | |
920 // we would have reset it to ReplaceMainModel. But we don't | |
921 // know whether the pane contains a waveform model at all. | |
922 | |
923 Pane *pane = m_paneStack->getCurrentPane(); | |
924 Layer *replace = 0; | |
925 | |
926 for (int i = 0; i < pane->getLayerCount(); ++i) { | |
927 Layer *layer = pane->getLayer(i); | |
928 if (dynamic_cast<WaveformLayer *>(layer)) { | |
929 replace = layer; | |
930 break; | |
931 } | |
932 } | |
933 | |
934 CommandHistory::getInstance()->startCompoundOperation | |
935 (tr("Import \"%1\"").arg(source.getLocation()), true); | |
936 | |
937 m_document->addImportedModel(newModel); | |
938 | |
939 if (replace) { | |
940 m_document->removeLayerFromView(pane, replace); | |
941 } | |
942 | |
943 Layer *newLayer = m_document->createImportedLayer(newModel); | |
944 | |
945 if (newLayer) { | |
946 m_document->addLayerToView(pane, newLayer); | |
947 } | |
948 | |
949 CommandHistory::getInstance()->endCompoundOperation(); | |
950 } | |
951 | |
952 updateMenuStates(); | |
953 m_recentFiles.addFile(source.getLocation()); | |
954 if (!source.isRemote()) { | |
955 // for file dialog | |
956 registerLastOpenedFilePath(FileFinder::AudioFile, | |
957 source.getLocalFilename()); | |
958 } | |
959 m_openingAudioFile = false; | |
960 | |
961 currentPaneChanged(m_paneStack->getCurrentPane()); | |
962 | |
963 return FileOpenSucceeded; | |
964 } | |
965 | |
966 MainWindowBase::FileOpenStatus | |
967 MainWindowBase::openPlaylist(FileSource source, AudioFileOpenMode mode) | |
968 { | |
969 std::set<QString> extensions; | |
970 PlaylistFileReader::getSupportedExtensions(extensions); | |
971 QString extension = source.getExtension(); | |
972 if (extensions.find(extension) == extensions.end()) return FileOpenFailed; | |
973 | |
974 if (!source.isAvailable()) return FileOpenFailed; | |
975 source.waitForData(); | |
976 | |
977 PlaylistFileReader reader(source.getLocalFilename()); | |
978 if (!reader.isOK()) return FileOpenFailed; | |
979 | |
980 PlaylistFileReader::Playlist playlist = reader.load(); | |
981 | |
982 bool someSuccess = false; | |
983 | |
984 for (PlaylistFileReader::Playlist::const_iterator i = playlist.begin(); | |
985 i != playlist.end(); ++i) { | |
986 | |
987 FileOpenStatus status = openAudio(*i, mode); | |
988 | |
989 if (status == FileOpenCancelled) { | |
990 return FileOpenCancelled; | |
991 } | |
992 | |
993 if (status == FileOpenSucceeded) { | |
994 someSuccess = true; | |
995 mode = CreateAdditionalModel; | |
996 } | |
997 } | |
998 | |
999 if (someSuccess) return FileOpenSucceeded; | |
1000 else return FileOpenFailed; | |
1001 } | |
1002 | |
1003 MainWindowBase::FileOpenStatus | |
1004 MainWindowBase::openLayer(FileSource source) | |
1005 { | |
1006 Pane *pane = m_paneStack->getCurrentPane(); | |
1007 | |
1008 if (!pane) { | |
1009 // shouldn't happen, as the menu action should have been disabled | |
1010 std::cerr << "WARNING: MainWindowBase::openLayer: no current pane" << std::endl; | |
1011 return FileOpenWrongMode; | |
1012 } | |
1013 | |
1014 if (!getMainModel()) { | |
1015 // shouldn't happen, as the menu action should have been disabled | |
1016 std::cerr << "WARNING: MainWindowBase::openLayer: No main model -- hence no default sample rate available" << std::endl; | |
1017 return FileOpenWrongMode; | |
1018 } | |
1019 | |
1020 if (!source.isAvailable()) return FileOpenFailed; | |
1021 source.waitForData(); | |
1022 | |
1023 QString path = source.getLocalFilename(); | |
1024 | |
1025 if (source.getExtension() == "svl" || source.getExtension() == "xml") { | |
1026 | |
1027 PaneCallback callback(this); | |
1028 QFile file(path); | |
1029 | |
1030 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { | |
1031 std::cerr << "ERROR: MainWindowBase::openLayer(" | |
1032 << source.getLocation().toStdString() | |
1033 << "): Failed to open file for reading" << std::endl; | |
1034 return FileOpenFailed; | |
1035 } | |
1036 | |
1037 SVFileReader reader(m_document, callback, source.getLocation()); | |
1038 reader.setCurrentPane(pane); | |
1039 | |
1040 QXmlInputSource inputSource(&file); | |
1041 reader.parse(inputSource); | |
1042 | |
1043 if (!reader.isOK()) { | |
1044 std::cerr << "ERROR: MainWindowBase::openLayer(" | |
1045 << source.getLocation().toStdString() | |
1046 << "): Failed to read XML file: " | |
1047 << reader.getErrorString().toStdString() << std::endl; | |
1048 return FileOpenFailed; | |
1049 } | |
1050 | |
1051 m_recentFiles.addFile(source.getLocation()); | |
1052 | |
1053 if (!source.isRemote()) { | |
1054 registerLastOpenedFilePath(FileFinder::LayerFile, path); // for file dialog | |
1055 } | |
1056 | |
1057 } else { | |
1058 | |
1059 try { | |
1060 | |
1061 Model *model = DataFileReaderFactory::load | |
1062 (path, getMainModel()->getSampleRate()); | |
1063 | |
1064 if (model) { | |
1065 | |
1066 std::cerr << "MainWindowBase::openLayer: Have model" << std::endl; | |
1067 | |
1068 Layer *newLayer = m_document->createImportedLayer(model); | |
1069 | |
1070 if (newLayer) { | |
1071 | |
1072 m_document->addLayerToView(pane, newLayer); | |
1073 m_recentFiles.addFile(source.getLocation()); | |
1074 | |
1075 if (!source.isRemote()) { | |
1076 registerLastOpenedFilePath | |
1077 (FileFinder::LayerFile, | |
1078 path); // for file dialog | |
1079 } | |
1080 | |
1081 return FileOpenSucceeded; | |
1082 } | |
1083 } | |
1084 } catch (DataFileReaderFactory::Exception e) { | |
1085 if (e == DataFileReaderFactory::ImportCancelled) { | |
1086 return FileOpenCancelled; | |
1087 } | |
1088 } | |
1089 } | |
1090 | |
1091 source.setLeaveLocalFile(true); | |
1092 return FileOpenFailed; | |
1093 } | |
1094 | |
1095 MainWindowBase::FileOpenStatus | |
1096 MainWindowBase::openImage(FileSource source) | |
1097 { | |
1098 Pane *pane = m_paneStack->getCurrentPane(); | |
1099 | |
1100 if (!pane) { | |
1101 // shouldn't happen, as the menu action should have been disabled | |
1102 std::cerr << "WARNING: MainWindowBase::openImage: no current pane" << std::endl; | |
1103 return FileOpenWrongMode; | |
1104 } | |
1105 | |
1106 if (!m_document->getMainModel()) { | |
1107 return FileOpenWrongMode; | |
1108 } | |
1109 | |
1110 bool newLayer = false; | |
1111 | |
1112 ImageLayer *il = dynamic_cast<ImageLayer *>(pane->getSelectedLayer()); | |
1113 if (!il) { | |
1114 for (int i = pane->getLayerCount()-1; i >= 0; --i) { | |
1115 il = dynamic_cast<ImageLayer *>(pane->getLayer(i)); | |
1116 if (il) break; | |
1117 } | |
1118 } | |
1119 if (!il) { | |
1120 il = dynamic_cast<ImageLayer *> | |
1121 (m_document->createEmptyLayer(LayerFactory::Image)); | |
1122 if (!il) return FileOpenFailed; | |
1123 newLayer = true; | |
1124 } | |
1125 | |
1126 // We don't put the image file in Recent Files | |
1127 | |
1128 std::cerr << "openImage: trying location \"" << source.getLocation().toStdString() << "\" in image layer" << std::endl; | |
1129 | |
1130 if (!il->addImage(m_viewManager->getGlobalCentreFrame(), source.getLocation())) { | |
1131 if (newLayer) { | |
1132 m_document->setModel(il, 0); // releasing its model | |
1133 delete il; | |
1134 } | |
1135 return FileOpenFailed; | |
1136 } else { | |
1137 if (newLayer) { | |
1138 m_document->addLayerToView(pane, il); | |
1139 } | |
1140 m_paneStack->setCurrentLayer(pane, il); | |
1141 } | |
1142 | |
1143 return FileOpenSucceeded; | |
1144 } | |
1145 | |
1146 MainWindowBase::FileOpenStatus | |
1147 MainWindowBase::openSessionFile(QString fileOrUrl) | |
1148 { | |
1149 return openSession(FileSource(fileOrUrl)); | |
1150 } | |
1151 | |
1152 MainWindowBase::FileOpenStatus | |
1153 MainWindowBase::openSession(FileSource source) | |
1154 { | |
1155 if (!source.isAvailable()) return FileOpenFailed; | |
1156 if (source.getExtension() != "sv") return FileOpenFailed; | |
1157 source.waitForData(); | |
1158 | |
1159 BZipFileDevice bzFile(source.getLocalFilename()); | |
1160 if (!bzFile.open(QIODevice::ReadOnly)) return FileOpenFailed; | |
1161 | |
1162 if (!checkSaveModified()) return FileOpenCancelled; | |
1163 | |
1164 QString error; | |
1165 closeSession(); | |
1166 createDocument(); | |
1167 | |
1168 PaneCallback callback(this); | |
1169 m_viewManager->clearSelections(); | |
1170 | |
1171 SVFileReader reader(m_document, callback, source.getLocation()); | |
1172 QXmlInputSource inputSource(&bzFile); | |
1173 reader.parse(inputSource); | |
1174 | |
1175 if (!reader.isOK()) { | |
1176 error = tr("SV XML file read error:\n%1").arg(reader.getErrorString()); | |
1177 } | |
1178 | |
1179 bzFile.close(); | |
1180 | |
1181 bool ok = (error == ""); | |
1182 | |
1183 if (ok) { | |
1184 | |
1185 setWindowTitle(tr("Sonic Visualiser: %1") | |
1186 .arg(source.getLocation())); | |
1187 | |
1188 if (!source.isRemote()) m_sessionFile = source.getLocalFilename(); | |
1189 | |
1190 setupMenus(); | |
1191 | |
1192 CommandHistory::getInstance()->clear(); | |
1193 CommandHistory::getInstance()->documentSaved(); | |
1194 m_documentModified = false; | |
1195 updateMenuStates(); | |
1196 | |
1197 m_recentFiles.addFile(source.getLocation()); | |
1198 | |
1199 if (!source.isRemote()) { | |
1200 // for file dialog | |
1201 registerLastOpenedFilePath(FileFinder::SessionFile, | |
1202 source.getLocalFilename()); | |
1203 } | |
1204 | |
1205 } else { | |
1206 setWindowTitle(tr("Sonic Visualiser")); | |
1207 } | |
1208 | |
1209 return ok ? FileOpenSucceeded : FileOpenFailed; | |
1210 } | |
1211 | |
1212 void | |
1213 MainWindowBase::createPlayTarget() | |
1214 { | |
1215 if (m_playTarget) return; | |
1216 | |
1217 m_playTarget = AudioTargetFactory::createCallbackTarget(m_playSource); | |
1218 if (!m_playTarget) { | |
1219 QMessageBox::warning | |
1220 (this, tr("Couldn't open audio device"), | |
1221 tr("<b>No audio available</b><p>Could not open an audio device for playback.<p>Audio playback will not be available during this session."), | |
1222 QMessageBox::Ok); | |
1223 } | |
1224 } | |
1225 | |
1226 WaveFileModel * | |
1227 MainWindowBase::getMainModel() | |
1228 { | |
1229 if (!m_document) return 0; | |
1230 return m_document->getMainModel(); | |
1231 } | |
1232 | |
1233 const WaveFileModel * | |
1234 MainWindowBase::getMainModel() const | |
1235 { | |
1236 if (!m_document) return 0; | |
1237 return m_document->getMainModel(); | |
1238 } | |
1239 | |
1240 void | |
1241 MainWindowBase::createDocument() | |
1242 { | |
1243 m_document = new Document; | |
1244 | |
1245 connect(m_document, SIGNAL(layerAdded(Layer *)), | |
1246 this, SLOT(layerAdded(Layer *))); | |
1247 connect(m_document, SIGNAL(layerRemoved(Layer *)), | |
1248 this, SLOT(layerRemoved(Layer *))); | |
1249 connect(m_document, SIGNAL(layerAboutToBeDeleted(Layer *)), | |
1250 this, SLOT(layerAboutToBeDeleted(Layer *))); | |
1251 connect(m_document, SIGNAL(layerInAView(Layer *, bool)), | |
1252 this, SLOT(layerInAView(Layer *, bool))); | |
1253 | |
1254 connect(m_document, SIGNAL(modelAdded(Model *)), | |
1255 this, SLOT(modelAdded(Model *))); | |
1256 connect(m_document, SIGNAL(mainModelChanged(WaveFileModel *)), | |
1257 this, SLOT(mainModelChanged(WaveFileModel *))); | |
1258 connect(m_document, SIGNAL(modelAboutToBeDeleted(Model *)), | |
1259 this, SLOT(modelAboutToBeDeleted(Model *))); | |
1260 | |
1261 connect(m_document, SIGNAL(modelGenerationFailed(QString)), | |
1262 this, SLOT(modelGenerationFailed(QString))); | |
1263 connect(m_document, SIGNAL(modelRegenerationFailed(QString, QString)), | |
1264 this, SLOT(modelRegenerationFailed(QString, QString))); | |
1265 } | |
1266 | |
1267 bool | |
1268 MainWindowBase::saveSessionFile(QString path) | |
1269 { | |
1270 BZipFileDevice bzFile(path); | |
1271 if (!bzFile.open(QIODevice::WriteOnly)) { | |
1272 std::cerr << "Failed to open session file \"" << path.toStdString() | |
1273 << "\" for writing: " | |
1274 << bzFile.errorString().toStdString() << std::endl; | |
1275 return false; | |
1276 } | |
1277 | |
1278 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); | |
1279 | |
1280 QTextStream out(&bzFile); | |
1281 toXml(out); | |
1282 out.flush(); | |
1283 | |
1284 QApplication::restoreOverrideCursor(); | |
1285 | |
1286 if (!bzFile.isOK()) { | |
1287 QMessageBox::critical(this, tr("Failed to write file"), | |
1288 tr("<b>Save failed</b><p>Failed to write to file \"%1\": %2") | |
1289 .arg(path).arg(bzFile.errorString())); | |
1290 bzFile.close(); | |
1291 return false; | |
1292 } | |
1293 | |
1294 bzFile.close(); | |
1295 return true; | |
1296 } | |
1297 | |
1298 void | |
1299 MainWindowBase::toXml(QTextStream &out) | |
1300 { | |
1301 QString indent(" "); | |
1302 | |
1303 out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; | |
1304 out << "<!DOCTYPE sonic-visualiser>\n"; | |
1305 out << "<sv>\n"; | |
1306 | |
1307 m_document->toXml(out, "", ""); | |
1308 | |
1309 out << "<display>\n"; | |
1310 | |
1311 out << QString(" <window width=\"%1\" height=\"%2\"/>\n") | |
1312 .arg(width()).arg(height()); | |
1313 | |
1314 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) { | |
1315 | |
1316 Pane *pane = m_paneStack->getPane(i); | |
1317 | |
1318 if (pane) { | |
1319 pane->toXml(out, indent); | |
1320 } | |
1321 } | |
1322 | |
1323 out << "</display>\n"; | |
1324 | |
1325 m_viewManager->getSelection().toXml(out); | |
1326 | |
1327 out << "</sv>\n"; | |
1328 } | |
1329 | |
1330 Pane * | |
1331 MainWindowBase::addPaneToStack() | |
1332 { | |
1333 AddPaneCommand *command = new AddPaneCommand(this); | |
1334 CommandHistory::getInstance()->addCommand(command); | |
1335 return command->getPane(); | |
1336 } | |
1337 | |
1338 void | |
1339 MainWindowBase::zoomIn() | |
1340 { | |
1341 Pane *currentPane = m_paneStack->getCurrentPane(); | |
1342 if (currentPane) currentPane->zoom(true); | |
1343 } | |
1344 | |
1345 void | |
1346 MainWindowBase::zoomOut() | |
1347 { | |
1348 Pane *currentPane = m_paneStack->getCurrentPane(); | |
1349 if (currentPane) currentPane->zoom(false); | |
1350 } | |
1351 | |
1352 void | |
1353 MainWindowBase::zoomToFit() | |
1354 { | |
1355 Pane *currentPane = m_paneStack->getCurrentPane(); | |
1356 if (!currentPane) return; | |
1357 | |
1358 Model *model = getMainModel(); | |
1359 if (!model) return; | |
1360 | |
1361 size_t start = model->getStartFrame(); | |
1362 size_t end = model->getEndFrame(); | |
1363 size_t pixels = currentPane->width(); | |
1364 | |
1365 size_t sw = currentPane->getVerticalScaleWidth(); | |
1366 if (pixels > sw * 2) pixels -= sw * 2; | |
1367 else pixels = 1; | |
1368 if (pixels > 4) pixels -= 4; | |
1369 | |
1370 size_t zoomLevel = (end - start) / pixels; | |
1371 | |
1372 currentPane->setZoomLevel(zoomLevel); | |
1373 currentPane->setCentreFrame((start + end) / 2); | |
1374 } | |
1375 | |
1376 void | |
1377 MainWindowBase::zoomDefault() | |
1378 { | |
1379 Pane *currentPane = m_paneStack->getCurrentPane(); | |
1380 if (currentPane) currentPane->setZoomLevel(1024); | |
1381 } | |
1382 | |
1383 void | |
1384 MainWindowBase::scrollLeft() | |
1385 { | |
1386 Pane *currentPane = m_paneStack->getCurrentPane(); | |
1387 if (currentPane) currentPane->scroll(false, false); | |
1388 } | |
1389 | |
1390 void | |
1391 MainWindowBase::jumpLeft() | |
1392 { | |
1393 Pane *currentPane = m_paneStack->getCurrentPane(); | |
1394 if (currentPane) currentPane->scroll(false, true); | |
1395 } | |
1396 | |
1397 void | |
1398 MainWindowBase::scrollRight() | |
1399 { | |
1400 Pane *currentPane = m_paneStack->getCurrentPane(); | |
1401 if (currentPane) currentPane->scroll(true, false); | |
1402 } | |
1403 | |
1404 void | |
1405 MainWindowBase::jumpRight() | |
1406 { | |
1407 Pane *currentPane = m_paneStack->getCurrentPane(); | |
1408 if (currentPane) currentPane->scroll(true, true); | |
1409 } | |
1410 | |
1411 void | |
1412 MainWindowBase::showNoOverlays() | |
1413 { | |
1414 m_viewManager->setOverlayMode(ViewManager::NoOverlays); | |
1415 } | |
1416 | |
1417 void | |
1418 MainWindowBase::showMinimalOverlays() | |
1419 { | |
1420 m_viewManager->setOverlayMode(ViewManager::MinimalOverlays); | |
1421 } | |
1422 | |
1423 void | |
1424 MainWindowBase::showStandardOverlays() | |
1425 { | |
1426 m_viewManager->setOverlayMode(ViewManager::StandardOverlays); | |
1427 } | |
1428 | |
1429 void | |
1430 MainWindowBase::showAllOverlays() | |
1431 { | |
1432 m_viewManager->setOverlayMode(ViewManager::AllOverlays); | |
1433 } | |
1434 | |
1435 void | |
1436 MainWindowBase::toggleZoomWheels() | |
1437 { | |
1438 if (m_viewManager->getZoomWheelsEnabled()) { | |
1439 m_viewManager->setZoomWheelsEnabled(false); | |
1440 } else { | |
1441 m_viewManager->setZoomWheelsEnabled(true); | |
1442 } | |
1443 } | |
1444 | |
1445 void | |
1446 MainWindowBase::togglePropertyBoxes() | |
1447 { | |
1448 if (m_paneStack->getLayoutStyle() == PaneStack::NoPropertyStacks) { | |
1449 if (Preferences::getInstance()->getPropertyBoxLayout() == | |
1450 Preferences::VerticallyStacked) { | |
1451 m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout); | |
1452 } else { | |
1453 m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout); | |
1454 } | |
1455 } else { | |
1456 m_paneStack->setLayoutStyle(PaneStack::NoPropertyStacks); | |
1457 } | |
1458 } | |
1459 | |
1460 void | |
1461 MainWindowBase::toggleStatusBar() | |
1462 { | |
1463 QSettings settings; | |
1464 settings.beginGroup("MainWindow"); | |
1465 bool sb = settings.value("showstatusbar", true).toBool(); | |
1466 | |
1467 if (sb) { | |
1468 statusBar()->hide(); | |
1469 } else { | |
1470 statusBar()->show(); | |
1471 } | |
1472 | |
1473 settings.setValue("showstatusbar", !sb); | |
1474 | |
1475 settings.endGroup(); | |
1476 } | |
1477 | |
1478 void | |
1479 MainWindowBase::preferenceChanged(PropertyContainer::PropertyName name) | |
1480 { | |
1481 if (name == "Property Box Layout") { | |
1482 if (m_paneStack->getLayoutStyle() != PaneStack::NoPropertyStacks) { | |
1483 if (Preferences::getInstance()->getPropertyBoxLayout() == | |
1484 Preferences::VerticallyStacked) { | |
1485 m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout); | |
1486 } else { | |
1487 m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout); | |
1488 } | |
1489 } | |
1490 } else if (name == "Background Mode" && m_viewManager) { | |
1491 Preferences::BackgroundMode mode = | |
1492 Preferences::getInstance()->getBackgroundMode(); | |
1493 if (mode == Preferences::BackgroundFromTheme) { | |
1494 m_viewManager->setGlobalDarkBackground(m_initialDarkBackground); | |
1495 } else if (mode == Preferences::DarkBackground) { | |
1496 m_viewManager->setGlobalDarkBackground(true); | |
1497 } else { | |
1498 m_viewManager->setGlobalDarkBackground(false); | |
1499 } | |
1500 } | |
1501 } | |
1502 | |
1503 void | |
1504 MainWindowBase::play() | |
1505 { | |
1506 if (m_playSource->isPlaying()) { | |
1507 stop(); | |
1508 } else { | |
1509 playbackFrameChanged(m_viewManager->getPlaybackFrame()); | |
1510 m_playSource->play(m_viewManager->getPlaybackFrame()); | |
1511 } | |
1512 } | |
1513 | |
1514 void | |
1515 MainWindowBase::ffwd() | |
1516 { | |
1517 if (!getMainModel()) return; | |
1518 | |
1519 int frame = m_viewManager->getPlaybackFrame(); | |
1520 ++frame; | |
1521 | |
1522 Layer *layer = getSnapLayer(); | |
1523 size_t sr = getMainModel()->getSampleRate(); | |
1524 | |
1525 if (!layer) { | |
1526 | |
1527 frame = RealTime::realTime2Frame | |
1528 (RealTime::frame2RealTime(frame, sr) + RealTime(2, 0), sr); | |
1529 if (frame > int(getMainModel()->getEndFrame())) { | |
1530 frame = getMainModel()->getEndFrame(); | |
1531 } | |
1532 | |
1533 } else { | |
1534 | |
1535 size_t resolution = 0; | |
1536 if (!layer->snapToFeatureFrame(m_paneStack->getCurrentPane(), | |
1537 frame, resolution, Layer::SnapRight)) { | |
1538 frame = getMainModel()->getEndFrame(); | |
1539 } | |
1540 } | |
1541 | |
1542 if (frame < 0) frame = 0; | |
1543 | |
1544 if (m_viewManager->getPlaySelectionMode()) { | |
1545 frame = m_viewManager->constrainFrameToSelection(size_t(frame)); | |
1546 } | |
1547 | |
1548 m_viewManager->setPlaybackFrame(frame); | |
1549 } | |
1550 | |
1551 void | |
1552 MainWindowBase::ffwdEnd() | |
1553 { | |
1554 if (!getMainModel()) return; | |
1555 | |
1556 size_t frame = getMainModel()->getEndFrame(); | |
1557 | |
1558 if (m_viewManager->getPlaySelectionMode()) { | |
1559 frame = m_viewManager->constrainFrameToSelection(frame); | |
1560 } | |
1561 | |
1562 m_viewManager->setPlaybackFrame(frame); | |
1563 } | |
1564 | |
1565 void | |
1566 MainWindowBase::rewind() | |
1567 { | |
1568 if (!getMainModel()) return; | |
1569 | |
1570 int frame = m_viewManager->getPlaybackFrame(); | |
1571 if (frame > 0) --frame; | |
1572 | |
1573 Layer *layer = getSnapLayer(); | |
1574 size_t sr = getMainModel()->getSampleRate(); | |
1575 | |
1576 // when rewinding during playback, we want to allow a period | |
1577 // following a rewind target point at which the rewind will go to | |
1578 // the prior point instead of the immediately neighbouring one | |
1579 if (m_playSource && m_playSource->isPlaying()) { | |
1580 RealTime ct = RealTime::frame2RealTime(frame, sr); | |
1581 ct = ct - RealTime::fromSeconds(0.25); | |
1582 if (ct < RealTime::zeroTime) ct = RealTime::zeroTime; | |
1583 // std::cerr << "rewind: frame " << frame << " -> "; | |
1584 frame = RealTime::realTime2Frame(ct, sr); | |
1585 // std::cerr << frame << std::endl; | |
1586 } | |
1587 | |
1588 if (!layer) { | |
1589 | |
1590 frame = RealTime::realTime2Frame | |
1591 (RealTime::frame2RealTime(frame, sr) - RealTime(2, 0), sr); | |
1592 if (frame < int(getMainModel()->getStartFrame())) { | |
1593 frame = getMainModel()->getStartFrame(); | |
1594 } | |
1595 | |
1596 } else { | |
1597 | |
1598 size_t resolution = 0; | |
1599 if (!layer->snapToFeatureFrame(m_paneStack->getCurrentPane(), | |
1600 frame, resolution, Layer::SnapLeft)) { | |
1601 frame = getMainModel()->getStartFrame(); | |
1602 } | |
1603 } | |
1604 | |
1605 if (frame < 0) frame = 0; | |
1606 | |
1607 if (m_viewManager->getPlaySelectionMode()) { | |
1608 frame = m_viewManager->constrainFrameToSelection(size_t(frame)); | |
1609 } | |
1610 | |
1611 m_viewManager->setPlaybackFrame(frame); | |
1612 } | |
1613 | |
1614 void | |
1615 MainWindowBase::rewindStart() | |
1616 { | |
1617 if (!getMainModel()) return; | |
1618 | |
1619 size_t frame = getMainModel()->getStartFrame(); | |
1620 | |
1621 if (m_viewManager->getPlaySelectionMode()) { | |
1622 frame = m_viewManager->constrainFrameToSelection(frame); | |
1623 } | |
1624 | |
1625 m_viewManager->setPlaybackFrame(frame); | |
1626 } | |
1627 | |
1628 Layer * | |
1629 MainWindowBase::getSnapLayer() const | |
1630 { | |
1631 Pane *pane = m_paneStack->getCurrentPane(); | |
1632 if (!pane) return 0; | |
1633 | |
1634 Layer *layer = pane->getSelectedLayer(); | |
1635 | |
1636 if (!dynamic_cast<TimeInstantLayer *>(layer) && | |
1637 !dynamic_cast<TimeValueLayer *>(layer) && | |
1638 !dynamic_cast<TimeRulerLayer *>(layer)) { | |
1639 | |
1640 layer = 0; | |
1641 | |
1642 for (int i = pane->getLayerCount(); i > 0; --i) { | |
1643 Layer *l = pane->getLayer(i-1); | |
1644 if (dynamic_cast<TimeRulerLayer *>(l)) { | |
1645 layer = l; | |
1646 break; | |
1647 } | |
1648 } | |
1649 } | |
1650 | |
1651 return layer; | |
1652 } | |
1653 | |
1654 void | |
1655 MainWindowBase::stop() | |
1656 { | |
1657 m_playSource->stop(); | |
1658 | |
1659 if (m_paneStack && m_paneStack->getCurrentPane()) { | |
1660 updateVisibleRangeDisplay(m_paneStack->getCurrentPane()); | |
1661 } else { | |
1662 m_myStatusMessage = ""; | |
1663 statusBar()->showMessage(""); | |
1664 } | |
1665 } | |
1666 | |
1667 MainWindowBase::AddPaneCommand::AddPaneCommand(MainWindowBase *mw) : | |
1668 m_mw(mw), | |
1669 m_pane(0), | |
1670 m_prevCurrentPane(0), | |
1671 m_added(false) | |
1672 { | |
1673 } | |
1674 | |
1675 MainWindowBase::AddPaneCommand::~AddPaneCommand() | |
1676 { | |
1677 if (m_pane && !m_added) { | |
1678 m_mw->m_paneStack->deletePane(m_pane); | |
1679 } | |
1680 } | |
1681 | |
1682 QString | |
1683 MainWindowBase::AddPaneCommand::getName() const | |
1684 { | |
1685 return tr("Add Pane"); | |
1686 } | |
1687 | |
1688 void | |
1689 MainWindowBase::AddPaneCommand::execute() | |
1690 { | |
1691 if (!m_pane) { | |
1692 m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane(); | |
1693 m_pane = m_mw->m_paneStack->addPane(); | |
1694 | |
1695 connect(m_pane, SIGNAL(contextHelpChanged(const QString &)), | |
1696 m_mw, SLOT(contextHelpChanged(const QString &))); | |
1697 } else { | |
1698 m_mw->m_paneStack->showPane(m_pane); | |
1699 } | |
1700 | |
1701 m_mw->m_paneStack->setCurrentPane(m_pane); | |
1702 m_added = true; | |
1703 } | |
1704 | |
1705 void | |
1706 MainWindowBase::AddPaneCommand::unexecute() | |
1707 { | |
1708 m_mw->m_paneStack->hidePane(m_pane); | |
1709 m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane); | |
1710 m_added = false; | |
1711 } | |
1712 | |
1713 MainWindowBase::RemovePaneCommand::RemovePaneCommand(MainWindowBase *mw, Pane *pane) : | |
1714 m_mw(mw), | |
1715 m_pane(pane), | |
1716 m_added(true) | |
1717 { | |
1718 } | |
1719 | |
1720 MainWindowBase::RemovePaneCommand::~RemovePaneCommand() | |
1721 { | |
1722 if (m_pane && !m_added) { | |
1723 m_mw->m_paneStack->deletePane(m_pane); | |
1724 } | |
1725 } | |
1726 | |
1727 QString | |
1728 MainWindowBase::RemovePaneCommand::getName() const | |
1729 { | |
1730 return tr("Remove Pane"); | |
1731 } | |
1732 | |
1733 void | |
1734 MainWindowBase::RemovePaneCommand::execute() | |
1735 { | |
1736 m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane(); | |
1737 m_mw->m_paneStack->hidePane(m_pane); | |
1738 m_added = false; | |
1739 } | |
1740 | |
1741 void | |
1742 MainWindowBase::RemovePaneCommand::unexecute() | |
1743 { | |
1744 m_mw->m_paneStack->showPane(m_pane); | |
1745 m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane); | |
1746 m_added = true; | |
1747 } | |
1748 | |
1749 void | |
1750 MainWindowBase::deleteCurrentPane() | |
1751 { | |
1752 CommandHistory::getInstance()->startCompoundOperation | |
1753 (tr("Delete Pane"), true); | |
1754 | |
1755 Pane *pane = m_paneStack->getCurrentPane(); | |
1756 if (pane) { | |
1757 while (pane->getLayerCount() > 0) { | |
1758 Layer *layer = pane->getLayer(0); | |
1759 if (layer) { | |
1760 m_document->removeLayerFromView(pane, layer); | |
1761 } else { | |
1762 break; | |
1763 } | |
1764 } | |
1765 | |
1766 RemovePaneCommand *command = new RemovePaneCommand(this, pane); | |
1767 CommandHistory::getInstance()->addCommand(command); | |
1768 } | |
1769 | |
1770 CommandHistory::getInstance()->endCompoundOperation(); | |
1771 | |
1772 updateMenuStates(); | |
1773 } | |
1774 | |
1775 void | |
1776 MainWindowBase::deleteCurrentLayer() | |
1777 { | |
1778 Pane *pane = m_paneStack->getCurrentPane(); | |
1779 if (pane) { | |
1780 Layer *layer = pane->getSelectedLayer(); | |
1781 if (layer) { | |
1782 m_document->removeLayerFromView(pane, layer); | |
1783 } | |
1784 } | |
1785 updateMenuStates(); | |
1786 } | |
1787 | |
1788 void | |
1789 MainWindowBase::playbackFrameChanged(unsigned long frame) | |
1790 { | |
1791 if (!(m_playSource && m_playSource->isPlaying()) || !getMainModel()) return; | |
1792 | |
1793 RealTime now = RealTime::frame2RealTime | |
1794 (frame, getMainModel()->getSampleRate()); | |
1795 | |
1796 if (now.sec == m_lastPlayStatusSec) return; | |
1797 | |
1798 RealTime then = RealTime::frame2RealTime | |
1799 (m_playSource->getPlayEndFrame(), getMainModel()->getSampleRate()); | |
1800 | |
1801 QString nowStr; | |
1802 QString thenStr; | |
1803 QString remainingStr; | |
1804 | |
1805 if (then.sec > 10) { | |
1806 nowStr = now.toSecText().c_str(); | |
1807 thenStr = then.toSecText().c_str(); | |
1808 remainingStr = (then - now).toSecText().c_str(); | |
1809 m_lastPlayStatusSec = now.sec; | |
1810 } else { | |
1811 nowStr = now.toText(true).c_str(); | |
1812 thenStr = then.toText(true).c_str(); | |
1813 remainingStr = (then - now).toText(true).c_str(); | |
1814 } | |
1815 | |
1816 m_myStatusMessage = tr("Playing: %1 of %2 (%3 remaining)") | |
1817 .arg(nowStr).arg(thenStr).arg(remainingStr); | |
1818 | |
1819 statusBar()->showMessage(m_myStatusMessage); | |
1820 } | |
1821 | |
1822 void | |
1823 MainWindowBase::globalCentreFrameChanged(unsigned long ) | |
1824 { | |
1825 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return; | |
1826 Pane *p = 0; | |
1827 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return; | |
1828 if (!p->getFollowGlobalPan()) return; | |
1829 updateVisibleRangeDisplay(p); | |
1830 } | |
1831 | |
1832 void | |
1833 MainWindowBase::viewCentreFrameChanged(View *v, unsigned long ) | |
1834 { | |
1835 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return; | |
1836 Pane *p = 0; | |
1837 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return; | |
1838 if (v == p) updateVisibleRangeDisplay(p); | |
1839 } | |
1840 | |
1841 void | |
1842 MainWindowBase::viewZoomLevelChanged(View *v, unsigned long , bool ) | |
1843 { | |
1844 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return; | |
1845 Pane *p = 0; | |
1846 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return; | |
1847 if (v == p) updateVisibleRangeDisplay(p); | |
1848 } | |
1849 | |
1850 void | |
1851 MainWindowBase::layerAdded(Layer *) | |
1852 { | |
1853 // std::cerr << "MainWindowBase::layerAdded(" << layer << ")" << std::endl; | |
1854 updateMenuStates(); | |
1855 } | |
1856 | |
1857 void | |
1858 MainWindowBase::layerRemoved(Layer *) | |
1859 { | |
1860 // std::cerr << "MainWindowBase::layerRemoved(" << layer << ")" << std::endl; | |
1861 updateMenuStates(); | |
1862 } | |
1863 | |
1864 void | |
1865 MainWindowBase::layerAboutToBeDeleted(Layer *layer) | |
1866 { | |
1867 // std::cerr << "MainWindowBase::layerAboutToBeDeleted(" << layer << ")" << std::endl; | |
1868 if (layer == m_timeRulerLayer) { | |
1869 // std::cerr << "(this is the time ruler layer)" << std::endl; | |
1870 m_timeRulerLayer = 0; | |
1871 } | |
1872 } | |
1873 | |
1874 void | |
1875 MainWindowBase::layerInAView(Layer *layer, bool inAView) | |
1876 { | |
1877 // std::cerr << "MainWindowBase::layerInAView(" << layer << "," << inAView << ")" << std::endl; | |
1878 | |
1879 // Check whether we need to add or remove model from play source | |
1880 Model *model = layer->getModel(); | |
1881 if (model) { | |
1882 if (inAView) { | |
1883 m_playSource->addModel(model); | |
1884 } else { | |
1885 bool found = false; | |
1886 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) { | |
1887 Pane *pane = m_paneStack->getPane(i); | |
1888 if (!pane) continue; | |
1889 for (int j = 0; j < pane->getLayerCount(); ++j) { | |
1890 Layer *pl = pane->getLayer(j); | |
1891 if (pl && pl->getModel() == model) { | |
1892 found = true; | |
1893 break; | |
1894 } | |
1895 } | |
1896 if (found) break; | |
1897 } | |
1898 if (!found) m_playSource->removeModel(model); | |
1899 } | |
1900 } | |
1901 | |
1902 updateMenuStates(); | |
1903 } | |
1904 | |
1905 void | |
1906 MainWindowBase::modelAdded(Model *model) | |
1907 { | |
1908 // std::cerr << "MainWindowBase::modelAdded(" << model << ")" << std::endl; | |
1909 m_playSource->addModel(model); | |
1910 } | |
1911 | |
1912 void | |
1913 MainWindowBase::mainModelChanged(WaveFileModel *model) | |
1914 { | |
1915 // std::cerr << "MainWindowBase::mainModelChanged(" << model << ")" << std::endl; | |
1916 updateDescriptionLabel(); | |
1917 if (model) m_viewManager->setMainModelSampleRate(model->getSampleRate()); | |
1918 if (model && !m_playTarget && m_audioOutput) createPlayTarget(); | |
1919 } | |
1920 | |
1921 void | |
1922 MainWindowBase::modelAboutToBeDeleted(Model *model) | |
1923 { | |
1924 // std::cerr << "MainWindowBase::modelAboutToBeDeleted(" << model << ")" << std::endl; | |
1925 if (model == m_viewManager->getPlaybackModel()) { | |
1926 m_viewManager->setPlaybackModel(0); | |
1927 } | |
1928 m_playSource->removeModel(model); | |
1929 FFTDataServer::modelAboutToBeDeleted(model); | |
1930 } | |
1931 | |
1932 void | |
1933 MainWindowBase::pollOSC() | |
1934 { | |
1935 if (!m_oscQueue || m_oscQueue->isEmpty()) return; | |
1936 std::cerr << "MainWindowBase::pollOSC: have " << m_oscQueue->getMessagesAvailable() << " messages" << std::endl; | |
1937 | |
1938 if (m_openingAudioFile) return; | |
1939 | |
1940 OSCMessage message = m_oscQueue->readMessage(); | |
1941 | |
1942 if (message.getTarget() != 0) { | |
1943 return; //!!! for now -- this class is target 0, others not handled yet | |
1944 } | |
1945 | |
1946 handleOSCMessage(message); | |
1947 } | |
1948 | |
1949 void | |
1950 MainWindowBase::inProgressSelectionChanged() | |
1951 { | |
1952 Pane *currentPane = 0; | |
1953 if (m_paneStack) currentPane = m_paneStack->getCurrentPane(); | |
1954 if (currentPane) updateVisibleRangeDisplay(currentPane); | |
1955 } | |
1956 | |
1957 void | |
1958 MainWindowBase::contextHelpChanged(const QString &s) | |
1959 { | |
1960 if (s == "" && m_myStatusMessage != "") { | |
1961 statusBar()->showMessage(m_myStatusMessage); | |
1962 return; | |
1963 } | |
1964 statusBar()->showMessage(s); | |
1965 } | |
1966 | |
1967 void | |
1968 MainWindowBase::openHelpUrl(QString url) | |
1969 { | |
1970 // This method mostly lifted from Qt Assistant source code | |
1971 | |
1972 QProcess *process = new QProcess(this); | |
1973 connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater())); | |
1974 | |
1975 QStringList args; | |
1976 | |
1977 #ifdef Q_OS_MAC | |
1978 args.append(url); | |
1979 process->start("open", args); | |
1980 #else | |
1981 #ifdef Q_OS_WIN32 | |
1982 | |
1983 QString pf(getenv("ProgramFiles")); | |
1984 QString command = pf + QString("\\Internet Explorer\\IEXPLORE.EXE"); | |
1985 | |
1986 args.append(url); | |
1987 process->start(command, args); | |
1988 | |
1989 #else | |
1990 #ifdef Q_WS_X11 | |
1991 if (!qgetenv("KDE_FULL_SESSION").isEmpty()) { | |
1992 args.append("exec"); | |
1993 args.append(url); | |
1994 process->start("kfmclient", args); | |
1995 } else if (!qgetenv("BROWSER").isEmpty()) { | |
1996 args.append(url); | |
1997 process->start(qgetenv("BROWSER"), args); | |
1998 } else { | |
1999 args.append(url); | |
2000 process->start("firefox", args); | |
2001 } | |
2002 #endif | |
2003 #endif | |
2004 #endif | |
2005 } | |
2006 |