Chris@127: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@127: Chris@127: /* Chris@127: Sonic Visualiser Chris@127: An audio file viewer and annotation editor. Chris@127: Centre for Digital Music, Queen Mary, University of London. Chris@182: This file copyright 2006 Chris Cannam and QMUL. Chris@127: Chris@127: This program is free software; you can redistribute it and/or Chris@127: modify it under the terms of the GNU General Public License as Chris@127: published by the Free Software Foundation; either version 2 of the Chris@127: License, or (at your option) any later version. See the file Chris@127: COPYING included with this distribution for more information. Chris@127: */ Chris@127: Chris@127: #include "Layer.h" Chris@128: #include "view/View.h" Chris@128: #include "data/model/Model.h" Chris@376: #include "widgets/CommandHistory.h" Chris@127: Chris@127: #include Chris@127: Chris@131: #include Chris@267: #include Chris@316: #include Chris@131: Chris@326: #include Chris@326: #include Chris@326: #include Chris@326: #include Chris@326: Chris@131: #include "LayerFactory.h" Chris@128: #include "base/PlayParameterRepository.h" Chris@127: Chris@272: #include Chris@272: Chris@267: Layer::Layer() : Chris@283: m_haveDraggingRect(false), Chris@283: m_haveCurrentMeasureRect(false) Chris@127: { Chris@127: } Chris@127: Chris@127: Layer::~Layer() Chris@127: { Chris@587: // SVDEBUG << "Layer::~Layer(" << this << ")" << endl; Chris@127: } Chris@127: Chris@320: void Chris@320: Layer::connectSignals(const Model *model) Chris@320: { Chris@320: connect(model, SIGNAL(modelChanged()), Chris@320: this, SIGNAL(modelChanged())); Chris@320: Chris@908: connect(model, SIGNAL(modelChangedWithin(sv_frame_t, sv_frame_t)), Chris@908: this, SIGNAL(modelChangedWithin(sv_frame_t, sv_frame_t))); Chris@320: Chris@320: connect(model, SIGNAL(completionChanged()), Chris@320: this, SIGNAL(modelCompletionChanged())); Chris@320: Chris@320: connect(model, SIGNAL(alignmentCompletionChanged()), Chris@320: this, SIGNAL(modelAlignmentCompletionChanged())); Chris@320: } Chris@320: Chris@127: QString Chris@127: Layer::getPropertyContainerIconName() const Chris@127: { Chris@127: return LayerFactory::getInstance()->getLayerIconName Chris@127: (LayerFactory::getInstance()->getLayerType(this)); Chris@127: } Chris@127: Chris@363: void Chris@363: Layer::setPresentationName(QString name) Chris@363: { Chris@363: m_presentationName = name; Chris@363: } Chris@363: Chris@127: QString Chris@127: Layer::getLayerPresentationName() const Chris@127: { Chris@363: if (m_presentationName != "") return m_presentationName; Chris@203: Chris@203: LayerFactory *factory = LayerFactory::getInstance(); Chris@203: QString layerName = factory->getLayerPresentationName Chris@203: (factory->getLayerType(this)); Chris@203: Chris@127: QString modelName; Chris@127: if (getModel()) modelName = getModel()->objectName(); Chris@127: Chris@127: QString text; Chris@127: if (modelName != "") { Chris@127: text = QString("%1: %2").arg(modelName).arg(layerName); Chris@127: } else { Chris@127: text = layerName; Chris@127: } Chris@127: Chris@127: return text; Chris@127: } Chris@127: Chris@127: void Chris@127: Layer::setObjectName(const QString &name) Chris@127: { Chris@127: QObject::setObjectName(name); Chris@127: emit layerNameChanged(); Chris@127: } Chris@127: Chris@127: PlayParameters * Chris@127: Layer::getPlayParameters() Chris@127: { Chris@682: // cerr << "Layer (" << this << ", " << objectName() << ")::getPlayParameters: model is "<< getModel() << endl; Chris@127: const Model *model = getModel(); Chris@127: if (model) { Chris@127: return PlayParameterRepository::getInstance()->getPlayParameters(model); Chris@127: } Chris@127: return 0; Chris@127: } Chris@127: Chris@127: void Chris@131: Layer::setLayerDormant(const View *v, bool dormant) Chris@131: { Chris@131: const void *vv = (const void *)v; Chris@131: QMutexLocker locker(&m_dormancyMutex); Chris@131: m_dormancy[vv] = dormant; Chris@131: } Chris@131: Chris@131: bool Chris@131: Layer::isLayerDormant(const View *v) const Chris@131: { Chris@131: const void *vv = (const void *)v; Chris@131: QMutexLocker locker(&m_dormancyMutex); Chris@131: if (m_dormancy.find(vv) == m_dormancy.end()) return false; Chris@131: return m_dormancy.find(vv)->second; Chris@131: } Chris@131: Chris@131: void Chris@127: Layer::showLayer(View *view, bool show) Chris@127: { Chris@127: setLayerDormant(view, !show); Chris@127: emit layerParametersChanged(); Chris@127: } Chris@127: Chris@260: bool Chris@904: Layer::getXScaleValue(const View *v, int x, double &value, QString &unit) const Chris@260: { Chris@260: if (!hasTimeXAxis()) return false; Chris@260: Chris@260: const Model *m = getModel(); Chris@260: if (!m) return false; Chris@260: Chris@904: value = double(v->getFrameForX(x)) / m->getSampleRate(); Chris@260: unit = "s"; Chris@260: return true; Chris@260: } Chris@260: Chris@268: bool Chris@274: Layer::getYScaleDifference(const View *v, int y0, int y1, Chris@904: double &diff, QString &unit) const Chris@274: { Chris@904: double v0, v1; Chris@274: if (!getYScaleValue(v, y0, v0, unit) || Chris@274: !getYScaleValue(v, y1, v1, unit)) { Chris@274: diff = 0.f; Chris@274: return false; Chris@274: } Chris@904: diff = fabs(v1 - v0); Chris@274: return true; Chris@274: } Chris@274: Chris@904: sv_frame_t Chris@904: Layer::alignToReference(View *v, sv_frame_t frame) const Chris@359: { Chris@359: const Model *m = getModel(); Chris@587: SVDEBUG << "Layer::alignToReference(" << frame << "): model = " << m << ", alignment reference = " << (m ? m->getAlignmentReference() : 0) << endl; Chris@359: if (m && m->getAlignmentReference()) { Chris@359: return m->alignToReference(frame); Chris@359: } else { Chris@359: return v->alignToReference(frame); Chris@359: } Chris@359: } Chris@359: Chris@904: sv_frame_t Chris@904: Layer::alignFromReference(View *v, sv_frame_t frame) const Chris@359: { Chris@359: const Model *m = getModel(); Chris@587: SVDEBUG << "Layer::alignFromReference(" << frame << "): model = " << m << ", alignment reference = " << (m ? m->getAlignmentReference() : 0) << endl; Chris@359: if (m && m->getAlignmentReference()) { Chris@359: return m->alignFromReference(frame); Chris@359: } else { Chris@359: return v->alignFromReference(frame); Chris@359: } Chris@359: } Chris@359: Chris@274: bool Chris@360: Layer::clipboardHasDifferentAlignment(View *v, const Clipboard &clip) const Chris@360: { Chris@360: // Notes on pasting to an aligned layer: Chris@360: // Chris@360: // Each point may have a reference frame that may differ from the Chris@360: // point's given frame (in its source model). If it has no Chris@360: // reference frame, we have to assume the source model was not Chris@360: // aligned or was the reference model: when cutting or copying Chris@360: // points from a layer, we must always set their reference frame Chris@360: // correctly if we are aligned. Chris@360: // Chris@360: // When pasting: Chris@360: // - if point's reference and aligned frames differ: Chris@360: // - if this layer is aligned: Chris@360: // - if point's aligned frame matches this layer's aligned version Chris@360: // of point's reference frame: Chris@360: // - we can paste at reference frame or our frame Chris@360: // - else Chris@360: // - we can paste at reference frame, result of aligning reference Chris@360: // frame in our model, or literal source frame Chris@360: // - else Chris@360: // - we can paste at reference (our) frame, or literal source frame Chris@360: // - else Chris@360: // - if this layer is aligned: Chris@360: // - we can paste at reference (point's only available) frame, Chris@360: // or result of aligning reference frame in our model Chris@360: // - else Chris@360: // - we can only paste at reference frame Chris@360: // Chris@360: // Which of these alternatives are useful? Chris@360: // Chris@360: // Example: we paste between two tracks that are aligned to the Chris@360: // same reference, and the points are at 10s and 20s in the source Chris@360: // track, corresponding to 5s and 10s in the reference but 20s and Chris@360: // 30s in the target track. Chris@360: // Chris@360: // The obvious default is to paste at 20s and 30s; if we aren't Chris@360: // doing that, would it be better to paste at 5s and 10s or at 10s Chris@360: // and 20s? We probably don't ever want to do the former, do we? Chris@360: // We either want to be literal all the way through, or aligned Chris@360: // all the way through. Chris@360: Chris@360: for (Clipboard::PointList::const_iterator i = clip.getPoints().begin(); Chris@360: i != clip.getPoints().end(); ++i) { Chris@360: Chris@360: // In principle, we want to know whether the aligned version Chris@360: // of the reference frame in our layer is the same as the Chris@360: // source frame contained in the clipboard point. However, Chris@360: // because of rounding during alignment, that won't Chris@360: // necessarily be the case even if the clipboard point came Chris@360: // from our layer! What we need to check is whether, if we Chris@360: // aligned the clipboard point's frame back to the reference Chris@360: // using this layer's alignment, we would obtain the same Chris@360: // reference frame as that for the clipboard point. Chris@360: Chris@360: // What if the clipboard point has no reference frame? Then Chris@360: // we have to treat it as having its own frame as the Chris@360: // reference (i.e. having been copied from the reference Chris@360: // model). Chris@360: Chris@905: sv_frame_t sourceFrame = i->getFrame(); Chris@905: sv_frame_t referenceFrame = sourceFrame; Chris@360: if (i->haveReferenceFrame()) { Chris@360: referenceFrame = i->getReferenceFrame(); Chris@360: } Chris@905: sv_frame_t myMappedFrame = alignToReference(v, sourceFrame); Chris@360: Chris@682: // cerr << "sourceFrame = " << sourceFrame << ", referenceFrame = " << referenceFrame << " (have = " << i->haveReferenceFrame() << "), myMappedFrame = " << myMappedFrame << endl; Chris@360: Chris@360: if (myMappedFrame != referenceFrame) return true; Chris@360: } Chris@360: Chris@360: return false; Chris@360: } Chris@360: Chris@360: bool Chris@268: Layer::MeasureRect::operator<(const MeasureRect &mr) const Chris@268: { Chris@268: if (haveFrames) { Chris@268: if (startFrame == mr.startFrame) { Chris@268: if (endFrame != mr.endFrame) { Chris@268: return endFrame < mr.endFrame; Chris@268: } Chris@268: } else { Chris@268: return startFrame < mr.startFrame; Chris@268: } Chris@268: } else { Chris@268: if (pixrect.x() == mr.pixrect.x()) { Chris@268: if (pixrect.width() != mr.pixrect.width()) { Chris@268: return pixrect.width() < mr.pixrect.width(); Chris@268: } Chris@268: } else { Chris@268: return pixrect.x() < mr.pixrect.x(); Chris@268: } Chris@268: } Chris@268: Chris@268: // the two rects are equal in x and width Chris@268: Chris@268: if (pixrect.y() == mr.pixrect.y()) { Chris@268: return pixrect.height() < mr.pixrect.height(); Chris@268: } else { Chris@268: return pixrect.y() < mr.pixrect.y(); Chris@268: } Chris@268: } Chris@268: Chris@316: void Chris@316: Layer::MeasureRect::toXml(QTextStream &stream, QString indent) const Chris@269: { Chris@316: stream << indent; Chris@316: stream << QString("\n") Chris@273: .arg(startY).arg(endY); Chris@269: } Chris@269: Chris@269: void Chris@269: Layer::addMeasurementRect(const QXmlAttributes &attributes) Chris@269: { Chris@269: MeasureRect rect; Chris@269: QString fs = attributes.value("startFrame"); Chris@273: int x0 = 0, x1 = 0; Chris@269: if (fs != "") { Chris@806: rect.startFrame = fs.toInt(); Chris@806: rect.endFrame = attributes.value("endFrame").toInt(); Chris@269: rect.haveFrames = true; Chris@269: } else { Chris@269: x0 = attributes.value("startX").toInt(); Chris@269: x1 = attributes.value("endX").toInt(); Chris@269: rect.haveFrames = false; Chris@269: } Chris@273: rect.startY = attributes.value("startY").toDouble(); Chris@273: rect.endY = attributes.value("endY").toDouble(); Chris@273: rect.pixrect = QRect(x0, 0, x1 - x0, 0); Chris@269: addMeasureRectToSet(rect); Chris@269: } Chris@269: Chris@269: QString Chris@268: Layer::AddMeasurementRectCommand::getName() const Chris@268: { Chris@268: return tr("Make Measurement"); Chris@268: } Chris@268: Chris@268: void Chris@268: Layer::AddMeasurementRectCommand::execute() Chris@268: { Chris@269: m_layer->addMeasureRectToSet(m_rect); Chris@268: } Chris@268: Chris@268: void Chris@268: Layer::AddMeasurementRectCommand::unexecute() Chris@268: { Chris@269: m_layer->deleteMeasureRectFromSet(m_rect); Chris@268: } Chris@268: Chris@283: QString Chris@283: Layer::DeleteMeasurementRectCommand::getName() const Chris@283: { Chris@283: return tr("Delete Measurement"); Chris@283: } Chris@283: Chris@283: void Chris@283: Layer::DeleteMeasurementRectCommand::execute() Chris@283: { Chris@283: m_layer->deleteMeasureRectFromSet(m_rect); Chris@283: } Chris@283: Chris@283: void Chris@283: Layer::DeleteMeasurementRectCommand::unexecute() Chris@283: { Chris@283: m_layer->addMeasureRectToSet(m_rect); Chris@283: } Chris@283: Chris@267: void Chris@267: Layer::measureStart(View *v, QMouseEvent *e) Chris@267: { Chris@283: setMeasureRectFromPixrect(v, m_draggingRect, Chris@283: QRect(e->x(), e->y(), 0, 0)); Chris@267: m_haveDraggingRect = true; Chris@267: } Chris@267: Chris@267: void Chris@267: Layer::measureDrag(View *v, QMouseEvent *e) Chris@267: { Chris@267: if (!m_haveDraggingRect) return; Chris@268: Chris@283: setMeasureRectFromPixrect(v, m_draggingRect, Chris@283: QRect(m_draggingRect.pixrect.x(), Chris@283: m_draggingRect.pixrect.y(), Chris@283: e->x() - m_draggingRect.pixrect.x(), Chris@283: e->y() - m_draggingRect.pixrect.y())); Chris@267: } Chris@267: Chris@267: void Chris@267: Layer::measureEnd(View *v, QMouseEvent *e) Chris@267: { Chris@267: if (!m_haveDraggingRect) return; Chris@267: measureDrag(v, e); Chris@283: Chris@283: if (!m_draggingRect.pixrect.isNull()) { Chris@283: CommandHistory::getInstance()->addCommand Chris@283: (new AddMeasurementRectCommand(this, m_draggingRect)); Chris@283: } Chris@268: Chris@267: m_haveDraggingRect = false; Chris@267: } Chris@267: Chris@267: void Chris@805: Layer::measureDoubleClick(View *, QMouseEvent *) Chris@280: { Chris@283: // nothing, in the base class Chris@283: } Chris@283: Chris@283: void Chris@283: Layer::deleteCurrentMeasureRect() Chris@283: { Chris@283: if (!m_haveCurrentMeasureRect) return; Chris@283: Chris@283: MeasureRectSet::const_iterator focusRectItr = Chris@283: findFocusedMeasureRect(m_currentMeasureRectPoint); Chris@283: Chris@283: if (focusRectItr == m_measureRects.end()) return; Chris@283: Chris@283: CommandHistory::getInstance()->addCommand Chris@283: (new DeleteMeasurementRectCommand(this, *focusRectItr)); Chris@280: } Chris@280: Chris@280: void Chris@272: Layer::paintMeasurementRects(View *v, QPainter &paint, Chris@272: bool showFocus, QPoint focusPoint) const Chris@267: { Chris@273: updateMeasurePixrects(v); Chris@272: Chris@272: MeasureRectSet::const_iterator focusRectItr = m_measureRects.end(); Chris@272: Chris@267: if (m_haveDraggingRect) { Chris@272: Chris@270: paintMeasurementRect(v, paint, m_draggingRect, true); Chris@272: Chris@272: } else if (showFocus) { Chris@272: Chris@272: focusRectItr = findFocusedMeasureRect(focusPoint); Chris@267: } Chris@267: Chris@283: m_haveCurrentMeasureRect = false; Chris@283: Chris@268: for (MeasureRectSet::const_iterator i = m_measureRects.begin(); Chris@268: i != m_measureRects.end(); ++i) { Chris@283: Chris@283: bool focused = (i == focusRectItr); Chris@283: paintMeasurementRect(v, paint, *i, focused); Chris@283: Chris@283: if (focused) { Chris@283: m_haveCurrentMeasureRect = true; Chris@283: m_currentMeasureRectPoint = focusPoint; Chris@283: } Chris@267: } Chris@267: } Chris@267: Chris@272: bool Chris@272: Layer::nearestMeasurementRectChanged(View *v, QPoint prev, QPoint now) const Chris@272: { Chris@273: updateMeasurePixrects(v); Chris@272: Chris@272: MeasureRectSet::const_iterator i0 = findFocusedMeasureRect(prev); Chris@272: MeasureRectSet::const_iterator i1 = findFocusedMeasureRect(now); Chris@272: Chris@272: return (i0 != i1); Chris@272: } Chris@272: Chris@272: void Chris@273: Layer::updateMeasurePixrects(View *v) const Chris@272: { Chris@905: sv_frame_t sf = v->getStartFrame(); Chris@905: sv_frame_t ef = v->getEndFrame(); Chris@272: Chris@272: for (MeasureRectSet::const_iterator i = m_measureRects.begin(); Chris@272: i != m_measureRects.end(); ++i) { Chris@272: Chris@273: // This logic depends on the fact that if one measure rect in Chris@273: // a layer has frame values, they all will. That is in fact Chris@273: // the case, because haveFrames is based on whether the layer Chris@273: // hasTimeXAxis() or not. Measure rect ordering in the rect Chris@273: // set wouldn't work correctly either, if haveFrames could Chris@273: // vary. Chris@272: Chris@273: if (i->haveFrames) { Chris@273: if (i->startFrame >= ef) break; Chris@273: if (i->endFrame <= sf) continue; Chris@273: } Chris@272: Chris@273: int x0 = i->pixrect.x(); Chris@273: int x1 = x0 + i->pixrect.width(); Chris@273: Chris@273: if (i->haveFrames) { Chris@273: if (i->startFrame >= v->getStartFrame()) { Chris@273: x0 = v->getXForFrame(i->startFrame); Chris@273: } Chris@806: if (i->endFrame <= int(v->getEndFrame())) { Chris@273: x1 = v->getXForFrame(i->endFrame); Chris@273: } Chris@272: } Chris@272: Chris@273: i->pixrect = QRect(x0, i->pixrect.y(), x1 - x0, i->pixrect.height()); Chris@273: Chris@273: updateMeasureRectYCoords(v, *i); Chris@273: } Chris@273: } Chris@273: Chris@273: void Chris@273: Layer::updateMeasureRectYCoords(View *v, const MeasureRect &r) const Chris@273: { Chris@905: int y0 = int(lrint(r.startY * v->height())); Chris@905: int y1 = int(lrint(r.endY * v->height())); Chris@273: r.pixrect = QRect(r.pixrect.x(), y0, r.pixrect.width(), y1 - y0); Chris@273: } Chris@273: Chris@273: void Chris@273: Layer::setMeasureRectYCoord(View *v, MeasureRect &r, bool start, int y) const Chris@273: { Chris@273: if (start) { Chris@273: r.startY = double(y) / double(v->height()); Chris@273: r.endY = r.startY; Chris@273: } else { Chris@273: r.endY = double(y) / double(v->height()); Chris@272: } Chris@272: } Chris@272: Chris@283: void Chris@283: Layer::setMeasureRectFromPixrect(View *v, MeasureRect &r, QRect pixrect) const Chris@283: { Chris@283: r.pixrect = pixrect; Chris@283: r.haveFrames = hasTimeXAxis(); Chris@283: if (r.haveFrames) { Chris@283: r.startFrame = v->getFrameForX(pixrect.x()); Chris@283: r.endFrame = v->getFrameForX(pixrect.x() + pixrect.width()); Chris@283: } Chris@283: setMeasureRectYCoord(v, r, true, pixrect.y()); Chris@283: setMeasureRectYCoord(v, r, false, pixrect.y() + pixrect.height()); Chris@283: } Chris@283: Chris@272: Layer::MeasureRectSet::const_iterator Chris@272: Layer::findFocusedMeasureRect(QPoint focusPoint) const Chris@272: { Chris@904: double frDist = 0; Chris@272: MeasureRectSet::const_iterator focusRectItr = m_measureRects.end(); Chris@272: Chris@272: for (MeasureRectSet::const_iterator i = m_measureRects.begin(); Chris@272: i != m_measureRects.end(); ++i) { Chris@272: Chris@272: if (!i->pixrect.adjusted(-2, -2, 2, 2).contains(focusPoint)) continue; Chris@272: Chris@272: int cx = i->pixrect.x() + i->pixrect.width()/2; Chris@272: int cy = i->pixrect.y() + i->pixrect.height()/2; Chris@272: int xd = focusPoint.x() - cx; Chris@272: int yd = focusPoint.y() - cy; Chris@272: Chris@904: double d = sqrt(double(xd * xd + yd * yd)); Chris@272: Chris@272: if (focusRectItr == m_measureRects.end() || d < frDist) { Chris@272: focusRectItr = i; Chris@272: frDist = d; Chris@272: } Chris@272: } Chris@272: Chris@272: return focusRectItr; Chris@272: } Chris@272: Chris@268: void Chris@270: Layer::paintMeasurementRect(View *v, QPainter &paint, Chris@270: const MeasureRect &r, bool focus) const Chris@268: { Chris@268: if (r.haveFrames) { Chris@268: Chris@268: int x0 = -1; Chris@268: int x1 = v->width() + 1; Chris@268: Chris@268: if (r.startFrame >= v->getStartFrame()) { Chris@268: x0 = v->getXForFrame(r.startFrame); Chris@268: } Chris@806: if (r.endFrame <= v->getEndFrame()) { Chris@268: x1 = v->getXForFrame(r.endFrame); Chris@268: } Chris@268: Chris@272: QRect pr = QRect(x0, r.pixrect.y(), x1 - x0, r.pixrect.height()); Chris@268: r.pixrect = pr; Chris@268: } Chris@274: Chris@274: v->drawMeasurementRect(paint, this, r.pixrect.normalized(), focus); Chris@268: } Chris@268: Chris@316: void Chris@316: Layer::toXml(QTextStream &stream, Chris@316: QString indent, QString extraAttributes) const Chris@268: { Chris@316: stream << indent; Chris@268: Chris@363: if (m_presentationName != "") { Chris@363: extraAttributes = QString("%1 presentationName=\"%2\"") Chris@363: .arg(extraAttributes).arg(encodeEntities(m_presentationName)); Chris@363: } Chris@363: Chris@316: stream << QString("getLayerTypeName Chris@268: (LayerFactory::getInstance()->getLayerType(this)))) Chris@268: .arg(getObjectExportId(this)) Chris@268: .arg(encodeEntities(objectName())) Chris@268: .arg(getObjectExportId(getModel())) Chris@268: .arg(extraAttributes); Chris@268: Chris@269: if (m_measureRects.empty()) { Chris@316: stream << QString("/>\n"); Chris@316: return; Chris@269: } Chris@269: Chris@316: stream << QString(">\n"); Chris@269: Chris@269: for (MeasureRectSet::const_iterator i = m_measureRects.begin(); Chris@269: i != m_measureRects.end(); ++i) { Chris@316: i->toXml(stream, indent + " "); Chris@269: } Chris@269: Chris@316: stream << QString("\n"); Chris@268: } Chris@269: Chris@316: void Chris@316: Layer::toBriefXml(QTextStream &stream, Chris@316: QString indent, QString extraAttributes) const Chris@269: { Chris@316: stream << indent; Chris@269: Chris@363: if (m_presentationName != "") { Chris@363: extraAttributes = QString("%1 presentationName=\"%2\"") Chris@363: .arg(extraAttributes).arg(encodeEntities(m_presentationName)); Chris@363: } Chris@363: Chris@316: stream << QString("\n") Chris@269: .arg(encodeEntities(LayerFactory::getInstance()->getLayerTypeName Chris@269: (LayerFactory::getInstance()->getLayerType(this)))) Chris@269: .arg(getObjectExportId(this)) Chris@269: .arg(encodeEntities(objectName())) Chris@269: .arg(getObjectExportId(getModel())) Chris@269: .arg(extraAttributes); Chris@269: } Chris@269: