annotate framework/MainWindowBase.cpp @ 451:dc1a360f2b69

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