annotate framework/MainWindowBase.cpp @ 622:22e455beee3b import-audio-data

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