File indexing completed on 2024-04-28 07:37:45
0001 // SPDX-License-Identifier: LGPL-2.1-or-later 0002 // 0003 // SPDX-FileCopyrightText: 2004-2007 Torsten Rahn <tackat@kde.org> 0004 // SPDX-FileCopyrightText: 2007 Inge Wallin <ingwa@kde.org> 0005 // SPDX-FileCopyrightText: 2007 Thomas Zander <zander@kde.org> 0006 // SPDX-FileCopyrightText: 2010 Bastian Holst <bastianholst@gmx.de> 0007 // 0008 0009 // Self 0010 #include "CurrentLocationWidget.h" 0011 0012 // Marble 0013 #include "MarbleDebug.h" 0014 #include "MarbleLocale.h" 0015 #include "MarbleModel.h" 0016 #include "MarbleWidget.h" 0017 #include "MarbleWidgetPopupMenu.h" 0018 #include "GeoDataCoordinates.h" 0019 #include "PositionProviderPlugin.h" 0020 #include "PluginManager.h" 0021 #include "PositionTracking.h" 0022 #include "routing/RoutingManager.h" 0023 0024 using namespace Marble; 0025 /* TRANSLATOR Marble::CurrentLocationWidget */ 0026 0027 // Ui 0028 #include "ui_CurrentLocationWidget.h" 0029 0030 #include <QDateTime> 0031 #include <QFileDialog> 0032 #include <QMessageBox> 0033 0034 namespace Marble 0035 { 0036 0037 class CurrentLocationWidgetPrivate 0038 { 0039 public: 0040 CurrentLocationWidgetPrivate(); 0041 0042 Ui::CurrentLocationWidget m_currentLocationUi; 0043 MarbleWidget *m_widget; 0044 AutoNavigation *m_adjustNavigation; 0045 0046 QList<const PositionProviderPlugin*> m_positionProviderPlugins; 0047 GeoDataCoordinates m_currentPosition; 0048 0049 QString m_lastOpenPath; 0050 QString m_lastSavePath; 0051 0052 void receiveGpsCoordinates( const GeoDataCoordinates &position, qreal speed ); 0053 void adjustPositionTrackingStatus( PositionProviderStatus status ); 0054 void changePositionProvider( const QString &provider ); 0055 void trackPlacemark(); 0056 void centerOnCurrentLocation(); 0057 void updateRecenterComboBox( AutoNavigation::CenterMode centerMode ); 0058 void updateAutoZoomCheckBox( bool autoZoom ); 0059 void updateActivePositionProvider( PositionProviderPlugin* ); 0060 void updateGuidanceMode(); 0061 void saveTrack(); 0062 void openTrack(); 0063 void clearTrack(); 0064 }; 0065 0066 CurrentLocationWidgetPrivate::CurrentLocationWidgetPrivate() 0067 : m_widget( nullptr ), 0068 m_adjustNavigation( nullptr ), 0069 m_positionProviderPlugins(), 0070 m_currentPosition(), 0071 m_lastOpenPath(), 0072 m_lastSavePath() 0073 { 0074 } 0075 0076 CurrentLocationWidget::CurrentLocationWidget( QWidget *parent, Qt::WindowFlags f ) 0077 : QWidget( parent, f ), 0078 d( new CurrentLocationWidgetPrivate() ) 0079 { 0080 d->m_currentLocationUi.setupUi( this ); 0081 layout()->setMargin( 0 ); 0082 0083 connect( d->m_currentLocationUi.recenterComboBox, SIGNAL (currentIndexChanged(int)), 0084 this, SLOT(setRecenterMode(int)) ); 0085 0086 connect( d->m_currentLocationUi.autoZoomCheckBox, SIGNAL(clicked(bool)), 0087 this, SLOT(setAutoZoom(bool)) ); 0088 0089 bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen; 0090 d->m_currentLocationUi.positionTrackingComboBox->setVisible( !smallScreen ); 0091 d->m_currentLocationUi.locationLabel->setVisible( !smallScreen ); 0092 } 0093 0094 CurrentLocationWidget::~CurrentLocationWidget() 0095 { 0096 delete d; 0097 } 0098 0099 void CurrentLocationWidget::setMarbleWidget( MarbleWidget *widget ) 0100 { 0101 d->m_widget = widget; 0102 0103 delete d->m_adjustNavigation; 0104 d->m_adjustNavigation = new AutoNavigation( widget->model(), widget->viewport(), this ); 0105 0106 const PluginManager* pluginManager = d->m_widget->model()->pluginManager(); 0107 d->m_positionProviderPlugins = pluginManager->positionProviderPlugins(); 0108 for( const PositionProviderPlugin *plugin: d->m_positionProviderPlugins ) { 0109 d->m_currentLocationUi.positionTrackingComboBox->addItem( plugin->guiString() ); 0110 } 0111 if ( d->m_positionProviderPlugins.isEmpty() ) { 0112 d->m_currentLocationUi.positionTrackingComboBox->setEnabled( false ); 0113 QString html = "<p>No Position Tracking Plugin installed.</p>"; 0114 d->m_currentLocationUi.locationLabel->setText( html ); 0115 d->m_currentLocationUi.locationLabel->setEnabled ( true ); 0116 bool const hasTrack = !d->m_widget->model()->positionTracking()->isTrackEmpty(); 0117 d->m_currentLocationUi.showTrackCheckBox->setEnabled( hasTrack ); 0118 d->m_currentLocationUi.saveTrackButton->setEnabled( hasTrack ); 0119 d->m_currentLocationUi.clearTrackButton->setEnabled( hasTrack ); 0120 } 0121 0122 //disconnect CurrentLocation Signals 0123 disconnect( d->m_widget->model()->positionTracking(), 0124 SIGNAL(gpsLocation(GeoDataCoordinates,qreal)), 0125 this, SLOT(receiveGpsCoordinates(GeoDataCoordinates,qreal)) ); 0126 disconnect( d->m_widget->model()->positionTracking(), 0127 SIGNAL(positionProviderPluginChanged(PositionProviderPlugin*)), 0128 this, SLOT(updateActivePositionProvider(PositionProviderPlugin*)) ); 0129 disconnect( d->m_currentLocationUi.positionTrackingComboBox, SIGNAL(currentIndexChanged(QString)), 0130 this, SLOT(changePositionProvider(QString)) ); 0131 disconnect( d->m_currentLocationUi.locationLabel, SIGNAL(linkActivated(QString)), 0132 this, SLOT(centerOnCurrentLocation()) ); 0133 disconnect( d->m_widget->model()->positionTracking(), 0134 SIGNAL(statusChanged(PositionProviderStatus)),this, 0135 SLOT(adjustPositionTrackingStatus(PositionProviderStatus)) ); 0136 0137 disconnect( d->m_widget->model(), SIGNAL(trackedPlacemarkChanged(const GeoDataPlacemark*)), 0138 this, SLOT(trackPlacemark()) ); 0139 0140 //connect CurrentLocation signals 0141 connect( d->m_widget->model()->positionTracking(), 0142 SIGNAL(gpsLocation(GeoDataCoordinates,qreal)), 0143 this, SLOT(receiveGpsCoordinates(GeoDataCoordinates,qreal)) ); 0144 connect( d->m_widget->model()->positionTracking(), 0145 SIGNAL(positionProviderPluginChanged(PositionProviderPlugin*)), 0146 this, SLOT(updateActivePositionProvider(PositionProviderPlugin*)) ); 0147 d->updateActivePositionProvider( d->m_widget->model()->positionTracking()->positionProviderPlugin() ); 0148 connect( d->m_currentLocationUi.positionTrackingComboBox, SIGNAL(currentIndexChanged(QString)), 0149 this, SLOT(changePositionProvider(QString)) ); 0150 connect( d->m_currentLocationUi.locationLabel, SIGNAL(linkActivated(QString)), 0151 this, SLOT(centerOnCurrentLocation()) ); 0152 connect( d->m_widget->model()->positionTracking(), 0153 SIGNAL(statusChanged(PositionProviderStatus)), this, 0154 SLOT(adjustPositionTrackingStatus(PositionProviderStatus)) ); 0155 0156 connect( d->m_adjustNavigation, SIGNAL(recenterModeChanged(AutoNavigation::CenterMode)), 0157 this, SLOT(updateRecenterComboBox(AutoNavigation::CenterMode)) ); 0158 connect( d->m_adjustNavigation, SIGNAL(autoZoomToggled(bool)), 0159 this, SLOT(updateAutoZoomCheckBox(bool)) ); 0160 connect( d->m_adjustNavigation, SIGNAL(zoomIn(FlyToMode)), 0161 d->m_widget, SLOT(zoomIn(FlyToMode)) ); 0162 connect( d->m_adjustNavigation, SIGNAL(zoomOut(FlyToMode)), 0163 d->m_widget, SLOT(zoomOut(FlyToMode)) ); 0164 connect( d->m_adjustNavigation, SIGNAL(centerOn(GeoDataCoordinates,bool)), 0165 d->m_widget, SLOT(centerOn(GeoDataCoordinates,bool)) ); 0166 0167 connect( d->m_widget, SIGNAL(visibleLatLonAltBoxChanged(GeoDataLatLonAltBox)), 0168 d->m_adjustNavigation, SLOT(inhibitAutoAdjustments()) ); 0169 connect( d->m_widget->model()->routingManager(), SIGNAL(guidanceModeEnabledChanged(bool)), 0170 this, SLOT(updateGuidanceMode()) ); 0171 0172 connect (d->m_currentLocationUi.showTrackCheckBox, SIGNAL(clicked(bool)), 0173 d->m_widget->model()->positionTracking(), SLOT(setTrackVisible(bool))); 0174 connect (d->m_currentLocationUi.showTrackCheckBox, SIGNAL(clicked(bool)), 0175 d->m_widget, SLOT(update())); 0176 if ( d->m_widget->model()->positionTracking()->trackVisible() ) { 0177 d->m_currentLocationUi.showTrackCheckBox->setCheckState(Qt::Checked); 0178 } 0179 connect ( d->m_currentLocationUi.saveTrackButton, SIGNAL(clicked(bool)), 0180 this, SLOT(saveTrack())); 0181 connect ( d->m_currentLocationUi.openTrackButton, SIGNAL(clicked(bool)), 0182 this, SLOT(openTrack())); 0183 connect (d->m_currentLocationUi.clearTrackButton, SIGNAL(clicked(bool)), 0184 this, SLOT(clearTrack())); 0185 connect( d->m_widget->model(), SIGNAL(trackedPlacemarkChanged(const GeoDataPlacemark*)), 0186 this, SLOT(trackPlacemark()) ); 0187 } 0188 0189 void CurrentLocationWidgetPrivate::adjustPositionTrackingStatus( PositionProviderStatus status ) 0190 { 0191 if ( status == PositionProviderStatusAvailable ) { 0192 return; 0193 } 0194 0195 QString html = "<html><body><p>"; 0196 0197 switch ( status ) { 0198 case PositionProviderStatusUnavailable: 0199 html += QObject::tr( "No position available." ); 0200 break; 0201 case PositionProviderStatusAcquiring: 0202 html += QObject::tr( "Waiting for current location information..." ); 0203 break; 0204 case PositionProviderStatusAvailable: 0205 Q_ASSERT( false ); 0206 break; 0207 case PositionProviderStatusError: 0208 html += QObject::tr( "Error when determining current location: " ); 0209 html += m_widget->model()->positionTracking()->error(); 0210 break; 0211 } 0212 0213 html += QLatin1String("</p></body></html>"); 0214 m_currentLocationUi.locationLabel->setEnabled( true ); 0215 m_currentLocationUi.locationLabel->setText( html ); 0216 } 0217 0218 void CurrentLocationWidgetPrivate::updateActivePositionProvider( PositionProviderPlugin *plugin ) 0219 { 0220 m_currentLocationUi.positionTrackingComboBox->blockSignals( true ); 0221 if ( !plugin ) { 0222 m_currentLocationUi.positionTrackingComboBox->setCurrentIndex( 0 ); 0223 } else { 0224 for( int i=0; i<m_currentLocationUi.positionTrackingComboBox->count(); ++i ) { 0225 if ( m_currentLocationUi.positionTrackingComboBox->itemText( i ) == plugin->guiString() ) { 0226 m_currentLocationUi.positionTrackingComboBox->setCurrentIndex( i ); 0227 break; 0228 } 0229 } 0230 } 0231 m_currentLocationUi.positionTrackingComboBox->blockSignals( false ); 0232 m_currentLocationUi.recenterLabel->setEnabled( plugin ); 0233 m_currentLocationUi.recenterComboBox->setEnabled( plugin ); 0234 m_currentLocationUi.autoZoomCheckBox->setEnabled( plugin ); 0235 0236 } 0237 0238 void CurrentLocationWidgetPrivate::updateGuidanceMode() 0239 { 0240 const bool enabled = m_widget->model()->routingManager()->guidanceModeEnabled(); 0241 0242 m_adjustNavigation->setAutoZoom( enabled ); 0243 m_adjustNavigation->setRecenter( enabled ? AutoNavigation::RecenterOnBorder : AutoNavigation::DontRecenter ); 0244 } 0245 0246 void CurrentLocationWidgetPrivate::receiveGpsCoordinates( const GeoDataCoordinates &position, qreal speed ) 0247 { 0248 m_currentPosition = position; 0249 QString unitString; 0250 QString altitudeUnitString; 0251 QString distanceUnitString; 0252 qreal unitSpeed = 0.0; 0253 qreal altitude = 0.0; 0254 qreal length = m_widget->model()->positionTracking()->length( m_widget->model()->planetRadius() ); 0255 0256 QString html = QLatin1String("<html><body>" 0257 "<table cellspacing=\"2\" cellpadding=\"2\">" 0258 "<tr><td>Longitude</td><td><a href=\"https://edu.kde.org/marble\">%1</a></td></tr>" 0259 "<tr><td>Latitude</td><td><a href=\"https://edu.kde.org/marble\">%2</a></td></tr>" 0260 "<tr><td>Altitude</td><td>%3</td></tr>" 0261 "<tr><td>Speed</td><td>%4</td></tr>" 0262 "<tr><td>Distance</td><td>%5</td></tr>" 0263 "</table>" 0264 "</body></html>"); 0265 0266 switch ( MarbleGlobal::getInstance()->locale()->measurementSystem() ) { 0267 case MarbleLocale::MetricSystem: 0268 //kilometers per hour 0269 unitString = QObject::tr("km/h"); 0270 unitSpeed = speed * HOUR2SEC * METER2KM; 0271 altitudeUnitString = QObject::tr("m"); 0272 distanceUnitString = QObject::tr("m"); 0273 if ( length > 1000.0 ) { 0274 length /= 1000.0; 0275 distanceUnitString = QObject::tr("km"); 0276 } 0277 altitude = position.altitude(); 0278 break; 0279 case MarbleLocale::ImperialSystem: 0280 //miles per hour 0281 unitString = QObject::tr("m/h"); 0282 unitSpeed = speed * HOUR2SEC * METER2KM * KM2MI; 0283 altitudeUnitString = QObject::tr("ft"); 0284 distanceUnitString = QObject::tr("ft"); 0285 altitude = position.altitude() * M2FT; 0286 length *= M2FT; 0287 break; 0288 0289 case MarbleLocale::NauticalSystem: 0290 // nautical miles 0291 unitString = QObject::tr("kt"); 0292 unitSpeed = speed * HOUR2SEC * METER2KM * KM2NM; 0293 altitudeUnitString = QObject::tr("m"); 0294 distanceUnitString = QObject::tr("nm"); 0295 altitude = position.altitude(); 0296 length *= METER2KM*KM2NM; 0297 break; 0298 } 0299 // TODO read this value from the incoming signal 0300 const QString speedString = QLocale::system().toString( unitSpeed, 'f', 1); 0301 const QString altitudeString = QString( "%1 %2" ).arg( altitude, 0, 'f', 1, QChar(' ') ).arg( altitudeUnitString ); 0302 const QString distanceString = QString( "%1 %2" ).arg( length, 0, 'f', 1, QChar(' ') ).arg( distanceUnitString ); 0303 0304 html = html.arg( position.lonToString(), position.latToString() ); 0305 html = html.arg(altitudeString, speedString + QLatin1Char(' ') + unitString); 0306 html = html.arg( distanceString ); 0307 m_currentLocationUi.locationLabel->setText( html ); 0308 m_currentLocationUi.showTrackCheckBox->setEnabled( true ); 0309 m_currentLocationUi.saveTrackButton->setEnabled( true ); 0310 m_currentLocationUi.clearTrackButton->setEnabled( true ); 0311 } 0312 0313 void CurrentLocationWidgetPrivate::changePositionProvider( const QString &provider ) 0314 { 0315 for( const PositionProviderPlugin* plugin: m_positionProviderPlugins ) { 0316 if ( plugin->guiString() == provider ) { 0317 m_currentLocationUi.locationLabel->setEnabled( true ); 0318 PositionProviderPlugin* instance = plugin->newInstance(); 0319 PositionTracking *tracking = m_widget->model()->positionTracking(); 0320 tracking->setPositionProviderPlugin( instance ); 0321 m_widget->update(); 0322 return; 0323 } 0324 } 0325 0326 // requested provider not found -> disable position tracking 0327 m_currentLocationUi.locationLabel->setEnabled( false ); 0328 m_widget->model()->positionTracking()->setPositionProviderPlugin( nullptr ); 0329 m_widget->update(); 0330 } 0331 0332 void CurrentLocationWidgetPrivate::trackPlacemark() 0333 { 0334 changePositionProvider( QObject::tr( "Placemark" ) ); 0335 m_adjustNavigation->setRecenter( AutoNavigation::AlwaysRecenter ); 0336 } 0337 0338 void CurrentLocationWidget::setRecenterMode( int mode ) 0339 { 0340 if ( mode >= 0 && mode <= AutoNavigation::RecenterOnBorder ) { 0341 AutoNavigation::CenterMode centerMode = ( AutoNavigation::CenterMode ) mode; 0342 d->m_adjustNavigation->setRecenter( centerMode ); 0343 } 0344 } 0345 0346 void CurrentLocationWidget::setAutoZoom( bool autoZoom ) 0347 { 0348 d->m_adjustNavigation->setAutoZoom( autoZoom ); 0349 } 0350 0351 void CurrentLocationWidgetPrivate::updateAutoZoomCheckBox( bool autoZoom ) 0352 { 0353 m_currentLocationUi.autoZoomCheckBox->setChecked( autoZoom ); 0354 } 0355 0356 void CurrentLocationWidgetPrivate::updateRecenterComboBox( AutoNavigation::CenterMode centerMode ) 0357 { 0358 m_currentLocationUi.recenterComboBox->setCurrentIndex( centerMode ); 0359 } 0360 0361 void CurrentLocationWidgetPrivate::centerOnCurrentLocation() 0362 { 0363 m_widget->centerOn(m_currentPosition, true); 0364 } 0365 0366 void CurrentLocationWidgetPrivate::saveTrack() 0367 { 0368 QString suggested = m_lastSavePath; 0369 QString fileName = QFileDialog::getSaveFileName(m_widget, QObject::tr("Save Track"), // krazy:exclude=qclasses 0370 suggested.append(QLatin1Char('/') + QDateTime::currentDateTime().toString("yyyy-MM-dd_hhmmss") + QLatin1String(".kml")), 0371 QObject::tr("KML File (*.kml)")); 0372 if ( fileName.isEmpty() ) { 0373 return; 0374 } 0375 if ( !fileName.endsWith(QLatin1String( ".kml" ), Qt::CaseInsensitive) ) { 0376 fileName += QLatin1String(".kml"); 0377 } 0378 QFileInfo file( fileName ); 0379 m_lastSavePath = file.absolutePath(); 0380 m_widget->model()->positionTracking()->saveTrack( fileName ); 0381 } 0382 0383 void CurrentLocationWidgetPrivate::openTrack() 0384 { 0385 QString suggested = m_lastOpenPath; 0386 QString fileName = QFileDialog::getOpenFileName( m_widget, QObject::tr("Open Track"), // krazy:exclude=qclasses 0387 suggested, QObject::tr("KML File (*.kml)")); 0388 if ( !fileName.isEmpty() ) { 0389 QFileInfo file( fileName ); 0390 m_lastOpenPath = file.absolutePath(); 0391 m_widget->model()->addGeoDataFile( fileName ); 0392 } 0393 } 0394 0395 void CurrentLocationWidgetPrivate::clearTrack() 0396 { 0397 const int result = QMessageBox::question( m_widget, 0398 QObject::tr( "Clear current track" ), 0399 QObject::tr( "Are you sure you want to clear the current track?" ), 0400 QMessageBox::Yes, 0401 QMessageBox::No ); 0402 0403 if ( result == QMessageBox::Yes ) { 0404 m_widget->model()->positionTracking()->clearTrack(); 0405 m_widget->update(); 0406 m_currentLocationUi.saveTrackButton->setEnabled( false ); 0407 m_currentLocationUi.clearTrackButton->setEnabled( false ); 0408 } 0409 } 0410 0411 AutoNavigation::CenterMode CurrentLocationWidget::recenterMode() const 0412 { 0413 return d->m_adjustNavigation->recenterMode(); 0414 } 0415 0416 bool CurrentLocationWidget::autoZoom() const 0417 { 0418 return d->m_adjustNavigation->autoZoom(); 0419 } 0420 0421 bool CurrentLocationWidget::trackVisible() const 0422 { 0423 return d->m_widget->model()->positionTracking()->trackVisible(); 0424 } 0425 0426 QString CurrentLocationWidget::lastOpenPath() const 0427 { 0428 return d->m_lastOpenPath; 0429 } 0430 0431 QString CurrentLocationWidget::lastSavePath() const 0432 { 0433 return d->m_lastSavePath; 0434 } 0435 0436 void CurrentLocationWidget::setTrackVisible( bool visible ) 0437 { 0438 d->m_currentLocationUi.showTrackCheckBox->setChecked( visible ); 0439 d->m_widget->model()->positionTracking()->setTrackVisible( visible ); 0440 } 0441 0442 void CurrentLocationWidget::setLastOpenPath( const QString &path ) 0443 { 0444 d->m_lastOpenPath = path; 0445 } 0446 0447 void CurrentLocationWidget::setLastSavePath( const QString &path ) 0448 { 0449 d->m_lastSavePath = path; 0450 } 0451 0452 } 0453 0454 #include "moc_CurrentLocationWidget.cpp"