File indexing completed on 2024-05-12 15:27:31
0001 /*************************************************************************** 0002 File : Image.cpp 0003 Project : LabPlot 0004 Description : Worksheet element to draw images 0005 -------------------------------------------------------------------- 0006 Copyright : (C) 2019 Alexander Semke (alexander.semke@web.de) 0007 ***************************************************************************/ 0008 0009 /*************************************************************************** 0010 * * 0011 * This program is free software; you can redistribute it and/or modify * 0012 * it under the terms of the GNU General Public License as published by * 0013 * the Free Software Foundation; either version 2 of the License, or * 0014 * (at your option) any later version. * 0015 * * 0016 * This program is distributed in the hope that it will be useful, * 0017 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0019 * GNU General Public License for more details. * 0020 * * 0021 * You should have received a copy of the GNU General Public License * 0022 * along with this program; if not, write to the Free Software * 0023 * Foundation, Inc., 51 Franklin Street, Fifth Floor, * 0024 * Boston, MA 02110-1301 USA * 0025 * * 0026 ***************************************************************************/ 0027 0028 #include "Image.h" 0029 #include "Worksheet.h" 0030 #include "ImagePrivate.h" 0031 #include "backend/lib/commandtemplates.h" 0032 #include "backend/lib/XmlStreamReader.h" 0033 0034 #include <QPainter> 0035 #include <QGraphicsScene> 0036 #include <QGraphicsSceneMouseEvent> 0037 #include <QMenu> 0038 0039 #include <QIcon> 0040 #include <KConfig> 0041 #include <KConfigGroup> 0042 #include <KLocalizedString> 0043 0044 /** 0045 * \class Image 0046 * \brief A label supporting rendering of html- and tex-formatted texts. 0047 * 0048 * The label is aligned relative to the specified position. 0049 * The position can be either specified by providing the x- and y- coordinates 0050 * in parent's coordinate system, or by specifying one of the predefined position 0051 * flags (\c HorizontalPosition, \c VerticalPosition). 0052 */ 0053 0054 0055 Image::Image(const QString& name) 0056 : WorksheetElement(name, AspectType::Image), d_ptr(new ImagePrivate(this)) { 0057 0058 init(); 0059 } 0060 0061 Image::Image(const QString &name, ImagePrivate *dd) 0062 : WorksheetElement(name, AspectType::Image), d_ptr(dd) { 0063 0064 init(); 0065 } 0066 0067 void Image::init() { 0068 Q_D(Image); 0069 0070 KConfig config; 0071 KConfigGroup group = config.group("Image"); 0072 0073 d->opacity = group.readEntry("opacity", d->opacity); 0074 0075 //geometry 0076 d->position.point.setX( group.readEntry("PositionXValue", d->position.point.x()) ); 0077 d->position.point.setY( group.readEntry("PositionYValue", d->position.point.y()) ); 0078 d->position.horizontalPosition = (WorksheetElement::HorizontalPosition) group.readEntry("PositionX", (int)d->position.horizontalPosition); 0079 d->position.verticalPosition = (WorksheetElement::VerticalPosition) group.readEntry("PositionY", (int)d->position.verticalPosition); 0080 d->horizontalAlignment = (WorksheetElement::HorizontalAlignment) group.readEntry("HorizontalAlignment", (int)d->horizontalAlignment); 0081 d->verticalAlignment = (WorksheetElement::VerticalAlignment) group.readEntry("VerticalAlignment", (int)d->verticalAlignment); 0082 d->rotationAngle = group.readEntry("Rotation", d->rotationAngle); 0083 0084 //border 0085 d->borderPen = QPen(group.readEntry("BorderColor", d->borderPen.color()), 0086 group.readEntry("BorderWidth", d->borderPen.widthF()), 0087 (Qt::PenStyle) group.readEntry("BorderStyle", (int)(d->borderPen.style()))); 0088 d->borderOpacity = group.readEntry("BorderOpacity", d->borderOpacity); 0089 0090 //initial placeholder image 0091 d->image = QIcon::fromTheme("viewimage").pixmap(d->width, d->height).toImage(); 0092 } 0093 0094 //no need to delete the d-pointer here - it inherits from QGraphicsItem 0095 //and is deleted during the cleanup in QGraphicsScene 0096 Image::~Image() = default; 0097 0098 QGraphicsItem* Image::graphicsItem() const { 0099 return d_ptr; 0100 } 0101 0102 void Image::setParentGraphicsItem(QGraphicsItem* item) { 0103 Q_D(Image); 0104 d->setParentItem(item); 0105 d->updatePosition(); 0106 } 0107 0108 void Image::retransform() { 0109 Q_D(Image); 0110 d->retransform(); 0111 } 0112 0113 void Image::handleResize(double horizontalRatio, double verticalRatio, bool pageResize) { 0114 DEBUG("Image::handleResize()"); 0115 Q_UNUSED(pageResize); 0116 Q_UNUSED(horizontalRatio); 0117 Q_UNUSED(verticalRatio); 0118 // Q_D(Image); 0119 0120 // double ratio = 0; 0121 // if (horizontalRatio > 1.0 || verticalRatio > 1.0) 0122 // ratio = qMax(horizontalRatio, verticalRatio); 0123 // else 0124 // ratio = qMin(horizontalRatio, verticalRatio); 0125 } 0126 0127 /*! 0128 Returns an icon to be used in the project explorer. 0129 */ 0130 QIcon Image::icon() const{ 0131 return QIcon::fromTheme("viewimage"); 0132 } 0133 0134 QMenu* Image::createContextMenu() { 0135 QMenu *menu = WorksheetElement::createContextMenu(); 0136 QAction* firstAction = menu->actions().at(1); //skip the first action because of the "title-action" 0137 0138 if (!visibilityAction) { 0139 visibilityAction = new QAction(i18n("Visible"), this); 0140 visibilityAction->setCheckable(true); 0141 connect(visibilityAction, &QAction::triggered, this, &Image::visibilityChanged); 0142 } 0143 0144 visibilityAction->setChecked(isVisible()); 0145 menu->insertAction(firstAction, visibilityAction); 0146 menu->insertSeparator(firstAction); 0147 0148 return menu; 0149 } 0150 0151 /* ============================ getter methods ================= */ 0152 CLASS_SHARED_D_READER_IMPL(Image, QString, fileName, fileName) 0153 BASIC_SHARED_D_READER_IMPL(Image, qreal, opacity, opacity) 0154 BASIC_SHARED_D_READER_IMPL(Image, int, width, width) 0155 BASIC_SHARED_D_READER_IMPL(Image, int, height, height) 0156 BASIC_SHARED_D_READER_IMPL(Image, bool, keepRatio, keepRatio) 0157 CLASS_SHARED_D_READER_IMPL(Image, WorksheetElement::PositionWrapper, position, position) 0158 BASIC_SHARED_D_READER_IMPL(Image, WorksheetElement::HorizontalAlignment, horizontalAlignment, horizontalAlignment) 0159 BASIC_SHARED_D_READER_IMPL(Image, WorksheetElement::VerticalAlignment, verticalAlignment, verticalAlignment) 0160 BASIC_SHARED_D_READER_IMPL(Image, qreal, rotationAngle, rotationAngle) 0161 0162 CLASS_SHARED_D_READER_IMPL(Image, QPen, borderPen, borderPen) 0163 BASIC_SHARED_D_READER_IMPL(Image, qreal, borderOpacity, borderOpacity) 0164 0165 /* ============================ setter methods and undo commands ================= */ 0166 STD_SETTER_CMD_IMPL_F_S(Image, SetFileName, QString, fileName, updateImage) 0167 void Image::setFileName(const QString& fileName) { 0168 Q_D(Image); 0169 if (fileName != d->fileName) 0170 exec(new ImageSetFileNameCmd(d, fileName, ki18n("%1: set image"))); 0171 } 0172 0173 STD_SETTER_CMD_IMPL_F_S(Image, SetOpacity, qreal, opacity, update) 0174 void Image::setOpacity(qreal opacity) { 0175 Q_D(Image); 0176 if (opacity != d->opacity) 0177 exec(new ImageSetOpacityCmd(d, opacity, ki18n("%1: set border opacity"))); 0178 } 0179 0180 STD_SETTER_CMD_IMPL_F_S(Image, SetWidth, int, width, scaleImage) 0181 void Image::setWidth(int width) { 0182 Q_D(Image); 0183 if (width != d->width) 0184 exec(new ImageSetWidthCmd(d, width, ki18n("%1: set width"))); 0185 } 0186 0187 STD_SETTER_CMD_IMPL_F_S(Image, SetHeight, int, height, scaleImage) 0188 void Image::setHeight(int height) { 0189 Q_D(Image); 0190 if (height != d->height) 0191 exec(new ImageSetHeightCmd(d, height, ki18n("%1: set height"))); 0192 } 0193 0194 STD_SETTER_CMD_IMPL_S(Image, SetKeepRatio, bool, keepRatio) 0195 void Image::setKeepRatio(bool keepRatio) { 0196 Q_D(Image); 0197 if (keepRatio != d->keepRatio) 0198 exec(new ImageSetKeepRatioCmd(d, keepRatio, ki18n("%1: change keep ratio"))); 0199 } 0200 0201 STD_SETTER_CMD_IMPL_F_S(Image, SetPosition, WorksheetElement::PositionWrapper, position, retransform); 0202 void Image::setPosition(const WorksheetElement::PositionWrapper& pos) { 0203 Q_D(Image); 0204 if (pos.point != d->position.point || pos.horizontalPosition != d->position.horizontalPosition || pos.verticalPosition != d->position.verticalPosition) 0205 exec(new ImageSetPositionCmd(d, pos, ki18n("%1: set position"))); 0206 } 0207 0208 /*! 0209 sets the position without undo/redo-stuff 0210 */ 0211 void Image::setPosition(QPointF point) { 0212 Q_D(Image); 0213 if (point != d->position.point) { 0214 d->position.point = point; 0215 retransform(); 0216 } 0217 } 0218 0219 STD_SETTER_CMD_IMPL_F_S(Image, SetRotationAngle, qreal, rotationAngle, recalcShapeAndBoundingRect); 0220 void Image::setRotationAngle(qreal angle) { 0221 Q_D(Image); 0222 if (angle != d->rotationAngle) 0223 exec(new ImageSetRotationAngleCmd(d, angle, ki18n("%1: set rotation angle"))); 0224 } 0225 0226 STD_SETTER_CMD_IMPL_F_S(Image, SetHorizontalAlignment, WorksheetElement::HorizontalAlignment, horizontalAlignment, retransform); 0227 void Image::setHorizontalAlignment(const WorksheetElement::HorizontalAlignment hAlign) { 0228 Q_D(Image); 0229 if (hAlign != d->horizontalAlignment) 0230 exec(new ImageSetHorizontalAlignmentCmd(d, hAlign, ki18n("%1: set horizontal alignment"))); 0231 } 0232 0233 STD_SETTER_CMD_IMPL_F_S(Image, SetVerticalAlignment, WorksheetElement::VerticalAlignment, verticalAlignment, retransform); 0234 void Image::setVerticalAlignment(const WorksheetElement::VerticalAlignment vAlign) { 0235 Q_D(Image); 0236 if (vAlign != d->verticalAlignment) 0237 exec(new ImageSetVerticalAlignmentCmd(d, vAlign, ki18n("%1: set vertical alignment"))); 0238 } 0239 0240 //Border 0241 STD_SETTER_CMD_IMPL_F_S(Image, SetBorderPen, QPen, borderPen, update) 0242 void Image::setBorderPen(const QPen &pen) { 0243 Q_D(Image); 0244 if (pen != d->borderPen) 0245 exec(new ImageSetBorderPenCmd(d, pen, ki18n("%1: set border"))); 0246 } 0247 0248 STD_SETTER_CMD_IMPL_F_S(Image, SetBorderOpacity, qreal, borderOpacity, update) 0249 void Image::setBorderOpacity(qreal opacity) { 0250 Q_D(Image); 0251 if (opacity != d->borderOpacity) 0252 exec(new ImageSetBorderOpacityCmd(d, opacity, ki18n("%1: set border opacity"))); 0253 } 0254 0255 //misc 0256 STD_SWAP_METHOD_SETTER_CMD_IMPL_F(Image, SetVisible, bool, swapVisible, retransform); 0257 void Image::setVisible(bool on) { 0258 Q_D(Image); 0259 exec(new ImageSetVisibleCmd(d, on, on ? ki18n("%1: set visible") : ki18n("%1: set invisible"))); 0260 } 0261 0262 bool Image::isVisible() const { 0263 Q_D(const Image); 0264 return d->isVisible(); 0265 } 0266 0267 void Image::setPrinting(bool on) { 0268 Q_D(Image); 0269 d->m_printing = on; 0270 } 0271 0272 //############################################################################## 0273 //###### SLOTs for changes triggered via QActions in the context menu ######## 0274 //############################################################################## 0275 void Image::visibilityChanged() { 0276 Q_D(const Image); 0277 this->setVisible(!d->isVisible()); 0278 } 0279 0280 //############################################################################## 0281 //####################### Private implementation ############################### 0282 //############################################################################## 0283 ImagePrivate::ImagePrivate(Image* owner) : q(owner) { 0284 setFlag(QGraphicsItem::ItemIsSelectable); 0285 setFlag(QGraphicsItem::ItemIsMovable); 0286 setFlag(QGraphicsItem::ItemSendsGeometryChanges); 0287 setAcceptHoverEvents(true); 0288 } 0289 0290 QString ImagePrivate::name() const { 0291 return q->name(); 0292 } 0293 0294 /*! 0295 calculates the position and the bounding box of the label. Called on geometry or text changes. 0296 */ 0297 void ImagePrivate::retransform() { 0298 if (suppressRetransform) 0299 return; 0300 0301 if (position.horizontalPosition != WorksheetElement::HorizontalPosition::Custom 0302 || position.verticalPosition != WorksheetElement::VerticalPosition::Custom) 0303 updatePosition(); 0304 0305 float x = position.point.x(); 0306 float y = position.point.y(); 0307 float w = image.width(); 0308 float h = image.height(); 0309 0310 //depending on the alignment, calculate the new GraphicsItem's position in parent's coordinate system 0311 QPointF itemPos; 0312 switch (horizontalAlignment) { 0313 case WorksheetElement::HorizontalAlignment::Left: 0314 itemPos.setX(x - w/2); 0315 break; 0316 case WorksheetElement::HorizontalAlignment::Center: 0317 itemPos.setX(x); 0318 break; 0319 case WorksheetElement::HorizontalAlignment::Right: 0320 itemPos.setX(x + w/2); 0321 break; 0322 } 0323 0324 switch (verticalAlignment) { 0325 case WorksheetElement::VerticalAlignment::Top: 0326 itemPos.setY(y - h/2); 0327 break; 0328 case WorksheetElement::VerticalAlignment::Center: 0329 itemPos.setY(y); 0330 break; 0331 case WorksheetElement::VerticalAlignment::Bottom: 0332 itemPos.setY(y + h/2); 0333 break; 0334 } 0335 0336 suppressItemChangeEvent = true; 0337 setPos(itemPos); 0338 suppressItemChangeEvent = false; 0339 0340 boundingRectangle.setX(-w/2); 0341 boundingRectangle.setY(-h/2); 0342 boundingRectangle.setWidth(w); 0343 boundingRectangle.setHeight(h); 0344 0345 updateBorder(); 0346 } 0347 0348 void ImagePrivate::updateImage() { 0349 if (!fileName.isEmpty()) { 0350 image = QImage(fileName); 0351 width = image.width(); 0352 height = image.height(); 0353 q->widthChanged(width); 0354 q->heightChanged(height); 0355 } else { 0356 width = Worksheet::convertToSceneUnits(2, Worksheet::Unit::Centimeter); 0357 height = Worksheet::convertToSceneUnits(3, Worksheet::Unit::Centimeter); 0358 image = QIcon::fromTheme("viewimage").pixmap(width, height).toImage(); 0359 q->widthChanged(width); 0360 q->heightChanged(height); 0361 } 0362 0363 retransform(); 0364 } 0365 0366 void ImagePrivate::scaleImage() { 0367 if (keepRatio) { 0368 if (width != image.width()) { 0369 //width was changed -> rescale the height to keep the ratio 0370 if (image.width() != 0) 0371 height = image.height()*width/image.width(); 0372 else 0373 height = 0; 0374 q->heightChanged(height); 0375 } else { 0376 //height was changed -> rescale the width to keep the ratio 0377 if (image.height() != 0) 0378 width = image.width()*height/image.height(); 0379 else 0380 width = 0; 0381 q->widthChanged(width); 0382 } 0383 } 0384 0385 if (width != 0 && height != 0) 0386 image = image.scaled(width, height, Qt::KeepAspectRatio, Qt::SmoothTransformation); 0387 retransform(); 0388 } 0389 0390 /*! 0391 calculates the position of the label, when the position relative to the parent was specified (left, right, etc.) 0392 */ 0393 void ImagePrivate::updatePosition() { 0394 //determine the parent item 0395 QRectF parentRect; 0396 QGraphicsItem* parent = parentItem(); 0397 if (parent) { 0398 parentRect = parent->boundingRect(); 0399 } else { 0400 if (!scene()) 0401 return; 0402 0403 parentRect = scene()->sceneRect(); 0404 } 0405 0406 if (position.horizontalPosition != WorksheetElement::HorizontalPosition::Custom) { 0407 if (position.horizontalPosition == WorksheetElement::HorizontalPosition::Left) 0408 position.point.setX( parentRect.x() ); 0409 else if (position.horizontalPosition == WorksheetElement::HorizontalPosition::Center) 0410 position.point.setX( parentRect.x() + parentRect.width()/2 ); 0411 else if (position.horizontalPosition == WorksheetElement::HorizontalPosition::Right) 0412 position.point.setX( parentRect.x() + parentRect.width() ); 0413 } 0414 0415 if (position.verticalPosition != WorksheetElement::VerticalPosition::Custom) { 0416 if (position.verticalPosition == WorksheetElement::VerticalPosition::Top) 0417 position.point.setY( parentRect.y() ); 0418 else if (position.verticalPosition == WorksheetElement::VerticalPosition::Center) 0419 position.point.setY( parentRect.y() + parentRect.height()/2 ); 0420 else if (position.verticalPosition == WorksheetElement::VerticalPosition::Bottom) 0421 position.point.setY( parentRect.y() + parentRect.height() ); 0422 } 0423 0424 emit q->positionChanged(position); 0425 } 0426 0427 void ImagePrivate::updateBorder() { 0428 borderShapePath = QPainterPath(); 0429 borderShapePath.addRect(boundingRectangle); 0430 recalcShapeAndBoundingRect(); 0431 } 0432 0433 bool ImagePrivate::swapVisible(bool on) { 0434 bool oldValue = isVisible(); 0435 setVisible(on); 0436 emit q->changed(); 0437 emit q->visibleChanged(on); 0438 return oldValue; 0439 } 0440 0441 /*! 0442 Returns the outer bounds of the item as a rectangle. 0443 */ 0444 QRectF ImagePrivate::boundingRect() const { 0445 return transformedBoundingRectangle; 0446 } 0447 0448 /*! 0449 Returns the shape of this item as a QPainterPath in local coordinates. 0450 */ 0451 QPainterPath ImagePrivate::shape() const { 0452 return imageShape; 0453 } 0454 0455 /*! 0456 recalculates the outer bounds and the shape of the label. 0457 */ 0458 void ImagePrivate::recalcShapeAndBoundingRect() { 0459 prepareGeometryChange(); 0460 0461 QMatrix matrix; 0462 matrix.rotate(-rotationAngle); 0463 imageShape = QPainterPath(); 0464 if (borderPen.style() != Qt::NoPen) { 0465 imageShape.addPath(WorksheetElement::shapeFromPath(borderShapePath, borderPen)); 0466 transformedBoundingRectangle = matrix.mapRect(imageShape.boundingRect()); 0467 } else { 0468 imageShape.addRect(boundingRectangle); 0469 transformedBoundingRectangle = matrix.mapRect(boundingRectangle); 0470 } 0471 0472 imageShape = matrix.map(imageShape); 0473 0474 emit q->changed(); 0475 } 0476 0477 void ImagePrivate::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) { 0478 Q_UNUSED(option) 0479 Q_UNUSED(widget) 0480 0481 painter->save(); 0482 0483 //draw the image 0484 painter->rotate(-rotationAngle); 0485 painter->setOpacity(opacity); 0486 painter->drawImage(boundingRectangle.topLeft(), image, image.rect()); 0487 painter->restore(); 0488 0489 //draw the border 0490 if (borderPen.style() != Qt::NoPen) { 0491 painter->save(); 0492 painter->rotate(-rotationAngle); 0493 painter->setPen(borderPen); 0494 painter->setOpacity(borderOpacity); 0495 painter->drawPath(borderShapePath); 0496 painter->restore(); 0497 } 0498 0499 if (m_hovered && !isSelected() && !m_printing) { 0500 painter->setPen(QPen(QApplication::palette().color(QPalette::Shadow), 2, Qt::SolidLine)); 0501 painter->drawPath(imageShape); 0502 } 0503 0504 if (isSelected() && !m_printing) { 0505 painter->setPen(QPen(QApplication::palette().color(QPalette::Highlight), 2, Qt::SolidLine)); 0506 painter->drawPath(imageShape); 0507 } 0508 } 0509 0510 QVariant ImagePrivate::itemChange(GraphicsItemChange change, const QVariant &value) { 0511 if (suppressItemChangeEvent) 0512 return value; 0513 0514 if (change == QGraphicsItem::ItemPositionChange) { 0515 //convert item's center point in parent's coordinates 0516 WorksheetElement::PositionWrapper tempPosition; 0517 tempPosition.point = positionFromItemPosition(value.toPointF()); 0518 tempPosition.horizontalPosition = WorksheetElement::HorizontalPosition::Custom; 0519 tempPosition.verticalPosition = WorksheetElement::VerticalPosition::Custom; 0520 0521 //emit the signals in order to notify the UI. 0522 //we don't set the position related member variables during the mouse movements. 0523 //this is done on mouse release events only. 0524 emit q->positionChanged(tempPosition); 0525 } 0526 0527 return QGraphicsItem::itemChange(change, value); 0528 } 0529 0530 void ImagePrivate::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) { 0531 //convert position of the item in parent coordinates to label's position 0532 QPointF point = positionFromItemPosition(pos()); 0533 if (qAbs(point.x()-position.point.x())>20 && qAbs(point.y()-position.point.y())>20 ) { 0534 //position was changed -> set the position related member variables 0535 suppressRetransform = true; 0536 WorksheetElement::PositionWrapper tempPosition; 0537 tempPosition.point = point; 0538 tempPosition.horizontalPosition = WorksheetElement::HorizontalPosition::Custom; 0539 tempPosition.verticalPosition = WorksheetElement::VerticalPosition::Custom; 0540 q->setPosition(tempPosition); 0541 suppressRetransform = false; 0542 } 0543 0544 QGraphicsItem::mouseReleaseEvent(event); 0545 } 0546 0547 /*! 0548 * converts label's position to GraphicsItem's position. 0549 */ 0550 QPointF ImagePrivate::positionFromItemPosition(QPointF itemPos) { 0551 float x = itemPos.x(); 0552 float y = itemPos.y(); 0553 float w = image.width(); 0554 float h = image.height(); 0555 QPointF tmpPosition; 0556 0557 //depending on the alignment, calculate the new position 0558 switch (horizontalAlignment) { 0559 case WorksheetElement::HorizontalAlignment::Left: 0560 tmpPosition.setX(x + w/2); 0561 break; 0562 case WorksheetElement::HorizontalAlignment::Center: 0563 tmpPosition.setX(x); 0564 break; 0565 case WorksheetElement::HorizontalAlignment::Right: 0566 tmpPosition.setX(x - w/2); 0567 break; 0568 } 0569 0570 switch (verticalAlignment) { 0571 case WorksheetElement::VerticalAlignment::Top: 0572 tmpPosition.setY(y + h/2); 0573 break; 0574 case WorksheetElement::VerticalAlignment::Center: 0575 tmpPosition.setY(y); 0576 break; 0577 case WorksheetElement::VerticalAlignment::Bottom: 0578 tmpPosition.setY(y - h/2); 0579 break; 0580 } 0581 0582 return tmpPosition; 0583 } 0584 0585 void ImagePrivate::contextMenuEvent(QGraphicsSceneContextMenuEvent* event) { 0586 q->createContextMenu()->exec(event->screenPos()); 0587 } 0588 0589 void ImagePrivate::hoverEnterEvent(QGraphicsSceneHoverEvent*) { 0590 if (!isSelected()) { 0591 m_hovered = true; 0592 emit q->hovered(); 0593 update(); 0594 } 0595 } 0596 0597 void ImagePrivate::hoverLeaveEvent(QGraphicsSceneHoverEvent*) { 0598 if (m_hovered) { 0599 m_hovered = false; 0600 emit q->unhovered(); 0601 update(); 0602 } 0603 } 0604 0605 //############################################################################## 0606 //################## Serialization/Deserialization ########################### 0607 //############################################################################## 0608 //! Save as XML 0609 void Image::save(QXmlStreamWriter* writer) const { 0610 Q_D(const Image); 0611 0612 writer->writeStartElement("image"); 0613 writeBasicAttributes(writer); 0614 writeCommentElement(writer); 0615 0616 //general 0617 writer->writeStartElement("general"); 0618 writer->writeAttribute("fileName", d->fileName); 0619 writer->writeAttribute("opacity", QString::number(d->opacity)); 0620 writer->writeEndElement(); 0621 0622 //geometry 0623 writer->writeStartElement("geometry"); 0624 writer->writeAttribute("width", QString::number(d->width)); 0625 writer->writeAttribute("height", QString::number(d->height)); 0626 writer->writeAttribute("keepRatio", QString::number(d->keepRatio)); 0627 writer->writeAttribute("x", QString::number(d->position.point.x())); 0628 writer->writeAttribute("y", QString::number(d->position.point.y())); 0629 writer->writeAttribute("horizontalPosition", QString::number(static_cast<int>(d->position.horizontalPosition))); 0630 writer->writeAttribute("verticalPosition", QString::number(static_cast<int>(d->position.verticalPosition))); 0631 writer->writeAttribute("horizontalAlignment", QString::number(static_cast<int>(d->horizontalAlignment))); 0632 writer->writeAttribute("verticalAlignment", QString::number(static_cast<int>(d->verticalAlignment))); 0633 writer->writeAttribute("rotationAngle", QString::number(d->rotationAngle)); 0634 writer->writeAttribute("visible", QString::number(d->isVisible())); 0635 writer->writeEndElement(); 0636 0637 //border 0638 writer->writeStartElement("border"); 0639 WRITE_QPEN(d->borderPen); 0640 writer->writeAttribute("borderOpacity", QString::number(d->borderOpacity)); 0641 writer->writeEndElement(); 0642 0643 writer->writeEndElement(); // close "image" section 0644 } 0645 0646 //! Load from XML 0647 bool Image::load(XmlStreamReader* reader, bool preview) { 0648 if (!readBasicAttributes(reader)) 0649 return false; 0650 0651 Q_D(Image); 0652 KLocalizedString attributeWarning = ki18n("Attribute '%1' missing or empty, default value is used"); 0653 QXmlStreamAttributes attribs; 0654 QString str; 0655 0656 while (!reader->atEnd()) { 0657 reader->readNext(); 0658 if (reader->isEndElement() && reader->name() == "image") 0659 break; 0660 0661 if (!reader->isStartElement()) 0662 continue; 0663 0664 if (!preview && reader->name() == "comment") { 0665 if (!readCommentElement(reader)) return false; 0666 } else if (!preview && reader->name() == "general") { 0667 attribs = reader->attributes(); 0668 d->fileName = attribs.value("fileName").toString(); 0669 READ_DOUBLE_VALUE("opacity", opacity); 0670 } else if (!preview && reader->name() == "geometry") { 0671 attribs = reader->attributes(); 0672 0673 READ_INT_VALUE("width", width, int); 0674 READ_INT_VALUE("height", height, int); 0675 READ_INT_VALUE("keepRatio", keepRatio, bool); 0676 0677 str = attribs.value("x").toString(); 0678 if (str.isEmpty()) 0679 reader->raiseWarning(attributeWarning.subs("x").toString()); 0680 else 0681 d->position.point.setX(str.toDouble()); 0682 0683 str = attribs.value("y").toString(); 0684 if (str.isEmpty()) 0685 reader->raiseWarning(attributeWarning.subs("y").toString()); 0686 else 0687 d->position.point.setY(str.toDouble()); 0688 0689 READ_INT_VALUE("horizontalPosition", position.horizontalPosition, WorksheetElement::HorizontalPosition); 0690 READ_INT_VALUE("verticalPosition", position.verticalPosition, WorksheetElement::VerticalPosition); 0691 READ_INT_VALUE("horizontalAlignment", horizontalAlignment, WorksheetElement::HorizontalAlignment); 0692 READ_INT_VALUE("verticalAlignment", verticalAlignment, WorksheetElement::VerticalAlignment); 0693 READ_DOUBLE_VALUE("rotationAngle", rotationAngle); 0694 0695 str = attribs.value("visible").toString(); 0696 if (str.isEmpty()) 0697 reader->raiseWarning(attributeWarning.subs("visible").toString()); 0698 else 0699 d->setVisible(str.toInt()); 0700 } else if (!preview && reader->name() == "border") { 0701 attribs = reader->attributes(); 0702 READ_QPEN(d->borderPen); 0703 READ_DOUBLE_VALUE("borderOpacity", borderOpacity); 0704 } else { // unknown element 0705 reader->raiseWarning(i18n("unknown element '%1'", reader->name().toString())); 0706 if (!reader->skipToEndElement()) return false; 0707 } 0708 } 0709 0710 if (!preview) { 0711 d->image = QImage(d->fileName); 0712 d->scaleImage(); 0713 } 0714 0715 return true; 0716 } 0717 0718 //############################################################################## 0719 //######################### Theme management ################################## 0720 //############################################################################## 0721 void Image::loadThemeConfig(const KConfig& config) { 0722 Q_UNUSED(config) 0723 } 0724 0725 void Image::saveThemeConfig(const KConfig& config) { 0726 Q_UNUSED(config) 0727 }