14 #include "ui_RoutingPlugin.h"
15 #include "ui_RoutingConfigDialog.h"
38 #include <QToolButton>
40 #include <QActionGroup>
43 #include <QPushButton>
44 #include <QSpacerItem>
45 #if QT_VERSION < 0x050000
46 #include <QPlastiqueStyle>
54 int const thresholdTime = 3;
55 int const thresholdDistance = 1000;
58 class RoutingPluginPrivate
62 WidgetGraphicsItem* m_widgetItem;
63 RoutingModel* m_routingModel;
64 Ui::RoutingPlugin m_widget;
65 bool m_nearNextInstruction;
66 bool m_guidanceModeEnabled;
69 Ui::RoutingConfigDialog m_configUi;
70 bool m_routeCompleted;
71 SpeakersModel* m_speakersModel;
73 RoutingPluginPrivate( RoutingPlugin* parent );
75 void updateZoomButtons(
int zoomValue );
77 void updateZoomButtons();
79 void updateGuidanceModeButton();
83 void updateButtonVisibility();
87 void toggleGuidanceMode(
bool enabled );
89 void updateDestinationInformation();
91 void updateGpsButton( PositionProviderPlugin *activePlugin );
93 void togglePositionTracking(
bool enabled );
95 QString richText(
const QString &source )
const;
97 QString fuzzyDistance( qreal distanceMeter )
const;
101 qreal nextInstructionDistance()
const;
103 qreal remainingDistance()
const;
106 RoutingPlugin* m_parent;
109 RoutingPluginPrivate::RoutingPluginPrivate( RoutingPlugin *parent ) :
113 m_nearNextInstruction( false ),
114 m_guidanceModeEnabled( false ),
115 m_audio( new AudioOutput( parent ) ),
117 m_routeCompleted( false ),
118 m_speakersModel( 0 ),
121 m_audio->setMuted(
false );
122 m_audio->setSoundEnabled(
true );
125 QString RoutingPluginPrivate::richText(
const QString &source )
const
127 return QString(
"<font size=\"+1\" color=\"black\">%1</font>" ).arg( source );
130 QString RoutingPluginPrivate::fuzzyDistance( qreal length )
const
133 QString distanceUnit = QLatin1String(
"m" );
141 if ( length >= 1000 ) {
145 }
else if ( length >= 200 ) {
146 length = 50 * qRound( length / 50 );
147 }
else if ( length >= 100 ) {
148 length = 25 * qRound( length / 25 );
150 length = 10 * qRound( length / 10 );
154 return QString(
"%1 %2" ).arg( length, 0,
'f', precision ).arg( distanceUnit );
157 void RoutingPluginPrivate::updateZoomButtons(
int zoomValue )
159 int const minZoom = m_marbleWidget ? m_marbleWidget->minimumZoom() : 900;
160 int const maxZoom = m_marbleWidget ? m_marbleWidget->maximumZoom() : 2400;
162 bool const zoomInEnabled = zoomValue < maxZoom;
163 bool const zoomOutEnabled = zoomValue > minZoom;
165 if ( ( zoomInEnabled != m_widget.zoomInButton->isEnabled() ) ||
166 ( zoomOutEnabled != m_widget.zoomOutButton->isEnabled() ) ) {
167 m_widget.zoomInButton->setEnabled( zoomInEnabled );
168 m_widget.zoomOutButton->setEnabled( zoomOutEnabled );
173 void RoutingPluginPrivate::updateGuidanceModeButton()
175 bool const hasRoute = m_routingModel->rowCount() > 0;
176 m_widget.routingButton->setEnabled( hasRoute );
180 void RoutingPluginPrivate::forceRepaint()
183 emit m_parent->repaintNeeded();
186 void RoutingPluginPrivate::updateButtonVisibility()
188 bool const show = m_guidanceModeEnabled;
189 bool const near = show && m_nearNextInstruction;
190 m_widget.progressBar->setVisible( near );
191 m_widget.instructionIconLabel->setVisible( show );
192 m_widget.spacer->changeSize( show ? 10 : 0, 20 );
193 m_widget.instructionLabel->setVisible( show );
197 m_widget.followingInstructionIconLabel->setVisible(
false );
199 m_widget.destinationDistanceLabel->setVisible( show );
201 m_widget.gpsButton->setVisible( !show );
202 m_widget.zoomOutButton->setVisible( !show );
203 m_widget.zoomInButton->setVisible( !show );
205 m_widgetItem->widget()->updateGeometry();
206 QSize
const size = m_widgetItem->widget()->sizeHint();
207 m_widgetItem->widget()->resize( size );
208 m_widgetItem->setContentSize( size );
212 qreal
const pluginWidth = size.width();
214 if ( m_guidanceModeEnabled ) {
215 int const parentWidth = m_marbleWidget->width();
216 x = qRound( ( parentWidth - pluginWidth ) / 2.0 );
218 m_parent->setPosition( QPointF( x, m_parent->position().y() ) );
222 void RoutingPluginPrivate::updateZoomButtons()
224 if ( m_marbleWidget ) {
225 updateZoomButtons( m_marbleWidget->zoom() );
229 void RoutingPluginPrivate::toggleGuidanceMode(
bool enabled )
231 if( !m_marbleWidget || m_guidanceModeEnabled == enabled ) {
235 m_guidanceModeEnabled = enabled;
236 updateButtonVisibility();
239 QObject::connect( m_routingModel, SIGNAL(positionChanged()),
240 m_parent, SLOT(updateDestinationInformation()) );
242 QObject::disconnect( m_routingModel, SIGNAL(positionChanged()),
243 m_parent, SLOT(updateDestinationInformation()) );
247 QString
const text = QObject::tr(
"Starting guidance mode, please wait..." );
248 m_widget.instructionLabel->setText( richText(
"%1" ).arg( text ) );
252 RouteRequest* request = m_marbleWidget->model()->routingManager()->routeRequest();
253 if ( request && request->size() > 0 ) {
254 GeoDataCoordinates source = request->source();
255 if ( source.longitude() != 0.0 || source.latitude() != 0.0 ) {
257 view.setCoordinates( source );
259 view.setRange( 851.807 );
260 m_marbleWidget->flyTo( view );
265 m_marbleWidget->model()->routingManager()->setGuidanceModeEnabled( enabled );
268 m_routeCompleted =
false;
274 void RoutingPluginPrivate::updateDestinationInformation()
276 if ( m_routingModel->route().currentSegment().isValid() ) {
277 qreal remaining = remainingDistance();
278 qreal distanceLeft = nextInstructionDistance();
279 m_audio->update( m_routingModel->route(), distanceLeft, remaining, m_routingModel->deviatedFromRoute() );
281 m_nearNextInstruction = distanceLeft < thresholdDistance;
283 QString pixmapHtml =
"<img src=\":/flag.png\" /><br />";
284 m_widget.destinationDistanceLabel->setText( pixmapHtml + richText( fuzzyDistance( remaining ) ) );
286 m_widget.instructionIconLabel->setEnabled( m_nearNextInstruction );
287 m_widget.progressBar->setMaximum( thresholdDistance );
288 m_widget.progressBar->setValue( qRound( distanceLeft ) );
290 updateButtonVisibility();
293 pixmapHtml = QString(
"<img src=\"%1\" />" ).arg( pixmap );
295 GeoDataCoordinates
const onRoute = m_routingModel->route().positionOnRoute();
296 GeoDataCoordinates
const ego = m_routingModel->route().position();
299 if ( !m_routingModel->route().currentSegment().isValid() ) {
300 m_widget.instructionLabel->setText( richText( QObject::tr(
"Calculate a route to get directions." ) ) );
301 m_widget.instructionIconLabel->setText( pixmapHtml );
302 }
else if ( distanceToRoute > 300.0 ) {
303 m_widget.instructionLabel->setText( richText( QObject::tr(
"Route left." ) ) );
304 m_widget.instructionIconLabel->setText( pixmapHtml );
305 }
else if ( !m_routingModel->route().currentSegment().nextRouteSegment().isValid() ) {
306 m_widget.instructionLabel->setText( richText( QObject::tr(
"Destination ahead." ) ) );
307 m_widget.instructionIconLabel->setText( pixmapHtml );
309 pixmap = m_routingModel->route().currentSegment().nextRouteSegment().maneuver().directionPixmap();
310 QString
const instructionText = m_routingModel->route().currentSegment().nextRouteSegment().maneuver().instructionText();
311 m_widget.instructionLabel->setText( richText(
"%1" ).arg( instructionText ) );
312 pixmapHtml = QString(
"<p align=\"center\"><img src=\"%1\" /><br />%2</p>" ).arg( pixmap );
313 m_widget.instructionIconLabel->setText( pixmapHtml.arg( richText( fuzzyDistance( distanceLeft ) ) ) );
315 if( remaining > 50 ) {
316 m_routeCompleted =
false;
318 if ( !m_routeCompleted ) {
319 QString content = QObject::tr(
"Arrived at destination. <a href=\"#reverse\">Calculate the way back.</a>" );
320 m_widget.instructionLabel->setText( richText(
"%1" ).arg( content ) );
322 m_routeCompleted =
true;
330 void RoutingPluginPrivate::updateGpsButton( PositionProviderPlugin *activePlugin )
332 m_widget.gpsButton->setChecked( activePlugin != 0 );
336 void RoutingPluginPrivate::togglePositionTracking(
bool enabled )
338 PositionProviderPlugin* plugin = 0;
340 const PluginManager* pluginManager = m_marbleWidget->model()->pluginManager();
341 QList<const PositionProviderPlugin*> plugins = pluginManager->positionProviderPlugins();
342 if ( plugins.size() > 0 ) {
343 plugin = plugins.first()->newInstance();
346 m_parent->marbleModel()->positionTracking()->setPositionProviderPlugin( plugin );
349 void RoutingPluginPrivate::reverseRoute()
351 if ( m_marbleWidget ) {
352 m_marbleWidget->model()->routingManager()->reverseRoute();
356 void RoutingPluginPrivate::readSettings()
358 if ( m_configDialog ) {
359 if ( !m_speakersModel ) {
360 m_speakersModel =
new SpeakersModel( m_parent );
362 int const index = m_speakersModel->indexOf( m_audio->speaker() );
363 m_configUi.speakerComboBox->setModel( m_speakersModel );
364 m_configUi.speakerComboBox->setCurrentIndex( index );
365 m_configUi.voiceNavigationCheckBox->setChecked( !m_audio->isMuted() );
366 m_configUi.soundRadioButton->setChecked( m_audio->isSoundEnabled() );
367 m_configUi.speakerRadioButton->setChecked( !m_audio->isSoundEnabled() );
371 qreal RoutingPluginPrivate::nextInstructionDistance()
const
373 GeoDataCoordinates position = m_routingModel->route().position();
374 GeoDataCoordinates interpolated = m_routingModel->route().positionOnRoute();
375 GeoDataCoordinates onRoute = m_routingModel->route().currentWaypoint();
377 const RouteSegment &segment = m_routingModel->route().currentSegment();
378 for (
int i=0; i<segment.path().size(); ++i) {
379 if (segment.path()[i] == onRoute) {
380 return distance + segment.path().length(
EARTH_RADIUS, i );
387 qreal RoutingPluginPrivate::remainingDistance()
const
389 GeoDataCoordinates position = m_routingModel->route().currentSegment().maneuver().position();
390 bool foundSegment =
false;
391 qreal distance = nextInstructionDistance();
392 for (
int i=0; i<m_routingModel->route().size(); ++i ) {
393 if ( foundSegment ) {
394 distance += m_routingModel->route().at( i ).distance();
396 foundSegment = m_routingModel->route().at( i ).maneuver().position() == position;
403 void RoutingPlugin::writeSettings()
405 Q_ASSERT( d->m_configDialog );
406 int const index = d->m_configUi.speakerComboBox->currentIndex();
408 QModelIndex
const idx = d->m_speakersModel->index( index );
411 d->m_speakersModel->install( index );
414 d->m_audio->setMuted( !d->m_configUi.voiceNavigationCheckBox->isChecked() );
415 d->m_audio->setSoundEnabled( d->m_configUi.soundRadioButton->isChecked() );
429 d( new RoutingPluginPrivate( this ) )
446 return QStringList(
"routing" );
451 return tr(
"Routing" );
456 return tr(
"&Routing" );
461 return QString(
"routing" );
471 return tr(
"Routing information and navigation controls" );
481 return QList<PluginAuthor>()
482 <<
PluginAuthor(
"Siddharth Srivastava",
"akssps011@gmail.com" )
483 <<
PluginAuthor( QString::fromUtf8(
"Dennis Nienhüser" ),
"earthwings@gentoo.org" );
488 return QIcon(
":/icons/routeplanning.png");
494 d->m_widget.setupUi( widget );
496 d->m_widgetItem->setWidget( widget );
499 d->updateGpsButton( activePlugin );
504 d->m_widget.routingButton->setEnabled(
false );
505 connect( d->m_widget.instructionLabel, SIGNAL(linkActivated(QString)),
506 this, SLOT(reverseRoute()) );
510 #if QT_VERSION < 0x050000
517 d->m_widget.progressBar->setStyle(
new QPlastiqueStyle );
522 layout->
addItem( d->m_widgetItem, 0, 0 );
524 d->updateButtonVisibility();
529 return d->m_widgetItem;
534 if ( d->m_marbleWidget || !enabled() || !
visible() ) {
540 if ( widget && !d->m_marbleWidget ) {
541 d->m_marbleWidget = widget;
542 d->m_routingModel = d->m_marbleWidget->model()->routingManager()->routingModel();
544 connect( d->m_widget.routingButton, SIGNAL(clicked(
bool)),
545 this, SLOT(toggleGuidanceMode(
bool)) );
546 connect( d->m_widget.gpsButton, SIGNAL(clicked(
bool)),
547 this, SLOT(togglePositionTracking(
bool)) );
548 connect( d->m_widget.zoomInButton, SIGNAL(clicked()),
549 d->m_marbleWidget, SLOT(zoomIn()) );
550 connect( d->m_widget.zoomOutButton, SIGNAL(clicked()),
551 d->m_marbleWidget, SLOT(zoomOut()) );
552 connect( d->m_marbleWidget, SIGNAL(themeChanged(QString)),
553 this, SLOT(updateZoomButtons()) );
554 connect( d->m_marbleWidget, SIGNAL(zoomChanged(
int)),
555 this, SLOT(updateZoomButtons(
int)) );
556 connect( d->m_routingModel, SIGNAL(currentRouteChanged()),
557 this, SLOT(updateGuidanceModeButton()) );
558 d->updateGuidanceModeButton();
567 result.insert(
"muted", d->m_audio->isMuted() );
568 result.insert(
"sound", d->m_audio->isSoundEnabled() );
569 result.insert(
"speaker", d->m_audio->speaker() );
578 d->m_audio->setMuted( settings.value(
"muted",
false ).toBool() );
579 d->m_audio->setSoundEnabled( settings.value(
"sound",
true ).toBool() );
580 d->m_audio->setSpeaker( settings.value(
"speaker" ).toString() );
587 if ( !d->m_configDialog ) {
588 d->m_configDialog =
new QDialog;
589 d->m_configUi.setupUi( d->m_configDialog );
592 connect( d->m_configDialog, SIGNAL(accepted()),
this, SLOT(writeSettings()) );
593 connect( d->m_configDialog, SIGNAL(rejected()),
this, SLOT(readSettings()) );
594 connect( d->m_configUi.buttonBox->button( QDialogButtonBox::Reset ), SIGNAL(clicked()),
598 return d->m_configDialog;
605 #include "RoutingPlugin.moc"
QString copyrightYears() const
PositionProviderPlugin positionProviderPlugin
virtual QHash< QString, QVariant > settings() const
Settings of the plugin.
bool visible() const
Check visibility of the float item.
QString nameId() const
Returns the unique name of the plugin.
static QString path(const QString &relativePath)
QIcon icon() const
Returns an icon for the plugin.
virtual void setSettings(const QHash< QString, QVariant > &settings)
Set the settings of the plugin.
This file contains the headers for MarbleModel.
virtual bool eventFilter(QObject *object, QEvent *e)
bool eventFilter(QObject *object, QEvent *event)
void setBackground(const QBrush &background)
Changes the background brush of the item.
virtual void setSettings(const QHash< QString, QVariant > &settings)
Set the settings of the plugin.
void restoreDefaultSettings()
Passes an empty set of settings to the plugin.
qreal distanceSphere(qreal lon1, qreal lat1, qreal lon2, qreal lat2)
This method calculates the shortest distance between two points on a sphere.
void setLayout(AbstractMarbleGraphicsLayout *layout)
Set the layout of the graphics item.
void addItem(ScreenGraphicsItem *item, int row, int column)
The abstract class that provides position information.
bool isInitialized() const
QStringList backendTypes() const
Returns the name(s) of the backend that the plugin can render This method should return the name of t...
void settingsChanged(QString nameId)
This signal is emitted if the settings of the RenderPlugin changed.
The abstract class for float item plugins.
PositionTracking * positionTracking() const
QList< PluginAuthor > pluginAuthors() const
QString name() const
Returns the user-visible name of the plugin.
#define Q_EXPORT_PLUGIN2(a, b)
This file contains the headers for ViewportParams.
static MarbleGlobal * getInstance()
virtual QHash< QString, QVariant > settings() const
Settings of the plugin.
The data model (not based on QAbstractModel) for a MarbleWidget.
void setEnabled(bool enabled)
settting enabled
Profiles profiles() const
QString guiString() const
String that should be displayed in GUI.
QDialog * configDialog()
Returns a pointer to the configuration dialog of the plugin.
AbstractMarbleGraphicsLayout * layout() const
Returns the layout of the MarbleGraphicsItem.
void setBorderWidth(qreal width)
Set the border width of the item.
QString description() const
Returns a user description of the plugin.
const MarbleModel * marbleModel() const
Access to the MarbleModel.
void setPadding(qreal width)
Set the padding of the item.
void setVisible(bool visible)
Set visibility of the float item.