annotate framework/MainWindowBase.cpp @ 403:eb84b06301da

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