svgui  1.9
Layer.cpp
Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2006 Chris Cannam and QMUL.
00008     
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 #include "Layer.h"
00017 #include "view/View.h"
00018 #include "data/model/Model.h"
00019 #include "widgets/CommandHistory.h"
00020 
00021 #include <iostream>
00022 
00023 #include <QMutexLocker>
00024 #include <QMouseEvent>
00025 #include <QTextStream>
00026 
00027 #include <QDomDocument>
00028 #include <QDomElement>
00029 #include <QDomNamedNodeMap>
00030 #include <QDomAttr>
00031 
00032 #include "LayerFactory.h"
00033 #include "base/PlayParameterRepository.h"
00034 
00035 #include <cmath>
00036 
00037 Layer::Layer() :
00038     m_haveDraggingRect(false),
00039     m_haveCurrentMeasureRect(false)
00040 {
00041 }
00042 
00043 Layer::~Layer()
00044 {
00045 //    SVDEBUG << "Layer::~Layer(" << this << ")" << endl;
00046 }
00047 
00048 void
00049 Layer::connectSignals(const Model *model)
00050 {
00051     connect(model, SIGNAL(modelChanged()),
00052             this, SIGNAL(modelChanged()));
00053 
00054     connect(model, SIGNAL(modelChangedWithin(int, int)),
00055             this, SIGNAL(modelChangedWithin(int, int)));
00056 
00057     connect(model, SIGNAL(completionChanged()),
00058             this, SIGNAL(modelCompletionChanged()));
00059 
00060     connect(model, SIGNAL(alignmentCompletionChanged()),
00061             this, SIGNAL(modelAlignmentCompletionChanged()));
00062 }
00063 
00064 QString
00065 Layer::getPropertyContainerIconName() const
00066 {
00067     return LayerFactory::getInstance()->getLayerIconName
00068         (LayerFactory::getInstance()->getLayerType(this));
00069 }
00070 
00071 void
00072 Layer::setPresentationName(QString name)
00073 {
00074     m_presentationName = name;
00075 }
00076 
00077 QString
00078 Layer::getLayerPresentationName() const
00079 {
00080     if (m_presentationName != "") return m_presentationName;
00081 
00082     LayerFactory *factory = LayerFactory::getInstance();
00083     QString layerName = factory->getLayerPresentationName
00084         (factory->getLayerType(this));
00085 
00086     QString modelName;
00087     if (getModel()) modelName = getModel()->objectName();
00088             
00089     QString text;
00090     if (modelName != "") {
00091         text = QString("%1: %2").arg(modelName).arg(layerName);
00092     } else {
00093         text = layerName;
00094     }
00095         
00096     return text;
00097 }
00098 
00099 void
00100 Layer::setObjectName(const QString &name)
00101 {
00102     QObject::setObjectName(name);
00103     emit layerNameChanged();
00104 }
00105 
00106 PlayParameters *
00107 Layer::getPlayParameters() 
00108 {
00109 //    cerr << "Layer (" << this << ", " << objectName() << ")::getPlayParameters: model is "<< getModel() << endl;
00110     const Model *model = getModel();
00111     if (model) {
00112         return PlayParameterRepository::getInstance()->getPlayParameters(model);
00113     }
00114     return 0;
00115 }
00116 
00117 void
00118 Layer::setLayerDormant(const View *v, bool dormant)
00119 {
00120     const void *vv = (const void *)v;
00121     QMutexLocker locker(&m_dormancyMutex);
00122     m_dormancy[vv] = dormant;
00123 }
00124 
00125 bool
00126 Layer::isLayerDormant(const View *v) const
00127 {
00128     const void *vv = (const void *)v;
00129     QMutexLocker locker(&m_dormancyMutex);
00130     if (m_dormancy.find(vv) == m_dormancy.end()) return false;
00131     return m_dormancy.find(vv)->second;
00132 }
00133 
00134 void
00135 Layer::showLayer(View *view, bool show)
00136 {
00137     setLayerDormant(view, !show);
00138     emit layerParametersChanged();
00139 }
00140 
00141 bool
00142 Layer::getXScaleValue(const View *v, int x, float &value, QString &unit) const
00143 {
00144     if (!hasTimeXAxis()) return false;
00145 
00146     const Model *m = getModel();
00147     if (!m) return false;
00148 
00149     value = float(v->getFrameForX(x)) / m->getSampleRate();
00150     unit = "s";
00151     return true;
00152 }
00153 
00154 bool
00155 Layer::getYScaleDifference(const View *v, int y0, int y1,
00156                            float &diff, QString &unit) const
00157 {
00158     float v0, v1;
00159     if (!getYScaleValue(v, y0, v0, unit) ||
00160         !getYScaleValue(v, y1, v1, unit)) {
00161         diff = 0.f;
00162         return false;
00163     }
00164     diff = fabsf(v1 - v0);
00165     return true;
00166 }
00167 
00168 int
00169 Layer::alignToReference(View *v, int frame) const
00170 {
00171     const Model *m = getModel();
00172     SVDEBUG << "Layer::alignToReference(" << frame << "): model = " << m << ", alignment reference = " << (m ? m->getAlignmentReference() : 0) << endl;
00173     if (m && m->getAlignmentReference()) {
00174         return m->alignToReference(frame);
00175     } else {
00176         return v->alignToReference(frame);
00177     }
00178 }
00179 
00180 int
00181 Layer::alignFromReference(View *v, int frame) const
00182 {
00183     const Model *m = getModel();
00184     SVDEBUG << "Layer::alignFromReference(" << frame << "): model = " << m << ", alignment reference = " << (m ? m->getAlignmentReference() : 0) << endl;
00185     if (m && m->getAlignmentReference()) {
00186         return m->alignFromReference(frame);
00187     } else {
00188         return v->alignFromReference(frame);
00189     }
00190 }
00191 
00192 bool
00193 Layer::clipboardHasDifferentAlignment(View *v, const Clipboard &clip) const
00194 {
00195     // Notes on pasting to an aligned layer:
00196     // 
00197     // Each point may have a reference frame that may differ from the
00198     // point's given frame (in its source model).  If it has no
00199     // reference frame, we have to assume the source model was not
00200     // aligned or was the reference model: when cutting or copying
00201     // points from a layer, we must always set their reference frame
00202     // correctly if we are aligned.
00203     // 
00204     // When pasting:
00205     // - if point's reference and aligned frames differ:
00206     //   - if this layer is aligned:
00207     //     - if point's aligned frame matches this layer's aligned version
00208     //       of point's reference frame:
00209     //       - we can paste at reference frame or our frame
00210     //     - else
00211     //       - we can paste at reference frame, result of aligning reference
00212     //         frame in our model, or literal source frame
00213     //   - else
00214     //     - we can paste at reference (our) frame, or literal source frame
00215     // - else
00216     //   - if this layer is aligned:
00217     //     - we can paste at reference (point's only available) frame,
00218     //       or result of aligning reference frame in our model
00219     //   - else
00220     //     - we can only paste at reference frame
00221     // 
00222     // Which of these alternatives are useful?
00223     //
00224     // Example: we paste between two tracks that are aligned to the
00225     // same reference, and the points are at 10s and 20s in the source
00226     // track, corresponding to 5s and 10s in the reference but 20s and
00227     // 30s in the target track.
00228     // 
00229     // The obvious default is to paste at 20s and 30s; if we aren't
00230     // doing that, would it be better to paste at 5s and 10s or at 10s
00231     // and 20s?  We probably don't ever want to do the former, do we?
00232     // We either want to be literal all the way through, or aligned
00233     // all the way through.
00234 
00235     for (Clipboard::PointList::const_iterator i = clip.getPoints().begin();
00236          i != clip.getPoints().end(); ++i) {
00237 
00238         // In principle, we want to know whether the aligned version
00239         // of the reference frame in our layer is the same as the
00240         // source frame contained in the clipboard point.  However,
00241         // because of rounding during alignment, that won't
00242         // necessarily be the case even if the clipboard point came
00243         // from our layer!  What we need to check is whether, if we
00244         // aligned the clipboard point's frame back to the reference
00245         // using this layer's alignment, we would obtain the same
00246         // reference frame as that for the clipboard point.
00247 
00248         // What if the clipboard point has no reference frame?  Then
00249         // we have to treat it as having its own frame as the
00250         // reference (i.e. having been copied from the reference
00251         // model).
00252         
00253         int sourceFrame = i->getFrame();
00254         int referenceFrame = sourceFrame;
00255         if (i->haveReferenceFrame()) {
00256             referenceFrame = i->getReferenceFrame();
00257         }
00258         int myMappedFrame = alignToReference(v, sourceFrame);
00259 
00260 //        cerr << "sourceFrame = " << sourceFrame << ", referenceFrame = " << referenceFrame << " (have = " << i->haveReferenceFrame() << "), myMappedFrame = " << myMappedFrame << endl;
00261 
00262         if (myMappedFrame != referenceFrame) return true;
00263     }
00264 
00265     return false;
00266 }
00267 
00268 bool
00269 Layer::MeasureRect::operator<(const MeasureRect &mr) const
00270 {
00271     if (haveFrames) {
00272         if (startFrame == mr.startFrame) {
00273             if (endFrame != mr.endFrame) {
00274                 return endFrame < mr.endFrame;
00275             }
00276         } else {
00277             return startFrame < mr.startFrame;
00278         }
00279     } else {
00280         if (pixrect.x() == mr.pixrect.x()) {
00281             if (pixrect.width() != mr.pixrect.width()) {
00282                 return pixrect.width() < mr.pixrect.width();
00283             }
00284         } else {
00285             return pixrect.x() < mr.pixrect.x();
00286         }
00287     }
00288 
00289     // the two rects are equal in x and width
00290 
00291     if (pixrect.y() == mr.pixrect.y()) {
00292         return pixrect.height() < mr.pixrect.height();
00293     } else {
00294         return pixrect.y() < mr.pixrect.y();
00295     }
00296 }
00297 
00298 void
00299 Layer::MeasureRect::toXml(QTextStream &stream, QString indent) const
00300 {
00301     stream << indent;
00302     stream << QString("<measurement ");
00303 
00304     if (haveFrames) {
00305         stream << QString("startFrame=\"%1\" endFrame=\"%2\" ")
00306             .arg(startFrame).arg(endFrame);
00307     } else {
00308         stream << QString("startX=\"%1\" endX=\"%2\" ")
00309             .arg(pixrect.x()).arg(pixrect.x() << pixrect.width());
00310     }
00311 
00312     stream << QString("startY=\"%1\" endY=\"%2\"/>\n")
00313         .arg(startY).arg(endY);
00314 }
00315 
00316 void
00317 Layer::addMeasurementRect(const QXmlAttributes &attributes)
00318 {
00319     MeasureRect rect;
00320     QString fs = attributes.value("startFrame");
00321     int x0 = 0, x1 = 0;
00322     if (fs != "") {
00323         rect.startFrame = fs.toInt();
00324         rect.endFrame = attributes.value("endFrame").toInt();
00325         rect.haveFrames = true;
00326     } else {
00327         x0 = attributes.value("startX").toInt();
00328         x1 = attributes.value("endX").toInt();
00329         rect.haveFrames = false;
00330     }
00331     rect.startY = attributes.value("startY").toDouble();
00332     rect.endY = attributes.value("endY").toDouble();
00333     rect.pixrect = QRect(x0, 0, x1 - x0, 0);
00334     addMeasureRectToSet(rect);
00335 }
00336 
00337 QString
00338 Layer::AddMeasurementRectCommand::getName() const
00339 {
00340     return tr("Make Measurement");
00341 }
00342 
00343 void
00344 Layer::AddMeasurementRectCommand::execute()
00345 {
00346     m_layer->addMeasureRectToSet(m_rect);
00347 }
00348 
00349 void
00350 Layer::AddMeasurementRectCommand::unexecute()
00351 {
00352     m_layer->deleteMeasureRectFromSet(m_rect);
00353 }
00354 
00355 QString
00356 Layer::DeleteMeasurementRectCommand::getName() const
00357 {
00358     return tr("Delete Measurement");
00359 }
00360 
00361 void
00362 Layer::DeleteMeasurementRectCommand::execute()
00363 {
00364     m_layer->deleteMeasureRectFromSet(m_rect);
00365 }
00366 
00367 void
00368 Layer::DeleteMeasurementRectCommand::unexecute()
00369 {
00370     m_layer->addMeasureRectToSet(m_rect);
00371 }
00372 
00373 void
00374 Layer::measureStart(View *v, QMouseEvent *e)
00375 {
00376     setMeasureRectFromPixrect(v, m_draggingRect,
00377                               QRect(e->x(), e->y(), 0, 0));
00378     m_haveDraggingRect = true;
00379 }
00380 
00381 void
00382 Layer::measureDrag(View *v, QMouseEvent *e)
00383 {
00384     if (!m_haveDraggingRect) return;
00385 
00386     setMeasureRectFromPixrect(v, m_draggingRect,
00387                               QRect(m_draggingRect.pixrect.x(),
00388                                     m_draggingRect.pixrect.y(),
00389                                     e->x() - m_draggingRect.pixrect.x(),
00390                                     e->y() - m_draggingRect.pixrect.y()));
00391 }
00392 
00393 void
00394 Layer::measureEnd(View *v, QMouseEvent *e)
00395 {
00396     if (!m_haveDraggingRect) return;
00397     measureDrag(v, e);
00398 
00399     if (!m_draggingRect.pixrect.isNull()) {
00400         CommandHistory::getInstance()->addCommand
00401             (new AddMeasurementRectCommand(this, m_draggingRect));
00402     }
00403 
00404     m_haveDraggingRect = false;
00405 }
00406 
00407 void
00408 Layer::measureDoubleClick(View *, QMouseEvent *)
00409 {
00410     // nothing, in the base class
00411 }
00412 
00413 void
00414 Layer::deleteCurrentMeasureRect()
00415 {
00416     if (!m_haveCurrentMeasureRect) return;
00417     
00418     MeasureRectSet::const_iterator focusRectItr =
00419         findFocusedMeasureRect(m_currentMeasureRectPoint);
00420 
00421     if (focusRectItr == m_measureRects.end()) return;
00422 
00423     CommandHistory::getInstance()->addCommand
00424         (new DeleteMeasurementRectCommand(this, *focusRectItr));
00425 }
00426 
00427 void
00428 Layer::paintMeasurementRects(View *v, QPainter &paint,
00429                              bool showFocus, QPoint focusPoint) const
00430 {
00431     updateMeasurePixrects(v);
00432 
00433     MeasureRectSet::const_iterator focusRectItr = m_measureRects.end();
00434 
00435     if (m_haveDraggingRect) {
00436 
00437         paintMeasurementRect(v, paint, m_draggingRect, true);
00438 
00439     } else if (showFocus) {
00440 
00441         focusRectItr = findFocusedMeasureRect(focusPoint);
00442     }
00443 
00444     m_haveCurrentMeasureRect = false;
00445 
00446     for (MeasureRectSet::const_iterator i = m_measureRects.begin(); 
00447          i != m_measureRects.end(); ++i) {
00448 
00449         bool focused = (i == focusRectItr);
00450         paintMeasurementRect(v, paint, *i, focused);
00451 
00452         if (focused) {
00453             m_haveCurrentMeasureRect = true;
00454             m_currentMeasureRectPoint = focusPoint;
00455         }
00456     }
00457 }
00458 
00459 bool
00460 Layer::nearestMeasurementRectChanged(View *v, QPoint prev, QPoint now) const
00461 {
00462     updateMeasurePixrects(v);
00463     
00464     MeasureRectSet::const_iterator i0 = findFocusedMeasureRect(prev);
00465     MeasureRectSet::const_iterator i1 = findFocusedMeasureRect(now);
00466 
00467     return (i0 != i1);
00468 }
00469 
00470 void
00471 Layer::updateMeasurePixrects(View *v) const
00472 {
00473     int sf = v->getStartFrame();
00474     int ef = v->getEndFrame();
00475 
00476     for (MeasureRectSet::const_iterator i = m_measureRects.begin(); 
00477          i != m_measureRects.end(); ++i) {
00478 
00479         // This logic depends on the fact that if one measure rect in
00480         // a layer has frame values, they all will.  That is in fact
00481         // the case, because haveFrames is based on whether the layer
00482         // hasTimeXAxis() or not.  Measure rect ordering in the rect
00483         // set wouldn't work correctly either, if haveFrames could
00484         // vary.
00485 
00486         if (i->haveFrames) {
00487             if (i->startFrame >= ef) break;
00488             if (i->endFrame <= sf) continue;
00489         }
00490 
00491         int x0 = i->pixrect.x();
00492         int x1 = x0 + i->pixrect.width();
00493 
00494         if (i->haveFrames) {
00495             if (i->startFrame >= v->getStartFrame()) {
00496                 x0 = v->getXForFrame(i->startFrame);
00497             }
00498             if (i->endFrame <= int(v->getEndFrame())) {
00499                 x1 = v->getXForFrame(i->endFrame);
00500             }
00501         }
00502         
00503         i->pixrect = QRect(x0, i->pixrect.y(), x1 - x0, i->pixrect.height());
00504 
00505         updateMeasureRectYCoords(v, *i);
00506     }
00507 }
00508 
00509 void
00510 Layer::updateMeasureRectYCoords(View *v, const MeasureRect &r) const
00511 {
00512     int y0 = lrint(r.startY * v->height());
00513     int y1 = lrint(r.endY * v->height());
00514     r.pixrect = QRect(r.pixrect.x(), y0, r.pixrect.width(), y1 - y0);
00515 }
00516 
00517 void
00518 Layer::setMeasureRectYCoord(View *v, MeasureRect &r, bool start, int y) const
00519 {
00520     if (start) {
00521         r.startY = double(y) / double(v->height());
00522         r.endY = r.startY;
00523     } else {
00524         r.endY = double(y) / double(v->height());
00525     }
00526 }
00527 
00528 void
00529 Layer::setMeasureRectFromPixrect(View *v, MeasureRect &r, QRect pixrect) const
00530 {
00531     r.pixrect = pixrect;
00532     r.haveFrames = hasTimeXAxis();
00533     if (r.haveFrames) {
00534         r.startFrame = v->getFrameForX(pixrect.x());
00535         r.endFrame = v->getFrameForX(pixrect.x() + pixrect.width());
00536     }
00537     setMeasureRectYCoord(v, r, true, pixrect.y());
00538     setMeasureRectYCoord(v, r, false, pixrect.y() + pixrect.height());
00539 }
00540 
00541 Layer::MeasureRectSet::const_iterator
00542 Layer::findFocusedMeasureRect(QPoint focusPoint) const
00543 {
00544     float frDist = 0;
00545     MeasureRectSet::const_iterator focusRectItr = m_measureRects.end();
00546 
00547     for (MeasureRectSet::const_iterator i = m_measureRects.begin(); 
00548          i != m_measureRects.end(); ++i) {
00549 
00550         if (!i->pixrect.adjusted(-2, -2, 2, 2).contains(focusPoint)) continue;
00551 
00552         int cx = i->pixrect.x() + i->pixrect.width()/2;
00553         int cy = i->pixrect.y() + i->pixrect.height()/2;
00554         int xd = focusPoint.x() - cx;
00555         int yd = focusPoint.y() - cy;
00556         
00557         float d = sqrt(float(xd * xd + yd * yd));
00558         
00559         if (focusRectItr == m_measureRects.end() || d < frDist) {
00560             focusRectItr = i;
00561             frDist = d;
00562         }
00563     }
00564 
00565     return focusRectItr;
00566 }
00567 
00568 void
00569 Layer::paintMeasurementRect(View *v, QPainter &paint,
00570                             const MeasureRect &r, bool focus) const
00571 {
00572     if (r.haveFrames) {
00573         
00574         int x0 = -1;
00575         int x1 = v->width() + 1;
00576         
00577         if (r.startFrame >= v->getStartFrame()) {
00578             x0 = v->getXForFrame(r.startFrame);
00579         }
00580         if (r.endFrame <= v->getEndFrame()) {
00581             x1 = v->getXForFrame(r.endFrame);
00582         }
00583         
00584         QRect pr = QRect(x0, r.pixrect.y(), x1 - x0, r.pixrect.height());
00585         r.pixrect = pr;
00586     }
00587 
00588     v->drawMeasurementRect(paint, this, r.pixrect.normalized(), focus);
00589 }
00590 
00591 void
00592 Layer::toXml(QTextStream &stream,
00593              QString indent, QString extraAttributes) const
00594 {
00595     stream << indent;
00596 
00597     if (m_presentationName != "") {
00598         extraAttributes = QString("%1 presentationName=\"%2\"")
00599             .arg(extraAttributes).arg(encodeEntities(m_presentationName));
00600     }
00601 
00602     stream << QString("<layer id=\"%2\" type=\"%1\" name=\"%3\" model=\"%4\" %5")
00603         .arg(encodeEntities(LayerFactory::getInstance()->getLayerTypeName
00604                             (LayerFactory::getInstance()->getLayerType(this))))
00605         .arg(getObjectExportId(this))
00606         .arg(encodeEntities(objectName()))
00607         .arg(getObjectExportId(getModel()))
00608         .arg(extraAttributes);
00609 
00610     if (m_measureRects.empty()) {
00611         stream << QString("/>\n");
00612         return;
00613     }
00614 
00615     stream << QString(">\n");
00616 
00617     for (MeasureRectSet::const_iterator i = m_measureRects.begin();
00618          i != m_measureRects.end(); ++i) {
00619         i->toXml(stream, indent + "  ");
00620     }
00621 
00622     stream << QString("</layer>\n");
00623 }
00624 
00625 void
00626 Layer::toBriefXml(QTextStream &stream,
00627                   QString indent, QString extraAttributes) const
00628 {
00629     stream << indent;
00630 
00631     if (m_presentationName != "") {
00632         extraAttributes = QString("%1 presentationName=\"%2\"")
00633             .arg(extraAttributes).arg(encodeEntities(m_presentationName));
00634     }
00635 
00636     stream << QString("<layer id=\"%2\" type=\"%1\" name=\"%3\" model=\"%4\" %5/>\n")
00637         .arg(encodeEntities(LayerFactory::getInstance()->getLayerTypeName
00638                             (LayerFactory::getInstance()->getLayerType(this))))
00639         .arg(getObjectExportId(this))
00640         .arg(encodeEntities(objectName()))
00641         .arg(getObjectExportId(getModel()))
00642         .arg(extraAttributes);
00643 }
00644