29 #include <QAbstractItemModel>
31 #include <QItemSelectionModel>
34 #include <QMouseEvent>
36 #include <QFileDialog>
41 class RoutingLayerPrivate
48 PaintRegion(
const T &index_,
const QRegion ®ion_ ) :
49 index( index_ ), region( region_ )
55 typedef PaintRegion<QModelIndex> ModelRegion;
56 typedef PaintRegion<int> RequestRegion;
59 RoutingLayer *
const q;
83 int m_dragStopOverRightIndex;
85 RoutingModel *
const m_routingModel;
87 MarblePlacemarkModel *m_placemarkModel;
95 RouteRequest *
const m_routeRequest;
97 MarbleWidgetPopupMenu *m_contextMenu;
99 QAction *m_removeViaPointAction;
101 int m_activeMenuIndex;
103 AlternativeRoutesModel *
const m_alternativeRoutesModel;
107 bool m_viewportChanged;
109 bool m_isInteractive;
112 explicit RoutingLayerPrivate( RoutingLayer *parent,
MarbleWidget *widget );
115 void storeDragPosition(
const QPoint &position );
122 static inline QColor alphaAdjusted(
const QColor &color,
int alpha );
131 inline void renderPlacemarks( GeoPainter *painter );
134 inline void renderRoute( GeoPainter *painter );
137 inline void renderAnnotations( GeoPainter *painter )
const;
140 inline void renderAlternativeRoutes( GeoPainter *painter );
143 inline void renderRequest( GeoPainter *painter );
146 void setRouteDirty(
bool dirty );
149 inline bool handleMouseButtonRelease(
QMouseEvent *e );
152 inline bool handleMouseButtonPress(
QMouseEvent *e );
158 inline bool isInfoPoint(
const QPoint &point );
161 inline bool isAlternativeRoutePoint(
const QPoint &point );
164 inline void paintStopOver(
QRect position );
167 inline void clearStopOver();
170 RoutingLayerPrivate::RoutingLayerPrivate( RoutingLayer *parent,
MarbleWidget *widget ) :
171 q( parent ), m_movingIndex( -1 ), m_marbleWidget( widget ),
172 m_targetPixmap(
":/data/bitmaps/routing_pick.png" ), m_dragStopOverRightIndex( -1 ),
173 m_routingModel( widget->model()->routingManager()->routingModel() ),
174 m_placemarkModel( 0 ), m_selectionModel( 0 ), m_routeDirty( false ), m_pixmapSize( 22, 22 ),
175 m_routeRequest( widget->model()->routingManager()->routeRequest() ),
176 m_activeMenuIndex( -1 ),
177 m_alternativeRoutesModel( widget->model()->routingManager()->alternativeRoutesModel() ),
178 m_viewContext(
Still ),
179 m_viewportChanged( true ),
180 m_isInteractive( true )
182 m_contextMenu =
new MarbleWidgetPopupMenu( m_marbleWidget, m_marbleWidget->model() );
184 QObject::connect( m_removeViaPointAction, SIGNAL(triggered()), q, SLOT(removeViaPoint()) );
185 m_contextMenu->addAction( Qt::RightButton, m_removeViaPointAction );
187 QObject::connect( exportAction, SIGNAL(triggered()), q, SLOT(exportRoute()) );
188 m_contextMenu->addAction( Qt::RightButton, exportAction );
190 m_pixmapSize =
QSize( 38, 38 );
197 if ( modifiers & Qt::ControlModifier ) {
198 bool leftHand = m_routeRequest->size() / 2 >= m_dragStopOverRightIndex;
199 if ( leftHand && m_routeRequest->size() > 2 ) {
202 return m_routeRequest->size();
205 return m_dragStopOverRightIndex;
209 void RoutingLayerPrivate::renderPlacemarks( GeoPainter *painter )
211 m_placemarks.clear();
212 painter->setPen(
QColor( Qt::black ) );
213 for (
int i = 0; i < m_placemarkModel->rowCount(); ++i ) {
214 QModelIndex index = m_placemarkModel->index( i, 0 );
215 QVariant data = index.
data( MarblePlacemarkModel::CoordinateRole );
217 GeoDataCoordinates pos = data.
value<GeoDataCoordinates>();
220 if ( !pixmap.isNull() && m_selectionModel->isSelected( index ) ) {
222 QPixmap result = selected.
pixmap( m_pixmapSize, QIcon::Selected, QIcon::On );
223 painter->drawPixmap( pos, result );
225 painter->drawPixmap( pos, pixmap );
228 QRegion region = painter->regionFromRect( pos, m_targetPixmap.width(), m_targetPixmap.height() );
229 m_placemarks.push_back( ModelRegion( index, region ) );
234 void RoutingLayerPrivate::renderAlternativeRoutes( GeoPainter *painter )
236 QPen alternativeRoutePen( m_marbleWidget->model()->routingManager()->routeColorAlternative() );
238 painter->setPen( alternativeRoutePen );
240 for (
int i=0; i<m_alternativeRoutesModel->rowCount(); ++i ) {
241 GeoDataDocument* route = m_alternativeRoutesModel->route( i );
242 if ( route && route != m_alternativeRoutesModel->currentRoute() ) {
243 const GeoDataLineString* points = AlternativeRoutesModel::waypoints( route );
245 painter->drawPolyline( *points );
246 if ( m_viewportChanged && m_isInteractive && m_viewContext ==
Still ) {
247 QRegion region = painter->regionFromPolyline( *points, 8 );
248 m_alternativeRouteRegions.push_back( RequestRegion( i, region ) );
255 void RoutingLayerPrivate::renderRoute( GeoPainter *painter )
257 GeoDataLineString waypoints = m_routingModel->route().path();
259 QPen standardRoutePen( m_marbleWidget->model()->routingManager()->routeColorStandard() );
261 if ( m_routeDirty ) {
262 standardRoutePen.setStyle( Qt::DotLine );
264 painter->setPen( standardRoutePen );
266 painter->drawPolyline( waypoints );
267 if ( m_viewportChanged && m_viewContext ==
Still ) {
268 int const offset = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen ? 24 : 8;
269 if ( m_isInteractive ) {
270 m_routeRegion = painter->regionFromPolyline( waypoints, offset );
275 standardRoutePen.setWidth( 2 );
276 painter->setPen( standardRoutePen );
282 painter->setBrush(
QBrush( m_marbleWidget->model()->routingManager()->routeColorAlternative() ) );
284 if ( !m_dropStopOver.isNull() ) {
285 int dx = 1 + m_pixmapSize.width() / 2;
286 int dy = 1 + m_pixmapSize.height() / 2;
288 painter->drawPixmap( center, m_targetPixmap );
290 if ( !m_dragStopOver.isNull() && m_dragStopOverRightIndex >= 0 && m_dragStopOverRightIndex <= m_routeRequest->size() ) {
291 QPoint moved = m_dropStopOver - m_dragStopOver;
293 qreal lon( 0.0 ), lat( 0.0 );
294 if ( m_marbleWidget->geoCoordinates( m_dropStopOver.x(), m_dropStopOver.y(),
295 lon, lat, GeoDataCoordinates::Radian ) ) {
296 GeoDataCoordinates drag( lon, lat );
297 standardRoutePen.setStyle( Qt::DotLine );
298 painter->setPen( standardRoutePen );
299 GeoDataLineString lineString;
300 if ( m_dragStopOverRightIndex > 0 ) {
301 lineString << m_routeRequest->at( m_dragStopOverRightIndex-1 );
304 if ( m_dragStopOverRightIndex < m_routeRequest->size() ) {
305 lineString << m_routeRequest->at( m_dragStopOverRightIndex );
307 painter->drawPolyline( lineString );
308 standardRoutePen.setStyle( Qt::SolidLine );
309 painter->setPen( standardRoutePen );
319 m_instructionRegions.clear();
320 for (
int i = 0; i < m_routingModel->rowCount(); ++i ) {
322 GeoDataCoordinates pos = index.
data( MarblePlacemarkModel::CoordinateRole ).
value<GeoDataCoordinates>();
324 painter->setBrush(
QBrush( m_marbleWidget->model()->routingManager()->routeColorAlternative() ) );
325 if ( m_selectionModel && m_selectionModel->selection().contains( index ) ) {
326 for (
int j=0; j<m_routingModel->route().size(); ++j ) {
327 const RouteSegment & segment = m_routingModel->route().at( j );
328 if ( segment.maneuver().position() == pos ) {
329 GeoDataLineString currentRoutePoints = segment.path();
331 QPen activeRouteSegmentPen( m_marbleWidget->model()->routingManager()->routeColorHighlighted() );
333 activeRouteSegmentPen.
setWidth( 6 );
334 if ( m_routeDirty ) {
335 activeRouteSegmentPen.setStyle( Qt::DotLine );
337 painter->setPen( activeRouteSegmentPen );
338 painter->drawPolyline( currentRoutePoints );
340 painter->setPen( standardRoutePen );
346 if ( m_isInteractive ) {
347 QRegion region = painter->regionFromEllipse( pos, 12, 12 );
348 m_instructionRegions.push_front( ModelRegion( index, region ) );
350 painter->drawEllipse( pos, 6, 6 );
352 if( !m_routingModel->deviatedFromRoute() ) {
353 GeoDataCoordinates location = m_routingModel->route().currentSegment().nextRouteSegment().maneuver().position();
354 QString nextInstruction = m_routingModel->route().currentSegment().nextRouteSegment().maneuver().instructionText();
355 if( !nextInstruction.
isEmpty() ) {
357 painter->drawEllipse( location, 6, 6 );
363 void RoutingLayerPrivate::renderAnnotations( GeoPainter *painter )
const
365 if ( !m_selectionModel || m_selectionModel->selection().isEmpty() ) {
370 for (
int i = 0; i < m_routingModel->rowCount(); ++i ) {
373 if ( m_selectionModel->selection().contains( index ) ) {
374 bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen;
375 GeoDataCoordinates pos = index.
data( MarblePlacemarkModel::CoordinateRole ).
value<GeoDataCoordinates>();
376 painter->setPen(
QColor( Qt::black ) );
378 painter->drawAnnotation( pos, index.
data().
toString(),
QSize( smallScreen ? 240 : 120, 0 ), 10, 30, 5, 5 );
383 void RoutingLayerPrivate::renderRequest( GeoPainter *painter )
386 for (
int i = 0; i < m_routeRequest->size(); ++i ) {
387 GeoDataCoordinates pos = m_routeRequest->at( i );
388 if ( pos.longitude() != 0.0 && pos.latitude() != 0.0 ) {
389 QPixmap pixmap = m_routeRequest->pixmap( i );
390 painter->drawPixmap( pos, pixmap );
392 m_regions.push_front( RequestRegion( i, region ) );
397 void RoutingLayerPrivate::storeDragPosition(
const QPoint &pos )
399 m_dragStopOver = pos;
400 m_dragStopOverRightIndex = -1;
402 qreal lon( 0.0 ), lat( 0.0 );
403 if ( m_routeRequest && !pos.
isNull()
404 && m_marbleWidget->geoCoordinates( pos.
x(), pos.
y(), lon, lat, GeoDataCoordinates::Radian ) ) {
405 GeoDataCoordinates waypoint( lon, lat );
406 m_dragStopOverRightIndex = m_routingModel->rightNeighbor( waypoint, m_routeRequest );
410 QColor RoutingLayerPrivate::alphaAdjusted(
const QColor &color,
int alpha )
413 result.setAlpha( alpha );
417 bool RoutingLayerPrivate::handleMouseButtonPress(
QMouseEvent *e )
419 foreach(
const RequestRegion ®ion, m_regions ) {
420 if ( region.region.contains( e->
pos() ) ) {
421 if ( e->
button() == Qt::LeftButton ) {
422 m_movingIndex = region.index;
423 m_dropStopOver =
QPoint();
424 m_dragStopOver =
QPoint();
426 }
else if ( e->
button() == Qt::RightButton ) {
427 m_removeViaPointAction->setEnabled(
true );
428 m_activeMenuIndex = region.index;
429 m_contextMenu->showRmbMenu( e->
x(), e->
y() );
436 foreach(
const ModelRegion ®ion, m_instructionRegions ) {
437 if ( region.region.contains( e->
pos() ) && m_selectionModel ) {
438 if ( e->
button() == Qt::LeftButton ) {
439 QItemSelectionModel::SelectionFlag command = QItemSelectionModel::ClearAndSelect;
440 if ( m_selectionModel->isSelected( region.index ) ) {
441 command = QItemSelectionModel::Clear;
443 m_selectionModel->select( region.index, command );
444 m_dropStopOver = e->
pos();
445 storeDragPosition( e->
pos() );
447 emit q->repaintNeeded();
449 }
else if ( e->
button() == Qt::RightButton ) {
450 m_removeViaPointAction->setEnabled(
false );
451 m_contextMenu->showRmbMenu( e->
x(), e->
y() );
458 if ( m_routeRegion.contains( e->
pos() ) ) {
459 if ( e->
button() == Qt::LeftButton ) {
461 m_dropStopOver = e->
pos();
462 storeDragPosition( e->
pos() );
464 }
else if ( e->
button() == Qt::RightButton ) {
465 m_removeViaPointAction->setEnabled(
false );
466 m_contextMenu->showRmbMenu( e->
x(), e->
y() );
472 if ( e->
button() != Qt::LeftButton ) {
476 foreach(
const RequestRegion ®ion, m_alternativeRouteRegions ) {
477 if ( region.region.contains( e->
pos() ) ) {
478 m_alternativeRoutesModel->setCurrentRoute( region.index );
483 foreach(
const ModelRegion ®ion, m_placemarks ) {
484 if ( region.region.contains( e->
pos() ) ) {
485 emit q->placemarkSelected( region.index );
493 bool RoutingLayerPrivate::handleMouseButtonRelease(
QMouseEvent *e )
495 if ( e->
button() != Qt::LeftButton ) {
499 if ( m_movingIndex >= 0 ) {
502 m_marbleWidget->model()->routingManager()->retrieveRoute();
506 if ( !m_dropStopOver.isNull() && !m_dragStopOver.isNull() ) {
507 QPoint moved = e->
pos() - m_dragStopOver;
512 qreal lon( 0.0 ), lat( 0.0 );
513 if ( m_dragStopOverRightIndex >= 0 && m_dragStopOverRightIndex <= m_routeRequest->size()
514 && m_marbleWidget->geoCoordinates( m_dropStopOver.x(), m_dropStopOver.y(), lon, lat, GeoDataCoordinates::Radian ) ) {
515 GeoDataCoordinates position( lon, lat );
516 m_dragStopOverRightIndex = viaInsertPosition( e->
modifiers() );
517 m_routeRequest->insert( m_dragStopOverRightIndex, position );
519 m_marbleWidget->model()->routingManager()->retrieveRoute();
527 bool RoutingLayerPrivate::handleMouseMove(
QMouseEvent *e )
529 qreal lon( 0.0 ), lat( 0.0 );
530 if ( m_marbleWidget->geoCoordinates( e->
pos().
x(), e->
pos().
y(),
531 lon, lat, GeoDataCoordinates::Radian ) ) {
533 if ( m_movingIndex >= 0 ) {
534 GeoDataCoordinates moved( lon, lat );
535 m_routeRequest->setPosition( m_movingIndex, moved );
536 m_marbleWidget->setCursor( Qt::ArrowCursor );
537 }
else if ( !m_dragStopOver.isNull() ) {
539 m_dragStopOverRightIndex = viaInsertPosition( e->
modifiers() );
540 QRect dirty = m_routeRegion.boundingRect();
541 dirty |=
QRect( m_dropStopOver, m_pixmapSize );
542 dirty |=
QRect( e->
pos(), m_pixmapSize );
543 if ( e->
buttons() & Qt::LeftButton ) {
544 m_dropStopOver = e->
pos();
546 m_dragStopOver =
QPoint();
547 m_dropStopOver =
QPoint();
549 emit q->repaintNeeded( dirty );
550 m_marbleWidget->setCursor( Qt::ArrowCursor );
551 }
else if ( isInfoPoint( e->
pos() ) ) {
553 m_marbleWidget->setCursor( Qt::ArrowCursor );
554 }
else if ( m_routeRegion.contains( e->
pos() ) ) {
555 m_dropStopOver = e->
pos();
556 m_marbleWidget->setCursor( Qt::ArrowCursor );
557 }
else if ( !m_dropStopOver.isNull() ) {
559 }
else if ( isAlternativeRoutePoint( e->
pos() ) ) {
560 m_marbleWidget->setCursor( Qt::ArrowCursor );
567 paintStopOver(
QRect( e->
pos(), m_pixmapSize ) );
574 bool RoutingLayerPrivate::isInfoPoint(
const QPoint &point )
576 foreach(
const RequestRegion ®ion, m_regions ) {
577 if ( region.region.contains( point ) ) {
582 foreach(
const ModelRegion ®ion, m_instructionRegions ) {
583 if ( region.region.contains( point ) ) {
591 bool RoutingLayerPrivate::isAlternativeRoutePoint(
const QPoint &point )
593 foreach(
const RequestRegion ®ion, m_alternativeRouteRegions ) {
594 if ( region.region.contains( point ) ) {
602 void RoutingLayerPrivate::paintStopOver(
QRect dirty )
604 emit q->repaintNeeded( m_dirtyRect );
605 int dx = 1 + m_pixmapSize.width() / 2;
606 int dy = 1 + m_pixmapSize.height() / 2;
607 dirty.
adjust( -dx, -dy, -dx, -dy );
608 emit q->repaintNeeded( dirty );
612 void RoutingLayerPrivate::clearStopOver()
614 m_dropStopOver =
QPoint();
615 m_dragStopOver =
QPoint();
616 emit q->repaintNeeded( m_dirtyRect );
620 QObject( parent ), d( new RoutingLayerPrivate( this, widget ) )
625 this, SLOT(setViewportChanged()) );
627 this, SLOT(setViewportChanged()) );
631 this, SLOT(showAlternativeRoutes()) );
653 Q_UNUSED( renderPos )
658 if ( d->m_placemarkModel) {
659 d->renderPlacemarks( painter );
662 if ( d->m_alternativeRoutesModel ) {
663 d->renderAlternativeRoutes( painter );
666 d->renderRoute( painter );
668 if ( d->m_routeRequest) {
669 d->renderRequest( painter );
672 d->renderAnnotations( painter );
675 if ( d->m_viewportChanged && d->m_viewContext ==
Still ) {
676 d->m_viewportChanged =
false;
690 if ( !d->m_isInteractive ) {
694 if ( event->
type() == QEvent::MouseButtonPress ) {
696 return d->handleMouseButtonPress( e );
699 if ( event->
type() == QEvent::MouseButtonRelease ) {
701 return d->handleMouseButtonRelease( e );
704 if ( event->
type() == QEvent::MouseMove ) {
706 return d->handleMouseMove( e );
714 d->m_placemarkModel = model;
715 setViewportChanged();
720 d->m_selectionModel = selection;
723 void RoutingLayerPrivate::setRouteDirty(
bool dirty )
725 m_routeDirty = dirty;
731 emit q->repaintNeeded();
734 void RoutingLayer::removeViaPoint()
736 if ( d->m_activeMenuIndex >= 0 ) {
737 d->m_routeRequest->remove( d->m_activeMenuIndex );
738 d->m_activeMenuIndex = -1;
739 d->setRouteDirty(
true );
740 d->m_marbleWidget->model()->routingManager()->retrieveRoute();
744 void RoutingLayer::showAlternativeRoutes()
746 setViewportChanged();
750 void RoutingLayer::exportRoute()
753 tr(
"Export Route" ),
755 tr(
"GPX and KML files (*.gpx *.kml)" ) );
759 QFile gpx( fileName );
760 if ( gpx.open( QFile::WriteOnly) ) {
761 d->m_routingModel->exportGpx( &gpx );
765 d->m_marbleWidget->model()->routingManager()->saveRoute( fileName );
773 setViewportChanged();
776 void RoutingLayer::setViewportChanged()
778 d->m_viewportChanged =
true;
780 d->m_instructionRegions.clear();
781 d->m_alternativeRouteRegions.clear();
786 d->m_viewContext = viewContext;
791 d->m_isInteractive = interactive;
796 return d->m_isInteractive;
801 #include "RoutingLayer.moc"
This class represents a model of all place marks which are currently available through a given Placem...
A container for Features, Styles and in the future Schemas.
bool eventFilter(QObject *obj, QEvent *event)
Overriding QWidget, used to make the layer interactive.
void setViewContext(ViewContext viewContext)
Set the view context to determine whether the map is used interactively.
void repaintNeeded(const QRect &rect=QRect())
A painter that allows to draw geometric primitives on the map.
qreal zValue() const
Reimplemented from LayerInterface.
This file contains the headers for MarbleModel.
ViewContext
This enum is used to choose context in which map quality gets used.
bool isInteractive() const
Returns whether the route is interactive (true by default if not changed by setInteractive) ...
QString tr(const char *sourceText, const char *disambiguation, int n)
~RoutingLayer()
Destructor.
QPixmap pixmap(const QSize &size, Mode mode, State state) const
virtual bool event(QEvent *e)
Layer of a GeoScene document.
animated view (e.g. while rotating the globe)
RoutingManager * routingManager()
QStringList renderPosition() const
Reimplemented from LayerInterface.
bool render(GeoPainter *painter, ViewportParams *viewport, const QString &renderPos="NONE", GeoSceneLayer *layer=0)
Reimplemented from LayerInterface.
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const
A public class that controls what is visible in the viewport of a Marble map.
int manhattanLength() const
All data is there and up to date.
static MarbleGlobal * getInstance()
QVariant data(int role) const
void setPlacemarkModel(MarblePlacemarkModel *model)
Set the placemark model to use.
void adjust(int dx1, int dy1, int dx2, int dy2)
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFlags< QFileDialog::Option > options)
Rendering is based on complete, but outdated data, data update was requested.
void synchronizeWith(QItemSelectionModel *selection)
Set the proxy model another QAbstractItemView uses that should share its selection model with us...
const QPoint & pos() const
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
A class that defines a 3D bounding box for geographic data.
RenderState renderState() const
AlternativeRoutesModel * alternativeRoutesModel()
Provides access to the model which contains a list of alternative routes.
void setInteractive(bool interactive)
Determine whether the route can be edited by the user (via points added, route cleared) ...
typedef KeyboardModifiers