annotate framework/MainWindowBase.cpp @ 626:51ecc3e2d71c

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