File indexing completed on 2024-04-28 03:50:18

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