File indexing completed on 2024-05-12 15:26:41
0001 /*************************************************************************** 0002 File : DatapickerImage.cpp 0003 Project : LabPlot 0004 Description : Worksheet for Datapicker 0005 -------------------------------------------------------------------- 0006 Copyright : (C) 2015 by Ankit Wagadre (wagadre.ankit@gmail.com) 0007 Copyright : (C) 2015-2019 by Alexander Semke (alexander.semke@web.de) 0008 0009 ***************************************************************************/ 0010 /*************************************************************************** 0011 * * 0012 * This program is free software; you can redistribute it and/or modify * 0013 * it under the terms of the GNU General Public License as published by * 0014 * the Free Software Foundation; either version 2 of the License, or * 0015 * (at your option) any later version. * 0016 * * 0017 * This program is distributed in the hope that it will be useful, * 0018 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0019 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0020 * GNU General Public License for more details. * 0021 * * 0022 * You should have received a copy of the GNU General Public License * 0023 * along with this program; if not, write to the Free Software * 0024 * Foundation, Inc., 51 Franklin Street, Fifth Floor, * 0025 * Boston, MA 02110-1301 USA * 0026 * * 0027 ***************************************************************************/ 0028 0029 #include "DatapickerImage.h" 0030 #include "DatapickerImagePrivate.h" 0031 #include "backend/datapicker/ImageEditor.h" 0032 #include "backend/lib/commandtemplates.h" 0033 #include "backend/lib/XmlStreamReader.h" 0034 #include "backend/datapicker/DatapickerPoint.h" 0035 #include "backend/datapicker/Segments.h" 0036 #include "backend/worksheet/Worksheet.h" 0037 #include "commonfrontend/datapicker/DatapickerImageView.h" 0038 #include "kdefrontend/worksheet/ExportWorksheetDialog.h" 0039 #include "backend/lib/trace.h" 0040 0041 #include <QDesktopWidget> 0042 #include <QGraphicsScene> 0043 #include <QMenu> 0044 #include <QPrinter> 0045 #include <QPrintDialog> 0046 #include <QPrintPreviewDialog> 0047 0048 #include <KConfig> 0049 #include <KConfigGroup> 0050 #include <KLocalizedString> 0051 0052 /** 0053 * \class DatapickerImage 0054 * \brief container to open image/plot. 0055 * 0056 * Top-level container for DatapickerPoint. 0057 * 0058 * * \ingroup datapicker 0059 */ 0060 DatapickerImage::DatapickerImage(const QString& name, bool loading) : 0061 AbstractPart(name, AspectType::DatapickerImage), 0062 foregroundBins( new int[ImageEditor::colorAttributeMax(ColorAttributes::Foreground) + 1]), 0063 hueBins( new int[ImageEditor::colorAttributeMax(ColorAttributes::Hue) + 1]), 0064 saturationBins( new int[ImageEditor::colorAttributeMax(ColorAttributes::Saturation) + 1]), 0065 valueBins( new int[ImageEditor::colorAttributeMax(ColorAttributes::Value) + 1]), 0066 intensityBins( new int[ImageEditor::colorAttributeMax(ColorAttributes::Intensity) + 1]), 0067 d(new DatapickerImagePrivate(this)), 0068 m_segments(new Segments(this)) { 0069 0070 if (!loading) 0071 init(); 0072 } 0073 0074 DatapickerImage::~DatapickerImage() { 0075 delete [] hueBins; 0076 delete [] saturationBins; 0077 delete [] valueBins; 0078 delete [] intensityBins; 0079 delete [] foregroundBins; 0080 delete m_segments; 0081 delete d; 0082 } 0083 0084 void DatapickerImage::init() { 0085 KConfig config; 0086 KConfigGroup group = config.group( "DatapickerImage" ); 0087 0088 //general properties 0089 d->fileName = group.readEntry("FileName", QString()); 0090 d->rotationAngle = group.readEntry("RotationAngle", 0.0); 0091 d->minSegmentLength = group.readEntry("MinSegmentLength", 30); 0092 d->pointSeparation = group.readEntry("PointSeparation", 30); 0093 d->axisPoints.type = (DatapickerImage::GraphType) group.readEntry("GraphType", static_cast<int>(DatapickerImage::GraphType::Cartesian)); 0094 d->axisPoints.ternaryScale = group.readEntry("TernaryScale", 1); 0095 0096 //edit image settings 0097 d->plotImageType = DatapickerImage::PlotImageType::OriginalImage; 0098 d->settings.foregroundThresholdHigh = group.readEntry("ForegroundThresholdHigh", 90); 0099 d->settings.foregroundThresholdLow = group.readEntry("ForegroundThresholdLow", 30); 0100 d->settings.hueThresholdHigh = group.readEntry("HueThresholdHigh", 360); 0101 d->settings.hueThresholdLow = group.readEntry("HueThresholdLow", 0); 0102 d->settings.intensityThresholdHigh = group.readEntry("IntensityThresholdHigh", 100); 0103 d->settings.intensityThresholdLow = group.readEntry("IntensityThresholdLow", 20); 0104 d->settings.saturationThresholdHigh = group.readEntry("SaturationThresholdHigh", 100); 0105 d->settings.saturationThresholdLow = group.readEntry("SaturationThresholdLow", 30); 0106 d->settings.valueThresholdHigh = group.readEntry("ValueThresholdHigh", 90); 0107 d->settings.valueThresholdLow = group.readEntry("ValueThresholdLow", 30); 0108 0109 // reference point symbol properties 0110 d->pointStyle = (Symbol::Style)group.readEntry("PointStyle", (int)Symbol::Style::Cross); 0111 d->pointSize = group.readEntry("Size", Worksheet::convertToSceneUnits(7, Worksheet::Unit::Point)); 0112 d->pointRotationAngle = group.readEntry("Rotation", 0.0); 0113 d->pointOpacity = group.readEntry("Opacity", 1.0); 0114 d->pointBrush.setStyle( (Qt::BrushStyle)group.readEntry("FillingStyle", (int)Qt::NoBrush) ); 0115 d->pointBrush.setColor( group.readEntry("FillingColor", QColor(Qt::black)) ); 0116 d->pointPen.setStyle( (Qt::PenStyle)group.readEntry("BorderStyle", (int)Qt::SolidLine) ); 0117 d->pointPen.setColor( group.readEntry("BorderColor", QColor(Qt::red)) ); 0118 d->pointPen.setWidthF( group.readEntry("BorderWidth", Worksheet::convertToSceneUnits(1, Worksheet::Unit::Point)) ); 0119 d->pointVisibility = group.readEntry("PointVisibility", true); 0120 } 0121 0122 /*! 0123 Returns an icon to be used in the project explorer. 0124 */ 0125 QIcon DatapickerImage::icon() const { 0126 return QIcon::fromTheme("image-x-generic"); 0127 } 0128 0129 /*! 0130 Return a new context menu 0131 */ 0132 QMenu* DatapickerImage::createContextMenu() { 0133 QMenu* menu = new QMenu(nullptr); 0134 emit requestProjectContextMenu(menu); 0135 return menu; 0136 } 0137 0138 void DatapickerImage::createContextMenu(QMenu* menu) { 0139 emit requestProjectContextMenu(menu); 0140 } 0141 0142 //! Construct a primary view on me. 0143 /** 0144 * This method may be called multiple times during the life time of an Aspect, or it might not get 0145 * called at all. Aspects must not depend on the existence of a view for their operation. 0146 */ 0147 QWidget* DatapickerImage::view() const { 0148 if (!m_partView) { 0149 m_view = new DatapickerImageView(const_cast<DatapickerImage *>(this)); 0150 m_partView = m_view; 0151 connect(m_view, &DatapickerImageView::statusInfo, this, &DatapickerImage::statusInfo); 0152 } 0153 return m_partView; 0154 } 0155 0156 bool DatapickerImage::exportView() const { 0157 auto* dlg = new ExportWorksheetDialog(m_view); 0158 dlg->setFileName(name()); 0159 bool ret; 0160 if ( (ret = (dlg->exec() == QDialog::Accepted)) ) { 0161 const QString path = dlg->path(); 0162 const WorksheetView::ExportFormat format = dlg->exportFormat(); 0163 const int resolution = dlg->exportResolution(); 0164 0165 WAIT_CURSOR; 0166 m_view->exportToFile(path, format, resolution); 0167 RESET_CURSOR; 0168 } 0169 delete dlg; 0170 return ret; 0171 } 0172 0173 bool DatapickerImage::printView() { 0174 QPrinter printer; 0175 auto* dlg = new QPrintDialog(&printer, m_view); 0176 bool ret; 0177 dlg->setWindowTitle(i18nc("@title:window", "Print Datapicker Image")); 0178 if ( (ret = (dlg->exec() == QDialog::Accepted)) ) 0179 m_view->print(&printer); 0180 0181 delete dlg; 0182 return ret; 0183 } 0184 0185 bool DatapickerImage::printPreview() const { 0186 auto* dlg = new QPrintPreviewDialog(m_view); 0187 connect(dlg, &QPrintPreviewDialog::paintRequested, m_view, &DatapickerImageView::print); 0188 return dlg->exec(); 0189 } 0190 0191 /*! 0192 Selects or deselects the Datapicker/DatapickerImage in the project explorer. 0193 This function is called in \c DatapickerImageView. 0194 The DatapickerImage gets deselected if there are selected items in the view, 0195 and selected if there are no selected items in the view. 0196 */ 0197 void DatapickerImage::setSelectedInView(const bool b) { 0198 if (b) 0199 emit childAspectSelectedInView(this); 0200 else 0201 emit childAspectDeselectedInView(this); 0202 } 0203 0204 void DatapickerImage::setSegmentsHoverEvent(const bool on) { 0205 m_segments->setAcceptHoverEvents(on); 0206 } 0207 0208 QGraphicsScene* DatapickerImage::scene() const { 0209 return d->m_scene; 0210 } 0211 0212 QRectF DatapickerImage::pageRect() const { 0213 return d->m_scene->sceneRect(); 0214 } 0215 0216 void DatapickerImage::setPlotImageType(const DatapickerImage::PlotImageType type) { 0217 d->plotImageType = type; 0218 if (d->plotImageType == DatapickerImage::PlotImageType::ProcessedImage) 0219 d->discretize(); 0220 0221 emit requestUpdate(); 0222 } 0223 0224 DatapickerImage::PlotImageType DatapickerImage::plotImageType() { 0225 return d->plotImageType; 0226 } 0227 0228 /* =============================== getter methods for background options ================================= */ 0229 CLASS_D_READER_IMPL(DatapickerImage, QString, fileName, fileName) 0230 CLASS_D_READER_IMPL(DatapickerImage, DatapickerImage::ReferencePoints, axisPoints, axisPoints) 0231 CLASS_D_READER_IMPL(DatapickerImage, DatapickerImage::EditorSettings, settings, settings) 0232 BASIC_D_READER_IMPL(DatapickerImage, float, rotationAngle, rotationAngle) 0233 BASIC_D_READER_IMPL(DatapickerImage, DatapickerImage::PointsType, plotPointsType, plotPointsType) 0234 BASIC_D_READER_IMPL(DatapickerImage, int, pointSeparation, pointSeparation) 0235 BASIC_D_READER_IMPL(DatapickerImage, int, minSegmentLength, minSegmentLength) 0236 BASIC_D_READER_IMPL(DatapickerImage, Symbol::Style, pointStyle, pointStyle) 0237 BASIC_D_READER_IMPL(DatapickerImage, qreal, pointOpacity, pointOpacity) 0238 BASIC_D_READER_IMPL(DatapickerImage, qreal, pointRotationAngle, pointRotationAngle) 0239 BASIC_D_READER_IMPL(DatapickerImage, qreal, pointSize, pointSize) 0240 CLASS_D_READER_IMPL(DatapickerImage, QBrush, pointBrush, pointBrush) 0241 CLASS_D_READER_IMPL(DatapickerImage, QPen, pointPen, pointPen) 0242 BASIC_D_READER_IMPL(DatapickerImage, bool, pointVisibility, pointVisibility) 0243 /* ============================ setter methods and undo commands for background options ================= */ 0244 STD_SETTER_CMD_IMPL_F_S(DatapickerImage, SetFileName, QString, fileName, updateFileName) 0245 void DatapickerImage::setFileName(const QString& fileName) { 0246 if (fileName!= d->fileName) { 0247 beginMacro(i18n("%1: upload new image", name())); 0248 exec(new DatapickerImageSetFileNameCmd(d, fileName, ki18n("%1: upload image"))); 0249 endMacro(); 0250 } 0251 } 0252 0253 STD_SETTER_CMD_IMPL_S(DatapickerImage, SetRotationAngle, float, rotationAngle) 0254 void DatapickerImage::setRotationAngle(float angle) { 0255 if (angle != d->rotationAngle) 0256 exec(new DatapickerImageSetRotationAngleCmd(d, angle, ki18n("%1: set rotation angle"))); 0257 } 0258 0259 STD_SETTER_CMD_IMPL_S(DatapickerImage, SetAxisPoints, DatapickerImage::ReferencePoints, axisPoints) 0260 void DatapickerImage::setAxisPoints(const DatapickerImage::ReferencePoints& points) { 0261 if (memcmp(&points, &d->axisPoints, sizeof(points)) != 0) 0262 exec(new DatapickerImageSetAxisPointsCmd(d, points, ki18n("%1: set Axis points"))); 0263 } 0264 0265 STD_SETTER_CMD_IMPL_F_S(DatapickerImage, SetSettings, DatapickerImage::EditorSettings, settings, discretize) 0266 void DatapickerImage::setSettings(const DatapickerImage::EditorSettings& editorSettings) { 0267 if (memcmp(&editorSettings, &d->settings, sizeof(editorSettings)) != 0) 0268 exec(new DatapickerImageSetSettingsCmd(d, editorSettings, ki18n("%1: set editor settings"))); 0269 } 0270 0271 STD_SETTER_CMD_IMPL_F_S(DatapickerImage, SetMinSegmentLength, int, minSegmentLength, makeSegments) 0272 void DatapickerImage::setminSegmentLength(const int value) { 0273 if (d->minSegmentLength != value) 0274 exec(new DatapickerImageSetMinSegmentLengthCmd(d, value, ki18n("%1: set minimum segment length"))); ; 0275 } 0276 0277 STD_SETTER_CMD_IMPL_F_S(DatapickerImage, SetPointStyle, Symbol::Style, pointStyle, retransform) 0278 void DatapickerImage::setPointStyle(Symbol::Style newStyle) { 0279 if (newStyle != d->pointStyle) 0280 exec(new DatapickerImageSetPointStyleCmd(d, newStyle, ki18n("%1: set point's style"))); 0281 } 0282 0283 STD_SETTER_CMD_IMPL_F_S(DatapickerImage, SetPointSize, qreal, pointSize, retransform) 0284 void DatapickerImage::setPointSize(qreal value) { 0285 if (!qFuzzyCompare(1 + value, 1 + d->pointSize)) 0286 exec(new DatapickerImageSetPointSizeCmd(d, value, ki18n("%1: set point's size"))); 0287 } 0288 0289 STD_SETTER_CMD_IMPL_F_S(DatapickerImage, SetPointRotationAngle, qreal, pointRotationAngle, retransform) 0290 void DatapickerImage::setPointRotationAngle(qreal angle) { 0291 if (!qFuzzyCompare(1 + angle, 1 + d->pointRotationAngle)) 0292 exec(new DatapickerImageSetPointRotationAngleCmd(d, angle, ki18n("%1: rotate point"))); 0293 } 0294 0295 STD_SETTER_CMD_IMPL_F_S(DatapickerImage, SetPointBrush, QBrush, pointBrush, retransform) 0296 void DatapickerImage::setPointBrush(const QBrush& newBrush) { 0297 if (newBrush != d->pointBrush) 0298 exec(new DatapickerImageSetPointBrushCmd(d, newBrush, ki18n("%1: set point's filling"))); 0299 } 0300 0301 STD_SETTER_CMD_IMPL_F_S(DatapickerImage, SetPointPen, QPen, pointPen, retransform) 0302 void DatapickerImage::setPointPen(const QPen &newPen) { 0303 if (newPen != d->pointPen) 0304 exec(new DatapickerImageSetPointPenCmd(d, newPen, ki18n("%1: set outline style"))); 0305 } 0306 0307 STD_SETTER_CMD_IMPL_F_S(DatapickerImage, SetPointOpacity, qreal, pointOpacity, retransform) 0308 void DatapickerImage::setPointOpacity(qreal newOpacity) { 0309 if (newOpacity != d->pointOpacity) 0310 exec(new DatapickerImageSetPointOpacityCmd(d, newOpacity, ki18n("%1: set point's opacity"))); 0311 } 0312 0313 STD_SETTER_CMD_IMPL_F_S(DatapickerImage, SetPointVisibility, bool, pointVisibility, retransform) 0314 void DatapickerImage::setPointVisibility(const bool on) { 0315 if (on != d->pointVisibility) 0316 exec(new DatapickerImageSetPointVisibilityCmd(d, on, on ? ki18n("%1: set visible") : ki18n("%1: set invisible"))); 0317 } 0318 0319 void DatapickerImage::setPrinting(bool on) const { 0320 auto points = parentAspect()->children<DatapickerPoint>(ChildIndexFlag::Recursive | ChildIndexFlag::IncludeHidden); 0321 for (auto* point : points) 0322 point->setPrinting(on); 0323 } 0324 0325 void DatapickerImage::setPlotPointsType(const PointsType pointsType) { 0326 if (d->plotPointsType == pointsType) 0327 return; 0328 0329 d->plotPointsType = pointsType; 0330 0331 if (pointsType == DatapickerImage::PointsType::AxisPoints) { 0332 //clear image 0333 auto points = children<DatapickerPoint>(ChildIndexFlag::IncludeHidden); 0334 if (!points.isEmpty()) { 0335 beginMacro(i18n("%1: remove all axis points", name())); 0336 0337 for (auto* point : points) 0338 point->remove(); 0339 endMacro(); 0340 } 0341 m_segments->setSegmentsVisible(false); 0342 } else if (pointsType == DatapickerImage::PointsType::CurvePoints) 0343 m_segments->setSegmentsVisible(false); 0344 else if (pointsType == DatapickerImage::PointsType::SegmentPoints) { 0345 d->makeSegments(); 0346 m_segments->setSegmentsVisible(true); 0347 } 0348 } 0349 0350 void DatapickerImage::setPointSeparation(const int value) { 0351 d->pointSeparation = value; 0352 } 0353 0354 //############################################################################## 0355 //###################### Private implementation ############################### 0356 //############################################################################## 0357 DatapickerImagePrivate::DatapickerImagePrivate(DatapickerImage *owner) : q(owner), 0358 pageRect(0, 0, 1000, 1000), 0359 m_scene(new QGraphicsScene(pageRect)) { 0360 } 0361 0362 QString DatapickerImagePrivate::name() const { 0363 return q->name(); 0364 } 0365 0366 void DatapickerImagePrivate::retransform() { 0367 auto points = q->children<DatapickerPoint>(AbstractAspect::ChildIndexFlag::IncludeHidden); 0368 for (auto* point : points) 0369 point->retransform(); 0370 } 0371 0372 bool DatapickerImagePrivate::uploadImage(const QString& address) { 0373 bool rc = q->originalPlotImage.load(address); 0374 if (rc) { 0375 //convert the image to 32bit-format if this is not the case yet 0376 QImage::Format format = q->originalPlotImage.format(); 0377 if (format != QImage::Format_RGB32 && format != QImage::Format_ARGB32 && format != QImage::Format_ARGB32_Premultiplied) 0378 q->originalPlotImage = q->originalPlotImage.convertToFormat(QImage::Format_RGB32); 0379 0380 q->processedPlotImage = q->originalPlotImage; 0381 q->background = ImageEditor::findBackgroundColor(&q->originalPlotImage); 0382 //upload Histogram 0383 ImageEditor::uploadHistogram(q->intensityBins, &q->originalPlotImage, q->background, DatapickerImage::ColorAttributes::Intensity); 0384 ImageEditor::uploadHistogram(q->foregroundBins, &q->originalPlotImage, q->background, DatapickerImage::ColorAttributes::Foreground); 0385 ImageEditor::uploadHistogram(q->hueBins, &q->originalPlotImage, q->background, DatapickerImage::ColorAttributes::Hue); 0386 ImageEditor::uploadHistogram(q->saturationBins, &q->originalPlotImage, q->background, DatapickerImage::ColorAttributes::Saturation); 0387 ImageEditor::uploadHistogram(q->valueBins, &q->originalPlotImage, q->background, DatapickerImage::ColorAttributes::Value); 0388 discretize(); 0389 0390 //resize the screen 0391 double w = Worksheet::convertToSceneUnits(q->originalPlotImage.width(), Worksheet::Unit::Inch)/QApplication::desktop()->physicalDpiX(); 0392 double h = Worksheet::convertToSceneUnits(q->originalPlotImage.height(), Worksheet::Unit::Inch)/QApplication::desktop()->physicalDpiX(); 0393 m_scene->setSceneRect(0, 0, w, h); 0394 q->isLoaded = true; 0395 } 0396 return rc; 0397 } 0398 0399 void DatapickerImagePrivate::discretize() { 0400 PERFTRACE("DatapickerImagePrivate::discretize()"); 0401 if (plotImageType != DatapickerImage::PlotImageType::ProcessedImage) 0402 return; 0403 0404 ImageEditor::discretize(&q->processedPlotImage, &q->originalPlotImage, settings, q->background); 0405 0406 if (plotPointsType != DatapickerImage::PointsType::SegmentPoints) 0407 emit q->requestUpdate(); 0408 else 0409 makeSegments(); 0410 } 0411 0412 void DatapickerImagePrivate::makeSegments() { 0413 if (plotPointsType != DatapickerImage::PointsType::SegmentPoints) 0414 return; 0415 0416 PERFTRACE("DatapickerImagePrivate::makeSegments()"); 0417 q->m_segments->makeSegments(q->processedPlotImage); 0418 q->m_segments->setSegmentsVisible(true); 0419 emit q->requestUpdate(); 0420 } 0421 0422 DatapickerImagePrivate::~DatapickerImagePrivate() { 0423 delete m_scene; 0424 } 0425 0426 void DatapickerImagePrivate::updateFileName() { 0427 WAIT_CURSOR; 0428 q->isLoaded = false; 0429 const QString& address = fileName.trimmed(); 0430 0431 if (!address.isEmpty()) { 0432 if (uploadImage(address)) 0433 fileName = address; 0434 } else { 0435 //hide segments if they are visible 0436 q->m_segments->setSegmentsVisible(false); 0437 } 0438 0439 auto points = q->parentAspect()->children<DatapickerPoint>(AbstractAspect::ChildIndexFlag::Recursive | AbstractAspect::ChildIndexFlag::IncludeHidden); 0440 if (!points.isEmpty()) { 0441 for (auto* point : points) 0442 point->remove(); 0443 } 0444 0445 emit q->requestUpdate(); 0446 emit q->requestUpdateActions(); 0447 RESET_CURSOR; 0448 } 0449 0450 //############################################################################## 0451 //################## Serialization/Deserialization ########################### 0452 //############################################################################## 0453 0454 //! Save as XML 0455 void DatapickerImage::save(QXmlStreamWriter* writer) const { 0456 writer->writeStartElement( "datapickerImage" ); 0457 writeBasicAttributes(writer); 0458 0459 //general properties 0460 writer->writeStartElement( "general" ); 0461 writer->writeAttribute( "fileName", d->fileName ); 0462 writer->writeAttribute( "plotPointsType", QString::number(static_cast<int>(d->plotPointsType)) ); 0463 writer->writeEndElement(); 0464 0465 writer->writeStartElement( "axisPoint" ); 0466 writer->writeAttribute( "graphType", QString::number(static_cast<int>(d->axisPoints.type)) ); 0467 writer->writeAttribute( "ternaryScale", QString::number(d->axisPoints.ternaryScale) ); 0468 writer->writeAttribute( "axisPointLogicalX1", QString::number(d->axisPoints.logicalPos[0].x()) ); 0469 writer->writeAttribute( "axisPointLogicalY1", QString::number(d->axisPoints.logicalPos[0].y()) ); 0470 writer->writeAttribute( "axisPointLogicalX2", QString::number(d->axisPoints.logicalPos[1].x()) ); 0471 writer->writeAttribute( "axisPointLogicalY2", QString::number(d->axisPoints.logicalPos[1].y()) ); 0472 writer->writeAttribute( "axisPointLogicalX3", QString::number(d->axisPoints.logicalPos[2].x()) ); 0473 writer->writeAttribute( "axisPointLogicalY3", QString::number(d->axisPoints.logicalPos[2].y()) ); 0474 writer->writeAttribute( "axisPointLogicalZ1", QString::number(d->axisPoints.logicalPos[0].z()) ); 0475 writer->writeAttribute( "axisPointLogicalZ2", QString::number(d->axisPoints.logicalPos[1].z()) ); 0476 writer->writeAttribute( "axisPointLogicalZ3", QString::number(d->axisPoints.logicalPos[2].z()) ); 0477 writer->writeAttribute( "axisPointSceneX1", QString::number(d->axisPoints.scenePos[0].x()) ); 0478 writer->writeAttribute( "axisPointSceneY1", QString::number(d->axisPoints.scenePos[0].y()) ); 0479 writer->writeAttribute( "axisPointSceneX2", QString::number(d->axisPoints.scenePos[1].x()) ); 0480 writer->writeAttribute( "axisPointSceneY2", QString::number(d->axisPoints.scenePos[1].y()) ); 0481 writer->writeAttribute( "axisPointSceneX3", QString::number(d->axisPoints.scenePos[2].x()) ); 0482 writer->writeAttribute( "axisPointSceneY3", QString::number(d->axisPoints.scenePos[2].y()) ); 0483 writer->writeEndElement(); 0484 0485 //editor and segment settings 0486 writer->writeStartElement( "editorSettings" ); 0487 writer->writeAttribute( "plotImageType", QString::number(static_cast<int>(d->plotImageType)) ); 0488 writer->writeAttribute( "rotationAngle", QString::number(d->rotationAngle) ); 0489 writer->writeAttribute( "minSegmentLength", QString::number(d->minSegmentLength) ); 0490 writer->writeAttribute( "pointSeparation", QString::number(d->pointSeparation) ); 0491 writer->writeAttribute( "foregroundThresholdHigh", QString::number(d->settings.foregroundThresholdHigh) ); 0492 writer->writeAttribute( "foregroundThresholdLow", QString::number(d->settings.foregroundThresholdLow) ); 0493 writer->writeAttribute( "hueThresholdHigh", QString::number(d->settings.hueThresholdHigh) ); 0494 writer->writeAttribute( "hueThresholdLow", QString::number(d->settings.hueThresholdLow) ); 0495 writer->writeAttribute( "intensityThresholdHigh", QString::number(d->settings.intensityThresholdHigh) ); 0496 writer->writeAttribute( "intensityThresholdLow", QString::number(d->settings.intensityThresholdLow) ); 0497 writer->writeAttribute( "saturationThresholdHigh", QString::number(d->settings.saturationThresholdHigh) ); 0498 writer->writeAttribute( "saturationThresholdLow", QString::number(d->settings.saturationThresholdLow) ); 0499 writer->writeAttribute( "valueThresholdHigh", QString::number(d->settings.valueThresholdHigh) ); 0500 writer->writeAttribute( "valueThresholdLow", QString::number(d->settings.valueThresholdLow) ); 0501 writer->writeEndElement(); 0502 0503 //symbol properties 0504 writer->writeStartElement( "symbolProperties" ); 0505 writer->writeAttribute( "pointRotationAngle", QString::number(d->pointRotationAngle) ); 0506 writer->writeAttribute( "pointOpacity", QString::number(d->pointOpacity) ); 0507 writer->writeAttribute( "pointSize", QString::number(d->pointSize) ); 0508 writer->writeAttribute( "pointStyle", QString::number(static_cast<int>(d->pointStyle)) ); 0509 writer->writeAttribute( "pointVisibility", QString::number(d->pointVisibility) ); 0510 WRITE_QBRUSH(d->pointBrush); 0511 WRITE_QPEN(d->pointPen); 0512 writer->writeEndElement(); 0513 0514 //serialize all children 0515 for (auto* child : children<AbstractAspect>(ChildIndexFlag::IncludeHidden)) 0516 child->save(writer); 0517 0518 writer->writeEndElement(); 0519 } 0520 0521 //! Load from XML 0522 bool DatapickerImage::load(XmlStreamReader* reader, bool preview) { 0523 if (!readBasicAttributes(reader)) 0524 return false; 0525 0526 KLocalizedString attributeWarning = ki18n("Attribute '%1' missing or empty, default value is used"); 0527 QXmlStreamAttributes attribs; 0528 QString str; 0529 0530 while (!reader->atEnd()) { 0531 reader->readNext(); 0532 if (reader->isEndElement() && reader->name() == "datapickerImage") 0533 break; 0534 0535 if (!reader->isStartElement()) 0536 continue; 0537 0538 if (!preview && reader->name() == "general") { 0539 attribs = reader->attributes(); 0540 0541 str = attribs.value("fileName").toString(); 0542 d->fileName = str; 0543 0544 READ_INT_VALUE("plotPointsType", plotPointsType, DatapickerImage::PointsType); 0545 } else if (!preview && reader->name() == "axisPoint") { 0546 attribs = reader->attributes(); 0547 0548 READ_INT_VALUE("graphType", axisPoints.type, DatapickerImage::GraphType); 0549 READ_INT_VALUE("ternaryScale", axisPoints.ternaryScale, int); 0550 0551 str = attribs.value("axisPointLogicalX1").toString(); 0552 if (str.isEmpty()) 0553 reader->raiseWarning(attributeWarning.subs("axisPointLogicalX1").toString()); 0554 else 0555 d->axisPoints.logicalPos[0].setX(str.toDouble()); 0556 0557 str = attribs.value("axisPointLogicalY1").toString(); 0558 if (str.isEmpty()) 0559 reader->raiseWarning(attributeWarning.subs("axisPointLogicalY1").toString()); 0560 else 0561 d->axisPoints.logicalPos[0].setY(str.toDouble()); 0562 0563 str = attribs.value("axisPointLogicalZ1").toString(); 0564 if (str.isEmpty()) 0565 reader->raiseWarning(attributeWarning.subs("axisPointLogicalZ1").toString()); 0566 else 0567 d->axisPoints.logicalPos[0].setZ(str.toDouble()); 0568 0569 str = attribs.value("axisPointLogicalX2").toString(); 0570 if (str.isEmpty()) 0571 reader->raiseWarning(attributeWarning.subs("axisPointLogicalX2").toString()); 0572 else 0573 d->axisPoints.logicalPos[1].setX(str.toDouble()); 0574 0575 str = attribs.value("axisPointLogicalY2").toString(); 0576 if (str.isEmpty()) 0577 reader->raiseWarning(attributeWarning.subs("axisPointLogicalY2").toString()); 0578 else 0579 d->axisPoints.logicalPos[1].setY(str.toDouble()); 0580 0581 str = attribs.value("axisPointLogicalZ2").toString(); 0582 if (str.isEmpty()) 0583 reader->raiseWarning(attributeWarning.subs("axisPointLogicalZ2").toString()); 0584 else 0585 d->axisPoints.logicalPos[1].setZ(str.toDouble()); 0586 0587 str = attribs.value("axisPointLogicalX3").toString(); 0588 if (str.isEmpty()) 0589 reader->raiseWarning(attributeWarning.subs("axisPointLogicalX3").toString()); 0590 else 0591 d->axisPoints.logicalPos[2].setX(str.toDouble()); 0592 0593 str = attribs.value("axisPointLogicalY3").toString(); 0594 if (str.isEmpty()) 0595 reader->raiseWarning(attributeWarning.subs("axisPointLogicalY3").toString()); 0596 else 0597 d->axisPoints.logicalPos[2].setY(str.toDouble()); 0598 0599 str = attribs.value("axisPointLogicalZ3").toString(); 0600 if (str.isEmpty()) 0601 reader->raiseWarning(attributeWarning.subs("axisPointLogicalZ3").toString()); 0602 else 0603 d->axisPoints.logicalPos[2].setZ(str.toDouble()); 0604 0605 str = attribs.value("axisPointSceneX1").toString(); 0606 if (str.isEmpty()) 0607 reader->raiseWarning(attributeWarning.subs("axisPointSceneX1").toString()); 0608 else 0609 d->axisPoints.scenePos[0].setX(str.toDouble()); 0610 0611 str = attribs.value("axisPointSceneY1").toString(); 0612 if (str.isEmpty()) 0613 reader->raiseWarning(attributeWarning.subs("axisPointSceneY1").toString()); 0614 else 0615 d->axisPoints.scenePos[0].setY(str.toDouble()); 0616 0617 str = attribs.value("axisPointSceneX2").toString(); 0618 if (str.isEmpty()) 0619 reader->raiseWarning(attributeWarning.subs("axisPointSceneX2").toString()); 0620 else 0621 d->axisPoints.scenePos[1].setX(str.toDouble()); 0622 0623 str = attribs.value("axisPointSceneY2").toString(); 0624 if (str.isEmpty()) 0625 reader->raiseWarning(attributeWarning.subs("axisPointSceneY2").toString()); 0626 else 0627 d->axisPoints.scenePos[1].setY(str.toDouble()); 0628 0629 str = attribs.value("axisPointSceneX3").toString(); 0630 if (str.isEmpty()) 0631 reader->raiseWarning(attributeWarning.subs("axisPointSceneX3").toString()); 0632 else 0633 d->axisPoints.scenePos[2].setX(str.toDouble()); 0634 0635 str = attribs.value("axisPointSceneY3").toString(); 0636 if (str.isEmpty()) 0637 reader->raiseWarning(attributeWarning.subs("axisPointSceneY3").toString()); 0638 else 0639 d->axisPoints.scenePos[2].setY(str.toDouble()); 0640 0641 } else if (!preview && reader->name() == "editorSettings") { 0642 attribs = reader->attributes(); 0643 0644 READ_INT_VALUE("plotImageType", plotImageType, DatapickerImage::PlotImageType); 0645 READ_DOUBLE_VALUE("rotationAngle", rotationAngle); 0646 READ_INT_VALUE("minSegmentLength", minSegmentLength, int); 0647 READ_INT_VALUE("pointSeparation", pointSeparation, int); 0648 READ_INT_VALUE("foregroundThresholdHigh", settings.foregroundThresholdHigh, int); 0649 READ_INT_VALUE("foregroundThresholdLow", settings.foregroundThresholdLow, int); 0650 READ_INT_VALUE("hueThresholdHigh", settings.hueThresholdHigh, int); 0651 READ_INT_VALUE("hueThresholdLow", settings.hueThresholdLow, int); 0652 READ_INT_VALUE("intensityThresholdHigh", settings.intensityThresholdHigh, int); 0653 READ_INT_VALUE("intensityThresholdLow", settings.intensityThresholdLow, int); 0654 READ_INT_VALUE("saturationThresholdHigh", settings.saturationThresholdHigh, int); 0655 READ_INT_VALUE("saturationThresholdLow", settings.saturationThresholdLow, int); 0656 READ_INT_VALUE("valueThresholdHigh", settings.valueThresholdHigh, int); 0657 READ_INT_VALUE("valueThresholdLow", settings.valueThresholdLow, int); 0658 } else if (!preview && reader->name() == "symbolProperties") { 0659 attribs = reader->attributes(); 0660 0661 READ_DOUBLE_VALUE("pointRotationAngle", pointRotationAngle); 0662 READ_DOUBLE_VALUE("pointOpacity", pointOpacity); 0663 READ_DOUBLE_VALUE("pointSize", pointSize); 0664 READ_INT_VALUE("pointStyle", pointStyle, Symbol::Style); 0665 READ_INT_VALUE("pointVisibility", pointVisibility, bool); 0666 READ_QBRUSH(d->pointBrush); 0667 READ_QPEN(d->pointPen); 0668 } else if (reader->name() == "datapickerPoint") { 0669 auto* datapickerPoint = new DatapickerPoint(QString()); 0670 datapickerPoint->setHidden(true); 0671 if (!datapickerPoint->load(reader, preview)) { 0672 delete datapickerPoint; 0673 return false; 0674 } else 0675 addChild(datapickerPoint); 0676 } else { // unknown element 0677 reader->raiseWarning(i18n("unknown element '%1'", reader->name().toString())); 0678 if (!reader->skipToEndElement()) return false; 0679 } 0680 } 0681 0682 d->uploadImage(d->fileName); 0683 d->retransform(); 0684 return true; 0685 }