Marble

CurrentLocationWidget.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later
2//
3// SPDX-FileCopyrightText: 2004-2007 Torsten Rahn <tackat@kde.org>
4// SPDX-FileCopyrightText: 2007 Inge Wallin <ingwa@kde.org>
5// SPDX-FileCopyrightText: 2007 Thomas Zander <zander@kde.org>
6// SPDX-FileCopyrightText: 2010 Bastian Holst <bastianholst@gmx.de>
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
24using 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
34namespace Marble
35{
36
37class 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
66CurrentLocationWidgetPrivate::CurrentLocationWidgetPrivate()
67 : m_widget( nullptr ),
68 m_adjustNavigation( nullptr ),
69 m_positionProviderPlugins(),
70 m_currentPosition(),
71 m_lastOpenPath(),
72 m_lastSavePath()
73{
74}
75
76CurrentLocationWidget::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
94CurrentLocationWidget::~CurrentLocationWidget()
95{
96 delete d;
97}
98
99void 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
189void 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
218void 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
238void 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
246void 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
313void 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
332void CurrentLocationWidgetPrivate::trackPlacemark()
333{
334 changePositionProvider( QObject::tr( "Placemark" ) );
335 m_adjustNavigation->setRecenter( AutoNavigation::AlwaysRecenter );
336}
337
338void 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
346void CurrentLocationWidget::setAutoZoom( bool autoZoom )
347{
348 d->m_adjustNavigation->setAutoZoom( autoZoom );
349}
350
351void CurrentLocationWidgetPrivate::updateAutoZoomCheckBox( bool autoZoom )
352{
353 m_currentLocationUi.autoZoomCheckBox->setChecked( autoZoom );
354}
355
356void CurrentLocationWidgetPrivate::updateRecenterComboBox( AutoNavigation::CenterMode centerMode )
357{
358 m_currentLocationUi.recenterComboBox->setCurrentIndex( centerMode );
359}
360
361void CurrentLocationWidgetPrivate::centerOnCurrentLocation()
362{
363 m_widget->centerOn(m_currentPosition, true);
364}
365
366void 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
383void 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
395void 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?" ),
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
411AutoNavigation::CenterMode CurrentLocationWidget::recenterMode() const
412{
413 return d->m_adjustNavigation->recenterMode();
414}
415
416bool CurrentLocationWidget::autoZoom() const
417{
418 return d->m_adjustNavigation->autoZoom();
419}
420
421bool CurrentLocationWidget::trackVisible() const
422{
423 return d->m_widget->model()->positionTracking()->trackVisible();
424}
425
426QString CurrentLocationWidget::lastOpenPath() const
427{
428 return d->m_lastOpenPath;
429}
430
431QString CurrentLocationWidget::lastSavePath() const
432{
433 return d->m_lastSavePath;
434}
435
436void CurrentLocationWidget::setTrackVisible( bool visible )
437{
438 d->m_currentLocationUi.showTrackCheckBox->setChecked( visible );
439 d->m_widget->model()->positionTracking()->setTrackVisible( visible );
440}
441
442void CurrentLocationWidget::setLastOpenPath( const QString &path )
443{
444 d->m_lastOpenPath = path;
445}
446
447void CurrentLocationWidget::setLastSavePath( const QString &path )
448{
449 d->m_lastSavePath = path;
450}
451
452}
453
454#include "moc_CurrentLocationWidget.cpp"
This file contains the headers for MarbleModel.
This file contains the headers for MarbleWidget.
A 3d point representation.
static QString latToString(qreal lat, GeoDataCoordinates::Notation notation, GeoDataCoordinates::Unit unit=Radian, int precision=-1, char format='f')
qreal altitude() const
return the altitude of the Point in meters
static QString lonToString(qreal lon, GeoDataCoordinates::Notation notation, GeoDataCoordinates::Unit unit=Radian, int precision=-1, char format='f')
A class that defines a 3D bounding box for geographic data.
a class representing a point of interest on the map
void addGeoDataFile(const QString &filename)
Handle file loading into the treeModel.
A widget class that displays a view of the earth.
MarbleModel * model()
Return the model that this view shows.
void centerOn(const qreal lon, const qreal lat, bool animated=false)
Center the view on a geographical point.
The class that handles Marble's plugins.
QList< const PositionProviderPlugin * > positionProviderPlugins() const
Returns all available PositionProviderPlugins.
The abstract class that provides position information.
virtual QString guiString() const =0
Returns the string that should appear in the user interface.
virtual PositionProviderPlugin * newInstance() const =0
Create a new PositionProvider Plugin and return it.
Q_SCRIPTABLE CaptureState status()
char * toString(const EngineQuery &query)
QString path(const QString &relativePath)
QAction * zoomIn(const QObject *recvr, const char *slot, QObject *parent)
QAction * zoomOut(const QObject *recvr, const char *slot, QObject *parent)
Binds a QML item to a specific geodetic location in screen coordinates.
FlyToMode
Describes possible flight mode (interpolation between source and target camera positions)
QDateTime currentDateTime()
QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, Options options)
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, Options options)
QLocale system()
QString toString(QDate date, FormatType format) const const
StandardButton question(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons, StandardButton defaultButton)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool disconnect(const QMetaObject::Connection &connection)
T qobject_cast(QObject *object)
QString tr(const char *sourceText, const char *disambiguation, int n)
QString & append(QChar ch)
QString arg(Args &&... args) const const
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
CaseInsensitive
typedef WindowFlags
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void setupUi(QWidget *widget)
void update()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jun 21 2024 12:00:06 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.