annotate layer/LayerFactory.cpp @ 349:369a197737c7

* Various fixes to object lifetime management, particularly in the spectrum layer and for notification of main model deletion. The main purpose of this is to improve the behaviour of the spectrum, but I think it may also help with #1840922 Various crashes in Layer Summary window.
author Chris Cannam
date Wed, 23 Jan 2008 15:43:27 +0000
parents 4a542ba875c2
children d58701996fae
rev   line source
Chris@58 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@59 4 Sonic Visualiser
Chris@59 5 An audio file viewer and annotation editor.
Chris@59 6 Centre for Digital Music, Queen Mary, University of London.
Chris@59 7 This file copyright 2006 Chris Cannam.
Chris@0 8
Chris@59 9 This program is free software; you can redistribute it and/or
Chris@59 10 modify it under the terms of the GNU General Public License as
Chris@59 11 published by the Free Software Foundation; either version 2 of the
Chris@59 12 License, or (at your option) any later version. See the file
Chris@59 13 COPYING included with this distribution for more information.
Chris@0 14 */
Chris@0 15
Chris@0 16 #include "LayerFactory.h"
Chris@0 17
Chris@0 18 #include "WaveformLayer.h"
Chris@0 19 #include "SpectrogramLayer.h"
Chris@0 20 #include "TimeRulerLayer.h"
Chris@0 21 #include "TimeInstantLayer.h"
Chris@0 22 #include "TimeValueLayer.h"
Chris@30 23 #include "NoteLayer.h"
Chris@35 24 #include "TextLayer.h"
Chris@303 25 #include "ImageLayer.h"
Chris@0 26 #include "Colour3DPlotLayer.h"
Chris@133 27 #include "SpectrumLayer.h"
Chris@193 28 #include "SliceLayer.h"
Chris@193 29 #include "SliceableLayer.h"
Chris@0 30
Chris@128 31 #include "data/model/RangeSummarisableTimeValueModel.h"
Chris@128 32 #include "data/model/DenseTimeValueModel.h"
Chris@128 33 #include "data/model/SparseOneDimensionalModel.h"
Chris@128 34 #include "data/model/SparseTimeValueModel.h"
Chris@128 35 #include "data/model/NoteModel.h"
Chris@128 36 #include "data/model/TextModel.h"
Chris@303 37 #include "data/model/ImageModel.h"
Chris@128 38 #include "data/model/DenseThreeDimensionalModel.h"
Chris@156 39 #include "data/model/WaveFileModel.h"
Chris@156 40 #include "data/model/WritableWaveFileModel.h"
Chris@0 41
Chris@326 42 #include <QDomDocument>
Chris@326 43 #include <QDomElement>
Chris@326 44 #include <QDomNamedNodeMap>
Chris@326 45 #include <QDomAttr>
Chris@326 46
Chris@326 47 #include <QSettings>
Chris@326 48
Chris@0 49 LayerFactory *
Chris@0 50 LayerFactory::m_instance = new LayerFactory;
Chris@0 51
Chris@0 52 LayerFactory *
Chris@125 53 LayerFactory::getInstance()
Chris@0 54 {
Chris@0 55 return m_instance;
Chris@0 56 }
Chris@0 57
Chris@0 58 LayerFactory::~LayerFactory()
Chris@0 59 {
Chris@0 60 }
Chris@0 61
Chris@0 62 QString
Chris@0 63 LayerFactory::getLayerPresentationName(LayerType type)
Chris@0 64 {
Chris@0 65 switch (type) {
Chris@0 66 case Waveform: return Layer::tr("Waveform");
Chris@0 67 case Spectrogram: return Layer::tr("Spectrogram");
Chris@0 68 case TimeRuler: return Layer::tr("Ruler");
Chris@0 69 case TimeInstants: return Layer::tr("Time Instants");
Chris@0 70 case TimeValues: return Layer::tr("Time Values");
Chris@30 71 case Notes: return Layer::tr("Notes");
Chris@35 72 case Text: return Layer::tr("Text");
Chris@303 73 case Image: return Layer::tr("Images");
Chris@0 74 case Colour3DPlot: return Layer::tr("Colour 3D Plot");
Chris@133 75 case Spectrum: return Layer::tr("Spectrum");
Chris@193 76 case Slice: return Layer::tr("Time Slice");
Chris@0 77
Chris@0 78 case MelodicRangeSpectrogram:
Chris@0 79 // The user can change all the parameters of this after the
Chris@0 80 // fact -- there's nothing permanently melodic-range about it
Chris@0 81 // that should be encoded in its name
Chris@0 82 return Layer::tr("Spectrogram");
Chris@11 83
Chris@37 84 case PeakFrequencySpectrogram:
Chris@37 85 // likewise
Chris@37 86 return Layer::tr("Spectrogram");
Chris@37 87
Chris@11 88 default: break;
Chris@0 89 }
Chris@0 90
Chris@0 91 return Layer::tr("Layer");
Chris@0 92 }
Chris@0 93
Chris@193 94 bool
Chris@193 95 LayerFactory::isLayerSliceable(const Layer *layer)
Chris@193 96 {
Chris@193 97 if (dynamic_cast<const SliceableLayer *>(layer)) {
Chris@193 98 if (dynamic_cast<const SpectrogramLayer *>(layer)) {
Chris@193 99
Chris@193 100 //!!! We can create slices of spectrograms, but there's a
Chris@193 101 // problem managing the models. The source model for the
Chris@193 102 // slice layer has to be one of the spectrogram's FFT
Chris@193 103 // models -- that's fine, except that we can't store &
Chris@193 104 // recall the slice layer with a reference to that model
Chris@193 105 // because the model is internal to the spectrogram layer
Chris@193 106 // and the document has no record of it. We would need
Chris@193 107 // some other way of managing models that are used in this
Chris@193 108 // way. For the moment we just don't allow slices of
Chris@193 109 // spectrograms -- and provide a spectrum layer for this
Chris@193 110 // instead.
Chris@193 111 //
Chris@193 112 // This business needs a bit more thought -- either come
Chris@193 113 // up with a sensible way to deal with that stuff, or
Chris@193 114 // simplify the existing slice layer logic so that it
Chris@193 115 // doesn't have to deal with models disappearing on it at
Chris@193 116 // all (and use the normal Document setModel mechanism to
Chris@193 117 // set its sliceable model instead of the fancy pants
Chris@193 118 // nonsense it's doing at the moment).
Chris@193 119
Chris@193 120 return false;
Chris@193 121 }
Chris@193 122 return true;
Chris@193 123 }
Chris@193 124 return false;
Chris@193 125 }
Chris@193 126
Chris@0 127 LayerFactory::LayerTypeSet
Chris@0 128 LayerFactory::getValidLayerTypes(Model *model)
Chris@0 129 {
Chris@0 130 LayerTypeSet types;
Chris@0 131
Chris@0 132 if (dynamic_cast<DenseThreeDimensionalModel *>(model)) {
Chris@0 133 types.insert(Colour3DPlot);
Chris@193 134 types.insert(Slice);
Chris@193 135 }
Chris@193 136
Chris@193 137 if (dynamic_cast<RangeSummarisableTimeValueModel *>(model)) {
Chris@193 138 types.insert(Waveform);
Chris@0 139 }
Chris@0 140
Chris@0 141 if (dynamic_cast<DenseTimeValueModel *>(model)) {
Chris@0 142 types.insert(Spectrogram);
Chris@0 143 types.insert(MelodicRangeSpectrogram);
Chris@37 144 types.insert(PeakFrequencySpectrogram);
Chris@0 145 }
Chris@0 146
Chris@0 147 if (dynamic_cast<SparseOneDimensionalModel *>(model)) {
Chris@0 148 types.insert(TimeInstants);
Chris@0 149 }
Chris@0 150
Chris@0 151 if (dynamic_cast<SparseTimeValueModel *>(model)) {
Chris@0 152 types.insert(TimeValues);
Chris@35 153
Chris@35 154 }
Chris@35 155 if (dynamic_cast<NoteModel *>(model)) {
Chris@35 156 types.insert(Notes);
Chris@0 157 }
Chris@0 158
Chris@35 159 if (dynamic_cast<TextModel *>(model)) {
Chris@35 160 types.insert(Text);
Chris@30 161 }
Chris@30 162
Chris@303 163 if (dynamic_cast<ImageModel *>(model)) {
Chris@303 164 types.insert(Image);
Chris@303 165 }
Chris@303 166
Chris@133 167 if (dynamic_cast<DenseTimeValueModel *>(model)) {
Chris@133 168 types.insert(Spectrum);
Chris@133 169 }
Chris@133 170
Chris@0 171 // We don't count TimeRuler here as it doesn't actually display
Chris@0 172 // the data, although it can be backed by any model
Chris@0 173
Chris@0 174 return types;
Chris@0 175 }
Chris@0 176
Chris@17 177 LayerFactory::LayerTypeSet
Chris@17 178 LayerFactory::getValidEmptyLayerTypes()
Chris@17 179 {
Chris@17 180 LayerTypeSet types;
Chris@17 181 types.insert(TimeInstants);
Chris@17 182 types.insert(TimeValues);
Chris@30 183 types.insert(Notes);
Chris@35 184 types.insert(Text);
Chris@303 185 types.insert(Image);
Chris@17 186 //!!! and in principle Colour3DPlot -- now that's a challenge
Chris@17 187 return types;
Chris@17 188 }
Chris@17 189
Chris@0 190 LayerFactory::LayerType
Chris@6 191 LayerFactory::getLayerType(const Layer *layer)
Chris@0 192 {
Chris@6 193 if (dynamic_cast<const WaveformLayer *>(layer)) return Waveform;
Chris@6 194 if (dynamic_cast<const SpectrogramLayer *>(layer)) return Spectrogram;
Chris@6 195 if (dynamic_cast<const TimeRulerLayer *>(layer)) return TimeRuler;
Chris@6 196 if (dynamic_cast<const TimeInstantLayer *>(layer)) return TimeInstants;
Chris@6 197 if (dynamic_cast<const TimeValueLayer *>(layer)) return TimeValues;
Chris@30 198 if (dynamic_cast<const NoteLayer *>(layer)) return Notes;
Chris@35 199 if (dynamic_cast<const TextLayer *>(layer)) return Text;
Chris@303 200 if (dynamic_cast<const ImageLayer *>(layer)) return Image;
Chris@6 201 if (dynamic_cast<const Colour3DPlotLayer *>(layer)) return Colour3DPlot;
Chris@133 202 if (dynamic_cast<const SpectrumLayer *>(layer)) return Spectrum;
Chris@193 203 if (dynamic_cast<const SliceLayer *>(layer)) return Slice;
Chris@6 204 return UnknownLayer;
Chris@6 205 }
Chris@6 206
Chris@6 207 QString
Chris@17 208 LayerFactory::getLayerIconName(LayerType type)
Chris@17 209 {
Chris@17 210 switch (type) {
Chris@17 211 case Waveform: return "waveform";
Chris@17 212 case Spectrogram: return "spectrogram";
Chris@17 213 case TimeRuler: return "timeruler";
Chris@17 214 case TimeInstants: return "instants";
Chris@17 215 case TimeValues: return "values";
Chris@30 216 case Notes: return "notes";
Chris@35 217 case Text: return "text";
Chris@303 218 case Image: return "image";
Chris@17 219 case Colour3DPlot: return "colour3d";
Chris@133 220 case Spectrum: return "spectrum";
Chris@193 221 case Slice: return "spectrum";
Chris@326 222 case MelodicRangeSpectrogram: return "spectrogram";
Chris@326 223 case PeakFrequencySpectrogram: return "spectrogram";
Chris@17 224 default: return "unknown";
Chris@17 225 }
Chris@17 226 }
Chris@17 227
Chris@17 228 QString
Chris@6 229 LayerFactory::getLayerTypeName(LayerType type)
Chris@6 230 {
Chris@6 231 switch (type) {
Chris@6 232 case Waveform: return "waveform";
Chris@6 233 case Spectrogram: return "spectrogram";
Chris@6 234 case TimeRuler: return "timeruler";
Chris@6 235 case TimeInstants: return "timeinstants";
Chris@6 236 case TimeValues: return "timevalues";
Chris@30 237 case Notes: return "notes";
Chris@35 238 case Text: return "text";
Chris@303 239 case Image: return "image";
Chris@6 240 case Colour3DPlot: return "colour3dplot";
Chris@133 241 case Spectrum: return "spectrum";
Chris@193 242 case Slice: return "slice";
Chris@326 243 case MelodicRangeSpectrogram: return "melodicrange";
Chris@326 244 case PeakFrequencySpectrogram: return "peakfrequency";
Chris@6 245 default: return "unknown";
Chris@6 246 }
Chris@6 247 }
Chris@6 248
Chris@6 249 LayerFactory::LayerType
Chris@6 250 LayerFactory::getLayerTypeForName(QString name)
Chris@6 251 {
Chris@6 252 if (name == "waveform") return Waveform;
Chris@6 253 if (name == "spectrogram") return Spectrogram;
Chris@6 254 if (name == "timeruler") return TimeRuler;
Chris@6 255 if (name == "timeinstants") return TimeInstants;
Chris@6 256 if (name == "timevalues") return TimeValues;
Chris@30 257 if (name == "notes") return Notes;
Chris@35 258 if (name == "text") return Text;
Chris@303 259 if (name == "image") return Image;
Chris@6 260 if (name == "colour3dplot") return Colour3DPlot;
Chris@133 261 if (name == "spectrum") return Spectrum;
Chris@193 262 if (name == "slice") return Slice;
Chris@0 263 return UnknownLayer;
Chris@0 264 }
Chris@0 265
Chris@0 266 void
Chris@0 267 LayerFactory::setModel(Layer *layer, Model *model)
Chris@0 268 {
Chris@156 269 // if (trySetModel<WaveformLayer, RangeSummarisableTimeValueModel>(layer, model))
Chris@156 270 // return;
Chris@156 271
Chris@156 272 if (trySetModel<WaveformLayer, WaveFileModel>(layer, model))
Chris@156 273 return;
Chris@156 274
Chris@156 275 if (trySetModel<WaveformLayer, WritableWaveFileModel>(layer, model))
Chris@0 276 return;
Chris@0 277
Chris@0 278 if (trySetModel<SpectrogramLayer, DenseTimeValueModel>(layer, model))
Chris@0 279 return;
Chris@0 280
Chris@0 281 if (trySetModel<TimeRulerLayer, Model>(layer, model))
Chris@0 282 return;
Chris@0 283
Chris@0 284 if (trySetModel<TimeInstantLayer, SparseOneDimensionalModel>(layer, model))
Chris@0 285 return;
Chris@0 286
Chris@0 287 if (trySetModel<TimeValueLayer, SparseTimeValueModel>(layer, model))
Chris@0 288 return;
Chris@0 289
Chris@30 290 if (trySetModel<NoteLayer, NoteModel>(layer, model))
Chris@30 291 return;
Chris@30 292
Chris@35 293 if (trySetModel<TextLayer, TextModel>(layer, model))
Chris@35 294 return;
Chris@35 295
Chris@303 296 if (trySetModel<ImageLayer, ImageModel>(layer, model))
Chris@303 297 return;
Chris@303 298
Chris@0 299 if (trySetModel<Colour3DPlotLayer, DenseThreeDimensionalModel>(layer, model))
Chris@0 300 return;
Chris@0 301
Chris@0 302 if (trySetModel<SpectrogramLayer, DenseTimeValueModel>(layer, model))
Chris@0 303 return;
Chris@133 304
Chris@133 305 if (trySetModel<SpectrumLayer, DenseTimeValueModel>(layer, model))
Chris@133 306 return;
Chris@193 307
Chris@193 308 // if (trySetModel<SliceLayer, DenseThreeDimensionalModel>(layer, model))
Chris@193 309 // return;
Chris@0 310 }
Chris@0 311
Chris@17 312 Model *
Chris@17 313 LayerFactory::createEmptyModel(LayerType layerType, Model *baseModel)
Chris@17 314 {
Chris@17 315 if (layerType == TimeInstants) {
Chris@17 316 return new SparseOneDimensionalModel(baseModel->getSampleRate(), 1);
Chris@17 317 } else if (layerType == TimeValues) {
Chris@245 318 return new SparseTimeValueModel(baseModel->getSampleRate(), 1, true);
Chris@30 319 } else if (layerType == Notes) {
Chris@245 320 return new NoteModel(baseModel->getSampleRate(), 1, true);
Chris@35 321 } else if (layerType == Text) {
Chris@35 322 return new TextModel(baseModel->getSampleRate(), 1, true);
Chris@303 323 } else if (layerType == Image) {
Chris@303 324 return new ImageModel(baseModel->getSampleRate(), 1, true);
Chris@17 325 } else {
Chris@17 326 return 0;
Chris@17 327 }
Chris@17 328 }
Chris@17 329
Chris@53 330 int
Chris@53 331 LayerFactory::getChannel(Layer *layer)
Chris@53 332 {
Chris@53 333 if (dynamic_cast<WaveformLayer *>(layer)) {
Chris@53 334 return dynamic_cast<WaveformLayer *>(layer)->getChannel();
Chris@53 335 }
Chris@53 336 if (dynamic_cast<SpectrogramLayer *>(layer)) {
Chris@53 337 return dynamic_cast<SpectrogramLayer *>(layer)->getChannel();
Chris@53 338 }
Chris@53 339 return -1;
Chris@53 340 }
Chris@53 341
Chris@53 342 void
Chris@53 343 LayerFactory::setChannel(Layer *layer, int channel)
Chris@53 344 {
Chris@53 345 if (dynamic_cast<WaveformLayer *>(layer)) {
Chris@53 346 dynamic_cast<WaveformLayer *>(layer)->setChannel(channel);
Chris@53 347 return;
Chris@53 348 }
Chris@53 349 if (dynamic_cast<SpectrogramLayer *>(layer)) {
Chris@53 350 dynamic_cast<SpectrogramLayer *>(layer)->setChannel(channel);
Chris@53 351 return;
Chris@53 352 }
Chris@349 353 if (dynamic_cast<SpectrumLayer *>(layer)) {
Chris@349 354 dynamic_cast<SpectrumLayer *>(layer)->setChannel(channel);
Chris@349 355 return;
Chris@349 356 }
Chris@53 357 }
Chris@53 358
Chris@0 359 Layer *
Chris@53 360 LayerFactory::createLayer(LayerType type)
Chris@0 361 {
Chris@0 362 Layer *layer = 0;
Chris@0 363
Chris@0 364 switch (type) {
Chris@0 365
Chris@0 366 case Waveform:
Chris@44 367 layer = new WaveformLayer;
Chris@0 368 break;
Chris@0 369
Chris@0 370 case Spectrogram:
Chris@44 371 layer = new SpectrogramLayer;
Chris@0 372 break;
Chris@0 373
Chris@0 374 case TimeRuler:
Chris@44 375 layer = new TimeRulerLayer;
Chris@0 376 break;
Chris@0 377
Chris@0 378 case TimeInstants:
Chris@44 379 layer = new TimeInstantLayer;
Chris@0 380 break;
Chris@0 381
Chris@0 382 case TimeValues:
Chris@44 383 layer = new TimeValueLayer;
Chris@0 384 break;
Chris@0 385
Chris@30 386 case Notes:
Chris@44 387 layer = new NoteLayer;
Chris@30 388 break;
Chris@30 389
Chris@35 390 case Text:
Chris@44 391 layer = new TextLayer;
Chris@35 392 break;
Chris@35 393
Chris@303 394 case Image:
Chris@303 395 layer = new ImageLayer;
Chris@303 396 break;
Chris@303 397
Chris@0 398 case Colour3DPlot:
Chris@44 399 layer = new Colour3DPlotLayer;
Chris@0 400 break;
Chris@0 401
Chris@133 402 case Spectrum:
Chris@133 403 layer = new SpectrumLayer;
Chris@133 404 break;
Chris@133 405
Chris@193 406 case Slice:
Chris@193 407 layer = new SliceLayer;
Chris@193 408 break;
Chris@193 409
Chris@0 410 case MelodicRangeSpectrogram:
Chris@44 411 layer = new SpectrogramLayer(SpectrogramLayer::MelodicRange);
Chris@0 412 break;
Chris@11 413
Chris@37 414 case PeakFrequencySpectrogram:
Chris@44 415 layer = new SpectrogramLayer(SpectrogramLayer::MelodicPeaks);
Chris@37 416 break;
Chris@37 417
Chris@11 418 default: break;
Chris@0 419 }
Chris@0 420
Chris@0 421 if (!layer) {
Chris@0 422 std::cerr << "LayerFactory::createLayer: Unknown layer type "
Chris@0 423 << type << std::endl;
Chris@0 424 } else {
Chris@336 425 // std::cerr << "LayerFactory::createLayer: Setting object name "
Chris@336 426 // << getLayerPresentationName(type).toStdString() << " on " << layer << std::endl;
Chris@0 427 layer->setObjectName(getLayerPresentationName(type));
Chris@326 428 setLayerDefaultProperties(type, layer);
Chris@0 429 }
Chris@0 430
Chris@0 431 return layer;
Chris@0 432 }
Chris@0 433
Chris@326 434 void
Chris@326 435 LayerFactory::setLayerDefaultProperties(LayerType type, Layer *layer)
Chris@326 436 {
Chris@336 437 // std::cerr << "LayerFactory::setLayerDefaultProperties: type " << type << " (name \"" << getLayerTypeName(type).toStdString() << "\")" << std::endl;
Chris@327 438
Chris@326 439 QSettings settings;
Chris@326 440 settings.beginGroup("LayerDefaults");
Chris@326 441 QString defaults = settings.value(getLayerTypeName(type), "").toString();
Chris@326 442 if (defaults == "") return;
Chris@326 443
Chris@336 444 // std::cerr << "defaults=\"" << defaults.toStdString() << "\"" << std::endl;
Chris@327 445
Chris@326 446 QString xml = layer->toXmlString();
Chris@326 447 QDomDocument docOld, docNew;
Chris@326 448
Chris@326 449 if (docOld.setContent(xml, false) &&
Chris@326 450 docNew.setContent(defaults, false)) {
Chris@326 451
Chris@326 452 QXmlAttributes attrs;
Chris@326 453
Chris@326 454 QDomElement layerElt = docNew.firstChildElement("layer");
Chris@326 455 QDomNamedNodeMap attrNodes = layerElt.attributes();
Chris@326 456
Chris@326 457 for (unsigned int i = 0; i < attrNodes.length(); ++i) {
Chris@326 458 QDomAttr attr = attrNodes.item(i).toAttr();
Chris@326 459 if (attr.isNull()) continue;
Chris@336 460 // std::cerr << "append \"" << attr.name().toStdString()
Chris@336 461 // << "\" -> \"" << attr.value().toStdString() << "\""
Chris@336 462 // << std::endl;
Chris@326 463 attrs.append(attr.name(), "", "", attr.value());
Chris@326 464 }
Chris@326 465
Chris@326 466 layerElt = docOld.firstChildElement("layer");
Chris@326 467 attrNodes = layerElt.attributes();
Chris@326 468 for (unsigned int i = 0; i < attrNodes.length(); ++i) {
Chris@326 469 QDomAttr attr = attrNodes.item(i).toAttr();
Chris@326 470 if (attr.isNull()) continue;
Chris@326 471 if (attrs.value(attr.name()) == "") {
Chris@336 472 // std::cerr << "append \"" << attr.name().toStdString()
Chris@336 473 // << "\" -> \"" << attr.value().toStdString() << "\""
Chris@336 474 // << std::endl;
Chris@326 475 attrs.append(attr.name(), "", "", attr.value());
Chris@326 476 }
Chris@326 477 }
Chris@326 478
Chris@326 479 layer->setProperties(attrs);
Chris@326 480 }
Chris@326 481
Chris@326 482 settings.endGroup();
Chris@326 483 }
Chris@326 484