File indexing completed on 2025-01-05 03:59:25

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2006-2007 Torsten Rahn <tackat@kde.org>
0004 // SPDX-FileCopyrightText: 2007-2008 Inge Wallin <ingwa@kde.org>
0005 // SPDX-FileCopyrightText: 2007-2008 Carlos Licea <carlos.licea@kdemail.net>
0006 // SPDX-FileCopyrightText: 2011 Michael Henning <mikehenning@eclipse.net>
0007 // SPDX-FileCopyrightText: 2011 Valery Kharitonov <kharvd@gmail.com>
0008 // SPDX-FileCopyrightText: 2012 Mohammed Nafees <nafees.technocool@gmail.com>
0009 //
0010 
0011 #include "MeasureToolPlugin.h"
0012 
0013 #include <QDialog>
0014 #include <QColor>
0015 #include <QTextDocument>
0016 #include <qmath.h>
0017 
0018 #include "MeasureConfigDialog.h"
0019 #include "GeoPainter.h"
0020 #include "GeoDataLinearRing.h"
0021 #include "MarbleColors.h"
0022 #include "MarbleWidgetPopupMenu.h"
0023 #include "MarbleModel.h"
0024 #include "MarbleLocale.h"
0025 #include "ViewportParams.h"
0026 #include "Planet.h"
0027 
0028 #include <klocalizedstring.h>
0029 
0030 #include "digikam_debug.h"
0031 
0032 namespace Marble
0033 {
0034 
0035 MeasureToolPlugin::MeasureToolPlugin( const MarbleModel *marbleModel )
0036     : RenderPlugin( marbleModel ),
0037       m_measureLineString( GeoDataLineString( Tessellate ) ),
0038 #ifdef Q_OS_MACX
0039       m_font_regular( QFont( QStringLiteral( "Sans Serif" ), 10, 50, false ) ),
0040 #else
0041       m_font_regular( QFont( QStringLiteral( "Sans Serif" ),  8, 50, false ) ),
0042 #endif
0043       m_fontascent(-1),
0044       m_pen( Qt::red ),
0045       m_addMeasurePointAction( nullptr ),
0046       m_removeLastMeasurePointAction( nullptr ),
0047       m_removeMeasurePointsAction( nullptr ),
0048       m_separator( nullptr ),
0049       m_marbleWidget( nullptr ),
0050       m_configDialog( nullptr ),
0051       m_showDistanceLabel( true ),
0052       m_showBearingLabel( true ),
0053       m_showBearingChangeLabel( true ),
0054       m_showPolygonArea(false),
0055       m_showCircularArea(true),
0056       m_showRadius(true),
0057       m_showPerimeter(true),
0058       m_showCircumference(true),
0059       m_totalDistance(0.0),
0060       m_polygonArea(0.0),
0061       m_circularArea(0.0),
0062       m_radius(0.0),
0063       m_perimeter(0.0),
0064       m_circumference(0.0),
0065       m_paintMode(Polygon)
0066 {
0067     m_pen.setWidthF( 2.0 );
0068 }
0069 
0070 QStringList MeasureToolPlugin::backendTypes() const
0071 {
0072     return QStringList(QStringLiteral("measuretool"));
0073 }
0074 
0075 QString MeasureToolPlugin::renderPolicy() const
0076 {
0077     return QStringLiteral("ALWAYS");
0078 }
0079 
0080 QStringList MeasureToolPlugin::renderPosition() const
0081 {
0082     return QStringList(QStringLiteral("ATMOSPHERE"));
0083 }
0084 
0085 QString MeasureToolPlugin::name() const
0086 {
0087     return i18n( "Measure Tool" );
0088 }
0089 
0090 QString MeasureToolPlugin::guiString() const
0091 {
0092     return i18n( "&Measure Tool" );
0093 }
0094 
0095 QString MeasureToolPlugin::nameId() const
0096 {
0097     return QStringLiteral("measure-tool");
0098 }
0099 
0100 QString MeasureToolPlugin::version() const
0101 {
0102     return QStringLiteral("1.0");
0103 }
0104 
0105 QString MeasureToolPlugin::description() const
0106 {
0107     return i18n( "Measure distances between two or more points." );
0108 }
0109 
0110 QString MeasureToolPlugin::copyrightYears() const
0111 {
0112     return QStringLiteral("2006-2008, 2011");
0113 }
0114 
0115 QVector<PluginAuthor> MeasureToolPlugin::pluginAuthors() const
0116 {
0117     return QVector<PluginAuthor>()
0118             << PluginAuthor(QStringLiteral("Dennis Nienhüser"), QStringLiteral("nienhueser@kde.org"))
0119             << PluginAuthor(QStringLiteral("Torsten Rahn"), QStringLiteral("tackat@kde.org"))
0120             << PluginAuthor(QStringLiteral("Inge Wallin"), QStringLiteral("ingwa@kde.org"))
0121             << PluginAuthor(QStringLiteral("Carlos Licea"), QStringLiteral("carlos.licea@kdemail.net"))
0122             << PluginAuthor(QStringLiteral("Michael Henning"), QStringLiteral("mikehenning@eclipse.net"))
0123             << PluginAuthor(QStringLiteral("Valery Kharitonov"), QStringLiteral("kharvd@gmail.com"))
0124             << PluginAuthor(QStringLiteral("Mohammed Nafees"), QStringLiteral("nafees.technocool@gmail.com"))
0125             << PluginAuthor(QStringLiteral("Illya Kovalevskyy"), QStringLiteral("illya.kovalevskyy@gmail.com"));
0126 }
0127 
0128 QIcon MeasureToolPlugin::icon () const
0129 {
0130     return QIcon::fromTheme(QStringLiteral("measure"));
0131 }
0132 
0133 void MeasureToolPlugin::initialize ()
0134 {
0135     m_fontascent = QFontMetrics( m_font_regular ).ascent();
0136 }
0137 
0138 bool MeasureToolPlugin::isInitialized () const
0139 {
0140     return (m_fontascent >= 0);
0141 }
0142 
0143 QDialog *MeasureToolPlugin::configDialog()
0144 {
0145     if ( !m_configDialog ) {
0146         m_configDialog = new MeasureConfigDialog(m_configDialog);
0147         connect( m_configDialog, SIGNAL(accepted()),
0148                  SLOT(writeSettings()) );
0149         connect( m_configDialog, SIGNAL(applied()),
0150                  this, SLOT(writeSettings()) );
0151     }
0152 
0153     m_configDialog->setShowDistanceLabels( m_showDistanceLabel );
0154     m_configDialog->setShowBearingLabel( m_showBearingLabel );
0155     m_configDialog->setShowBearingLabelChange( m_showBearingChangeLabel );
0156     m_configDialog->setShowPolygonArea( m_showPolygonArea );
0157     m_configDialog->setShowCircularArea( m_showCircularArea );
0158     m_configDialog->setShowRadius( m_showRadius );
0159     m_configDialog->setShowPerimeter( m_showPerimeter );
0160     m_configDialog->setShowCircumference( m_showCircumference );
0161     m_configDialog->setPaintMode( m_paintMode );
0162 
0163     return m_configDialog;
0164 }
0165 
0166 QHash<QString,QVariant> MeasureToolPlugin::settings() const
0167 {
0168     QHash<QString, QVariant> settings = RenderPlugin::settings();
0169 
0170     settings.insert(QStringLiteral("showDistanceLabel"), m_showDistanceLabel);
0171     settings.insert(QStringLiteral("showBearingLabel"), m_showBearingLabel);
0172     settings.insert(QStringLiteral("showBearingChangeLabel"), m_showBearingChangeLabel);
0173     settings.insert(QStringLiteral("showPolygonArea"), m_showPolygonArea);
0174     settings.insert(QStringLiteral("showCircularArea"), m_showCircularArea);
0175     settings.insert(QStringLiteral("showRadius"), m_showRadius);
0176     settings.insert(QStringLiteral("showPerimeter"), m_showPerimeter);
0177     settings.insert(QStringLiteral("showCircumference"), m_showCircumference);
0178     settings.insert(QStringLiteral("paintMode"), (int)m_paintMode);
0179 
0180     return settings;
0181 }
0182 
0183 void MeasureToolPlugin::setSettings( const QHash<QString,QVariant> &settings )
0184 {
0185     RenderPlugin::setSettings( settings );
0186 
0187     m_showDistanceLabel = settings.value(QStringLiteral("showDistanceLabel"), true).toBool();
0188     m_showBearingLabel = settings.value(QStringLiteral("showBearingLabel"), true).toBool();
0189     m_showBearingChangeLabel = settings.value(QStringLiteral("showBearingChangeLabel"), true).toBool();
0190     m_showPolygonArea = settings.value(QStringLiteral("showPolygonArea"), false).toBool();
0191     m_showCircularArea = settings.value(QStringLiteral("showCircularArea"), true).toBool();
0192     m_showRadius = settings.value(QStringLiteral("showRadius"), true).toBool();
0193     m_showPerimeter = settings.value(QStringLiteral("showPerimeter"), true).toBool();
0194     m_showCircumference = settings.value(QStringLiteral("showCircumference"), true).toBool();
0195     m_paintMode = (PaintMode)settings.value(QStringLiteral("paintMode"), 0).toInt();
0196 }
0197 
0198 void MeasureToolPlugin::writeSettings()
0199 {
0200     m_showDistanceLabel = m_configDialog->showDistanceLabels();
0201     m_showBearingLabel = m_configDialog->showBearingLabel();
0202     m_showBearingChangeLabel = m_configDialog->showBearingLabelChange();
0203     m_showPolygonArea = m_configDialog->showPolygonArea();
0204     m_showCircularArea = m_configDialog->showCircularArea();
0205     m_showRadius = m_configDialog->showRadius();
0206     m_showPerimeter = m_configDialog->showPerimeter();
0207     m_showCircumference = m_configDialog->showCircumference();
0208     m_paintMode = (PaintMode)m_configDialog->paintMode();
0209 
0210     if (m_paintMode == Circular) {
0211         if (m_measureLineString.size() < 2) {
0212             m_addMeasurePointAction->setEnabled(true);
0213         } else {
0214             m_addMeasurePointAction->setEnabled(false);
0215             while (m_measureLineString.size() > 2)
0216                 m_measureLineString.remove(m_measureLineString.size()-1);
0217         }
0218     } else {
0219         m_addMeasurePointAction->setEnabled(true);
0220     }
0221 
0222     Q_EMIT settingsChanged( nameId() );
0223     Q_EMIT repaintNeeded();
0224 }
0225 
0226 bool MeasureToolPlugin::render( GeoPainter *painter,
0227                           ViewportParams *viewport,
0228                           const QString& renderPos,
0229                           GeoSceneLayer * layer )
0230 {
0231     Q_UNUSED(renderPos)
0232     Q_UNUSED(layer)
0233 
0234     m_latLonAltBox = viewport->viewLatLonAltBox();
0235 
0236     // No way to paint anything if the list is empty.
0237     if ( m_measureLineString.isEmpty() )
0238         return true;
0239 
0240     painter->save();
0241 
0242     // Prepare for painting the measure line string and paint it.
0243     painter->setPen( m_pen );
0244 
0245     if ( m_showDistanceLabel || m_showBearingLabel || m_showBearingChangeLabel ) {
0246         drawSegments( painter );
0247     } else {
0248         painter->drawPolyline( m_measureLineString );
0249     }
0250 
0251     // Paint the nodes of the paths.
0252     drawMeasurePoints( painter );
0253 
0254     m_totalDistance = m_measureLineString.length( marbleModel()->planet()->radius() );
0255 
0256     if ( m_measureLineString.size() > 1 )
0257         drawInfobox(painter);
0258 
0259     painter->restore();
0260 
0261     return true;
0262 }
0263 
0264 void MeasureToolPlugin::drawSegments( GeoPainter* painter )
0265 {
0266     for ( int segmentIndex = 0; segmentIndex < m_measureLineString.size() - 1; ++segmentIndex ) {
0267         GeoDataLineString segment( Tessellate );
0268         segment << m_measureLineString[segmentIndex] ;
0269         segment << m_measureLineString[segmentIndex + 1];
0270 
0271         QPen shadowPen( Oxygen::aluminumGray5 );
0272         shadowPen.setWidthF(4.0);
0273         painter->setPen( shadowPen );
0274         painter->drawPolyline( segment );
0275 
0276         QString infoString;
0277 
0278         if ( (m_paintMode == Polygon && m_showDistanceLabel)
0279              || (m_paintMode == Circular && m_showRadius) ) {
0280             const qreal segmentLength = segment.length( marbleModel()->planet()->radius() );
0281             m_radius = segmentLength;
0282 
0283             infoString = meterToPreferredUnit(segmentLength);
0284         }
0285 
0286         if ( m_showBearingLabel && m_paintMode != Circular ) {
0287             GeoDataCoordinates coordinates = segment.first();
0288             qreal bearing = coordinates.bearing( segment.last(), GeoDataCoordinates::Degree );
0289 
0290             if ( bearing < 0 ) {
0291                 bearing += 360;
0292             }
0293             QString bearingString = QString::fromUtf8( "%1°" ).arg( bearing, 0, 'f', 2 );
0294             if ( !infoString.isEmpty() ) {
0295                 infoString += QLatin1Char('\n');
0296             }
0297             infoString.append( bearingString );
0298         }
0299 
0300         if ( m_showBearingChangeLabel && segmentIndex != 0 ) {
0301             GeoDataCoordinates currentCoordinates = m_measureLineString[segmentIndex];
0302             qreal currentBearing = currentCoordinates.bearing(m_measureLineString[segmentIndex+1]);
0303             qreal previousBearing = currentCoordinates.bearing( m_measureLineString[segmentIndex-1]);
0304 
0305             GeoDataLinearRing ring;
0306             painter->setPen( Qt::NoPen );
0307             painter->setBrush( QBrush ( QColor ( 127, 127, 127, 127 ) ) );
0308 
0309             if (currentBearing < previousBearing) currentBearing += 2 * M_PI;
0310             ring << currentCoordinates;
0311 
0312             qreal angleLength = qAbs(m_latLonAltBox.north() - m_latLonAltBox.south()) / 20;
0313 
0314             qreal iterBearing = previousBearing;
0315             while ( iterBearing < currentBearing ) {
0316                 ring << currentCoordinates.moveByBearing( iterBearing, angleLength );
0317                 iterBearing += 0.1;
0318             }
0319 
0320             ring << currentCoordinates.moveByBearing( currentBearing, angleLength );
0321 
0322             painter->drawPolygon( ring );
0323 
0324             qreal currentBearingChange = (currentBearing - previousBearing) * RAD2DEG;
0325             if (currentBearingChange < 0) currentBearingChange += 360;
0326             QString bearingChangedString = QString::fromUtf8( "%1°" ).arg( currentBearingChange, 0, 'f', 2 );
0327             painter->setPen( Qt::black );
0328             GeoDataCoordinates textPosition = ring.latLonAltBox().center();
0329             qreal deltaEast = ring.latLonAltBox().east() - currentCoordinates.longitude();
0330             qreal deltaWest = currentCoordinates.longitude() - ring.latLonAltBox().west();
0331             if (deltaEast > deltaWest) {
0332                 textPosition.setLongitude(currentCoordinates.longitude() + deltaEast / 2);
0333             }
0334             else {
0335                 textPosition.setLongitude(currentCoordinates.longitude() - deltaWest);
0336             }
0337             painter->drawText(textPosition, bearingChangedString );
0338        }
0339 
0340         // Drawing ellipse around 1st point towards the 2nd
0341         if ( m_paintMode == Circular ) {
0342             GeoDataCoordinates currentCoordinates = m_measureLineString[segmentIndex];
0343 
0344             GeoDataLinearRing ring;
0345 
0346             // planetRadius - planet radius
0347             // d - distance between points
0348             // S - area of the painted circle
0349             qreal planetRadius = marbleModel()->planet()->radius();
0350             qreal d = m_measureLineString.length(1);
0351             m_circularArea = 2 * M_PI * planetRadius * planetRadius * (1 - qCos(d));
0352 
0353             qreal iterBearing = 0;
0354             while ( iterBearing < 2 * M_PI ) {
0355                 ring << currentCoordinates.moveByBearing(iterBearing, d);
0356                 iterBearing += 0.1;
0357             }
0358 
0359             painter->setPen( Qt::NoPen );
0360             painter->setBrush( QBrush ( QColor ( 127, 127, 127, 127 ) ) );
0361             painter->drawPolygon(ring);
0362 
0363             if ( m_showCircularArea ) {
0364                 painter->setPen(Qt::white);
0365                 GeoDataCoordinates textPosition = ring.latLonAltBox().center();
0366 
0367                 QString areaText = i18n("Area:\n%1").arg(meterToPreferredUnit(m_circularArea, true));
0368 
0369                 QFontMetrics fontMetrics = painter->fontMetrics();
0370                 QRect boundingRect = fontMetrics.boundingRect(QRect(), Qt::AlignCenter, areaText);
0371 
0372                 painter->drawText(textPosition,
0373                                   areaText,
0374                                   -boundingRect.width()/2, -boundingRect.height()*1.5,
0375                                   boundingRect.width(), boundingRect.height(),
0376                                   QTextOption(Qt::AlignCenter));
0377             }
0378 
0379             if ( m_showCircumference ) {
0380                 painter->setPen(Qt::white);
0381                 GeoDataCoordinates textPosition = ring.latLonAltBox().center();
0382 
0383                 m_circumference = 2 * M_PI * planetRadius * qSin(d);
0384 
0385                 QString circumferenceText = i18n("Circumference:\n%1").arg(meterToPreferredUnit(m_circumference));
0386 
0387                 QFontMetrics fontMetrics = painter->fontMetrics();
0388                 QRect boundingRect = fontMetrics.boundingRect(QRect(),Qt::AlignCenter,
0389                                                               circumferenceText);
0390 
0391                 painter->drawText(textPosition,
0392                                   circumferenceText,
0393                                   -boundingRect.width()/2, boundingRect.height(),
0394                                   boundingRect.width(), boundingRect.height(),
0395                                   QTextOption(Qt::AlignCenter));
0396             }
0397         }
0398 
0399         if ( !infoString.isEmpty() ) {
0400             QPen linePen;
0401 
0402             // have three alternating colors for the segments
0403             switch ( segmentIndex % 3 ) {
0404             case 0:
0405                 linePen.setColor( Oxygen::brickRed4 );
0406                 break;
0407             case 1:
0408                 linePen.setColor( Oxygen::forestGreen4 );
0409                 break;
0410             case 2:
0411                 linePen.setColor( Oxygen::skyBlue4 );
0412                 break;
0413             }
0414 
0415             linePen.setWidthF(2.0);
0416             painter->setPen( linePen );
0417             painter->drawPolyline( segment, infoString, LineCenter );
0418         }
0419     }
0420 
0421     if (m_paintMode == Polygon && m_measureLineString.size() > 2) {
0422         GeoDataLinearRing measureRing(m_measureLineString);
0423 
0424         if (m_showPolygonArea || m_showPerimeter) {
0425             painter->setPen( Qt::NoPen );
0426             painter->setBrush( QBrush ( QColor ( 127, 127, 127, 127 ) ) );
0427             painter->drawPolygon(measureRing);
0428 
0429             QPen shadowPen( Oxygen::aluminumGray5 );
0430             shadowPen.setStyle(Qt::DashLine);
0431             shadowPen.setWidthF(3.0);
0432             painter->setPen( shadowPen );
0433             painter->drawPolyline(GeoDataLineString( Tessellate ) << m_measureLineString.first()
0434                                                       << m_measureLineString.last());
0435         }
0436 
0437         if (m_showPolygonArea) {
0438             qreal theta1 = 0.0;
0439             qreal n = m_measureLineString.size();
0440 
0441             for (int segmentIndex = 1; segmentIndex < m_measureLineString.size()-1; segmentIndex++) {
0442                 GeoDataCoordinates current = m_measureLineString[segmentIndex];
0443                 qreal prevBearing = current.bearing(m_measureLineString[segmentIndex-1]);
0444                 qreal nextBearing = current.bearing(m_measureLineString[segmentIndex+1]);
0445                 if (nextBearing < prevBearing)
0446                     nextBearing += 2 * M_PI;
0447 
0448                 qreal angle = nextBearing - prevBearing;
0449                 theta1 += angle;
0450             }
0451 
0452             // Traversing first vertex
0453             GeoDataCoordinates current = m_measureLineString[0];
0454             qreal prevBearing = current.bearing(m_measureLineString[n-1]);
0455             qreal nextBearing = current.bearing(m_measureLineString[1]);
0456             if (nextBearing < prevBearing)
0457                 nextBearing += 2 * M_PI;
0458             qreal angle = nextBearing - prevBearing;
0459             theta1 += angle;
0460 
0461             // And the last one
0462             current = m_measureLineString[n-1];
0463             prevBearing = current.bearing(m_measureLineString[n-2]);
0464             nextBearing = current.bearing(m_measureLineString[0]);
0465             if (nextBearing < prevBearing)
0466                 nextBearing += 2 * M_PI;
0467             angle = nextBearing - prevBearing;
0468             theta1 += angle;
0469 
0470             qreal theta2 = 2 * M_PI * n - theta1;
0471 
0472             // theta = smaller of theta1 and theta2
0473             qreal theta = (theta1 < theta2) ? theta1 : theta2;
0474 
0475             qreal planetRadius = marbleModel()->planet()->radius();
0476             qreal S = qAbs((theta - (n-2) * M_PI) * planetRadius * planetRadius);
0477             m_polygonArea = S;
0478 
0479             painter->setPen(Qt::white);
0480             GeoDataCoordinates textPosition = measureRing.latLonAltBox().center();
0481 
0482             QString areaText = i18n("Area:\n%1").arg(meterToPreferredUnit(S, true));
0483 
0484             QFontMetrics fontMetrics = painter->fontMetrics();
0485             QRect boundingRect = fontMetrics.boundingRect(QRect(), Qt::AlignCenter, areaText);
0486 
0487             painter->drawText(textPosition,
0488                               areaText,
0489                               -boundingRect.width()/2, -(boundingRect.height()+fontMetrics.height()*0.25),
0490                               boundingRect.width(), boundingRect.height(),
0491                               QTextOption(Qt::AlignCenter));
0492         }
0493 
0494         if (m_showPerimeter) {
0495             painter->setPen(Qt::white);
0496             GeoDataCoordinates textPosition = measureRing.latLonAltBox().center();
0497 
0498             qreal P = measureRing.length(marbleModel()->planet()->radius());
0499             m_perimeter = P;
0500             QString perimeterText = i18n("Perimeter:\n%1").arg(meterToPreferredUnit(P));
0501 
0502             QFontMetrics fontMetrics = painter->fontMetrics();
0503             QRect boundingRect = fontMetrics.boundingRect(QRect(),Qt::AlignCenter,
0504                                                           perimeterText);
0505 
0506             painter->drawText(textPosition,
0507                               perimeterText,
0508                               -boundingRect.width()/2, 0,
0509                               boundingRect.width(), boundingRect.height(),
0510                               QTextOption(Qt::AlignCenter));
0511         }
0512     }
0513 }
0514 
0515 QString MeasureToolPlugin::meterToPreferredUnit(qreal meters, bool isSquare)
0516 {
0517     MarbleLocale *locale = MarbleGlobal::getInstance()->locale();
0518     const MarbleLocale::MeasurementSystem measurementSystem = locale->measurementSystem();
0519     MarbleLocale::MeasureUnit unit;
0520     qreal convertedMeters;
0521     if (isSquare)
0522         meters = qSqrt(meters);
0523 
0524     locale->meterToTargetUnit(meters, measurementSystem, convertedMeters, unit);
0525     QString unitString = locale->unitAbbreviation(unit);
0526 
0527     if (isSquare) {
0528         qreal k = convertedMeters/meters;
0529         convertedMeters *= k;
0530         convertedMeters *= meters;
0531 
0532         unitString.append(QChar(0xB2));
0533     }
0534 
0535     return QString::fromUtf8("%L1 %2").arg(convertedMeters, 8, 'f', 1, QLatin1Char(' '))
0536                             .arg(unitString);
0537 }
0538 
0539 void MeasureToolPlugin::drawMeasurePoints( GeoPainter *painter )
0540 {
0541     // Paint the marks.
0542     GeoDataLineString::const_iterator itpoint = m_measureLineString.constBegin();
0543     GeoDataLineString::const_iterator const endpoint = m_measureLineString.constEnd();
0544     if (m_mark.isNull()) {
0545         m_mark = QPixmap(QStringLiteral(":/mark.png"));
0546     }
0547     for (; itpoint != endpoint; ++itpoint )
0548     {
0549         painter->drawPixmap( *itpoint, m_mark );
0550     }
0551 }
0552 
0553 void MeasureToolPlugin::drawInfobox( GeoPainter *painter ) const
0554 {
0555     QString boxContent;
0556 
0557     if (m_paintMode == Polygon) {
0558         boxContent += QLatin1String("<strong>") + i18n("Polygon Ruler") + QLatin1String(":</strong><br/>\n");
0559     } else /* Circular */ {
0560         boxContent += QLatin1String("<strong>") + i18n("Circle Ruler") + QLatin1String(":</strong><br/>\n");
0561     }
0562     if (m_paintMode == Polygon) {
0563         boxContent += i18n("Total Distance: %1<br/>\n").arg( meterToPreferredUnit(m_totalDistance) );
0564         if (m_showPolygonArea)
0565             boxContent += i18n("Area: %1<br/>\n").arg( meterToPreferredUnit(m_polygonArea, true) );
0566         if (m_showPerimeter)
0567             boxContent += i18n("Perimeter: %1<br/>\n").arg( meterToPreferredUnit(m_perimeter) );
0568     } else /* Circular */ {
0569         if (m_showRadius)
0570             boxContent += i18n("Radius: %1<br/>\n").arg( meterToPreferredUnit(m_radius) );
0571         if (m_showCircumference)
0572             boxContent += i18n("Circumference: %1<br/>\n").arg( meterToPreferredUnit(m_circumference) );
0573         if (m_showCircularArea)
0574             boxContent += i18n("Area: %1<br/>\n").arg( meterToPreferredUnit(m_circularArea, true) );
0575     }
0576 
0577     painter->setPen( QColor( Qt::black ) );
0578     painter->setBrush( QColor( 192, 192, 192, 192 ) );
0579 
0580     QTextDocument doc;
0581     doc.setHtml(boxContent);
0582     doc.setDefaultFont(m_font_regular);
0583     doc.adjustSize();
0584     QSizeF pageSize = doc.size();
0585 
0586     painter->drawRect( 10, 105, 10 + pageSize.width(), pageSize.height() );
0587     QTransform transform;
0588     transform.translate(15, 110);
0589     painter->setTransform(transform);
0590     doc.drawContents(painter);
0591     painter->setTransform(QTransform());
0592 }
0593 
0594 void MeasureToolPlugin::addMeasurePoint( qreal lon, qreal lat )
0595 {
0596     m_measureLineString << GeoDataCoordinates( lon, lat );
0597 
0598     Q_EMIT numberOfMeasurePointsChanged( m_measureLineString.size() );
0599 }
0600 
0601 void MeasureToolPlugin::removeLastMeasurePoint()
0602 {
0603     if (!m_measureLineString.isEmpty())
0604         m_measureLineString.remove( m_measureLineString.size() - 1 );
0605 
0606     Q_EMIT numberOfMeasurePointsChanged( m_measureLineString.size() );
0607 }
0608 
0609 void MeasureToolPlugin::removeMeasurePoints()
0610 {
0611     m_measureLineString.clear();
0612 
0613     Q_EMIT numberOfMeasurePointsChanged( m_measureLineString.size() );
0614 }
0615 
0616 void MeasureToolPlugin::addContextItems()
0617 {
0618     MarbleWidgetPopupMenu *menu = m_marbleWidget->popupMenu();
0619 
0620     // Connect the inputHandler and the measure tool to the popup menu
0621     m_addMeasurePointAction = new QAction(QIcon::fromTheme(QStringLiteral("measure")), i18n("Add &Measure Point"), this);
0622     m_removeLastMeasurePointAction = new QAction( i18n( "Remove &Last Measure Point" ), this );
0623     m_removeLastMeasurePointAction->setEnabled( false );
0624     m_removeMeasurePointsAction = new QAction( i18n( "&Remove Measure Points" ), this );
0625     m_removeMeasurePointsAction->setEnabled( false );
0626     m_separator = new QAction( this );
0627     m_separator->setSeparator( true );
0628 
0629     bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen;
0630     if ( !smallScreen ) {
0631         menu->addAction( Qt::RightButton, m_addMeasurePointAction );
0632         menu->addAction( Qt::RightButton, m_removeLastMeasurePointAction );
0633         menu->addAction( Qt::RightButton, m_removeMeasurePointsAction );
0634         menu->addAction( Qt::RightButton, m_separator );
0635     }
0636 
0637     connect( m_addMeasurePointAction, SIGNAL(triggered()), SLOT(addMeasurePointEvent()) );
0638     connect( m_removeLastMeasurePointAction, SIGNAL(triggered()), SLOT(removeLastMeasurePoint()) );
0639     connect( m_removeMeasurePointsAction, SIGNAL(triggered()), SLOT(removeMeasurePoints()) );
0640 
0641     connect( this, SIGNAL(numberOfMeasurePointsChanged(int)), SLOT(setNumberOfMeasurePoints(int)) );
0642 }
0643 
0644 void MeasureToolPlugin::removeContextItems()
0645 {
0646     delete m_addMeasurePointAction;
0647     delete m_removeLastMeasurePointAction;
0648     delete m_removeMeasurePointsAction;
0649     delete m_separator;
0650 }
0651 
0652 void MeasureToolPlugin::addMeasurePointEvent()
0653 {
0654     QPoint p = m_marbleWidget->popupMenu()->mousePosition();
0655 
0656     qreal  lat;
0657     qreal  lon;
0658     m_marbleWidget->geoCoordinates( p.x(), p.y(), lon, lat, GeoDataCoordinates::Radian );
0659 
0660     addMeasurePoint( lon, lat );
0661 }
0662 
0663 void MeasureToolPlugin::setNumberOfMeasurePoints( int newNumber )
0664 {
0665     const bool enableMeasureActions = ( newNumber > 0 );
0666     m_removeMeasurePointsAction->setEnabled(enableMeasureActions);
0667     m_removeLastMeasurePointAction->setEnabled(enableMeasureActions);
0668 
0669     if (m_paintMode == Circular) {
0670         if (newNumber >= 2) {
0671             m_addMeasurePointAction->setEnabled(false);
0672         } else {
0673             m_addMeasurePointAction->setEnabled(true);
0674         }
0675     }
0676 }
0677 
0678 bool MeasureToolPlugin::eventFilter( QObject *object, QEvent *e )
0679 {
0680     if ( m_marbleWidget && !enabled() ) {
0681         m_marbleWidget = nullptr;
0682         removeContextItems();
0683         m_measureLineString.clear();
0684     }
0685 
0686     if ( m_marbleWidget || !enabled() || !visible() ) {
0687         return RenderPlugin::eventFilter( object, e );
0688     }
0689 
0690     MarbleWidget *widget = qobject_cast<MarbleWidget*>( object );
0691 
0692     if ( widget ) {
0693         m_marbleWidget = widget;
0694         addContextItems();
0695     }
0696 
0697     return RenderPlugin::eventFilter( object, e );
0698 }
0699 
0700 }
0701 
0702 #include "moc_MeasureToolPlugin.cpp"