"Fossies" - the Fresh Open Source Software Archive

Member "labplot-2.8.2/src/backend/worksheet/plots/cartesian/ReferenceLine.cpp" (24 Feb 2021, 19820 Bytes) of package /linux/privat/labplot-2.8.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ReferenceLine.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.8.1_vs_2.8.2.

    1 /***************************************************************************
    2     File                 : ReferenceLine.cpp
    3     Project              : LabPlot
    4     Description          : Custom user-defined point on the plot
    5     --------------------------------------------------------------------
    6     Copyright            : (C) 2020 Alexander Semke (alexander.semke@web.de)
    7  ***************************************************************************/
    8 
    9 /***************************************************************************
   10  *                                                                         *
   11  *  This program is free software; you can redistribute it and/or modify   *
   12  *  it under the terms of the GNU General Public License as published by   *
   13  *  the Free Software Foundation; either version 2 of the License, or      *
   14  *  (at your option) any later version.                                    *
   15  *                                                                         *
   16  *  This program is distributed in the hope that it will be useful,        *
   17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
   18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
   19  *  GNU General Public License for more details.                           *
   20  *                                                                         *
   21  *   You should have received a copy of the GNU General Public License     *
   22  *   along with this program; if not, write to the Free Software           *
   23  *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
   24  *   Boston, MA  02110-1301  USA                                           *
   25  *                                                                         *
   26  ***************************************************************************/
   27 
   28 #include "ReferenceLine.h"
   29 #include "ReferenceLinePrivate.h"
   30 #include "backend/worksheet/Worksheet.h"
   31 #include "backend/worksheet/plots/cartesian/CartesianPlot.h"
   32 #include "backend/worksheet/plots/cartesian/CartesianCoordinateSystem.h"
   33 #include "backend/lib/commandtemplates.h"
   34 #include "backend/lib/XmlStreamReader.h"
   35 #include "kdefrontend/GuiTools.h"
   36 
   37 #include <QActionGroup>
   38 #include <QPainter>
   39 #include <QMenu>
   40 #include <QGraphicsSceneMouseEvent>
   41 
   42 #include <KConfig>
   43 #include <KConfigGroup>
   44 #include <KLocalizedString>
   45 
   46 /**
   47  * \class ReferenceLine
   48  * \brief A customizable point.
   49  *
   50  * The position can be either specified by mouse events or by providing the
   51  * x- and y- coordinates in parent's coordinate system
   52  */
   53 
   54 ReferenceLine::ReferenceLine(const CartesianPlot* plot, const QString& name)
   55     : WorksheetElement(name, AspectType::ReferenceLine), d_ptr(new ReferenceLinePrivate(this, plot)) {
   56 
   57     init();
   58 }
   59 
   60 ReferenceLine::ReferenceLine(const QString& name, ReferenceLinePrivate* dd)
   61     : WorksheetElement(name, AspectType::ReferenceLine), d_ptr(dd) {
   62 
   63     init();
   64 }
   65 
   66 //no need to delete the d-pointer here - it inherits from QGraphicsItem
   67 //and is deleted during the cleanup in QGraphicsScene
   68 ReferenceLine::~ReferenceLine() = default;
   69 
   70 void ReferenceLine::init() {
   71     Q_D(ReferenceLine);
   72 
   73     KConfig config;
   74     KConfigGroup group;
   75     group = config.group("ReferenceLine");
   76 
   77     d->orientation = (Orientation)group.readEntry("Orientation", static_cast<int>(Orientation::Vertical));
   78     d->position = group.readEntry("Position", d->plot->xMin() + (d->plot->xMax() - d->plot->xMin())/2);
   79 
   80     d->pen.setStyle( (Qt::PenStyle) group.readEntry("Style", (int)Qt::SolidLine) );
   81     d->pen.setColor( group.readEntry("Color", QColor(Qt::black)) );
   82     d->pen.setWidthF( group.readEntry("Width", Worksheet::convertToSceneUnits(1.0, Worksheet::Unit::Point)) );
   83     d->opacity = group.readEntry("Opacity", 1.0);
   84 }
   85 
   86 /*!
   87     Returns an icon to be used in the project explorer.
   88 */
   89 QIcon ReferenceLine::icon() const {
   90     return  QIcon::fromTheme(QLatin1String("draw-line"));
   91 }
   92 
   93 void ReferenceLine::initActions() {
   94     visibilityAction = new QAction(i18n("Visible"), this);
   95     visibilityAction->setCheckable(true);
   96     connect(visibilityAction, &QAction::triggered, this, &ReferenceLine::visibilityChangedSlot);
   97 
   98     //Orientation
   99     auto* orientationActionGroup = new QActionGroup(this);
  100     orientationActionGroup->setExclusive(true);
  101     connect(orientationActionGroup, &QActionGroup::triggered, this, &ReferenceLine::orientationChangedSlot);
  102 
  103     orientationHorizontalAction = new QAction(QIcon::fromTheme(QLatin1String("labplot-axis-horizontal")), i18n("Horizontal"), orientationActionGroup);
  104     orientationHorizontalAction->setCheckable(true);
  105 
  106     orientationVerticalAction = new QAction(QIcon::fromTheme(QLatin1String("labplot-axis-vertical")), i18n("Vertical"), orientationActionGroup);
  107     orientationVerticalAction->setCheckable(true);
  108 
  109     //Line
  110     lineStyleActionGroup = new QActionGroup(this);
  111     lineStyleActionGroup->setExclusive(true);
  112     connect(lineStyleActionGroup, &QActionGroup::triggered, this, &ReferenceLine::lineStyleChanged);
  113 
  114     lineColorActionGroup = new QActionGroup(this);
  115     lineColorActionGroup->setExclusive(true);
  116     connect(lineColorActionGroup, &QActionGroup::triggered, this, &ReferenceLine::lineColorChanged);
  117 }
  118 
  119 void ReferenceLine::initMenus() {
  120     this->initActions();
  121 
  122     //Orientation
  123     orientationMenu = new QMenu(i18n("Orientation"));
  124     orientationMenu->setIcon(QIcon::fromTheme(QLatin1String("labplot-axis-horizontal")));
  125     orientationMenu->addAction(orientationHorizontalAction);
  126     orientationMenu->addAction(orientationVerticalAction);
  127 
  128     //Line
  129     lineMenu = new QMenu(i18n("Line"));
  130     lineMenu->setIcon(QIcon::fromTheme(QLatin1String("draw-line")));
  131     lineStyleMenu = new QMenu(i18n("Style"), lineMenu);
  132     lineStyleMenu->setIcon(QIcon::fromTheme(QLatin1String("object-stroke-style")));
  133     lineMenu->setIcon(QIcon::fromTheme(QLatin1String("draw-line")));
  134     lineMenu->addMenu(lineStyleMenu);
  135 
  136     lineColorMenu = new QMenu(i18n("Color"), lineMenu);
  137     lineColorMenu->setIcon(QIcon::fromTheme(QLatin1String("fill-color")));
  138     GuiTools::fillColorMenu(lineColorMenu, lineColorActionGroup);
  139     lineMenu->addMenu(lineColorMenu);
  140 }
  141 
  142 QMenu* ReferenceLine::createContextMenu() {
  143     if (!orientationMenu)
  144         initMenus();
  145 
  146     QMenu* menu = WorksheetElement::createContextMenu();
  147     QAction* firstAction = menu->actions().at(1); //skip the first action because of the "title-action"
  148     visibilityAction->setChecked(isVisible());
  149     menu->insertAction(firstAction, visibilityAction);
  150 
  151     Q_D(const ReferenceLine);
  152 
  153     //Orientation
  154     if (d->orientation == Orientation::Horizontal)
  155         orientationHorizontalAction->setChecked(true);
  156     else
  157         orientationVerticalAction->setChecked(true);
  158     menu->insertMenu(firstAction, orientationMenu);
  159 
  160     //Line styles
  161     GuiTools::updatePenStyles(lineStyleMenu, lineStyleActionGroup, d->pen.color());
  162     GuiTools::selectPenStyleAction(lineStyleActionGroup, d->pen.style());
  163     GuiTools::selectColorAction(lineColorActionGroup, d->pen.color() );
  164 
  165     menu->insertMenu(firstAction, lineMenu);
  166     menu->insertSeparator(firstAction);
  167 
  168     return menu;
  169 }
  170 
  171 QGraphicsItem* ReferenceLine::graphicsItem() const {
  172     return d_ptr;
  173 }
  174 
  175 void ReferenceLine::retransform() {
  176     Q_D(ReferenceLine);
  177     d->retransform();
  178 }
  179 
  180 void ReferenceLine::handleResize(double horizontalRatio, double verticalRatio, bool pageResize) {
  181     Q_UNUSED(horizontalRatio);
  182     Q_UNUSED(verticalRatio);
  183     Q_UNUSED(pageResize);
  184 }
  185 
  186 /* ============================ getter methods ================= */
  187 CLASS_SHARED_D_READER_IMPL(ReferenceLine, ReferenceLine::Orientation, orientation, orientation)
  188 BASIC_SHARED_D_READER_IMPL(ReferenceLine, double, position, position)
  189 CLASS_SHARED_D_READER_IMPL(ReferenceLine, QPen, pen, pen)
  190 BASIC_SHARED_D_READER_IMPL(ReferenceLine, qreal, opacity, opacity)
  191 
  192 /* ============================ setter methods and undo commands ================= */
  193 STD_SETTER_CMD_IMPL_F_S(ReferenceLine, SetOrientation, ReferenceLine::Orientation, orientation, retransform)
  194 void ReferenceLine::setOrientation(Orientation orientation) {
  195     Q_D(ReferenceLine);
  196     if (orientation != d->orientation)
  197         exec(new ReferenceLineSetOrientationCmd(d, orientation, ki18n("%1: set orientation")));
  198 }
  199 
  200 STD_SETTER_CMD_IMPL_F_S(ReferenceLine, SetPosition, double, position, retransform)
  201 void ReferenceLine::setPosition(double position) {
  202     Q_D(ReferenceLine);
  203     if (position != d->position)
  204         exec(new ReferenceLineSetPositionCmd(d, position, ki18n("%1: set position")));
  205 }
  206 
  207 STD_SETTER_CMD_IMPL_F_S(ReferenceLine, SetPen, QPen, pen, recalcShapeAndBoundingRect)
  208 void ReferenceLine::setPen(const QPen& pen) {
  209     Q_D(ReferenceLine);
  210     if (pen != d->pen)
  211         exec(new ReferenceLineSetPenCmd(d, pen, ki18n("%1: set line style")));
  212 }
  213 
  214 STD_SETTER_CMD_IMPL_F_S(ReferenceLine, SetOpacity, qreal, opacity, update);
  215 void ReferenceLine::setOpacity(qreal opacity) {
  216     Q_D(ReferenceLine);
  217     if (opacity != d->opacity)
  218         exec(new ReferenceLineSetOpacityCmd(d, opacity, ki18n("%1: set line opacity")));
  219 }
  220 
  221 STD_SWAP_METHOD_SETTER_CMD_IMPL_F(ReferenceLine, SetVisible, bool, swapVisible, update);
  222 void ReferenceLine::setVisible(bool on) {
  223     Q_D(ReferenceLine);
  224     exec(new ReferenceLineSetVisibleCmd(d, on, on ? ki18n("%1: set visible") : ki18n("%1: set invisible")));
  225 }
  226 
  227 bool ReferenceLine::isVisible() const {
  228     Q_D(const ReferenceLine);
  229     return d->isVisible();
  230 }
  231 
  232 void ReferenceLine::setPrinting(bool on) {
  233     Q_D(ReferenceLine);
  234     d->m_printing = on;
  235 }
  236 
  237 //##############################################################################
  238 //######  SLOTs for changes triggered via QActions in the context menu  ########
  239 //##############################################################################
  240 void ReferenceLine::orientationChangedSlot(QAction* action) {
  241     if (action == orientationHorizontalAction)
  242         this->setOrientation(Orientation::Horizontal);
  243     else
  244         this->setOrientation(Orientation::Vertical);
  245 }
  246 
  247 void ReferenceLine::lineStyleChanged(QAction* action) {
  248     Q_D(const ReferenceLine);
  249     QPen pen = d->pen;
  250     pen.setStyle(GuiTools::penStyleFromAction(lineStyleActionGroup, action));
  251     this->setPen(pen);
  252 }
  253 
  254 void ReferenceLine::lineColorChanged(QAction* action) {
  255     Q_D(const ReferenceLine);
  256     QPen pen = d->pen;
  257     pen.setColor(GuiTools::colorFromAction(lineColorActionGroup, action));
  258     this->setPen(pen);
  259 }
  260 
  261 void ReferenceLine::visibilityChangedSlot() {
  262     Q_D(const ReferenceLine);
  263     this->setVisible(!d->isVisible());
  264 }
  265 
  266 //##############################################################################
  267 //####################### Private implementation ###############################
  268 //##############################################################################
  269 ReferenceLinePrivate::ReferenceLinePrivate(ReferenceLine* owner, const CartesianPlot* p) : plot(p), q(owner) {
  270     setFlag(QGraphicsItem::ItemSendsGeometryChanges);
  271     setFlag(QGraphicsItem::ItemIsMovable);
  272     setFlag(QGraphicsItem::ItemIsSelectable);
  273     setAcceptHoverEvents(true);
  274 }
  275 
  276 QString ReferenceLinePrivate::name() const {
  277     return q->name();
  278 }
  279 
  280 /*!
  281     calculates the position and the bounding box of the item/point. Called on geometry or properties changes.
  282  */
  283 void ReferenceLinePrivate::retransform() {
  284     if (suppressRetransform)
  285         return;
  286 
  287     //calculate the position in the scene coordinates
  288     QVector<QPointF> listLogical;
  289     if (orientation == ReferenceLine::Orientation::Vertical)
  290         listLogical << QPointF(position, plot->yMin() + (plot->yMax() - plot->yMin())/2);
  291     else
  292         listLogical << QPointF(plot->xMin() + (plot->xMax() - plot->xMin())/2, position);
  293 
  294     const auto* cSystem = static_cast<const CartesianCoordinateSystem*>(plot->coordinateSystem());
  295     QVector<QPointF> listScene = cSystem->mapLogicalToScene(listLogical);
  296 
  297     if (!listScene.isEmpty()) {
  298         positionScene = listScene.at(0);
  299         m_visible = true;
  300         suppressItemChangeEvent = true;
  301         setPos(positionScene);
  302         suppressItemChangeEvent = false;
  303 
  304         //determine the length of the line to be drawn
  305         QVector<QPointF> pointsLogical;
  306         if (orientation == ReferenceLine::Orientation::Vertical)
  307             pointsLogical << QPointF(position, plot->yMin()) << QPointF(position, plot->yMax());
  308         else
  309             pointsLogical << QPointF(plot->xMin(), position) << QPointF(plot->xMax(), position);
  310 
  311         QVector<QPointF> pointsScene = cSystem->mapLogicalToScene(pointsLogical);
  312 
  313         if (pointsScene.size() > 1) {
  314             if (orientation == ReferenceLine::Orientation::Vertical)
  315                 length = pointsScene.at(0).y() - pointsScene.at(1).y();
  316             else
  317                 length = pointsScene.at(0).x() - pointsScene.at(1).x();
  318         }
  319     } else
  320         m_visible = false;
  321 
  322     recalcShapeAndBoundingRect();
  323 }
  324 
  325 bool ReferenceLinePrivate::swapVisible(bool on) {
  326     bool oldValue = isVisible();
  327 
  328     //When making a graphics item invisible, it gets deselected in the scene.
  329     //In this case we don't want to deselect the item in the project explorer.
  330     //We need to supress the deselection in the view.
  331     auto* worksheet = static_cast<Worksheet*>(q->parent(AspectType::Worksheet));
  332     worksheet->suppressSelectionChangedEvent(true);
  333     setVisible(on);
  334     worksheet->suppressSelectionChangedEvent(false);
  335 
  336 //  emit q->changed();
  337     emit q->visibleChanged(on);
  338     return oldValue;
  339 }
  340 
  341 /*!
  342     Returns the outer bounds of the item as a rectangle.
  343  */
  344 QRectF ReferenceLinePrivate::boundingRect() const {
  345     return boundingRectangle;
  346 }
  347 
  348 /*!
  349     Returns the shape of this item as a QPainterPath in local coordinates.
  350 */
  351 QPainterPath ReferenceLinePrivate::shape() const {
  352     return lineShape;
  353 }
  354 
  355 /*!
  356   recalculates the outer bounds and the shape of the item.
  357 */
  358 void ReferenceLinePrivate::recalcShapeAndBoundingRect() {
  359     prepareGeometryChange();
  360 
  361     lineShape = QPainterPath();
  362     if (m_visible) {
  363         QPainterPath path;
  364         if (orientation == ReferenceLine::Orientation::Horizontal) {
  365             path.moveTo(-length/2, 0);
  366             path.lineTo(length/2, 0);
  367         } else {
  368             path.moveTo(0, length/2);
  369             path.lineTo(0, -length/2);
  370         }
  371         lineShape.addPath(WorksheetElement::shapeFromPath(path, pen));
  372         boundingRectangle = lineShape.boundingRect();
  373     }
  374 }
  375 
  376 void ReferenceLinePrivate::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
  377     Q_UNUSED(option)
  378     Q_UNUSED(widget)
  379 
  380     if (!m_visible)
  381         return;
  382 
  383     painter->setOpacity(opacity);
  384     painter->setPen(pen);
  385     if (orientation == ReferenceLine::Orientation::Horizontal)
  386         painter->drawLine(-length/2, 0, length/2, 0);
  387     else
  388         painter->drawLine(0, length/2, 0, -length/2);
  389 
  390     if (m_hovered && !isSelected() && !m_printing) {
  391         painter->setPen(QPen(QApplication::palette().color(QPalette::Shadow), 2, Qt::SolidLine));
  392         painter->drawPath(lineShape);
  393     }
  394 
  395     if (isSelected() && !m_printing) {
  396         painter->setPen(QPen(QApplication::palette().color(QPalette::Highlight), 2, Qt::SolidLine));
  397         painter->drawPath(lineShape);
  398     }
  399 }
  400 
  401 QVariant ReferenceLinePrivate::itemChange(GraphicsItemChange change, const QVariant &value) {
  402     if (suppressItemChangeEvent)
  403         return value;
  404 
  405     if (change != QGraphicsItem::ItemPositionChange)
  406         return QGraphicsItem::itemChange(change, value);
  407 
  408     QPointF positionSceneNew = value.toPointF();
  409 
  410     //don't allow to move the line outside of the plot rect
  411     //in the direction orthogonal to the orientation of the line
  412     if (orientation == ReferenceLine::Orientation::Horizontal) {
  413         if (positionSceneNew.x() != positionScene.x())
  414             positionSceneNew.setX(positionScene.x());
  415     } else {
  416         if (positionSceneNew.y() != positionScene.y())
  417             positionSceneNew.setY(positionScene.y());
  418     }
  419 
  420     if (plot->dataRect().contains(positionSceneNew)) {
  421         //emit the signals in order to notify the UI (dock widget and status bar) about the new logical position.
  422         //we don't set the position related member variables during the mouse movements.
  423         //this is done on mouse release events only.
  424         const auto* cSystem = static_cast<const CartesianCoordinateSystem*>(plot->coordinateSystem());
  425         QPointF positionLogical = cSystem->mapSceneToLogical(positionSceneNew);
  426         if (orientation == ReferenceLine::Orientation::Horizontal) {
  427             emit q->positionChanged(positionLogical.y());
  428             emit q->statusInfo(QLatin1String("y=") + QString::number(positionLogical.y()));
  429         } else {
  430             emit q->positionChanged(positionLogical.x());
  431             emit q->statusInfo(QLatin1String("x=") + QString::number(positionLogical.x()));
  432         }
  433     } else {
  434         //line is moved outside of the plot, keep it at the plot boundary
  435         if (orientation == ReferenceLine::Orientation::Horizontal) {
  436             if (positionSceneNew.y() < plot->dataRect().y())
  437                 positionSceneNew.setY(plot->dataRect().y());
  438             else
  439                 positionSceneNew.setY(plot->dataRect().y() + plot->dataRect().height());
  440         } else {
  441             if (positionSceneNew.x() < plot->dataRect().x())
  442                 positionSceneNew.setX(plot->dataRect().x());
  443             else
  444                 positionSceneNew.setX(plot->dataRect().x() + plot->dataRect().width());
  445         }
  446     }
  447 
  448     return QGraphicsItem::itemChange(change, QVariant(positionSceneNew));
  449 }
  450 
  451 void ReferenceLinePrivate::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) {
  452     //position was changed -> set the position member variables
  453     suppressRetransform = true;
  454     const auto* cSystem = static_cast<const CartesianCoordinateSystem*>(plot->coordinateSystem());
  455     QPointF positionLogical = cSystem->mapSceneToLogical(pos());
  456     if (orientation == ReferenceLine::Orientation::Horizontal)
  457         q->setPosition(positionLogical.y());
  458     else
  459         q->setPosition(positionLogical.x());
  460     suppressRetransform = false;
  461 
  462     QGraphicsItem::mouseReleaseEvent(event);
  463 }
  464 
  465 void ReferenceLinePrivate::contextMenuEvent(QGraphicsSceneContextMenuEvent* event) {
  466     q->createContextMenu()->exec(event->screenPos());
  467 }
  468 
  469 void ReferenceLinePrivate::hoverEnterEvent(QGraphicsSceneHoverEvent*) {
  470     if (!isSelected()) {
  471         m_hovered = true;
  472         emit q->hovered();
  473         update();
  474     }
  475 }
  476 
  477 void ReferenceLinePrivate::hoverLeaveEvent(QGraphicsSceneHoverEvent*) {
  478     if (m_hovered) {
  479         m_hovered = false;
  480         emit q->unhovered();
  481         update();
  482     }
  483 }
  484 
  485 //##############################################################################
  486 //##################  Serialization/Deserialization  ###########################
  487 //##############################################################################
  488 //! Save as XML
  489 void ReferenceLine::save(QXmlStreamWriter* writer) const {
  490     Q_D(const ReferenceLine);
  491 
  492     writer->writeStartElement("referenceLine");
  493     writeBasicAttributes(writer);
  494     writeCommentElement(writer);
  495 
  496     writer->writeStartElement("general");
  497     writer->writeAttribute("orientation", QString::number(static_cast<int>(d->orientation)));
  498     writer->writeAttribute("position", QString::number(d->position));
  499     writer->writeAttribute("visible", QString::number(d->isVisible()));
  500     writer->writeEndElement();
  501 
  502     writer->writeStartElement("line");
  503     WRITE_QPEN(d->pen);
  504     writer->writeAttribute("opacity", QString::number(d->opacity));
  505     writer->writeEndElement();
  506 
  507     writer->writeEndElement(); // close "ReferenceLine" section
  508 }
  509 
  510 //! Load from XML
  511 bool ReferenceLine::load(XmlStreamReader* reader, bool preview) {
  512     Q_D(ReferenceLine);
  513 
  514     if (!readBasicAttributes(reader))
  515         return false;
  516 
  517     KLocalizedString attributeWarning = ki18n("Attribute '%1' missing or empty, default value is used");
  518     QXmlStreamAttributes attribs;
  519     QString str;
  520 
  521     while (!reader->atEnd()) {
  522         reader->readNext();
  523         if (reader->isEndElement() && reader->name() == "referenceLine")
  524             break;
  525 
  526         if (!reader->isStartElement())
  527             continue;
  528 
  529         if (!preview && reader->name() == "comment") {
  530             if (!readCommentElement(reader)) return false;
  531         } else if (!preview && reader->name() == "general") {
  532             attribs = reader->attributes();
  533             READ_DOUBLE_VALUE("position", position);
  534             READ_INT_VALUE("orientation", orientation, Orientation);
  535 
  536             str = attribs.value("visible").toString();
  537             if (str.isEmpty())
  538                 reader->raiseWarning(attributeWarning.subs("visible").toString());
  539             else
  540                 d->setVisible(str.toInt());
  541         } else if (!preview && reader->name() == "line") {
  542             attribs = reader->attributes();
  543             READ_QPEN(d->pen);
  544             READ_DOUBLE_VALUE("opacity", opacity);
  545         } else { // unknown element
  546             reader->raiseWarning(i18n("unknown element '%1'", reader->name().toString()));
  547             if (!reader->skipToEndElement()) return false;
  548         }
  549     }
  550 
  551     if (!preview)
  552         retransform();
  553 
  554     return true;
  555 }