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"