annotate framework/MainWindowBase.cpp @ 610:5ddcbc55b6a2

If audio IO is recreated due to channel count change when recording, make sure it's recreated ready-resumed if we were recording already
author Chris Cannam
date Wed, 08 Aug 2018 15:18:52 +0100
parents 523dc97f027d
children 37b23e50832b
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@293 1501 // cerr << "mode = " << mode << endl;
Chris@45 1502
Chris@45 1503 if (mode == AskUser) {
Chris@45 1504 if (getMainModel()) {
Chris@45 1505
Chris@147 1506 QSettings settings;
Chris@147 1507 settings.beginGroup("MainWindow");
Chris@221 1508 int lastMode = settings.value("lastaudioopenmode", 0).toBool();
Chris@147 1509 settings.endGroup();
Chris@221 1510 int imode = 0;
Chris@45 1511
Chris@45 1512 QStringList items;
Chris@221 1513 items << tr("Close the current session and start a new one")
Chris@221 1514 << tr("Replace the main audio file in this session")
Chris@221 1515 << tr("Add the audio file to this session");
Chris@45 1516
Chris@45 1517 bool ok = false;
Chris@45 1518 QString item = ListInputDialog::getItem
Chris@45 1519 (this, tr("Select target for import"),
Chris@221 1520 tr("<b>Select a target for import</b><p>You already have an audio file loaded.<br>What would you like to do with the new audio file?"),
Chris@221 1521 items, lastMode, &ok);
Chris@45 1522
Chris@45 1523 if (!ok || item.isEmpty()) {
Chris@45 1524 delete newModel;
Chris@45 1525 m_openingAudioFile = false;
Chris@45 1526 return FileOpenCancelled;
Chris@45 1527 }
Chris@45 1528
Chris@221 1529 for (int i = 0; i < items.size(); ++i) {
Chris@221 1530 if (item == items[i]) imode = i;
Chris@221 1531 }
Chris@221 1532
Chris@147 1533 settings.beginGroup("MainWindow");
Chris@221 1534 settings.setValue("lastaudioopenmode", imode);
Chris@147 1535 settings.endGroup();
Chris@45 1536
Chris@221 1537 mode = (AudioFileOpenMode)imode;
Chris@45 1538
Chris@45 1539 } else {
Chris@221 1540 // no main model: make a new session
Chris@221 1541 mode = ReplaceSession;
Chris@45 1542 }
Chris@45 1543 }
Chris@45 1544
Chris@45 1545 if (mode == ReplaceCurrentPane) {
Chris@45 1546
Chris@45 1547 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 1548 if (pane) {
Chris@45 1549 if (getMainModel()) {
Chris@45 1550 View::ModelSet models(pane->getModels());
Chris@45 1551 if (models.find(getMainModel()) != models.end()) {
Chris@221 1552 // Current pane contains main model: replace that
Chris@45 1553 mode = ReplaceMainModel;
Chris@45 1554 }
Chris@221 1555 // Otherwise the current pane has a non-default model,
Chris@221 1556 // which we will deal with later
Chris@45 1557 } else {
Chris@221 1558 // We have no main model, so start a new session with
Chris@221 1559 // optional template
Chris@221 1560 mode = ReplaceSession;
Chris@45 1561 }
Chris@45 1562 } else {
Chris@221 1563 // We seem to have no current pane! Oh well
Chris@45 1564 mode = CreateAdditionalModel;
Chris@45 1565 }
Chris@45 1566 }
Chris@45 1567
Chris@45 1568 if (mode == CreateAdditionalModel && !getMainModel()) {
Chris@386 1569 SVDEBUG << "Mode is CreateAdditionalModel but we have no main model, switching to ReplaceSession mode" << endl;
Chris@221 1570 mode = ReplaceSession;
Chris@221 1571 }
Chris@221 1572
Chris@221 1573 bool loadedTemplate = false;
Chris@221 1574
Chris@221 1575 if (mode == ReplaceSession) {
Chris@258 1576
Chris@258 1577 if (!checkSaveModified()) return FileOpenCancelled;
Chris@258 1578
Chris@386 1579 SVDEBUG << "SV looking for template " << templateName << endl;
Chris@230 1580 if (templateName != "") {
Chris@230 1581 FileOpenStatus tplStatus = openSessionTemplate(templateName);
Chris@258 1582 if (tplStatus == FileOpenCancelled) {
Chris@577 1583 SVDEBUG << "Template load cancelled" << endl;
Chris@258 1584 return FileOpenCancelled;
Chris@258 1585 }
Chris@230 1586 if (tplStatus != FileOpenFailed) {
Chris@577 1587 SVDEBUG << "Template load succeeded" << endl;
Chris@230 1588 loadedTemplate = true;
Chris@221 1589 }
Chris@221 1590 }
Chris@221 1591
Chris@221 1592 if (!loadedTemplate) {
Chris@386 1593 SVDEBUG << "No template found: closing session, creating new empty document" << endl;
Chris@221 1594 closeSession();
Chris@221 1595 createDocument();
Chris@221 1596 }
Chris@221 1597
Chris@386 1598 SVDEBUG << "Now switching to ReplaceMainModel mode" << endl;
Chris@45 1599 mode = ReplaceMainModel;
Chris@45 1600 }
Chris@45 1601
Chris@164 1602 emit activity(tr("Import audio file \"%1\"").arg(source.getLocation()));
Chris@164 1603
Chris@45 1604 if (mode == ReplaceMainModel) {
Chris@45 1605
Chris@45 1606 Model *prevMain = getMainModel();
Chris@45 1607 if (prevMain) {
Chris@45 1608 m_playSource->removeModel(prevMain);
Chris@108 1609 PlayParameterRepository::getInstance()->removePlayable(prevMain);
Chris@45 1610 }
Chris@108 1611 PlayParameterRepository::getInstance()->addPlayable(newModel);
Chris@45 1612
Chris@248 1613 SVDEBUG << "SV about to call setMainModel(" << newModel << "): prevMain is " << prevMain << endl;
Chris@248 1614
Chris@595 1615 m_document->setMainModel(newModel);
Chris@595 1616
Chris@595 1617 setupMenus();
Chris@595 1618
Chris@595 1619 if (loadedTemplate || (m_sessionFile == "")) {
Chris@45 1620 //!!! shouldn't be dealing directly with title from here -- call a method
Chris@595 1621 setWindowTitle(tr("%1: %2")
Chris@57 1622 .arg(QApplication::applicationName())
Chris@45 1623 .arg(source.getLocation()));
Chris@595 1624 CommandHistory::getInstance()->clear();
Chris@595 1625 CommandHistory::getInstance()->documentSaved();
Chris@595 1626 m_documentModified = false;
Chris@595 1627 } else {
Chris@595 1628 setWindowTitle(tr("%1: %2 [%3]")
Chris@57 1629 .arg(QApplication::applicationName())
Chris@595 1630 .arg(QFileInfo(m_sessionFile).fileName())
Chris@595 1631 .arg(source.getLocation()));
Chris@595 1632 if (m_documentModified) {
Chris@595 1633 m_documentModified = false;
Chris@595 1634 documentModified(); // so as to restore "(modified)" window title
Chris@595 1635 }
Chris@595 1636 }
Chris@45 1637
Chris@45 1638 if (!source.isRemote()) m_audioFile = source.getLocalFilename();
Chris@45 1639
Chris@45 1640 } else if (mode == CreateAdditionalModel) {
Chris@45 1641
Chris@577 1642 SVCERR << "Mode is CreateAdditionalModel" << endl;
Chris@577 1643
Chris@595 1644 CommandHistory::getInstance()->startCompoundOperation
Chris@595 1645 (tr("Import \"%1\"").arg(source.getBasename()), true);
Chris@595 1646
Chris@595 1647 m_document->addImportedModel(newModel);
Chris@595 1648
Chris@595 1649 AddPaneCommand *command = new AddPaneCommand(this);
Chris@595 1650 CommandHistory::getInstance()->addCommand(command);
Chris@595 1651
Chris@595 1652 Pane *pane = command->getPane();
Chris@45 1653
Chris@47 1654 if (m_timeRulerLayer) {
Chris@577 1655 SVCERR << "Have time ruler, adding it" << endl;
Chris@47 1656 m_document->addLayerToView(pane, m_timeRulerLayer);
Chris@577 1657 } else {
Chris@577 1658 SVCERR << "Do not have time ruler" << endl;
Chris@47 1659 }
Chris@45 1660
Chris@595 1661 Layer *newLayer = m_document->createImportedLayer(newModel);
Chris@595 1662
Chris@595 1663 if (newLayer) {
Chris@595 1664 m_document->addLayerToView(pane, newLayer);
Chris@595 1665 }
Chris@595 1666
Chris@595 1667 CommandHistory::getInstance()->endCompoundOperation();
Chris@45 1668
Chris@45 1669 } else if (mode == ReplaceCurrentPane) {
Chris@45 1670
Chris@45 1671 // We know there is a current pane, otherwise we would have
Chris@45 1672 // reset the mode to CreateAdditionalModel above; and we know
Chris@45 1673 // the current pane does not contain the main model, otherwise
Chris@45 1674 // we would have reset it to ReplaceMainModel. But we don't
Chris@45 1675 // know whether the pane contains a waveform model at all.
Chris@45 1676
Chris@45 1677 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 1678 Layer *replace = 0;
Chris@45 1679
Chris@45 1680 for (int i = 0; i < pane->getLayerCount(); ++i) {
Chris@45 1681 Layer *layer = pane->getLayer(i);
Chris@45 1682 if (dynamic_cast<WaveformLayer *>(layer)) {
Chris@45 1683 replace = layer;
Chris@45 1684 break;
Chris@45 1685 }
Chris@45 1686 }
Chris@45 1687
Chris@595 1688 CommandHistory::getInstance()->startCompoundOperation
Chris@595 1689 (tr("Import \"%1\"").arg(source.getBasename()), true);
Chris@595 1690
Chris@595 1691 m_document->addImportedModel(newModel);
Chris@45 1692
Chris@45 1693 if (replace) {
Chris@45 1694 m_document->removeLayerFromView(pane, replace);
Chris@45 1695 }
Chris@45 1696
Chris@595 1697 Layer *newLayer = m_document->createImportedLayer(newModel);
Chris@595 1698
Chris@595 1699 if (newLayer) {
Chris@595 1700 m_document->addLayerToView(pane, newLayer);
Chris@595 1701 }
Chris@595 1702
Chris@595 1703 CommandHistory::getInstance()->endCompoundOperation();
Chris@45 1704 }
Chris@45 1705
Chris@45 1706 updateMenuStates();
Chris@45 1707 m_recentFiles.addFile(source.getLocation());
Chris@45 1708 if (!source.isRemote()) {
Chris@45 1709 // for file dialog
Chris@45 1710 registerLastOpenedFilePath(FileFinder::AudioFile,
Chris@45 1711 source.getLocalFilename());
Chris@45 1712 }
Chris@45 1713 m_openingAudioFile = false;
Chris@45 1714
Chris@45 1715 currentPaneChanged(m_paneStack->getCurrentPane());
Chris@45 1716
Chris@342 1717 emit audioFileLoaded();
Chris@342 1718
Chris@45 1719 return FileOpenSucceeded;
Chris@45 1720 }
Chris@45 1721
Chris@45 1722 MainWindowBase::FileOpenStatus
Chris@45 1723 MainWindowBase::openPlaylist(FileSource source, AudioFileOpenMode mode)
Chris@45 1724 {
Chris@233 1725 SVDEBUG << "MainWindowBase::openPlaylist(" << source.getLocation() << ")" << endl;
Chris@135 1726
Chris@45 1727 std::set<QString> extensions;
Chris@45 1728 PlaylistFileReader::getSupportedExtensions(extensions);
Chris@152 1729 QString extension = source.getExtension().toLower();
Chris@45 1730 if (extensions.find(extension) == extensions.end()) return FileOpenFailed;
Chris@45 1731
Chris@45 1732 if (!source.isAvailable()) return FileOpenFailed;
Chris@45 1733 source.waitForData();
Chris@45 1734
Chris@45 1735 PlaylistFileReader reader(source.getLocalFilename());
Chris@45 1736 if (!reader.isOK()) return FileOpenFailed;
Chris@45 1737
Chris@45 1738 PlaylistFileReader::Playlist playlist = reader.load();
Chris@45 1739
Chris@45 1740 bool someSuccess = false;
Chris@45 1741
Chris@45 1742 for (PlaylistFileReader::Playlist::const_iterator i = playlist.begin();
Chris@45 1743 i != playlist.end(); ++i) {
Chris@45 1744
Chris@134 1745 ProgressDialog dialog(tr("Opening playlist..."), true, 2000, this);
Chris@134 1746 connect(&dialog, SIGNAL(showing()), this, SIGNAL(hideSplash()));
Chris@109 1747 FileOpenStatus status = openAudio(FileSource(*i, &dialog), mode);
Chris@45 1748
Chris@45 1749 if (status == FileOpenCancelled) {
Chris@45 1750 return FileOpenCancelled;
Chris@45 1751 }
Chris@45 1752
Chris@45 1753 if (status == FileOpenSucceeded) {
Chris@45 1754 someSuccess = true;
Chris@45 1755 mode = CreateAdditionalModel;
Chris@45 1756 }
Chris@45 1757 }
Chris@45 1758
Chris@45 1759 if (someSuccess) return FileOpenSucceeded;
Chris@45 1760 else return FileOpenFailed;
Chris@45 1761 }
Chris@45 1762
Chris@45 1763 MainWindowBase::FileOpenStatus
Chris@45 1764 MainWindowBase::openLayer(FileSource source)
Chris@45 1765 {
Chris@233 1766 SVDEBUG << "MainWindowBase::openLayer(" << source.getLocation() << ")" << endl;
Chris@135 1767
Chris@45 1768 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 1769
Chris@45 1770 if (!pane) {
Chris@595 1771 // shouldn't happen, as the menu action should have been disabled
Chris@595 1772 cerr << "WARNING: MainWindowBase::openLayer: no current pane" << endl;
Chris@595 1773 return FileOpenWrongMode;
Chris@45 1774 }
Chris@45 1775
Chris@45 1776 if (!getMainModel()) {
Chris@595 1777 // shouldn't happen, as the menu action should have been disabled
Chris@595 1778 cerr << "WARNING: MainWindowBase::openLayer: No main model -- hence no default sample rate available" << endl;
Chris@595 1779 return FileOpenWrongMode;
Chris@45 1780 }
Chris@45 1781
Chris@45 1782 if (!source.isAvailable()) return FileOpenFailed;
Chris@45 1783 source.waitForData();
Chris@45 1784
Chris@45 1785 QString path = source.getLocalFilename();
Chris@45 1786
Chris@145 1787 RDFImporter::RDFDocumentType rdfType =
Chris@145 1788 RDFImporter::identifyDocumentType(QUrl::fromLocalFile(path).toString());
Chris@145 1789
Chris@293 1790 // cerr << "RDF type: (in layer) " << (int) rdfType << endl;
Chris@148 1791
Chris@145 1792 if (rdfType != RDFImporter::NotRDF) {
Chris@145 1793
Chris@145 1794 return openLayersFromRDF(source);
Chris@134 1795
Chris@152 1796 } else if (source.getExtension().toLower() == "svl" ||
Chris@152 1797 (source.getExtension().toLower() == "xml" &&
Chris@140 1798 (SVFileReader::identifyXmlFile(source.getLocalFilename())
Chris@140 1799 == SVFileReader::SVLayerFile))) {
Chris@45 1800
Chris@45 1801 PaneCallback callback(this);
Chris@45 1802 QFile file(path);
Chris@45 1803
Chris@45 1804 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
Chris@293 1805 cerr << "ERROR: MainWindowBase::openLayer("
Chris@294 1806 << source.getLocation()
Chris@293 1807 << "): Failed to open file for reading" << endl;
Chris@45 1808 return FileOpenFailed;
Chris@45 1809 }
Chris@45 1810
Chris@45 1811 SVFileReader reader(m_document, callback, source.getLocation());
Chris@79 1812 connect
Chris@79 1813 (&reader, SIGNAL(modelRegenerationFailed(QString, QString, QString)),
Chris@79 1814 this, SLOT(modelRegenerationFailed(QString, QString, QString)));
Chris@79 1815 connect
Chris@79 1816 (&reader, SIGNAL(modelRegenerationWarning(QString, QString, QString)),
Chris@79 1817 this, SLOT(modelRegenerationWarning(QString, QString, QString)));
Chris@45 1818 reader.setCurrentPane(pane);
Chris@45 1819
Chris@45 1820 QXmlInputSource inputSource(&file);
Chris@45 1821 reader.parse(inputSource);
Chris@45 1822
Chris@45 1823 if (!reader.isOK()) {
Chris@293 1824 cerr << "ERROR: MainWindowBase::openLayer("
Chris@294 1825 << source.getLocation()
Chris@45 1826 << "): Failed to read XML file: "
Chris@293 1827 << reader.getErrorString() << endl;
Chris@45 1828 return FileOpenFailed;
Chris@45 1829 }
Chris@45 1830
Chris@164 1831 emit activity(tr("Import layer XML file \"%1\"").arg(source.getLocation()));
Chris@164 1832
Chris@45 1833 m_recentFiles.addFile(source.getLocation());
Chris@45 1834
Chris@45 1835 if (!source.isRemote()) {
Chris@45 1836 registerLastOpenedFilePath(FileFinder::LayerFile, path); // for file dialog
Chris@45 1837 }
Chris@45 1838
Chris@75 1839 return FileOpenSucceeded;
Chris@75 1840
Chris@45 1841 } else {
Chris@45 1842
Chris@45 1843 try {
Chris@45 1844
Chris@109 1845 MIDIFileImportDialog midiDlg(this);
Chris@109 1846
Chris@109 1847 Model *model = DataFileReaderFactory::loadNonCSV
Chris@109 1848 (path, &midiDlg, getMainModel()->getSampleRate());
Chris@45 1849
Chris@109 1850 if (!model) {
Chris@196 1851 CSVFormat format(path);
Chris@196 1852 format.setSampleRate(getMainModel()->getSampleRate());
Chris@196 1853 CSVFormatDialog *dialog = new CSVFormatDialog(this, format);
Chris@109 1854 if (dialog->exec() == QDialog::Accepted) {
Chris@109 1855 model = DataFileReaderFactory::loadCSV
Chris@109 1856 (path, dialog->getFormat(),
Chris@109 1857 getMainModel()->getSampleRate());
Chris@109 1858 }
Chris@109 1859 }
Chris@109 1860
Chris@45 1861 if (model) {
Chris@45 1862
Chris@233 1863 SVDEBUG << "MainWindowBase::openLayer: Have model" << endl;
Chris@45 1864
Chris@164 1865 emit activity(tr("Import MIDI file \"%1\"").arg(source.getLocation()));
Chris@164 1866
Chris@45 1867 Layer *newLayer = m_document->createImportedLayer(model);
Chris@45 1868
Chris@45 1869 if (newLayer) {
Chris@45 1870
Chris@45 1871 m_document->addLayerToView(pane, newLayer);
Chris@88 1872 m_paneStack->setCurrentLayer(pane, newLayer);
Chris@88 1873
Chris@45 1874 m_recentFiles.addFile(source.getLocation());
Chris@45 1875
Chris@45 1876 if (!source.isRemote()) {
Chris@45 1877 registerLastOpenedFilePath
Chris@45 1878 (FileFinder::LayerFile,
Chris@45 1879 path); // for file dialog
Chris@45 1880 }
Chris@88 1881
Chris@45 1882 return FileOpenSucceeded;
Chris@45 1883 }
Chris@45 1884 }
Chris@45 1885 } catch (DataFileReaderFactory::Exception e) {
Chris@45 1886 if (e == DataFileReaderFactory::ImportCancelled) {
Chris@45 1887 return FileOpenCancelled;
Chris@45 1888 }
Chris@45 1889 }
Chris@45 1890 }
Chris@45 1891
Chris@45 1892 return FileOpenFailed;
Chris@45 1893 }
Chris@45 1894
Chris@45 1895 MainWindowBase::FileOpenStatus
Chris@45 1896 MainWindowBase::openImage(FileSource source)
Chris@45 1897 {
Chris@233 1898 SVDEBUG << "MainWindowBase::openImage(" << source.getLocation() << ")" << endl;
Chris@135 1899
Chris@45 1900 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 1901
Chris@45 1902 if (!pane) {
Chris@595 1903 // shouldn't happen, as the menu action should have been disabled
Chris@595 1904 cerr << "WARNING: MainWindowBase::openImage: no current pane" << endl;
Chris@595 1905 return FileOpenWrongMode;
Chris@45 1906 }
Chris@45 1907
Chris@45 1908 if (!m_document->getMainModel()) {
Chris@45 1909 return FileOpenWrongMode;
Chris@45 1910 }
Chris@45 1911
Chris@45 1912 bool newLayer = false;
Chris@45 1913
Chris@45 1914 ImageLayer *il = dynamic_cast<ImageLayer *>(pane->getSelectedLayer());
Chris@45 1915 if (!il) {
Chris@45 1916 for (int i = pane->getLayerCount()-1; i >= 0; --i) {
Chris@45 1917 il = dynamic_cast<ImageLayer *>(pane->getLayer(i));
Chris@45 1918 if (il) break;
Chris@45 1919 }
Chris@45 1920 }
Chris@45 1921 if (!il) {
Chris@45 1922 il = dynamic_cast<ImageLayer *>
Chris@45 1923 (m_document->createEmptyLayer(LayerFactory::Image));
Chris@45 1924 if (!il) return FileOpenFailed;
Chris@45 1925 newLayer = true;
Chris@45 1926 }
Chris@45 1927
Chris@45 1928 // We don't put the image file in Recent Files
Chris@45 1929
Chris@293 1930 cerr << "openImage: trying location \"" << source.getLocation() << "\" in image layer" << endl;
Chris@45 1931
Chris@45 1932 if (!il->addImage(m_viewManager->getGlobalCentreFrame(), source.getLocation())) {
Chris@45 1933 if (newLayer) {
Chris@52 1934 m_document->deleteLayer(il); // also releases its model
Chris@45 1935 }
Chris@45 1936 return FileOpenFailed;
Chris@45 1937 } else {
Chris@45 1938 if (newLayer) {
Chris@45 1939 m_document->addLayerToView(pane, il);
Chris@45 1940 }
Chris@45 1941 m_paneStack->setCurrentLayer(pane, il);
Chris@45 1942 }
Chris@45 1943
Chris@45 1944 return FileOpenSucceeded;
Chris@45 1945 }
Chris@45 1946
Chris@45 1947 MainWindowBase::FileOpenStatus
Chris@427 1948 MainWindowBase::openDirOfAudio(QString dirPath)
Chris@427 1949 {
Chris@427 1950 QDir dir(dirPath);
Chris@427 1951 QStringList files = dir.entryList(QDir::Files | QDir::Readable);
Chris@427 1952 files.sort();
Chris@427 1953
Chris@427 1954 FileOpenStatus status = FileOpenFailed;
Chris@427 1955 bool first = true;
Chris@427 1956 bool cancelled = false;
Chris@427 1957
Chris@427 1958 foreach (QString file, files) {
Chris@427 1959
Chris@427 1960 FileSource source(dir.filePath(file));
Chris@427 1961 if (!source.isAvailable()) {
Chris@427 1962 continue;
Chris@427 1963 }
Chris@427 1964
Chris@427 1965 if (AudioFileReaderFactory::getKnownExtensions().contains
Chris@427 1966 (source.getExtension().toLower())) {
Chris@427 1967
Chris@427 1968 AudioFileOpenMode mode = CreateAdditionalModel;
Chris@427 1969 if (first) mode = ReplaceSession;
Chris@427 1970
Chris@427 1971 switch (openAudio(source, mode)) {
Chris@427 1972 case FileOpenSucceeded:
Chris@427 1973 status = FileOpenSucceeded;
Chris@427 1974 first = false;
Chris@427 1975 break;
Chris@427 1976 case FileOpenFailed:
Chris@427 1977 break;
Chris@427 1978 case FileOpenCancelled:
Chris@427 1979 cancelled = true;
Chris@427 1980 break;
Chris@427 1981 case FileOpenWrongMode:
Chris@427 1982 break;
Chris@427 1983 }
Chris@427 1984 }
Chris@427 1985
Chris@427 1986 if (cancelled) break;
Chris@427 1987 }
Chris@427 1988
Chris@427 1989 return status;
Chris@427 1990 }
Chris@427 1991
Chris@427 1992 MainWindowBase::FileOpenStatus
Chris@373 1993 MainWindowBase::openSessionPath(QString fileOrUrl)
Chris@45 1994 {
Chris@134 1995 ProgressDialog dialog(tr("Opening session..."), true, 2000, this);
Chris@134 1996 connect(&dialog, SIGNAL(showing()), this, SIGNAL(hideSplash()));
Chris@109 1997 return openSession(FileSource(fileOrUrl, &dialog));
Chris@45 1998 }
Chris@45 1999
Chris@45 2000 MainWindowBase::FileOpenStatus
Chris@45 2001 MainWindowBase::openSession(FileSource source)
Chris@45 2002 {
Chris@233 2003 SVDEBUG << "MainWindowBase::openSession(" << source.getLocation() << ")" << endl;
Chris@135 2004
Chris@45 2005 if (!source.isAvailable()) return FileOpenFailed;
Chris@145 2006 source.waitForData();
Chris@141 2007
Chris@341 2008 QString sessionExt =
Chris@341 2009 InteractiveFileFinder::getInstance()->getApplicationSessionExtension();
Chris@341 2010
Chris@341 2011 if (source.getExtension().toLower() != sessionExt) {
Chris@145 2012
Chris@145 2013 RDFImporter::RDFDocumentType rdfType =
Chris@145 2014 RDFImporter::identifyDocumentType
Chris@145 2015 (QUrl::fromLocalFile(source.getLocalFilename()).toString());
Chris@145 2016
Chris@293 2017 // cerr << "RDF type: " << (int)rdfType << endl;
Chris@148 2018
Chris@145 2019 if (rdfType == RDFImporter::AudioRefAndAnnotations ||
Chris@145 2020 rdfType == RDFImporter::AudioRef) {
Chris@145 2021 return openSessionFromRDF(source);
Chris@145 2022 } else if (rdfType != RDFImporter::NotRDF) {
Chris@145 2023 return FileOpenFailed;
Chris@145 2024 }
Chris@145 2025
Chris@152 2026 if (source.getExtension().toLower() == "xml") {
Chris@140 2027 if (SVFileReader::identifyXmlFile(source.getLocalFilename()) ==
Chris@140 2028 SVFileReader::SVSessionFile) {
Chris@293 2029 cerr << "This XML file looks like a session file, attempting to open it as a session" << endl;
Chris@140 2030 } else {
Chris@140 2031 return FileOpenFailed;
Chris@140 2032 }
Chris@140 2033 } else {
Chris@140 2034 return FileOpenFailed;
Chris@140 2035 }
Chris@140 2036 }
Chris@45 2037
Chris@140 2038 QXmlInputSource *inputSource = 0;
Chris@140 2039 BZipFileDevice *bzFile = 0;
Chris@140 2040 QFile *rawFile = 0;
Chris@140 2041
Chris@341 2042 if (source.getExtension().toLower() == sessionExt) {
Chris@140 2043 bzFile = new BZipFileDevice(source.getLocalFilename());
Chris@140 2044 if (!bzFile->open(QIODevice::ReadOnly)) {
Chris@140 2045 delete bzFile;
Chris@140 2046 return FileOpenFailed;
Chris@140 2047 }
Chris@140 2048 inputSource = new QXmlInputSource(bzFile);
Chris@140 2049 } else {
Chris@140 2050 rawFile = new QFile(source.getLocalFilename());
Chris@140 2051 inputSource = new QXmlInputSource(rawFile);
Chris@140 2052 }
Chris@140 2053
Chris@140 2054 if (!checkSaveModified()) {
Chris@140 2055 if (bzFile) bzFile->close();
Chris@140 2056 delete inputSource;
Chris@140 2057 delete bzFile;
Chris@140 2058 delete rawFile;
Chris@140 2059 return FileOpenCancelled;
Chris@140 2060 }
Chris@45 2061
Chris@45 2062 QString error;
Chris@45 2063 closeSession();
Chris@45 2064 createDocument();
Chris@45 2065
Chris@45 2066 PaneCallback callback(this);
Chris@45 2067 m_viewManager->clearSelections();
Chris@45 2068
Chris@45 2069 SVFileReader reader(m_document, callback, source.getLocation());
Chris@79 2070 connect
Chris@79 2071 (&reader, SIGNAL(modelRegenerationFailed(QString, QString, QString)),
Chris@79 2072 this, SLOT(modelRegenerationFailed(QString, QString, QString)));
Chris@79 2073 connect
Chris@79 2074 (&reader, SIGNAL(modelRegenerationWarning(QString, QString, QString)),
Chris@79 2075 this, SLOT(modelRegenerationWarning(QString, QString, QString)));
Chris@140 2076
Chris@140 2077 reader.parse(*inputSource);
Chris@45 2078
Chris@45 2079 if (!reader.isOK()) {
Chris@45 2080 error = tr("SV XML file read error:\n%1").arg(reader.getErrorString());
Chris@45 2081 }
Chris@45 2082
Chris@140 2083 if (bzFile) bzFile->close();
Chris@140 2084
Chris@140 2085 delete inputSource;
Chris@140 2086 delete bzFile;
Chris@140 2087 delete rawFile;
Chris@45 2088
Chris@45 2089 bool ok = (error == "");
Chris@45 2090
Chris@45 2091 if (ok) {
Chris@45 2092
Chris@164 2093 emit activity(tr("Import session file \"%1\"").arg(source.getLocation()));
Chris@164 2094
Chris@595 2095 setWindowTitle(tr("%1: %2")
Chris@57 2096 .arg(QApplication::applicationName())
Chris@595 2097 .arg(source.getLocation()));
Chris@595 2098
Chris@601 2099 if (!source.isRemote() && !m_document->isIncomplete()) {
Chris@601 2100 // Setting the session file path enables the Save (as
Chris@601 2101 // opposed to Save As...) option. We can't do this if we
Chris@601 2102 // don't have a local path to save to, but we also don't
Chris@601 2103 // want to do it if we failed to find an audio file or
Chris@601 2104 // similar on load, as the audio reference would then end
Chris@601 2105 // up being lost from any saved or auto-saved-on-exit copy
Chris@601 2106 m_sessionFile = source.getLocalFilename();
Chris@602 2107 } else {
Chris@602 2108 QMessageBox::warning
Chris@602 2109 (this,
Chris@602 2110 tr("Incomplete session loaded"),
Chris@603 2111 tr("Some of the audio content referred to by the original session file could not be loaded.\nIf you save this session, it will be saved without any reference to that audio, and information may be lost."),
Chris@602 2112 QMessageBox::Ok);
Chris@601 2113 }
Chris@595 2114
Chris@595 2115 setupMenus();
Chris@577 2116 findTimeRulerLayer();
Chris@45 2117
Chris@595 2118 CommandHistory::getInstance()->clear();
Chris@595 2119 CommandHistory::getInstance()->documentSaved();
Chris@595 2120 m_documentModified = false;
Chris@595 2121 updateMenuStates();
Chris@45 2122
Chris@227 2123 m_recentFiles.addFile(source.getLocation());
Chris@45 2124
Chris@45 2125 if (!source.isRemote()) {
Chris@45 2126 // for file dialog
Chris@45 2127 registerLastOpenedFilePath(FileFinder::SessionFile,
Chris@227 2128 source.getLocalFilename());
Chris@45 2129 }
Chris@45 2130
Chris@342 2131 emit sessionLoaded();
Chris@342 2132
Chris@45 2133 } else {
Chris@595 2134 setWindowTitle(QApplication::applicationName());
Chris@45 2135 }
Chris@45 2136
Chris@45 2137 return ok ? FileOpenSucceeded : FileOpenFailed;
Chris@45 2138 }
Chris@45 2139
Chris@141 2140 MainWindowBase::FileOpenStatus
Chris@230 2141 MainWindowBase::openSessionTemplate(QString templateName)
Chris@230 2142 {
Chris@230 2143 // Template in the user's template directory takes
Chris@230 2144 // priority over a bundled one; we don't unbundle, but
Chris@230 2145 // open directly from the bundled file (where applicable)
Chris@230 2146 ResourceFinder rf;
Chris@230 2147 QString tfile = rf.getResourcePath("templates", templateName + ".svt");
Chris@230 2148 if (tfile != "") {
Chris@294 2149 cerr << "SV loading template file " << tfile << endl;
Chris@230 2150 return openSessionTemplate(FileSource("file:" + tfile));
Chris@230 2151 } else {
Chris@230 2152 return FileOpenFailed;
Chris@230 2153 }
Chris@230 2154 }
Chris@230 2155
Chris@230 2156 MainWindowBase::FileOpenStatus
Chris@227 2157 MainWindowBase::openSessionTemplate(FileSource source)
Chris@227 2158 {
Chris@294 2159 cerr << "MainWindowBase::openSessionTemplate(" << source.getLocation() << ")" << endl;
Chris@227 2160
Chris@227 2161 if (!source.isAvailable()) return FileOpenFailed;
Chris@227 2162 source.waitForData();
Chris@227 2163
Chris@227 2164 QXmlInputSource *inputSource = 0;
Chris@227 2165 QFile *file = 0;
Chris@227 2166
Chris@227 2167 file = new QFile(source.getLocalFilename());
Chris@227 2168 inputSource = new QXmlInputSource(file);
Chris@227 2169
Chris@227 2170 if (!checkSaveModified()) {
Chris@227 2171 delete inputSource;
Chris@227 2172 delete file;
Chris@227 2173 return FileOpenCancelled;
Chris@227 2174 }
Chris@227 2175
Chris@227 2176 QString error;
Chris@227 2177 closeSession();
Chris@227 2178 createDocument();
Chris@227 2179
Chris@227 2180 PaneCallback callback(this);
Chris@227 2181 m_viewManager->clearSelections();
Chris@227 2182
Chris@227 2183 SVFileReader reader(m_document, callback, source.getLocation());
Chris@227 2184 connect
Chris@227 2185 (&reader, SIGNAL(modelRegenerationFailed(QString, QString, QString)),
Chris@227 2186 this, SLOT(modelRegenerationFailed(QString, QString, QString)));
Chris@227 2187 connect
Chris@227 2188 (&reader, SIGNAL(modelRegenerationWarning(QString, QString, QString)),
Chris@227 2189 this, SLOT(modelRegenerationWarning(QString, QString, QString)));
Chris@227 2190
Chris@227 2191 reader.parse(*inputSource);
Chris@227 2192
Chris@227 2193 if (!reader.isOK()) {
Chris@227 2194 error = tr("SV XML file read error:\n%1").arg(reader.getErrorString());
Chris@227 2195 }
Chris@227 2196
Chris@227 2197 delete inputSource;
Chris@227 2198 delete file;
Chris@227 2199
Chris@227 2200 bool ok = (error == "");
Chris@227 2201
Chris@227 2202 setWindowTitle(QApplication::applicationName());
Chris@227 2203
Chris@227 2204 if (ok) {
Chris@227 2205
Chris@227 2206 emit activity(tr("Open session template \"%1\"").arg(source.getLocation()));
Chris@227 2207
Chris@595 2208 setupMenus();
Chris@577 2209 findTimeRulerLayer();
Chris@227 2210
Chris@595 2211 CommandHistory::getInstance()->clear();
Chris@595 2212 CommandHistory::getInstance()->documentSaved();
Chris@595 2213 m_documentModified = false;
Chris@595 2214 updateMenuStates();
Chris@342 2215
Chris@342 2216 emit sessionLoaded();
Chris@227 2217 }
Chris@227 2218
Chris@227 2219 return ok ? FileOpenSucceeded : FileOpenFailed;
Chris@227 2220 }
Chris@227 2221
Chris@227 2222 MainWindowBase::FileOpenStatus
Chris@141 2223 MainWindowBase::openSessionFromRDF(FileSource source)
Chris@141 2224 {
Chris@233 2225 SVDEBUG << "MainWindowBase::openSessionFromRDF(" << source.getLocation() << ")" << endl;
Chris@141 2226
Chris@141 2227 if (!source.isAvailable()) return FileOpenFailed;
Chris@141 2228 source.waitForData();
Chris@141 2229
Chris@145 2230 if (!checkSaveModified()) {
Chris@145 2231 return FileOpenCancelled;
Chris@141 2232 }
Chris@143 2233
Chris@145 2234 closeSession();
Chris@145 2235 createDocument();
Chris@145 2236
Chris@145 2237 FileOpenStatus status = openLayersFromRDF(source);
Chris@141 2238
Chris@141 2239 setupMenus();
Chris@577 2240 findTimeRulerLayer();
Chris@141 2241
Chris@141 2242 setWindowTitle(tr("%1: %2")
Chris@141 2243 .arg(QApplication::applicationName())
Chris@141 2244 .arg(source.getLocation()));
Chris@141 2245 CommandHistory::getInstance()->clear();
Chris@141 2246 CommandHistory::getInstance()->documentSaved();
Chris@141 2247 m_documentModified = false;
Chris@145 2248
Chris@342 2249 emit sessionLoaded();
Chris@342 2250
Chris@145 2251 return status;
Chris@145 2252 }
Chris@145 2253
Chris@145 2254 MainWindowBase::FileOpenStatus
Chris@145 2255 MainWindowBase::openLayersFromRDF(FileSource source)
Chris@145 2256 {
Chris@435 2257 sv_samplerate_t rate = 0;
Chris@145 2258
Chris@233 2259 SVDEBUG << "MainWindowBase::openLayersFromRDF" << endl;
Chris@186 2260
Chris@145 2261 ProgressDialog dialog(tr("Importing from RDF..."), true, 2000, this);
Chris@145 2262 connect(&dialog, SIGNAL(showing()), this, SIGNAL(hideSplash()));
Chris@145 2263
Chris@145 2264 if (getMainModel()) {
Chris@145 2265 rate = getMainModel()->getSampleRate();
Chris@145 2266 } else if (Preferences::getInstance()->getResampleOnLoad()) {
Chris@552 2267 if (getMainModel()) {
Chris@552 2268 rate = getMainModel()->getSampleRate();
Chris@552 2269 }
Chris@145 2270 }
Chris@145 2271
Chris@145 2272 RDFImporter importer
Chris@145 2273 (QUrl::fromLocalFile(source.getLocalFilename()).toString(), rate);
Chris@145 2274
Chris@145 2275 if (!importer.isOK()) {
Chris@147 2276 if (importer.getErrorString() != "") {
Chris@147 2277 QMessageBox::critical
Chris@147 2278 (this, tr("Failed to import RDF"),
Chris@147 2279 tr("<b>Failed to import RDF</b><p>Importing data from RDF document at \"%1\" failed: %2</p>")
Chris@147 2280 .arg(source.getLocation()).arg(importer.getErrorString()));
Chris@147 2281 }
Chris@145 2282 return FileOpenFailed;
Chris@145 2283 }
Chris@145 2284
Chris@145 2285 std::vector<Model *> models = importer.getDataModels(&dialog);
Chris@145 2286
Chris@145 2287 dialog.setMessage(tr("Importing from RDF..."));
Chris@145 2288
Chris@145 2289 if (models.empty()) {
Chris@186 2290 QMessageBox::critical
Chris@186 2291 (this, tr("Failed to import RDF"),
Chris@186 2292 tr("<b>Failed to import RDF</b><p>No suitable data models found for import from RDF document at \"%1\"</p>").arg(source.getLocation()));
Chris@145 2293 return FileOpenFailed;
Chris@145 2294 }
Chris@145 2295
Chris@164 2296 emit activity(tr("Import RDF document \"%1\"").arg(source.getLocation()));
Chris@164 2297
Chris@145 2298 std::set<Model *> added;
Chris@145 2299
Chris@221 2300 for (int i = 0; i < (int)models.size(); ++i) {
Chris@145 2301
Chris@145 2302 Model *m = models[i];
Chris@145 2303 WaveFileModel *w = dynamic_cast<WaveFileModel *>(m);
Chris@145 2304
Chris@145 2305 if (w) {
Chris@145 2306
Chris@145 2307 Pane *pane = addPaneToStack();
Chris@145 2308 Layer *layer = 0;
Chris@145 2309
Chris@145 2310 if (m_timeRulerLayer) {
Chris@145 2311 m_document->addLayerToView(pane, m_timeRulerLayer);
Chris@145 2312 }
Chris@145 2313
Chris@145 2314 if (!getMainModel()) {
Chris@145 2315 m_document->setMainModel(w);
Chris@145 2316 layer = m_document->createMainModelLayer(LayerFactory::Waveform);
Chris@145 2317 } else {
Chris@145 2318 layer = m_document->createImportedLayer(w);
Chris@145 2319 }
Chris@145 2320
Chris@145 2321 m_document->addLayerToView(pane, layer);
Chris@145 2322
Chris@145 2323 added.insert(w);
Chris@145 2324
Chris@221 2325 for (int j = 0; j < (int)models.size(); ++j) {
Chris@145 2326
Chris@145 2327 Model *dm = models[j];
Chris@145 2328
Chris@145 2329 if (dm == m) continue;
Chris@145 2330 if (dm->getSourceModel() != m) continue;
Chris@145 2331
Chris@145 2332 layer = m_document->createImportedLayer(dm);
Chris@145 2333
Chris@145 2334 if (layer->isLayerOpaque() ||
Chris@145 2335 dynamic_cast<Colour3DPlotLayer *>(layer)) {
Chris@145 2336
Chris@156 2337 // these always go in a new pane, with nothing
Chris@156 2338 // else going in the same pane
Chris@156 2339
Chris@145 2340 Pane *singleLayerPane = addPaneToStack();
Chris@145 2341 if (m_timeRulerLayer) {
Chris@145 2342 m_document->addLayerToView(singleLayerPane, m_timeRulerLayer);
Chris@145 2343 }
Chris@145 2344 m_document->addLayerToView(singleLayerPane, layer);
Chris@145 2345
Chris@156 2346 } else if (layer->getLayerColourSignificance() ==
Chris@156 2347 Layer::ColourHasMeaningfulValue) {
Chris@156 2348
Chris@156 2349 // these can go in a pane with something else, but
Chris@156 2350 // only if none of the something elses also have
Chris@156 2351 // this quality
Chris@156 2352
Chris@156 2353 bool needNewPane = false;
Chris@156 2354 for (int i = 0; i < pane->getLayerCount(); ++i) {
Chris@156 2355 Layer *otherLayer = pane->getLayer(i);
Chris@156 2356 if (otherLayer &&
Chris@156 2357 (otherLayer->getLayerColourSignificance() ==
Chris@156 2358 Layer::ColourHasMeaningfulValue)) {
Chris@156 2359 needNewPane = true;
Chris@156 2360 break;
Chris@156 2361 }
Chris@156 2362 }
Chris@156 2363 if (needNewPane) {
Chris@156 2364 pane = addPaneToStack();
Chris@156 2365 }
Chris@156 2366
Chris@156 2367 m_document->addLayerToView(pane, layer);
Chris@156 2368
Chris@145 2369 } else {
Chris@145 2370
Chris@145 2371 if (pane->getLayerCount() > 4) {
Chris@145 2372 pane = addPaneToStack();
Chris@145 2373 }
Chris@145 2374
Chris@145 2375 m_document->addLayerToView(pane, layer);
Chris@145 2376 }
Chris@145 2377
Chris@145 2378 added.insert(dm);
Chris@145 2379 }
Chris@145 2380 }
Chris@145 2381 }
Chris@145 2382
Chris@221 2383 for (int i = 0; i < (int)models.size(); ++i) {
Chris@145 2384
Chris@145 2385 Model *m = models[i];
Chris@145 2386
Chris@145 2387 if (added.find(m) == added.end()) {
Chris@145 2388
Chris@145 2389 Layer *layer = m_document->createImportedLayer(m);
Chris@145 2390 if (!layer) return FileOpenFailed;
Chris@145 2391
Chris@145 2392 Pane *singleLayerPane = addPaneToStack();
Chris@145 2393 if (m_timeRulerLayer) {
Chris@145 2394 m_document->addLayerToView(singleLayerPane, m_timeRulerLayer);
Chris@145 2395 }
Chris@145 2396 m_document->addLayerToView(singleLayerPane, layer);
Chris@145 2397 }
Chris@145 2398 }
Chris@145 2399
Chris@145 2400 m_recentFiles.addFile(source.getLocation());
Chris@145 2401 return FileOpenSucceeded;
Chris@141 2402 }
Chris@141 2403
Chris@584 2404 class AudioLogCallback : public breakfastquay::AudioFactory::LogCallback
Chris@584 2405 {
Chris@584 2406 public:
Chris@584 2407 void log(std::string message) const override {
Chris@584 2408 SVDEBUG << message << endl;
Chris@584 2409 }
Chris@584 2410 };
Chris@584 2411
Chris@45 2412 void
Chris@475 2413 MainWindowBase::createAudioIO()
Chris@45 2414 {
Chris@475 2415 if (m_playTarget || m_audioIO) return;
Chris@475 2416
Chris@584 2417 static AudioLogCallback audioLogCallback;
Chris@584 2418 breakfastquay::AudioFactory::setLogCallback(&audioLogCallback);
Chris@584 2419
Chris@475 2420 if (!(m_soundOptions & WithAudioOutput)) return;
Chris@45 2421
Chris@126 2422 QSettings settings;
Chris@126 2423 settings.beginGroup("Preferences");
Chris@547 2424 QString implementation = settings.value
Chris@547 2425 ("audio-target", "").toString();
Chris@547 2426 QString suffix;
Chris@547 2427 if (implementation != "") suffix = "-" + implementation;
Chris@547 2428 QString recordDevice = settings.value
Chris@547 2429 ("audio-record-device" + suffix, "").toString();
Chris@547 2430 QString playbackDevice = settings.value
Chris@547 2431 ("audio-playback-device" + suffix, "").toString();
Chris@126 2432 settings.endGroup();
Chris@547 2433
Chris@547 2434 if (implementation == "auto") {
Chris@547 2435 implementation = "";
Chris@547 2436 }
Chris@468 2437
Chris@547 2438 breakfastquay::AudioFactory::Preference preference;
Chris@547 2439 preference.implementation = implementation.toStdString();
Chris@547 2440 preference.recordDevice = recordDevice.toStdString();
Chris@547 2441 preference.playbackDevice = playbackDevice.toStdString();
Chris@547 2442
Chris@547 2443 SVCERR << "createAudioIO: Preferred implementation = \""
Chris@547 2444 << preference.implementation << "\"" << endl;
Chris@547 2445 SVCERR << "createAudioIO: Preferred playback device = \""
Chris@547 2446 << preference.playbackDevice << "\"" << endl;
Chris@547 2447 SVCERR << "createAudioIO: Preferred record device = \""
Chris@547 2448 << preference.recordDevice << "\"" << endl;
Chris@475 2449
Chris@551 2450 if (!m_resamplerWrapper) {
Chris@551 2451 m_resamplerWrapper = new breakfastquay::ResamplerWrapper(m_playSource);
Chris@551 2452 m_playSource->setResamplerWrapper(m_resamplerWrapper);
Chris@551 2453 }
Chris@569 2454
Chris@569 2455 std::string errorString;
Chris@551 2456
Chris@475 2457 if (m_soundOptions & WithAudioInput) {
Chris@475 2458 m_audioIO = breakfastquay::AudioFactory::
Chris@569 2459 createCallbackIO(m_recordTarget, m_resamplerWrapper,
Chris@569 2460 preference, errorString);
Chris@525 2461 if (m_audioIO) {
Chris@525 2462 m_audioIO->suspend(); // start in suspended state
Chris@525 2463 m_playSource->setSystemPlaybackTarget(m_audioIO);
Chris@586 2464 } else {
Chris@586 2465 // Failed to create audio I/O; this may just mean there is
Chris@586 2466 // no record device, so fall through to see what happens
Chris@586 2467 // next. We only report complete failure if we end up with
Chris@586 2468 // neither m_audioIO nor m_playTarget.
Chris@525 2469 }
Chris@586 2470 }
Chris@586 2471
Chris@586 2472 if (!m_audioIO) {
Chris@475 2473 m_playTarget = breakfastquay::AudioFactory::
Chris@569 2474 createCallbackPlayTarget(m_resamplerWrapper,
Chris@569 2475 preference, errorString);
Chris@525 2476 if (m_playTarget) {
Chris@525 2477 m_playTarget->suspend(); // start in suspended state
Chris@525 2478 m_playSource->setSystemPlaybackTarget(m_playTarget);
Chris@525 2479 }
Chris@475 2480 }
Chris@475 2481
Chris@475 2482 if (!m_playTarget && !m_audioIO) {
Chris@104 2483 emit hideSplash();
Chris@569 2484 QString message;
Chris@569 2485 QString error = errorString.c_str();
Chris@569 2486 QString firstBit, secondBit;
Chris@547 2487 if (implementation == "") {
Chris@569 2488 if (error == "") {
Chris@569 2489 firstBit = tr("<b>No audio available</b><p>Could not open an audio device.</p>");
Chris@569 2490 } else {
Chris@569 2491 firstBit = tr("<b>No audio available</b><p>Could not open audio device: %1</p>").arg(error);
Chris@569 2492 }
Chris@569 2493 if (m_soundOptions & WithAudioInput) {
Chris@569 2494 secondBit = tr("<p>Automatic audio device detection failed. Audio playback and recording will not be available during this session.</p>");
Chris@569 2495 } else {
Chris@569 2496 secondBit = tr("<p>Automatic audio device detection failed. Audio playback will not be available during this session.</p>");
Chris@569 2497 }
Chris@126 2498 } else {
Chris@569 2499 QString driverName = breakfastquay::AudioFactory::
Chris@569 2500 getImplementationDescription(implementation.toStdString())
Chris@569 2501 .c_str();
Chris@569 2502 if (error == "") {
Chris@569 2503 firstBit = tr("<b>No audio available</b><p>Failed to open your preferred audio driver (\"%1\").</p>").arg(driverName);
Chris@569 2504 } else {
Chris@569 2505 firstBit = tr("<b>No audio available</b><p>Failed to open your preferred audio driver (\"%1\"): %2.</p>").arg(driverName).arg(error);
Chris@569 2506 }
Chris@569 2507 if (m_soundOptions & WithAudioInput) {
Chris@569 2508 secondBit = tr("<p>Audio playback and recording will not be available during this session.</p>");
Chris@569 2509 } else {
Chris@569 2510 secondBit = tr("<p>Audio playback will not be available during this session.</p>");
Chris@569 2511 }
Chris@126 2512 }
Chris@570 2513 SVDEBUG << "createAudioIO: ERROR: Failed to open audio device \""
Chris@570 2514 << implementation << "\": error is: " << error << endl;
Chris@569 2515 QMessageBox::warning(this, tr("Couldn't open audio device"),
Chris@569 2516 firstBit + secondBit, QMessageBox::Ok);
Chris@45 2517 }
Chris@45 2518 }
Chris@45 2519
Chris@556 2520 void
Chris@556 2521 MainWindowBase::deleteAudioIO()
Chris@556 2522 {
Chris@556 2523 // First prevent this trying to call target.
Chris@559 2524 if (m_playSource) {
Chris@559 2525 m_playSource->setSystemPlaybackTarget(0);
Chris@559 2526 m_playSource->setResamplerWrapper(0);
Chris@559 2527 }
Chris@556 2528
Chris@556 2529 // Then delete the breakfastquay::System object.
Chris@556 2530 // Only one of these two exists!
Chris@556 2531 delete m_audioIO;
Chris@556 2532 delete m_playTarget;
Chris@556 2533
Chris@559 2534 // And the breakfastquay resampler wrapper. We need to
Chris@559 2535 // delete/recreate this if the channel count changes, which is one
Chris@559 2536 // of the use cases for recreateAudioIO() calling this
Chris@559 2537 delete m_resamplerWrapper;
Chris@559 2538
Chris@556 2539 m_audioIO = 0;
Chris@556 2540 m_playTarget = 0;
Chris@559 2541 m_resamplerWrapper = 0;
Chris@556 2542 }
Chris@556 2543
Chris@556 2544 void
Chris@556 2545 MainWindowBase::recreateAudioIO()
Chris@556 2546 {
Chris@556 2547 deleteAudioIO();
Chris@556 2548 createAudioIO();
Chris@556 2549 }
Chris@556 2550
Chris@570 2551 void
Chris@570 2552 MainWindowBase::audioChannelCountIncreased(int)
Chris@570 2553 {
Chris@570 2554 recreateAudioIO();
Chris@610 2555
Chris@610 2556 if (m_recordTarget &&
Chris@610 2557 m_recordTarget->isRecording() &&
Chris@610 2558 m_audioIO) {
Chris@610 2559 SVCERR << "MainWindowBase::audioChannelCountIncreased: we were recording already, so resuming IO now" << endl;
Chris@610 2560 m_audioIO->resume();
Chris@610 2561 }
Chris@570 2562 }
Chris@570 2563
Chris@45 2564 WaveFileModel *
Chris@45 2565 MainWindowBase::getMainModel()
Chris@45 2566 {
Chris@45 2567 if (!m_document) return 0;
Chris@45 2568 return m_document->getMainModel();
Chris@45 2569 }
Chris@45 2570
Chris@45 2571 const WaveFileModel *
Chris@45 2572 MainWindowBase::getMainModel() const
Chris@45 2573 {
Chris@45 2574 if (!m_document) return 0;
Chris@45 2575 return m_document->getMainModel();
Chris@45 2576 }
Chris@45 2577
Chris@45 2578 void
Chris@45 2579 MainWindowBase::createDocument()
Chris@45 2580 {
Chris@45 2581 m_document = new Document;
Chris@45 2582
Chris@45 2583 connect(m_document, SIGNAL(layerAdded(Layer *)),
Chris@595 2584 this, SLOT(layerAdded(Layer *)));
Chris@45 2585 connect(m_document, SIGNAL(layerRemoved(Layer *)),
Chris@595 2586 this, SLOT(layerRemoved(Layer *)));
Chris@45 2587 connect(m_document, SIGNAL(layerAboutToBeDeleted(Layer *)),
Chris@595 2588 this, SLOT(layerAboutToBeDeleted(Layer *)));
Chris@45 2589 connect(m_document, SIGNAL(layerInAView(Layer *, bool)),
Chris@595 2590 this, SLOT(layerInAView(Layer *, bool)));
Chris@45 2591
Chris@45 2592 connect(m_document, SIGNAL(modelAdded(Model *)),
Chris@595 2593 this, SLOT(modelAdded(Model *)));
Chris@45 2594 connect(m_document, SIGNAL(mainModelChanged(WaveFileModel *)),
Chris@595 2595 this, SLOT(mainModelChanged(WaveFileModel *)));
Chris@45 2596 connect(m_document, SIGNAL(modelAboutToBeDeleted(Model *)),
Chris@595 2597 this, SLOT(modelAboutToBeDeleted(Model *)));
Chris@45 2598
Chris@78 2599 connect(m_document, SIGNAL(modelGenerationFailed(QString, QString)),
Chris@78 2600 this, SLOT(modelGenerationFailed(QString, QString)));
Chris@78 2601 connect(m_document, SIGNAL(modelRegenerationWarning(QString, QString, QString)),
Chris@78 2602 this, SLOT(modelRegenerationWarning(QString, QString, QString)));
Chris@429 2603 connect(m_document, SIGNAL(alignmentComplete(AlignmentModel *)),
Chris@429 2604 this, SLOT(alignmentComplete(AlignmentModel *)));
Chris@423 2605 connect(m_document, SIGNAL(alignmentFailed(QString)),
Chris@423 2606 this, SLOT(alignmentFailed(QString)));
Chris@160 2607
Chris@160 2608 emit replacedDocument();
Chris@45 2609 }
Chris@45 2610
Chris@45 2611 bool
Chris@45 2612 MainWindowBase::saveSessionFile(QString path)
Chris@45 2613 {
Chris@217 2614 try {
Chris@217 2615
Chris@217 2616 TempWriteFile temp(path);
Chris@217 2617
Chris@217 2618 BZipFileDevice bzFile(temp.getTemporaryFilename());
Chris@217 2619 if (!bzFile.open(QIODevice::WriteOnly)) {
Chris@293 2620 cerr << "Failed to open session file \""
Chris@294 2621 << temp.getTemporaryFilename()
Chris@217 2622 << "\" for writing: "
Chris@293 2623 << bzFile.errorString() << endl;
Chris@217 2624 return false;
Chris@217 2625 }
Chris@217 2626
Chris@217 2627 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
Chris@217 2628
Chris@217 2629 QTextStream out(&bzFile);
Chris@432 2630 out.setCodec(QTextCodec::codecForName("UTF-8"));
Chris@226 2631 toXml(out, false);
Chris@217 2632 out.flush();
Chris@217 2633
Chris@217 2634 QApplication::restoreOverrideCursor();
Chris@217 2635
Chris@217 2636 if (!bzFile.isOK()) {
Chris@217 2637 QMessageBox::critical(this, tr("Failed to write file"),
Chris@217 2638 tr("<b>Save failed</b><p>Failed to write to file \"%1\": %2")
Chris@217 2639 .arg(path).arg(bzFile.errorString()));
Chris@217 2640 bzFile.close();
Chris@217 2641 return false;
Chris@217 2642 }
Chris@217 2643
Chris@217 2644 bzFile.close();
Chris@217 2645 temp.moveToTarget();
Chris@217 2646 return true;
Chris@217 2647
Chris@217 2648 } catch (FileOperationFailed &f) {
Chris@217 2649
Chris@217 2650 QMessageBox::critical(this, tr("Failed to write file"),
Chris@217 2651 tr("<b>Save failed</b><p>Failed to write to file \"%1\": %2")
Chris@217 2652 .arg(path).arg(f.what()));
Chris@45 2653 return false;
Chris@45 2654 }
Chris@45 2655 }
Chris@45 2656
Chris@224 2657 bool
Chris@224 2658 MainWindowBase::saveSessionTemplate(QString path)
Chris@224 2659 {
Chris@224 2660 try {
Chris@224 2661
Chris@224 2662 TempWriteFile temp(path);
Chris@224 2663
Chris@224 2664 QFile file(temp.getTemporaryFilename());
Chris@224 2665 if (!file.open(QIODevice::WriteOnly)) {
Chris@293 2666 cerr << "Failed to open session template file \""
Chris@294 2667 << temp.getTemporaryFilename()
Chris@224 2668 << "\" for writing: "
Chris@294 2669 << file.errorString() << endl;
Chris@224 2670 return false;
Chris@224 2671 }
Chris@224 2672
Chris@224 2673 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
Chris@224 2674
Chris@224 2675 QTextStream out(&file);
Chris@432 2676 out.setCodec(QTextCodec::codecForName("UTF-8"));
Chris@226 2677 toXml(out, true);
Chris@224 2678 out.flush();
Chris@224 2679
Chris@224 2680 QApplication::restoreOverrideCursor();
Chris@224 2681
Chris@224 2682 file.close();
Chris@224 2683 temp.moveToTarget();
Chris@224 2684 return true;
Chris@224 2685
Chris@224 2686 } catch (FileOperationFailed &f) {
Chris@224 2687
Chris@224 2688 QMessageBox::critical(this, tr("Failed to write file"),
Chris@224 2689 tr("<b>Save failed</b><p>Failed to write to file \"%1\": %2")
Chris@224 2690 .arg(path).arg(f.what()));
Chris@224 2691 return false;
Chris@224 2692 }
Chris@224 2693 }
Chris@224 2694
Chris@45 2695 void
Chris@226 2696 MainWindowBase::toXml(QTextStream &out, bool asTemplate)
Chris@45 2697 {
Chris@45 2698 QString indent(" ");
Chris@45 2699
Chris@45 2700 out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
Chris@45 2701 out << "<!DOCTYPE sonic-visualiser>\n";
Chris@45 2702 out << "<sv>\n";
Chris@45 2703
Chris@226 2704 if (asTemplate) {
Chris@226 2705 m_document->toXmlAsTemplate(out, "", "");
Chris@226 2706 } else {
Chris@226 2707 m_document->toXml(out, "", "");
Chris@226 2708 }
Chris@45 2709
Chris@45 2710 out << "<display>\n";
Chris@45 2711
Chris@45 2712 out << QString(" <window width=\"%1\" height=\"%2\"/>\n")
Chris@595 2713 .arg(width()).arg(height());
Chris@45 2714
Chris@45 2715 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@45 2716
Chris@595 2717 Pane *pane = m_paneStack->getPane(i);
Chris@595 2718
Chris@595 2719 if (pane) {
Chris@45 2720 pane->toXml(out, indent);
Chris@595 2721 }
Chris@45 2722 }
Chris@45 2723
Chris@45 2724 out << "</display>\n";
Chris@45 2725
Chris@45 2726 m_viewManager->getSelection().toXml(out);
Chris@45 2727
Chris@45 2728 out << "</sv>\n";
Chris@45 2729 }
Chris@45 2730
Chris@45 2731 Pane *
Chris@45 2732 MainWindowBase::addPaneToStack()
Chris@45 2733 {
Chris@342 2734 cerr << "MainWindowBase::addPaneToStack()" << endl;
Chris@45 2735 AddPaneCommand *command = new AddPaneCommand(this);
Chris@45 2736 CommandHistory::getInstance()->addCommand(command);
Chris@57 2737 Pane *pane = command->getPane();
Chris@57 2738 return pane;
Chris@45 2739 }
Chris@45 2740
Chris@45 2741 void
Chris@45 2742 MainWindowBase::zoomIn()
Chris@45 2743 {
Chris@45 2744 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 2745 if (currentPane) currentPane->zoom(true);
Chris@45 2746 }
Chris@45 2747
Chris@45 2748 void
Chris@45 2749 MainWindowBase::zoomOut()
Chris@45 2750 {
Chris@45 2751 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 2752 if (currentPane) currentPane->zoom(false);
Chris@45 2753 }
Chris@45 2754
Chris@45 2755 void
Chris@45 2756 MainWindowBase::zoomToFit()
Chris@45 2757 {
Chris@45 2758 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 2759 if (!currentPane) return;
Chris@45 2760
Chris@45 2761 Model *model = getMainModel();
Chris@45 2762 if (!model) return;
Chris@45 2763
Chris@434 2764 sv_frame_t start = model->getStartFrame();
Chris@434 2765 sv_frame_t end = model->getEndFrame();
Chris@60 2766 if (m_playSource) end = std::max(end, m_playSource->getPlayEndFrame());
Chris@366 2767 int pixels = currentPane->width();
Chris@366 2768
Chris@366 2769 int sw = currentPane->getVerticalScaleWidth();
Chris@45 2770 if (pixels > sw * 2) pixels -= sw * 2;
Chris@45 2771 else pixels = 1;
Chris@45 2772 if (pixels > 4) pixels -= 4;
Chris@45 2773
Chris@436 2774 int zoomLevel = int((end - start) / pixels);
Chris@150 2775 if (zoomLevel < 1) zoomLevel = 1;
Chris@45 2776
Chris@45 2777 currentPane->setZoomLevel(zoomLevel);
Chris@45 2778 currentPane->setCentreFrame((start + end) / 2);
Chris@45 2779 }
Chris@45 2780
Chris@45 2781 void
Chris@45 2782 MainWindowBase::zoomDefault()
Chris@45 2783 {
Chris@45 2784 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@302 2785 QSettings settings;
Chris@302 2786 settings.beginGroup("MainWindow");
Chris@302 2787 int zoom = settings.value("zoom-default", 1024).toInt();
Chris@302 2788 settings.endGroup();
Chris@302 2789 if (currentPane) currentPane->setZoomLevel(zoom);
Chris@45 2790 }
Chris@45 2791
Chris@45 2792 void
Chris@45 2793 MainWindowBase::scrollLeft()
Chris@45 2794 {
Chris@45 2795 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 2796 if (currentPane) currentPane->scroll(false, false);
Chris@45 2797 }
Chris@45 2798
Chris@45 2799 void
Chris@45 2800 MainWindowBase::jumpLeft()
Chris@45 2801 {
Chris@45 2802 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 2803 if (currentPane) currentPane->scroll(false, true);
Chris@45 2804 }
Chris@45 2805
Chris@45 2806 void
Chris@162 2807 MainWindowBase::peekLeft()
Chris@162 2808 {
Chris@162 2809 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@162 2810 if (currentPane) currentPane->scroll(false, false, false);
Chris@162 2811 }
Chris@162 2812
Chris@162 2813 void
Chris@45 2814 MainWindowBase::scrollRight()
Chris@45 2815 {
Chris@45 2816 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 2817 if (currentPane) currentPane->scroll(true, false);
Chris@45 2818 }
Chris@45 2819
Chris@45 2820 void
Chris@45 2821 MainWindowBase::jumpRight()
Chris@45 2822 {
Chris@45 2823 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 2824 if (currentPane) currentPane->scroll(true, true);
Chris@45 2825 }
Chris@45 2826
Chris@45 2827 void
Chris@162 2828 MainWindowBase::peekRight()
Chris@162 2829 {
Chris@162 2830 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@162 2831 if (currentPane) currentPane->scroll(true, false, false);
Chris@162 2832 }
Chris@162 2833
Chris@162 2834 void
Chris@45 2835 MainWindowBase::showNoOverlays()
Chris@45 2836 {
Chris@45 2837 m_viewManager->setOverlayMode(ViewManager::NoOverlays);
Chris@45 2838 }
Chris@45 2839
Chris@45 2840 void
Chris@45 2841 MainWindowBase::showMinimalOverlays()
Chris@45 2842 {
Chris@335 2843 m_viewManager->setOverlayMode(ViewManager::StandardOverlays);
Chris@45 2844 }
Chris@45 2845
Chris@45 2846 void
Chris@45 2847 MainWindowBase::showAllOverlays()
Chris@45 2848 {
Chris@45 2849 m_viewManager->setOverlayMode(ViewManager::AllOverlays);
Chris@45 2850 }
Chris@45 2851
Chris@45 2852 void
Chris@577 2853 MainWindowBase::findTimeRulerLayer()
Chris@577 2854 {
Chris@577 2855 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@577 2856 Pane *pane = m_paneStack->getPane(i);
Chris@577 2857 if (!pane) continue;
Chris@577 2858 for (int j = 0; j < pane->getLayerCount(); ++j) {
Chris@577 2859 Layer *layer = pane->getLayer(j);
Chris@577 2860 if (!dynamic_cast<TimeRulerLayer *>(layer)) continue;
Chris@577 2861 m_timeRulerLayer = layer;
Chris@577 2862 return;
Chris@577 2863 }
Chris@577 2864 }
Chris@577 2865 if (m_timeRulerLayer) {
Chris@577 2866 SVCERR << "WARNING: Time ruler layer was not reset to 0 before session template loaded?" << endl;
Chris@577 2867 delete m_timeRulerLayer;
Chris@577 2868 m_timeRulerLayer = 0;
Chris@577 2869 }
Chris@577 2870 }
Chris@577 2871
Chris@577 2872 void
Chris@211 2873 MainWindowBase::toggleTimeRulers()
Chris@211 2874 {
Chris@211 2875 bool haveRulers = false;
Chris@211 2876 bool someHidden = false;
Chris@211 2877
Chris@211 2878 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@211 2879
Chris@211 2880 Pane *pane = m_paneStack->getPane(i);
Chris@211 2881 if (!pane) continue;
Chris@211 2882
Chris@211 2883 for (int j = 0; j < pane->getLayerCount(); ++j) {
Chris@211 2884
Chris@211 2885 Layer *layer = pane->getLayer(j);
Chris@211 2886 if (!dynamic_cast<TimeRulerLayer *>(layer)) continue;
Chris@211 2887
Chris@211 2888 haveRulers = true;
Chris@211 2889 if (layer->isLayerDormant(pane)) someHidden = true;
Chris@211 2890 }
Chris@211 2891 }
Chris@211 2892
Chris@211 2893 if (haveRulers) {
Chris@211 2894
Chris@211 2895 bool show = someHidden;
Chris@211 2896
Chris@211 2897 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@211 2898
Chris@211 2899 Pane *pane = m_paneStack->getPane(i);
Chris@211 2900 if (!pane) continue;
Chris@211 2901
Chris@211 2902 for (int j = 0; j < pane->getLayerCount(); ++j) {
Chris@211 2903
Chris@211 2904 Layer *layer = pane->getLayer(j);
Chris@211 2905 if (!dynamic_cast<TimeRulerLayer *>(layer)) continue;
Chris@211 2906
Chris@211 2907 layer->showLayer(pane, show);
Chris@211 2908 }
Chris@211 2909 }
Chris@211 2910 }
Chris@211 2911 }
Chris@211 2912
Chris@211 2913 void
Chris@45 2914 MainWindowBase::toggleZoomWheels()
Chris@45 2915 {
Chris@45 2916 if (m_viewManager->getZoomWheelsEnabled()) {
Chris@45 2917 m_viewManager->setZoomWheelsEnabled(false);
Chris@45 2918 } else {
Chris@45 2919 m_viewManager->setZoomWheelsEnabled(true);
Chris@45 2920 }
Chris@45 2921 }
Chris@45 2922
Chris@45 2923 void
Chris@45 2924 MainWindowBase::togglePropertyBoxes()
Chris@45 2925 {
Chris@45 2926 if (m_paneStack->getLayoutStyle() == PaneStack::NoPropertyStacks) {
Chris@45 2927 if (Preferences::getInstance()->getPropertyBoxLayout() ==
Chris@45 2928 Preferences::VerticallyStacked) {
Chris@45 2929 m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout);
Chris@45 2930 } else {
Chris@45 2931 m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout);
Chris@45 2932 }
Chris@45 2933 } else {
Chris@45 2934 m_paneStack->setLayoutStyle(PaneStack::NoPropertyStacks);
Chris@45 2935 }
Chris@45 2936 }
Chris@45 2937
Chris@378 2938 QLabel *
Chris@378 2939 MainWindowBase::getStatusLabel() const
Chris@378 2940 {
Chris@378 2941 if (!m_statusLabel) {
Chris@378 2942 m_statusLabel = new QLabel();
Chris@378 2943 statusBar()->addWidget(m_statusLabel, 1);
Chris@378 2944 }
Chris@379 2945
Chris@379 2946 QList<QFrame *> frames = statusBar()->findChildren<QFrame *>();
Chris@379 2947 foreach (QFrame *f, frames) {
Chris@379 2948 f->setFrameStyle(QFrame::NoFrame);
Chris@379 2949 }
Chris@379 2950
Chris@378 2951 return m_statusLabel;
Chris@378 2952 }
Chris@378 2953
Chris@45 2954 void
Chris@45 2955 MainWindowBase::toggleStatusBar()
Chris@45 2956 {
Chris@45 2957 QSettings settings;
Chris@45 2958 settings.beginGroup("MainWindow");
Chris@45 2959 bool sb = settings.value("showstatusbar", true).toBool();
Chris@45 2960
Chris@45 2961 if (sb) {
Chris@45 2962 statusBar()->hide();
Chris@45 2963 } else {
Chris@45 2964 statusBar()->show();
Chris@45 2965 }
Chris@45 2966
Chris@45 2967 settings.setValue("showstatusbar", !sb);
Chris@45 2968
Chris@45 2969 settings.endGroup();
Chris@45 2970 }
Chris@45 2971
Chris@45 2972 void
Chris@256 2973 MainWindowBase::toggleCentreLine()
Chris@256 2974 {
Chris@256 2975 if (m_viewManager->shouldShowCentreLine()) {
Chris@256 2976 m_viewManager->setShowCentreLine(false);
Chris@256 2977 } else {
Chris@256 2978 m_viewManager->setShowCentreLine(true);
Chris@256 2979 }
Chris@256 2980 }
Chris@256 2981
Chris@256 2982 void
Chris@45 2983 MainWindowBase::preferenceChanged(PropertyContainer::PropertyName name)
Chris@45 2984 {
Chris@45 2985 if (name == "Property Box Layout") {
Chris@45 2986 if (m_paneStack->getLayoutStyle() != PaneStack::NoPropertyStacks) {
Chris@45 2987 if (Preferences::getInstance()->getPropertyBoxLayout() ==
Chris@45 2988 Preferences::VerticallyStacked) {
Chris@45 2989 m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout);
Chris@45 2990 } else {
Chris@45 2991 m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout);
Chris@45 2992 }
Chris@45 2993 }
Chris@45 2994 } else if (name == "Background Mode" && m_viewManager) {
Chris@45 2995 Preferences::BackgroundMode mode =
Chris@45 2996 Preferences::getInstance()->getBackgroundMode();
Chris@45 2997 if (mode == Preferences::BackgroundFromTheme) {
Chris@45 2998 m_viewManager->setGlobalDarkBackground(m_initialDarkBackground);
Chris@45 2999 } else if (mode == Preferences::DarkBackground) {
Chris@45 3000 m_viewManager->setGlobalDarkBackground(true);
Chris@45 3001 } else {
Chris@45 3002 m_viewManager->setGlobalDarkBackground(false);
Chris@45 3003 }
Chris@45 3004 }
Chris@45 3005 }
Chris@45 3006
Chris@45 3007 void
Chris@45 3008 MainWindowBase::play()
Chris@45 3009 {
Chris@516 3010 if ((m_recordTarget && m_recordTarget->isRecording()) ||
Chris@516 3011 (m_playSource && m_playSource->isPlaying())) {
Chris@45 3012 stop();
Chris@479 3013 QAction *action = qobject_cast<QAction *>(sender());
Chris@479 3014 if (action) action->setChecked(false);
Chris@45 3015 } else {
Chris@487 3016 if (m_audioIO) m_audioIO->resume();
Chris@509 3017 else if (m_playTarget) m_playTarget->resume();
Chris@45 3018 playbackFrameChanged(m_viewManager->getPlaybackFrame());
Chris@595 3019 m_playSource->play(m_viewManager->getPlaybackFrame());
Chris@45 3020 }
Chris@45 3021 }
Chris@45 3022
Chris@45 3023 void
Chris@477 3024 MainWindowBase::record()
Chris@477 3025 {
Chris@586 3026 QAction *action = qobject_cast<QAction *>(sender());
Chris@586 3027
Chris@478 3028 if (!(m_soundOptions & WithAudioInput)) {
Chris@586 3029 if (action) action->setChecked(false);
Chris@478 3030 return;
Chris@478 3031 }
Chris@478 3032
Chris@477 3033 if (!m_recordTarget) {
Chris@586 3034 if (action) action->setChecked(false);
Chris@477 3035 return;
Chris@477 3036 }
Chris@477 3037
Chris@478 3038 if (!m_audioIO) {
Chris@570 3039 cerr << "MainWindowBase::record: about to create audio IO" << endl;
Chris@478 3040 createAudioIO();
Chris@478 3041 }
Chris@492 3042
Chris@492 3043 if (!m_audioIO) {
Chris@586 3044 if (!m_playTarget) {
Chris@586 3045 // Don't need to report this, createAudioIO should have
Chris@586 3046 if (action) action->setChecked(false);
Chris@586 3047 return;
Chris@586 3048 } else {
Chris@586 3049 // Need to report this: if the play target exists instead
Chris@586 3050 // of the audio IO, then that means we failed to open a
Chris@586 3051 // capture device. The record control should be disabled
Chris@586 3052 // in that situation, so if it happens here, that must
Chris@586 3053 // mean this is the first time we ever tried to open the
Chris@586 3054 // audio device, hence the need to report the problem here
Chris@586 3055 QMessageBox::critical
Chris@586 3056 (this, tr("No record device available"),
Chris@586 3057 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 3058 if (action) action->setChecked(false);
Chris@586 3059 updateMenuStates();
Chris@586 3060 return;
Chris@586 3061 }
Chris@492 3062 }
Chris@478 3063
Chris@477 3064 if (m_recordTarget->isRecording()) {
Chris@492 3065 stop();
Chris@477 3066 return;
Chris@477 3067 }
Chris@490 3068
Chris@483 3069 if (m_audioRecordMode == RecordReplaceSession) {
Chris@490 3070 if (!checkSaveModified()) {
Chris@490 3071 if (action) action->setChecked(false);
Chris@490 3072 return;
Chris@490 3073 }
Chris@483 3074 }
Chris@487 3075
Chris@557 3076 if (m_viewManager) m_viewManager->setGlobalCentreFrame(0);
Chris@557 3077
Chris@586 3078 SVDEBUG << "MainWindowBase::record: about to resume" << endl;
Chris@492 3079 m_audioIO->resume();
Chris@509 3080
Chris@477 3081 WritableWaveFileModel *model = m_recordTarget->startRecording();
Chris@477 3082 if (!model) {
Chris@586 3083 SVCERR << "ERROR: MainWindowBase::record: Recording failed" << endl;
Chris@586 3084 QMessageBox::critical
Chris@586 3085 (this, tr("Recording failed"),
Chris@586 3086 tr("<b>Recording failed</b><p>Failed to switch to record mode (some internal problem?)</p>"));
Chris@490 3087 if (action) action->setChecked(false);
Chris@477 3088 return;
Chris@477 3089 }
Chris@477 3090
Chris@477 3091 if (!model->isOK()) {
Chris@477 3092 m_recordTarget->stopRecording();
Chris@492 3093 m_audioIO->suspend();
Chris@586 3094 if (action) action->setChecked(false);
Chris@477 3095 delete model;
Chris@477 3096 return;
Chris@477 3097 }
Chris@487 3098
Chris@478 3099 PlayParameterRepository::getInstance()->addPlayable(model);
Chris@483 3100
Chris@483 3101 if (m_audioRecordMode == RecordReplaceSession || !getMainModel()) {
Chris@478 3102
Chris@479 3103 //!!! duplication with openAudio here
Chris@479 3104
Chris@479 3105 QString templateName = getDefaultSessionTemplate();
Chris@479 3106 bool loadedTemplate = false;
Chris@479 3107
Chris@479 3108 if (templateName != "") {
Chris@479 3109 FileOpenStatus tplStatus = openSessionTemplate(templateName);
Chris@479 3110 if (tplStatus == FileOpenCancelled) {
Chris@490 3111 m_recordTarget->stopRecording();
Chris@492 3112 m_audioIO->suspend();
Chris@490 3113 PlayParameterRepository::getInstance()->removePlayable(model);
Chris@479 3114 return;
Chris@479 3115 }
Chris@479 3116 if (tplStatus != FileOpenFailed) {
Chris@479 3117 loadedTemplate = true;
Chris@479 3118 }
Chris@479 3119 }
Chris@479 3120
Chris@479 3121 if (!loadedTemplate) {
Chris@479 3122 closeSession();
Chris@479 3123 createDocument();
Chris@479 3124 }
Chris@479 3125
Chris@479 3126 Model *prevMain = getMainModel();
Chris@479 3127 if (prevMain) {
Chris@479 3128 m_playSource->removeModel(prevMain);
Chris@479 3129 PlayParameterRepository::getInstance()->removePlayable(prevMain);
Chris@479 3130 }
Chris@479 3131
Chris@478 3132 m_document->setMainModel(model);
Chris@478 3133 setupMenus();
Chris@577 3134 findTimeRulerLayer();
Chris@478 3135
Chris@595 3136 if (loadedTemplate || (m_sessionFile == "")) {
Chris@479 3137 //!!! shouldn't be dealing directly with title from here -- call a method
Chris@595 3138 setWindowTitle(tr("%1: %2")
Chris@479 3139 .arg(QApplication::applicationName())
Chris@479 3140 .arg(model->getLocation()));
Chris@595 3141 CommandHistory::getInstance()->clear();
Chris@595 3142 CommandHistory::getInstance()->documentSaved();
Chris@595 3143 m_documentModified = false;
Chris@595 3144 } else {
Chris@595 3145 setWindowTitle(tr("%1: %2 [%3]")
Chris@479 3146 .arg(QApplication::applicationName())
Chris@595 3147 .arg(QFileInfo(m_sessionFile).fileName())
Chris@595 3148 .arg(model->getLocation()));
Chris@595 3149 if (m_documentModified) {
Chris@595 3150 m_documentModified = false;
Chris@595 3151 documentModified(); // so as to restore "(modified)" window title
Chris@595 3152 }
Chris@595 3153 }
Chris@479 3154
Chris@478 3155 } else {
Chris@478 3156
Chris@478 3157 CommandHistory::getInstance()->startCompoundOperation
Chris@478 3158 (tr("Import Recorded Audio"), true);
Chris@478 3159
Chris@478 3160 m_document->addImportedModel(model);
Chris@478 3161
Chris@478 3162 AddPaneCommand *command = new AddPaneCommand(this);
Chris@478 3163 CommandHistory::getInstance()->addCommand(command);
Chris@478 3164
Chris@478 3165 Pane *pane = command->getPane();
Chris@478 3166
Chris@478 3167 if (m_timeRulerLayer) {
Chris@478 3168 m_document->addLayerToView(pane, m_timeRulerLayer);
Chris@478 3169 }
Chris@478 3170
Chris@478 3171 Layer *newLayer = m_document->createImportedLayer(model);
Chris@478 3172
Chris@478 3173 if (newLayer) {
Chris@478 3174 m_document->addLayerToView(pane, newLayer);
Chris@478 3175 }
Chris@595 3176
Chris@478 3177 CommandHistory::getInstance()->endCompoundOperation();
Chris@477 3178 }
Chris@479 3179
Chris@479 3180 updateMenuStates();
Chris@479 3181 m_recentFiles.addFile(model->getLocation());
Chris@479 3182 currentPaneChanged(m_paneStack->getCurrentPane());
Chris@496 3183
Chris@496 3184 emit audioFileLoaded();
Chris@477 3185 }
Chris@477 3186
Chris@477 3187 void
Chris@45 3188 MainWindowBase::ffwd()
Chris@45 3189 {
Chris@45 3190 if (!getMainModel()) return;
Chris@45 3191
Chris@435 3192 sv_frame_t frame = m_viewManager->getPlaybackFrame();
Chris@45 3193 ++frame;
Chris@45 3194
Chris@85 3195 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 3196 Layer *layer = getSnapLayer();
Chris@435 3197 sv_samplerate_t sr = getMainModel()->getSampleRate();
Chris@45 3198
Chris@45 3199 if (!layer) {
Chris@45 3200
Chris@45 3201 frame = RealTime::realTime2Frame
Chris@357 3202 (RealTime::frame2RealTime(frame, sr) + m_defaultFfwdRwdStep, sr);
Chris@435 3203 if (frame > getMainModel()->getEndFrame()) {
Chris@45 3204 frame = getMainModel()->getEndFrame();
Chris@45 3205 }
Chris@45 3206
Chris@45 3207 } else {
Chris@45 3208
Chris@366 3209 int resolution = 0;
Chris@166 3210 if (pane) frame = pane->alignFromReference(frame);
Chris@85 3211 if (layer->snapToFeatureFrame(m_paneStack->getCurrentPane(),
Chris@85 3212 frame, resolution, Layer::SnapRight)) {
Chris@85 3213 if (pane) frame = pane->alignToReference(frame);
Chris@85 3214 } else {
Chris@45 3215 frame = getMainModel()->getEndFrame();
Chris@45 3216 }
Chris@45 3217 }
Chris@45 3218
Chris@45 3219 if (frame < 0) frame = 0;
Chris@45 3220
Chris@45 3221 if (m_viewManager->getPlaySelectionMode()) {
Chris@435 3222 frame = m_viewManager->constrainFrameToSelection(frame);
Chris@45 3223 }
Chris@45 3224
Chris@45 3225 m_viewManager->setPlaybackFrame(frame);
Chris@166 3226
Chris@435 3227 if (frame == getMainModel()->getEndFrame() &&
Chris@166 3228 m_playSource &&
Chris@166 3229 m_playSource->isPlaying() &&
Chris@166 3230 !m_viewManager->getPlayLoopMode()) {
Chris@166 3231 stop();
Chris@166 3232 }
Chris@45 3233 }
Chris@45 3234
Chris@45 3235 void
Chris@45 3236 MainWindowBase::ffwdEnd()
Chris@45 3237 {
Chris@45 3238 if (!getMainModel()) return;
Chris@45 3239
Chris@139 3240 if (m_playSource &&
Chris@139 3241 m_playSource->isPlaying() &&
Chris@139 3242 !m_viewManager->getPlayLoopMode()) {
Chris@139 3243 stop();
Chris@139 3244 }
Chris@139 3245
Chris@435 3246 sv_frame_t frame = getMainModel()->getEndFrame();
Chris@45 3247
Chris@45 3248 if (m_viewManager->getPlaySelectionMode()) {
Chris@45 3249 frame = m_viewManager->constrainFrameToSelection(frame);
Chris@45 3250 }
Chris@45 3251
Chris@45 3252 m_viewManager->setPlaybackFrame(frame);
Chris@45 3253 }
Chris@45 3254
Chris@45 3255 void
Chris@166 3256 MainWindowBase::ffwdSimilar()
Chris@166 3257 {
Chris@166 3258 if (!getMainModel()) return;
Chris@166 3259
Chris@166 3260 Layer *layer = getSnapLayer();
Chris@166 3261 if (!layer) { ffwd(); return; }
Chris@166 3262
Chris@166 3263 Pane *pane = m_paneStack->getCurrentPane();
Chris@435 3264 sv_frame_t frame = m_viewManager->getPlaybackFrame();
Chris@166 3265
Chris@366 3266 int resolution = 0;
Chris@166 3267 if (pane) frame = pane->alignFromReference(frame);
Chris@166 3268 if (layer->snapToSimilarFeature(m_paneStack->getCurrentPane(),
Chris@166 3269 frame, resolution, Layer::SnapRight)) {
Chris@166 3270 if (pane) frame = pane->alignToReference(frame);
Chris@166 3271 } else {
Chris@166 3272 frame = getMainModel()->getEndFrame();
Chris@166 3273 }
Chris@166 3274
Chris@166 3275 if (frame < 0) frame = 0;
Chris@166 3276
Chris@166 3277 if (m_viewManager->getPlaySelectionMode()) {
Chris@435 3278 frame = m_viewManager->constrainFrameToSelection(frame);
Chris@166 3279 }
Chris@166 3280
Chris@166 3281 m_viewManager->setPlaybackFrame(frame);
Chris@166 3282
Chris@435 3283 if (frame == getMainModel()->getEndFrame() &&
Chris@166 3284 m_playSource &&
Chris@166 3285 m_playSource->isPlaying() &&
Chris@166 3286 !m_viewManager->getPlayLoopMode()) {
Chris@166 3287 stop();
Chris@166 3288 }
Chris@166 3289 }
Chris@166 3290
Chris@166 3291 void
Chris@45 3292 MainWindowBase::rewind()
Chris@45 3293 {
Chris@45 3294 if (!getMainModel()) return;
Chris@45 3295
Chris@435 3296 sv_frame_t frame = m_viewManager->getPlaybackFrame();
Chris@45 3297 if (frame > 0) --frame;
Chris@45 3298
Chris@85 3299 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 3300 Layer *layer = getSnapLayer();
Chris@435 3301 sv_samplerate_t sr = getMainModel()->getSampleRate();
Chris@45 3302
Chris@45 3303 // when rewinding during playback, we want to allow a period
Chris@45 3304 // following a rewind target point at which the rewind will go to
Chris@45 3305 // the prior point instead of the immediately neighbouring one
Chris@45 3306 if (m_playSource && m_playSource->isPlaying()) {
Chris@45 3307 RealTime ct = RealTime::frame2RealTime(frame, sr);
Chris@357 3308 ct = ct - RealTime::fromSeconds(0.15);
Chris@45 3309 if (ct < RealTime::zeroTime) ct = RealTime::zeroTime;
Chris@45 3310 frame = RealTime::realTime2Frame(ct, sr);
Chris@45 3311 }
Chris@45 3312
Chris@45 3313 if (!layer) {
Chris@45 3314
Chris@45 3315 frame = RealTime::realTime2Frame
Chris@357 3316 (RealTime::frame2RealTime(frame, sr) - m_defaultFfwdRwdStep, sr);
Chris@435 3317 if (frame < getMainModel()->getStartFrame()) {
Chris@45 3318 frame = getMainModel()->getStartFrame();
Chris@45 3319 }
Chris@45 3320
Chris@45 3321 } else {
Chris@45 3322
Chris@366 3323 int resolution = 0;
Chris@166 3324 if (pane) frame = pane->alignFromReference(frame);
Chris@85 3325 if (layer->snapToFeatureFrame(m_paneStack->getCurrentPane(),
Chris@85 3326 frame, resolution, Layer::SnapLeft)) {
Chris@85 3327 if (pane) frame = pane->alignToReference(frame);
Chris@85 3328 } else {
Chris@45 3329 frame = getMainModel()->getStartFrame();
Chris@45 3330 }
Chris@45 3331 }
Chris@45 3332
Chris@45 3333 if (frame < 0) frame = 0;
Chris@45 3334
Chris@45 3335 if (m_viewManager->getPlaySelectionMode()) {
Chris@435 3336 frame = m_viewManager->constrainFrameToSelection(frame);
Chris@45 3337 }
Chris@45 3338
Chris@45 3339 m_viewManager->setPlaybackFrame(frame);
Chris@45 3340 }
Chris@45 3341
Chris@45 3342 void
Chris@45 3343 MainWindowBase::rewindStart()
Chris@45 3344 {
Chris@45 3345 if (!getMainModel()) return;
Chris@45 3346
Chris@435 3347 sv_frame_t frame = getMainModel()->getStartFrame();
Chris@45 3348
Chris@45 3349 if (m_viewManager->getPlaySelectionMode()) {
Chris@45 3350 frame = m_viewManager->constrainFrameToSelection(frame);
Chris@45 3351 }
Chris@45 3352
Chris@45 3353 m_viewManager->setPlaybackFrame(frame);
Chris@45 3354 }
Chris@45 3355
Chris@166 3356 void
Chris@166 3357 MainWindowBase::rewindSimilar()
Chris@166 3358 {
Chris@166 3359 if (!getMainModel()) return;
Chris@166 3360
Chris@166 3361 Layer *layer = getSnapLayer();
Chris@166 3362 if (!layer) { rewind(); return; }
Chris@166 3363
Chris@166 3364 Pane *pane = m_paneStack->getCurrentPane();
Chris@435 3365 sv_frame_t frame = m_viewManager->getPlaybackFrame();
Chris@166 3366
Chris@366 3367 int resolution = 0;
Chris@166 3368 if (pane) frame = pane->alignFromReference(frame);
Chris@166 3369 if (layer->snapToSimilarFeature(m_paneStack->getCurrentPane(),
Chris@166 3370 frame, resolution, Layer::SnapLeft)) {
Chris@166 3371 if (pane) frame = pane->alignToReference(frame);
Chris@166 3372 } else {
Chris@166 3373 frame = getMainModel()->getStartFrame();
Chris@166 3374 }
Chris@166 3375
Chris@166 3376 if (frame < 0) frame = 0;
Chris@166 3377
Chris@166 3378 if (m_viewManager->getPlaySelectionMode()) {
Chris@435 3379 frame = m_viewManager->constrainFrameToSelection(frame);
Chris@166 3380 }
Chris@166 3381
Chris@166 3382 m_viewManager->setPlaybackFrame(frame);
Chris@166 3383 }
Chris@166 3384
Chris@45 3385 Layer *
Chris@45 3386 MainWindowBase::getSnapLayer() const
Chris@45 3387 {
Chris@45 3388 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 3389 if (!pane) return 0;
Chris@45 3390
Chris@45 3391 Layer *layer = pane->getSelectedLayer();
Chris@45 3392
Chris@45 3393 if (!dynamic_cast<TimeInstantLayer *>(layer) &&
Chris@45 3394 !dynamic_cast<TimeValueLayer *>(layer) &&
Chris@194 3395 !dynamic_cast<RegionLayer *>(layer) &&
Chris@45 3396 !dynamic_cast<TimeRulerLayer *>(layer)) {
Chris@45 3397
Chris@45 3398 layer = 0;
Chris@45 3399
Chris@45 3400 for (int i = pane->getLayerCount(); i > 0; --i) {
Chris@45 3401 Layer *l = pane->getLayer(i-1);
Chris@45 3402 if (dynamic_cast<TimeRulerLayer *>(l)) {
Chris@45 3403 layer = l;
Chris@45 3404 break;
Chris@45 3405 }
Chris@45 3406 }
Chris@45 3407 }
Chris@45 3408
Chris@45 3409 return layer;
Chris@45 3410 }
Chris@45 3411
Chris@45 3412 void
Chris@45 3413 MainWindowBase::stop()
Chris@45 3414 {
Chris@516 3415 if (m_recordTarget &&
Chris@516 3416 m_recordTarget->isRecording()) {
Chris@477 3417 m_recordTarget->stopRecording();
Chris@477 3418 }
Chris@516 3419
Chris@516 3420 if (!m_playSource) return;
Chris@516 3421
Chris@45 3422 m_playSource->stop();
Chris@45 3423
Chris@487 3424 if (m_audioIO) m_audioIO->suspend();
Chris@509 3425 else if (m_playTarget) m_playTarget->suspend();
Chris@487 3426
Chris@45 3427 if (m_paneStack && m_paneStack->getCurrentPane()) {
Chris@45 3428 updateVisibleRangeDisplay(m_paneStack->getCurrentPane());
Chris@45 3429 } else {
Chris@45 3430 m_myStatusMessage = "";
Chris@378 3431 getStatusLabel()->setText("");
Chris@45 3432 }
Chris@45 3433 }
Chris@45 3434
Chris@45 3435 MainWindowBase::AddPaneCommand::AddPaneCommand(MainWindowBase *mw) :
Chris@45 3436 m_mw(mw),
Chris@45 3437 m_pane(0),
Chris@45 3438 m_prevCurrentPane(0),
Chris@45 3439 m_added(false)
Chris@45 3440 {
Chris@45 3441 }
Chris@45 3442
Chris@45 3443 MainWindowBase::AddPaneCommand::~AddPaneCommand()
Chris@45 3444 {
Chris@45 3445 if (m_pane && !m_added) {
Chris@595 3446 m_mw->m_paneStack->deletePane(m_pane);
Chris@45 3447 }
Chris@45 3448 }
Chris@45 3449
Chris@45 3450 QString
Chris@45 3451 MainWindowBase::AddPaneCommand::getName() const
Chris@45 3452 {
Chris@45 3453 return tr("Add Pane");
Chris@45 3454 }
Chris@45 3455
Chris@45 3456 void
Chris@45 3457 MainWindowBase::AddPaneCommand::execute()
Chris@45 3458 {
Chris@45 3459 if (!m_pane) {
Chris@595 3460 m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane();
Chris@595 3461 m_pane = m_mw->m_paneStack->addPane();
Chris@45 3462
Chris@45 3463 connect(m_pane, SIGNAL(contextHelpChanged(const QString &)),
Chris@45 3464 m_mw, SLOT(contextHelpChanged(const QString &)));
Chris@45 3465 } else {
Chris@595 3466 m_mw->m_paneStack->showPane(m_pane);
Chris@45 3467 }
Chris@45 3468
Chris@45 3469 m_mw->m_paneStack->setCurrentPane(m_pane);
Chris@45 3470 m_added = true;
Chris@45 3471 }
Chris@45 3472
Chris@45 3473 void
Chris@45 3474 MainWindowBase::AddPaneCommand::unexecute()
Chris@45 3475 {
Chris@45 3476 m_mw->m_paneStack->hidePane(m_pane);
Chris@45 3477 m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane);
Chris@45 3478 m_added = false;
Chris@45 3479 }
Chris@45 3480
Chris@45 3481 MainWindowBase::RemovePaneCommand::RemovePaneCommand(MainWindowBase *mw, Pane *pane) :
Chris@45 3482 m_mw(mw),
Chris@45 3483 m_pane(pane),
Chris@409 3484 m_prevCurrentPane(0),
Chris@45 3485 m_added(true)
Chris@45 3486 {
Chris@45 3487 }
Chris@45 3488
Chris@45 3489 MainWindowBase::RemovePaneCommand::~RemovePaneCommand()
Chris@45 3490 {
Chris@45 3491 if (m_pane && !m_added) {
Chris@595 3492 m_mw->m_paneStack->deletePane(m_pane);
Chris@45 3493 }
Chris@45 3494 }
Chris@45 3495
Chris@45 3496 QString
Chris@45 3497 MainWindowBase::RemovePaneCommand::getName() const
Chris@45 3498 {
Chris@45 3499 return tr("Remove Pane");
Chris@45 3500 }
Chris@45 3501
Chris@45 3502 void
Chris@45 3503 MainWindowBase::RemovePaneCommand::execute()
Chris@45 3504 {
Chris@45 3505 m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane();
Chris@45 3506 m_mw->m_paneStack->hidePane(m_pane);
Chris@45 3507 m_added = false;
Chris@45 3508 }
Chris@45 3509
Chris@45 3510 void
Chris@45 3511 MainWindowBase::RemovePaneCommand::unexecute()
Chris@45 3512 {
Chris@45 3513 m_mw->m_paneStack->showPane(m_pane);
Chris@45 3514 m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane);
Chris@45 3515 m_added = true;
Chris@45 3516 }
Chris@45 3517
Chris@45 3518 void
Chris@45 3519 MainWindowBase::deleteCurrentPane()
Chris@45 3520 {
Chris@45 3521 CommandHistory::getInstance()->startCompoundOperation
Chris@595 3522 (tr("Delete Pane"), true);
Chris@45 3523
Chris@45 3524 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 3525 if (pane) {
Chris@595 3526 while (pane->getLayerCount() > 0) {
Chris@595 3527 Layer *layer = pane->getLayer(0);
Chris@595 3528 if (layer) {
Chris@595 3529 m_document->removeLayerFromView(pane, layer);
Chris@595 3530 } else {
Chris@595 3531 break;
Chris@595 3532 }
Chris@595 3533 }
Chris@595 3534
Chris@595 3535 RemovePaneCommand *command = new RemovePaneCommand(this, pane);
Chris@595 3536 CommandHistory::getInstance()->addCommand(command);
Chris@45 3537 }
Chris@45 3538
Chris@45 3539 CommandHistory::getInstance()->endCompoundOperation();
Chris@45 3540
Chris@45 3541 updateMenuStates();
Chris@45 3542 }
Chris@45 3543
Chris@45 3544 void
Chris@45 3545 MainWindowBase::deleteCurrentLayer()
Chris@45 3546 {
Chris@45 3547 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 3548 if (pane) {
Chris@595 3549 Layer *layer = pane->getSelectedLayer();
Chris@595 3550 if (layer) {
Chris@595 3551 m_document->removeLayerFromView(pane, layer);
Chris@595 3552 }
Chris@45 3553 }
Chris@45 3554 updateMenuStates();
Chris@45 3555 }
Chris@45 3556
Chris@45 3557 void
Chris@123 3558 MainWindowBase::editCurrentLayer()
Chris@123 3559 {
Chris@123 3560 Layer *layer = 0;
Chris@123 3561 Pane *pane = m_paneStack->getCurrentPane();
Chris@123 3562 if (pane) layer = pane->getSelectedLayer();
Chris@123 3563 if (!layer) return;
Chris@123 3564
Chris@123 3565 Model *model = layer->getModel();
Chris@123 3566 if (!model) return;
Chris@123 3567
Chris@124 3568 TabularModel *tabular = dynamic_cast<TabularModel *>(model);
Chris@124 3569 if (!tabular) {
Chris@124 3570 //!!! how to prevent this function from being active if not
Chris@124 3571 //appropriate model type? or will we ultimately support
Chris@124 3572 //tabular display for all editable models?
Chris@233 3573 SVDEBUG << "NOTE: Not a tabular model" << endl;
Chris@124 3574 return;
Chris@124 3575 }
Chris@124 3576
Chris@123 3577 if (m_layerDataDialogMap.find(layer) != m_layerDataDialogMap.end()) {
Chris@126 3578 if (!m_layerDataDialogMap[layer].isNull()) {
Chris@126 3579 m_layerDataDialogMap[layer]->show();
Chris@126 3580 m_layerDataDialogMap[layer]->raise();
Chris@126 3581 return;
Chris@126 3582 }
Chris@123 3583 }
Chris@123 3584
Chris@125 3585 QString title = layer->getLayerPresentationName();
Chris@125 3586
Chris@125 3587 ModelDataTableDialog *dialog = new ModelDataTableDialog(tabular, title, this);
Chris@128 3588 dialog->setAttribute(Qt::WA_DeleteOnClose);
Chris@128 3589
Chris@128 3590 connectLayerEditDialog(dialog);
Chris@123 3591
Chris@128 3592 m_layerDataDialogMap[layer] = dialog;
Chris@128 3593 m_viewDataDialogMap[pane].insert(dialog);
Chris@128 3594
Chris@128 3595 dialog->show();
Chris@128 3596 }
Chris@128 3597
Chris@128 3598 void
Chris@128 3599 MainWindowBase::connectLayerEditDialog(ModelDataTableDialog *dialog)
Chris@128 3600 {
Chris@123 3601 connect(m_viewManager,
Chris@435 3602 SIGNAL(globalCentreFrameChanged(sv_frame_t)),
Chris@123 3603 dialog,
Chris@435 3604 SLOT(userScrolledToFrame(sv_frame_t)));
Chris@127 3605
Chris@127 3606 connect(m_viewManager,
Chris@435 3607 SIGNAL(playbackFrameChanged(sv_frame_t)),
Chris@127 3608 dialog,
Chris@435 3609 SLOT(playbackScrolledToFrame(sv_frame_t)));
Chris@127 3610
Chris@123 3611 connect(dialog,
Chris@435 3612 SIGNAL(scrollToFrame(sv_frame_t)),
Chris@123 3613 m_viewManager,
Chris@435 3614 SLOT(setGlobalCentreFrame(sv_frame_t)));
Chris@129 3615
Chris@129 3616 connect(dialog,
Chris@435 3617 SIGNAL(scrollToFrame(sv_frame_t)),
Chris@129 3618 m_viewManager,
Chris@435 3619 SLOT(setPlaybackFrame(sv_frame_t)));
Chris@128 3620 }
Chris@123 3621
Chris@123 3622 void
Chris@73 3623 MainWindowBase::previousPane()
Chris@73 3624 {
Chris@73 3625 if (!m_paneStack) return;
Chris@73 3626
Chris@73 3627 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@73 3628 if (!currentPane) return;
Chris@73 3629
Chris@73 3630 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@73 3631 if (m_paneStack->getPane(i) == currentPane) {
Chris@73 3632 if (i == 0) return;
Chris@73 3633 m_paneStack->setCurrentPane(m_paneStack->getPane(i-1));
Chris@73 3634 updateMenuStates();
Chris@73 3635 return;
Chris@73 3636 }
Chris@73 3637 }
Chris@73 3638 }
Chris@73 3639
Chris@73 3640 void
Chris@73 3641 MainWindowBase::nextPane()
Chris@73 3642 {
Chris@73 3643 if (!m_paneStack) return;
Chris@73 3644
Chris@73 3645 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@73 3646 if (!currentPane) return;
Chris@73 3647
Chris@73 3648 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@73 3649 if (m_paneStack->getPane(i) == currentPane) {
Chris@73 3650 if (i == m_paneStack->getPaneCount()-1) return;
Chris@73 3651 m_paneStack->setCurrentPane(m_paneStack->getPane(i+1));
Chris@73 3652 updateMenuStates();
Chris@73 3653 return;
Chris@73 3654 }
Chris@73 3655 }
Chris@73 3656 }
Chris@73 3657
Chris@73 3658 void
Chris@73 3659 MainWindowBase::previousLayer()
Chris@73 3660 {
Chris@73 3661 if (!m_paneStack) return;
Chris@73 3662
Chris@73 3663 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@73 3664 if (!currentPane) return;
Chris@73 3665
Chris@403 3666 int count = currentPane->getLayerCount();
Chris@403 3667 if (count == 0) return;
Chris@403 3668
Chris@73 3669 Layer *currentLayer = currentPane->getSelectedLayer();
Chris@403 3670
Chris@403 3671 if (!currentLayer) {
Chris@403 3672 // The pane itself is current
Chris@403 3673 m_paneStack->setCurrentLayer
Chris@403 3674 (currentPane, currentPane->getFixedOrderLayer(count-1));
Chris@403 3675 } else {
Chris@403 3676 for (int i = 0; i < count; ++i) {
Chris@403 3677 if (currentPane->getFixedOrderLayer(i) == currentLayer) {
Chris@403 3678 if (i == 0) {
Chris@403 3679 m_paneStack->setCurrentLayer
Chris@403 3680 (currentPane, 0); // pane
Chris@403 3681 } else {
Chris@403 3682 m_paneStack->setCurrentLayer
Chris@403 3683 (currentPane, currentPane->getFixedOrderLayer(i-1));
Chris@403 3684 }
Chris@403 3685 break;
Chris@403 3686 }
Chris@73 3687 }
Chris@73 3688 }
Chris@403 3689
Chris@403 3690 updateMenuStates();
Chris@73 3691 }
Chris@73 3692
Chris@73 3693 void
Chris@73 3694 MainWindowBase::nextLayer()
Chris@73 3695 {
Chris@73 3696 if (!m_paneStack) return;
Chris@73 3697
Chris@73 3698 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@73 3699 if (!currentPane) return;
Chris@73 3700
Chris@403 3701 int count = currentPane->getLayerCount();
Chris@403 3702 if (count == 0) return;
Chris@403 3703
Chris@73 3704 Layer *currentLayer = currentPane->getSelectedLayer();
Chris@403 3705
Chris@403 3706 if (!currentLayer) {
Chris@403 3707 // The pane itself is current
Chris@403 3708 m_paneStack->setCurrentLayer
Chris@403 3709 (currentPane, currentPane->getFixedOrderLayer(0));
Chris@403 3710 } else {
Chris@403 3711 for (int i = 0; i < count; ++i) {
Chris@403 3712 if (currentPane->getFixedOrderLayer(i) == currentLayer) {
Chris@403 3713 if (i == currentPane->getLayerCount()-1) {
Chris@403 3714 m_paneStack->setCurrentLayer
Chris@403 3715 (currentPane, 0); // pane
Chris@403 3716 } else {
Chris@403 3717 m_paneStack->setCurrentLayer
Chris@403 3718 (currentPane, currentPane->getFixedOrderLayer(i+1));
Chris@403 3719 }
Chris@403 3720 break;
Chris@403 3721 }
Chris@73 3722 }
Chris@73 3723 }
Chris@403 3724
Chris@403 3725 updateMenuStates();
Chris@73 3726 }
Chris@73 3727
Chris@73 3728 void
Chris@435 3729 MainWindowBase::playbackFrameChanged(sv_frame_t frame)
Chris@45 3730 {
Chris@45 3731 if (!(m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
Chris@45 3732
Chris@187 3733 updatePositionStatusDisplays();
Chris@187 3734
Chris@45 3735 RealTime now = RealTime::frame2RealTime
Chris@45 3736 (frame, getMainModel()->getSampleRate());
Chris@45 3737
Chris@45 3738 if (now.sec == m_lastPlayStatusSec) return;
Chris@45 3739
Chris@45 3740 RealTime then = RealTime::frame2RealTime
Chris@45 3741 (m_playSource->getPlayEndFrame(), getMainModel()->getSampleRate());
Chris@45 3742
Chris@45 3743 QString nowStr;
Chris@45 3744 QString thenStr;
Chris@45 3745 QString remainingStr;
Chris@45 3746
Chris@45 3747 if (then.sec > 10) {
Chris@45 3748 nowStr = now.toSecText().c_str();
Chris@45 3749 thenStr = then.toSecText().c_str();
Chris@45 3750 remainingStr = (then - now).toSecText().c_str();
Chris@45 3751 m_lastPlayStatusSec = now.sec;
Chris@45 3752 } else {
Chris@45 3753 nowStr = now.toText(true).c_str();
Chris@45 3754 thenStr = then.toText(true).c_str();
Chris@45 3755 remainingStr = (then - now).toText(true).c_str();
Chris@45 3756 }
Chris@45 3757
Chris@45 3758 m_myStatusMessage = tr("Playing: %1 of %2 (%3 remaining)")
Chris@45 3759 .arg(nowStr).arg(thenStr).arg(remainingStr);
Chris@45 3760
Chris@378 3761 getStatusLabel()->setText(m_myStatusMessage);
Chris@45 3762 }
Chris@45 3763
Chris@45 3764 void
Chris@486 3765 MainWindowBase::recordDurationChanged(sv_frame_t frame, sv_samplerate_t rate)
Chris@486 3766 {
Chris@486 3767 RealTime duration = RealTime::frame2RealTime(frame, rate);
Chris@486 3768 QString durStr = duration.toSecText().c_str();
Chris@486 3769
Chris@486 3770 m_myStatusMessage = tr("Recording: %1").arg(durStr);
Chris@486 3771
Chris@486 3772 getStatusLabel()->setText(m_myStatusMessage);
Chris@486 3773 }
Chris@486 3774
Chris@486 3775 void
Chris@435 3776 MainWindowBase::globalCentreFrameChanged(sv_frame_t )
Chris@45 3777 {
Chris@45 3778 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
Chris@45 3779 Pane *p = 0;
Chris@45 3780 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
Chris@45 3781 if (!p->getFollowGlobalPan()) return;
Chris@45 3782 updateVisibleRangeDisplay(p);
Chris@45 3783 }
Chris@45 3784
Chris@45 3785 void
Chris@435 3786 MainWindowBase::viewCentreFrameChanged(View *v, sv_frame_t frame)
Chris@45 3787 {
Chris@233 3788 // SVDEBUG << "MainWindowBase::viewCentreFrameChanged(" << v << "," << frame << ")" << endl;
Chris@123 3789
Chris@123 3790 if (m_viewDataDialogMap.find(v) != m_viewDataDialogMap.end()) {
Chris@123 3791 for (DataDialogSet::iterator i = m_viewDataDialogMap[v].begin();
Chris@123 3792 i != m_viewDataDialogMap[v].end(); ++i) {
Chris@127 3793 (*i)->userScrolledToFrame(frame);
Chris@123 3794 }
Chris@123 3795 }
Chris@45 3796 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
Chris@45 3797 Pane *p = 0;
Chris@45 3798 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
Chris@45 3799 if (v == p) updateVisibleRangeDisplay(p);
Chris@45 3800 }
Chris@45 3801
Chris@45 3802 void
Chris@366 3803 MainWindowBase::viewZoomLevelChanged(View *v, int , bool )
Chris@45 3804 {
Chris@45 3805 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
Chris@45 3806 Pane *p = 0;
Chris@45 3807 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
Chris@45 3808 if (v == p) updateVisibleRangeDisplay(p);
Chris@45 3809 }
Chris@45 3810
Chris@45 3811 void
Chris@45 3812 MainWindowBase::layerAdded(Layer *)
Chris@45 3813 {
Chris@233 3814 // SVDEBUG << "MainWindowBase::layerAdded(" << layer << ")" << endl;
Chris@45 3815 updateMenuStates();
Chris@45 3816 }
Chris@45 3817
Chris@45 3818 void
Chris@45 3819 MainWindowBase::layerRemoved(Layer *)
Chris@45 3820 {
Chris@233 3821 // SVDEBUG << "MainWindowBase::layerRemoved(" << layer << ")" << endl;
Chris@45 3822 updateMenuStates();
Chris@45 3823 }
Chris@45 3824
Chris@45 3825 void
Chris@45 3826 MainWindowBase::layerAboutToBeDeleted(Layer *layer)
Chris@45 3827 {
Chris@233 3828 // SVDEBUG << "MainWindowBase::layerAboutToBeDeleted(" << layer << ")" << endl;
Chris@123 3829
Chris@128 3830 removeLayerEditDialog(layer);
Chris@123 3831
Chris@47 3832 if (m_timeRulerLayer && (layer == m_timeRulerLayer)) {
Chris@595 3833 // cerr << "(this is the time ruler layer)" << endl;
Chris@595 3834 m_timeRulerLayer = 0;
Chris@45 3835 }
Chris@45 3836 }
Chris@45 3837
Chris@45 3838 void
Chris@45 3839 MainWindowBase::layerInAView(Layer *layer, bool inAView)
Chris@45 3840 {
Chris@233 3841 // SVDEBUG << "MainWindowBase::layerInAView(" << layer << "," << inAView << ")" << endl;
Chris@128 3842
Chris@128 3843 if (!inAView) removeLayerEditDialog(layer);
Chris@45 3844
Chris@45 3845 // Check whether we need to add or remove model from play source
Chris@45 3846 Model *model = layer->getModel();
Chris@45 3847 if (model) {
Chris@45 3848 if (inAView) {
Chris@45 3849 m_playSource->addModel(model);
Chris@45 3850 } else {
Chris@45 3851 bool found = false;
Chris@45 3852 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@45 3853 Pane *pane = m_paneStack->getPane(i);
Chris@45 3854 if (!pane) continue;
Chris@45 3855 for (int j = 0; j < pane->getLayerCount(); ++j) {
Chris@45 3856 Layer *pl = pane->getLayer(j);
Chris@183 3857 if (pl &&
Chris@183 3858 !dynamic_cast<TimeRulerLayer *>(pl) &&
Chris@183 3859 (pl->getModel() == model)) {
Chris@45 3860 found = true;
Chris@45 3861 break;
Chris@45 3862 }
Chris@45 3863 }
Chris@45 3864 if (found) break;
Chris@45 3865 }
Chris@173 3866 if (!found) {
Chris@173 3867 m_playSource->removeModel(model);
Chris@173 3868 }
Chris@45 3869 }
Chris@45 3870 }
Chris@45 3871
Chris@45 3872 updateMenuStates();
Chris@45 3873 }
Chris@45 3874
Chris@45 3875 void
Chris@128 3876 MainWindowBase::removeLayerEditDialog(Layer *layer)
Chris@128 3877 {
Chris@128 3878 if (m_layerDataDialogMap.find(layer) != m_layerDataDialogMap.end()) {
Chris@128 3879
Chris@128 3880 ModelDataTableDialog *dialog = m_layerDataDialogMap[layer];
Chris@128 3881
Chris@128 3882 for (ViewDataDialogMap::iterator vi = m_viewDataDialogMap.begin();
Chris@128 3883 vi != m_viewDataDialogMap.end(); ++vi) {
Chris@128 3884 vi->second.erase(dialog);
Chris@128 3885 }
Chris@128 3886
Chris@128 3887 m_layerDataDialogMap.erase(layer);
Chris@128 3888 delete dialog;
Chris@128 3889 }
Chris@128 3890 }
Chris@128 3891
Chris@128 3892 void
Chris@45 3893 MainWindowBase::modelAdded(Model *model)
Chris@45 3894 {
Chris@233 3895 // SVDEBUG << "MainWindowBase::modelAdded(" << model << ")" << endl;
Chris@595 3896 std::cerr << "\nAdding model " << model->getTypeName() << " to playsource " << std::endl;
Chris@45 3897 m_playSource->addModel(model);
Chris@45 3898 }
Chris@45 3899
Chris@45 3900 void
Chris@45 3901 MainWindowBase::mainModelChanged(WaveFileModel *model)
Chris@45 3902 {
Chris@233 3903 // SVDEBUG << "MainWindowBase::mainModelChanged(" << model << ")" << endl;
Chris@45 3904 updateDescriptionLabel();
Chris@45 3905 if (model) m_viewManager->setMainModelSampleRate(model->getSampleRate());
Chris@475 3906 if (model && !(m_playTarget || m_audioIO) &&
Chris@475 3907 (m_soundOptions & WithAudioOutput)) {
Chris@475 3908 createAudioIO();
Chris@360 3909 }
Chris@45 3910 }
Chris@45 3911
Chris@45 3912 void
Chris@45 3913 MainWindowBase::modelAboutToBeDeleted(Model *model)
Chris@45 3914 {
Chris@233 3915 // SVDEBUG << "MainWindowBase::modelAboutToBeDeleted(" << model << ")" << endl;
Chris@45 3916 if (model == m_viewManager->getPlaybackModel()) {
Chris@45 3917 m_viewManager->setPlaybackModel(0);
Chris@45 3918 }
Chris@45 3919 m_playSource->removeModel(model);
Chris@45 3920 }
Chris@45 3921
Chris@45 3922 void
Chris@55 3923 MainWindowBase::paneDeleteButtonClicked(Pane *pane)
Chris@55 3924 {
Chris@55 3925 bool found = false;
Chris@55 3926 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@55 3927 if (m_paneStack->getPane(i) == pane) {
Chris@55 3928 found = true;
Chris@55 3929 break;
Chris@55 3930 }
Chris@55 3931 }
Chris@55 3932 if (!found) {
Chris@233 3933 SVDEBUG << "MainWindowBase::paneDeleteButtonClicked: Unknown pane "
Chris@229 3934 << pane << endl;
Chris@55 3935 return;
Chris@55 3936 }
Chris@55 3937
Chris@55 3938 CommandHistory::getInstance()->startCompoundOperation
Chris@595 3939 (tr("Delete Pane"), true);
Chris@55 3940
Chris@55 3941 while (pane->getLayerCount() > 0) {
Chris@55 3942 Layer *layer = pane->getLayer(0);
Chris@55 3943 if (layer) {
Chris@55 3944 m_document->removeLayerFromView(pane, layer);
Chris@55 3945 } else {
Chris@55 3946 break;
Chris@55 3947 }
Chris@55 3948 }
Chris@55 3949
Chris@55 3950 RemovePaneCommand *command = new RemovePaneCommand(this, pane);
Chris@55 3951 CommandHistory::getInstance()->addCommand(command);
Chris@55 3952
Chris@55 3953 CommandHistory::getInstance()->endCompoundOperation();
Chris@55 3954
Chris@55 3955 updateMenuStates();
Chris@55 3956 }
Chris@55 3957
Chris@55 3958 void
Chris@429 3959 MainWindowBase::alignmentComplete(AlignmentModel *model)
Chris@429 3960 {
Chris@429 3961 cerr << "MainWindowBase::alignmentComplete(" << model << ")" << endl;
Chris@429 3962 }
Chris@429 3963
Chris@429 3964 void
Chris@45 3965 MainWindowBase::pollOSC()
Chris@45 3966 {
Chris@45 3967 if (!m_oscQueue || m_oscQueue->isEmpty()) return;
Chris@233 3968 SVDEBUG << "MainWindowBase::pollOSC: have " << m_oscQueue->getMessagesAvailable() << " messages" << endl;
Chris@45 3969
Chris@45 3970 if (m_openingAudioFile) return;
Chris@45 3971
Chris@45 3972 OSCMessage message = m_oscQueue->readMessage();
Chris@45 3973
Chris@45 3974 if (message.getTarget() != 0) {
Chris@45 3975 return; //!!! for now -- this class is target 0, others not handled yet
Chris@45 3976 }
Chris@45 3977
Chris@45 3978 handleOSCMessage(message);
Chris@45 3979 }
Chris@45 3980
Chris@45 3981 void
Chris@45 3982 MainWindowBase::inProgressSelectionChanged()
Chris@45 3983 {
Chris@45 3984 Pane *currentPane = 0;
Chris@45 3985 if (m_paneStack) currentPane = m_paneStack->getCurrentPane();
justin@331 3986 if (currentPane) {
justin@331 3987 //cerr << "JTEST: mouse event on selection pane" << endl;
justin@331 3988 updateVisibleRangeDisplay(currentPane);
justin@331 3989 }
Chris@45 3990 }
Chris@45 3991
Chris@45 3992 void
Chris@45 3993 MainWindowBase::contextHelpChanged(const QString &s)
Chris@45 3994 {
Chris@378 3995 QLabel *lab = getStatusLabel();
Chris@375 3996
Chris@45 3997 if (s == "" && m_myStatusMessage != "") {
Chris@378 3998 if (lab->text() != m_myStatusMessage) {
Chris@378 3999 lab->setText(m_myStatusMessage);
Chris@375 4000 }
Chris@45 4001 return;
Chris@45 4002 }
Chris@375 4003
Chris@378 4004 lab->setText(s);
Chris@45 4005 }
Chris@45 4006
Chris@45 4007 void
Chris@45 4008 MainWindowBase::openHelpUrl(QString url)
Chris@45 4009 {
Chris@45 4010 // This method mostly lifted from Qt Assistant source code
Chris@45 4011
Chris@45 4012 QProcess *process = new QProcess(this);
Chris@45 4013 connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater()));
Chris@45 4014
Chris@45 4015 QStringList args;
Chris@45 4016
Chris@45 4017 #ifdef Q_OS_MAC
Chris@45 4018 args.append(url);
Chris@45 4019 process->start("open", args);
Chris@45 4020 #else
Chris@45 4021 #ifdef Q_OS_WIN32
Chris@599 4022 std::string pfiles;
Chris@599 4023 (void)getEnvUtf8("ProgramFiles", pfiles);
Chris@599 4024 QString command =
Chris@599 4025 QString::fromStdString(pfiles) +
Chris@599 4026 QString("\\Internet Explorer\\IEXPLORE.EXE");
Chris@358 4027
Chris@358 4028 args.append(url);
Chris@358 4029 process->start(command, args);
Chris@45 4030 #else
Chris@45 4031 if (!qgetenv("KDE_FULL_SESSION").isEmpty()) {
Chris@45 4032 args.append("exec");
Chris@45 4033 args.append(url);
Chris@45 4034 process->start("kfmclient", args);
Chris@45 4035 } else if (!qgetenv("BROWSER").isEmpty()) {
Chris@45 4036 args.append(url);
Chris@45 4037 process->start(qgetenv("BROWSER"), args);
Chris@45 4038 } else {
Chris@45 4039 args.append(url);
Chris@45 4040 process->start("firefox", args);
Chris@45 4041 }
Chris@45 4042 #endif
Chris@45 4043 #endif
Chris@45 4044 }
Chris@45 4045
Chris@483 4046 void
Chris@483 4047 MainWindowBase::openLocalFolder(QString path)
Chris@483 4048 {
Chris@483 4049 QDir d(path);
Chris@483 4050 if (d.exists()) {
Chris@483 4051 QStringList args;
Chris@483 4052 QString path = d.canonicalPath();
Chris@483 4053 #if defined Q_OS_WIN32
Chris@483 4054 // Although the Win32 API is quite happy to have
Chris@483 4055 // forward slashes as directory separators, Windows
Chris@483 4056 // Explorer is not
Chris@483 4057 path = path.replace('/', '\\');
Chris@483 4058 args << path;
Chris@483 4059 QProcess::execute("c:/windows/explorer.exe", args);
Chris@483 4060 #else
Chris@483 4061 args << path;
Chris@605 4062 QProcess process;
Chris@605 4063 QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
Chris@606 4064 env.insert("LD_LIBRARY_PATH", "");
Chris@605 4065 process.setProcessEnvironment(env);
Chris@605 4066 process.start(
Chris@483 4067 #if defined Q_OS_MAC
Chris@483 4068 "/usr/bin/open",
Chris@483 4069 #else
Chris@483 4070 "/usr/bin/xdg-open",
Chris@483 4071 #endif
Chris@483 4072 args);
Chris@608 4073 process.waitForFinished();
Chris@483 4074 #endif
Chris@483 4075 }
Chris@483 4076 }
Chris@483 4077