Marble

CurrentLocationWidget.cpp
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 //
3 // SPDX-FileCopyrightText: 2004-2007 Torsten Rahn <[email protected]>
4 // SPDX-FileCopyrightText: 2007 Inge Wallin <[email protected]>
5 // SPDX-FileCopyrightText: 2007 Thomas Zander <[email protected]>
6 // SPDX-FileCopyrightText: 2010 Bastian Holst <[email protected]>
7 //
8 
9 // Self
10 #include "CurrentLocationWidget.h"
11 
12 // Marble
13 #include "MarbleDebug.h"
14 #include "MarbleLocale.h"
15 #include "MarbleModel.h"
16 #include "MarbleWidget.h"
17 #include "MarbleWidgetPopupMenu.h"
18 #include "GeoDataCoordinates.h"
19 #include "PositionProviderPlugin.h"
20 #include "PluginManager.h"
21 #include "PositionTracking.h"
22 #include "routing/RoutingManager.h"
23 
24 using namespace Marble;
25 /* TRANSLATOR Marble::CurrentLocationWidget */
26 
27 // Ui
28 #include "ui_CurrentLocationWidget.h"
29 
30 #include <QDateTime>
31 #include <QFileDialog>
32 #include <QMessageBox>
33 
34 namespace Marble
35 {
36 
37 class CurrentLocationWidgetPrivate
38 {
39  public:
40  CurrentLocationWidgetPrivate();
41 
42  Ui::CurrentLocationWidget m_currentLocationUi;
43  MarbleWidget *m_widget;
44  AutoNavigation *m_adjustNavigation;
45 
46  QList<const PositionProviderPlugin*> m_positionProviderPlugins;
47  GeoDataCoordinates m_currentPosition;
48 
49  QString m_lastOpenPath;
50  QString m_lastSavePath;
51 
52  void receiveGpsCoordinates( const GeoDataCoordinates &position, qreal speed );
53  void adjustPositionTrackingStatus( PositionProviderStatus status );
54  void changePositionProvider( const QString &provider );
55  void trackPlacemark();
56  void centerOnCurrentLocation();
57  void updateRecenterComboBox( AutoNavigation::CenterMode centerMode );
58  void updateAutoZoomCheckBox( bool autoZoom );
59  void updateActivePositionProvider( PositionProviderPlugin* );
60  void updateGuidanceMode();
61  void saveTrack();
62  void openTrack();
63  void clearTrack();
64 };
65 
66 CurrentLocationWidgetPrivate::CurrentLocationWidgetPrivate()
67  : m_widget( nullptr ),
68  m_adjustNavigation( nullptr ),
69  m_positionProviderPlugins(),
70  m_currentPosition(),
71  m_lastOpenPath(),
72  m_lastSavePath()
73 {
74 }
75 
76 CurrentLocationWidget::CurrentLocationWidget( QWidget *parent, Qt::WindowFlags f )
77  : QWidget( parent, f ),
78  d( new CurrentLocationWidgetPrivate() )
79 {
80  d->m_currentLocationUi.setupUi( this );
81  layout()->setMargin( 0 );
82 
83  connect( d->m_currentLocationUi.recenterComboBox, SIGNAL (currentIndexChanged(int)),
84  this, SLOT(setRecenterMode(int)) );
85 
86  connect( d->m_currentLocationUi.autoZoomCheckBox, SIGNAL(clicked(bool)),
87  this, SLOT(setAutoZoom(bool)) );
88 
89  bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen;
90  d->m_currentLocationUi.positionTrackingComboBox->setVisible( !smallScreen );
91  d->m_currentLocationUi.locationLabel->setVisible( !smallScreen );
92 }
93 
94 CurrentLocationWidget::~CurrentLocationWidget()
95 {
96  delete d;
97 }
98 
99 void CurrentLocationWidget::setMarbleWidget( MarbleWidget *widget )
100 {
101  d->m_widget = widget;
102 
103  delete d->m_adjustNavigation;
104  d->m_adjustNavigation = new AutoNavigation( widget->model(), widget->viewport(), this );
105 
106  const PluginManager* pluginManager = d->m_widget->model()->pluginManager();
107  d->m_positionProviderPlugins = pluginManager->positionProviderPlugins();
108  for( const PositionProviderPlugin *plugin: d->m_positionProviderPlugins ) {
109  d->m_currentLocationUi.positionTrackingComboBox->addItem( plugin->guiString() );
110  }
111  if ( d->m_positionProviderPlugins.isEmpty() ) {
112  d->m_currentLocationUi.positionTrackingComboBox->setEnabled( false );
113  QString html = "<p>No Position Tracking Plugin installed.</p>";
114  d->m_currentLocationUi.locationLabel->setText( html );
115  d->m_currentLocationUi.locationLabel->setEnabled ( true );
116  bool const hasTrack = !d->m_widget->model()->positionTracking()->isTrackEmpty();
117  d->m_currentLocationUi.showTrackCheckBox->setEnabled( hasTrack );
118  d->m_currentLocationUi.saveTrackButton->setEnabled( hasTrack );
119  d->m_currentLocationUi.clearTrackButton->setEnabled( hasTrack );
120  }
121 
122  //disconnect CurrentLocation Signals
123  disconnect( d->m_widget->model()->positionTracking(),
124  SIGNAL(gpsLocation(GeoDataCoordinates,qreal)),
125  this, SLOT(receiveGpsCoordinates(GeoDataCoordinates,qreal)) );
126  disconnect( d->m_widget->model()->positionTracking(),
127  SIGNAL(positionProviderPluginChanged(PositionProviderPlugin*)),
128  this, SLOT(updateActivePositionProvider(PositionProviderPlugin*)) );
129  disconnect( d->m_currentLocationUi.positionTrackingComboBox, SIGNAL(currentIndexChanged(QString)),
130  this, SLOT(changePositionProvider(QString)) );
131  disconnect( d->m_currentLocationUi.locationLabel, SIGNAL(linkActivated(QString)),
132  this, SLOT(centerOnCurrentLocation()) );
133  disconnect( d->m_widget->model()->positionTracking(),
134  SIGNAL(statusChanged(PositionProviderStatus)),this,
135  SLOT(adjustPositionTrackingStatus(PositionProviderStatus)) );
136 
137  disconnect( d->m_widget->model(), SIGNAL(trackedPlacemarkChanged(const GeoDataPlacemark*)),
138  this, SLOT(trackPlacemark()) );
139 
140  //connect CurrentLocation signals
141  connect( d->m_widget->model()->positionTracking(),
142  SIGNAL(gpsLocation(GeoDataCoordinates,qreal)),
143  this, SLOT(receiveGpsCoordinates(GeoDataCoordinates,qreal)) );
144  connect( d->m_widget->model()->positionTracking(),
145  SIGNAL(positionProviderPluginChanged(PositionProviderPlugin*)),
146  this, SLOT(updateActivePositionProvider(PositionProviderPlugin*)) );
147  d->updateActivePositionProvider( d->m_widget->model()->positionTracking()->positionProviderPlugin() );
148  connect( d->m_currentLocationUi.positionTrackingComboBox, SIGNAL(currentIndexChanged(QString)),
149  this, SLOT(changePositionProvider(QString)) );
150  connect( d->m_currentLocationUi.locationLabel, SIGNAL(linkActivated(QString)),
151  this, SLOT(centerOnCurrentLocation()) );
152  connect( d->m_widget->model()->positionTracking(),
153  SIGNAL(statusChanged(PositionProviderStatus)), this,
154  SLOT(adjustPositionTrackingStatus(PositionProviderStatus)) );
155 
156  connect( d->m_adjustNavigation, SIGNAL(recenterModeChanged(AutoNavigation::CenterMode)),
157  this, SLOT(updateRecenterComboBox(AutoNavigation::CenterMode)) );
158  connect( d->m_adjustNavigation, SIGNAL(autoZoomToggled(bool)),
159  this, SLOT(updateAutoZoomCheckBox(bool)) );
160  connect( d->m_adjustNavigation, SIGNAL(zoomIn(FlyToMode)),
161  d->m_widget, SLOT(zoomIn(FlyToMode)) );
162  connect( d->m_adjustNavigation, SIGNAL(zoomOut(FlyToMode)),
163  d->m_widget, SLOT(zoomOut(FlyToMode)) );
164  connect( d->m_adjustNavigation, SIGNAL(centerOn(GeoDataCoordinates,bool)),
165  d->m_widget, SLOT(centerOn(GeoDataCoordinates,bool)) );
166 
167  connect( d->m_widget, SIGNAL(visibleLatLonAltBoxChanged(GeoDataLatLonAltBox)),
168  d->m_adjustNavigation, SLOT(inhibitAutoAdjustments()) );
169  connect( d->m_widget->model()->routingManager(), SIGNAL(guidanceModeEnabledChanged(bool)),
170  this, SLOT(updateGuidanceMode()) );
171 
172  connect (d->m_currentLocationUi.showTrackCheckBox, SIGNAL(clicked(bool)),
173  d->m_widget->model()->positionTracking(), SLOT(setTrackVisible(bool)));
174  connect (d->m_currentLocationUi.showTrackCheckBox, SIGNAL(clicked(bool)),
175  d->m_widget, SLOT(update()));
176  if ( d->m_widget->model()->positionTracking()->trackVisible() ) {
177  d->m_currentLocationUi.showTrackCheckBox->setCheckState(Qt::Checked);
178  }
179  connect ( d->m_currentLocationUi.saveTrackButton, SIGNAL(clicked(bool)),
180  this, SLOT(saveTrack()));
181  connect ( d->m_currentLocationUi.openTrackButton, SIGNAL(clicked(bool)),
182  this, SLOT(openTrack()));
183  connect (d->m_currentLocationUi.clearTrackButton, SIGNAL(clicked(bool)),
184  this, SLOT(clearTrack()));
185  connect( d->m_widget->model(), SIGNAL(trackedPlacemarkChanged(const GeoDataPlacemark*)),
186  this, SLOT(trackPlacemark()) );
187 }
188 
189 void CurrentLocationWidgetPrivate::adjustPositionTrackingStatus( PositionProviderStatus status )
190 {
191  if ( status == PositionProviderStatusAvailable ) {
192  return;
193  }
194 
195  QString html = "<html><body><p>";
196 
197  switch ( status ) {
198  case PositionProviderStatusUnavailable:
199  html += QObject::tr( "No position available." );
200  break;
201  case PositionProviderStatusAcquiring:
202  html += QObject::tr( "Waiting for current location information..." );
203  break;
204  case PositionProviderStatusAvailable:
205  Q_ASSERT( false );
206  break;
207  case PositionProviderStatusError:
208  html += QObject::tr( "Error when determining current location: " );
209  html += m_widget->model()->positionTracking()->error();
210  break;
211  }
212 
213  html += QLatin1String("</p></body></html>");
214  m_currentLocationUi.locationLabel->setEnabled( true );
215  m_currentLocationUi.locationLabel->setText( html );
216 }
217 
218 void CurrentLocationWidgetPrivate::updateActivePositionProvider( PositionProviderPlugin *plugin )
219 {
220  m_currentLocationUi.positionTrackingComboBox->blockSignals( true );
221  if ( !plugin ) {
222  m_currentLocationUi.positionTrackingComboBox->setCurrentIndex( 0 );
223  } else {
224  for( int i=0; i<m_currentLocationUi.positionTrackingComboBox->count(); ++i ) {
225  if ( m_currentLocationUi.positionTrackingComboBox->itemText( i ) == plugin->guiString() ) {
226  m_currentLocationUi.positionTrackingComboBox->setCurrentIndex( i );
227  break;
228  }
229  }
230  }
231  m_currentLocationUi.positionTrackingComboBox->blockSignals( false );
232  m_currentLocationUi.recenterLabel->setEnabled( plugin );
233  m_currentLocationUi.recenterComboBox->setEnabled( plugin );
234  m_currentLocationUi.autoZoomCheckBox->setEnabled( plugin );
235 
236 }
237 
238 void CurrentLocationWidgetPrivate::updateGuidanceMode()
239 {
240  const bool enabled = m_widget->model()->routingManager()->guidanceModeEnabled();
241 
242  m_adjustNavigation->setAutoZoom( enabled );
243  m_adjustNavigation->setRecenter( enabled ? AutoNavigation::RecenterOnBorder : AutoNavigation::DontRecenter );
244 }
245 
246 void CurrentLocationWidgetPrivate::receiveGpsCoordinates( const GeoDataCoordinates &position, qreal speed )
247 {
248  m_currentPosition = position;
249  QString unitString;
250  QString altitudeUnitString;
251  QString distanceUnitString;
252  qreal unitSpeed = 0.0;
253  qreal altitude = 0.0;
254  qreal length = m_widget->model()->positionTracking()->length( m_widget->model()->planetRadius() );
255 
256  QString html = QLatin1String("<html><body>"
257  "<table cellspacing=\"2\" cellpadding=\"2\">"
258  "<tr><td>Longitude</td><td><a href=\"https://edu.kde.org/marble\">%1</a></td></tr>"
259  "<tr><td>Latitude</td><td><a href=\"https://edu.kde.org/marble\">%2</a></td></tr>"
260  "<tr><td>Altitude</td><td>%3</td></tr>"
261  "<tr><td>Speed</td><td>%4</td></tr>"
262  "<tr><td>Distance</td><td>%5</td></tr>"
263  "</table>"
264  "</body></html>");
265 
266  switch ( MarbleGlobal::getInstance()->locale()->measurementSystem() ) {
267  case MarbleLocale::MetricSystem:
268  //kilometers per hour
269  unitString = QObject::tr("km/h");
270  unitSpeed = speed * HOUR2SEC * METER2KM;
271  altitudeUnitString = QObject::tr("m");
272  distanceUnitString = QObject::tr("m");
273  if ( length > 1000.0 ) {
274  length /= 1000.0;
275  distanceUnitString = QObject::tr("km");
276  }
277  altitude = position.altitude();
278  break;
279  case MarbleLocale::ImperialSystem:
280  //miles per hour
281  unitString = QObject::tr("m/h");
282  unitSpeed = speed * HOUR2SEC * METER2KM * KM2MI;
283  altitudeUnitString = QObject::tr("ft");
284  distanceUnitString = QObject::tr("ft");
285  altitude = position.altitude() * M2FT;
286  length *= M2FT;
287  break;
288 
289  case MarbleLocale::NauticalSystem:
290  // nautical miles
291  unitString = QObject::tr("kt");
292  unitSpeed = speed * HOUR2SEC * METER2KM * KM2NM;
293  altitudeUnitString = QObject::tr("m");
294  distanceUnitString = QObject::tr("nm");
295  altitude = position.altitude();
296  length *= METER2KM*KM2NM;
297  break;
298  }
299  // TODO read this value from the incoming signal
300  const QString speedString = QLocale::system().toString( unitSpeed, 'f', 1);
301  const QString altitudeString = QString( "%1 %2" ).arg( altitude, 0, 'f', 1, QChar(' ') ).arg( altitudeUnitString );
302  const QString distanceString = QString( "%1 %2" ).arg( length, 0, 'f', 1, QChar(' ') ).arg( distanceUnitString );
303 
304  html = html.arg( position.lonToString(), position.latToString() );
305  html = html.arg(altitudeString, speedString + QLatin1Char(' ') + unitString);
306  html = html.arg( distanceString );
307  m_currentLocationUi.locationLabel->setText( html );
308  m_currentLocationUi.showTrackCheckBox->setEnabled( true );
309  m_currentLocationUi.saveTrackButton->setEnabled( true );
310  m_currentLocationUi.clearTrackButton->setEnabled( true );
311 }
312 
313 void CurrentLocationWidgetPrivate::changePositionProvider( const QString &provider )
314 {
315  for( const PositionProviderPlugin* plugin: m_positionProviderPlugins ) {
316  if ( plugin->guiString() == provider ) {
317  m_currentLocationUi.locationLabel->setEnabled( true );
318  PositionProviderPlugin* instance = plugin->newInstance();
319  PositionTracking *tracking = m_widget->model()->positionTracking();
320  tracking->setPositionProviderPlugin( instance );
321  m_widget->update();
322  return;
323  }
324  }
325 
326  // requested provider not found -> disable position tracking
327  m_currentLocationUi.locationLabel->setEnabled( false );
328  m_widget->model()->positionTracking()->setPositionProviderPlugin( nullptr );
329  m_widget->update();
330 }
331 
332 void CurrentLocationWidgetPrivate::trackPlacemark()
333 {
334  changePositionProvider( QObject::tr( "Placemark" ) );
335  m_adjustNavigation->setRecenter( AutoNavigation::AlwaysRecenter );
336 }
337 
338 void CurrentLocationWidget::setRecenterMode( int mode )
339 {
340  if ( mode >= 0 && mode <= AutoNavigation::RecenterOnBorder ) {
341  AutoNavigation::CenterMode centerMode = ( AutoNavigation::CenterMode ) mode;
342  d->m_adjustNavigation->setRecenter( centerMode );
343  }
344 }
345 
346 void CurrentLocationWidget::setAutoZoom( bool autoZoom )
347 {
348  d->m_adjustNavigation->setAutoZoom( autoZoom );
349 }
350 
351 void CurrentLocationWidgetPrivate::updateAutoZoomCheckBox( bool autoZoom )
352 {
353  m_currentLocationUi.autoZoomCheckBox->setChecked( autoZoom );
354 }
355 
356 void CurrentLocationWidgetPrivate::updateRecenterComboBox( AutoNavigation::CenterMode centerMode )
357 {
358  m_currentLocationUi.recenterComboBox->setCurrentIndex( centerMode );
359 }
360 
361 void CurrentLocationWidgetPrivate::centerOnCurrentLocation()
362 {
363  m_widget->centerOn(m_currentPosition, true);
364 }
365 
366 void CurrentLocationWidgetPrivate::saveTrack()
367 {
368  QString suggested = m_lastSavePath;
369  QString fileName = QFileDialog::getSaveFileName(m_widget, QObject::tr("Save Track"), // krazy:exclude=qclasses
370  suggested.append(QLatin1Char('/') + QDateTime::currentDateTime().toString("yyyy-MM-dd_hhmmss") + QLatin1String(".kml")),
371  QObject::tr("KML File (*.kml)"));
372  if ( fileName.isEmpty() ) {
373  return;
374  }
375  if ( !fileName.endsWith(QLatin1String( ".kml" ), Qt::CaseInsensitive) ) {
376  fileName += QLatin1String(".kml");
377  }
378  QFileInfo file( fileName );
379  m_lastSavePath = file.absolutePath();
380  m_widget->model()->positionTracking()->saveTrack( fileName );
381 }
382 
383 void CurrentLocationWidgetPrivate::openTrack()
384 {
385  QString suggested = m_lastOpenPath;
386  QString fileName = QFileDialog::getOpenFileName( m_widget, QObject::tr("Open Track"), // krazy:exclude=qclasses
387  suggested, QObject::tr("KML File (*.kml)"));
388  if ( !fileName.isEmpty() ) {
389  QFileInfo file( fileName );
390  m_lastOpenPath = file.absolutePath();
391  m_widget->model()->addGeoDataFile( fileName );
392  }
393 }
394 
395 void CurrentLocationWidgetPrivate::clearTrack()
396 {
397  const int result = QMessageBox::question( m_widget,
398  QObject::tr( "Clear current track" ),
399  QObject::tr( "Are you sure you want to clear the current track?" ),
401  QMessageBox::No );
402 
403  if ( result == QMessageBox::Yes ) {
404  m_widget->model()->positionTracking()->clearTrack();
405  m_widget->update();
406  m_currentLocationUi.saveTrackButton->setEnabled( false );
407  m_currentLocationUi.clearTrackButton->setEnabled( false );
408  }
409 }
410 
411 AutoNavigation::CenterMode CurrentLocationWidget::recenterMode() const
412 {
413  return d->m_adjustNavigation->recenterMode();
414 }
415 
416 bool CurrentLocationWidget::autoZoom() const
417 {
418  return d->m_adjustNavigation->autoZoom();
419 }
420 
421 bool CurrentLocationWidget::trackVisible() const
422 {
423  return d->m_widget->model()->positionTracking()->trackVisible();
424 }
425 
426 QString CurrentLocationWidget::lastOpenPath() const
427 {
428  return d->m_lastOpenPath;
429 }
430 
431 QString CurrentLocationWidget::lastSavePath() const
432 {
433  return d->m_lastSavePath;
434 }
435 
436 void CurrentLocationWidget::setTrackVisible( bool visible )
437 {
438  d->m_currentLocationUi.showTrackCheckBox->setChecked( visible );
439  d->m_widget->model()->positionTracking()->setTrackVisible( visible );
440 }
441 
442 void CurrentLocationWidget::setLastOpenPath( const QString &path )
443 {
444  d->m_lastOpenPath = path;
445 }
446 
447 void CurrentLocationWidget::setLastSavePath( const QString &path )
448 {
449  d->m_lastSavePath = path;
450 }
451 
452 }
453 
454 #include "moc_CurrentLocationWidget.cpp"
QList< const PositionProviderPlugin * > positionProviderPlugins() const
Returns all available PositionProviderPlugins.
A 3d point representation.
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
A class that defines a 3D bounding box for geographic data.
CaseInsensitive
QDateTime currentDateTime()
MarbleModel * model()
Return the model that this view shows.
The abstract class that provides position information.
static QString lonToString(qreal lon, GeoDataCoordinates::Notation notation, GeoDataCoordinates::Unit unit=Radian, int precision=-1, char format='f')
A widget class that displays a view of the earth.
Definition: MarbleWidget.h:98
virtual QString guiString() const =0
Returns the string that should appear in the user interface.
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QAction * zoomOut(const QObject *recvr, const char *slot, QObject *parent)
QLocale system()
typedef WindowFlags
QMessageBox::StandardButton question(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)
qreal altitude() const
return the altitude of the Point in meters
char * toString(const T &value)
bool isEmpty() const const
int length() const const
QString toString(qlonglong i) const const
The class that handles Marble's plugins.
Definition: PluginManager.h:39
Binds a QML item to a specific geodetic location in screen coordinates.
virtual PositionProviderPlugin * newInstance() const =0
Create a new PositionProvider Plugin and return it.
void setupUi(QWidget *widget)
FlyToMode
Describes possible flight mode (interpolation between source and target camera positions)
Definition: MarbleGlobal.h:157
a class representing a point of interest on the map
LocaleWrapper locale()
QAction * zoomIn(const QObject *recvr, const char *slot, QObject *parent)
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options)
QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options)
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
void update(Part *part, const QByteArray &data, qint64 dataSize)
QString tr(const char *sourceText, const char *disambiguation, int n)
static QString latToString(qreal lat, GeoDataCoordinates::Notation notation, GeoDataCoordinates::Unit unit=Radian, int precision=-1, char format='f')
QString & append(QChar ch)
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Thu May 26 2022 04:07:48 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.