comparison main/MainWindow.cpp @ 200:1871581e4da9

* Split MainWindow out into MainWindowBase (pane stack management, basic file I/O etc) and MainWindow (widget structure, menus and actions etc)
author Chris Cannam
date Mon, 22 Oct 2007 14:24:31 +0000
parents 6e1d4d500092
children 0de89bce24e4
comparison
equal deleted inserted replaced
199:6e1d4d500092 200:1871581e4da9
2 2
3 /* 3 /*
4 Sonic Visualiser 4 Sonic Visualiser
5 An audio file viewer and annotation editor. 5 An audio file viewer and annotation editor.
6 Centre for Digital Music, Queen Mary, University of London. 6 Centre for Digital Music, Queen Mary, University of London.
7 This file copyright 2006 Chris Cannam and QMUL. 7 This file copyright 2006-2007 Chris Cannam and QMUL.
8 8
9 This program is free software; you can redistribute it and/or 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 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 11 published by the Free Software Foundation; either version 2 of the
12 License, or (at your option) any later version. See the file 12 License, or (at your option) any later version. See the file
68 #include "base/Clipboard.h" 68 #include "base/Clipboard.h"
69 #include "base/UnitDatabase.h" 69 #include "base/UnitDatabase.h"
70 #include "base/ColourDatabase.h" 70 #include "base/ColourDatabase.h"
71 #include "osc/OSCQueue.h" 71 #include "osc/OSCQueue.h"
72 72
73 //!!!
74 #include "data/model/AggregateWaveModel.h"
75
76 // For version information 73 // For version information
77 #include "vamp/vamp.h" 74 #include "vamp/vamp.h"
78 #include "vamp-sdk/PluginBase.h" 75 #include "vamp-sdk/PluginBase.h"
79 #include "plugin/api/ladspa.h" 76 #include "plugin/api/ladspa.h"
80 #include "plugin/api/dssi.h" 77 #include "plugin/api/dssi.h"
113 using std::map; 110 using std::map;
114 using std::set; 111 using std::set;
115 112
116 113
117 MainWindow::MainWindow(bool withAudioOutput, bool withOSCSupport) : 114 MainWindow::MainWindow(bool withAudioOutput, bool withOSCSupport) :
118 m_document(0), 115 MainWindowBase(withAudioOutput, withOSCSupport),
119 m_paneStack(0),
120 m_viewManager(0),
121 m_overview(0), 116 m_overview(0),
122 m_timeRulerLayer(0),
123 m_audioOutput(withAudioOutput),
124 m_playSource(0),
125 m_playTarget(0),
126 m_oscQueue(withOSCSupport ? new OSCQueue() : 0),
127 m_recentFiles("RecentFiles", 20),
128 m_recentTransforms("RecentTransforms", 20),
129 m_mainMenusCreated(false), 117 m_mainMenusCreated(false),
130 m_paneMenu(0), 118 m_paneMenu(0),
131 m_layerMenu(0), 119 m_layerMenu(0),
132 m_transformsMenu(0), 120 m_transformsMenu(0),
133 m_playbackMenu(0), 121 m_playbackMenu(0),
139 m_rightButtonLayerMenu(0), 127 m_rightButtonLayerMenu(0),
140 m_rightButtonTransformsMenu(0), 128 m_rightButtonTransformsMenu(0),
141 m_rightButtonPlaybackMenu(0), 129 m_rightButtonPlaybackMenu(0),
142 m_ffwdAction(0), 130 m_ffwdAction(0),
143 m_rwdAction(0), 131 m_rwdAction(0),
144 m_documentModified(false),
145 m_openingAudioFile(false),
146 m_abandoning(false),
147 m_labeller(0),
148 m_preferencesDialog(0), 132 m_preferencesDialog(0),
149 m_layerTreeView(0), 133 m_layerTreeView(0),
150 m_keyReference(new KeyReference()) 134 m_keyReference(new KeyReference())
151 { 135 {
152 setWindowTitle(tr("Sonic Visualiser")); 136 setWindowTitle(tr("Sonic Visualiser"));
168 cdb->setUseDarkBackground(cdb->addColour(QColor(30, 150, 255), tr("Bright Blue")), true); 152 cdb->setUseDarkBackground(cdb->addColour(QColor(30, 150, 255), tr("Bright Blue")), true);
169 cdb->setUseDarkBackground(cdb->addColour(Qt::green, tr("Bright Green")), true); 153 cdb->setUseDarkBackground(cdb->addColour(Qt::green, tr("Bright Green")), true);
170 cdb->setUseDarkBackground(cdb->addColour(QColor(225, 74, 255), tr("Bright Purple")), true); 154 cdb->setUseDarkBackground(cdb->addColour(QColor(225, 74, 255), tr("Bright Purple")), true);
171 cdb->setUseDarkBackground(cdb->addColour(QColor(255, 188, 80), tr("Bright Orange")), true); 155 cdb->setUseDarkBackground(cdb->addColour(QColor(255, 188, 80), tr("Bright Orange")), true);
172 156
173 connect(CommandHistory::getInstance(), SIGNAL(commandExecuted()),
174 this, SLOT(documentModified()));
175 connect(CommandHistory::getInstance(), SIGNAL(documentRestored()),
176 this, SLOT(documentRestored()));
177
178 QFrame *frame = new QFrame; 157 QFrame *frame = new QFrame;
179 setCentralWidget(frame); 158 setCentralWidget(frame);
180 159
181 QGridLayout *layout = new QGridLayout; 160 QGridLayout *layout = new QGridLayout;
182
183 m_viewManager = new ViewManager();
184 connect(m_viewManager, SIGNAL(selectionChanged()),
185 this, SLOT(updateMenuStates()));
186 connect(m_viewManager, SIGNAL(inProgressSelectionChanged()),
187 this, SLOT(inProgressSelectionChanged()));
188
189 Preferences::BackgroundMode mode =
190 Preferences::getInstance()->getBackgroundMode();
191 m_initialDarkBackground = m_viewManager->getGlobalDarkBackground();
192 if (mode != Preferences::BackgroundFromTheme) {
193 m_viewManager->setGlobalDarkBackground
194 (mode == Preferences::DarkBackground);
195 }
196 161
197 m_descriptionLabel = new QLabel; 162 m_descriptionLabel = new QLabel;
198 163
199 QScrollArea *scroll = new QScrollArea(frame); 164 QScrollArea *scroll = new QScrollArea(frame);
200 scroll->setWidgetResizable(true); 165 scroll->setWidgetResizable(true);
201 scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 166 scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
202 scroll->setFrameShape(QFrame::NoFrame); 167 scroll->setFrameShape(QFrame::NoFrame);
203
204 m_paneStack = new PaneStack(scroll, m_viewManager);
205 connect(m_paneStack, SIGNAL(currentPaneChanged(Pane *)),
206 this, SLOT(currentPaneChanged(Pane *)));
207 connect(m_paneStack, SIGNAL(currentLayerChanged(Pane *, Layer *)),
208 this, SLOT(currentLayerChanged(Pane *, Layer *)));
209 connect(m_paneStack, SIGNAL(rightButtonMenuRequested(Pane *, QPoint)),
210 this, SLOT(rightButtonMenuRequested(Pane *, QPoint)));
211 connect(m_paneStack, SIGNAL(propertyStacksResized()),
212 this, SLOT(propertyStacksResized()));
213 connect(m_paneStack, SIGNAL(contextHelpChanged(const QString &)),
214 this, SLOT(contextHelpChanged(const QString &)));
215 connect(m_paneStack, SIGNAL(dropAccepted(Pane *, QStringList)),
216 this, SLOT(paneDropAccepted(Pane *, QStringList)));
217 connect(m_paneStack, SIGNAL(dropAccepted(Pane *, QString)),
218 this, SLOT(paneDropAccepted(Pane *, QString)));
219 168
220 scroll->setWidget(m_paneStack); 169 scroll->setWidget(m_paneStack);
221 170
222 m_overview = new Overview(frame); 171 m_overview = new Overview(frame);
223 m_overview->setViewManager(m_viewManager); 172 m_overview->setViewManager(m_viewManager);
240 m_panLayer->setBaseColour 189 m_panLayer->setBaseColour
241 (ColourDatabase::getInstance()->getColourIndex(tr("Bright Green"))); 190 (ColourDatabase::getInstance()->getColourIndex(tr("Bright Green")));
242 } else { 191 } else {
243 m_panLayer->setBaseColour 192 m_panLayer->setBaseColour
244 (ColourDatabase::getInstance()->getColourIndex(tr("Green"))); 193 (ColourDatabase::getInstance()->getColourIndex(tr("Green")));
245 } 194 }
246
247 m_playSource = new AudioCallbackPlaySource(m_viewManager);
248
249 connect(m_playSource, SIGNAL(sampleRateMismatch(size_t, size_t, bool)),
250 this, SLOT(sampleRateMismatch(size_t, size_t, bool)));
251 connect(m_playSource, SIGNAL(audioOverloadPluginDisabled()),
252 this, SLOT(audioOverloadPluginDisabled()));
253 195
254 m_fader = new Fader(frame, false); 196 m_fader = new Fader(frame, false);
255 connect(m_fader, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget())); 197 connect(m_fader, SIGNAL(mouseEntered()), this, SLOT(mouseEnteredWidget()));
256 connect(m_fader, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget())); 198 connect(m_fader, SIGNAL(mouseLeft()), this, SLOT(mouseLeftWidget()));
257 199
316 258
317 layout->setColumnStretch(0, 10); 259 layout->setColumnStretch(0, 10);
318 260
319 frame->setLayout(layout); 261 frame->setLayout(layout);
320 262
321 connect(m_viewManager, SIGNAL(outputLevelsChanged(float, float)),
322 this, SLOT(outputLevelsChanged(float, float)));
323
324 connect(m_viewManager, SIGNAL(playbackFrameChanged(unsigned long)),
325 this, SLOT(playbackFrameChanged(unsigned long)));
326
327 connect(m_viewManager, SIGNAL(globalCentreFrameChanged(unsigned long)),
328 this, SLOT(globalCentreFrameChanged(unsigned long)));
329
330 connect(m_viewManager, SIGNAL(viewCentreFrameChanged(View *, unsigned long)),
331 this, SLOT(viewCentreFrameChanged(View *, unsigned long)));
332
333 connect(m_viewManager, SIGNAL(viewZoomLevelChanged(View *, unsigned long, bool)),
334 this, SLOT(viewZoomLevelChanged(View *, unsigned long, bool)));
335
336 connect(Preferences::getInstance(),
337 SIGNAL(propertyChanged(PropertyContainer::PropertyName)),
338 this,
339 SLOT(preferenceChanged(PropertyContainer::PropertyName)));
340
341 // preferenceChanged("Property Box Layout");
342
343 if (m_oscQueue && m_oscQueue->isOK()) {
344 connect(m_oscQueue, SIGNAL(messagesAvailable()), this, SLOT(pollOSC()));
345 QTimer *oscTimer = new QTimer(this);
346 connect(oscTimer, SIGNAL(timeout()), this, SLOT(pollOSC()));
347 oscTimer->start(1000);
348 }
349
350 Labeller::ValueType labellerType = Labeller::ValueFromTwoLevelCounter;
351 settings.beginGroup("MainWindow");
352 labellerType = (Labeller::ValueType)
353 settings.value("labellertype", (int)labellerType).toInt();
354 int cycle = settings.value("labellercycle", 4).toInt();
355 settings.endGroup();
356
357 m_labeller = new Labeller(labellerType);
358 m_labeller->setCounterCycleSize(cycle);
359
360 setupMenus(); 263 setupMenus();
361 setupToolbars(); 264 setupToolbars();
362 setupHelpMenu(); 265 setupHelpMenu();
363 266
364 statusBar(); 267 statusBar();
366 newSession(); 269 newSession();
367 } 270 }
368 271
369 MainWindow::~MainWindow() 272 MainWindow::~MainWindow()
370 { 273 {
371 // std::cerr << "MainWindow::~MainWindow()" << std::endl;
372
373 if (!m_abandoning) {
374 closeSession();
375 }
376 delete m_playTarget;
377 delete m_playSource;
378 delete m_viewManager;
379 delete m_oscQueue;
380 delete m_keyReference; 274 delete m_keyReference;
381 delete m_preferencesDialog; 275 delete m_preferencesDialog;
382 delete m_layerTreeView; 276 delete m_layerTreeView;
383 Profiles::getInstance()->dump(); 277 Profiles::getInstance()->dump();
384 }
385
386 QString
387 MainWindow::getOpenFileName(FileFinder::FileType type)
388 {
389 FileFinder *ff = FileFinder::getInstance();
390 switch (type) {
391 case FileFinder::SessionFile:
392 return ff->getOpenFileName(type, m_sessionFile);
393 case FileFinder::AudioFile:
394 return ff->getOpenFileName(type, m_audioFile);
395 case FileFinder::LayerFile:
396 return ff->getOpenFileName(type, m_sessionFile);
397 case FileFinder::LayerFileNoMidi:
398 return ff->getOpenFileName(type, m_sessionFile);
399 case FileFinder::SessionOrAudioFile:
400 return ff->getOpenFileName(type, m_sessionFile);
401 case FileFinder::ImageFile:
402 return ff->getOpenFileName(type, m_sessionFile);
403 case FileFinder::AnyFile:
404 if (getMainModel() != 0 &&
405 m_paneStack != 0 &&
406 m_paneStack->getCurrentPane() != 0) { // can import a layer
407 return ff->getOpenFileName(FileFinder::AnyFile, m_sessionFile);
408 } else {
409 return ff->getOpenFileName(FileFinder::SessionOrAudioFile,
410 m_sessionFile);
411 }
412 }
413 return "";
414 }
415
416 QString
417 MainWindow::getSaveFileName(FileFinder::FileType type)
418 {
419 FileFinder *ff = FileFinder::getInstance();
420 switch (type) {
421 case FileFinder::SessionFile:
422 return ff->getSaveFileName(type, m_sessionFile);
423 case FileFinder::AudioFile:
424 return ff->getSaveFileName(type, m_audioFile);
425 case FileFinder::LayerFile:
426 return ff->getSaveFileName(type, m_sessionFile);
427 case FileFinder::LayerFileNoMidi:
428 return ff->getSaveFileName(type, m_sessionFile);
429 case FileFinder::SessionOrAudioFile:
430 return ff->getSaveFileName(type, m_sessionFile);
431 case FileFinder::ImageFile:
432 return ff->getSaveFileName(type, m_sessionFile);
433 case FileFinder::AnyFile:
434 return ff->getSaveFileName(type, m_sessionFile);
435 }
436 return "";
437 }
438
439 void
440 MainWindow::registerLastOpenedFilePath(FileFinder::FileType type, QString path)
441 {
442 FileFinder *ff = FileFinder::getInstance();
443 ff->registerLastOpenedFilePath(type, path);
444 } 278 }
445 279
446 void 280 void
447 MainWindow::setupMenus() 281 MainWindow::setupMenus()
448 { 282 {
775 609
776 QMenu *cycleMenu = numberingMenu->addMenu(tr("Cycle size")); 610 QMenu *cycleMenu = numberingMenu->addMenu(tr("Cycle size"));
777 QActionGroup *cycleGroup = new QActionGroup(this); 611 QActionGroup *cycleGroup = new QActionGroup(this);
778 612
779 int cycles[] = { 2, 3, 4, 5, 6, 7, 8, 10, 12, 16 }; 613 int cycles[] = { 2, 3, 4, 5, 6, 7, 8, 10, 12, 16 };
780 for (int i = 0; i < sizeof(cycles)/sizeof(cycles[0]); ++i) { 614 for (int i = 0; i < int(sizeof(cycles)/sizeof(cycles[0])); ++i) {
781 action = new QAction(QString("%1").arg(cycles[i]), this); 615 action = new QAction(QString("%1").arg(cycles[i]), this);
782 connect(action, SIGNAL(triggered()), this, SLOT(setInstantsCounterCycle())); 616 connect(action, SIGNAL(triggered()), this, SLOT(setInstantsCounterCycle()));
783 action->setCheckable(true); 617 action->setCheckable(true);
784 action->setChecked(cycles[i] == m_labeller->getCounterCycleSize()); 618 action->setChecked(cycles[i] == m_labeller->getCounterCycleSize());
785 cycleGroup->addAction(action); 619 cycleGroup->addAction(action);
1907 } 1741 }
1908 1742
1909 void 1743 void
1910 MainWindow::updateMenuStates() 1744 MainWindow::updateMenuStates()
1911 { 1745 {
1746 MainWindowBase::updateMenuStates();
1747
1912 Pane *currentPane = 0; 1748 Pane *currentPane = 0;
1913 Layer *currentLayer = 0; 1749 Layer *currentLayer = 0;
1914 1750
1915 if (m_paneStack) currentPane = m_paneStack->getCurrentPane(); 1751 if (m_paneStack) currentPane = m_paneStack->getCurrentPane();
1916 if (currentPane) currentLayer = currentPane->getSelectedLayer(); 1752 if (currentPane) currentLayer = currentPane->getSelectedLayer();
1918 bool haveCurrentPane = 1754 bool haveCurrentPane =
1919 (currentPane != 0); 1755 (currentPane != 0);
1920 bool haveCurrentLayer = 1756 bool haveCurrentLayer =
1921 (haveCurrentPane && 1757 (haveCurrentPane &&
1922 (currentLayer != 0)); 1758 (currentLayer != 0));
1923 bool haveMainModel =
1924 (getMainModel() != 0);
1925 bool havePlayTarget =
1926 (m_playTarget != 0);
1927 bool haveSelection = 1759 bool haveSelection =
1928 (m_viewManager && 1760 (m_viewManager &&
1929 !m_viewManager->getSelections().empty()); 1761 !m_viewManager->getSelections().empty());
1930 bool haveCurrentEditableLayer = 1762 bool haveCurrentEditableLayer =
1931 (haveCurrentLayer && 1763 (haveCurrentLayer &&
1934 (haveCurrentLayer && 1766 (haveCurrentLayer &&
1935 dynamic_cast<TimeInstantLayer *>(currentLayer)); 1767 dynamic_cast<TimeInstantLayer *>(currentLayer));
1936 bool haveCurrentTimeValueLayer = 1768 bool haveCurrentTimeValueLayer =
1937 (haveCurrentLayer && 1769 (haveCurrentLayer &&
1938 dynamic_cast<TimeValueLayer *>(currentLayer)); 1770 dynamic_cast<TimeValueLayer *>(currentLayer));
1939 bool haveCurrentColour3DPlot = 1771
1940 (haveCurrentLayer && 1772 emit canChangePlaybackSpeed(true);
1941 dynamic_cast<Colour3DPlotLayer *>(currentLayer)); 1773 int v = m_playSpeed->value();
1942 bool haveClipboardContents = 1774 emit canSpeedUpPlayback(v < m_playSpeed->maximum());
1943 (m_viewManager && 1775 emit canSlowDownPlayback(v > m_playSpeed->minimum());
1944 !m_viewManager->getClipboard().empty());
1945
1946 emit canAddPane(haveMainModel);
1947 emit canDeleteCurrentPane(haveCurrentPane);
1948 emit canZoom(haveMainModel && haveCurrentPane);
1949 emit canScroll(haveMainModel && haveCurrentPane);
1950 emit canAddLayer(haveMainModel && haveCurrentPane);
1951 emit canImportMoreAudio(haveMainModel);
1952 emit canImportLayer(haveMainModel && haveCurrentPane);
1953 emit canExportAudio(haveMainModel);
1954 emit canExportLayer(haveMainModel &&
1955 (haveCurrentEditableLayer || haveCurrentColour3DPlot));
1956 emit canExportImage(haveMainModel && haveCurrentPane);
1957 emit canDeleteCurrentLayer(haveCurrentLayer);
1958 emit canRenameLayer(haveCurrentLayer);
1959 emit canEditLayer(haveCurrentEditableLayer);
1960 emit canMeasureLayer(haveCurrentLayer);
1961 emit canSelect(haveMainModel && haveCurrentPane);
1962 emit canPlay(havePlayTarget);
1963 emit canFfwd(true);
1964 emit canRewind(true);
1965 emit canPaste(haveCurrentEditableLayer && haveClipboardContents);
1966 emit canInsertInstant(haveCurrentPane);
1967 emit canInsertInstantsAtBoundaries(haveCurrentPane && haveSelection);
1968 emit canRenumberInstants(haveCurrentTimeInstantsLayer && haveSelection);
1969 emit canPlaySelection(haveMainModel && havePlayTarget && haveSelection);
1970 emit canClearSelection(haveSelection);
1971 emit canEditSelection(haveSelection && haveCurrentEditableLayer);
1972 emit canSave(m_sessionFile != "" && m_documentModified);
1973 1776
1974 if (m_viewManager && 1777 if (m_viewManager &&
1975 (m_viewManager->getToolMode() == ViewManager::MeasureMode)) { 1778 (m_viewManager->getToolMode() == ViewManager::MeasureMode)) {
1976 emit canDeleteSelection(haveCurrentLayer); 1779 emit canDeleteSelection(haveCurrentLayer);
1977 m_deleteSelectedAction->setText(tr("&Delete Current Measurement")); 1780 m_deleteSelectedAction->setText(tr("&Delete Current Measurement"));
1979 } else { 1782 } else {
1980 emit canDeleteSelection(haveSelection && haveCurrentEditableLayer); 1783 emit canDeleteSelection(haveSelection && haveCurrentEditableLayer);
1981 m_deleteSelectedAction->setText(tr("&Delete Selected Items")); 1784 m_deleteSelectedAction->setText(tr("&Delete Selected Items"));
1982 m_deleteSelectedAction->setStatusTip(tr("Delete items in current selection from the current layer")); 1785 m_deleteSelectedAction->setStatusTip(tr("Delete items in current selection from the current layer"));
1983 } 1786 }
1984
1985 emit canChangePlaybackSpeed(true);
1986 int v = m_playSpeed->value();
1987 emit canSpeedUpPlayback(v < m_playSpeed->maximum());
1988 emit canSlowDownPlayback(v > m_playSpeed->minimum());
1989 1787
1990 if (m_ffwdAction && m_rwdAction) { 1788 if (m_ffwdAction && m_rwdAction) {
1991 if (haveCurrentTimeInstantsLayer) { 1789 if (haveCurrentTimeInstantsLayer) {
1992 m_ffwdAction->setText(tr("Fast Forward to Next Instant")); 1790 m_ffwdAction->setText(tr("Fast Forward to Next Instant"));
1993 m_ffwdAction->setStatusTip(tr("Fast forward to the next time instant in the current layer")); 1791 m_ffwdAction->setStatusTip(tr("Fast forward to the next time instant in the current layer"));
2036 } 1834 }
2037 1835
2038 void 1836 void
2039 MainWindow::documentModified() 1837 MainWindow::documentModified()
2040 { 1838 {
2041 // std::cerr << "MainWindow::documentModified" << std::endl; 1839 //!!!
2042 1840 MainWindowBase::documentModified();
2043 if (!m_documentModified) {
2044 setWindowTitle(tr("%1 (modified)").arg(windowTitle()));
2045 }
2046
2047 m_documentModified = true;
2048 updateMenuStates();
2049 } 1841 }
2050 1842
2051 void 1843 void
2052 MainWindow::documentRestored() 1844 MainWindow::documentRestored()
2053 { 1845 {
2054 // std::cerr << "MainWindow::documentRestored" << std::endl; 1846 //!!!
2055 1847 MainWindowBase::documentRestored();
2056 if (m_documentModified) {
2057 QString wt(windowTitle());
2058 wt.replace(tr(" (modified)"), "");
2059 setWindowTitle(wt);
2060 }
2061
2062 m_documentModified = false;
2063 updateMenuStates();
2064 }
2065
2066 void
2067 MainWindow::playLoopToggled()
2068 {
2069 QAction *action = dynamic_cast<QAction *>(sender());
2070
2071 if (action) {
2072 m_viewManager->setPlayLoopMode(action->isChecked());
2073 } else {
2074 m_viewManager->setPlayLoopMode(!m_viewManager->getPlayLoopMode());
2075 }
2076 }
2077
2078 void
2079 MainWindow::playSelectionToggled()
2080 {
2081 QAction *action = dynamic_cast<QAction *>(sender());
2082
2083 if (action) {
2084 m_viewManager->setPlaySelectionMode(action->isChecked());
2085 } else {
2086 m_viewManager->setPlaySelectionMode(!m_viewManager->getPlaySelectionMode());
2087 }
2088 }
2089
2090 void
2091 MainWindow::playSoloToggled()
2092 {
2093 QAction *action = dynamic_cast<QAction *>(sender());
2094
2095 if (action) {
2096 m_viewManager->setPlaySoloMode(action->isChecked());
2097 } else {
2098 m_viewManager->setPlaySoloMode(!m_viewManager->getPlaySoloMode());
2099 }
2100
2101 if (m_viewManager->getPlaySoloMode()) {
2102 currentPaneChanged(m_paneStack->getCurrentPane());
2103 } else {
2104 m_viewManager->setPlaybackModel(0);
2105 if (m_playSource) {
2106 m_playSource->clearSoloModelSet();
2107 }
2108 }
2109 }
2110
2111 void
2112 MainWindow::currentPaneChanged(Pane *p)
2113 {
2114 updateMenuStates();
2115 updateVisibleRangeDisplay(p);
2116
2117 if (!p) return;
2118
2119 if (!(m_viewManager &&
2120 m_playSource &&
2121 m_viewManager->getPlaySoloMode())) {
2122 if (m_viewManager) m_viewManager->setPlaybackModel(0);
2123 return;
2124 }
2125
2126 Model *prevPlaybackModel = m_viewManager->getPlaybackModel();
2127
2128 View::ModelSet soloModels = p->getModels();
2129
2130 for (View::ModelSet::iterator mi = soloModels.begin();
2131 mi != soloModels.end(); ++mi) {
2132 if (dynamic_cast<RangeSummarisableTimeValueModel *>(*mi)) {
2133 m_viewManager->setPlaybackModel(*mi);
2134 }
2135 }
2136
2137 RangeSummarisableTimeValueModel *a =
2138 dynamic_cast<RangeSummarisableTimeValueModel *>(prevPlaybackModel);
2139 RangeSummarisableTimeValueModel *b =
2140 dynamic_cast<RangeSummarisableTimeValueModel *>(m_viewManager->
2141 getPlaybackModel());
2142
2143 m_playSource->setSoloModelSet(soloModels);
2144
2145 if (a && b && (a != b)) {
2146 int frame = m_playSource->getCurrentPlayingFrame();
2147 //!!! I don't really believe that these functions are the right way around
2148 int rframe = a->alignFromReference(frame);
2149 int bframe = b->alignToReference(rframe);
2150 if (m_playSource->isPlaying()) m_playSource->play(bframe);
2151 }
2152 }
2153
2154 void
2155 MainWindow::currentLayerChanged(Pane *p, Layer *)
2156 {
2157 updateMenuStates();
2158 updateVisibleRangeDisplay(p);
2159 } 1848 }
2160 1849
2161 void 1850 void
2162 MainWindow::toolNavigateSelected() 1851 MainWindow::toolNavigateSelected()
2163 { 1852 {
2191 //void 1880 //void
2192 //MainWindow::toolTextSelected() 1881 //MainWindow::toolTextSelected()
2193 //{ 1882 //{
2194 // m_viewManager->setToolMode(ViewManager::TextMode); 1883 // m_viewManager->setToolMode(ViewManager::TextMode);
2195 //} 1884 //}
2196
2197 void
2198 MainWindow::selectAll()
2199 {
2200 if (!getMainModel()) return;
2201 m_viewManager->setSelection(Selection(getMainModel()->getStartFrame(),
2202 getMainModel()->getEndFrame()));
2203 }
2204
2205 void
2206 MainWindow::selectToStart()
2207 {
2208 if (!getMainModel()) return;
2209 m_viewManager->setSelection(Selection(getMainModel()->getStartFrame(),
2210 m_viewManager->getGlobalCentreFrame()));
2211 }
2212
2213 void
2214 MainWindow::selectToEnd()
2215 {
2216 if (!getMainModel()) return;
2217 m_viewManager->setSelection(Selection(m_viewManager->getGlobalCentreFrame(),
2218 getMainModel()->getEndFrame()));
2219 }
2220
2221 void
2222 MainWindow::selectVisible()
2223 {
2224 Model *model = getMainModel();
2225 if (!model) return;
2226
2227 Pane *currentPane = m_paneStack->getCurrentPane();
2228 if (!currentPane) return;
2229
2230 size_t startFrame, endFrame;
2231
2232 if (currentPane->getStartFrame() < 0) startFrame = 0;
2233 else startFrame = currentPane->getStartFrame();
2234
2235 if (currentPane->getEndFrame() > model->getEndFrame()) endFrame = model->getEndFrame();
2236 else endFrame = currentPane->getEndFrame();
2237
2238 m_viewManager->setSelection(Selection(startFrame, endFrame));
2239 }
2240
2241 void
2242 MainWindow::clearSelection()
2243 {
2244 m_viewManager->clearSelections();
2245 }
2246
2247 void
2248 MainWindow::cut()
2249 {
2250 Pane *currentPane = m_paneStack->getCurrentPane();
2251 if (!currentPane) return;
2252
2253 Layer *layer = currentPane->getSelectedLayer();
2254 if (!layer) return;
2255
2256 Clipboard &clipboard = m_viewManager->getClipboard();
2257 clipboard.clear();
2258
2259 MultiSelection::SelectionList selections = m_viewManager->getSelections();
2260
2261 CommandHistory::getInstance()->startCompoundOperation(tr("Cut"), true);
2262
2263 for (MultiSelection::SelectionList::iterator i = selections.begin();
2264 i != selections.end(); ++i) {
2265 layer->copy(*i, clipboard);
2266 layer->deleteSelection(*i);
2267 }
2268
2269 CommandHistory::getInstance()->endCompoundOperation();
2270 }
2271
2272 void
2273 MainWindow::copy()
2274 {
2275 Pane *currentPane = m_paneStack->getCurrentPane();
2276 if (!currentPane) return;
2277
2278 Layer *layer = currentPane->getSelectedLayer();
2279 if (!layer) return;
2280
2281 Clipboard &clipboard = m_viewManager->getClipboard();
2282 clipboard.clear();
2283
2284 MultiSelection::SelectionList selections = m_viewManager->getSelections();
2285
2286 for (MultiSelection::SelectionList::iterator i = selections.begin();
2287 i != selections.end(); ++i) {
2288 layer->copy(*i, clipboard);
2289 }
2290 }
2291
2292 void
2293 MainWindow::paste()
2294 {
2295 Pane *currentPane = m_paneStack->getCurrentPane();
2296 if (!currentPane) return;
2297
2298 //!!! if we have no current layer, we should create one of the most
2299 // appropriate type
2300
2301 Layer *layer = currentPane->getSelectedLayer();
2302 if (!layer) return;
2303
2304 Clipboard &clipboard = m_viewManager->getClipboard();
2305 Clipboard::PointList contents = clipboard.getPoints();
2306 /*
2307 long minFrame = 0;
2308 bool have = false;
2309 for (int i = 0; i < contents.size(); ++i) {
2310 if (!contents[i].haveFrame()) continue;
2311 if (!have || contents[i].getFrame() < minFrame) {
2312 minFrame = contents[i].getFrame();
2313 have = true;
2314 }
2315 }
2316
2317 long frameOffset = long(m_viewManager->getGlobalCentreFrame()) - minFrame;
2318
2319 layer->paste(clipboard, frameOffset);
2320 */
2321 layer->paste(clipboard, 0, true);
2322 }
2323
2324 void
2325 MainWindow::deleteSelected()
2326 {
2327 if (m_paneStack->getCurrentPane() &&
2328 m_paneStack->getCurrentPane()->getSelectedLayer()) {
2329
2330 Layer *layer = m_paneStack->getCurrentPane()->getSelectedLayer();
2331
2332 if (m_viewManager &&
2333 (m_viewManager->getToolMode() == ViewManager::MeasureMode)) {
2334
2335 layer->deleteCurrentMeasureRect();
2336
2337 } else {
2338
2339 MultiSelection::SelectionList selections =
2340 m_viewManager->getSelections();
2341
2342 for (MultiSelection::SelectionList::iterator i = selections.begin();
2343 i != selections.end(); ++i) {
2344 layer->deleteSelection(*i);
2345 }
2346 }
2347 }
2348 }
2349
2350 void
2351 MainWindow::insertInstant()
2352 {
2353 int frame = m_viewManager->getPlaybackFrame();
2354 insertInstantAt(frame);
2355 }
2356
2357 void
2358 MainWindow::insertInstantsAtBoundaries()
2359 {
2360 MultiSelection::SelectionList selections = m_viewManager->getSelections();
2361 for (MultiSelection::SelectionList::iterator i = selections.begin();
2362 i != selections.end(); ++i) {
2363 size_t start = i->getStartFrame();
2364 size_t end = i->getEndFrame();
2365 if (start != end) {
2366 insertInstantAt(i->getStartFrame());
2367 insertInstantAt(i->getEndFrame());
2368 }
2369 }
2370 }
2371
2372 void
2373 MainWindow::insertInstantAt(size_t frame)
2374 {
2375 Pane *pane = m_paneStack->getCurrentPane();
2376 if (!pane) {
2377 return;
2378 }
2379
2380 Layer *layer = dynamic_cast<TimeInstantLayer *>
2381 (pane->getSelectedLayer());
2382
2383 if (!layer) {
2384 for (int i = pane->getLayerCount(); i > 0; --i) {
2385 layer = dynamic_cast<TimeInstantLayer *>(pane->getLayer(i - 1));
2386 if (layer) break;
2387 }
2388
2389 if (!layer) {
2390 CommandHistory::getInstance()->startCompoundOperation
2391 (tr("Add Point"), true);
2392 layer = m_document->createEmptyLayer(LayerFactory::TimeInstants);
2393 if (layer) {
2394 m_document->addLayerToView(pane, layer);
2395 m_paneStack->setCurrentLayer(pane, layer);
2396 }
2397 CommandHistory::getInstance()->endCompoundOperation();
2398 }
2399 }
2400
2401 if (layer) {
2402
2403 Model *model = layer->getModel();
2404 SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *>
2405 (model);
2406
2407 if (sodm) {
2408 SparseOneDimensionalModel::Point point(frame, "");
2409
2410 SparseOneDimensionalModel::Point prevPoint(0);
2411 bool havePrevPoint = false;
2412
2413 SparseOneDimensionalModel::EditCommand *command =
2414 new SparseOneDimensionalModel::EditCommand(sodm, tr("Add Point"));
2415
2416 if (m_labeller->actingOnPrevPoint()) {
2417
2418 SparseOneDimensionalModel::PointList prevPoints =
2419 sodm->getPreviousPoints(frame);
2420
2421 if (!prevPoints.empty()) {
2422 prevPoint = *prevPoints.begin();
2423 havePrevPoint = true;
2424 }
2425 }
2426
2427 if (m_labeller) {
2428
2429 m_labeller->setSampleRate(sodm->getSampleRate());
2430
2431 if (havePrevPoint) {
2432 command->deletePoint(prevPoint);
2433 }
2434
2435 m_labeller->label<SparseOneDimensionalModel::Point>
2436 (point, havePrevPoint ? &prevPoint : 0);
2437
2438 if (havePrevPoint) {
2439 command->addPoint(prevPoint);
2440 }
2441 }
2442
2443 command->addPoint(point);
2444
2445 command->setName(tr("Add Point at %1 s")
2446 .arg(RealTime::frame2RealTime
2447 (frame,
2448 sodm->getSampleRate())
2449 .toText(false).c_str()));
2450
2451 command->finish();
2452 }
2453 }
2454 }
2455
2456 void
2457 MainWindow::setInstantsNumbering()
2458 {
2459 QAction *a = dynamic_cast<QAction *>(sender());
2460 if (!a) return;
2461
2462 int type = m_numberingActions[a];
2463
2464 if (m_labeller) m_labeller->setType(Labeller::ValueType(type));
2465
2466 QSettings settings;
2467 settings.beginGroup("MainWindow");
2468 settings.setValue("labellertype", type);
2469 settings.endGroup();
2470 }
2471
2472 void
2473 MainWindow::setInstantsCounterCycle()
2474 {
2475 QAction *a = dynamic_cast<QAction *>(sender());
2476 if (!a) return;
2477
2478 int cycle = a->text().toInt();
2479 if (cycle == 0) return;
2480
2481 if (m_labeller) m_labeller->setCounterCycleSize(cycle);
2482
2483 QSettings settings;
2484 settings.beginGroup("MainWindow");
2485 settings.setValue("labellercycle", cycle);
2486 settings.endGroup();
2487 }
2488
2489 void
2490 MainWindow::resetInstantsCounters()
2491 {
2492 LabelCounterInputDialog dialog(m_labeller, this);
2493 dialog.exec();
2494 }
2495
2496 void
2497 MainWindow::renumberInstants()
2498 {
2499 Pane *pane = m_paneStack->getCurrentPane();
2500 if (!pane) return;
2501
2502 Layer *layer = dynamic_cast<TimeInstantLayer *>(pane->getSelectedLayer());
2503 if (!layer) return;
2504
2505 MultiSelection ms(m_viewManager->getSelection());
2506
2507 Model *model = layer->getModel();
2508 SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *>
2509 (model);
2510 if (!sodm) return;
2511
2512 if (!m_labeller) return;
2513
2514 Labeller labeller(*m_labeller);
2515 labeller.setSampleRate(sodm->getSampleRate());
2516
2517 // This uses a command
2518
2519 labeller.labelAll<SparseOneDimensionalModel::Point>(*sodm, &ms);
2520 }
2521 1885
2522 void 1886 void
2523 MainWindow::importAudio() 1887 MainWindow::importAudio()
2524 { 1888 {
2525 QString path = getOpenFileName(FileFinder::AudioFile); 1889 QString path = getOpenFileName(FileFinder::AudioFile);
2855 } 2219 }
2856 2220
2857 delete image; 2221 delete image;
2858 } 2222 }
2859 2223
2860 MainWindow::FileOpenStatus
2861 MainWindow::open(QString fileOrUrl, AudioFileOpenMode mode)
2862 {
2863 return open(FileSource(fileOrUrl), mode);
2864 }
2865
2866 MainWindow::FileOpenStatus
2867 MainWindow::open(FileSource source, AudioFileOpenMode mode)
2868 {
2869 FileOpenStatus status;
2870
2871 if (!source.isAvailable()) return FileOpenFailed;
2872 source.waitForData();
2873
2874 bool canImportLayer = (getMainModel() != 0 &&
2875 m_paneStack != 0 &&
2876 m_paneStack->getCurrentPane() != 0);
2877
2878 if ((status = openAudio(source, mode)) != FileOpenFailed) {
2879 return status;
2880 } else if ((status = openSession(source)) != FileOpenFailed) {
2881 return status;
2882 } else if ((status = openPlaylist(source, mode)) != FileOpenFailed) {
2883 return status;
2884 } else if (!canImportLayer) {
2885 return FileOpenWrongMode;
2886 } else if ((status = openImage(source)) != FileOpenFailed) {
2887 return status;
2888 } else if ((status = openLayer(source)) != FileOpenFailed) {
2889 return status;
2890 } else {
2891 return FileOpenFailed;
2892 }
2893 }
2894
2895 MainWindow::FileOpenStatus
2896 MainWindow::openAudio(FileSource source, AudioFileOpenMode mode)
2897 {
2898 std::cerr << "MainWindow::openAudio(" << source.getLocation().toStdString() << ")" << std::endl;
2899
2900 if (!source.isAvailable()) return FileOpenFailed;
2901 source.waitForData();
2902
2903 m_openingAudioFile = true;
2904
2905 size_t rate = 0;
2906
2907 if (Preferences::getInstance()->getResampleOnLoad()) {
2908 rate = m_playSource->getSourceSampleRate();
2909 }
2910
2911 WaveFileModel *newModel = new WaveFileModel(source, rate);
2912
2913 if (!newModel->isOK()) {
2914 delete newModel;
2915 m_openingAudioFile = false;
2916 return FileOpenFailed;
2917 }
2918
2919 std::cerr << "mode = " << mode << std::endl;
2920
2921 if (mode == AskUser) {
2922 if (getMainModel()) {
2923
2924 static bool prevSetAsMain = true;
2925 bool setAsMain = true;
2926
2927 QStringList items;
2928 items << tr("Replace the existing main waveform")
2929 << tr("Load this file into a new waveform pane");
2930
2931 bool ok = false;
2932 QString item = ListInputDialog::getItem
2933 (this, tr("Select target for import"),
2934 tr("You already have an audio waveform loaded.\nWhat would you like to do with the new audio file?"),
2935 items, prevSetAsMain ? 0 : 1, &ok);
2936
2937 if (!ok || item.isEmpty()) {
2938 delete newModel;
2939 m_openingAudioFile = false;
2940 return FileOpenCancelled;
2941 }
2942
2943 setAsMain = (item == items[0]);
2944 prevSetAsMain = setAsMain;
2945
2946 if (setAsMain) mode = ReplaceMainModel;
2947 else mode = CreateAdditionalModel;
2948
2949 } else {
2950 mode = ReplaceMainModel;
2951 }
2952 }
2953
2954 if (mode == ReplaceCurrentPane) {
2955
2956 Pane *pane = m_paneStack->getCurrentPane();
2957 if (pane) {
2958 if (getMainModel()) {
2959 View::ModelSet models(pane->getModels());
2960 if (models.find(getMainModel()) != models.end()) {
2961 mode = ReplaceMainModel;
2962 }
2963 } else {
2964 mode = ReplaceMainModel;
2965 }
2966 } else {
2967 mode = CreateAdditionalModel;
2968 }
2969 }
2970
2971 if (mode == CreateAdditionalModel && !getMainModel()) {
2972 mode = ReplaceMainModel;
2973 }
2974
2975 if (mode == ReplaceMainModel) {
2976
2977 Model *prevMain = getMainModel();
2978 if (prevMain) {
2979 m_playSource->removeModel(prevMain);
2980 PlayParameterRepository::getInstance()->removeModel(prevMain);
2981 }
2982 PlayParameterRepository::getInstance()->addModel(newModel);
2983
2984 m_document->setMainModel(newModel);
2985 setupMenus();
2986
2987 if (m_sessionFile == "") {
2988 setWindowTitle(tr("Sonic Visualiser: %1")
2989 .arg(source.getLocation()));
2990 CommandHistory::getInstance()->clear();
2991 CommandHistory::getInstance()->documentSaved();
2992 m_documentModified = false;
2993 } else {
2994 setWindowTitle(tr("Sonic Visualiser: %1 [%2]")
2995 .arg(QFileInfo(m_sessionFile).fileName())
2996 .arg(source.getLocation()));
2997 if (m_documentModified) {
2998 m_documentModified = false;
2999 documentModified(); // so as to restore "(modified)" window title
3000 }
3001 }
3002
3003 if (!source.isRemote()) m_audioFile = source.getLocalFilename();
3004
3005 } else if (mode == CreateAdditionalModel) {
3006
3007 CommandHistory::getInstance()->startCompoundOperation
3008 (tr("Import \"%1\"").arg(source.getLocation()), true);
3009
3010 m_document->addImportedModel(newModel);
3011
3012 AddPaneCommand *command = new AddPaneCommand(this);
3013 CommandHistory::getInstance()->addCommand(command);
3014
3015 Pane *pane = command->getPane();
3016
3017 if (!m_timeRulerLayer) {
3018 m_timeRulerLayer = m_document->createMainModelLayer
3019 (LayerFactory::TimeRuler);
3020 }
3021
3022 m_document->addLayerToView(pane, m_timeRulerLayer);
3023
3024 Layer *newLayer = m_document->createImportedLayer(newModel);
3025
3026 if (newLayer) {
3027 m_document->addLayerToView(pane, newLayer);
3028 }
3029
3030 CommandHistory::getInstance()->endCompoundOperation();
3031
3032 } else if (mode == ReplaceCurrentPane) {
3033
3034 // We know there is a current pane, otherwise we would have
3035 // reset the mode to CreateAdditionalModel above; and we know
3036 // the current pane does not contain the main model, otherwise
3037 // we would have reset it to ReplaceMainModel. But we don't
3038 // know whether the pane contains a waveform model at all.
3039
3040 Pane *pane = m_paneStack->getCurrentPane();
3041 Layer *replace = 0;
3042
3043 for (int i = 0; i < pane->getLayerCount(); ++i) {
3044 Layer *layer = pane->getLayer(i);
3045 if (dynamic_cast<WaveformLayer *>(layer)) {
3046 replace = layer;
3047 break;
3048 }
3049 }
3050
3051 CommandHistory::getInstance()->startCompoundOperation
3052 (tr("Import \"%1\"").arg(source.getLocation()), true);
3053
3054 m_document->addImportedModel(newModel);
3055
3056 if (replace) {
3057 m_document->removeLayerFromView(pane, replace);
3058 }
3059
3060 Layer *newLayer = m_document->createImportedLayer(newModel);
3061
3062 if (newLayer) {
3063 m_document->addLayerToView(pane, newLayer);
3064 }
3065
3066 CommandHistory::getInstance()->endCompoundOperation();
3067 }
3068
3069 updateMenuStates();
3070 m_recentFiles.addFile(source.getLocation());
3071 if (!source.isRemote()) {
3072 // for file dialog
3073 registerLastOpenedFilePath(FileFinder::AudioFile,
3074 source.getLocalFilename());
3075 }
3076 m_openingAudioFile = false;
3077
3078 currentPaneChanged(m_paneStack->getCurrentPane());
3079
3080 return FileOpenSucceeded;
3081 }
3082
3083 MainWindow::FileOpenStatus
3084 MainWindow::openPlaylist(FileSource source, AudioFileOpenMode mode)
3085 {
3086 std::set<QString> extensions;
3087 PlaylistFileReader::getSupportedExtensions(extensions);
3088 QString extension = source.getExtension();
3089 if (extensions.find(extension) == extensions.end()) return FileOpenFailed;
3090
3091 if (!source.isAvailable()) return FileOpenFailed;
3092 source.waitForData();
3093
3094 PlaylistFileReader reader(source.getLocalFilename());
3095 if (!reader.isOK()) return FileOpenFailed;
3096
3097 PlaylistFileReader::Playlist playlist = reader.load();
3098
3099 bool someSuccess = false;
3100
3101 for (PlaylistFileReader::Playlist::const_iterator i = playlist.begin();
3102 i != playlist.end(); ++i) {
3103
3104 FileOpenStatus status = openAudio(*i, mode);
3105
3106 if (status == FileOpenCancelled) {
3107 return FileOpenCancelled;
3108 }
3109
3110 if (status == FileOpenSucceeded) {
3111 someSuccess = true;
3112 mode = CreateAdditionalModel;
3113 }
3114 }
3115
3116 if (someSuccess) return FileOpenSucceeded;
3117 else return FileOpenFailed;
3118 }
3119
3120 MainWindow::FileOpenStatus
3121 MainWindow::openLayer(FileSource source)
3122 {
3123 Pane *pane = m_paneStack->getCurrentPane();
3124
3125 if (!pane) {
3126 // shouldn't happen, as the menu action should have been disabled
3127 std::cerr << "WARNING: MainWindow::openLayer: no current pane" << std::endl;
3128 return FileOpenWrongMode;
3129 }
3130
3131 if (!getMainModel()) {
3132 // shouldn't happen, as the menu action should have been disabled
3133 std::cerr << "WARNING: MainWindow::openLayer: No main model -- hence no default sample rate available" << std::endl;
3134 return FileOpenWrongMode;
3135 }
3136
3137 if (!source.isAvailable()) return FileOpenFailed;
3138 source.waitForData();
3139
3140 QString path = source.getLocalFilename();
3141
3142 if (source.getExtension() == "svl" || source.getExtension() == "xml") {
3143
3144 PaneCallback callback(this);
3145 QFile file(path);
3146
3147 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
3148 std::cerr << "ERROR: MainWindow::openLayer("
3149 << source.getLocation().toStdString()
3150 << "): Failed to open file for reading" << std::endl;
3151 return FileOpenFailed;
3152 }
3153
3154 SVFileReader reader(m_document, callback, source.getLocation());
3155 reader.setCurrentPane(pane);
3156
3157 QXmlInputSource inputSource(&file);
3158 reader.parse(inputSource);
3159
3160 if (!reader.isOK()) {
3161 std::cerr << "ERROR: MainWindow::openLayer("
3162 << source.getLocation().toStdString()
3163 << "): Failed to read XML file: "
3164 << reader.getErrorString().toStdString() << std::endl;
3165 return FileOpenFailed;
3166 }
3167
3168 m_recentFiles.addFile(source.getLocation());
3169
3170 if (!source.isRemote()) {
3171 registerLastOpenedFilePath(FileFinder::LayerFile, path); // for file dialog
3172 }
3173
3174 } else {
3175
3176 try {
3177
3178 Model *model = DataFileReaderFactory::load
3179 (path, getMainModel()->getSampleRate());
3180
3181 if (model) {
3182
3183 std::cerr << "MainWindow::openLayer: Have model" << std::endl;
3184
3185 Layer *newLayer = m_document->createImportedLayer(model);
3186
3187 if (newLayer) {
3188
3189 m_document->addLayerToView(pane, newLayer);
3190 m_recentFiles.addFile(source.getLocation());
3191
3192 if (!source.isRemote()) {
3193 registerLastOpenedFilePath
3194 (FileFinder::LayerFile,
3195 path); // for file dialog
3196 }
3197
3198 return FileOpenSucceeded;
3199 }
3200 }
3201 } catch (DataFileReaderFactory::Exception e) {
3202 if (e == DataFileReaderFactory::ImportCancelled) {
3203 return FileOpenCancelled;
3204 }
3205 }
3206 }
3207
3208 source.setLeaveLocalFile(true);
3209 return FileOpenFailed;
3210 }
3211
3212 MainWindow::FileOpenStatus
3213 MainWindow::openImage(FileSource source)
3214 {
3215 Pane *pane = m_paneStack->getCurrentPane();
3216
3217 if (!pane) {
3218 // shouldn't happen, as the menu action should have been disabled
3219 std::cerr << "WARNING: MainWindow::openImage: no current pane" << std::endl;
3220 return FileOpenWrongMode;
3221 }
3222
3223 if (!m_document->getMainModel()) {
3224 return FileOpenWrongMode;
3225 }
3226
3227 bool newLayer = false;
3228
3229 ImageLayer *il = dynamic_cast<ImageLayer *>(pane->getSelectedLayer());
3230 if (!il) {
3231 for (int i = pane->getLayerCount()-1; i >= 0; --i) {
3232 il = dynamic_cast<ImageLayer *>(pane->getLayer(i));
3233 if (il) break;
3234 }
3235 }
3236 if (!il) {
3237 il = dynamic_cast<ImageLayer *>
3238 (m_document->createEmptyLayer(LayerFactory::Image));
3239 if (!il) return FileOpenFailed;
3240 newLayer = true;
3241 }
3242
3243 // We don't put the image file in Recent Files
3244
3245 std::cerr << "openImage: trying location \"" << source.getLocation().toStdString() << "\" in image layer" << std::endl;
3246
3247 if (!il->addImage(m_viewManager->getGlobalCentreFrame(), source.getLocation())) {
3248 if (newLayer) {
3249 m_document->setModel(il, 0); // releasing its model
3250 delete il;
3251 }
3252 return FileOpenFailed;
3253 } else {
3254 if (newLayer) {
3255 m_document->addLayerToView(pane, il);
3256 }
3257 m_paneStack->setCurrentLayer(pane, il);
3258 }
3259
3260 return FileOpenSucceeded;
3261 }
3262
3263 MainWindow::FileOpenStatus
3264 MainWindow::openSession(FileSource source)
3265 {
3266 if (!source.isAvailable()) return FileOpenFailed;
3267 if (source.getExtension() != "sv") return FileOpenFailed;
3268 source.waitForData();
3269
3270 BZipFileDevice bzFile(source.getLocalFilename());
3271 if (!bzFile.open(QIODevice::ReadOnly)) return FileOpenFailed;
3272
3273 if (!checkSaveModified()) return FileOpenCancelled;
3274
3275 QString error;
3276 closeSession();
3277 createDocument();
3278
3279 PaneCallback callback(this);
3280 m_viewManager->clearSelections();
3281
3282 SVFileReader reader(m_document, callback, source.getLocation());
3283 QXmlInputSource inputSource(&bzFile);
3284 reader.parse(inputSource);
3285
3286 if (!reader.isOK()) {
3287 error = tr("SV XML file read error:\n%1").arg(reader.getErrorString());
3288 }
3289
3290 bzFile.close();
3291
3292 bool ok = (error == "");
3293
3294 if (ok) {
3295
3296 setWindowTitle(tr("Sonic Visualiser: %1")
3297 .arg(source.getLocation()));
3298
3299 if (!source.isRemote()) m_sessionFile = source.getLocalFilename();
3300
3301 setupMenus();
3302 CommandHistory::getInstance()->clear();
3303 CommandHistory::getInstance()->documentSaved();
3304 m_documentModified = false;
3305 updateMenuStates();
3306
3307 m_recentFiles.addFile(source.getLocation());
3308
3309 if (!source.isRemote()) {
3310 // for file dialog
3311 registerLastOpenedFilePath(FileFinder::SessionFile,
3312 source.getLocalFilename());
3313 }
3314
3315 } else {
3316 setWindowTitle(tr("Sonic Visualiser"));
3317 }
3318
3319 return ok ? FileOpenSucceeded : FileOpenFailed;
3320 }
3321
3322 void
3323 MainWindow::createPlayTarget()
3324 {
3325 if (m_playTarget) return;
3326
3327 m_playTarget = AudioTargetFactory::createCallbackTarget(m_playSource);
3328 if (!m_playTarget) {
3329 QMessageBox::warning
3330 (this, tr("Couldn't open audio device"),
3331 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."),
3332 QMessageBox::Ok);
3333 }
3334 connect(m_fader, SIGNAL(valueChanged(float)),
3335 m_playTarget, SLOT(setOutputGain(float)));
3336 }
3337
3338 WaveFileModel *
3339 MainWindow::getMainModel()
3340 {
3341 if (!m_document) return 0;
3342 return m_document->getMainModel();
3343 }
3344
3345 const WaveFileModel *
3346 MainWindow::getMainModel() const
3347 {
3348 if (!m_document) return 0;
3349 return m_document->getMainModel();
3350 }
3351
3352 void 2224 void
3353 MainWindow::newSession() 2225 MainWindow::newSession()
3354 { 2226 {
3355 if (!checkSaveModified()) return; 2227 if (!checkSaveModified()) return;
3356 2228
3379 documentRestored(); 2251 documentRestored();
3380 updateMenuStates(); 2252 updateMenuStates();
3381 } 2253 }
3382 2254
3383 void 2255 void
3384 MainWindow::createDocument()
3385 {
3386 m_document = new Document;
3387
3388 connect(m_document, SIGNAL(layerAdded(Layer *)),
3389 this, SLOT(layerAdded(Layer *)));
3390 connect(m_document, SIGNAL(layerRemoved(Layer *)),
3391 this, SLOT(layerRemoved(Layer *)));
3392 connect(m_document, SIGNAL(layerAboutToBeDeleted(Layer *)),
3393 this, SLOT(layerAboutToBeDeleted(Layer *)));
3394 connect(m_document, SIGNAL(layerInAView(Layer *, bool)),
3395 this, SLOT(layerInAView(Layer *, bool)));
3396
3397 connect(m_document, SIGNAL(modelAdded(Model *)),
3398 this, SLOT(modelAdded(Model *)));
3399 connect(m_document, SIGNAL(mainModelChanged(WaveFileModel *)),
3400 this, SLOT(mainModelChanged(WaveFileModel *)));
3401 connect(m_document, SIGNAL(modelAboutToBeDeleted(Model *)),
3402 this, SLOT(modelAboutToBeDeleted(Model *)));
3403
3404 connect(m_document, SIGNAL(modelGenerationFailed(QString)),
3405 this, SLOT(modelGenerationFailed(QString)));
3406 connect(m_document, SIGNAL(modelRegenerationFailed(QString, QString)),
3407 this, SLOT(modelRegenerationFailed(QString, QString)));
3408 }
3409
3410 void
3411 MainWindow::closeSession() 2256 MainWindow::closeSession()
3412 { 2257 {
3413 if (!checkSaveModified()) return; 2258 if (!checkSaveModified()) return;
3414 2259
3415 while (m_paneStack->getPaneCount() > 0) { 2260 while (m_paneStack->getPaneCount() > 0) {
3463 2308
3464 QString path = getOpenFileName(FileFinder::SessionFile); 2309 QString path = getOpenFileName(FileFinder::SessionFile);
3465 2310
3466 if (path.isEmpty()) return; 2311 if (path.isEmpty()) return;
3467 2312
3468 if (openSession(path) == FileOpenFailed) { 2313 if (openSessionFile(path) == FileOpenFailed) {
3469 QMessageBox::critical(this, tr("Failed to open file"), 2314 QMessageBox::critical(this, tr("Failed to open file"),
3470 tr("<b>File open failed</b><p>Session file \"%1\" could not be opened").arg(path)); 2315 tr("<b>File open failed</b><p>Session file \"%1\" could not be opened").arg(path));
3471 } 2316 }
3472 } 2317 }
3473 2318
3546 } else if (status == FileOpenWrongMode) { 2391 } else if (status == FileOpenWrongMode) {
3547 QMessageBox::critical(this, tr("Failed to open location"), 2392 QMessageBox::critical(this, tr("Failed to open location"),
3548 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data")); 2393 tr("<b>Audio required</b><p>Please load at least one audio file before importing annotation data"));
3549 } 2394 }
3550 } 2395 }
2396
2397 void
2398 MainWindow::paneAdded(Pane *pane)
2399 {
2400 if (m_overview) m_overview->registerView(pane);
2401 }
2402
2403 void
2404 MainWindow::paneHidden(Pane *pane)
2405 {
2406 if (m_overview) m_overview->unregisterView(pane);
2407 }
2408
2409 void
2410 MainWindow::paneAboutToBeDeleted(Pane *pane)
2411 {
2412 if (m_overview) m_overview->unregisterView(pane);
2413 }
3551 2414
3552 void 2415 void
3553 MainWindow::paneDropAccepted(Pane *pane, QStringList uriList) 2416 MainWindow::paneDropAccepted(Pane *pane, QStringList uriList)
3554 { 2417 {
3555 if (pane) m_paneStack->setCurrentPane(pane); 2418 if (pane) m_paneStack->setCurrentPane(pane);
3621 2484
3622 if (m_layerTreeView && 2485 if (m_layerTreeView &&
3623 m_layerTreeView->isVisible()) { 2486 m_layerTreeView->isVisible()) {
3624 delete m_layerTreeView; 2487 delete m_layerTreeView;
3625 } 2488 }
2489
2490 closeSession();
3626 2491
3627 e->accept(); 2492 e->accept();
3628 return; 2493 return;
3629 } 2494 }
3630 2495
3749 documentRestored(); 2614 documentRestored();
3750 m_recentFiles.addFile(path); 2615 m_recentFiles.addFile(path);
3751 } 2616 }
3752 } 2617 }
3753 2618
3754 bool
3755 MainWindow::saveSessionFile(QString path)
3756 {
3757 BZipFileDevice bzFile(path);
3758 if (!bzFile.open(QIODevice::WriteOnly)) {
3759 std::cerr << "Failed to open session file \"" << path.toStdString()
3760 << "\" for writing: "
3761 << bzFile.errorString().toStdString() << std::endl;
3762 return false;
3763 }
3764
3765 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
3766
3767 QTextStream out(&bzFile);
3768 toXml(out);
3769 out.flush();
3770
3771 QApplication::restoreOverrideCursor();
3772
3773 if (!bzFile.isOK()) {
3774 QMessageBox::critical(this, tr("Failed to write file"),
3775 tr("<b>Save failed</b><p>Failed to write to file \"%1\": %2")
3776 .arg(path).arg(bzFile.errorString()));
3777 bzFile.close();
3778 return false;
3779 }
3780
3781 bzFile.close();
3782 return true;
3783 }
3784
3785 void
3786 MainWindow::toXml(QTextStream &out)
3787 {
3788 QString indent(" ");
3789
3790 out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
3791 out << "<!DOCTYPE sonic-visualiser>\n";
3792 out << "<sv>\n";
3793
3794 m_document->toXml(out, "", "");
3795
3796 out << "<display>\n";
3797
3798 out << QString(" <window width=\"%1\" height=\"%2\"/>\n")
3799 .arg(width()).arg(height());
3800
3801 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
3802
3803 Pane *pane = m_paneStack->getPane(i);
3804
3805 if (pane) {
3806 pane->toXml(out, indent);
3807 }
3808 }
3809
3810 out << "</display>\n";
3811
3812 m_viewManager->getSelection().toXml(out);
3813
3814 out << "</sv>\n";
3815 }
3816
3817 Pane *
3818 MainWindow::addPaneToStack()
3819 {
3820 AddPaneCommand *command = new AddPaneCommand(this);
3821 CommandHistory::getInstance()->addCommand(command);
3822 return command->getPane();
3823 }
3824
3825 void
3826 MainWindow::zoomIn()
3827 {
3828 Pane *currentPane = m_paneStack->getCurrentPane();
3829 if (currentPane) currentPane->zoom(true);
3830 }
3831
3832 void
3833 MainWindow::zoomOut()
3834 {
3835 Pane *currentPane = m_paneStack->getCurrentPane();
3836 if (currentPane) currentPane->zoom(false);
3837 }
3838
3839 void
3840 MainWindow::zoomToFit()
3841 {
3842 Pane *currentPane = m_paneStack->getCurrentPane();
3843 if (!currentPane) return;
3844
3845 Model *model = getMainModel();
3846 if (!model) return;
3847
3848 size_t start = model->getStartFrame();
3849 size_t end = model->getEndFrame();
3850 size_t pixels = currentPane->width();
3851
3852 size_t sw = currentPane->getVerticalScaleWidth();
3853 if (pixels > sw * 2) pixels -= sw * 2;
3854 else pixels = 1;
3855 if (pixels > 4) pixels -= 4;
3856
3857 size_t zoomLevel = (end - start) / pixels;
3858
3859 currentPane->setZoomLevel(zoomLevel);
3860 currentPane->setCentreFrame((start + end) / 2);
3861 }
3862
3863 void
3864 MainWindow::zoomDefault()
3865 {
3866 Pane *currentPane = m_paneStack->getCurrentPane();
3867 if (currentPane) currentPane->setZoomLevel(1024);
3868 }
3869
3870 void
3871 MainWindow::scrollLeft()
3872 {
3873 Pane *currentPane = m_paneStack->getCurrentPane();
3874 if (currentPane) currentPane->scroll(false, false);
3875 }
3876
3877 void
3878 MainWindow::jumpLeft()
3879 {
3880 Pane *currentPane = m_paneStack->getCurrentPane();
3881 if (currentPane) currentPane->scroll(false, true);
3882 }
3883
3884 void
3885 MainWindow::scrollRight()
3886 {
3887 Pane *currentPane = m_paneStack->getCurrentPane();
3888 if (currentPane) currentPane->scroll(true, false);
3889 }
3890
3891 void
3892 MainWindow::jumpRight()
3893 {
3894 Pane *currentPane = m_paneStack->getCurrentPane();
3895 if (currentPane) currentPane->scroll(true, true);
3896 }
3897
3898 void
3899 MainWindow::showNoOverlays()
3900 {
3901 m_viewManager->setOverlayMode(ViewManager::NoOverlays);
3902 }
3903
3904 void
3905 MainWindow::showMinimalOverlays()
3906 {
3907 m_viewManager->setOverlayMode(ViewManager::MinimalOverlays);
3908 }
3909
3910 void
3911 MainWindow::showStandardOverlays()
3912 {
3913 m_viewManager->setOverlayMode(ViewManager::StandardOverlays);
3914 }
3915
3916 void
3917 MainWindow::showAllOverlays()
3918 {
3919 m_viewManager->setOverlayMode(ViewManager::AllOverlays);
3920 }
3921
3922 void
3923 MainWindow::toggleZoomWheels()
3924 {
3925 if (m_viewManager->getZoomWheelsEnabled()) {
3926 m_viewManager->setZoomWheelsEnabled(false);
3927 } else {
3928 m_viewManager->setZoomWheelsEnabled(true);
3929 }
3930 }
3931
3932 void
3933 MainWindow::togglePropertyBoxes()
3934 {
3935 if (m_paneStack->getLayoutStyle() == PaneStack::NoPropertyStacks) {
3936 if (Preferences::getInstance()->getPropertyBoxLayout() ==
3937 Preferences::VerticallyStacked) {
3938 m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout);
3939 } else {
3940 m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout);
3941 }
3942 } else {
3943 m_paneStack->setLayoutStyle(PaneStack::NoPropertyStacks);
3944 }
3945 }
3946
3947 void
3948 MainWindow::toggleStatusBar()
3949 {
3950 QSettings settings;
3951 settings.beginGroup("MainWindow");
3952 bool sb = settings.value("showstatusbar", true).toBool();
3953
3954 if (sb) {
3955 statusBar()->hide();
3956 } else {
3957 statusBar()->show();
3958 }
3959
3960 settings.setValue("showstatusbar", !sb);
3961
3962 settings.endGroup();
3963 }
3964
3965 void 2619 void
3966 MainWindow::preferenceChanged(PropertyContainer::PropertyName name) 2620 MainWindow::preferenceChanged(PropertyContainer::PropertyName name)
3967 { 2621 {
3968 if (name == "Property Box Layout") { 2622 MainWindowBase::preferenceChanged(name);
3969 if (m_paneStack->getLayoutStyle() != PaneStack::NoPropertyStacks) { 2623
3970 if (Preferences::getInstance()->getPropertyBoxLayout() == 2624 if (name == "Background Mode" && m_viewManager) {
3971 Preferences::VerticallyStacked) {
3972 m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout);
3973 } else {
3974 m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout);
3975 }
3976 }
3977 } else if (name == "Background Mode" && m_viewManager) {
3978 Preferences::BackgroundMode mode =
3979 Preferences::getInstance()->getBackgroundMode();
3980 if (mode == Preferences::BackgroundFromTheme) {
3981 m_viewManager->setGlobalDarkBackground(m_initialDarkBackground);
3982 } else if (mode == Preferences::DarkBackground) {
3983 m_viewManager->setGlobalDarkBackground(true);
3984 } else {
3985 m_viewManager->setGlobalDarkBackground(false);
3986 }
3987 if (m_viewManager->getGlobalDarkBackground()) { 2625 if (m_viewManager->getGlobalDarkBackground()) {
3988 m_panLayer->setBaseColour 2626 m_panLayer->setBaseColour
3989 (ColourDatabase::getInstance()->getColourIndex(tr("Bright Green"))); 2627 (ColourDatabase::getInstance()->getColourIndex(tr("Bright Green")));
3990 } else { 2628 } else {
3991 m_panLayer->setBaseColour 2629 m_panLayer->setBaseColour
3992 (ColourDatabase::getInstance()->getColourIndex(tr("Green"))); 2630 (ColourDatabase::getInstance()->getColourIndex(tr("Green")));
3993 } 2631 }
3994 } 2632 }
3995 }
3996
3997 void
3998 MainWindow::play()
3999 {
4000 if (m_playSource->isPlaying()) {
4001 stop();
4002 } else {
4003 playbackFrameChanged(m_viewManager->getPlaybackFrame());
4004 m_playSource->play(m_viewManager->getPlaybackFrame());
4005 }
4006 }
4007
4008 void
4009 MainWindow::ffwd()
4010 {
4011 if (!getMainModel()) return;
4012
4013 int frame = m_viewManager->getPlaybackFrame();
4014 ++frame;
4015
4016 Layer *layer = getSnapLayer();
4017 size_t sr = getMainModel()->getSampleRate();
4018
4019 if (!layer) {
4020
4021 frame = RealTime::realTime2Frame
4022 (RealTime::frame2RealTime(frame, sr) + RealTime(2, 0), sr);
4023 if (frame > int(getMainModel()->getEndFrame())) {
4024 frame = getMainModel()->getEndFrame();
4025 }
4026
4027 } else {
4028
4029 size_t resolution = 0;
4030 if (!layer->snapToFeatureFrame(m_paneStack->getCurrentPane(),
4031 frame, resolution, Layer::SnapRight)) {
4032 frame = getMainModel()->getEndFrame();
4033 }
4034 }
4035
4036 if (frame < 0) frame = 0;
4037
4038 if (m_viewManager->getPlaySelectionMode()) {
4039 frame = m_viewManager->constrainFrameToSelection(size_t(frame));
4040 }
4041
4042 m_viewManager->setPlaybackFrame(frame);
4043 }
4044
4045 void
4046 MainWindow::ffwdEnd()
4047 {
4048 if (!getMainModel()) return;
4049
4050 size_t frame = getMainModel()->getEndFrame();
4051
4052 if (m_viewManager->getPlaySelectionMode()) {
4053 frame = m_viewManager->constrainFrameToSelection(frame);
4054 }
4055
4056 m_viewManager->setPlaybackFrame(frame);
4057 }
4058
4059 void
4060 MainWindow::rewind()
4061 {
4062 if (!getMainModel()) return;
4063
4064 int frame = m_viewManager->getPlaybackFrame();
4065 if (frame > 0) --frame;
4066
4067 Layer *layer = getSnapLayer();
4068 size_t sr = getMainModel()->getSampleRate();
4069
4070 // when rewinding during playback, we want to allow a period
4071 // following a rewind target point at which the rewind will go to
4072 // the prior point instead of the immediately neighbouring one
4073 if (m_playSource && m_playSource->isPlaying()) {
4074 RealTime ct = RealTime::frame2RealTime(frame, sr);
4075 ct = ct - RealTime::fromSeconds(0.25);
4076 if (ct < RealTime::zeroTime) ct = RealTime::zeroTime;
4077 // std::cerr << "rewind: frame " << frame << " -> ";
4078 frame = RealTime::realTime2Frame(ct, sr);
4079 // std::cerr << frame << std::endl;
4080 }
4081
4082 if (!layer) {
4083
4084 frame = RealTime::realTime2Frame
4085 (RealTime::frame2RealTime(frame, sr) - RealTime(2, 0), sr);
4086 if (frame < int(getMainModel()->getStartFrame())) {
4087 frame = getMainModel()->getStartFrame();
4088 }
4089
4090 } else {
4091
4092 size_t resolution = 0;
4093 if (!layer->snapToFeatureFrame(m_paneStack->getCurrentPane(),
4094 frame, resolution, Layer::SnapLeft)) {
4095 frame = getMainModel()->getStartFrame();
4096 }
4097 }
4098
4099 if (frame < 0) frame = 0;
4100
4101 if (m_viewManager->getPlaySelectionMode()) {
4102 frame = m_viewManager->constrainFrameToSelection(size_t(frame));
4103 }
4104
4105 m_viewManager->setPlaybackFrame(frame);
4106 }
4107
4108 void
4109 MainWindow::rewindStart()
4110 {
4111 if (!getMainModel()) return;
4112
4113 size_t frame = getMainModel()->getStartFrame();
4114
4115 if (m_viewManager->getPlaySelectionMode()) {
4116 frame = m_viewManager->constrainFrameToSelection(frame);
4117 }
4118
4119 m_viewManager->setPlaybackFrame(frame);
4120 }
4121
4122 Layer *
4123 MainWindow::getSnapLayer() const
4124 {
4125 Pane *pane = m_paneStack->getCurrentPane();
4126 if (!pane) return 0;
4127
4128 Layer *layer = pane->getSelectedLayer();
4129
4130 if (!dynamic_cast<TimeInstantLayer *>(layer) &&
4131 !dynamic_cast<TimeValueLayer *>(layer) &&
4132 !dynamic_cast<TimeRulerLayer *>(layer)) {
4133
4134 layer = 0;
4135
4136 for (int i = pane->getLayerCount(); i > 0; --i) {
4137 Layer *l = pane->getLayer(i-1);
4138 if (dynamic_cast<TimeRulerLayer *>(l)) {
4139 layer = l;
4140 break;
4141 }
4142 }
4143 }
4144
4145 return layer;
4146 }
4147
4148 void
4149 MainWindow::stop()
4150 {
4151 m_playSource->stop();
4152
4153 if (m_paneStack && m_paneStack->getCurrentPane()) {
4154 updateVisibleRangeDisplay(m_paneStack->getCurrentPane());
4155 } else {
4156 m_myStatusMessage = "";
4157 statusBar()->showMessage("");
4158 }
4159 } 2633 }
4160 2634
4161 void 2635 void
4162 MainWindow::addPane() 2636 MainWindow::addPane()
4163 { 2637 {
4249 // pane->setCentreFrame(m_viewManager->getGlobalCentreFrame()); 2723 // pane->setCentreFrame(m_viewManager->getGlobalCentreFrame());
4250 2724
4251 CommandHistory::getInstance()->endCompoundOperation(); 2725 CommandHistory::getInstance()->endCompoundOperation();
4252 2726
4253 updateMenuStates(); 2727 updateMenuStates();
4254 }
4255
4256 MainWindow::AddPaneCommand::AddPaneCommand(MainWindow *mw) :
4257 m_mw(mw),
4258 m_pane(0),
4259 m_prevCurrentPane(0),
4260 m_added(false)
4261 {
4262 }
4263
4264 MainWindow::AddPaneCommand::~AddPaneCommand()
4265 {
4266 if (m_pane && !m_added) {
4267 m_mw->m_paneStack->deletePane(m_pane);
4268 }
4269 }
4270
4271 QString
4272 MainWindow::AddPaneCommand::getName() const
4273 {
4274 return tr("Add Pane");
4275 }
4276
4277 void
4278 MainWindow::AddPaneCommand::execute()
4279 {
4280 if (!m_pane) {
4281 m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane();
4282 m_pane = m_mw->m_paneStack->addPane();
4283
4284 connect(m_pane, SIGNAL(contextHelpChanged(const QString &)),
4285 m_mw, SLOT(contextHelpChanged(const QString &)));
4286 } else {
4287 m_mw->m_paneStack->showPane(m_pane);
4288 }
4289
4290 m_mw->m_paneStack->setCurrentPane(m_pane);
4291 m_mw->m_overview->registerView(m_pane);
4292 m_added = true;
4293 }
4294
4295 void
4296 MainWindow::AddPaneCommand::unexecute()
4297 {
4298 m_mw->m_paneStack->hidePane(m_pane);
4299 m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane);
4300 m_mw->m_overview->unregisterView(m_pane);
4301 m_added = false;
4302 }
4303
4304 MainWindow::RemovePaneCommand::RemovePaneCommand(MainWindow *mw, Pane *pane) :
4305 m_mw(mw),
4306 m_pane(pane),
4307 m_added(true)
4308 {
4309 }
4310
4311 MainWindow::RemovePaneCommand::~RemovePaneCommand()
4312 {
4313 if (m_pane && !m_added) {
4314 m_mw->m_paneStack->deletePane(m_pane);
4315 }
4316 }
4317
4318 QString
4319 MainWindow::RemovePaneCommand::getName() const
4320 {
4321 return tr("Remove Pane");
4322 }
4323
4324 void
4325 MainWindow::RemovePaneCommand::execute()
4326 {
4327 m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane();
4328 m_mw->m_paneStack->hidePane(m_pane);
4329 m_mw->m_overview->unregisterView(m_pane);
4330 m_added = false;
4331 }
4332
4333 void
4334 MainWindow::RemovePaneCommand::unexecute()
4335 {
4336 m_mw->m_paneStack->showPane(m_pane);
4337 m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane);
4338 m_mw->m_overview->registerView(m_pane);
4339 m_added = true;
4340 } 2728 }
4341 2729
4342 void 2730 void
4343 MainWindow::addLayer() 2731 MainWindow::addLayer()
4344 { 2732 {
4472 m_document->setChannel(newLayer, context.channel); 2860 m_document->setChannel(newLayer, context.channel);
4473 m_recentTransforms.add(transform); 2861 m_recentTransforms.add(transform);
4474 m_paneStack->setCurrentLayer(pane, newLayer); 2862 m_paneStack->setCurrentLayer(pane, newLayer);
4475 } 2863 }
4476 2864
4477 updateMenuStates();
4478 }
4479
4480 void
4481 MainWindow::deleteCurrentPane()
4482 {
4483 CommandHistory::getInstance()->startCompoundOperation
4484 (tr("Delete Pane"), true);
4485
4486 Pane *pane = m_paneStack->getCurrentPane();
4487 if (pane) {
4488 while (pane->getLayerCount() > 0) {
4489 Layer *layer = pane->getLayer(0);
4490 if (layer) {
4491 m_document->removeLayerFromView(pane, layer);
4492 } else {
4493 break;
4494 }
4495 }
4496
4497 RemovePaneCommand *command = new RemovePaneCommand(this, pane);
4498 CommandHistory::getInstance()->addCommand(command);
4499 }
4500
4501 CommandHistory::getInstance()->endCompoundOperation();
4502
4503 updateMenuStates();
4504 }
4505
4506 void
4507 MainWindow::deleteCurrentLayer()
4508 {
4509 Pane *pane = m_paneStack->getCurrentPane();
4510 if (pane) {
4511 Layer *layer = pane->getSelectedLayer();
4512 if (layer) {
4513 m_document->removeLayerFromView(pane, layer);
4514 }
4515 }
4516 updateMenuStates(); 2865 updateMenuStates();
4517 } 2866 }
4518 2867
4519 void 2868 void
4520 MainWindow::renameCurrentLayer() 2869 MainWindow::renameCurrentLayer()
4612 { 2961 {
4613 m_playSpeed->setValue(m_playSpeed->defaultValue()); 2962 m_playSpeed->setValue(m_playSpeed->defaultValue());
4614 } 2963 }
4615 2964
4616 void 2965 void
4617 MainWindow::playbackFrameChanged(unsigned long frame)
4618 {
4619 if (!(m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
4620
4621 RealTime now = RealTime::frame2RealTime
4622 (frame, getMainModel()->getSampleRate());
4623
4624 if (now.sec == m_lastPlayStatusSec) return;
4625
4626 RealTime then = RealTime::frame2RealTime
4627 (m_playSource->getPlayEndFrame(), getMainModel()->getSampleRate());
4628
4629 QString nowStr;
4630 QString thenStr;
4631 QString remainingStr;
4632
4633 if (then.sec > 10) {
4634 nowStr = now.toSecText().c_str();
4635 thenStr = then.toSecText().c_str();
4636 remainingStr = (then - now).toSecText().c_str();
4637 m_lastPlayStatusSec = now.sec;
4638 } else {
4639 nowStr = now.toText(true).c_str();
4640 thenStr = then.toText(true).c_str();
4641 remainingStr = (then - now).toText(true).c_str();
4642 }
4643
4644 m_myStatusMessage = tr("Playing: %1 of %2 (%3 remaining)")
4645 .arg(nowStr).arg(thenStr).arg(remainingStr);
4646
4647 statusBar()->showMessage(m_myStatusMessage);
4648 }
4649
4650 void
4651 MainWindow::globalCentreFrameChanged(unsigned long )
4652 {
4653 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
4654 Pane *p = 0;
4655 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
4656 if (!p->getFollowGlobalPan()) return;
4657 updateVisibleRangeDisplay(p);
4658 }
4659
4660 void
4661 MainWindow::viewCentreFrameChanged(View *v, unsigned long )
4662 {
4663 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
4664 Pane *p = 0;
4665 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
4666 if (v == p) updateVisibleRangeDisplay(p);
4667 }
4668
4669 void
4670 MainWindow::viewZoomLevelChanged(View *v, unsigned long , bool )
4671 {
4672 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
4673 Pane *p = 0;
4674 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
4675 if (v == p) updateVisibleRangeDisplay(p);
4676 }
4677
4678 void
4679 MainWindow::updateVisibleRangeDisplay(Pane *p) const 2966 MainWindow::updateVisibleRangeDisplay(Pane *p) const
4680 { 2967 {
4681 if (!getMainModel() || !p) { 2968 if (!getMainModel() || !p) {
4682 return; 2969 return;
4683 } 2970 }
4754 (this, tr("Audio processing overload"), 3041 (this, tr("Audio processing overload"),
4755 tr("<b>Overloaded</b><p>Audio effects plugin auditioning has been disabled due to a processing overload.")); 3042 tr("<b>Overloaded</b><p>Audio effects plugin auditioning has been disabled due to a processing overload."));
4756 } 3043 }
4757 3044
4758 void 3045 void
4759 MainWindow::layerAdded(Layer *) 3046 MainWindow::layerRemoved(Layer *layer)
4760 { 3047 {
4761 // std::cerr << "MainWindow::layerAdded(" << layer << ")" << std::endl;
4762 // setupExistingLayersMenu();
4763 updateMenuStates();
4764 }
4765
4766 void
4767 MainWindow::layerRemoved(Layer *)
4768 {
4769 // std::cerr << "MainWindow::layerRemoved(" << layer << ")" << std::endl;
4770 setupExistingLayersMenus(); 3048 setupExistingLayersMenus();
4771 updateMenuStates(); 3049 MainWindowBase::layerRemoved(layer);
4772 }
4773
4774 void
4775 MainWindow::layerAboutToBeDeleted(Layer *layer)
4776 {
4777 // std::cerr << "MainWindow::layerAboutToBeDeleted(" << layer << ")" << std::endl;
4778 if (layer == m_timeRulerLayer) {
4779 // std::cerr << "(this is the time ruler layer)" << std::endl;
4780 m_timeRulerLayer = 0;
4781 }
4782 } 3050 }
4783 3051
4784 void 3052 void
4785 MainWindow::layerInAView(Layer *layer, bool inAView) 3053 MainWindow::layerInAView(Layer *layer, bool inAView)
4786 { 3054 {
4787 // std::cerr << "MainWindow::layerInAView(" << layer << "," << inAView << ")" << std::endl;
4788
4789 // Check whether we need to add or remove model from play source
4790 Model *model = layer->getModel();
4791 if (model) {
4792 if (inAView) {
4793 m_playSource->addModel(model);
4794 } else {
4795 bool found = false;
4796 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
4797 Pane *pane = m_paneStack->getPane(i);
4798 if (!pane) continue;
4799 for (int j = 0; j < pane->getLayerCount(); ++j) {
4800 Layer *pl = pane->getLayer(j);
4801 if (pl && pl->getModel() == model) {
4802 found = true;
4803 break;
4804 }
4805 }
4806 if (found) break;
4807 }
4808 if (!found) m_playSource->removeModel(model);
4809 }
4810 }
4811
4812 setupExistingLayersMenus(); 3055 setupExistingLayersMenus();
4813 updateMenuStates(); 3056 MainWindowBase::layerInAView(layer, inAView);
4814 } 3057 }
4815 3058
4816 void 3059 void
4817 MainWindow::modelAdded(Model *model) 3060 MainWindow::modelAdded(Model *model)
4818 { 3061 {
4819 // std::cerr << "MainWindow::modelAdded(" << model << ")" << std::endl; 3062 MainWindowBase::modelAdded(model);
4820 m_playSource->addModel(model);
4821 if (dynamic_cast<DenseTimeValueModel *>(model)) { 3063 if (dynamic_cast<DenseTimeValueModel *>(model)) {
4822 setupPaneAndLayerMenus(); 3064 setupPaneAndLayerMenus();
4823 } 3065 }
4824 } 3066 }
4825 3067
4826 void 3068 void
4827 MainWindow::mainModelChanged(WaveFileModel *model) 3069 MainWindow::mainModelChanged(WaveFileModel *model)
4828 { 3070 {
4829 // std::cerr << "MainWindow::mainModelChanged(" << model << ")" << std::endl;
4830 updateDescriptionLabel();
4831 m_panLayer->setModel(model); 3071 m_panLayer->setModel(model);
4832 if (model) m_viewManager->setMainModelSampleRate(model->getSampleRate()); 3072
4833 if (model && !m_playTarget && m_audioOutput) createPlayTarget(); 3073 MainWindowBase::mainModelChanged(model);
4834 } 3074
4835 3075 if (m_playTarget) {
4836 void 3076 connect(m_fader, SIGNAL(valueChanged(float)),
4837 MainWindow::modelAboutToBeDeleted(Model *model) 3077 m_playTarget, SLOT(setOutputGain(float)));
4838 { 3078 }
4839 // std::cerr << "MainWindow::modelAboutToBeDeleted(" << model << ")" << std::endl; 3079 }
4840 if (model == m_viewManager->getPlaybackModel()) { 3080
4841 m_viewManager->setPlaybackModel(0); 3081 void
4842 } 3082 MainWindow::setInstantsNumbering()
4843 m_playSource->removeModel(model); 3083 {
4844 FFTDataServer::modelAboutToBeDeleted(model); 3084 QAction *a = dynamic_cast<QAction *>(sender());
3085 if (!a) return;
3086
3087 int type = m_numberingActions[a];
3088
3089 if (m_labeller) m_labeller->setType(Labeller::ValueType(type));
3090
3091 QSettings settings;
3092 settings.beginGroup("MainWindow");
3093 settings.setValue("labellertype", type);
3094 settings.endGroup();
3095 }
3096
3097 void
3098 MainWindow::setInstantsCounterCycle()
3099 {
3100 QAction *a = dynamic_cast<QAction *>(sender());
3101 if (!a) return;
3102
3103 int cycle = a->text().toInt();
3104 if (cycle == 0) return;
3105
3106 if (m_labeller) m_labeller->setCounterCycleSize(cycle);
3107
3108 QSettings settings;
3109 settings.beginGroup("MainWindow");
3110 settings.setValue("labellercycle", cycle);
3111 settings.endGroup();
3112 }
3113
3114 void
3115 MainWindow::resetInstantsCounters()
3116 {
3117 LabelCounterInputDialog dialog(m_labeller, this);
3118 dialog.exec();
4845 } 3119 }
4846 3120
4847 void 3121 void
4848 MainWindow::modelGenerationFailed(QString transformName) 3122 MainWindow::modelGenerationFailed(QString transformName)
4849 { 3123 {
4870 MainWindow::rightButtonMenuRequested(Pane *pane, QPoint position) 3144 MainWindow::rightButtonMenuRequested(Pane *pane, QPoint position)
4871 { 3145 {
4872 // std::cerr << "MainWindow::rightButtonMenuRequested(" << pane << ", " << position.x() << ", " << position.y() << ")" << std::endl; 3146 // std::cerr << "MainWindow::rightButtonMenuRequested(" << pane << ", " << position.x() << ", " << position.y() << ")" << std::endl;
4873 m_paneStack->setCurrentPane(pane); 3147 m_paneStack->setCurrentPane(pane);
4874 m_rightButtonMenu->popup(position); 3148 m_rightButtonMenu->popup(position);
4875 }
4876
4877 void
4878 MainWindow::propertyStacksResized()
4879 {
4880 /*
4881 std::cerr << "MainWindow::propertyStacksResized" << std::endl;
4882 Pane *pane = m_paneStack->getCurrentPane();
4883 if (pane && m_overview) {
4884 std::cerr << "Fixed width: " << pane->width() << std::endl;
4885 m_overview->setFixedWidth(pane->width());
4886 }
4887 */
4888 } 3149 }
4889 3150
4890 void 3151 void
4891 MainWindow::showLayerTree() 3152 MainWindow::showLayerTree()
4892 { 3153 {
4902 LayerTreeModel *tree = new LayerTreeModel(m_paneStack); 3163 LayerTreeModel *tree = new LayerTreeModel(m_paneStack);
4903 m_layerTreeView->resize(500, 300); //!!! 3164 m_layerTreeView->resize(500, 300); //!!!
4904 m_layerTreeView->setModel(tree); 3165 m_layerTreeView->setModel(tree);
4905 m_layerTreeView->expandAll(); 3166 m_layerTreeView->expandAll();
4906 m_layerTreeView->show(); 3167 m_layerTreeView->show();
4907 }
4908
4909 void
4910 MainWindow::pollOSC()
4911 {
4912 if (!m_oscQueue || m_oscQueue->isEmpty()) return;
4913 std::cerr << "MainWindow::pollOSC: have " << m_oscQueue->getMessagesAvailable() << " messages" << std::endl;
4914
4915 if (m_openingAudioFile) return;
4916
4917 OSCMessage message = m_oscQueue->readMessage();
4918
4919 if (message.getTarget() != 0) {
4920 return; //!!! for now -- this class is target 0, others not handled yet
4921 }
4922
4923 handleOSCMessage(message);
4924 } 3168 }
4925 3169
4926 void 3170 void
4927 MainWindow::handleOSCMessage(const OSCMessage &message) 3171 MainWindow::handleOSCMessage(const OSCMessage &message)
4928 { 3172 {
5455 { 3699 {
5456 contextHelpChanged(""); 3700 contextHelpChanged("");
5457 } 3701 }
5458 3702
5459 void 3703 void
5460 MainWindow::inProgressSelectionChanged()
5461 {
5462 Pane *currentPane = 0;
5463 if (m_paneStack) currentPane = m_paneStack->getCurrentPane();
5464 if (currentPane) updateVisibleRangeDisplay(currentPane);
5465 }
5466
5467 void
5468 MainWindow::contextHelpChanged(const QString &s)
5469 {
5470 if (s == "" && m_myStatusMessage != "") {
5471 statusBar()->showMessage(m_myStatusMessage);
5472 return;
5473 }
5474 statusBar()->showMessage(s);
5475 }
5476
5477 void
5478 MainWindow::website() 3704 MainWindow::website()
5479 { 3705 {
5480 openHelpUrl(tr("http://www.sonicvisualiser.org/")); 3706 openHelpUrl(tr("http://www.sonicvisualiser.org/"));
5481 } 3707 }
5482 3708
5483 void 3709 void
5484 MainWindow::help() 3710 MainWindow::help()
5485 { 3711 {
5486 openHelpUrl(tr("http://www.sonicvisualiser.org/doc/reference/1.0/en/")); 3712 openHelpUrl(tr("http://www.sonicvisualiser.org/doc/reference/1.0/en/"));
5487 }
5488
5489 void
5490 MainWindow::openHelpUrl(QString url)
5491 {
5492 // This method mostly lifted from Qt Assistant source code
5493
5494 QProcess *process = new QProcess(this);
5495 connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater()));
5496
5497 QStringList args;
5498
5499 #ifdef Q_OS_MAC
5500 args.append(url);
5501 process->start("open", args);
5502 #else
5503 #ifdef Q_OS_WIN32
5504
5505 QString pf(getenv("ProgramFiles"));
5506 QString command = pf + QString("\\Internet Explorer\\IEXPLORE.EXE");
5507
5508 args.append(url);
5509 process->start(command, args);
5510
5511 #else
5512 #ifdef Q_WS_X11
5513 if (!qgetenv("KDE_FULL_SESSION").isEmpty()) {
5514 args.append("exec");
5515 args.append(url);
5516 process->start("kfmclient", args);
5517 } else if (!qgetenv("BROWSER").isEmpty()) {
5518 args.append(url);
5519 process->start(qgetenv("BROWSER"), args);
5520 } else {
5521 args.append(url);
5522 process->start("firefox", args);
5523 }
5524 #endif
5525 #endif
5526 #endif
5527 } 3713 }
5528 3714
5529 void 3715 void
5530 MainWindow::about() 3716 MainWindow::about()
5531 { 3717 {