annotate framework/MainWindowBase.cpp @ 496:4f1d280903ad tony-2.0-integration

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