changeset 2306:a1c14880404b

Merge from branch by-id
author Chris Cannam
date Wed, 17 Jul 2019 14:28:24 +0100
parents a54082a29106 (current diff) 332df8c4562b (diff)
children a8dbf75ddac7
files main/MainWindow.cpp main/MainWindow.h main/main.cpp repoint-lock.json repoint-project.json
diffstat 6 files changed, 231 insertions(+), 178 deletions(-) [+]
line wrap: on
line diff
--- a/main/MainWindow.cpp	Fri Jun 21 13:30:17 2019 +0100
+++ b/main/MainWindow.cpp	Wed Jul 17 14:28:24 2019 +0100
@@ -76,7 +76,6 @@
 #include "plugin/PluginScan.h"
 #include "transform/TransformFactory.h"
 #include "transform/ModelTransformerFactory.h"
-#include "base/PlayParameterRepository.h"
 #include "base/XmlExportable.h"
 #include "widgets/CommandHistory.h"
 #include "base/Profiler.h"
@@ -1294,11 +1293,11 @@
     int backgroundTypeCount = int(sizeof(backgroundTypes) /
                                   sizeof(backgroundTypes[0]));
 
-    std::vector<Model *> models;
+    std::vector<ModelId> models;
     if (m_document) models = m_document->getTransformInputModels();
     bool plural = (models.size() > 1);
     if (models.empty()) {
-        models.push_back(getMainModel()); // probably 0
+        models.push_back(getMainModelId()); // probably None at this point
     }
 
     for (int i = 0; i < backgroundTypeCount; ++i) {
@@ -1382,19 +1381,21 @@
             default: break;
             }
 
-            std::vector<Model *> candidateModels = models;
+            std::vector<ModelId> candidateModels = models;
+            if (candidateModels.empty()) {
+                throw std::logic_error("candidateModels should not be empty");
+            }
             
