annotate framework/MainWindowBase.cpp @ 570:6f54789f3127 3.0-integration

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