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