-            for (std::vector<Model *>::iterator mi =
-                     candidateModels.begin();
-                 mi != candidateModels.end(); ++mi) {
+            for (auto modelId: candidateModels) {
+
+                auto model = ModelById::get(modelId);
                 
-                Model *model = *mi;
-
                 int channels = 0;
                 if (model) {
-                    DenseTimeValueModel *dtvm =
-                        dynamic_cast<DenseTimeValueModel *>(model);
-                    if (dtvm) channels = dtvm->getChannelCount();
+                    if (auto dtvm = ModelById::getAs<DenseTimeValueModel>
+                        (modelId)) {
+                        channels = dtvm->getChannelCount();
+                    }
                 }
                 if (channels < 1 && getMainModel()) {
                     channels = getMainModel()->getChannelCount();
@@ -1419,14 +1420,14 @@
                             connect(this, SIGNAL(canAddPane(bool)),
                                     action, SLOT(setEnabled(bool)));
                             m_paneActions.push_back
-                                ({ action, LayerConfiguration(type, model) });
+                                ({ action, LayerConfiguration(type, modelId) });
                         } else {
                             connect(action, SIGNAL(triggered()),
                                     this, SLOT(addLayer()));
                             connect(this, SIGNAL(canAddLayer(bool)),
                                     action, SLOT(setEnabled(bool)));
                             m_layerActions.push_back
-                                ({ action, LayerConfiguration(type, model) });
+                                ({ action, LayerConfiguration(type, modelId) });
                         }
                         if (shortcutText != "") {
                             m_keyReference->registerShortcut(action);
@@ -1461,7 +1462,7 @@
 
                         if (isDefault) {
                             action = new QAction(icon, actionText, this);
-                            if (!model || model == getMainModel()) {
+                            if (!model || modelId == getMainModelId()) {
                                 // Default for the shortcut is to
                                 // attach to an action that uses the
                                 // main model as input. But this may
@@ -1482,21 +1483,21 @@
                             connect(this, SIGNAL(canAddPane(bool)),
                                     action, SLOT(setEnabled(bool)));
                             m_paneActions.push_back
-                                ({ action, LayerConfiguration(type, model, c - 1) });
+                                ({ action, LayerConfiguration(type, modelId, c - 1) });
                         } else {
                             connect(action, SIGNAL(triggered()),
                                     this, SLOT(addLayer()));
                             connect(this, SIGNAL(canAddLayer(bool)),
                                     action, SLOT(setEnabled(bool)));
                             m_layerActions.push_back
-                                ({ action, LayerConfiguration(type, model, c - 1) });
+                                ({ action, LayerConfiguration(type, modelId, c - 1) });
                         }
 
                         submenu->addAction(action);
                     }
 
                     if (isDefault && menuType == layerMenuType &&
-                        mi == candidateModels.begin()) {
+                        modelId == *candidateModels.begin()) {
                         // only add for one model, one channel, one menu on
                         // right button -- the action itself will discover
                         // which model is the correct one (based on pane)
@@ -1507,7 +1508,7 @@
                         connect(this, SIGNAL(canAddLayer(bool)),
                                 action, SLOT(setEnabled(bool)));
                         m_layerActions.push_back
-                            ({ action, LayerConfiguration(type, nullptr, 0) });
+                            ({ action, LayerConfiguration(type, ModelId(), 0) });
                         m_rightButtonLayerMenu->addAction(action);
                     }
                 }
@@ -1620,7 +1621,7 @@
 }
 
 void
-MainWindow::updateLayerShortcutsFor(Model *model)
+MainWindow::updateLayerShortcutsFor(ModelId modelId)
 {
     // Called when e.g. the current pane has changed, to ensure the
     // various layer shortcuts select an action whose input model is
@@ -1629,9 +1630,11 @@
     set<LayerFactory::LayerType> seen;
     
     for (auto &a : m_paneActions) {
-        if (!a.second.sourceModel) continue; // empty pane/layer shortcut
+        if (a.second.sourceModel.isNone()) {
+            continue; // empty pane/layer shortcut
+        }
         auto type = a.second.layer;
-        if (a.second.sourceModel == model && seen.find(type) == seen.end()) {
+        if (a.second.sourceModel == modelId && seen.find(type) == seen.end()) {
             a.first->setShortcut(shortcutFor(type, true));
             seen.insert(type);
         } else {
@@ -1642,9 +1645,11 @@
     seen.clear();
     
     for (auto &a : m_layerActions) {
-        if (!a.second.sourceModel) continue; // empty pane/layer shortcut
+        if (a.second.sourceModel.isNone()) {
+            continue; // empty pane/layer shortcut
+        }
         auto type = a.second.layer;
-        if (a.second.sourceModel == model && seen.find(type) == seen.end()) {
+        if (a.second.sourceModel == modelId && seen.find(type) == seen.end()) {
             a.first->setShortcut(shortcutFor(type, false));
             seen.insert(type);
         } else {
@@ -2690,11 +2695,12 @@
 void
 MainWindow::exportAudio(bool asData)
 {
-    if (!getMainModel()) return;
-
-    RangeSummarisableTimeValueModel *model = getMainModel();
-    std::set<RangeSummarisableTimeValueModel *> otherModels;
-    RangeSummarisableTimeValueModel *current = model;
+    auto modelId = getMainModelId();
+    if (modelId.isNone()) return;
+    
+    std::set<ModelId> otherModelIds;
+    ModelId current = modelId;
+    
     if (m_paneStack) {
         for (int i = 0; i < m_paneStack->getPaneCount(); ++i) {
             Pane *pane = m_paneStack->getPane(i);
@@ -2703,37 +2709,39 @@
                 Layer *layer = pane->getLayer(j);
                 if (!layer) continue;
                 cerr << "layer = " << layer->objectName() << endl;
-                Model *m = layer->getModel();
-                RangeSummarisableTimeValueModel *wm = 
-                    dynamic_cast<RangeSummarisableTimeValueModel *>(m);
-                if (wm) {
-                    cerr << "found: " << wm->objectName() << endl;
-                    otherModels.insert(wm);
+                ModelId m = layer->getModel();
+                if (ModelById::isa<RangeSummarisableTimeValueModel>(m)) {
+                    otherModelIds.insert(m);
                     if (pane == m_paneStack->getCurrentPane()) {
-                        current = wm;
+                        current = m;
                     }
                 }
             }
         }
     }
-    if (!otherModels.empty()) {
-        std::map<QString, RangeSummarisableTimeValueModel *> m;
-        m[tr("1. %2").arg(model->objectName())] = model;
+    if (!otherModelIds.empty()) {
+        std::map<QString, ModelId> m;
+        QString unnamed = tr("<unnamed>");
+        QString oname = unnamed;
+        if (auto mp = ModelById::get(modelId)) {
+            oname = mp->objectName();
+        }
+        m[tr("1. %2").arg(oname)] = modelId;
         int n = 2;
         int c = 0;
-        for (std::set<RangeSummarisableTimeValueModel *>::const_iterator i
-                 = otherModels.begin();
-             i != otherModels.end(); ++i) {
-            if (*i == model) continue;
-            m[tr("%1. %2").arg(n).arg((*i)->objectName())] = *i;
+        for (auto otherModelId: otherModelIds) {
+            if (otherModelId == modelId) continue;
+            oname = unnamed;
+            if (auto mp = ModelById::get(otherModelId)) {
+                oname = mp->objectName();
+            }
+            m[tr("%1. %2").arg(n).arg(oname)] = otherModelId;
             ++n;
-            if (*i == current) c = n-1;
+            if (otherModelId == current) c = n-1;
         }
         QStringList items;
-        for (std::map<QString, RangeSummarisableTimeValueModel *>
-                 ::const_iterator i = m.begin();
-             i != m.end(); ++i) {
-            items << i->first;
+        for (auto i: m) {
+            items << i.first;
         }
         if (items.size() > 1) {
             bool ok = false;
@@ -2743,14 +2751,20 @@
                  items, c, false, &ok);
             if (!ok || item.isEmpty()) return;
             if (m.find(item) == m.end()) {
-                cerr << "WARNING: Model " << item
-                     << " not found in list!" << endl;
+                SVCERR << "WARNING: Model " << item
+                       << " not found in list!" << endl;
             } else {
-                model = m[item];
+                modelId = m[item];
             }
         }
     }
 
+    auto model = ModelById::getAs<DenseTimeValueModel>(modelId);
+    if (!model) {
+        SVCERR << "ERROR: Chosen model is not a DenseTimeValueModel!" << endl;
+        return;
+    }
+    
     QString path;
     if (asData) {
         path = getSaveFileName(FileFinder::CSVFile);
@@ -2835,7 +2849,7 @@
                                         model->getSampleRate(),
                                         model->getChannelCount(),
                                         WavFileWriter::WriteToTemporary);
-                subwriter.writeModel(model, &subms);
+                subwriter.writeModel(model.get(), &subms);
                 ok = subwriter.isOK();
 
                 if (!ok) {
@@ -2856,7 +2870,7 @@
                 this,
                 Qt::ApplicationModal
             };
-            CSVFileWriter writer(path, model, &dialog,
+            CSVFileWriter writer(path, model.get(), &dialog,
                                  ((QFileInfo(path).suffix() == "csv") ?
                                   "," : "\t"));
             if (selectionToWrite) {
@@ -2871,7 +2885,7 @@
                                  model->getSampleRate(),
                                  model->getChannelCount(),
                                  WavFileWriter::WriteToTemporary);
-            writer.writeModel(model, selectionToWrite);
+            writer.writeModel(model.get(), selectionToWrite);
             ok = writer.isOK();
             error = writer.getError();
         }
@@ -2936,8 +2950,10 @@
 
     } else {
 
+        auto modelId = ModelById::add(std::shared_ptr<Model>(model));
+        
         status = addOpenedAudioModel(path,
-                                     model,
+                                     modelId,
                                      CreateAdditionalModel,
                                      getDefaultSessionTemplate(),
                                      false);
@@ -2997,11 +3013,11 @@
     Layer *layer = pane->getSelectedLayer();
     if (!layer) return;
 
-    Model *model = layer->getModel();
-    if (!model) return;
+    ModelId modelId = layer->getModel();
+    if (modelId.isNone()) return;
 
     FileFinder::FileType type = FileFinder::LayerFileNoMidi;
-    if (dynamic_cast<NoteModel *>(model)) type = FileFinder::LayerFile;
+    if (ModelById::isa<NoteModel>(modelId)) type = FileFinder::LayerFile;
     QString path = getSaveFileName(type);
 
     if (path == "") return;
@@ -3385,7 +3401,7 @@
     }
 
     QString mainModelLocation;
-    WaveFileModel *mm = getMainModel();
+    auto mm = getMainModel();
     if (mm) mainModelLocation = mm->getLocation();
     if (mainModelLocation != "") {
         openAudio(mainModelLocation, ReplaceSession, n);
@@ -3457,6 +3473,10 @@
 MainWindow::paneAdded(Pane *pane)
 {
     if (m_overview) m_overview->registerView(pane);
+    if (pane) {
+        connect(pane, SIGNAL(cancelButtonPressed(Layer *)),
+                this, SLOT(paneCancelButtonPressed(Layer *)));
+    }
 }    
 
 void
@@ -3472,6 +3492,49 @@
 }    
 
 void
+MainWindow::paneCancelButtonPressed(Layer *layer)
+{
+    Pane *pane = qobject_cast<Pane *>(sender());
+    bool found = false;
+    if (pane && layer) {
+        for (int i = 0; i < pane->getLayerCount(); ++i) {
+            if (pane->getLayer(i) == layer) {
+                found = true;
+                break;
+            }
+        }
+    }
+    if (!found) {
+        SVDEBUG << "MainWindow::paneCancelButtonPressed: Unknown layer in pane"
+                << endl;
+        return;
+    }
+
+    SVDEBUG << "MainWindow::paneCancelButtonPressed: Layer " << layer << endl;
+
+    // We need to ensure that the transform that is populating this
+    // layer's model is stopped - that is the main reason to use
+    // Cancel after all. It would also be a good idea to remove the
+    // incomplete layer from both the view and the undo/redo stack.
+
+    // Deleting the target model will ensure that the transform gets
+    // stopped, but removing the layer from the view is not enough to
+    // delete the model, because a reference to the layer remains on
+    // the undo/redo stack. If we also replace the model id with None
+    // in the layer, that does the trick.
+    
+    m_document->setModel(layer, {});
+    m_document->removeLayerFromView(pane, layer);
+
+    // We still have a layer with no model on the undo/redo stack,
+    // which is a pity. I'm not sure we can easily remove it, since
+    // other commands may have been pushed on the stack since, so
+    // let's just leave that for now.
+    
+    updateMenuStates();
+}
+
+void
 MainWindow::paneDropAccepted(Pane *pane, QStringList uriList)
 {
     if (pane) m_paneStack->setCurrentPane(pane);
@@ -3835,32 +3898,31 @@
 
     Layer *newLayer = m_document->createLayer(configuration.layer);
 
-    Model *suggestedModel = configuration.sourceModel;
-    Model *model = nullptr;
-
-    if (suggestedModel) {
+    ModelId suggestedModelId = configuration.sourceModel;
+    ModelId modelId;
+
+    if (!suggestedModelId.isNone()) {
 
         // check its validity
-        std::vector<Model *> inputModels = m_document->getTransformInputModels();
-        for (size_t j = 0; j < inputModels.size(); ++j) {
-            if (inputModels[j] == suggestedModel) {
-                model = suggestedModel;
-                break;
+        std::vector<ModelId> inputModels = m_document->getTransformInputModels();
+        for (auto im: inputModels) {
+            if (im == suggestedModelId) {
+                modelId = suggestedModelId;
             }
         }
 
-        if (!model) {
-            cerr << "WARNING: Model " << (void *)suggestedModel
-                      << " appears in pane action map, but is not reported "
-                      << "by document as a valid transform source" << endl;
+        if (modelId.isNone()) {
+            cerr << "WARNING: Model " << modelId
+                 << " appears in pane action map, but is not reported "
+                 << "by document as a valid transform source" << endl;
         }
     }
 
-    if (!model) {
-        model = m_document->getMainModel();
+    if (modelId.isNone()) {
+        modelId = m_document->getMainModel();
     }
 
-    m_document->setModel(newLayer, model);
+    m_document->setModel(newLayer, modelId);
 
     m_document->setChannel(newLayer, configuration.channel);
     m_document->addLayerToView(pane, newLayer);
@@ -3974,11 +4036,9 @@
 
         } else {
 
-            Model *model = i->second.sourceModel;
-
-            cerr << "model = "<< model << endl;
-
-            if (!model) {
+            ModelId modelId = i->second.sourceModel;
+
+            if (modelId.isNone()) {
                 if (type == LayerFactory::TimeRuler) {
                     newLayer = m_document->createMainModelLayer(type);
                 } else {
@@ -3987,27 +4047,25 @@
                     // the current pane -- this is the case for
                     // right-button menu layer additions
                     Pane::ModelSet ms = pane->getModels();
-                    foreach (Model *m, ms) {
-                        RangeSummarisableTimeValueModel *r =
-                            dynamic_cast<RangeSummarisableTimeValueModel *>(m);
-                        if (r) model = m;
+                    for (ModelId m: ms) {
+                        if (ModelById::isa<RangeSummarisableTimeValueModel>(m)) {
+                            modelId = m;
+                        }
                     }
-                    if (!model) model = getMainModel();
+                    if (modelId.isNone()) {
+                        modelId = getMainModelId();
+                    }
                 }
             }
 
-            if (model) {
+            if (!modelId.isNone()) {
                 newLayer = m_document->createLayer(type);
-                if (m_document->isKnownModel(model)) {
+                if (m_document->isKnownModel(modelId)) {
                     m_document->setChannel(newLayer, i->second.channel);
-                    m_document->setModel(newLayer, model);
+                    m_document->setModel(newLayer, modelId);
                 } else {
-                    cerr << "WARNING: MainWindow::addLayer: unknown model "
-                              << model
-                              << " (\""
-                              << model->objectName()
-                              << "\") in layer action map"
-                              << endl;
+                    SVCERR << "WARNING: MainWindow::addLayer: unknown model "
+                           << modelId << " in layer action map" << endl;
                 }
             }
         }
@@ -4064,10 +4122,10 @@
         return;
     }
 
-    std::vector<Model *> candidateInputModels =
+    std::vector<ModelId> candidateInputModels =
         m_document->getTransformInputModels();
 
-    Model *defaultInputModel = nullptr;
+    ModelId defaultInputModelId;
 
     for (int j = 0; j < pane->getLayerCount(); ++j) {
 
@@ -4076,37 +4134,37 @@
 
         if (LayerFactory::getInstance()->getLayerType(layer) !=
             LayerFactory::Waveform &&
-            !layer->isLayerOpaque()) continue;
-
-        Model *model = layer->getModel();
-        if (!model) continue;
-
-        for (size_t k = 0; k < candidateInputModels.size(); ++k) {
-            if (candidateInputModels[k] == model) {
-                defaultInputModel = model;
+            !layer->isLayerOpaque()) {
+            continue;
+        }
+
+        ModelId modelId = layer->getModel();
+        if (modelId.isNone()) continue;
+
+        for (ModelId candidateId: candidateInputModels) {
+            if (candidateId == modelId) {
+                defaultInputModelId = modelId;
                 break;
             }
         }
 
-        if (defaultInputModel) break;
+        if (!defaultInputModelId.isNone()) break;
     }
 
-    AggregateWaveModel *aggregate = nullptr;
+    ModelId aggregate;
     
     if (candidateInputModels.size() > 1) {
         // Add an aggregate model as another option
         AggregateWaveModel::ChannelSpecList sl;
-        foreach (Model *m, candidateInputModels) {
-            RangeSummarisableTimeValueModel *r =
-                qobject_cast<RangeSummarisableTimeValueModel *>(m);
-            if (r) {
-                sl.push_back(AggregateWaveModel::ModelChannelSpec(r, -1));
+        for (ModelId mid: candidateInputModels) {
+            if (ModelById::isa<RangeSummarisableTimeValueModel>(mid)) {
+                sl.push_back(AggregateWaveModel::ModelChannelSpec(mid, -1));
             }
         }
         if (!sl.empty()) {
-            aggregate = new AggregateWaveModel(sl);
+            auto aggregate = std::make_shared<AggregateWaveModel>(sl);
             aggregate->setObjectName(tr("Multiplex all of the above"));
-            candidateInputModels.push_back(aggregate);
+            candidateInputModels.push_back(ModelById::add(aggregate));
         }
     }
     
@@ -4122,23 +4180,24 @@
         getConfigurationForTransform
         (transform,
          candidateInputModels,
-         defaultInputModel,
+         defaultInputModelId,
          m_playSource,
          startFrame,
          duration,
          &configurator);
 
-    if (aggregate) {
+    if (!aggregate.isNone()) {
         if (input.getModel() == aggregate) {
-            aggregate->setObjectName(tr("Multiplexed audio"));
-            m_document->addAggregateModel(aggregate);
+            if (auto aggregateModel = ModelById::get(aggregate)) {
+                aggregateModel->setObjectName(tr("Multiplexed audio"));
+            }
+            m_document->addNonDerivedModel(aggregate);
         } else {
-            aggregate->aboutToDelete();
-            delete aggregate;
+            ModelById::release(aggregate);
         }
     }
     
-    if (!input.getModel()) return;
+    if (input.getModel().isNone()) return;
 
 //    SVDEBUG << "MainWindow::addLayer: Input model is " << input.getModel() << " \"" << input.getModel()->objectName() << "\"" << endl << "transform:" << endl << transform.toXmlString() << endl;
 
@@ -4328,7 +4387,7 @@
         if (layer &&
             LayerFactory::getInstance()->getLayerType(layer) ==
             LayerFactory::Waveform &&
-            layer->getModel() == getMainModel()) {
+            layer->getModel() == getMainModelId()) {
             containsMainModel = true;
             break;
         }
@@ -4339,15 +4398,14 @@
     for (int i = pane->getLayerCount(); i > 0; ) {
         --i;
         Layer *layer = pane->getLayer(i);
-        RangeSummarisableTimeValueModel *tvm = 
-            qobject_cast<RangeSummarisableTimeValueModel *>(layer->getModel());
-        if (tvm) {
+        ModelId modelId = layer->getModel();
+        if (ModelById::isa<RangeSummarisableTimeValueModel>(modelId)) {
             auto type = LayerFactory::getInstance()->getLayerType(layer);
             if (type != LayerFactory::TimeRuler) {
-                updateLayerShortcutsFor(tvm);
+                updateLayerShortcutsFor(modelId);
             }
             if (type == LayerFactory::Waveform) {
-                m_panLayer->setModel(tvm);
+                m_panLayer->setModel(modelId);
                 panLayerSet = true;
                 break;
             }
@@ -4355,14 +4413,20 @@
     }
 
     if (containsMainModel && !panLayerSet) {
-        m_panLayer->setModel(getMainModel());
+        m_panLayer->setModel(getMainModelId());
     }
 }
 
 void
 MainWindow::updateVisibleRangeDisplay(Pane *p) const
 {
-    if (!getMainModel() || !p) {
+    sv_samplerate_t sampleRate = 0;
+    if (auto mm = getMainModel()) {
+        sampleRate = mm->getSampleRate();
+    } else {
+        return;
+    }
+    if (!p) {
         return;
     }
 
@@ -4386,12 +4450,8 @@
         endFrame = p->getLastVisibleFrame();
     }
 
-    RealTime start = RealTime::frame2RealTime
-        (startFrame, getMainModel()->getSampleRate());
-
-    RealTime end = RealTime::frame2RealTime
-        (endFrame, getMainModel()->getSampleRate());
-
+    RealTime start = RealTime::frame2RealTime(startFrame, sampleRate);
+    RealTime end = RealTime::frame2RealTime(endFrame, sampleRate);
     RealTime duration = end - start;
 
     QString startStr, endStr, durationStr;
@@ -4584,13 +4644,11 @@
 
             if (!m_playSource || !m_playSource->isPlaying()) continue;
 
-            Model *model = static_cast<Layer *>(currentTimeValueLayer)->getModel();
-            SparseTimeValueModel *tvm =
-                dynamic_cast<SparseTimeValueModel *>(model);
-            if (tvm) {
+            ModelId modelId = currentTimeValueLayer->getModel();
+            if (ModelById::isa<SparseTimeValueModel>(modelId)) {
                 Event point(frame, float(ev.getPitch() % 12), "");
                 AddEventCommand *command = new AddEventCommand
-                    (tvm, point, tr("Add Point"));
+                    (modelId.untyped, point, tr("Add Point"));
                 CommandHistory::getInstance()->addCommand(command);
             }
 
@@ -4637,20 +4695,20 @@
 }
 
 void
-MainWindow::modelAdded(Model *model)
+MainWindow::modelAdded(ModelId modelId)
 {
-    MainWindowBase::modelAdded(model);
-    if (dynamic_cast<DenseTimeValueModel *>(model)) {
+    MainWindowBase::modelAdded(modelId);
+    if (ModelById::isa<DenseTimeValueModel>(modelId)) {
         setupPaneAndLayerMenus();
     }
 }
 
 void
-MainWindow::mainModelChanged(WaveFileModel *model)
+MainWindow::mainModelChanged(ModelId modelId)
 {
-    m_panLayer->setModel(model);
-
-    MainWindowBase::mainModelChanged(model);
+    m_panLayer->setModel(modelId);
+
+    MainWindowBase::mainModelChanged(modelId);
 
     if (m_playTarget || m_audioIO) {
         connect(m_mainLevelPan, SIGNAL(levelChanged(float)),
@@ -4682,19 +4740,6 @@
 }
 
 void
-MainWindow::modelAboutToBeDeleted(Model *model)
-{
-    if (model == m_panLayer->getModel()) {
-        if (model == getMainModel()) {
-            m_panLayer->setModel(nullptr);
-        } else {
-            m_panLayer->setModel(getMainModel());
-        }
-    }
-    MainWindowBase::modelAboutToBeDeleted(model);
-}
-
-void
 MainWindow::setInstantsNumbering()
 {
     QAction *a = dynamic_cast<QAction *>(sender());
--- a/main/MainWindow.h	Fri Jun 21 13:30:17 2019 +0100
+++ b/main/MainWindow.h	Wed Jul 17 14:28:24 2019 +0100
@@ -118,6 +118,8 @@
     void paneDropAccepted(Pane *, QStringList) override;
     void paneDropAccepted(Pane *, QString) override;
 
+    void paneCancelButtonPressed(Layer *);
+
     virtual void setupRecentFilesMenu();
     virtual void setupRecentTransformsMenu();
     virtual void setupTemplatesMenu();
@@ -137,11 +139,10 @@
     void layerRemoved(Layer *) override;
     void layerInAView(Layer *, bool) override;
 
-    void mainModelChanged(WaveFileModel *) override;
+    void mainModelChanged(ModelId) override;
     virtual void mainModelGainChanged(float);
     virtual void mainModelPanChanged(float);
-    void modelAdded(Model *) override;
-    void modelAboutToBeDeleted(Model *) override;
+    void modelAdded(ModelId) override;
 
     virtual void showLayerTree();
     virtual void showActivityLog();
@@ -237,16 +238,16 @@
     struct LayerConfiguration {
         LayerConfiguration(LayerFactory::LayerType _layer
                                                = LayerFactory::TimeRuler,
-                           Model *_source = 0,
+                           ModelId _source = ModelId(),
                            int _channel = -1) :
             layer(_layer), sourceModel(_source), channel(_channel) { }
         LayerFactory::LayerType layer;
-        Model *sourceModel;
+        ModelId sourceModel;
         int channel;
     };
 
     QString shortcutFor(LayerFactory::LayerType, bool isPaneMenu);
-    void updateLayerShortcutsFor(Model *);
+    void updateLayerShortcutsFor(ModelId);
 
     // Map from menu action to the resulting layer configurations
     // etc. These all used to be std::maps, but we sometimes want to
--- a/main/OSCHandler.cpp	Fri Jun 21 13:30:17 2019 +0100
+++ b/main/OSCHandler.cpp	Wed Jul 17 14:28:24 2019 +0100
@@ -110,9 +110,10 @@
                                          WavFileWriter::WriteToTemporary);
                     MultiSelection ms = m_viewManager->getSelection();
                     if (!ms.getSelections().empty()) {
-                        writer.writeModel(getMainModel(), &ms);
+                        //!!! todo: update WavFileWriter!
+                        writer.writeModel(getMainModel().get(), &ms);
                     } else {
-                        writer.writeModel(getMainModel());
+                        writer.writeModel(getMainModel().get());
                     }
                 }
             }
@@ -352,7 +353,7 @@
                 } else {
 
                     LayerConfiguration configuration(type,
-                                                     getMainModel(),
+                                                     getMainModelId(),
                                                      channel);
                     
                     addPane(configuration,
@@ -611,7 +612,7 @@
                 getDefaultTransformFor(transformId);
             
             Layer *newLayer = m_document->createDerivedLayer
-                (transform, getMainModel());
+                (transform, getMainModelId());
 
             if (newLayer) {
                 m_document->addLayerToView(pane, newLayer);
--- a/main/SVSplash.cpp	Fri Jun 21 13:30:17 2019 +0100
+++ b/main/SVSplash.cpp	Wed Jul 17 14:28:24 2019 +0100
@@ -18,7 +18,7 @@
 
 #include <QPainter>
 #include <QApplication>
-#include <QDesktopWidget>
+#include <QScreen>
 #include <QSvgRenderer>
 
 #include <cmath>
@@ -33,7 +33,8 @@
     QPixmap *p1 = new QPixmap(":icons/scalable/sv-splash.png");
 
     int w = p1->width(), h = p1->height();
-    QRect desk = QApplication::desktop()->availableGeometry();
+    QScreen *screen = QApplication::primaryScreen();
+    QRect desk = screen->availableGeometry();
 
     double dpratio = devicePixelRatio();
     double widthMultiple = double(desk.width()) / double(w);
@@ -89,6 +90,11 @@
 void
 SVSplash::drawContents(QPainter *painter)
 {
+    // Qt 5.13 deprecates QFontMetrics::width(), but its suggested
+    // replacement (horizontalAdvance) was only added in Qt 5.11
+    // which is too new for us
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
     painter->drawPixmap(rect(), *m_pixmap, m_pixmap->rect());
     QString text = QString("v%1").arg(SV_VERSION);
     painter->setPen(Qt::black);
--- a/main/main.cpp	Fri Jun 21 13:30:17 2019 +0100
+++ b/main/main.cpp	Wed Jul 17 14:28:24 2019 +0100
@@ -31,7 +31,7 @@
 
 #include <QMetaType>
 #include <QApplication>
-#include <QDesktopWidget>
+#include <QScreen>
 #include <QMessageBox>
 #include <QTranslator>
 #include <QLocale>
@@ -404,8 +404,8 @@
                          splash, SLOT(finishSplash(QWidget *)));
     }
 
-    QDesktopWidget *desktop = QApplication::desktop();
-    QRect available = desktop->availableGeometry();
+    QScreen *screen = QApplication::primaryScreen();
+    QRect available = screen->availableGeometry();
 
     int width = (available.width() * 2) / 3;
     int height = available.height() / 2;
--- a/repoint-lock.json	Fri Jun 21 13:30:17 2019 +0100
+++ b/repoint-lock.json	Wed Jul 17 14:28:24 2019 +0100
@@ -4,13 +4,13 @@
       "pin": "62987b6d6a3b"
     },
     "svcore": {
-      "pin": "8efce64dd85e"
+      "pin": "85b9b466a59f"
     },
     "svgui": {
-      "pin": "de41a11cabc2"
+      "pin": "ac0a8addabcf"
     },
     "svapp": {
-      "pin": "a82b9d410393"
+      "pin": "155008f1bf10"
     },
     "checker": {
       "pin": "c8c17e51aab0"