annotate layer/Layer.cpp @ 316:c0b9eec70639

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