annotate framework/MainWindowBase.cpp @ 639:f54722b34c3a

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