File indexing completed on 2024-04-28 03:50:23
0001 // SPDX-License-Identifier: LGPL-2.1-or-later 0002 // 0003 // SPDX-FileCopyrightText: 2010 Siddharth Srivastava <akssps011@gmail.com> 0004 // SPDX-FileCopyrightText: 2010 Dennis Nienhüser <nienhueser@kde.org> 0005 // 0006 0007 #include "RoutingPlugin.h" 0008 0009 #include "ui_RoutingPlugin.h" 0010 #include "ui_RoutingConfigDialog.h" 0011 0012 #include "Planet.h" 0013 #include "AudioOutput.h" 0014 #include "GeoDataCoordinates.h" 0015 #include "GeoDataLookAt.h" 0016 #include "GeoPainter.h" 0017 #include "MarbleGraphicsGridLayout.h" 0018 #include "MarbleModel.h" 0019 #include "MarbleWidget.h" 0020 #include "MarbleLocale.h" 0021 #include "MarbleDirs.h" 0022 #include "PluginManager.h" 0023 #include "PositionTracking.h" 0024 #include "PositionProviderPlugin.h" 0025 #include "routing/Route.h" 0026 #include "routing/RoutingManager.h" 0027 #include "routing/RoutingModel.h" 0028 #include "routing/RouteRequest.h" 0029 #include "routing/SpeakersModel.h" 0030 #include "ViewportParams.h" 0031 #include "WidgetGraphicsItem.h" 0032 0033 #include <QDialog> 0034 #include <QPushButton> 0035 0036 namespace Marble 0037 { 0038 0039 namespace 0040 { 0041 int const thresholdDistance = 1000; // in meter 0042 } 0043 0044 class RoutingPluginPrivate 0045 { 0046 public: 0047 MarbleWidget* m_marbleWidget; 0048 WidgetGraphicsItem* m_widgetItem; 0049 RoutingModel* m_routingModel; 0050 Ui::RoutingPlugin m_widget; 0051 bool m_nearNextInstruction; 0052 bool m_guidanceModeEnabled; 0053 AudioOutput* m_audio; 0054 QDialog *m_configDialog; 0055 Ui::RoutingConfigDialog m_configUi; 0056 bool m_routeCompleted; 0057 SpeakersModel* m_speakersModel; 0058 0059 RoutingPluginPrivate( RoutingPlugin* parent ); 0060 0061 void updateZoomButtons( int zoomValue ); 0062 0063 void updateZoomButtons(); 0064 0065 void updateGuidanceModeButton(); 0066 0067 void forceRepaint(); 0068 0069 void updateButtonVisibility(); 0070 0071 void reverseRoute(); 0072 0073 void toggleGuidanceMode( bool enabled ); 0074 0075 void updateDestinationInformation(); 0076 0077 void updateGpsButton( PositionProviderPlugin *activePlugin ); 0078 0079 void togglePositionTracking( bool enabled ); 0080 0081 static QString richText( const QString &source ); 0082 0083 static QString fuzzyDistance( qreal distanceMeter ); 0084 0085 void readSettings(); 0086 0087 qreal nextInstructionDistance() const; 0088 0089 qreal remainingDistance() const; 0090 0091 private: 0092 RoutingPlugin* m_parent; 0093 }; 0094 0095 RoutingPluginPrivate::RoutingPluginPrivate( RoutingPlugin *parent ) : 0096 m_marbleWidget( nullptr ), 0097 m_widgetItem( nullptr ), 0098 m_routingModel( nullptr ), 0099 m_nearNextInstruction( false ), 0100 m_guidanceModeEnabled( false ), 0101 m_audio( new AudioOutput( parent ) ), 0102 m_configDialog( nullptr ), 0103 m_routeCompleted( false ), 0104 m_speakersModel( nullptr ), 0105 m_parent( parent ) 0106 { 0107 m_audio->setMuted( false ); 0108 m_audio->setSoundEnabled( true ); 0109 } 0110 0111 QString RoutingPluginPrivate::richText( const QString &source ) 0112 { 0113 return QLatin1String("<font size=\"+1\" color=\"black\">") + source + QLatin1String("</font>"); 0114 } 0115 0116 QString RoutingPluginPrivate::fuzzyDistance( qreal length ) 0117 { 0118 int precision = 0; 0119 QString distanceUnit = QLatin1String( "m" ); 0120 0121 if ( MarbleGlobal::getInstance()->locale()->measurementSystem() != MarbleLocale::MetricSystem ) { 0122 precision = 1; 0123 distanceUnit = "mi"; 0124 length *= METER2KM; 0125 length *= KM2MI; 0126 } else if (MarbleGlobal::getInstance()->locale()->measurementSystem() == 0127 MarbleLocale::MetricSystem) { 0128 if ( length >= 1000 ) { 0129 length /= 1000; 0130 distanceUnit = "km"; 0131 precision = 1; 0132 } else if ( length >= 200 ) { 0133 length = 50 * qRound( length / 50 ); 0134 } else if ( length >= 100 ) { 0135 length = 25 * qRound( length / 25 ); 0136 } else { 0137 length = 10 * qRound( length / 10 ); 0138 } 0139 } else if (MarbleGlobal::getInstance()->locale()->measurementSystem() == 0140 MarbleLocale::NauticalSystem) { 0141 precision = 2; 0142 distanceUnit = "nm"; 0143 length *= METER2KM; 0144 length *= KM2NM; 0145 } 0146 0147 return QString( "%1 %2" ).arg( length, 0, 'f', precision ).arg( distanceUnit ); 0148 } 0149 0150 void RoutingPluginPrivate::updateZoomButtons( int zoomValue ) 0151 { 0152 int const minZoom = m_marbleWidget ? m_marbleWidget->minimumZoom() : 900; 0153 int const maxZoom = m_marbleWidget ? m_marbleWidget->maximumZoom() : 2400; 0154 0155 bool const zoomInEnabled = zoomValue < maxZoom; 0156 bool const zoomOutEnabled = zoomValue > minZoom; 0157 0158 if ( ( zoomInEnabled != m_widget.zoomInButton->isEnabled() ) || 0159 ( zoomOutEnabled != m_widget.zoomOutButton->isEnabled() ) ) { 0160 m_widget.zoomInButton->setEnabled( zoomInEnabled ); 0161 m_widget.zoomOutButton->setEnabled( zoomOutEnabled ); 0162 forceRepaint(); 0163 } 0164 } 0165 0166 void RoutingPluginPrivate::updateGuidanceModeButton() 0167 { 0168 bool const hasRoute = m_routingModel->rowCount() > 0; 0169 m_widget.routingButton->setEnabled( hasRoute ); 0170 forceRepaint(); 0171 } 0172 0173 void RoutingPluginPrivate::forceRepaint() 0174 { 0175 m_parent->update(); 0176 emit m_parent->repaintNeeded(); 0177 } 0178 0179 void RoutingPluginPrivate::updateButtonVisibility() 0180 { 0181 bool const show = m_guidanceModeEnabled; 0182 bool const near = show && m_nearNextInstruction; 0183 m_widget.progressBar->setVisible( near ); 0184 m_widget.instructionIconLabel->setVisible( show ); 0185 m_widget.spacer->changeSize( show ? 10 : 0, 20 ); 0186 m_widget.instructionLabel->setVisible( show ); 0187 0188 // m_widget.followingInstructionIconLabel->setVisible( show ); 0189 // Disabling the next instruction turn icon for now, it seems to confuse first time users. 0190 m_widget.followingInstructionIconLabel->setVisible( false ); 0191 0192 m_widget.destinationDistanceLabel->setVisible( show ); 0193 0194 m_widget.gpsButton->setVisible( !show ); 0195 m_widget.zoomOutButton->setVisible( !show ); 0196 m_widget.zoomInButton->setVisible( !show ); 0197 0198 m_widgetItem->widget()->updateGeometry(); 0199 QSize const size = m_widgetItem->widget()->sizeHint(); 0200 m_widgetItem->widget()->resize( size ); 0201 m_widgetItem->setContentSize( size ); 0202 0203 bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen; 0204 if ( smallScreen ) { 0205 qreal const pluginWidth = size.width(); 0206 int x = -10; 0207 if ( m_guidanceModeEnabled ) { 0208 int const parentWidth = m_marbleWidget->width(); 0209 x = qRound( ( parentWidth - pluginWidth ) / 2.0 ); 0210 } 0211 m_parent->setPosition( QPointF( x, m_parent->position().y() ) ); 0212 } 0213 } 0214 0215 void RoutingPluginPrivate::updateZoomButtons() 0216 { 0217 if ( m_marbleWidget ) { 0218 updateZoomButtons( m_marbleWidget->zoom() ); 0219 } 0220 } 0221 0222 void RoutingPluginPrivate::toggleGuidanceMode( bool enabled ) 0223 { 0224 if( !m_marbleWidget || m_guidanceModeEnabled == enabled ) { 0225 return; 0226 } 0227 0228 m_guidanceModeEnabled = enabled; 0229 updateButtonVisibility(); 0230 0231 if( enabled ) { 0232 QObject::connect( m_routingModel, SIGNAL(positionChanged()), 0233 m_parent, SLOT(updateDestinationInformation()) ); 0234 } else { 0235 QObject::disconnect( m_routingModel, SIGNAL(positionChanged()), 0236 m_parent, SLOT(updateDestinationInformation()) ); 0237 } 0238 0239 if ( enabled ) { 0240 QString const text = QObject::tr( "Starting guidance mode, please wait..." ); 0241 m_widget.instructionLabel->setText( richText( "%1" ).arg( text ) ); 0242 } 0243 0244 if ( enabled ) { 0245 RouteRequest* request = m_marbleWidget->model()->routingManager()->routeRequest(); 0246 if ( request && request->size() > 0 ) { 0247 GeoDataCoordinates source = request->source(); 0248 if ( source.isValid() ) { 0249 GeoDataLookAt view; 0250 view.setCoordinates( source ); 0251 // By happy coincidence this equals OpenStreetMap tile level 15 0252 view.setRange( 851.807 ); 0253 m_marbleWidget->flyTo( view ); 0254 } 0255 } 0256 } 0257 0258 m_marbleWidget->model()->routingManager()->setGuidanceModeEnabled( enabled ); 0259 0260 if ( enabled ) { 0261 m_routeCompleted = false; 0262 } 0263 0264 forceRepaint(); 0265 } 0266 0267 void RoutingPluginPrivate::updateDestinationInformation() 0268 { 0269 if ( m_routingModel->route().currentSegment().isValid() ) { 0270 qreal remaining = remainingDistance(); 0271 qreal distanceLeft = nextInstructionDistance(); 0272 m_audio->update( m_routingModel->route(), distanceLeft, remaining, m_routingModel->deviatedFromRoute() ); 0273 0274 m_nearNextInstruction = distanceLeft < thresholdDistance; 0275 0276 QString pixmapHtml = "<img src=\":/flag.png\" /><br />"; 0277 m_widget.destinationDistanceLabel->setText( pixmapHtml + richText( fuzzyDistance( remaining ) ) ); 0278 0279 m_widget.instructionIconLabel->setEnabled( m_nearNextInstruction ); 0280 m_widget.progressBar->setMaximum( thresholdDistance ); 0281 m_widget.progressBar->setValue( qRound( distanceLeft ) ); 0282 0283 updateButtonVisibility(); 0284 0285 QString pixmap = MarbleDirs::path(QStringLiteral("bitmaps/routing_step.png")); 0286 pixmapHtml = QString( "<img src=\"%1\" />" ).arg( pixmap ); 0287 0288 qreal planetRadius = m_marbleWidget->model()->planet()->radius(); 0289 GeoDataCoordinates const onRoute = m_routingModel->route().positionOnRoute(); 0290 GeoDataCoordinates const ego = m_routingModel->route().position(); 0291 qreal const distanceToRoute = planetRadius * ego.sphericalDistanceTo(onRoute); 0292 0293 if ( !m_routingModel->route().currentSegment().isValid() ) { 0294 m_widget.instructionLabel->setText( richText( QObject::tr( "Calculate a route to get directions." ) ) ); 0295 m_widget.instructionIconLabel->setText( pixmapHtml ); 0296 } else if ( distanceToRoute > 300.0 ) { 0297 m_widget.instructionLabel->setText( richText( QObject::tr( "Route left." ) ) ); 0298 m_widget.instructionIconLabel->setText( pixmapHtml ); 0299 } else if ( !m_routingModel->route().currentSegment().nextRouteSegment().isValid() ) { 0300 m_widget.instructionLabel->setText( richText( QObject::tr( "Destination ahead." ) ) ); 0301 m_widget.instructionIconLabel->setText( pixmapHtml ); 0302 } else { 0303 pixmap = m_routingModel->route().currentSegment().nextRouteSegment().maneuver().directionPixmap(); 0304 QString const instructionText = m_routingModel->route().currentSegment().nextRouteSegment().maneuver().instructionText(); 0305 m_widget.instructionLabel->setText( richText( "%1" ).arg( instructionText ) ); 0306 pixmapHtml = QString( "<p align=\"center\"><img src=\"%1\" /><br />%2</p>" ).arg( pixmap ); 0307 m_widget.instructionIconLabel->setText( pixmapHtml.arg( richText( fuzzyDistance( distanceLeft ) ) ) ); 0308 0309 if( remaining > 50 ) { 0310 m_routeCompleted = false; 0311 } else { 0312 if ( !m_routeCompleted ) { 0313 QString content = QObject::tr( "Arrived at destination. <a href=\"#reverse\">Calculate the way back.</a>" ); 0314 m_widget.instructionLabel->setText( richText( "%1" ).arg( content ) ); 0315 } 0316 m_routeCompleted = true; 0317 } 0318 } 0319 0320 forceRepaint(); 0321 } 0322 } 0323 0324 void RoutingPluginPrivate::updateGpsButton( PositionProviderPlugin *activePlugin ) 0325 { 0326 m_widget.gpsButton->setChecked( activePlugin != nullptr ); 0327 forceRepaint(); 0328 } 0329 0330 void RoutingPluginPrivate::togglePositionTracking( bool enabled ) 0331 { 0332 PositionProviderPlugin* plugin = nullptr; 0333 if ( enabled ) { 0334 const PluginManager* pluginManager = m_marbleWidget->model()->pluginManager(); 0335 QList<const PositionProviderPlugin*> plugins = pluginManager->positionProviderPlugins(); 0336 if ( plugins.size() > 0 ) { 0337 plugin = plugins.first()->newInstance(); 0338 } 0339 } 0340 m_parent->marbleModel()->positionTracking()->setPositionProviderPlugin( plugin ); 0341 } 0342 0343 void RoutingPluginPrivate::reverseRoute() 0344 { 0345 if ( m_marbleWidget ) { 0346 m_marbleWidget->model()->routingManager()->reverseRoute(); 0347 } 0348 } 0349 0350 void RoutingPluginPrivate::readSettings() 0351 { 0352 if ( m_configDialog ) { 0353 if ( !m_speakersModel ) { 0354 m_speakersModel = new SpeakersModel( m_parent ); 0355 } 0356 int const index = m_speakersModel->indexOf( m_audio->speaker() ); 0357 m_configUi.speakerComboBox->setModel( m_speakersModel ); 0358 m_configUi.speakerComboBox->setCurrentIndex( index ); 0359 m_configUi.voiceNavigationCheckBox->setChecked( !m_audio->isMuted() ); 0360 m_configUi.soundRadioButton->setChecked( m_audio->isSoundEnabled() ); 0361 m_configUi.speakerRadioButton->setChecked( !m_audio->isSoundEnabled() ); 0362 } 0363 } 0364 0365 qreal RoutingPluginPrivate::nextInstructionDistance() const 0366 { 0367 GeoDataCoordinates position = m_routingModel->route().position(); 0368 GeoDataCoordinates interpolated = m_routingModel->route().positionOnRoute(); 0369 GeoDataCoordinates onRoute = m_routingModel->route().currentWaypoint(); 0370 qreal planetRadius = m_marbleWidget->model()->planet()->radius(); 0371 const qreal distance = planetRadius * (position.sphericalDistanceTo(interpolated) + interpolated.sphericalDistanceTo(onRoute)); 0372 const RouteSegment &segment = m_routingModel->route().currentSegment(); 0373 for (int i=0; i<segment.path().size(); ++i) { 0374 if (segment.path()[i] == onRoute) { 0375 return distance + segment.path().length( planetRadius, i ); 0376 } 0377 } 0378 0379 return distance; 0380 } 0381 0382 qreal RoutingPluginPrivate::remainingDistance() const 0383 { 0384 GeoDataCoordinates position = m_routingModel->route().currentSegment().maneuver().position(); 0385 bool foundSegment = false; 0386 qreal distance = nextInstructionDistance(); 0387 for ( int i=0; i<m_routingModel->route().size(); ++i ) { 0388 if ( foundSegment ) { 0389 distance += m_routingModel->route().at( i ).distance(); 0390 } else { 0391 foundSegment = m_routingModel->route().at( i ).maneuver().position() == position; 0392 } 0393 } 0394 0395 return distance; 0396 } 0397 0398 void RoutingPlugin::writeSettings() 0399 { 0400 Q_ASSERT( d->m_configDialog ); 0401 int const index = d->m_configUi.speakerComboBox->currentIndex(); 0402 if ( index >= 0 ) { 0403 QModelIndex const idx = d->m_speakersModel->index( index ); 0404 d->m_audio->setSpeaker( d->m_speakersModel->data( idx, SpeakersModel::Path ).toString() ); 0405 if ( !d->m_speakersModel->data( idx, SpeakersModel::IsLocal ).toBool() ) { 0406 d->m_speakersModel->install( index ); 0407 } 0408 } 0409 d->m_audio->setMuted( !d->m_configUi.voiceNavigationCheckBox->isChecked() ); 0410 d->m_audio->setSoundEnabled( d->m_configUi.soundRadioButton->isChecked() ); 0411 d->readSettings(); 0412 emit settingsChanged( nameId() ); 0413 } 0414 0415 0416 RoutingPlugin::RoutingPlugin() : 0417 AbstractFloatItem( nullptr ), 0418 d( nullptr ) 0419 { 0420 } 0421 0422 RoutingPlugin::RoutingPlugin( const MarbleModel *marbleModel ) : 0423 AbstractFloatItem( marbleModel, QPointF( -10, -10 ) ), 0424 d( new RoutingPluginPrivate( this ) ) 0425 { 0426 setEnabled( true ); 0427 //plugin is visible by default on small screen devices 0428 setVisible( MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen ); 0429 setPadding( 0.5 ); 0430 setBorderWidth( 1 ); 0431 setBackground( QBrush( QColor( "white" ) ) ); 0432 } 0433 0434 RoutingPlugin::~RoutingPlugin() 0435 { 0436 delete d; 0437 } 0438 0439 QStringList RoutingPlugin::backendTypes() const 0440 { 0441 return QStringList(QStringLiteral("routing")); 0442 } 0443 0444 QString RoutingPlugin::name() const 0445 { 0446 return tr( "Routing" ); 0447 } 0448 0449 QString RoutingPlugin::guiString() const 0450 { 0451 return tr( "&Routing" ); 0452 } 0453 0454 QString RoutingPlugin::nameId() const 0455 { 0456 return QStringLiteral("routing"); 0457 } 0458 0459 QString RoutingPlugin::version() const 0460 { 0461 return QStringLiteral("1.0"); 0462 } 0463 0464 QString RoutingPlugin::description() const 0465 { 0466 return tr( "Routing information and navigation controls" ); 0467 } 0468 0469 QString RoutingPlugin::copyrightYears() const 0470 { 0471 return QStringLiteral("2010"); 0472 } 0473 0474 QVector<PluginAuthor> RoutingPlugin::pluginAuthors() const 0475 { 0476 return QVector<PluginAuthor>() 0477 << PluginAuthor(QStringLiteral("Siddharth Srivastava"), QStringLiteral("akssps011@gmail.com")) 0478 << PluginAuthor(QStringLiteral("Dennis Nienhüser"), QStringLiteral("nienhueser@kde.org")); 0479 } 0480 0481 QIcon RoutingPlugin::icon() const 0482 { 0483 return QIcon(QStringLiteral(":/icons/routeplanning.png")); 0484 } 0485 0486 void RoutingPlugin::initialize() 0487 { 0488 QWidget *widget = new QWidget; 0489 d->m_widget.setupUi( widget ); 0490 d->m_widgetItem = new WidgetGraphicsItem( this ); 0491 d->m_widgetItem->setWidget( widget ); 0492 0493 PositionProviderPlugin* activePlugin = marbleModel()->positionTracking()->positionProviderPlugin(); 0494 d->updateGpsButton( activePlugin ); 0495 connect( marbleModel()->positionTracking(), 0496 SIGNAL(positionProviderPluginChanged(PositionProviderPlugin*)), 0497 this, SLOT(updateGpsButton(PositionProviderPlugin*)) ); 0498 0499 d->m_widget.routingButton->setEnabled( false ); 0500 connect( d->m_widget.instructionLabel, SIGNAL(linkActivated(QString)), 0501 this, SLOT(reverseRoute()) ); 0502 0503 MarbleGraphicsGridLayout *layout = new MarbleGraphicsGridLayout( 1, 1 ); 0504 layout->addItem( d->m_widgetItem, 0, 0 ); 0505 setLayout( layout ); 0506 d->updateButtonVisibility(); 0507 } 0508 0509 bool RoutingPlugin::isInitialized() const 0510 { 0511 return d->m_widgetItem; 0512 } 0513 0514 bool RoutingPlugin::eventFilter( QObject *object, QEvent *e ) 0515 { 0516 if ( d->m_marbleWidget || !enabled() || !visible() ) { 0517 return AbstractFloatItem::eventFilter( object, e ); 0518 } 0519 0520 MarbleWidget *widget = dynamic_cast<MarbleWidget*> ( object ); 0521 0522 if ( widget && !d->m_marbleWidget ) { 0523 d->m_marbleWidget = widget; 0524 d->m_routingModel = d->m_marbleWidget->model()->routingManager()->routingModel(); 0525 0526 connect( d->m_widget.routingButton, SIGNAL(clicked(bool)), 0527 this, SLOT(toggleGuidanceMode(bool)) ); 0528 connect( d->m_widget.gpsButton, SIGNAL(clicked(bool)), 0529 this, SLOT(togglePositionTracking(bool)) ); 0530 connect( d->m_widget.zoomInButton, SIGNAL(clicked()), 0531 d->m_marbleWidget, SLOT(zoomIn()) ); 0532 connect( d->m_widget.zoomOutButton, SIGNAL(clicked()), 0533 d->m_marbleWidget, SLOT(zoomOut()) ); 0534 connect( d->m_marbleWidget, SIGNAL(themeChanged(QString)), 0535 this, SLOT(updateZoomButtons()) ); 0536 connect( d->m_marbleWidget, SIGNAL(zoomChanged(int)), 0537 this, SLOT(updateZoomButtons(int)) ); 0538 connect( d->m_routingModel, SIGNAL(currentRouteChanged()), 0539 this, SLOT(updateGuidanceModeButton()) ); 0540 d->updateGuidanceModeButton(); 0541 } 0542 return AbstractFloatItem::eventFilter( object, e ); 0543 } 0544 0545 QHash<QString,QVariant> RoutingPlugin::settings() const 0546 { 0547 QHash<QString, QVariant> result = AbstractFloatItem::settings(); 0548 0549 result.insert(QStringLiteral("muted"), d->m_audio->isMuted()); 0550 result.insert(QStringLiteral("sound"), d->m_audio->isSoundEnabled()); 0551 result.insert(QStringLiteral("speaker"), d->m_audio->speaker()); 0552 0553 return result; 0554 } 0555 0556 void RoutingPlugin::setSettings( const QHash<QString,QVariant> &settings ) 0557 { 0558 AbstractFloatItem::setSettings( settings ); 0559 0560 d->m_audio->setMuted(settings.value(QStringLiteral("muted"), false).toBool()); 0561 d->m_audio->setSoundEnabled(settings.value(QStringLiteral("sound"), true).toBool()); 0562 d->m_audio->setSpeaker(settings.value(QStringLiteral("speaker")).toString()); 0563 0564 d->readSettings(); 0565 } 0566 0567 QDialog *RoutingPlugin::configDialog() 0568 { 0569 if ( !d->m_configDialog ) { 0570 d->m_configDialog = new QDialog; 0571 d->m_configUi.setupUi( d->m_configDialog ); 0572 d->readSettings(); 0573 0574 connect( d->m_configDialog, SIGNAL(accepted()), this, SLOT(writeSettings()) ); 0575 connect( d->m_configDialog, SIGNAL(rejected()), this, SLOT(readSettings()) ); 0576 connect( d->m_configUi.buttonBox->button( QDialogButtonBox::Reset ), SIGNAL(clicked()), 0577 SLOT(restoreDefaultSettings()) ); 0578 } 0579 0580 return d->m_configDialog; 0581 } 0582 0583 } 0584 0585 #include "moc_RoutingPlugin.cpp"