annotate framework/MainWindowBase.cpp @ 562:3c846b06c518 3.0-integration

When returning the frame that we have filled to, avoid accidentally reducing the frame number (making it appear we are less filled than we really are) when we had intended to round it up to the full requested amount. Fixes some unexpected double-playback in non-looping play-selection mode.
author Chris Cannam
date Wed, 14 Dec 2016 11:55:47 +0000
parents 7b115a6505b8
children 1cc23cee4ebf 58354f2934ec
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@559 245 connect(m_playSource, SIGNAL(channelCountIncreased()),
Chris@559 246 this, SLOT(recreateAudioIO()));
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@551 2337
Chris@475 2338 if (m_soundOptions & WithAudioInput) {
Chris@475 2339 m_audioIO = breakfastquay::AudioFactory::
Chris@551 2340 createCallbackIO(m_recordTarget, m_resamplerWrapper, preference);
Chris@525 2341 if (m_audioIO) {
Chris@525 2342 m_audioIO->suspend(); // start in suspended state
Chris@525 2343 m_playSource->setSystemPlaybackTarget(m_audioIO);
Chris@525 2344 }
Chris@475 2345 } else {
Chris@475 2346 m_playTarget = breakfastquay::AudioFactory::
Chris@551 2347 createCallbackPlayTarget(m_resamplerWrapper, preference);
Chris@525 2348 if (m_playTarget) {
Chris@525 2349 m_playTarget->suspend(); // start in suspended state
Chris@525 2350 m_playSource->setSystemPlaybackTarget(m_playTarget);
Chris@525 2351 }
Chris@475 2352 }
Chris@475 2353
Chris@475 2354 if (!m_playTarget && !m_audioIO) {
Chris@104 2355 emit hideSplash();
Chris@547 2356 if (implementation == "") {
Chris@128 2357 QMessageBox::warning
Chris@45 2358 (this, tr("Couldn't open audio device"),
Chris@126 2359 tr("<b>No audio available</b><p>Could not open an audio device for playback.<p>Automatic audio device detection failed. Audio playback will not be available during this session.</p>"),
Chris@45 2360 QMessageBox::Ok);
Chris@126 2361 } else {
Chris@126 2362 QMessageBox::warning
Chris@126 2363 (this, tr("Couldn't open audio device"),
Chris@126 2364 tr("<b>No audio available</b><p>Failed to open your preferred audio device (\"%1\").<p>Audio playback will not be available during this session.</p>")
Chris@547 2365 .arg(breakfastquay::AudioFactory::
Chris@547 2366 getImplementationDescription(implementation.toStdString())
Chris@547 2367 .c_str()),
Chris@126 2368 QMessageBox::Ok);
Chris@126 2369 }
Chris@45 2370 }
Chris@45 2371 }
Chris@45 2372
Chris@556 2373 void
Chris@556 2374 MainWindowBase::deleteAudioIO()
Chris@556 2375 {
Chris@556 2376 // First prevent this trying to call target.
Chris@559 2377 if (m_playSource) {
Chris@559 2378 m_playSource->setSystemPlaybackTarget(0);
Chris@559 2379 m_playSource->setResamplerWrapper(0);
Chris@559 2380 }
Chris@556 2381
Chris@556 2382 // Then delete the breakfastquay::System object.
Chris@556 2383 // Only one of these two exists!
Chris@556 2384 delete m_audioIO;
Chris@556 2385 delete m_playTarget;
Chris@556 2386
Chris@559 2387 // And the breakfastquay resampler wrapper. We need to
Chris@559 2388 // delete/recreate this if the channel count changes, which is one
Chris@559 2389 // of the use cases for recreateAudioIO() calling this
Chris@559 2390 delete m_resamplerWrapper;
Chris@559 2391
Chris@556 2392 m_audioIO = 0;
Chris@556 2393 m_playTarget = 0;
Chris@559 2394 m_resamplerWrapper = 0;
Chris@556 2395 }
Chris@556 2396
Chris@556 2397 void
Chris@556 2398 MainWindowBase::recreateAudioIO()
Chris@556 2399 {
Chris@556 2400 deleteAudioIO();
Chris@556 2401 createAudioIO();
Chris@556 2402 }
Chris@556 2403
Chris@45 2404 WaveFileModel *
Chris@45 2405 MainWindowBase::getMainModel()
Chris@45 2406 {
Chris@45 2407 if (!m_document) return 0;
Chris@45 2408 return m_document->getMainModel();
Chris@45 2409 }
Chris@45 2410
Chris@45 2411 const WaveFileModel *
Chris@45 2412 MainWindowBase::getMainModel() const
Chris@45 2413 {
Chris@45 2414 if (!m_document) return 0;
Chris@45 2415 return m_document->getMainModel();
Chris@45 2416 }
Chris@45 2417
Chris@45 2418 void
Chris@45 2419 MainWindowBase::createDocument()
Chris@45 2420 {
Chris@45 2421 m_document = new Document;
Chris@45 2422
Chris@45 2423 connect(m_document, SIGNAL(layerAdded(Layer *)),
Chris@45 2424 this, SLOT(layerAdded(Layer *)));
Chris@45 2425 connect(m_document, SIGNAL(layerRemoved(Layer *)),
Chris@45 2426 this, SLOT(layerRemoved(Layer *)));
Chris@45 2427 connect(m_document, SIGNAL(layerAboutToBeDeleted(Layer *)),
Chris@45 2428 this, SLOT(layerAboutToBeDeleted(Layer *)));
Chris@45 2429 connect(m_document, SIGNAL(layerInAView(Layer *, bool)),
Chris@45 2430 this, SLOT(layerInAView(Layer *, bool)));
Chris@45 2431
Chris@45 2432 connect(m_document, SIGNAL(modelAdded(Model *)),
Chris@45 2433 this, SLOT(modelAdded(Model *)));
Chris@45 2434 connect(m_document, SIGNAL(mainModelChanged(WaveFileModel *)),
Chris@45 2435 this, SLOT(mainModelChanged(WaveFileModel *)));
Chris@45 2436 connect(m_document, SIGNAL(modelAboutToBeDeleted(Model *)),
Chris@45 2437 this, SLOT(modelAboutToBeDeleted(Model *)));
Chris@45 2438
Chris@78 2439 connect(m_document, SIGNAL(modelGenerationFailed(QString, QString)),
Chris@78 2440 this, SLOT(modelGenerationFailed(QString, QString)));
Chris@78 2441 connect(m_document, SIGNAL(modelRegenerationWarning(QString, QString, QString)),
Chris@78 2442 this, SLOT(modelRegenerationWarning(QString, QString, QString)));
Chris@78 2443 connect(m_document, SIGNAL(modelGenerationFailed(QString, QString)),
Chris@78 2444 this, SLOT(modelGenerationFailed(QString, QString)));
Chris@78 2445 connect(m_document, SIGNAL(modelRegenerationWarning(QString, QString, QString)),
Chris@78 2446 this, SLOT(modelRegenerationWarning(QString, QString, QString)));
Chris@429 2447 connect(m_document, SIGNAL(alignmentComplete(AlignmentModel *)),
Chris@429 2448 this, SLOT(alignmentComplete(AlignmentModel *)));
Chris@423 2449 connect(m_document, SIGNAL(alignmentFailed(QString)),
Chris@423 2450 this, SLOT(alignmentFailed(QString)));
Chris@160 2451
Chris@160 2452 emit replacedDocument();
Chris@45 2453 }
Chris@45 2454
Chris@45 2455 bool
Chris@45 2456 MainWindowBase::saveSessionFile(QString path)
Chris@45 2457 {
Chris@217 2458 try {
Chris@217 2459
Chris@217 2460 TempWriteFile temp(path);
Chris@217 2461
Chris@217 2462 BZipFileDevice bzFile(temp.getTemporaryFilename());
Chris@217 2463 if (!bzFile.open(QIODevice::WriteOnly)) {
Chris@293 2464 cerr << "Failed to open session file \""
Chris@294 2465 << temp.getTemporaryFilename()
Chris@217 2466 << "\" for writing: "
Chris@293 2467 << bzFile.errorString() << endl;
Chris@217 2468 return false;
Chris@217 2469 }
Chris@217 2470
Chris@217 2471 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
Chris@217 2472
Chris@217 2473 QTextStream out(&bzFile);
Chris@432 2474 out.setCodec(QTextCodec::codecForName("UTF-8"));
Chris@226 2475 toXml(out, false);
Chris@217 2476 out.flush();
Chris@217 2477
Chris@217 2478 QApplication::restoreOverrideCursor();
Chris@217 2479
Chris@217 2480 if (!bzFile.isOK()) {
Chris@217 2481 QMessageBox::critical(this, tr("Failed to write file"),
Chris@217 2482 tr("<b>Save failed</b><p>Failed to write to file \"%1\": %2")
Chris@217 2483 .arg(path).arg(bzFile.errorString()));
Chris@217 2484 bzFile.close();
Chris@217 2485 return false;
Chris@217 2486 }
Chris@217 2487
Chris@217 2488 bzFile.close();
Chris@217 2489 temp.moveToTarget();
Chris@217 2490 return true;
Chris@217 2491
Chris@217 2492 } catch (FileOperationFailed &f) {
Chris@217 2493
Chris@217 2494 QMessageBox::critical(this, tr("Failed to write file"),
Chris@217 2495 tr("<b>Save failed</b><p>Failed to write to file \"%1\": %2")
Chris@217 2496 .arg(path).arg(f.what()));
Chris@45 2497 return false;
Chris@45 2498 }
Chris@45 2499 }
Chris@45 2500
Chris@224 2501 bool
Chris@224 2502 MainWindowBase::saveSessionTemplate(QString path)
Chris@224 2503 {
Chris@224 2504 try {
Chris@224 2505
Chris@224 2506 TempWriteFile temp(path);
Chris@224 2507
Chris@224 2508 QFile file(temp.getTemporaryFilename());
Chris@224 2509 if (!file.open(QIODevice::WriteOnly)) {
Chris@293 2510 cerr << "Failed to open session template file \""
Chris@294 2511 << temp.getTemporaryFilename()
Chris@224 2512 << "\" for writing: "
Chris@294 2513 << file.errorString() << endl;
Chris@224 2514 return false;
Chris@224 2515 }
Chris@224 2516
Chris@224 2517 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
Chris@224 2518
Chris@224 2519 QTextStream out(&file);
Chris@432 2520 out.setCodec(QTextCodec::codecForName("UTF-8"));
Chris@226 2521 toXml(out, true);
Chris@224 2522 out.flush();
Chris@224 2523
Chris@224 2524 QApplication::restoreOverrideCursor();
Chris@224 2525
Chris@224 2526 file.close();
Chris@224 2527 temp.moveToTarget();
Chris@224 2528 return true;
Chris@224 2529
Chris@224 2530 } catch (FileOperationFailed &f) {
Chris@224 2531
Chris@224 2532 QMessageBox::critical(this, tr("Failed to write file"),
Chris@224 2533 tr("<b>Save failed</b><p>Failed to write to file \"%1\": %2")
Chris@224 2534 .arg(path).arg(f.what()));
Chris@224 2535 return false;
Chris@224 2536 }
Chris@224 2537 }
Chris@224 2538
Chris@45 2539 void
Chris@226 2540 MainWindowBase::toXml(QTextStream &out, bool asTemplate)
Chris@45 2541 {
Chris@45 2542 QString indent(" ");
Chris@45 2543
Chris@45 2544 out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
Chris@45 2545 out << "<!DOCTYPE sonic-visualiser>\n";
Chris@45 2546 out << "<sv>\n";
Chris@45 2547
Chris@226 2548 if (asTemplate) {
Chris@226 2549 m_document->toXmlAsTemplate(out, "", "");
Chris@226 2550 } else {
Chris@226 2551 m_document->toXml(out, "", "");
Chris@226 2552 }
Chris@45 2553
Chris@45 2554 out << "<display>\n";
Chris@45 2555
Chris@45 2556 out << QString(" <window width=\"%1\" height=\"%2\"/>\n")
Chris@45 2557 .arg(width()).arg(height());
Chris@45 2558
Chris@45 2559 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@45 2560
Chris@45 2561 Pane *pane = m_paneStack->getPane(i);
Chris@45 2562
Chris@45 2563 if (pane) {
Chris@45 2564 pane->toXml(out, indent);
Chris@45 2565 }
Chris@45 2566 }
Chris@45 2567
Chris@45 2568 out << "</display>\n";
Chris@45 2569
Chris@45 2570 m_viewManager->getSelection().toXml(out);
Chris@45 2571
Chris@45 2572 out << "</sv>\n";
Chris@45 2573 }
Chris@45 2574
Chris@45 2575 Pane *
Chris@45 2576 MainWindowBase::addPaneToStack()
Chris@45 2577 {
Chris@342 2578 cerr << "MainWindowBase::addPaneToStack()" << endl;
Chris@45 2579 AddPaneCommand *command = new AddPaneCommand(this);
Chris@45 2580 CommandHistory::getInstance()->addCommand(command);
Chris@57 2581 Pane *pane = command->getPane();
Chris@57 2582 return pane;
Chris@45 2583 }
Chris@45 2584
Chris@45 2585 void
Chris@45 2586 MainWindowBase::zoomIn()
Chris@45 2587 {
Chris@45 2588 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 2589 if (currentPane) currentPane->zoom(true);
Chris@45 2590 }
Chris@45 2591
Chris@45 2592 void
Chris@45 2593 MainWindowBase::zoomOut()
Chris@45 2594 {
Chris@45 2595 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 2596 if (currentPane) currentPane->zoom(false);
Chris@45 2597 }
Chris@45 2598
Chris@45 2599 void
Chris@45 2600 MainWindowBase::zoomToFit()
Chris@45 2601 {
Chris@45 2602 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 2603 if (!currentPane) return;
Chris@45 2604
Chris@45 2605 Model *model = getMainModel();
Chris@45 2606 if (!model) return;
Chris@45 2607
Chris@434 2608 sv_frame_t start = model->getStartFrame();
Chris@434 2609 sv_frame_t end = model->getEndFrame();
Chris@60 2610 if (m_playSource) end = std::max(end, m_playSource->getPlayEndFrame());
Chris@366 2611 int pixels = currentPane->width();
Chris@366 2612
Chris@366 2613 int sw = currentPane->getVerticalScaleWidth();
Chris@45 2614 if (pixels > sw * 2) pixels -= sw * 2;
Chris@45 2615 else pixels = 1;
Chris@45 2616 if (pixels > 4) pixels -= 4;
Chris@45 2617
Chris@436 2618 int zoomLevel = int((end - start) / pixels);
Chris@150 2619 if (zoomLevel < 1) zoomLevel = 1;
Chris@45 2620
Chris@45 2621 currentPane->setZoomLevel(zoomLevel);
Chris@45 2622 currentPane->setCentreFrame((start + end) / 2);
Chris@45 2623 }
Chris@45 2624
Chris@45 2625 void
Chris@45 2626 MainWindowBase::zoomDefault()
Chris@45 2627 {
Chris@45 2628 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@302 2629 QSettings settings;
Chris@302 2630 settings.beginGroup("MainWindow");
Chris@302 2631 int zoom = settings.value("zoom-default", 1024).toInt();
Chris@302 2632 settings.endGroup();
Chris@302 2633 if (currentPane) currentPane->setZoomLevel(zoom);
Chris@45 2634 }
Chris@45 2635
Chris@45 2636 void
Chris@45 2637 MainWindowBase::scrollLeft()
Chris@45 2638 {
Chris@45 2639 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 2640 if (currentPane) currentPane->scroll(false, false);
Chris@45 2641 }
Chris@45 2642
Chris@45 2643 void
Chris@45 2644 MainWindowBase::jumpLeft()
Chris@45 2645 {
Chris@45 2646 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 2647 if (currentPane) currentPane->scroll(false, true);
Chris@45 2648 }
Chris@45 2649
Chris@45 2650 void
Chris@162 2651 MainWindowBase::peekLeft()
Chris@162 2652 {
Chris@162 2653 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@162 2654 if (currentPane) currentPane->scroll(false, false, false);
Chris@162 2655 }
Chris@162 2656
Chris@162 2657 void
Chris@45 2658 MainWindowBase::scrollRight()
Chris@45 2659 {
Chris@45 2660 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 2661 if (currentPane) currentPane->scroll(true, false);
Chris@45 2662 }
Chris@45 2663
Chris@45 2664 void
Chris@45 2665 MainWindowBase::jumpRight()
Chris@45 2666 {
Chris@45 2667 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@45 2668 if (currentPane) currentPane->scroll(true, true);
Chris@45 2669 }
Chris@45 2670
Chris@45 2671 void
Chris@162 2672 MainWindowBase::peekRight()
Chris@162 2673 {
Chris@162 2674 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@162 2675 if (currentPane) currentPane->scroll(true, false, false);
Chris@162 2676 }
Chris@162 2677
Chris@162 2678 void
Chris@45 2679 MainWindowBase::showNoOverlays()
Chris@45 2680 {
Chris@45 2681 m_viewManager->setOverlayMode(ViewManager::NoOverlays);
Chris@45 2682 }
Chris@45 2683
Chris@45 2684 void
Chris@45 2685 MainWindowBase::showMinimalOverlays()
Chris@45 2686 {
Chris@335 2687 m_viewManager->setOverlayMode(ViewManager::StandardOverlays);
Chris@45 2688 }
Chris@45 2689
Chris@45 2690 void
Chris@45 2691 MainWindowBase::showAllOverlays()
Chris@45 2692 {
Chris@45 2693 m_viewManager->setOverlayMode(ViewManager::AllOverlays);
Chris@45 2694 }
Chris@45 2695
Chris@45 2696 void
Chris@211 2697 MainWindowBase::toggleTimeRulers()
Chris@211 2698 {
Chris@211 2699 bool haveRulers = false;
Chris@211 2700 bool someHidden = false;
Chris@211 2701
Chris@211 2702 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@211 2703
Chris@211 2704 Pane *pane = m_paneStack->getPane(i);
Chris@211 2705 if (!pane) continue;
Chris@211 2706
Chris@211 2707 for (int j = 0; j < pane->getLayerCount(); ++j) {
Chris@211 2708
Chris@211 2709 Layer *layer = pane->getLayer(j);
Chris@211 2710 if (!dynamic_cast<TimeRulerLayer *>(layer)) continue;
Chris@211 2711
Chris@211 2712 haveRulers = true;
Chris@211 2713 if (layer->isLayerDormant(pane)) someHidden = true;
Chris@211 2714 }
Chris@211 2715 }
Chris@211 2716
Chris@211 2717 if (haveRulers) {
Chris@211 2718
Chris@211 2719 bool show = someHidden;
Chris@211 2720
Chris@211 2721 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@211 2722
Chris@211 2723 Pane *pane = m_paneStack->getPane(i);
Chris@211 2724 if (!pane) continue;
Chris@211 2725
Chris@211 2726 for (int j = 0; j < pane->getLayerCount(); ++j) {
Chris@211 2727
Chris@211 2728 Layer *layer = pane->getLayer(j);
Chris@211 2729 if (!dynamic_cast<TimeRulerLayer *>(layer)) continue;
Chris@211 2730
Chris@211 2731 layer->showLayer(pane, show);
Chris@211 2732 }
Chris@211 2733 }
Chris@211 2734 }
Chris@211 2735 }
Chris@211 2736
Chris@211 2737 void
Chris@45 2738 MainWindowBase::toggleZoomWheels()
Chris@45 2739 {
Chris@45 2740 if (m_viewManager->getZoomWheelsEnabled()) {
Chris@45 2741 m_viewManager->setZoomWheelsEnabled(false);
Chris@45 2742 } else {
Chris@45 2743 m_viewManager->setZoomWheelsEnabled(true);
Chris@45 2744 }
Chris@45 2745 }
Chris@45 2746
Chris@45 2747 void
Chris@45 2748 MainWindowBase::togglePropertyBoxes()
Chris@45 2749 {
Chris@45 2750 if (m_paneStack->getLayoutStyle() == PaneStack::NoPropertyStacks) {
Chris@45 2751 if (Preferences::getInstance()->getPropertyBoxLayout() ==
Chris@45 2752 Preferences::VerticallyStacked) {
Chris@45 2753 m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout);
Chris@45 2754 } else {
Chris@45 2755 m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout);
Chris@45 2756 }
Chris@45 2757 } else {
Chris@45 2758 m_paneStack->setLayoutStyle(PaneStack::NoPropertyStacks);
Chris@45 2759 }
Chris@45 2760 }
Chris@45 2761
Chris@378 2762 QLabel *
Chris@378 2763 MainWindowBase::getStatusLabel() const
Chris@378 2764 {
Chris@378 2765 if (!m_statusLabel) {
Chris@378 2766 m_statusLabel = new QLabel();
Chris@378 2767 statusBar()->addWidget(m_statusLabel, 1);
Chris@378 2768 }
Chris@379 2769
Chris@379 2770 QList<QFrame *> frames = statusBar()->findChildren<QFrame *>();
Chris@379 2771 foreach (QFrame *f, frames) {
Chris@379 2772 f->setFrameStyle(QFrame::NoFrame);
Chris@379 2773 }
Chris@379 2774
Chris@378 2775 return m_statusLabel;
Chris@378 2776 }
Chris@378 2777
Chris@45 2778 void
Chris@45 2779 MainWindowBase::toggleStatusBar()
Chris@45 2780 {
Chris@45 2781 QSettings settings;
Chris@45 2782 settings.beginGroup("MainWindow");
Chris@45 2783 bool sb = settings.value("showstatusbar", true).toBool();
Chris@45 2784
Chris@45 2785 if (sb) {
Chris@45 2786 statusBar()->hide();
Chris@45 2787 } else {
Chris@45 2788 statusBar()->show();
Chris@45 2789 }
Chris@45 2790
Chris@45 2791 settings.setValue("showstatusbar", !sb);
Chris@45 2792
Chris@45 2793 settings.endGroup();
Chris@45 2794 }
Chris@45 2795
Chris@45 2796 void
Chris@256 2797 MainWindowBase::toggleCentreLine()
Chris@256 2798 {
Chris@256 2799 if (m_viewManager->shouldShowCentreLine()) {
Chris@256 2800 m_viewManager->setShowCentreLine(false);
Chris@256 2801 } else {
Chris@256 2802 m_viewManager->setShowCentreLine(true);
Chris@256 2803 }
Chris@256 2804 }
Chris@256 2805
Chris@256 2806 void
Chris@45 2807 MainWindowBase::preferenceChanged(PropertyContainer::PropertyName name)
Chris@45 2808 {
Chris@45 2809 if (name == "Property Box Layout") {
Chris@45 2810 if (m_paneStack->getLayoutStyle() != PaneStack::NoPropertyStacks) {
Chris@45 2811 if (Preferences::getInstance()->getPropertyBoxLayout() ==
Chris@45 2812 Preferences::VerticallyStacked) {
Chris@45 2813 m_paneStack->setLayoutStyle(PaneStack::PropertyStackPerPaneLayout);
Chris@45 2814 } else {
Chris@45 2815 m_paneStack->setLayoutStyle(PaneStack::SinglePropertyStackLayout);
Chris@45 2816 }
Chris@45 2817 }
Chris@45 2818 } else if (name == "Background Mode" && m_viewManager) {
Chris@45 2819 Preferences::BackgroundMode mode =
Chris@45 2820 Preferences::getInstance()->getBackgroundMode();
Chris@45 2821 if (mode == Preferences::BackgroundFromTheme) {
Chris@45 2822 m_viewManager->setGlobalDarkBackground(m_initialDarkBackground);
Chris@45 2823 } else if (mode == Preferences::DarkBackground) {
Chris@45 2824 m_viewManager->setGlobalDarkBackground(true);
Chris@45 2825 } else {
Chris@45 2826 m_viewManager->setGlobalDarkBackground(false);
Chris@45 2827 }
Chris@45 2828 }
Chris@45 2829 }
Chris@45 2830
Chris@45 2831 void
Chris@45 2832 MainWindowBase::play()
Chris@45 2833 {
Chris@516 2834 if ((m_recordTarget && m_recordTarget->isRecording()) ||
Chris@516 2835 (m_playSource && m_playSource->isPlaying())) {
Chris@45 2836 stop();
Chris@479 2837 QAction *action = qobject_cast<QAction *>(sender());
Chris@479 2838 if (action) action->setChecked(false);
Chris@45 2839 } else {
Chris@487 2840 if (m_audioIO) m_audioIO->resume();
Chris@509 2841 else if (m_playTarget) m_playTarget->resume();
Chris@45 2842 playbackFrameChanged(m_viewManager->getPlaybackFrame());
Chris@45 2843 m_playSource->play(m_viewManager->getPlaybackFrame());
Chris@45 2844 }
Chris@45 2845 }
Chris@45 2846
Chris@45 2847 void
Chris@477 2848 MainWindowBase::record()
Chris@477 2849 {
Chris@478 2850 if (!(m_soundOptions & WithAudioInput)) {
Chris@478 2851 return;
Chris@478 2852 }
Chris@478 2853
Chris@477 2854 if (!m_recordTarget) {
Chris@477 2855 //!!! report
Chris@477 2856 return;
Chris@477 2857 }
Chris@477 2858
Chris@478 2859 if (!m_audioIO) {
Chris@478 2860 createAudioIO();
Chris@478 2861 }
Chris@492 2862
Chris@492 2863 if (!m_audioIO) {
Chris@492 2864 //!!! report
Chris@492 2865 return;
Chris@492 2866 }
Chris@478 2867
Chris@477 2868 if (m_recordTarget->isRecording()) {
Chris@492 2869 stop();
Chris@477 2870 return;
Chris@477 2871 }
Chris@477 2872
Chris@490 2873 QAction *action = qobject_cast<QAction *>(sender());
Chris@490 2874
Chris@483 2875 if (m_audioRecordMode == RecordReplaceSession) {
Chris@490 2876 if (!checkSaveModified()) {
Chris@490 2877 if (action) action->setChecked(false);
Chris@490 2878 return;
Chris@490 2879 }
Chris@483 2880 }
Chris@487 2881
Chris@557 2882 if (m_viewManager) m_viewManager->setGlobalCentreFrame(0);
Chris@557 2883
Chris@492 2884 m_audioIO->resume();
Chris@509 2885
Chris@477 2886 WritableWaveFileModel *model = m_recordTarget->startRecording();
Chris@477 2887 if (!model) {
Chris@477 2888 cerr << "ERROR: MainWindowBase::record: Recording failed" << endl;
Chris@477 2889 //!!! report
Chris@490 2890 if (action) action->setChecked(false);
Chris@477 2891 return;
Chris@477 2892 }
Chris@477 2893
Chris@477 2894 if (!model->isOK()) {
Chris@477 2895 m_recordTarget->stopRecording();
Chris@492 2896 m_audioIO->suspend();
Chris@477 2897 delete model;
Chris@477 2898 return;
Chris@477 2899 }
Chris@487 2900
Chris@478 2901 PlayParameterRepository::getInstance()->addPlayable(model);
Chris@483 2902
Chris@483 2903 if (m_audioRecordMode == RecordReplaceSession || !getMainModel()) {
Chris@478 2904
Chris@479 2905 //!!! duplication with openAudio here
Chris@479 2906
Chris@479 2907 QString templateName = getDefaultSessionTemplate();
Chris@479 2908 bool loadedTemplate = false;
Chris@479 2909
Chris@479 2910 if (templateName != "") {
Chris@479 2911 FileOpenStatus tplStatus = openSessionTemplate(templateName);
Chris@479 2912 if (tplStatus == FileOpenCancelled) {
Chris@490 2913 m_recordTarget->stopRecording();
Chris@492 2914 m_audioIO->suspend();
Chris@490 2915 PlayParameterRepository::getInstance()->removePlayable(model);
Chris@479 2916 return;
Chris@479 2917 }
Chris@479 2918 if (tplStatus != FileOpenFailed) {
Chris@479 2919 loadedTemplate = true;
Chris@479 2920 }
Chris@479 2921 }
Chris@479 2922
Chris@479 2923 if (!loadedTemplate) {
Chris@479 2924 closeSession();
Chris@479 2925 createDocument();
Chris@479 2926 }
Chris@479 2927
Chris@479 2928 Model *prevMain = getMainModel();
Chris@479 2929 if (prevMain) {
Chris@479 2930 m_playSource->removeModel(prevMain);
Chris@479 2931 PlayParameterRepository::getInstance()->removePlayable(prevMain);
Chris@479 2932 }
Chris@479 2933
Chris@478 2934 m_document->setMainModel(model);
Chris@478 2935 setupMenus();
Chris@478 2936
Chris@479 2937 if (loadedTemplate || (m_sessionFile == "")) {
Chris@479 2938 //!!! shouldn't be dealing directly with title from here -- call a method
Chris@479 2939 setWindowTitle(tr("%1: %2")
Chris@479 2940 .arg(QApplication::applicationName())
Chris@479 2941 .arg(model->getLocation()));
Chris@479 2942 CommandHistory::getInstance()->clear();
Chris@479 2943 CommandHistory::getInstance()->documentSaved();
Chris@479 2944 m_documentModified = false;
Chris@479 2945 } else {
Chris@479 2946 setWindowTitle(tr("%1: %2 [%3]")
Chris@479 2947 .arg(QApplication::applicationName())
Chris@479 2948 .arg(QFileInfo(m_sessionFile).fileName())
Chris@479 2949 .arg(model->getLocation()));
Chris@479 2950 if (m_documentModified) {
Chris@479 2951 m_documentModified = false;
Chris@479 2952 documentModified(); // so as to restore "(modified)" window title
Chris@479 2953 }
Chris@479 2954 }
Chris@479 2955
Chris@478 2956 } else {
Chris@478 2957
Chris@478 2958 CommandHistory::getInstance()->startCompoundOperation
Chris@478 2959 (tr("Import Recorded Audio"), true);
Chris@478 2960
Chris@478 2961 m_document->addImportedModel(model);
Chris@478 2962
Chris@478 2963 AddPaneCommand *command = new AddPaneCommand(this);
Chris@478 2964 CommandHistory::getInstance()->addCommand(command);
Chris@478 2965
Chris@478 2966 Pane *pane = command->getPane();
Chris@478 2967
Chris@478 2968 if (m_timeRulerLayer) {
Chris@478 2969 m_document->addLayerToView(pane, m_timeRulerLayer);
Chris@478 2970 }
Chris@478 2971
Chris@478 2972 Layer *newLayer = m_document->createImportedLayer(model);
Chris@478 2973
Chris@478 2974 if (newLayer) {
Chris@478 2975 m_document->addLayerToView(pane, newLayer);
Chris@478 2976 }
Chris@478 2977
Chris@478 2978 CommandHistory::getInstance()->endCompoundOperation();
Chris@477 2979 }
Chris@479 2980
Chris@479 2981 updateMenuStates();
Chris@479 2982 m_recentFiles.addFile(model->getLocation());
Chris@479 2983 currentPaneChanged(m_paneStack->getCurrentPane());
Chris@496 2984
Chris@496 2985 emit audioFileLoaded();
Chris@477 2986 }
Chris@477 2987
Chris@477 2988 void
Chris@45 2989 MainWindowBase::ffwd()
Chris@45 2990 {
Chris@45 2991 if (!getMainModel()) return;
Chris@45 2992
Chris@435 2993 sv_frame_t frame = m_viewManager->getPlaybackFrame();
Chris@45 2994 ++frame;
Chris@45 2995
Chris@85 2996 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 2997 Layer *layer = getSnapLayer();
Chris@435 2998 sv_samplerate_t sr = getMainModel()->getSampleRate();
Chris@45 2999
Chris@45 3000 if (!layer) {
Chris@45 3001
Chris@45 3002 frame = RealTime::realTime2Frame
Chris@357 3003 (RealTime::frame2RealTime(frame, sr) + m_defaultFfwdRwdStep, sr);
Chris@435 3004 if (frame > getMainModel()->getEndFrame()) {
Chris@45 3005 frame = getMainModel()->getEndFrame();
Chris@45 3006 }
Chris@45 3007
Chris@45 3008 } else {
Chris@45 3009
Chris@366 3010 int resolution = 0;
Chris@166 3011 if (pane) frame = pane->alignFromReference(frame);
Chris@85 3012 if (layer->snapToFeatureFrame(m_paneStack->getCurrentPane(),
Chris@85 3013 frame, resolution, Layer::SnapRight)) {
Chris@85 3014 if (pane) frame = pane->alignToReference(frame);
Chris@85 3015 } else {
Chris@45 3016 frame = getMainModel()->getEndFrame();
Chris@45 3017 }
Chris@45 3018 }
Chris@45 3019
Chris@45 3020 if (frame < 0) frame = 0;
Chris@45 3021
Chris@45 3022 if (m_viewManager->getPlaySelectionMode()) {
Chris@435 3023 frame = m_viewManager->constrainFrameToSelection(frame);
Chris@45 3024 }
Chris@45 3025
Chris@45 3026 m_viewManager->setPlaybackFrame(frame);
Chris@166 3027
Chris@435 3028 if (frame == getMainModel()->getEndFrame() &&
Chris@166 3029 m_playSource &&
Chris@166 3030 m_playSource->isPlaying() &&
Chris@166 3031 !m_viewManager->getPlayLoopMode()) {
Chris@166 3032 stop();
Chris@166 3033 }
Chris@45 3034 }
Chris@45 3035
Chris@45 3036 void
Chris@45 3037 MainWindowBase::ffwdEnd()
Chris@45 3038 {
Chris@45 3039 if (!getMainModel()) return;
Chris@45 3040
Chris@139 3041 if (m_playSource &&
Chris@139 3042 m_playSource->isPlaying() &&
Chris@139 3043 !m_viewManager->getPlayLoopMode()) {
Chris@139 3044 stop();
Chris@139 3045 }
Chris@139 3046
Chris@435 3047 sv_frame_t frame = getMainModel()->getEndFrame();
Chris@45 3048
Chris@45 3049 if (m_viewManager->getPlaySelectionMode()) {
Chris@45 3050 frame = m_viewManager->constrainFrameToSelection(frame);
Chris@45 3051 }
Chris@45 3052
Chris@45 3053 m_viewManager->setPlaybackFrame(frame);
Chris@45 3054 }
Chris@45 3055
Chris@45 3056 void
Chris@166 3057 MainWindowBase::ffwdSimilar()
Chris@166 3058 {
Chris@166 3059 if (!getMainModel()) return;
Chris@166 3060
Chris@166 3061 Layer *layer = getSnapLayer();
Chris@166 3062 if (!layer) { ffwd(); return; }
Chris@166 3063
Chris@166 3064 Pane *pane = m_paneStack->getCurrentPane();
Chris@435 3065 sv_frame_t frame = m_viewManager->getPlaybackFrame();
Chris@166 3066
Chris@366 3067 int resolution = 0;
Chris@166 3068 if (pane) frame = pane->alignFromReference(frame);
Chris@166 3069 if (layer->snapToSimilarFeature(m_paneStack->getCurrentPane(),
Chris@166 3070 frame, resolution, Layer::SnapRight)) {
Chris@166 3071 if (pane) frame = pane->alignToReference(frame);
Chris@166 3072 } else {
Chris@166 3073 frame = getMainModel()->getEndFrame();
Chris@166 3074 }
Chris@166 3075
Chris@166 3076 if (frame < 0) frame = 0;
Chris@166 3077
Chris@166 3078 if (m_viewManager->getPlaySelectionMode()) {
Chris@435 3079 frame = m_viewManager->constrainFrameToSelection(frame);
Chris@166 3080 }
Chris@166 3081
Chris@166 3082 m_viewManager->setPlaybackFrame(frame);
Chris@166 3083
Chris@435 3084 if (frame == getMainModel()->getEndFrame() &&
Chris@166 3085 m_playSource &&
Chris@166 3086 m_playSource->isPlaying() &&
Chris@166 3087 !m_viewManager->getPlayLoopMode()) {
Chris@166 3088 stop();
Chris@166 3089 }
Chris@166 3090 }
Chris@166 3091
Chris@166 3092 void
Chris@45 3093 MainWindowBase::rewind()
Chris@45 3094 {
Chris@45 3095 if (!getMainModel()) return;
Chris@45 3096
Chris@435 3097 sv_frame_t frame = m_viewManager->getPlaybackFrame();
Chris@45 3098 if (frame > 0) --frame;
Chris@45 3099
Chris@85 3100 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 3101 Layer *layer = getSnapLayer();
Chris@435 3102 sv_samplerate_t sr = getMainModel()->getSampleRate();
Chris@45 3103
Chris@45 3104 // when rewinding during playback, we want to allow a period
Chris@45 3105 // following a rewind target point at which the rewind will go to
Chris@45 3106 // the prior point instead of the immediately neighbouring one
Chris@45 3107 if (m_playSource && m_playSource->isPlaying()) {
Chris@45 3108 RealTime ct = RealTime::frame2RealTime(frame, sr);
Chris@357 3109 ct = ct - RealTime::fromSeconds(0.15);
Chris@45 3110 if (ct < RealTime::zeroTime) ct = RealTime::zeroTime;
Chris@45 3111 frame = RealTime::realTime2Frame(ct, sr);
Chris@45 3112 }
Chris@45 3113
Chris@45 3114 if (!layer) {
Chris@45 3115
Chris@45 3116 frame = RealTime::realTime2Frame
Chris@357 3117 (RealTime::frame2RealTime(frame, sr) - m_defaultFfwdRwdStep, sr);
Chris@435 3118 if (frame < getMainModel()->getStartFrame()) {
Chris@45 3119 frame = getMainModel()->getStartFrame();
Chris@45 3120 }
Chris@45 3121
Chris@45 3122 } else {
Chris@45 3123
Chris@366 3124 int resolution = 0;
Chris@166 3125 if (pane) frame = pane->alignFromReference(frame);
Chris@85 3126 if (layer->snapToFeatureFrame(m_paneStack->getCurrentPane(),
Chris@85 3127 frame, resolution, Layer::SnapLeft)) {
Chris@85 3128 if (pane) frame = pane->alignToReference(frame);
Chris@85 3129 } else {
Chris@45 3130 frame = getMainModel()->getStartFrame();
Chris@45 3131 }
Chris@45 3132 }
Chris@45 3133
Chris@45 3134 if (frame < 0) frame = 0;
Chris@45 3135
Chris@45 3136 if (m_viewManager->getPlaySelectionMode()) {
Chris@435 3137 frame = m_viewManager->constrainFrameToSelection(frame);
Chris@45 3138 }
Chris@45 3139
Chris@45 3140 m_viewManager->setPlaybackFrame(frame);
Chris@45 3141 }
Chris@45 3142
Chris@45 3143 void
Chris@45 3144 MainWindowBase::rewindStart()
Chris@45 3145 {
Chris@45 3146 if (!getMainModel()) return;
Chris@45 3147
Chris@435 3148 sv_frame_t frame = getMainModel()->getStartFrame();
Chris@45 3149
Chris@45 3150 if (m_viewManager->getPlaySelectionMode()) {
Chris@45 3151 frame = m_viewManager->constrainFrameToSelection(frame);
Chris@45 3152 }
Chris@45 3153
Chris@45 3154 m_viewManager->setPlaybackFrame(frame);
Chris@45 3155 }
Chris@45 3156
Chris@166 3157 void
Chris@166 3158 MainWindowBase::rewindSimilar()
Chris@166 3159 {
Chris@166 3160 if (!getMainModel()) return;
Chris@166 3161
Chris@166 3162 Layer *layer = getSnapLayer();
Chris@166 3163 if (!layer) { rewind(); return; }
Chris@166 3164
Chris@166 3165 Pane *pane = m_paneStack->getCurrentPane();
Chris@435 3166 sv_frame_t frame = m_viewManager->getPlaybackFrame();
Chris@166 3167
Chris@366 3168 int resolution = 0;
Chris@166 3169 if (pane) frame = pane->alignFromReference(frame);
Chris@166 3170 if (layer->snapToSimilarFeature(m_paneStack->getCurrentPane(),
Chris@166 3171 frame, resolution, Layer::SnapLeft)) {
Chris@166 3172 if (pane) frame = pane->alignToReference(frame);
Chris@166 3173 } else {
Chris@166 3174 frame = getMainModel()->getStartFrame();
Chris@166 3175 }
Chris@166 3176
Chris@166 3177 if (frame < 0) frame = 0;
Chris@166 3178
Chris@166 3179 if (m_viewManager->getPlaySelectionMode()) {
Chris@435 3180 frame = m_viewManager->constrainFrameToSelection(frame);
Chris@166 3181 }
Chris@166 3182
Chris@166 3183 m_viewManager->setPlaybackFrame(frame);
Chris@166 3184 }
Chris@166 3185
Chris@45 3186 Layer *
Chris@45 3187 MainWindowBase::getSnapLayer() const
Chris@45 3188 {
Chris@45 3189 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 3190 if (!pane) return 0;
Chris@45 3191
Chris@45 3192 Layer *layer = pane->getSelectedLayer();
Chris@45 3193
Chris@45 3194 if (!dynamic_cast<TimeInstantLayer *>(layer) &&
Chris@45 3195 !dynamic_cast<TimeValueLayer *>(layer) &&
Chris@194 3196 !dynamic_cast<RegionLayer *>(layer) &&
Chris@45 3197 !dynamic_cast<TimeRulerLayer *>(layer)) {
Chris@45 3198
Chris@45 3199 layer = 0;
Chris@45 3200
Chris@45 3201 for (int i = pane->getLayerCount(); i > 0; --i) {
Chris@45 3202 Layer *l = pane->getLayer(i-1);
Chris@45 3203 if (dynamic_cast<TimeRulerLayer *>(l)) {
Chris@45 3204 layer = l;
Chris@45 3205 break;
Chris@45 3206 }
Chris@45 3207 }
Chris@45 3208 }
Chris@45 3209
Chris@45 3210 return layer;
Chris@45 3211 }
Chris@45 3212
Chris@45 3213 void
Chris@45 3214 MainWindowBase::stop()
Chris@45 3215 {
Chris@516 3216 if (m_recordTarget &&
Chris@516 3217 m_recordTarget->isRecording()) {
Chris@477 3218 m_recordTarget->stopRecording();
Chris@477 3219 }
Chris@516 3220
Chris@516 3221 if (!m_playSource) return;
Chris@516 3222
Chris@45 3223 m_playSource->stop();
Chris@45 3224
Chris@487 3225 if (m_audioIO) m_audioIO->suspend();
Chris@509 3226 else if (m_playTarget) m_playTarget->suspend();
Chris@487 3227
Chris@45 3228 if (m_paneStack && m_paneStack->getCurrentPane()) {
Chris@45 3229 updateVisibleRangeDisplay(m_paneStack->getCurrentPane());
Chris@45 3230 } else {
Chris@45 3231 m_myStatusMessage = "";
Chris@378 3232 getStatusLabel()->setText("");
Chris@45 3233 }
Chris@45 3234 }
Chris@45 3235
Chris@45 3236 MainWindowBase::AddPaneCommand::AddPaneCommand(MainWindowBase *mw) :
Chris@45 3237 m_mw(mw),
Chris@45 3238 m_pane(0),
Chris@45 3239 m_prevCurrentPane(0),
Chris@45 3240 m_added(false)
Chris@45 3241 {
Chris@45 3242 }
Chris@45 3243
Chris@45 3244 MainWindowBase::AddPaneCommand::~AddPaneCommand()
Chris@45 3245 {
Chris@45 3246 if (m_pane && !m_added) {
Chris@45 3247 m_mw->m_paneStack->deletePane(m_pane);
Chris@45 3248 }
Chris@45 3249 }
Chris@45 3250
Chris@45 3251 QString
Chris@45 3252 MainWindowBase::AddPaneCommand::getName() const
Chris@45 3253 {
Chris@45 3254 return tr("Add Pane");
Chris@45 3255 }
Chris@45 3256
Chris@45 3257 void
Chris@45 3258 MainWindowBase::AddPaneCommand::execute()
Chris@45 3259 {
Chris@45 3260 if (!m_pane) {
Chris@45 3261 m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane();
Chris@45 3262 m_pane = m_mw->m_paneStack->addPane();
Chris@45 3263
Chris@45 3264 connect(m_pane, SIGNAL(contextHelpChanged(const QString &)),
Chris@45 3265 m_mw, SLOT(contextHelpChanged(const QString &)));
Chris@45 3266 } else {
Chris@45 3267 m_mw->m_paneStack->showPane(m_pane);
Chris@45 3268 }
Chris@45 3269
Chris@45 3270 m_mw->m_paneStack->setCurrentPane(m_pane);
Chris@45 3271 m_added = true;
Chris@45 3272 }
Chris@45 3273
Chris@45 3274 void
Chris@45 3275 MainWindowBase::AddPaneCommand::unexecute()
Chris@45 3276 {
Chris@45 3277 m_mw->m_paneStack->hidePane(m_pane);
Chris@45 3278 m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane);
Chris@45 3279 m_added = false;
Chris@45 3280 }
Chris@45 3281
Chris@45 3282 MainWindowBase::RemovePaneCommand::RemovePaneCommand(MainWindowBase *mw, Pane *pane) :
Chris@45 3283 m_mw(mw),
Chris@45 3284 m_pane(pane),
Chris@409 3285 m_prevCurrentPane(0),
Chris@45 3286 m_added(true)
Chris@45 3287 {
Chris@45 3288 }
Chris@45 3289
Chris@45 3290 MainWindowBase::RemovePaneCommand::~RemovePaneCommand()
Chris@45 3291 {
Chris@45 3292 if (m_pane && !m_added) {
Chris@45 3293 m_mw->m_paneStack->deletePane(m_pane);
Chris@45 3294 }
Chris@45 3295 }
Chris@45 3296
Chris@45 3297 QString
Chris@45 3298 MainWindowBase::RemovePaneCommand::getName() const
Chris@45 3299 {
Chris@45 3300 return tr("Remove Pane");
Chris@45 3301 }
Chris@45 3302
Chris@45 3303 void
Chris@45 3304 MainWindowBase::RemovePaneCommand::execute()
Chris@45 3305 {
Chris@45 3306 m_prevCurrentPane = m_mw->m_paneStack->getCurrentPane();
Chris@45 3307 m_mw->m_paneStack->hidePane(m_pane);
Chris@45 3308 m_added = false;
Chris@45 3309 }
Chris@45 3310
Chris@45 3311 void
Chris@45 3312 MainWindowBase::RemovePaneCommand::unexecute()
Chris@45 3313 {
Chris@45 3314 m_mw->m_paneStack->showPane(m_pane);
Chris@45 3315 m_mw->m_paneStack->setCurrentPane(m_prevCurrentPane);
Chris@45 3316 m_added = true;
Chris@45 3317 }
Chris@45 3318
Chris@45 3319 void
Chris@45 3320 MainWindowBase::deleteCurrentPane()
Chris@45 3321 {
Chris@45 3322 CommandHistory::getInstance()->startCompoundOperation
Chris@45 3323 (tr("Delete Pane"), true);
Chris@45 3324
Chris@45 3325 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 3326 if (pane) {
Chris@45 3327 while (pane->getLayerCount() > 0) {
Chris@45 3328 Layer *layer = pane->getLayer(0);
Chris@45 3329 if (layer) {
Chris@45 3330 m_document->removeLayerFromView(pane, layer);
Chris@45 3331 } else {
Chris@45 3332 break;
Chris@45 3333 }
Chris@45 3334 }
Chris@45 3335
Chris@45 3336 RemovePaneCommand *command = new RemovePaneCommand(this, pane);
Chris@45 3337 CommandHistory::getInstance()->addCommand(command);
Chris@45 3338 }
Chris@45 3339
Chris@45 3340 CommandHistory::getInstance()->endCompoundOperation();
Chris@45 3341
Chris@45 3342 updateMenuStates();
Chris@45 3343 }
Chris@45 3344
Chris@45 3345 void
Chris@45 3346 MainWindowBase::deleteCurrentLayer()
Chris@45 3347 {
Chris@45 3348 Pane *pane = m_paneStack->getCurrentPane();
Chris@45 3349 if (pane) {
Chris@45 3350 Layer *layer = pane->getSelectedLayer();
Chris@45 3351 if (layer) {
Chris@45 3352 m_document->removeLayerFromView(pane, layer);
Chris@45 3353 }
Chris@45 3354 }
Chris@45 3355 updateMenuStates();
Chris@45 3356 }
Chris@45 3357
Chris@45 3358 void
Chris@123 3359 MainWindowBase::editCurrentLayer()
Chris@123 3360 {
Chris@123 3361 Layer *layer = 0;
Chris@123 3362 Pane *pane = m_paneStack->getCurrentPane();
Chris@123 3363 if (pane) layer = pane->getSelectedLayer();
Chris@123 3364 if (!layer) return;
Chris@123 3365
Chris@123 3366 Model *model = layer->getModel();
Chris@123 3367 if (!model) return;
Chris@123 3368
Chris@124 3369 TabularModel *tabular = dynamic_cast<TabularModel *>(model);
Chris@124 3370 if (!tabular) {
Chris@124 3371 //!!! how to prevent this function from being active if not
Chris@124 3372 //appropriate model type? or will we ultimately support
Chris@124 3373 //tabular display for all editable models?
Chris@233 3374 SVDEBUG << "NOTE: Not a tabular model" << endl;
Chris@124 3375 return;
Chris@124 3376 }
Chris@124 3377
Chris@123 3378 if (m_layerDataDialogMap.find(layer) != m_layerDataDialogMap.end()) {
Chris@126 3379 if (!m_layerDataDialogMap[layer].isNull()) {
Chris@126 3380 m_layerDataDialogMap[layer]->show();
Chris@126 3381 m_layerDataDialogMap[layer]->raise();
Chris@126 3382 return;
Chris@126 3383 }
Chris@123 3384 }
Chris@123 3385
Chris@125 3386 QString title = layer->getLayerPresentationName();
Chris@125 3387
Chris@125 3388 ModelDataTableDialog *dialog = new ModelDataTableDialog(tabular, title, this);
Chris@128 3389 dialog->setAttribute(Qt::WA_DeleteOnClose);
Chris@128 3390
Chris@128 3391 connectLayerEditDialog(dialog);
Chris@123 3392
Chris@128 3393 m_layerDataDialogMap[layer] = dialog;
Chris@128 3394 m_viewDataDialogMap[pane].insert(dialog);
Chris@128 3395
Chris@128 3396 dialog->show();
Chris@128 3397 }
Chris@128 3398
Chris@128 3399 void
Chris@128 3400 MainWindowBase::connectLayerEditDialog(ModelDataTableDialog *dialog)
Chris@128 3401 {
Chris@123 3402 connect(m_viewManager,
Chris@435 3403 SIGNAL(globalCentreFrameChanged(sv_frame_t)),
Chris@123 3404 dialog,
Chris@435 3405 SLOT(userScrolledToFrame(sv_frame_t)));
Chris@127 3406
Chris@127 3407 connect(m_viewManager,
Chris@435 3408 SIGNAL(playbackFrameChanged(sv_frame_t)),
Chris@127 3409 dialog,
Chris@435 3410 SLOT(playbackScrolledToFrame(sv_frame_t)));
Chris@127 3411
Chris@123 3412 connect(dialog,
Chris@435 3413 SIGNAL(scrollToFrame(sv_frame_t)),
Chris@123 3414 m_viewManager,
Chris@435 3415 SLOT(setGlobalCentreFrame(sv_frame_t)));
Chris@129 3416
Chris@129 3417 connect(dialog,
Chris@435 3418 SIGNAL(scrollToFrame(sv_frame_t)),
Chris@129 3419 m_viewManager,
Chris@435 3420 SLOT(setPlaybackFrame(sv_frame_t)));
Chris@128 3421 }
Chris@123 3422
Chris@123 3423 void
Chris@73 3424 MainWindowBase::previousPane()
Chris@73 3425 {
Chris@73 3426 if (!m_paneStack) return;
Chris@73 3427
Chris@73 3428 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@73 3429 if (!currentPane) return;
Chris@73 3430
Chris@73 3431 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@73 3432 if (m_paneStack->getPane(i) == currentPane) {
Chris@73 3433 if (i == 0) return;
Chris@73 3434 m_paneStack->setCurrentPane(m_paneStack->getPane(i-1));
Chris@73 3435 updateMenuStates();
Chris@73 3436 return;
Chris@73 3437 }
Chris@73 3438 }
Chris@73 3439 }
Chris@73 3440
Chris@73 3441 void
Chris@73 3442 MainWindowBase::nextPane()
Chris@73 3443 {
Chris@73 3444 if (!m_paneStack) return;
Chris@73 3445
Chris@73 3446 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@73 3447 if (!currentPane) return;
Chris@73 3448
Chris@73 3449 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@73 3450 if (m_paneStack->getPane(i) == currentPane) {
Chris@73 3451 if (i == m_paneStack->getPaneCount()-1) return;
Chris@73 3452 m_paneStack->setCurrentPane(m_paneStack->getPane(i+1));
Chris@73 3453 updateMenuStates();
Chris@73 3454 return;
Chris@73 3455 }
Chris@73 3456 }
Chris@73 3457 }
Chris@73 3458
Chris@73 3459 void
Chris@73 3460 MainWindowBase::previousLayer()
Chris@73 3461 {
Chris@73 3462 if (!m_paneStack) return;
Chris@73 3463
Chris@73 3464 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@73 3465 if (!currentPane) return;
Chris@73 3466
Chris@403 3467 int count = currentPane->getLayerCount();
Chris@403 3468 if (count == 0) return;
Chris@403 3469
Chris@73 3470 Layer *currentLayer = currentPane->getSelectedLayer();
Chris@403 3471
Chris@403 3472 if (!currentLayer) {
Chris@403 3473 // The pane itself is current
Chris@403 3474 m_paneStack->setCurrentLayer
Chris@403 3475 (currentPane, currentPane->getFixedOrderLayer(count-1));
Chris@403 3476 } else {
Chris@403 3477 for (int i = 0; i < count; ++i) {
Chris@403 3478 if (currentPane->getFixedOrderLayer(i) == currentLayer) {
Chris@403 3479 if (i == 0) {
Chris@403 3480 m_paneStack->setCurrentLayer
Chris@403 3481 (currentPane, 0); // pane
Chris@403 3482 } else {
Chris@403 3483 m_paneStack->setCurrentLayer
Chris@403 3484 (currentPane, currentPane->getFixedOrderLayer(i-1));
Chris@403 3485 }
Chris@403 3486 break;
Chris@403 3487 }
Chris@73 3488 }
Chris@73 3489 }
Chris@403 3490
Chris@403 3491 updateMenuStates();
Chris@73 3492 }
Chris@73 3493
Chris@73 3494 void
Chris@73 3495 MainWindowBase::nextLayer()
Chris@73 3496 {
Chris@73 3497 if (!m_paneStack) return;
Chris@73 3498
Chris@73 3499 Pane *currentPane = m_paneStack->getCurrentPane();
Chris@73 3500 if (!currentPane) return;
Chris@73 3501
Chris@403 3502 int count = currentPane->getLayerCount();
Chris@403 3503 if (count == 0) return;
Chris@403 3504
Chris@73 3505 Layer *currentLayer = currentPane->getSelectedLayer();
Chris@403 3506
Chris@403 3507 if (!currentLayer) {
Chris@403 3508 // The pane itself is current
Chris@403 3509 m_paneStack->setCurrentLayer
Chris@403 3510 (currentPane, currentPane->getFixedOrderLayer(0));
Chris@403 3511 } else {
Chris@403 3512 for (int i = 0; i < count; ++i) {
Chris@403 3513 if (currentPane->getFixedOrderLayer(i) == currentLayer) {
Chris@403 3514 if (i == currentPane->getLayerCount()-1) {
Chris@403 3515 m_paneStack->setCurrentLayer
Chris@403 3516 (currentPane, 0); // pane
Chris@403 3517 } else {
Chris@403 3518 m_paneStack->setCurrentLayer
Chris@403 3519 (currentPane, currentPane->getFixedOrderLayer(i+1));
Chris@403 3520 }
Chris@403 3521 break;
Chris@403 3522 }
Chris@73 3523 }
Chris@73 3524 }
Chris@403 3525
Chris@403 3526 updateMenuStates();
Chris@73 3527 }
Chris@73 3528
Chris@73 3529 void
Chris@435 3530 MainWindowBase::playbackFrameChanged(sv_frame_t frame)
Chris@45 3531 {
Chris@45 3532 if (!(m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
Chris@45 3533
Chris@187 3534 updatePositionStatusDisplays();
Chris@187 3535
Chris@45 3536 RealTime now = RealTime::frame2RealTime
Chris@45 3537 (frame, getMainModel()->getSampleRate());
Chris@45 3538
Chris@45 3539 if (now.sec == m_lastPlayStatusSec) return;
Chris@45 3540
Chris@45 3541 RealTime then = RealTime::frame2RealTime
Chris@45 3542 (m_playSource->getPlayEndFrame(), getMainModel()->getSampleRate());
Chris@45 3543
Chris@45 3544 QString nowStr;
Chris@45 3545 QString thenStr;
Chris@45 3546 QString remainingStr;
Chris@45 3547
Chris@45 3548 if (then.sec > 10) {
Chris@45 3549 nowStr = now.toSecText().c_str();
Chris@45 3550 thenStr = then.toSecText().c_str();
Chris@45 3551 remainingStr = (then - now).toSecText().c_str();
Chris@45 3552 m_lastPlayStatusSec = now.sec;
Chris@45 3553 } else {
Chris@45 3554 nowStr = now.toText(true).c_str();
Chris@45 3555 thenStr = then.toText(true).c_str();
Chris@45 3556 remainingStr = (then - now).toText(true).c_str();
Chris@45 3557 }
Chris@45 3558
Chris@45 3559 m_myStatusMessage = tr("Playing: %1 of %2 (%3 remaining)")
Chris@45 3560 .arg(nowStr).arg(thenStr).arg(remainingStr);
Chris@45 3561
Chris@378 3562 getStatusLabel()->setText(m_myStatusMessage);
Chris@45 3563 }
Chris@45 3564
Chris@45 3565 void
Chris@486 3566 MainWindowBase::recordDurationChanged(sv_frame_t frame, sv_samplerate_t rate)
Chris@486 3567 {
Chris@486 3568 RealTime duration = RealTime::frame2RealTime(frame, rate);
Chris@486 3569 QString durStr = duration.toSecText().c_str();
Chris@486 3570
Chris@486 3571 m_myStatusMessage = tr("Recording: %1").arg(durStr);
Chris@486 3572
Chris@486 3573 getStatusLabel()->setText(m_myStatusMessage);
Chris@486 3574 }
Chris@486 3575
Chris@486 3576 void
Chris@435 3577 MainWindowBase::globalCentreFrameChanged(sv_frame_t )
Chris@45 3578 {
Chris@45 3579 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
Chris@45 3580 Pane *p = 0;
Chris@45 3581 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
Chris@45 3582 if (!p->getFollowGlobalPan()) return;
Chris@45 3583 updateVisibleRangeDisplay(p);
Chris@45 3584 }
Chris@45 3585
Chris@45 3586 void
Chris@435 3587 MainWindowBase::viewCentreFrameChanged(View *v, sv_frame_t frame)
Chris@45 3588 {
Chris@233 3589 // SVDEBUG << "MainWindowBase::viewCentreFrameChanged(" << v << "," << frame << ")" << endl;
Chris@123 3590
Chris@123 3591 if (m_viewDataDialogMap.find(v) != m_viewDataDialogMap.end()) {
Chris@123 3592 for (DataDialogSet::iterator i = m_viewDataDialogMap[v].begin();
Chris@123 3593 i != m_viewDataDialogMap[v].end(); ++i) {
Chris@127 3594 (*i)->userScrolledToFrame(frame);
Chris@123 3595 }
Chris@123 3596 }
Chris@45 3597 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
Chris@45 3598 Pane *p = 0;
Chris@45 3599 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
Chris@45 3600 if (v == p) updateVisibleRangeDisplay(p);
Chris@45 3601 }
Chris@45 3602
Chris@45 3603 void
Chris@366 3604 MainWindowBase::viewZoomLevelChanged(View *v, int , bool )
Chris@45 3605 {
Chris@45 3606 if ((m_playSource && m_playSource->isPlaying()) || !getMainModel()) return;
Chris@45 3607 Pane *p = 0;
Chris@45 3608 if (!m_paneStack || !(p = m_paneStack->getCurrentPane())) return;
Chris@45 3609 if (v == p) updateVisibleRangeDisplay(p);
Chris@45 3610 }
Chris@45 3611
Chris@45 3612 void
Chris@45 3613 MainWindowBase::layerAdded(Layer *)
Chris@45 3614 {
Chris@233 3615 // SVDEBUG << "MainWindowBase::layerAdded(" << layer << ")" << endl;
Chris@45 3616 updateMenuStates();
Chris@45 3617 }
Chris@45 3618
Chris@45 3619 void
Chris@45 3620 MainWindowBase::layerRemoved(Layer *)
Chris@45 3621 {
Chris@233 3622 // SVDEBUG << "MainWindowBase::layerRemoved(" << layer << ")" << endl;
Chris@45 3623 updateMenuStates();
Chris@45 3624 }
Chris@45 3625
Chris@45 3626 void
Chris@45 3627 MainWindowBase::layerAboutToBeDeleted(Layer *layer)
Chris@45 3628 {
Chris@233 3629 // SVDEBUG << "MainWindowBase::layerAboutToBeDeleted(" << layer << ")" << endl;
Chris@123 3630
Chris@128 3631 removeLayerEditDialog(layer);
Chris@123 3632
Chris@47 3633 if (m_timeRulerLayer && (layer == m_timeRulerLayer)) {
Chris@293 3634 // cerr << "(this is the time ruler layer)" << endl;
Chris@45 3635 m_timeRulerLayer = 0;
Chris@45 3636 }
Chris@45 3637 }
Chris@45 3638
Chris@45 3639 void
Chris@45 3640 MainWindowBase::layerInAView(Layer *layer, bool inAView)
Chris@45 3641 {
Chris@233 3642 // SVDEBUG << "MainWindowBase::layerInAView(" << layer << "," << inAView << ")" << endl;
Chris@128 3643
Chris@128 3644 if (!inAView) removeLayerEditDialog(layer);
Chris@45 3645
Chris@45 3646 // Check whether we need to add or remove model from play source
Chris@45 3647 Model *model = layer->getModel();
Chris@45 3648 if (model) {
Chris@45 3649 if (inAView) {
Chris@45 3650 m_playSource->addModel(model);
Chris@45 3651 } else {
Chris@45 3652 bool found = false;
Chris@45 3653 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@45 3654 Pane *pane = m_paneStack->getPane(i);
Chris@45 3655 if (!pane) continue;
Chris@45 3656 for (int j = 0; j < pane->getLayerCount(); ++j) {
Chris@45 3657 Layer *pl = pane->getLayer(j);
Chris@183 3658 if (pl &&
Chris@183 3659 !dynamic_cast<TimeRulerLayer *>(pl) &&
Chris@183 3660 (pl->getModel() == model)) {
Chris@45 3661 found = true;
Chris@45 3662 break;
Chris@45 3663 }
Chris@45 3664 }
Chris@45 3665 if (found) break;
Chris@45 3666 }
Chris@173 3667 if (!found) {
Chris@173 3668 m_playSource->removeModel(model);
Chris@173 3669 }
Chris@45 3670 }
Chris@45 3671 }
Chris@45 3672
Chris@45 3673 updateMenuStates();
Chris@45 3674 }
Chris@45 3675
Chris@45 3676 void
Chris@128 3677 MainWindowBase::removeLayerEditDialog(Layer *layer)
Chris@128 3678 {
Chris@128 3679 if (m_layerDataDialogMap.find(layer) != m_layerDataDialogMap.end()) {
Chris@128 3680
Chris@128 3681 ModelDataTableDialog *dialog = m_layerDataDialogMap[layer];
Chris@128 3682
Chris@128 3683 for (ViewDataDialogMap::iterator vi = m_viewDataDialogMap.begin();
Chris@128 3684 vi != m_viewDataDialogMap.end(); ++vi) {
Chris@128 3685 vi->second.erase(dialog);
Chris@128 3686 }
Chris@128 3687
Chris@128 3688 m_layerDataDialogMap.erase(layer);
Chris@128 3689 delete dialog;
Chris@128 3690 }
Chris@128 3691 }
Chris@128 3692
Chris@128 3693 void
Chris@45 3694 MainWindowBase::modelAdded(Model *model)
Chris@45 3695 {
Chris@233 3696 // SVDEBUG << "MainWindowBase::modelAdded(" << model << ")" << endl;
gyorgyf@273 3697 std::cerr << "\nAdding model " << model->getTypeName() << " to playsource " << std::endl;
Chris@45 3698 m_playSource->addModel(model);
Chris@45 3699 }
Chris@45 3700
Chris@45 3701 void
Chris@45 3702 MainWindowBase::mainModelChanged(WaveFileModel *model)
Chris@45 3703 {
Chris@233 3704 // SVDEBUG << "MainWindowBase::mainModelChanged(" << model << ")" << endl;
Chris@45 3705 updateDescriptionLabel();
Chris@45 3706 if (model) m_viewManager->setMainModelSampleRate(model->getSampleRate());
Chris@475 3707 if (model && !(m_playTarget || m_audioIO) &&
Chris@475 3708 (m_soundOptions & WithAudioOutput)) {
Chris@475 3709 createAudioIO();
Chris@360 3710 }
Chris@45 3711 }
Chris@45 3712
Chris@45 3713 void
Chris@45 3714 MainWindowBase::modelAboutToBeDeleted(Model *model)
Chris@45 3715 {
Chris@233 3716 // SVDEBUG << "MainWindowBase::modelAboutToBeDeleted(" << model << ")" << endl;
Chris@45 3717 if (model == m_viewManager->getPlaybackModel()) {
Chris@45 3718 m_viewManager->setPlaybackModel(0);
Chris@45 3719 }
Chris@45 3720 m_playSource->removeModel(model);
Chris@45 3721 }
Chris@45 3722
Chris@45 3723 void
Chris@55 3724 MainWindowBase::paneDeleteButtonClicked(Pane *pane)
Chris@55 3725 {
Chris@55 3726 bool found = false;
Chris@55 3727 for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
Chris@55 3728 if (m_paneStack->getPane(i) == pane) {
Chris@55 3729 found = true;
Chris@55 3730 break;
Chris@55 3731 }
Chris@55 3732 }
Chris@55 3733 if (!found) {
Chris@233 3734 SVDEBUG << "MainWindowBase::paneDeleteButtonClicked: Unknown pane "
Chris@229 3735 << pane << endl;
Chris@55 3736 return;
Chris@55 3737 }
Chris@55 3738
Chris@55 3739 CommandHistory::getInstance()->startCompoundOperation
Chris@55 3740 (tr("Delete Pane"), true);
Chris@55 3741
Chris@55 3742 while (pane->getLayerCount() > 0) {
Chris@55 3743 Layer *layer = pane->getLayer(0);
Chris@55 3744 if (layer) {
Chris@55 3745 m_document->removeLayerFromView(pane, layer);
Chris@55 3746 } else {
Chris@55 3747 break;
Chris@55 3748 }
Chris@55 3749 }
Chris@55 3750
Chris@55 3751 RemovePaneCommand *command = new RemovePaneCommand(this, pane);
Chris@55 3752 CommandHistory::getInstance()->addCommand(command);
Chris@55 3753
Chris@55 3754 CommandHistory::getInstance()->endCompoundOperation();
Chris@55 3755
Chris@55 3756 updateMenuStates();
Chris@55 3757 }
Chris@55 3758
Chris@55 3759 void
Chris@429 3760 MainWindowBase::alignmentComplete(AlignmentModel *model)
Chris@429 3761 {
Chris@429 3762 cerr << "MainWindowBase::alignmentComplete(" << model << ")" << endl;
Chris@429 3763 }
Chris@429 3764
Chris@429 3765 void
Chris@45 3766 MainWindowBase::pollOSC()
Chris@45 3767 {
Chris@45 3768 if (!m_oscQueue || m_oscQueue->isEmpty()) return;
Chris@233 3769 SVDEBUG << "MainWindowBase::pollOSC: have " << m_oscQueue->getMessagesAvailable() << " messages" << endl;
Chris@45 3770
Chris@45 3771 if (m_openingAudioFile) return;
Chris@45 3772
Chris@45 3773 OSCMessage message = m_oscQueue->readMessage();
Chris@45 3774
Chris@45 3775 if (message.getTarget() != 0) {
Chris@45 3776 return; //!!! for now -- this class is target 0, others not handled yet
Chris@45 3777 }
Chris@45 3778
Chris@45 3779 handleOSCMessage(message);
Chris@45 3780 }
Chris@45 3781
Chris@45 3782 void
Chris@45 3783 MainWindowBase::inProgressSelectionChanged()
Chris@45 3784 {
Chris@45 3785 Pane *currentPane = 0;
Chris@45 3786 if (m_paneStack) currentPane = m_paneStack->getCurrentPane();
justin@331 3787 if (currentPane) {
justin@331 3788 //cerr << "JTEST: mouse event on selection pane" << endl;
justin@331 3789 updateVisibleRangeDisplay(currentPane);
justin@331 3790 }
Chris@45 3791 }
Chris@45 3792
Chris@45 3793 void
Chris@45 3794 MainWindowBase::contextHelpChanged(const QString &s)
Chris@45 3795 {
Chris@378 3796 QLabel *lab = getStatusLabel();
Chris@375 3797
Chris@45 3798 if (s == "" && m_myStatusMessage != "") {
Chris@378 3799 if (lab->text() != m_myStatusMessage) {
Chris@378 3800 lab->setText(m_myStatusMessage);
Chris@375 3801 }
Chris@45 3802 return;
Chris@45 3803 }
Chris@375 3804
Chris@378 3805 lab->setText(s);
Chris@45 3806 }
Chris@45 3807
Chris@45 3808 void
Chris@45 3809 MainWindowBase::openHelpUrl(QString url)
Chris@45 3810 {
Chris@45 3811 // This method mostly lifted from Qt Assistant source code
Chris@45 3812
Chris@45 3813 QProcess *process = new QProcess(this);
Chris@45 3814 connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater()));
Chris@45 3815
Chris@45 3816 QStringList args;
Chris@45 3817
Chris@45 3818 #ifdef Q_OS_MAC
Chris@45 3819 args.append(url);
Chris@45 3820 process->start("open", args);
Chris@45 3821 #else
Chris@45 3822 #ifdef Q_OS_WIN32
Chris@358 3823 QString pf(getenv("ProgramFiles"));
Chris@358 3824 QString command = pf + QString("\\Internet Explorer\\IEXPLORE.EXE");
Chris@358 3825
Chris@358 3826 args.append(url);
Chris@358 3827 process->start(command, args);
Chris@45 3828 #else
Chris@45 3829 if (!qgetenv("KDE_FULL_SESSION").isEmpty()) {
Chris@45 3830 args.append("exec");
Chris@45 3831 args.append(url);
Chris@45 3832 process->start("kfmclient", args);
Chris@45 3833 } else if (!qgetenv("BROWSER").isEmpty()) {
Chris@45 3834 args.append(url);
Chris@45 3835 process->start(qgetenv("BROWSER"), args);
Chris@45 3836 } else {
Chris@45 3837 args.append(url);
Chris@45 3838 process->start("firefox", args);
Chris@45 3839 }
Chris@45 3840 #endif
Chris@45 3841 #endif
Chris@45 3842 }
Chris@45 3843
Chris@483 3844 void
Chris@483 3845 MainWindowBase::openLocalFolder(QString path)
Chris@483 3846 {
Chris@483 3847 QDir d(path);
Chris@483 3848 if (d.exists()) {
Chris@483 3849 QStringList args;
Chris@483 3850 QString path = d.canonicalPath();
Chris@483 3851 #if defined Q_OS_WIN32
Chris@483 3852 // Although the Win32 API is quite happy to have
Chris@483 3853 // forward slashes as directory separators, Windows
Chris@483 3854 // Explorer is not
Chris@483 3855 path = path.replace('/', '\\');
Chris@483 3856 args << path;
Chris@483 3857 QProcess::execute("c:/windows/explorer.exe", args);
Chris@483 3858 #else
Chris@483 3859 args << path;
Chris@483 3860 QProcess::execute(
Chris@483 3861 #if defined Q_OS_MAC
Chris@483 3862 "/usr/bin/open",
Chris@483 3863 #else
Chris@483 3864 "/usr/bin/xdg-open",
Chris@483 3865 #endif
Chris@483 3866 args);
Chris@483 3867 #endif
Chris@483 3868 }
Chris@483 3869 }
Chris@483 3870