1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 //
3 // SPDX-FileCopyrightText: 2006-2007 Torsten Rahn <tackat@kde.org>
4 // SPDX-FileCopyrightText: 2007-2008 Inge Wallin <ingwa@kde.org>
5 // SPDX-FileCopyrightText: 2007-2008 Carlos Licea <carlos.licea@kdemail.net>
6 // SPDX-FileCopyrightText: 2011 Michael Henning <mikehenning@eclipse.net>
7 // SPDX-FileCopyrightText: 2011 Valery Kharitonov <kharvd@gmail.com>
8 // SPDX-FileCopyrightText: 2012 Mohammed Nafees <nafees.technocool@gmail.com>
9 //
10 
11 #include "MeasureToolPlugin.h"
12 #include "MeasureConfigDialog.h"
13 
14 #include "GeoPainter.h"
15 #include "GeoDataLinearRing.h"
16 #include "MarbleColors.h"
17 #include "MarbleDebug.h"
18 #include "MarbleWidgetPopupMenu.h"
19 #include "MarbleModel.h"
20 #include "MarbleLocale.h"
21 #include "ViewportParams.h"
22 #include "Planet.h"
23 
24 #include <QDialog>
25 #include <QColor>
26 #include <QTextDocument>
27 #include <qmath.h>
28 
29 namespace Marble
30 {
31 
MeasureToolPlugin(const MarbleModel * marbleModel)32 MeasureToolPlugin::MeasureToolPlugin( const MarbleModel *marbleModel )
33     : RenderPlugin( marbleModel ),
34       m_measureLineString( GeoDataLineString( Tessellate ) ),
35 #ifdef Q_OS_MACX
36       m_font_regular( QFont( QStringLiteral( "Sans Serif" ), 10, 50, false ) ),
37 #else
38       m_font_regular( QFont( QStringLiteral( "Sans Serif" ),  8, 50, false ) ),
39 #endif
40       m_fontascent(-1),
41       m_pen( Qt::red ),
42       m_addMeasurePointAction( nullptr ),
43       m_removeLastMeasurePointAction( nullptr ),
44       m_removeMeasurePointsAction( nullptr ),
45       m_separator( nullptr ),
46       m_marbleWidget( nullptr ),
47       m_configDialog( nullptr ),
48       m_showDistanceLabel( true ),
49       m_showBearingLabel( true ),
50       m_showBearingChangeLabel( true ),
51       m_showPolygonArea(false),
52       m_showCircularArea(true),
53       m_showRadius(true),
54       m_showPerimeter(true),
55       m_showCircumference(true),
56       m_totalDistance(0.0),
57       m_polygonArea(0.0),
58       m_circularArea(0.0),
59       m_radius(0.0),
60       m_perimeter(0.0),
61       m_circumference(0.0),
62       m_paintMode(Polygon)
63 {
64     m_pen.setWidthF( 2.0 );
65 }
66 
backendTypes() const67 QStringList MeasureToolPlugin::backendTypes() const
68 {
69     return QStringList(QStringLiteral("measuretool"));
70 }
71 
renderPolicy() const72 QString MeasureToolPlugin::renderPolicy() const
73 {
74     return QStringLiteral("ALWAYS");
75 }
76 
renderPosition() const77 QStringList MeasureToolPlugin::renderPosition() const
78 {
79     return QStringList(QStringLiteral("ATMOSPHERE"));
80 }
81 
name() const82 QString MeasureToolPlugin::name() const
83 {
84     return tr( "Measure Tool" );
85 }
86 
guiString() const87 QString MeasureToolPlugin::guiString() const
88 {
89     return tr( "&Measure Tool" );
90 }
91 
nameId() const92 QString MeasureToolPlugin::nameId() const
93 {
94     return QStringLiteral("measure-tool");
95 }
96 
version() const97 QString MeasureToolPlugin::version() const
98 {
99     return QStringLiteral("1.0");
100 }
101 
description() const102 QString MeasureToolPlugin::description() const
103 {
104     return tr( "Measure distances between two or more points." );
105 }
106 
copyrightYears() const107 QString MeasureToolPlugin::copyrightYears() const
108 {
109     return QStringLiteral("2006-2008, 2011");
110 }
111 
pluginAuthors() const112 QVector<PluginAuthor> MeasureToolPlugin::pluginAuthors() const
113 {
114     return QVector<PluginAuthor>()
115             << PluginAuthor(QStringLiteral("Dennis Nienhüser"), QStringLiteral("nienhueser@kde.org"))
116             << PluginAuthor(QStringLiteral("Torsten Rahn"), QStringLiteral("tackat@kde.org"))
117             << PluginAuthor(QStringLiteral("Inge Wallin"), QStringLiteral("ingwa@kde.org"))
118             << PluginAuthor(QStringLiteral("Carlos Licea"), QStringLiteral("carlos.licea@kdemail.net"))
119             << PluginAuthor(QStringLiteral("Michael Henning"), QStringLiteral("mikehenning@eclipse.net"))
120             << PluginAuthor(QStringLiteral("Valery Kharitonov"), QStringLiteral("kharvd@gmail.com"))
121             << PluginAuthor(QStringLiteral("Mohammed Nafees"), QStringLiteral("nafees.technocool@gmail.com"))
122             << PluginAuthor(QStringLiteral("Illya Kovalevskyy"), QStringLiteral("illya.kovalevskyy@gmail.com"));
123 }
124 
icon() const125 QIcon MeasureToolPlugin::icon () const
126 {
127     return QIcon(QStringLiteral(":/icons/measure.png"));
128 }
129 
initialize()130 void MeasureToolPlugin::initialize ()
131 {
132      m_fontascent = QFontMetrics( m_font_regular ).ascent();
133 }
134 
isInitialized() const135 bool MeasureToolPlugin::isInitialized () const
136 {
137     return m_fontascent >= 0;
138 }
139 
configDialog()140 QDialog *MeasureToolPlugin::configDialog()
141 {
142     if ( !m_configDialog ) {
143         m_configDialog = new MeasureConfigDialog(m_configDialog);
144         connect( m_configDialog, SIGNAL(accepted()),
145                  SLOT(writeSettings()) );
146         connect( m_configDialog, SIGNAL(applied()),
147                  this, SLOT(writeSettings()) );
148     }
149 
150     m_configDialog->setShowDistanceLabels( m_showDistanceLabel );
151     m_configDialog->setShowBearingLabel( m_showBearingLabel );
152     m_configDialog->setShowBearingLabelChange( m_showBearingChangeLabel );
153     m_configDialog->setShowPolygonArea( m_showPolygonArea );
154     m_configDialog->setShowCircularArea( m_showCircularArea );
155     m_configDialog->setShowRadius( m_showRadius );
156     m_configDialog->setShowPerimeter( m_showPerimeter );
157     m_configDialog->setShowCircumference( m_showCircumference );
158     m_configDialog->setPaintMode( m_paintMode );
159 
160     return m_configDialog;
161 }
162 
settings() const163 QHash<QString,QVariant> MeasureToolPlugin::settings() const
164 {
165     QHash<QString, QVariant> settings = RenderPlugin::settings();
166 
167     settings.insert(QStringLiteral("showDistanceLabel"), m_showDistanceLabel);
168     settings.insert(QStringLiteral("showBearingLabel"), m_showBearingLabel);
169     settings.insert(QStringLiteral("showBearingChangeLabel"), m_showBearingChangeLabel);
170     settings.insert(QStringLiteral("showPolygonArea"), m_showPolygonArea);
171     settings.insert(QStringLiteral("showCircularArea"), m_showCircularArea);
172     settings.insert(QStringLiteral("showRadius"), m_showRadius);
173     settings.insert(QStringLiteral("showPerimeter"), m_showPerimeter);
174     settings.insert(QStringLiteral("showCircumference"), m_showCircumference);
175     settings.insert(QStringLiteral("paintMode"), (int)m_paintMode);
176 
177     return settings;
178 }
179 
setSettings(const QHash<QString,QVariant> & settings)180 void MeasureToolPlugin::setSettings( const QHash<QString,QVariant> &settings )
181 {
182     RenderPlugin::setSettings( settings );
183 
184     m_showDistanceLabel = settings.value(QStringLiteral("showDistanceLabel"), true).toBool();
185     m_showBearingLabel = settings.value(QStringLiteral("showBearingLabel"), true).toBool();
186     m_showBearingChangeLabel = settings.value(QStringLiteral("showBearingChangeLabel"), true).toBool();
187     m_showPolygonArea = settings.value(QStringLiteral("showPolygonArea"), false).toBool();
188     m_showCircularArea = settings.value(QStringLiteral("showCircularArea"), true).toBool();
189     m_showRadius = settings.value(QStringLiteral("showRadius"), true).toBool();
190     m_showPerimeter = settings.value(QStringLiteral("showPerimeter"), true).toBool();
191     m_showCircumference = settings.value(QStringLiteral("showCircumference"), true).toBool();
192     m_paintMode = (PaintMode)settings.value(QStringLiteral("paintMode"), 0).toInt();
193 }
194 
writeSettings()195 void MeasureToolPlugin::writeSettings()
196 {
197     m_showDistanceLabel = m_configDialog->showDistanceLabels();
198     m_showBearingLabel = m_configDialog->showBearingLabel();
199     m_showBearingChangeLabel = m_configDialog->showBearingLabelChange();
200     m_showPolygonArea = m_configDialog->showPolygonArea();
201     m_showCircularArea = m_configDialog->showCircularArea();
202     m_showRadius = m_configDialog->showRadius();
203     m_showPerimeter = m_configDialog->showPerimeter();
204     m_showCircumference = m_configDialog->showCircumference();
205     m_paintMode = (PaintMode)m_configDialog->paintMode();
206 
207     if (m_paintMode == Circular) {
208         if (m_measureLineString.size() < 2) {
209             m_addMeasurePointAction->setEnabled(true);
210         } else {
211             m_addMeasurePointAction->setEnabled(false);
212             while (m_measureLineString.size() > 2)
213                 m_measureLineString.remove(m_measureLineString.size()-1);
214         }
215     } else {
216         m_addMeasurePointAction->setEnabled(true);
217     }
218 
219     emit settingsChanged( nameId() );
220     emit repaintNeeded();
221 }
222 
render(GeoPainter * painter,ViewportParams * viewport,const QString & renderPos,GeoSceneLayer * layer)223 bool MeasureToolPlugin::render( GeoPainter *painter,
224                           ViewportParams *viewport,
225                           const QString& renderPos,
226                           GeoSceneLayer * layer )
227 {
228     Q_UNUSED(renderPos)
229     Q_UNUSED(layer)
230 
231     m_latLonAltBox = viewport->viewLatLonAltBox();
232 
233     // No way to paint anything if the list is empty.
234     if ( m_measureLineString.isEmpty() )
235         return true;
236 
237     painter->save();
238 
239     // Prepare for painting the measure line string and paint it.
240     painter->setPen( m_pen );
241 
242     if ( m_showDistanceLabel || m_showBearingLabel || m_showBearingChangeLabel ) {
243         drawSegments( painter );
244     } else {
245         painter->drawPolyline( m_measureLineString );
246     }
247 
248     // Paint the nodes of the paths.
249     drawMeasurePoints( painter );
250 
251     m_totalDistance = m_measureLineString.length( marbleModel()->planet()->radius() );
252 
253     if ( m_measureLineString.size() > 1 )
254         drawInfobox(painter);
255 
256     painter->restore();
257 
258     return true;
259 }
260 
drawSegments(GeoPainter * painter)261 void MeasureToolPlugin::drawSegments( GeoPainter* painter )
262 {
263     for ( int segmentIndex = 0; segmentIndex < m_measureLineString.size() - 1; ++segmentIndex ) {
264         GeoDataLineString segment( Tessellate );
265         segment << m_measureLineString[segmentIndex] ;
266         segment << m_measureLineString[segmentIndex + 1];
267 
268         QPen shadowPen( Oxygen::aluminumGray5 );
269         shadowPen.setWidthF(4.0);
270         painter->setPen( shadowPen );
271         painter->drawPolyline( segment );
272 
273         QString infoString;
274 
275         if ( (m_paintMode == Polygon && m_showDistanceLabel)
276              || (m_paintMode == Circular && m_showRadius) ) {
277             const qreal segmentLength = segment.length( marbleModel()->planet()->radius() );
278             m_radius = segmentLength;
279 
280             infoString = meterToPreferredUnit(segmentLength);
281         }
282 
283         if ( m_showBearingLabel && m_paintMode != Circular ) {
284             GeoDataCoordinates coordinates = segment.first();
285             qreal bearing = coordinates.bearing( segment.last(), GeoDataCoordinates::Degree );
286 
287             if ( bearing < 0 ) {
288                 bearing += 360;
289             }
290             QString bearingString = QString::fromUtf8( "%1°" ).arg( bearing, 0, 'f', 2 );
291             if ( !infoString.isEmpty() ) {
292                 infoString += QLatin1Char('\n');
293             }
294             infoString.append( bearingString );
295         }
296 
297         if ( m_showBearingChangeLabel && segmentIndex != 0 ) {
298             GeoDataCoordinates currentCoordinates = m_measureLineString[segmentIndex];
299             qreal currentBearing = currentCoordinates.bearing(m_measureLineString[segmentIndex+1]);
300             qreal previousBearing = currentCoordinates.bearing( m_measureLineString[segmentIndex-1]);
301 
302             GeoDataLinearRing ring;
303             painter->setPen( Qt::NoPen );
304             painter->setBrush( QBrush ( QColor ( 127, 127, 127, 127 ) ) );
305 
306             if (currentBearing < previousBearing) currentBearing += 2 * M_PI;
307             ring << currentCoordinates;
308 
309             qreal angleLength = qAbs(m_latLonAltBox.north() - m_latLonAltBox.south()) / 20;
310 
311             qreal iterBearing = previousBearing;
312             while ( iterBearing < currentBearing ) {
313                 ring << currentCoordinates.moveByBearing( iterBearing, angleLength );
314                 iterBearing += 0.1;
315             }
316 
317             ring << currentCoordinates.moveByBearing( currentBearing, angleLength );
318 
319             painter->drawPolygon( ring );
320 
321             qreal currentBearingChange = (currentBearing - previousBearing) * RAD2DEG;
322             if (currentBearingChange < 0) currentBearingChange += 360;
323             QString bearingChangedString = QString::fromUtf8( "%1°" ).arg( currentBearingChange, 0, 'f', 2 );
324             painter->setPen( Qt::black );
325             GeoDataCoordinates textPosition = ring.latLonAltBox().center();
326             qreal deltaEast = ring.latLonAltBox().east() - currentCoordinates.longitude();
327             qreal deltaWest = currentCoordinates.longitude() - ring.latLonAltBox().west();
328             if (deltaEast > deltaWest) {
329                 textPosition.setLongitude(currentCoordinates.longitude() + deltaEast / 2);
330             }
331             else {
332                 textPosition.setLongitude(currentCoordinates.longitude() - deltaWest);
333             }
334             painter->drawText(textPosition, bearingChangedString );
335        }
336 
337         // Drawing ellipse around 1st point towards the 2nd
338         if ( m_paintMode == Circular ) {
339             GeoDataCoordinates currentCoordinates = m_measureLineString[segmentIndex];
340 
341             GeoDataLinearRing ring;
342 
343             // planetRadius - planet radius
344             // d - distance between points
345             // S - area of the painted circle
346             qreal planetRadius = marbleModel()->planet()->radius();
347             qreal d = m_measureLineString.length(1);
348             m_circularArea = 2 * M_PI * planetRadius * planetRadius * (1 - qCos(d));
349 
350             qreal iterBearing = 0;
351             while ( iterBearing < 2 * M_PI ) {
352                 ring << currentCoordinates.moveByBearing(iterBearing, d);
353                 iterBearing += 0.1;
354             }
355 
356             painter->setPen( Qt::NoPen );
357             painter->setBrush( QBrush ( QColor ( 127, 127, 127, 127 ) ) );
358             painter->drawPolygon(ring);
359 
360             if ( m_showCircularArea ) {
361                 painter->setPen(Qt::white);
362                 GeoDataCoordinates textPosition = ring.latLonAltBox().center();
363 
364                 QString areaText = tr("Area:\n%1").arg(meterToPreferredUnit(m_circularArea, true));
365 
366                 QFontMetrics fontMetrics = painter->fontMetrics();
367                 QRect boundingRect = fontMetrics.boundingRect(QRect(), Qt::AlignCenter, areaText);
368 
369                 painter->drawText(textPosition,
370                                   areaText,
371                                   -boundingRect.width()/2, -boundingRect.height()*1.5,
372                                   boundingRect.width(), boundingRect.height(),
373                                   QTextOption(Qt::AlignCenter));
374             }
375 
376             if ( m_showCircumference ) {
377                 painter->setPen(Qt::white);
378                 GeoDataCoordinates textPosition = ring.latLonAltBox().center();
379 
380                 m_circumference = 2 * M_PI * planetRadius * qSin(d);
381 
382                 QString circumferenceText = tr("Circumference:\n%1").arg(meterToPreferredUnit(m_circumference));
383 
384                 QFontMetrics fontMetrics = painter->fontMetrics();
385                 QRect boundingRect = fontMetrics.boundingRect(QRect(),Qt::AlignCenter,
386                                                               circumferenceText);
387 
388                 painter->drawText(textPosition,
389                                   circumferenceText,
390                                   -boundingRect.width()/2, boundingRect.height(),
391                                   boundingRect.width(), boundingRect.height(),
392                                   QTextOption(Qt::AlignCenter));
393             }
394         }
395 
396         if ( !infoString.isEmpty() ) {
397             QPen linePen;
398 
399             // have three alternating colors for the segments
400             switch ( segmentIndex % 3 ) {
401             case 0:
402                 linePen.setColor( Oxygen::brickRed4 );
403                 break;
404             case 1:
405                 linePen.setColor( Oxygen::forestGreen4 );
406                 break;
407             case 2:
408                 linePen.setColor( Oxygen::skyBlue4 );
409                 break;
410             }
411 
412             linePen.setWidthF(2.0);
413             painter->setPen( linePen );
414             painter->drawPolyline( segment, infoString, LineCenter );
415         }
416     }
417 
418     if (m_paintMode == Polygon && m_measureLineString.size() > 2) {
419         GeoDataLinearRing measureRing(m_measureLineString);
420 
421         if (m_showPolygonArea || m_showPerimeter) {
422             painter->setPen( Qt::NoPen );
423             painter->setBrush( QBrush ( QColor ( 127, 127, 127, 127 ) ) );
424             painter->drawPolygon(measureRing);
425 
426             QPen shadowPen( Oxygen::aluminumGray5 );
427             shadowPen.setStyle(Qt::DashLine);
428             shadowPen.setWidthF(3.0);
429             painter->setPen( shadowPen );
430             painter->drawPolyline(GeoDataLineString( Tessellate ) << m_measureLineString.first()
431                                                       << m_measureLineString.last());
432         }
433 
434         if (m_showPolygonArea) {
435             qreal theta1 = 0.0;
436             qreal n = m_measureLineString.size();
437 
438             for (int segmentIndex = 1; segmentIndex < m_measureLineString.size()-1; segmentIndex++) {
439                 GeoDataCoordinates current = m_measureLineString[segmentIndex];
440                 qreal prevBearing = current.bearing(m_measureLineString[segmentIndex-1]);
441                 qreal nextBearing = current.bearing(m_measureLineString[segmentIndex+1]);
442                 if (nextBearing < prevBearing)
443                     nextBearing += 2 * M_PI;
444 
445                 qreal angle = nextBearing - prevBearing;
446                 theta1 += angle;
447             }
448 
449             // Traversing first vertex
450             GeoDataCoordinates current = m_measureLineString[0];
451             qreal prevBearing = current.bearing(m_measureLineString[n-1]);
452             qreal nextBearing = current.bearing(m_measureLineString[1]);
453             if (nextBearing < prevBearing)
454                 nextBearing += 2 * M_PI;
455             qreal angle = nextBearing - prevBearing;
456             theta1 += angle;
457 
458             // And the last one
459             current = m_measureLineString[n-1];
460             prevBearing = current.bearing(m_measureLineString[n-2]);
461             nextBearing = current.bearing(m_measureLineString[0]);
462             if (nextBearing < prevBearing)
463                 nextBearing += 2 * M_PI;
464             angle = nextBearing - prevBearing;
465             theta1 += angle;
466 
467             qreal theta2 = 2 * M_PI * n - theta1;
468 
469             // theta = smaller of theta1 and theta2
470             qreal theta = (theta1 < theta2) ? theta1 : theta2;
471 
472             qreal planetRadius = marbleModel()->planet()->radius();
473             qreal S = qAbs((theta - (n-2) * M_PI) * planetRadius * planetRadius);
474             m_polygonArea = S;
475 
476             painter->setPen(Qt::white);
477             GeoDataCoordinates textPosition = measureRing.latLonAltBox().center();
478 
479             QString areaText = tr("Area:\n%1").arg(meterToPreferredUnit(S, true));
480 
481             QFontMetrics fontMetrics = painter->fontMetrics();
482             QRect boundingRect = fontMetrics.boundingRect(QRect(), Qt::AlignCenter, areaText);
483 
484             painter->drawText(textPosition,
485                               areaText,
486                               -boundingRect.width()/2, -(boundingRect.height()+fontMetrics.height()*0.25),
487                               boundingRect.width(), boundingRect.height(),
488                               QTextOption(Qt::AlignCenter));
489         }
490 
491         if (m_showPerimeter) {
492             painter->setPen(Qt::white);
493             GeoDataCoordinates textPosition = measureRing.latLonAltBox().center();
494 
495             qreal P = measureRing.length(marbleModel()->planet()->radius());
496             m_perimeter = P;
497             QString perimeterText = tr("Perimeter:\n%1").arg(meterToPreferredUnit(P));
498 
499             QFontMetrics fontMetrics = painter->fontMetrics();
500             QRect boundingRect = fontMetrics.boundingRect(QRect(),Qt::AlignCenter,
501                                                           perimeterText);
502 
503             painter->drawText(textPosition,
504                               perimeterText,
505                               -boundingRect.width()/2, 0,
506                               boundingRect.width(), boundingRect.height(),
507                               QTextOption(Qt::AlignCenter));
508         }
509     }
510 }
511 
meterToPreferredUnit(qreal meters,bool isSquare)512 QString MeasureToolPlugin::meterToPreferredUnit(qreal meters, bool isSquare)
513 {
514     MarbleLocale *locale = MarbleGlobal::getInstance()->locale();
515     const MarbleLocale::MeasurementSystem measurementSystem = locale->measurementSystem();
516     MarbleLocale::MeasureUnit unit;
517     qreal convertedMeters;
518     if (isSquare)
519         meters = qSqrt(meters);
520 
521     locale->meterToTargetUnit(meters, measurementSystem, convertedMeters, unit);
522     QString unitString = locale->unitAbbreviation(unit);
523 
524     if (isSquare) {
525         qreal k = convertedMeters/meters;
526         convertedMeters *= k;
527         convertedMeters *= meters;
528 
529         unitString.append(QChar(0xB2));
530     }
531 
532     return QString("%L1 %2").arg(convertedMeters, 8, 'f', 1, QLatin1Char(' '))
533                             .arg(unitString);
534 }
535 
drawMeasurePoints(GeoPainter * painter)536 void MeasureToolPlugin::drawMeasurePoints( GeoPainter *painter )
537 {
538     // Paint the marks.
539     GeoDataLineString::const_iterator itpoint = m_measureLineString.constBegin();
540     GeoDataLineString::const_iterator const endpoint = m_measureLineString.constEnd();
541     if (m_mark.isNull()) {
542         m_mark = QPixmap(QStringLiteral(":/mark.png"));
543     }
544     for (; itpoint != endpoint; ++itpoint )
545     {
546         painter->drawPixmap( *itpoint, m_mark );
547     }
548 }
549 
drawInfobox(GeoPainter * painter) const550 void MeasureToolPlugin::drawInfobox( GeoPainter *painter ) const
551 {
552     QString boxContent;
553 
554     if (m_paintMode == Polygon) {
555         boxContent += QLatin1String("<strong>") + tr("Polygon Ruler") + QLatin1String(":</strong><br/>\n");
556     } else /* Circular */ {
557         boxContent += QLatin1String("<strong>") + tr("Circle Ruler") + QLatin1String(":</strong><br/>\n");
558     }
559     if (m_paintMode == Polygon) {
560         boxContent += tr("Total Distance: %1<br/>\n").arg( meterToPreferredUnit(m_totalDistance) );
561         if (m_showPolygonArea)
562             boxContent += tr("Area: %1<br/>\n").arg( meterToPreferredUnit(m_polygonArea, true) );
563         if (m_showPerimeter)
564             boxContent += tr("Perimeter: %1<br/>\n").arg( meterToPreferredUnit(m_perimeter) );
565     } else /* Circular */ {
566         if (m_showRadius)
567             boxContent += tr("Radius: %1<br/>\n").arg( meterToPreferredUnit(m_radius) );
568         if (m_showCircumference)
569             boxContent += tr("Circumference: %1<br/>\n").arg( meterToPreferredUnit(m_circumference) );
570         if (m_showCircularArea)
571             boxContent += tr("Area: %1<br/>\n").arg( meterToPreferredUnit(m_circularArea, true) );
572     }
573 
574     painter->setPen( QColor( Qt::black ) );
575     painter->setBrush( QColor( 192, 192, 192, 192 ) );
576 
577     QTextDocument doc;
578     doc.setHtml(boxContent);
579     doc.setDefaultFont(m_font_regular);
580     doc.adjustSize();
581     QSizeF pageSize = doc.size();
582 
583     painter->drawRect( 10, 105, 10 + pageSize.width(), pageSize.height() );
584     QTransform transform;
585     transform.translate(15, 110);
586     painter->setTransform(transform);
587     doc.drawContents(painter);
588     painter->setTransform(QTransform());
589 }
590 
591 
addMeasurePoint(qreal lon,qreal lat)592 void MeasureToolPlugin::addMeasurePoint( qreal lon, qreal lat )
593 {
594     m_measureLineString << GeoDataCoordinates( lon, lat );
595 
596     emit numberOfMeasurePointsChanged( m_measureLineString.size() );
597 }
598 
removeLastMeasurePoint()599 void MeasureToolPlugin::removeLastMeasurePoint()
600 {
601     if (!m_measureLineString.isEmpty())
602 	m_measureLineString.remove( m_measureLineString.size() - 1 );
603 
604     emit numberOfMeasurePointsChanged( m_measureLineString.size() );
605 }
606 
removeMeasurePoints()607 void MeasureToolPlugin::removeMeasurePoints()
608 {
609     m_measureLineString.clear();
610 
611     emit numberOfMeasurePointsChanged( m_measureLineString.size() );
612 }
613 
addContextItems()614 void MeasureToolPlugin::addContextItems()
615 {
616     MarbleWidgetPopupMenu *menu = m_marbleWidget->popupMenu();
617 
618     // Connect the inputHandler and the measure tool to the popup menu
619     m_addMeasurePointAction = new QAction(QIcon(QStringLiteral(":/icons/measure.png")), tr("Add &Measure Point"), this);
620     m_removeLastMeasurePointAction = new QAction( tr( "Remove &Last Measure Point" ), this );
621     m_removeLastMeasurePointAction->setEnabled( false );
622     m_removeMeasurePointsAction = new QAction( tr( "&Remove Measure Points" ), this );
623     m_removeMeasurePointsAction->setEnabled( false );
624     m_separator = new QAction( this );
625     m_separator->setSeparator( true );
626 
627     bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen;
628     if ( !smallScreen ) {
629         menu->addAction( Qt::RightButton, m_addMeasurePointAction );
630         menu->addAction( Qt::RightButton, m_removeLastMeasurePointAction );
631         menu->addAction( Qt::RightButton, m_removeMeasurePointsAction );
632         menu->addAction( Qt::RightButton, m_separator );
633     }
634 
635     connect( m_addMeasurePointAction, SIGNAL(triggered()), SLOT(addMeasurePointEvent()) );
636     connect( m_removeLastMeasurePointAction, SIGNAL(triggered()), SLOT(removeLastMeasurePoint()) );
637     connect( m_removeMeasurePointsAction, SIGNAL(triggered()), SLOT(removeMeasurePoints()) );
638 
639     connect( this, SIGNAL(numberOfMeasurePointsChanged(int)), SLOT(setNumberOfMeasurePoints(int)) );
640 }
641 
removeContextItems()642 void MeasureToolPlugin::removeContextItems()
643 {
644     delete m_addMeasurePointAction;
645     delete m_removeLastMeasurePointAction;
646     delete m_removeMeasurePointsAction;
647     delete m_separator;
648 }
649 
addMeasurePointEvent()650 void MeasureToolPlugin::addMeasurePointEvent()
651 {
652     QPoint p = m_marbleWidget->popupMenu()->mousePosition();
653 
654     qreal  lat;
655     qreal  lon;
656     m_marbleWidget->geoCoordinates( p.x(), p.y(), lon, lat, GeoDataCoordinates::Radian );
657 
658     addMeasurePoint( lon, lat );
659 }
660 
setNumberOfMeasurePoints(int newNumber)661 void MeasureToolPlugin::setNumberOfMeasurePoints( int newNumber )
662 {
663     const bool enableMeasureActions = ( newNumber > 0 );
664     m_removeMeasurePointsAction->setEnabled(enableMeasureActions);
665     m_removeLastMeasurePointAction->setEnabled(enableMeasureActions);
666 
667     if (m_paintMode == Circular) {
668         if (newNumber >= 2) {
669             m_addMeasurePointAction->setEnabled(false);
670         } else {
671             m_addMeasurePointAction->setEnabled(true);
672         }
673     }
674 }
675 
eventFilter(QObject * object,QEvent * e)676 bool MeasureToolPlugin::eventFilter( QObject *object, QEvent *e )
677 {
678     if ( m_marbleWidget && !enabled() ) {
679         m_marbleWidget = nullptr;
680         removeContextItems();
681         m_measureLineString.clear();
682     }
683 
684     if ( m_marbleWidget || !enabled() || !visible() ) {
685         return RenderPlugin::eventFilter( object, e );
686     }
687 
688     MarbleWidget *widget = qobject_cast<MarbleWidget*>( object );
689 
690     if ( widget ) {
691         m_marbleWidget = widget;
692         addContextItems();
693     }
694 
695     return RenderPlugin::eventFilter( object, e );
696 }
697 
698 }
699 
700 #include "moc_MeasureToolPlugin.cpp"
701 
702