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