6 #include "RoutingWidget.h"
8 #include "GeoDataLineString.h"
9 #include "GeoDataLookAt.h"
10 #include "GeoDataPlaylist.h"
11 #include "GeoDataTour.h"
12 #include "GeoDataFlyTo.h"
13 #include "GeoDataStyle.h"
14 #include "GeoDataIconStyle.h"
15 #include "GeoDataPlacemark.h"
16 #include "TourPlayback.h"
19 #include "MarblePlacemarkModel.h"
21 #include "MarbleWidgetInputHandler.h"
23 #include "RouteRequest.h"
24 #include "RoutingInputWidget.h"
25 #include "RoutingLayer.h"
26 #include "RoutingModel.h"
27 #include "RoutingProfilesModel.h"
28 #include "RoutingProfileSettingsDialog.h"
29 #include "GeoDataDocument.h"
30 #include "GeoDataTreeModel.h"
31 #include "GeoDataCreate.h"
32 #include "GeoDataUpdate.h"
33 #include "GeoDataDelete.h"
34 #include "AlternativeRoutesModel.h"
35 #include "RouteSyncManager.h"
36 #include "CloudRoutesDialog.h"
37 #include "CloudSyncManager.h"
38 #include "PlaybackAnimatedUpdateItem.h"
39 #include "GeoDataAnimatedUpdate.h"
44 #include <QFileDialog>
46 #include <QMouseEvent>
48 #include <QToolButton>
49 #include <QProgressDialog>
51 #include "ui_RoutingWidget.h"
60 GeoDataCoordinates coordinates;
64 WaypointInfo(
int index_,
double distance_,
const GeoDataCoordinates &coordinates_, Maneuver maneuver_,
const QString& info_ ) :
67 coordinates( coordinates_ ),
68 maneuver( maneuver_ ),
75 class RoutingWidgetPrivate
78 Ui::RoutingWidget m_ui;
79 MarbleWidget *
const m_widget;
80 RoutingManager *
const m_routingManager;
81 RoutingLayer *
const m_routingLayer;
82 RoutingInputWidget *m_activeInput;
84 RoutingInputWidget *m_inputRequest;
86 RouteRequest *
const m_routeRequest;
87 RouteSyncManager *m_routeSyncManager;
88 bool m_zoomRouteAfterDownload;
91 GeoDataDocument *m_document;
93 TourPlayback *m_playback;
105 QAction *m_uploadToCloudAction;
106 QAction *m_openCloudRoutesAction;
116 RoutingWidgetPrivate(RoutingWidget *parent, MarbleWidget *marbleWidget );
122 void adjustInputWidgets();
124 void adjustSearchButton();
132 void setActiveInput( RoutingInputWidget* widget );
137 void createProgressAnimation();
138 RoutingWidget *m_parent;
141 RoutingWidgetPrivate::RoutingWidgetPrivate( RoutingWidget *parent, MarbleWidget *marbleWidget ) :
142 m_widget( marbleWidget ),
143 m_routingManager( marbleWidget->model()->routingManager() ),
144 m_routingLayer( marbleWidget->routingLayer() ),
145 m_activeInput( nullptr ),
146 m_inputRequest( nullptr ),
147 m_routingModel( m_routingManager->routingModel() ),
148 m_routeRequest( marbleWidget->model()->routingManager()->routeRequest() ),
149 m_routeSyncManager( nullptr ),
150 m_zoomRouteAfterDownload( false ),
151 m_document( nullptr ),
153 m_playback( nullptr ),
156 m_collapse_width( 0 ),
158 m_planetId(marbleWidget->model()->planetId()),
159 m_toolBar( nullptr ),
160 m_openRouteButton( nullptr ),
161 m_saveRouteButton( nullptr ),
162 m_cloudSyncSeparator( nullptr ),
163 m_uploadToCloudAction( nullptr ),
164 m_openCloudRoutesAction( nullptr ),
165 m_addViaButton( nullptr ),
166 m_reverseRouteButton( nullptr ),
167 m_clearRouteButton( nullptr ),
168 m_configureButton( nullptr ),
169 m_routeUploadDialog( nullptr ),
172 createProgressAnimation();
173 m_progressTimer.setInterval( 100 );
174 if ( MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen ) {
179 void RoutingWidgetPrivate::adjustInputWidgets()
181 for (
int i = 0; i < m_inputWidgets.size(); ++i ) {
182 m_inputWidgets[i]->setIndex( i );
185 adjustSearchButton();
188 void RoutingWidgetPrivate::adjustSearchButton()
191 QString tooltip =
QObject::tr(
"Retrieve routing instructions for the selected destinations." );
194 for (
int i = 0; i < m_inputWidgets.size(); ++i ) {
195 if ( m_inputWidgets[i]->hasTargetPosition() ) {
200 if ( validInputs < 2 ) {
202 tooltip =
QObject::tr(
"Find places matching the search term" );
205 m_ui.searchButton->setText( text );
206 m_ui.searchButton->setToolTip( tooltip );
209 void RoutingWidgetPrivate::setActiveInput( RoutingInputWidget *widget )
211 Q_ASSERT( widget &&
"Must not pass null" );
212 MarblePlacemarkModel *model = widget->searchResultModel();
214 m_activeInput = widget;
215 m_ui.directionsListView->setModel( model );
216 m_routingLayer->setPlacemarkModel( model );
217 m_routingLayer->synchronizeWith( m_ui.directionsListView->selectionModel() );
220 void RoutingWidgetPrivate::setupToolBar()
226 m_openRouteButton->setIcon(
QIcon(QStringLiteral(
":/icons/16x16/document-open.png")));
227 m_toolBar->addWidget(m_openRouteButton);
231 m_saveRouteButton->setIcon(
QIcon(QStringLiteral(
":/icons/16x16/document-save.png")));
232 m_toolBar->addWidget(m_saveRouteButton);
236 m_playButton->setIcon(
QIcon(QStringLiteral(
":/marble/playback-play.png")));
237 m_toolBar->addWidget(m_playButton);
239 m_cloudSyncSeparator = m_toolBar->addSeparator();
240 m_uploadToCloudAction = m_toolBar->addAction(
QObject::tr(
"Upload to Cloud") );
241 m_uploadToCloudAction->setToolTip(
QObject::tr(
"Upload to Cloud") );
242 m_uploadToCloudAction->setIcon(
QIcon(QStringLiteral(
":/icons/cloud-upload.png")));
244 m_openCloudRoutesAction = m_toolBar->addAction(
QObject::tr(
"Manage Cloud Routes") );
245 m_openCloudRoutesAction->setToolTip(
QObject::tr(
"Manage Cloud Routes") );
246 m_openCloudRoutesAction->setIcon(
QIcon(QStringLiteral(
":/icons/cloud-download.png")));
248 m_toolBar->addSeparator();
251 m_addViaButton->setIcon(
QIcon(QStringLiteral(
":/marble/list-add.png")));
252 m_toolBar->addWidget(m_addViaButton);
256 m_reverseRouteButton->setIcon(
QIcon(QStringLiteral(
":/marble/reverse.png")));
257 m_toolBar->addWidget(m_reverseRouteButton);
261 m_clearRouteButton->setIcon(
QIcon(QStringLiteral(
":/marble/edit-clear.png")));
262 m_toolBar->addWidget(m_clearRouteButton);
264 m_toolBar->addSeparator();
268 m_configureButton->setIcon(
QIcon(QStringLiteral(
":/icons/16x16/configure.png")));
269 m_toolBar->addWidget(m_configureButton);
272 m_parent, SLOT(openRoute()) );
274 m_parent, SLOT(saveRoute()) );
276 m_parent, SLOT(uploadToCloud()) );
278 m_parent, SLOT(openCloudRoutesDialog()));
280 m_parent, SLOT(addInputWidget()) );
282 m_routingManager, SLOT(reverseRoute()) );
284 m_routingManager, SLOT(clearRoute()) );
286 m_parent, SLOT(configureProfile()) );
288 m_parent, SLOT(toggleRoutePlay()) );
290 m_toolBar->setIconSize(
QSize(16, 16));
294 void RoutingWidgetPrivate::createProgressAnimation()
297 qreal
const h = m_iconSize / 2.0;
298 qreal
const q = h / 2.0;
300 qreal
const r = d / 2.0;
310 for(
double t = 0.0; t < 2 * M_PI; t += M_PI / 8.0 ) {
312 QRectF firstCircle( h - r + q * cos( t ), h - r + q * sin( t ), d, d );
313 QRectF secondCircle( h - r + q * cos( t + M_PI ), h - r + q * sin( t + M_PI ), d, d );
314 painter.drawEllipse( firstCircle );
315 painter.drawEllipse( secondCircle );
321 QWidget( parent ), d( new RoutingWidgetPrivate( this, marbleWidget ) )
325 d->m_ui.routeComboBox->setVisible(
false );
326 d->m_ui.routeComboBox->setModel( d->m_routingManager->alternativeRoutesModel() );
329 d->m_ui.routingProfileComboBox->setModel( d->m_routingManager->profilesModel() );
331 connect( d->m_routingManager->profilesModel(), SIGNAL(rowsInserted(
QModelIndex,
int,
int)),
332 this, SLOT(selectFirstProfile()) );
333 connect( d->m_routingManager->profilesModel(), SIGNAL(modelReset()),
334 this, SLOT(selectFirstProfile()) );
337 connect( d->m_routingManager, SIGNAL(stateChanged(RoutingManager::State)),
338 this, SLOT(updateRouteState(RoutingManager::State)) );
339 connect( d->m_routeRequest, SIGNAL(positionAdded(
int)),
340 this, SLOT(insertInputWidget(
int)) );
341 connect( d->m_routeRequest, SIGNAL(positionRemoved(
int)),
342 this, SLOT(removeInputWidget(
int)) );
343 connect( d->m_routeRequest, SIGNAL(routingProfileChanged()),
344 this, SLOT(updateActiveRoutingProfile()) );
345 connect( &d->m_progressTimer, SIGNAL(timeout()),
346 this, SLOT(updateProgress()) );
347 connect( d->m_ui.routeComboBox, SIGNAL(currentIndexChanged(
int)),
348 d->m_routingManager->alternativeRoutesModel(), SLOT(setCurrentRoute(
int)) );
349 connect( d->m_routingManager->alternativeRoutesModel(), SIGNAL(currentRouteChanged(
int)),
350 d->m_ui.routeComboBox, SLOT(setCurrentIndex(
int)) );
351 connect( d->m_ui.routingProfileComboBox, SIGNAL(currentIndexChanged(
int)),
352 this, SLOT(setRoutingProfile(
int)) );
353 connect( d->m_ui.routingProfileComboBox, SIGNAL(activated(
int)),
354 this, SLOT(retrieveRoute()) );
355 connect( d->m_routingManager->alternativeRoutesModel(), SIGNAL(rowsInserted(
QModelIndex,
int,
int)),
356 this, SLOT(updateAlternativeRoutes()) );
358 d->m_ui.directionsListView->setModel( d->m_routingModel );
361 d->m_routingLayer->synchronizeWith( selectionModel );
366 connect( d->m_ui.searchButton, SIGNAL(clicked()),
367 this, SLOT(retrieveRoute()) );
368 connect( d->m_ui.showInstructionsButton, SIGNAL(clicked(
bool)),
369 this, SLOT(showDirections()) );
371 for(
int i=0; i<d->m_routeRequest->size(); ++i ) {
372 insertInputWidget( i );
375 for (
int i=0; i<2 && d->m_inputWidgets.size()<2; ++i ) {
380 d->m_ui.resultLabel->setVisible(
false );
382 updateActiveRoutingProfile();
383 updateCloudSyncButtons();
385 if ( MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen ) {
386 d->m_ui.directionsListView->setVisible(
false );
387 d->m_openRouteButton->setVisible(
false );
388 d->m_saveRouteButton->setVisible(
false );
392 this, SLOT(handlePlanetChange()) );
397 delete d->m_playback;
400 d->m_widget->model()->treeModel()->removeDocument( d->m_document );
401 delete d->m_document;
406 void RoutingWidget::retrieveRoute()
408 if ( d->m_inputWidgets.size() == 1 ) {
410 d->m_inputWidgets.first()->findPlacemarks();
414 int index = d->m_ui.routingProfileComboBox->currentIndex();
418 d->m_routeRequest->setRoutingProfile( d->m_routingManager->profilesModel()->profiles().at( index ) );
420 Q_ASSERT( d->m_routeRequest->size() == d->m_inputWidgets.size() );
421 for (
int i = 0; i < d->m_inputWidgets.size(); ++i ) {
422 RoutingInputWidget *widget = d->m_inputWidgets.at( i );
423 if ( !widget->hasTargetPosition() && widget->hasInput() ) {
424 widget->findPlacemarks();
429 d->m_activeInput =
nullptr;
430 if ( d->m_routeRequest->size() > 1 ) {
431 d->m_zoomRouteAfterDownload =
true;
432 d->m_routingLayer->setPlacemarkModel(
nullptr );
433 d->m_routingManager->retrieveRoute();
434 d->m_ui.directionsListView->setModel( d->m_routingModel );
435 d->m_routingLayer->synchronizeWith( d->m_ui.directionsListView->selectionModel() );
438 if( d->m_playback ) {
439 d->m_playback->stop();
443 void RoutingWidget::activateItem (
const QModelIndex &index )
448 GeoDataCoordinates position = qvariant_cast<GeoDataCoordinates>( data );
449 d->m_widget->centerOn( position,
true );
452 if ( d->m_activeInput && index.
isValid() ) {
455 d->m_activeInput->setTargetPosition( data.
value<GeoDataCoordinates>(), index.
data().
toString() );
460 void RoutingWidget::handleSearchResult( RoutingInputWidget *widget )
462 d->setActiveInput( widget );
463 MarblePlacemarkModel *model = widget->searchResultModel();
465 if ( model->rowCount() ) {
466 QString const results =
tr(
"placemarks found: %1" ).
arg( model->rowCount() );
467 d->m_ui.resultLabel->setText( results );
468 d->m_ui.resultLabel->setVisible(
true );
470 activatePlacemark( model->index( 0, 0 ) );
472 QString const results =
tr(
"No placemark found" );
474 d->m_ui.resultLabel->setVisible(
true );
477 GeoDataLineString placemarks;
478 for (
int i = 0; i < model->rowCount(); ++i ) {
481 placemarks << data.
value<GeoDataCoordinates>();
485 if ( placemarks.size() > 1 ) {
489 if ( MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen ) {
490 d->m_ui.directionsListView->setVisible(
true );
495 void RoutingWidget::centerOnInputWidget( RoutingInputWidget *widget )
497 if ( widget->hasTargetPosition() ) {
498 d->m_widget->centerOn( widget->targetPosition() );
502 void RoutingWidget::activatePlacemark(
const QModelIndex &index )
504 if ( d->m_activeInput && index.
isValid() ) {
507 d->m_activeInput->setTargetPosition( data.
value<GeoDataCoordinates>() );
511 d->m_ui.directionsListView->setCurrentIndex( index );
519 void RoutingWidget::insertInputWidget(
int index )
521 if ( index >= 0 && index <= d->m_inputWidgets.size() ) {
523 d->m_inputWidgets.insert( index, input );
532 connect( input, SIGNAL(targetValidityChanged(
bool)),
533 this, SLOT(adjustSearchButton()) );
535 d->m_ui.inputLayout->insertWidget( index, input );
536 d->adjustInputWidgets();
540 void RoutingWidget::removeInputWidget( RoutingInputWidget *widget )
542 int index = d->m_inputWidgets.indexOf( widget );
544 if ( d->m_inputWidgets.size() < 3 ) {
547 d->m_routeRequest->remove( index );
549 d->m_routingManager->retrieveRoute();
553 void RoutingWidget::removeInputWidget(
int index )
555 if ( index >= 0 && index < d->m_inputWidgets.size() ) {
556 RoutingInputWidget *widget = d->m_inputWidgets.at( index );
557 d->m_inputWidgets.remove( index );
558 d->m_ui.inputLayout->removeWidget( widget );
559 widget->deleteLater();
560 if ( widget == d->m_activeInput ) {
561 d->m_activeInput =
nullptr;
562 d->m_routingLayer->setPlacemarkModel(
nullptr );
563 d->m_ui.directionsListView->setModel( d->m_routingModel );
564 d->m_routingLayer->synchronizeWith( d->m_ui.directionsListView->selectionModel() );
566 d->adjustInputWidgets();
569 if ( d->m_inputWidgets.size() < 2 ) {
574 void RoutingWidget::updateRouteState( RoutingManager::State state )
579 case RoutingManager::Downloading:
580 d->m_ui.routeComboBox->setVisible(
false );
581 d->m_ui.routeComboBox->clear();
582 d->m_progressTimer.start();
583 d->m_ui.resultLabel->setVisible(
false );
585 case RoutingManager::Retrieved: {
586 d->m_progressTimer.stop();
587 d->m_ui.searchButton->setIcon(
QIcon() );
588 if ( d->m_routingManager->routingModel()->rowCount() == 0 ) {
589 const QString results =
tr(
"No route found" );
591 d->m_ui.resultLabel->setVisible(
true );
597 d->m_saveRouteButton->setEnabled( d->m_routingManager->routingModel()->rowCount() > 0 );
600 void RoutingWidget::requestMapPosition( RoutingInputWidget *widget,
bool enabled )
602 pointSelectionCanceled();
605 d->m_inputRequest = widget;
606 d->m_widget->installEventFilter(
this );
611 void RoutingWidget::retrieveSelectedPoint(
const GeoDataCoordinates &coordinates )
613 if ( d->m_inputRequest && d->m_inputWidgets.contains( d->m_inputRequest ) ) {
614 d->m_inputRequest->setTargetPosition( coordinates );
615 d->m_widget->update();
618 d->m_inputRequest =
nullptr;
619 d->m_widget->removeEventFilter(
this );
622 void RoutingWidget::adjustSearchButton()
624 d->adjustSearchButton();
627 void RoutingWidget::pointSelectionCanceled()
629 if ( d->m_inputRequest && d->m_inputWidgets.contains( d->m_inputRequest ) ) {
630 d->m_inputRequest->abortMapInputRequest();
633 d->m_inputRequest =
nullptr;
634 d->m_widget->removeEventFilter(
this );
637 void RoutingWidget::configureProfile()
639 int index = d->m_ui.routingProfileComboBox->currentIndex();
641 RoutingProfileSettingsDialog dialog( d->m_widget->model()->pluginManager(), d->m_routingManager->profilesModel(),
this );
642 dialog.editProfile( d->m_ui.routingProfileComboBox->currentIndex() );
643 d->m_routeRequest->setRoutingProfile( d->m_routingManager->profilesModel()->profiles().at( index ) );
647 void RoutingWidget::updateProgress()
649 if ( !d->m_progressAnimation.isEmpty() ) {
650 d->m_currentFrame = ( d->m_currentFrame + 1 ) % d->m_progressAnimation.size();
651 QIcon frame = d->m_progressAnimation[d->m_currentFrame];
652 d->m_ui.searchButton->setIcon( frame );
656 void RoutingWidget::updateAlternativeRoutes()
658 if ( d->m_ui.routeComboBox->count() == 1) {
660 GeoDataLatLonBox
const bbox = d->m_routingManager->routingModel()->route().bounds();
661 if ( d->m_zoomRouteAfterDownload ) {
662 d->m_zoomRouteAfterDownload =
false;
663 d->m_widget->centerOn( bbox );
667 d->m_ui.routeComboBox->setVisible( d->m_ui.routeComboBox->count() > 0 );
668 if ( d->m_ui.routeComboBox->currentIndex() < 0 && d->m_ui.routeComboBox->count() > 0 ) {
669 d->m_ui.routeComboBox->setCurrentIndex( 0 );
672 QString const results =
tr(
"routes found: %1" ).
arg( d->m_ui.routeComboBox->count() );
673 d->m_ui.resultLabel->setText( results );
674 d->m_ui.resultLabel->setVisible(
true );
675 d->m_saveRouteButton->setEnabled( d->m_routingManager->routingModel()->rowCount() > 0 );
680 d->m_ui.showInstructionsButton->setVisible(
visible );
683 void RoutingWidget::setRouteSyncManager(RouteSyncManager *manager)
685 d->m_routeSyncManager = manager;
686 connect( d->m_routeSyncManager, SIGNAL(routeSyncEnabledChanged(
bool)),
687 this, SLOT(updateCloudSyncButtons()) );
688 updateCloudSyncButtons();
694 d->m_routingManager->lastOpenPath(),
tr(
"KML Files (*.kml)") );
696 d->m_routingManager->setLastOpenPath(
QFileInfo( file ).absolutePath() );
697 d->m_zoomRouteAfterDownload =
true;
698 d->m_routingManager->loadRoute( file );
699 updateAlternativeRoutes();
703 void RoutingWidget::selectFirstProfile()
705 int count = d->m_routingManager->profilesModel()->rowCount();
706 if ( count && d->m_ui.routingProfileComboBox->currentIndex() < 0 ) {
707 d->m_ui.routingProfileComboBox->setCurrentIndex( 0 );
711 void RoutingWidget::setRoutingProfile(
int index )
713 if ( index >= 0 && index < d->m_routingManager->profilesModel()->rowCount() ) {
714 d->m_routeRequest->setRoutingProfile( d->m_routingManager->profilesModel()->profiles().at( index ) );
718 void RoutingWidget::showDirections()
720 d->m_ui.directionsListView->setVisible(
true );
727 d->m_routingManager->lastSavePath(),
728 tr(
"KML files (*.kml)" ) );
735 d->m_routingManager->setLastSavePath(
QFileInfo( fileName ).absolutePath() );
736 d->m_routingManager->saveRoute( fileName );
742 Q_ASSERT( d->m_routeSyncManager );
744 if (!d->m_routeUploadDialog) {
746 d->m_routeUploadDialog->setWindowTitle(
tr(
"Uploading route..." ) );
747 d->m_routeUploadDialog->setMinimum( 0 );
748 d->m_routeUploadDialog->setMaximum( 100 );
749 d->m_routeUploadDialog->setAutoClose(
true );
750 d->m_routeUploadDialog->setAutoReset(
true );
751 connect( d->m_routeSyncManager, SIGNAL(routeUploadProgress(qint64,qint64)),
this, SLOT(updateUploadProgress(qint64,qint64)) );
754 d->m_routeUploadDialog->show();
755 d->m_routeSyncManager->uploadRoute();
760 Q_ASSERT( d->m_routeSyncManager );
761 d->m_routeSyncManager->prepareRouteList();
764 connect( d->m_routeSyncManager, SIGNAL(routeListDownloadProgress(qint64,qint64)), dialog, SLOT(updateListDownloadProgressbar(qint64,qint64)) );
765 connect( dialog, SIGNAL(downloadButtonClicked(
QString)), d->m_routeSyncManager, SLOT(downloadRoute(
QString)) );
767 connect( dialog, SIGNAL(deleteButtonClicked(
QString)), d->m_routeSyncManager, SLOT(deleteRoute(
QString)) );
768 connect( dialog, SIGNAL(removeFromCacheButtonClicked(
QString)), d->m_routeSyncManager, SLOT(removeRouteFromCache(
QString)) );
769 connect( dialog, SIGNAL(uploadToCloudButtonClicked(
QString)), d->m_routeSyncManager, SLOT(uploadRoute(
QString)) );
774 void RoutingWidget::updateActiveRoutingProfile()
776 RoutingProfile
const profile = d->m_routingManager->routeRequest()->routingProfile();
778 d->m_ui.routingProfileComboBox->setCurrentIndex( profiles.
indexOf( profile ) );
781 void RoutingWidget::updateCloudSyncButtons()
783 bool const show = d->m_routeSyncManager && d->m_routeSyncManager->isRouteSyncEnabled();
784 d->m_cloudSyncSeparator->setVisible(
show );
785 d->m_uploadToCloudAction->setVisible(
show );
786 d->m_openCloudRoutesAction->setVisible(
show );
789 void RoutingWidget::openCloudRoute(
const QString &identifier)
791 Q_ASSERT( d->m_routeSyncManager );
792 d->m_routeSyncManager->openRoute( identifier );
793 d->m_widget->centerOn( d->m_routingManager->routingModel()->route().bounds() );
796 void RoutingWidget::updateUploadProgress(qint64 sent, qint64 total)
798 Q_ASSERT( d->m_routeUploadDialog );
799 d->m_routeUploadDialog->setValue( 100.0 * sent / total );
804 if ( o != d->m_widget ) {
808 Q_ASSERT( d->m_inputRequest !=
nullptr );
809 Q_ASSERT( d->m_inputWidgets.contains( d->m_inputRequest ) );
818 qreal lon( 0.0 ), lat( 0.0 );
820 lon, lat, GeoDataCoordinates::Radian ) ) {
821 retrieveSelectedPoint( GeoDataCoordinates( lon, lat ) );
836 pointSelectionCanceled();
851 void RoutingWidget::toggleRoutePlay()
853 if( !d->m_playback ){
854 if( d->m_routingModel->rowCount() != 0 ){
864 d->m_playButton->setIcon(
QIcon(QStringLiteral(
":/marble/playback-pause.png")));
867 d->m_playback->play();
870 d->m_playing =
false;
871 d->m_playButton->setIcon(
QIcon(QStringLiteral(
":/marble/playback-play.png")));
872 d->m_playback->pause();
876 void RoutingWidget::initializeTour()
878 d->m_tour =
new GeoDataTour;
880 d->m_widget->model()->treeModel()->removeDocument( d->m_document );
881 delete d->m_document;
883 d->m_document =
new GeoDataDocument;
884 d->m_document->setId(QStringLiteral(
"tourdoc"));
885 d->m_document->append( d->m_tour );
887 d->m_tour->setPlaylist(
new GeoDataPlaylist );
888 Route
const route = d->m_widget->model()->routingManager()->routingModel()->route();
889 GeoDataLineString
path = route.path();
895 double totalDistance = 0.0;
896 for(
int i=0; i<route.size(); ++i ){
898 waypoints << WaypointInfo(i, totalDistance, route.at(i).path().first(), route.at(i).maneuver(),
QLatin1String(
"start ") +
QString(i));
899 totalDistance += route.at( i ).distance();
902 if( waypoints.
size() < 1 ){
908 GeoDataCoordinates last =
path.
at( 0 );
910 qreal planetRadius = d->m_widget->model()->planet()->radius();
912 GeoDataCoordinates coordinates =
path.
at( i );
913 totalDistance += planetRadius *
path.
at(i - 1).sphericalDistanceTo(coordinates);
914 while (totalDistance >= allWaypoints[j].distance && j+1<allWaypoints.
size()) {
917 int const lastIndex = qBound( 0, j-1, allWaypoints.
size()-1 );
918 double const lastDistance = qAbs( totalDistance - allWaypoints[lastIndex].distance );
919 double const nextDistance = qAbs( allWaypoints[j].distance - totalDistance );
920 double const waypointDistance = qMin( lastDistance, nextDistance );
921 double const step = qBound( 100.0, waypointDistance*2, 1000.0 );
923 double const distance = planetRadius * last.sphericalDistanceTo(coordinates);
924 if( i > 1 && distance < step ){
929 GeoDataLookAt* lookat =
new GeoDataLookAt;
931 double const range = waypointDistance < 400 ? 400 : ( waypointDistance < 2000 ? 600 : 800 );
932 coordinates.setAltitude( range );
933 lookat->setCoordinates( coordinates );
934 lookat->setRange( range );
935 GeoDataFlyTo* flyto =
new GeoDataFlyTo;
936 double const duration = 0.75;
937 flyto->setDuration( duration );
938 flyto->setView( lookat );
939 flyto->setFlyToMode( GeoDataFlyTo::Smooth );
940 d->m_tour->playlist()->addPrimitive( flyto );
942 if( !waypoints.
empty() && totalDistance > waypoints.
first().distance-100 ){
943 WaypointInfo
const waypoint = waypoints.
first();
945 GeoDataAnimatedUpdate *updateCreate =
new GeoDataAnimatedUpdate;
946 updateCreate->setUpdate(
new GeoDataUpdate );
947 updateCreate->update()->setCreate(
new GeoDataCreate );
948 GeoDataPlacemark *placemarkCreate =
new GeoDataPlacemark;
950 placemarkCreate->setId( waypointId );
951 placemarkCreate->setTargetId( d->m_document->id() );
952 placemarkCreate->setCoordinate( waypoint.coordinates );
953 GeoDataStyle::Ptr
style(
new GeoDataStyle);
954 style->iconStyle().setIconPath( waypoint.maneuver.directionPixmap() );
955 placemarkCreate->setStyle(
style );
956 updateCreate->update()->create()->append( placemarkCreate );
957 d->m_tour->playlist()->addPrimitive( updateCreate );
959 GeoDataAnimatedUpdate *updateDelete =
new GeoDataAnimatedUpdate;
960 updateDelete->setDelayedStart( 2 );
961 updateDelete->setUpdate(
new GeoDataUpdate );
962 updateDelete->update()->setDelete(
new GeoDataDelete );
963 GeoDataPlacemark *placemarkDelete =
new GeoDataPlacemark;
964 placemarkDelete->setTargetId( waypointId );
965 updateDelete->update()->getDelete()->append( placemarkDelete );
966 d->m_tour->playlist()->addPrimitive( updateDelete );
970 d->m_playback =
new TourPlayback;
971 d->m_playback->setMarbleWidget( d->m_widget );
972 d->m_playback->setTour( d->m_tour );
973 d->m_widget->model()->treeModel()->addDocument( d->m_document );
975 this, SLOT(seekTourToStart()) );
978 void RoutingWidget::centerOn(
const GeoDataCoordinates &coordinates )
981 GeoDataLookAt lookat;
982 lookat.setCoordinates( coordinates );
983 lookat.setRange( coordinates.altitude() );
984 d->m_widget->flyTo( lookat,
Instant );
988 void RoutingWidget::clearTour()
990 d->m_playing =
false;
991 d->m_playButton->setIcon(
QIcon(QStringLiteral(
":/marble/playback-play.png")));
992 delete d->m_playback;
993 d->m_playback =
nullptr;
995 d->m_widget->model()->treeModel()->removeDocument( d->m_document );
996 delete d->m_document;
997 d->m_document =
nullptr;
1002 void RoutingWidget::seekTourToStart()
1004 Q_ASSERT( d->m_playback );
1005 d->m_playback->stop();
1006 d->m_playback->seek( 0 );
1007 d->m_playButton->setIcon(
QIcon(QStringLiteral(
":/marble/playback-play.png")));
1008 d->m_playing =
false;
1011 void RoutingWidget::handlePlanetChange()
1013 const QString newPlanetId = d->m_widget->model()->planetId();
1015 if (newPlanetId == d->m_planetId) {
1019 d->m_planetId = newPlanetId;
1020 d->m_routingManager->clearRoute();
1025 #include "moc_RoutingWidget.cpp"