annotate layer/Layer.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 4f4f38a11cd2
children 020c485aa7e0 0895517bb2d1
rev   line source
Chris@127 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@127 2
Chris@127 3 /*
Chris@127 4 Sonic Visualiser
Chris@127 5 An audio file viewer and annotation editor.
Chris@127 6 Centre for Digital Music, Queen Mary, University of London.
Chris@182 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@127 8
Chris@127 9 This program is free software; you can redistribute it and/or
Chris@127 10 modify it under the terms of the GNU General Public License as
Chris@127 11 published by the Free Software Foundation; either version 2 of the
Chris@127 12 License, or (at your option) any later version. See the file
Chris@127 13 COPYING included with this distribution for more information.
Chris@127 14 */
Chris@127 15
Chris@127 16 #include "Layer.h"
Chris@128 17 #include "view/View.h"
Chris@128 18 #include "data/model/Model.h"
Chris@268 19 #include "base/CommandHistory.h"
Chris@127 20
Chris@127 21 #include <iostream>
Chris@127 22
Chris@131 23 #include <QMutexLocker>
Chris@267 24 #include <QMouseEvent>
Chris@316 25 #include <QTextStream>
Chris@131 26
Chris@326 27 #include <QDomDocument>
Chris@326 28 #include <QDomElement>
Chris@326 29 #include <QDomNamedNodeMap>
Chris@326 30 #include <QDomAttr>
Chris@326 31
Chris@131 32 #include "LayerFactory.h"
Chris@128 33 #include "base/PlayParameterRepository.h"
Chris@127 34
Chris@272 35 #include <cmath>
Chris@272 36
Chris@267 37 Layer::Layer() :
Chris@283 38 m_haveDraggingRect(false),
Chris@283 39 m_haveCurrentMeasureRect(false)
Chris@127 40 {
Chris@127 41 }
Chris@127 42
Chris@127 43 Layer::~Layer()
Chris@127 44 {
Chris@127 45 // std::cerr << "Layer::~Layer(" << this << ")" << std::endl;
Chris@127 46 }
Chris@127 47
Chris@320 48 void
Chris@320 49 Layer::connectSignals(const Model *model)
Chris@320 50 {
Chris@320 51 connect(model, SIGNAL(modelChanged()),
Chris@320 52 this, SIGNAL(modelChanged()));
Chris@320 53
Chris@320 54 connect(model, SIGNAL(modelChanged(size_t, size_t)),
Chris@320 55 this, SIGNAL(modelChanged(size_t, size_t)));
Chris@320 56
Chris@320 57 connect(model, SIGNAL(completionChanged()),
Chris@320 58 this, SIGNAL(modelCompletionChanged()));
Chris@320 59
Chris@320 60 connect(model, SIGNAL(alignmentCompletionChanged()),
Chris@320 61 this, SIGNAL(modelAlignmentCompletionChanged()));
Chris@320 62 }
Chris@320 63
Chris@127 64 QString
Chris@127 65 Layer::getPropertyContainerIconName() const
Chris@127 66 {
Chris@127 67 return LayerFactory::getInstance()->getLayerIconName
Chris@127 68 (LayerFactory::getInstance()->getLayerType(this));
Chris@127 69 }
Chris@127 70
Chris@127 71 QString
Chris@127 72 Layer::getLayerPresentationName() const
Chris@127 73 {
Chris@203 74 // QString layerName = objectName();
Chris@203 75
Chris@203 76 LayerFactory *factory = LayerFactory::getInstance();
Chris@203 77 QString layerName = factory->getLayerPresentationName
Chris@203 78 (factory->getLayerType(this));
Chris@203 79
Chris@127 80 QString modelName;
Chris@127 81 if (getModel()) modelName = getModel()->objectName();
Chris@127 82
Chris@127 83 QString text;
Chris@127 84 if (modelName != "") {
Chris@127 85 text = QString("%1: %2").arg(modelName).arg(layerName);
Chris@127 86 } else {
Chris@127 87 text = layerName;
Chris@127 88 }
Chris@127 89
Chris@127 90 return text;
Chris@127 91 }
Chris@127 92
Chris@127 93 void
Chris@127 94 Layer::setObjectName(const QString &name)
Chris@127 95 {
Chris@127 96 QObject::setObjectName(name);
Chris@127 97 emit layerNameChanged();
Chris@127 98 }
Chris@127 99
Chris@127 100 PlayParameters *
Chris@127 101 Layer::getPlayParameters()
Chris@127 102 {
Chris@127 103 // std::cerr << "Layer (" << this << ", " << objectName().toStdString() << ")::getPlayParameters: model is "<< getModel() << std::endl;
Chris@127 104 const Model *model = getModel();
Chris@127 105 if (model) {
Chris@127 106 return PlayParameterRepository::getInstance()->getPlayParameters(model);
Chris@127 107 }
Chris@127 108 return 0;
Chris@127 109 }
Chris@127 110
Chris@127 111 void
Chris@131 112 Layer::setLayerDormant(const View *v, bool dormant)
Chris@131 113 {
Chris@131 114 const void *vv = (const void *)v;
Chris@131 115 QMutexLocker locker(&m_dormancyMutex);
Chris@131 116 m_dormancy[vv] = dormant;
Chris@131 117 }
Chris@131 118
Chris@131 119 bool
Chris@131 120 Layer::isLayerDormant(const View *v) const
Chris@131 121 {
Chris@131 122 const void *vv = (const void *)v;
Chris@131 123 QMutexLocker locker(&m_dormancyMutex);
Chris@131 124 if (m_dormancy.find(vv) == m_dormancy.end()) return false;
Chris@131 125 return m_dormancy.find(vv)->second;
Chris@131 126 }
Chris@131 127
Chris@131 128 void
Chris@127 129 Layer::showLayer(View *view, bool show)
Chris@127 130 {
Chris@127 131 setLayerDormant(view, !show);
Chris@127 132 emit layerParametersChanged();
Chris@127 133 }
Chris@127 134
Chris@260 135 bool
Chris@267 136 Layer::getXScaleValue(const View *v, int x, float &value, QString &unit) const
Chris@260 137 {
Chris@260 138 if (!hasTimeXAxis()) return false;
Chris@260 139
Chris@260 140 const Model *m = getModel();
Chris@260 141 if (!m) return false;
Chris@260 142
Chris@260 143 value = float(v->getFrameForX(x)) / m->getSampleRate();
Chris@260 144 unit = "s";
Chris@260 145 return true;
Chris@260 146 }
Chris@260 147
Chris@268 148 bool
Chris@274 149 Layer::getYScaleDifference(const View *v, int y0, int y1,
Chris@274 150 float &diff, QString &unit) const
Chris@274 151 {
Chris@274 152 float v0, v1;
Chris@274 153 if (!getYScaleValue(v, y0, v0, unit) ||
Chris@274 154 !getYScaleValue(v, y1, v1, unit)) {
Chris@274 155 diff = 0.f;
Chris@274 156 return false;
Chris@274 157 }
Chris@274 158 diff = fabsf(v1 - v0);
Chris@274 159 return true;
Chris@274 160 }
Chris@274 161
Chris@274 162 bool
Chris@268 163 Layer::MeasureRect::operator<(const MeasureRect &mr) const
Chris@268 164 {
Chris@268 165 if (haveFrames) {
Chris@268 166 if (startFrame == mr.startFrame) {
Chris@268 167 if (endFrame != mr.endFrame) {
Chris@268 168 return endFrame < mr.endFrame;
Chris@268 169 }
Chris@268 170 } else {
Chris@268 171 return startFrame < mr.startFrame;
Chris@268 172 }
Chris@268 173 } else {
Chris@268 174 if (pixrect.x() == mr.pixrect.x()) {
Chris@268 175 if (pixrect.width() != mr.pixrect.width()) {
Chris@268 176 return pixrect.width() < mr.pixrect.width();
Chris@268 177 }
Chris@268 178 } else {
Chris@268 179 return pixrect.x() < mr.pixrect.x();
Chris@268 180 }
Chris@268 181 }
Chris@268 182
Chris@268 183 // the two rects are equal in x and width
Chris@268 184
Chris@268 185 if (pixrect.y() == mr.pixrect.y()) {
Chris@268 186 return pixrect.height() < mr.pixrect.height();
Chris@268 187 } else {
Chris@268 188 return pixrect.y() < mr.pixrect.y();
Chris@268 189 }
Chris@268 190 }
Chris@268 191
Chris@316 192 void
Chris@316 193 Layer::MeasureRect::toXml(QTextStream &stream, QString indent) const
Chris@269 194 {
Chris@316 195 stream << indent;
Chris@316 196 stream << QString("<measurement ");
Chris@269 197
Chris@269 198 if (haveFrames) {
Chris@316 199 stream << QString("startFrame=\"%1\" endFrame=\"%2\" ")
Chris@269 200 .arg(startFrame).arg(endFrame);
Chris@269 201 } else {
Chris@316 202 stream << QString("startX=\"%1\" endX=\"%2\" ")
Chris@316 203 .arg(pixrect.x()).arg(pixrect.x() << pixrect.width());
Chris@269 204 }
Chris@269 205
Chris@316 206 stream << QString("startY=\"%1\" endY=\"%2\"/>\n")
Chris@273 207 .arg(startY).arg(endY);
Chris@269 208 }
Chris@269 209
Chris@269 210 void
Chris@269 211 Layer::addMeasurementRect(const QXmlAttributes &attributes)
Chris@269 212 {
Chris@269 213 MeasureRect rect;
Chris@269 214 QString fs = attributes.value("startFrame");
Chris@273 215 int x0 = 0, x1 = 0;
Chris@269 216 if (fs != "") {
Chris@269 217 rect.startFrame = fs.toLong();
Chris@269 218 rect.endFrame = attributes.value("endFrame").toLong();
Chris@269 219 rect.haveFrames = true;
Chris@269 220 } else {
Chris@269 221 x0 = attributes.value("startX").toInt();
Chris@269 222 x1 = attributes.value("endX").toInt();
Chris@269 223 rect.haveFrames = false;
Chris@269 224 }
Chris@273 225 rect.startY = attributes.value("startY").toDouble();
Chris@273 226 rect.endY = attributes.value("endY").toDouble();
Chris@273 227 rect.pixrect = QRect(x0, 0, x1 - x0, 0);
Chris@269 228 addMeasureRectToSet(rect);
Chris@269 229 }
Chris@269 230
Chris@269 231 QString
Chris@268 232 Layer::AddMeasurementRectCommand::getName() const
Chris@268 233 {
Chris@268 234 return tr("Make Measurement");
Chris@268 235 }
Chris@268 236
Chris@268 237 void
Chris@268 238 Layer::AddMeasurementRectCommand::execute()
Chris@268 239 {
Chris@269 240 m_layer->addMeasureRectToSet(m_rect);
Chris@268 241 }
Chris@268 242
Chris@268 243 void
Chris@268 244 Layer::AddMeasurementRectCommand::unexecute()
Chris@268 245 {
Chris@269 246 m_layer->deleteMeasureRectFromSet(m_rect);
Chris@268 247 }
Chris@268 248
Chris@283 249 QString
Chris@283 250 Layer::DeleteMeasurementRectCommand::getName() const
Chris@283 251 {
Chris@283 252 return tr("Delete Measurement");
Chris@283 253 }
Chris@283 254
Chris@283 255 void
Chris@283 256 Layer::DeleteMeasurementRectCommand::execute()
Chris@283 257 {
Chris@283 258 m_layer->deleteMeasureRectFromSet(m_rect);
Chris@283 259 }
Chris@283 260
Chris@283 261 void
Chris@283 262 Layer::DeleteMeasurementRectCommand::unexecute()
Chris@283 263 {
Chris@283 264 m_layer->addMeasureRectToSet(m_rect);
Chris@283 265 }
Chris@283 266
Chris@267 267 void
Chris@267 268 Layer::measureStart(View *v, QMouseEvent *e)
Chris@267 269 {
Chris@283 270 setMeasureRectFromPixrect(v, m_draggingRect,
Chris@283 271 QRect(e->x(), e->y(), 0, 0));
Chris@267 272 m_haveDraggingRect = true;
Chris@267 273 }
Chris@267 274
Chris@267 275 void
Chris@267 276 Layer::measureDrag(View *v, QMouseEvent *e)
Chris@267 277 {
Chris@267 278 if (!m_haveDraggingRect) return;
Chris@268 279
Chris@283 280 setMeasureRectFromPixrect(v, m_draggingRect,
Chris@283 281 QRect(m_draggingRect.pixrect.x(),
Chris@283 282 m_draggingRect.pixrect.y(),
Chris@283 283 e->x() - m_draggingRect.pixrect.x(),
Chris@283 284 e->y() - m_draggingRect.pixrect.y()));
Chris@267 285 }
Chris@267 286
Chris@267 287 void
Chris@267 288 Layer::measureEnd(View *v, QMouseEvent *e)
Chris@267 289 {
Chris@267 290 if (!m_haveDraggingRect) return;
Chris@267 291 measureDrag(v, e);
Chris@283 292
Chris@283 293 if (!m_draggingRect.pixrect.isNull()) {
Chris@283 294 CommandHistory::getInstance()->addCommand
Chris@283 295 (new AddMeasurementRectCommand(this, m_draggingRect));
Chris@283 296 }
Chris@268 297
Chris@267 298 m_haveDraggingRect = false;
Chris@267 299 }
Chris@267 300
Chris@267 301 void
Chris@280 302 Layer::measureDoubleClick(View *v, QMouseEvent *e)
Chris@280 303 {
Chris@283 304 // nothing, in the base class
Chris@283 305 }
Chris@283 306
Chris@283 307 void
Chris@283 308 Layer::deleteCurrentMeasureRect()
Chris@283 309 {
Chris@283 310 if (!m_haveCurrentMeasureRect) return;
Chris@283 311
Chris@283 312 MeasureRectSet::const_iterator focusRectItr =
Chris@283 313 findFocusedMeasureRect(m_currentMeasureRectPoint);
Chris@283 314
Chris@283 315 if (focusRectItr == m_measureRects.end()) return;
Chris@283 316
Chris@283 317 CommandHistory::getInstance()->addCommand
Chris@283 318 (new DeleteMeasurementRectCommand(this, *focusRectItr));
Chris@280 319 }
Chris@280 320
Chris@280 321 void
Chris@272 322 Layer::paintMeasurementRects(View *v, QPainter &paint,
Chris@272 323 bool showFocus, QPoint focusPoint) const
Chris@267 324 {
Chris@273 325 updateMeasurePixrects(v);
Chris@272 326
Chris@272 327 MeasureRectSet::const_iterator focusRectItr = m_measureRects.end();
Chris@272 328
Chris@267 329 if (m_haveDraggingRect) {
Chris@272 330
Chris@270 331 paintMeasurementRect(v, paint, m_draggingRect, true);
Chris@272 332
Chris@272 333 } else if (showFocus) {
Chris@272 334
Chris@272 335 focusRectItr = findFocusedMeasureRect(focusPoint);
Chris@267 336 }
Chris@267 337
Chris@283 338 m_haveCurrentMeasureRect = false;
Chris@283 339
Chris@268 340 for (MeasureRectSet::const_iterator i = m_measureRects.begin();
Chris@268 341 i != m_measureRects.end(); ++i) {
Chris@283 342
Chris@283 343 bool focused = (i == focusRectItr);
Chris@283 344 paintMeasurementRect(v, paint, *i, focused);
Chris@283 345
Chris@283 346 if (focused) {
Chris@283 347 m_haveCurrentMeasureRect = true;
Chris@283 348 m_currentMeasureRectPoint = focusPoint;
Chris@283 349 }
Chris@267 350 }
Chris@267 351 }
Chris@267 352
Chris@272 353 bool
Chris@272 354 Layer::nearestMeasurementRectChanged(View *v, QPoint prev, QPoint now) const
Chris@272 355 {
Chris@273 356 updateMeasurePixrects(v);
Chris@272 357
Chris@272 358 MeasureRectSet::const_iterator i0 = findFocusedMeasureRect(prev);
Chris@272 359 MeasureRectSet::const_iterator i1 = findFocusedMeasureRect(now);
Chris@272 360
Chris@272 361 return (i0 != i1);
Chris@272 362 }
Chris@272 363
Chris@272 364 void
Chris@273 365 Layer::updateMeasurePixrects(View *v) const
Chris@272 366 {
Chris@272 367 long sf = v->getStartFrame();
Chris@272 368 long ef = v->getEndFrame();
Chris@272 369
Chris@272 370 for (MeasureRectSet::const_iterator i = m_measureRects.begin();
Chris@272 371 i != m_measureRects.end(); ++i) {
Chris@272 372
Chris@273 373 // This logic depends on the fact that if one measure rect in
Chris@273 374 // a layer has frame values, they all will. That is in fact
Chris@273 375 // the case, because haveFrames is based on whether the layer
Chris@273 376 // hasTimeXAxis() or not. Measure rect ordering in the rect
Chris@273 377 // set wouldn't work correctly either, if haveFrames could
Chris@273 378 // vary.
Chris@272 379
Chris@273 380 if (i->haveFrames) {
Chris@273 381 if (i->startFrame >= ef) break;
Chris@273 382 if (i->endFrame <= sf) continue;
Chris@273 383 }
Chris@272 384
Chris@273 385 int x0 = i->pixrect.x();
Chris@273 386 int x1 = x0 + i->pixrect.width();
Chris@273 387
Chris@273 388 if (i->haveFrames) {
Chris@273 389 if (i->startFrame >= v->getStartFrame()) {
Chris@273 390 x0 = v->getXForFrame(i->startFrame);
Chris@273 391 }
Chris@273 392 if (i->endFrame <= long(v->getEndFrame())) {
Chris@273 393 x1 = v->getXForFrame(i->endFrame);
Chris@273 394 }
Chris@272 395 }
Chris@272 396
Chris@273 397 i->pixrect = QRect(x0, i->pixrect.y(), x1 - x0, i->pixrect.height());
Chris@273 398
Chris@273 399 updateMeasureRectYCoords(v, *i);
Chris@273 400 }
Chris@273 401 }
Chris@273 402
Chris@273 403 void
Chris@273 404 Layer::updateMeasureRectYCoords(View *v, const MeasureRect &r) const
Chris@273 405 {
Chris@273 406 int y0 = lrint(r.startY * v->height());
Chris@273 407 int y1 = lrint(r.endY * v->height());
Chris@273 408 r.pixrect = QRect(r.pixrect.x(), y0, r.pixrect.width(), y1 - y0);
Chris@273 409 }
Chris@273 410
Chris@273 411 void
Chris@273 412 Layer::setMeasureRectYCoord(View *v, MeasureRect &r, bool start, int y) const
Chris@273 413 {
Chris@273 414 if (start) {
Chris@273 415 r.startY = double(y) / double(v->height());
Chris@273 416 r.endY = r.startY;
Chris@273 417 } else {
Chris@273 418 r.endY = double(y) / double(v->height());
Chris@272 419 }
Chris@272 420 }
Chris@272 421
Chris@283 422 void
Chris@283 423 Layer::setMeasureRectFromPixrect(View *v, MeasureRect &r, QRect pixrect) const
Chris@283 424 {
Chris@283 425 r.pixrect = pixrect;
Chris@283 426 r.haveFrames = hasTimeXAxis();
Chris@283 427 if (r.haveFrames) {
Chris@283 428 r.startFrame = v->getFrameForX(pixrect.x());
Chris@283 429 r.endFrame = v->getFrameForX(pixrect.x() + pixrect.width());
Chris@283 430 }
Chris@283 431 setMeasureRectYCoord(v, r, true, pixrect.y());
Chris@283 432 setMeasureRectYCoord(v, r, false, pixrect.y() + pixrect.height());
Chris@283 433 }
Chris@283 434
Chris@272 435 Layer::MeasureRectSet::const_iterator
Chris@272 436 Layer::findFocusedMeasureRect(QPoint focusPoint) const
Chris@272 437 {
Chris@272 438 float frDist = 0;
Chris@272 439 MeasureRectSet::const_iterator focusRectItr = m_measureRects.end();
Chris@272 440
Chris@272 441 for (MeasureRectSet::const_iterator i = m_measureRects.begin();
Chris@272 442 i != m_measureRects.end(); ++i) {
Chris@272 443
Chris@272 444 if (!i->pixrect.adjusted(-2, -2, 2, 2).contains(focusPoint)) continue;
Chris@272 445
Chris@272 446 int cx = i->pixrect.x() + i->pixrect.width()/2;
Chris@272 447 int cy = i->pixrect.y() + i->pixrect.height()/2;
Chris@272 448 int xd = focusPoint.x() - cx;
Chris@272 449 int yd = focusPoint.y() - cy;
Chris@272 450
Chris@272 451 float d = sqrt(xd * xd + yd * yd);
Chris@272 452
Chris@272 453 if (focusRectItr == m_measureRects.end() || d < frDist) {
Chris@272 454 focusRectItr = i;
Chris@272 455 frDist = d;
Chris@272 456 }
Chris@272 457 }
Chris@272 458
Chris@272 459 return focusRectItr;
Chris@272 460 }
Chris@272 461
Chris@268 462 void
Chris@270 463 Layer::paintMeasurementRect(View *v, QPainter &paint,
Chris@270 464 const MeasureRect &r, bool focus) const
Chris@268 465 {
Chris@268 466 if (r.haveFrames) {
Chris@268 467
Chris@268 468 int x0 = -1;
Chris@268 469 int x1 = v->width() + 1;
Chris@268 470
Chris@268 471 if (r.startFrame >= v->getStartFrame()) {
Chris@268 472 x0 = v->getXForFrame(r.startFrame);
Chris@268 473 }
Chris@272 474 if (r.endFrame <= long(v->getEndFrame())) {
Chris@268 475 x1 = v->getXForFrame(r.endFrame);
Chris@268 476 }
Chris@268 477
Chris@272 478 QRect pr = QRect(x0, r.pixrect.y(), x1 - x0, r.pixrect.height());
Chris@268 479 r.pixrect = pr;
Chris@268 480 }
Chris@274 481
Chris@274 482 v->drawMeasurementRect(paint, this, r.pixrect.normalized(), focus);
Chris@268 483 }
Chris@268 484
Chris@316 485 void
Chris@316 486 Layer::toXml(QTextStream &stream,
Chris@316 487 QString indent, QString extraAttributes) const
Chris@268 488 {
Chris@316 489 stream << indent;
Chris@268 490
Chris@316 491 stream << QString("<layer id=\"%2\" type=\"%1\" name=\"%3\" model=\"%4\" %5")
Chris@268 492 .arg(encodeEntities(LayerFactory::getInstance()->getLayerTypeName
Chris@268 493 (LayerFactory::getInstance()->getLayerType(this))))
Chris@268 494 .arg(getObjectExportId(this))
Chris@268 495 .arg(encodeEntities(objectName()))
Chris@268 496 .arg(getObjectExportId(getModel()))
Chris@268 497 .arg(extraAttributes);
Chris@268 498
Chris@269 499 if (m_measureRects.empty()) {
Chris@316 500 stream << QString("/>\n");
Chris@316 501 return;
Chris@269 502 }
Chris@269 503
Chris@316 504 stream << QString(">\n");
Chris@269 505
Chris@269 506 for (MeasureRectSet::const_iterator i = m_measureRects.begin();
Chris@269 507 i != m_measureRects.end(); ++i) {
Chris@316 508 i->toXml(stream, indent + " ");
Chris@269 509 }
Chris@269 510
Chris@316 511 stream << QString("</layer>\n");
Chris@268 512 }
Chris@269 513
Chris@316 514 void
Chris@316 515 Layer::toBriefXml(QTextStream &stream,
Chris@316 516 QString indent, QString extraAttributes) const
Chris@269 517 {
Chris@316 518 stream << indent;
Chris@269 519
Chris@316 520 stream << QString("<layer id=\"%2\" type=\"%1\" name=\"%3\" model=\"%4\" %5/>\n")
Chris@269 521 .arg(encodeEntities(LayerFactory::getInstance()->getLayerTypeName
Chris@269 522 (LayerFactory::getInstance()->getLayerType(this))))
Chris@269 523 .arg(getObjectExportId(this))
Chris@269 524 .arg(encodeEntities(objectName()))
Chris@269 525 .arg(getObjectExportId(getModel()))
Chris@269 526 .arg(extraAttributes);
Chris@269 527 }
Chris@269 528