diff main/MainWindow.cpp @ 2300:eb7f4579e5cc by-id

Updates throughout for ModelById logic
author Chris Cannam
date Thu, 04 Jul 2019 14:32:08 +0100
parents f78177863e26
children 23fea10161a6
line wrap: on
line diff
--- a/main/MainWindow.cpp	Mon Jun 24 16:58:10 2019 +0100
+++ b/main/MainWindow.cpp	Thu Jul 04 14:32:08 2019 +0100
@@ -1294,11 +1294,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 +1382,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 +1421,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 +1463,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 +1484,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 +1509,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 +1622,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 +1631,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 +1646,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 +2696,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 +2710,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 +2752,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 +2850,7 @@
                                         model->getSampleRate(),
                                         model->getChannelCount(),
                                         WavFileWriter::WriteToTemporary);
-                subwriter.writeModel(model, &subms);
+                subwriter.writeModel(model.get(), &subms);
                 ok = subwriter.isOK();
 
                 if (!ok) {
@@ -2856,7 +2871,7 @@
                 this,
                 Qt::ApplicationModal
             };
-            CSVFileWriter writer(path, model, &dialog,
+            CSVFileWriter writer(path, model.get(), &dialog,
                                  ((QFileInfo(path).suffix() == "csv") ?
                                   "," : "\t"));
             if (selectionToWrite) {
@@ -2871,7 +2886,7 @@
                                  model->getSampleRate(),
                                  model->getChannelCount(),
                                  WavFileWriter::WriteToTemporary);
-            writer.writeModel(model, selectionToWrite);
+            writer.writeModel(model.get(), selectionToWrite);
             ok = writer.isOK();
             error = writer.getError();
         }
@@ -2936,8 +2951,10 @@
 
     } else {
 
+        auto modelId = ModelById::add(std::shared_ptr<Model>(model));
+        
         status = addOpenedAudioModel(path,
-                                     model,
+                                     modelId,
                                      CreateAdditionalModel,
                                      getDefaultSessionTemplate(),
                                      false);
@@ -2997,11 +3014,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;
@@ -3387,7 +3404,7 @@
     }
 
     QString mainModelLocation;
-    WaveFileModel *mm = getMainModel();
+    auto mm = getMainModel();
     if (mm) mainModelLocation = mm->getLocation();
     if (mainModelLocation != "") {
         openAudio(mainModelLocation, ReplaceSession, n);
@@ -3837,32 +3854,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);
@@ -3976,11 +3992,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 {
@@ -3989,27 +4003,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;
                 }
             }
         }
@@ -4066,10 +4078,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) {
 
@@ -4078,37 +4090,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->getId(), -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));
         }
     }
     
@@ -4124,23 +4136,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"));
+            if (auto aggregateModel = ModelById::get(aggregate)) {
+                aggregateModel->setObjectName(tr("Multiplexed audio"));
+            }
             m_document->addAggregateModel(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;
 
@@ -4330,7 +4343,7 @@
         if (layer &&
             LayerFactory::getInstance()->getLayerType(layer) ==
             LayerFactory::Waveform &&
-            layer->getModel() == getMainModel()) {
+            layer->getModel() == getMainModelId()) {
             containsMainModel = true;
             break;
         }
@@ -4341,15 +4354,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;
             }
@@ -4357,14 +4369,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;
     }
 
@@ -4388,12 +4406,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;
@@ -4586,13 +4600,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);
             }
 
@@ -4639,20 +4651,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)),
@@ -4684,19 +4696,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());