• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdeedu API Reference
  • KDE Home
  • Contact Us
 

marble

  • sources
  • kde-4.14
  • kdeedu
  • marble
  • src
  • plugins
  • render
  • annotate
AnnotatePlugin.cpp
Go to the documentation of this file.
1 //
2 // This file is part of the Marble Virtual Globe.
3 //
4 // This program is free software licensed under the GNU LGPL. You can
5 // find a copy of this license in LICENSE.txt in the top directory of
6 // the source code.
7 //
8 // Copyright 2009 Andrew Manson <g.real.ate@gmail.com>
9 // Copyright 2013 Thibaut Gridel <tgridel@free.fr>
10 // Copyright 2014 Calin-Cristian Cruceru <crucerucalincristian@gmail.com>
11 //
12 
13 // Self
14 #include "AnnotatePlugin.h"
15 
16 // Marble
17 #include "MarbleDebug.h"
18 #include "AbstractProjection.h"
19 #include "EditGroundOverlayDialog.h"
20 #include "EditPolygonDialog.h"
21 #include "GeoDataDocument.h"
22 #include "GeoDataGroundOverlay.h"
23 #include "GeoDataLatLonBox.h"
24 #include "GeoDataParser.h"
25 #include "GeoDataPlacemark.h"
26 #include "GeoDataStyle.h"
27 #include "GeoDataTreeModel.h"
28 #include "GeoDataTypes.h"
29 #include "GeoPainter.h"
30 #include "GeoWriter.h"
31 #include "KmlElementDictionary.h"
32 #include "MarbleDirs.h"
33 #include "MarbleModel.h"
34 #include "MarblePlacemarkModel.h"
35 #include "MarbleWidget.h"
36 #include "MarbleWidgetInputHandler.h"
37 #include "PlacemarkTextAnnotation.h"
38 #include "TextureLayer.h"
39 #include "SceneGraphicsTypes.h"
40 
41 // Qt
42 #include <QFileDialog>
43 #include <QAction>
44 #include <QNetworkAccessManager>
45 #include <QNetworkReply>
46 #include <QNetworkRequest>
47 #include <QMessageBox>
48 #include <QtAlgorithms>
49 #include <QMessageBox>
50 #include <QPair>
51 
52 
53 namespace Marble
54 {
55 
56 AnnotatePlugin::AnnotatePlugin( const MarbleModel *model )
57  : RenderPlugin( model ),
58  m_widgetInitialized( false ),
59  m_marbleWidget( 0 ),
60  m_overlayRmbMenu( new QMenu( m_marbleWidget ) ),
61  m_polygonRmbMenu( new QMenu( m_marbleWidget ) ),
62  m_nodeRmbMenu( new QMenu( m_marbleWidget ) ),
63  m_annotationDocument( new GeoDataDocument ),
64  m_polygonPlacemark( 0 ),
65  m_movedItem( 0 ),
66  m_addingPlacemark( false ),
67  m_drawingPolygon( false ),
68  m_addingPolygonHole( false ),
69  m_removingItem( false ),
70  // m_networkAccessManager( 0 ),
71  m_isInitialized( false )
72 {
73  // Plugin is enabled by default
74  setEnabled( true );
75  // Plugin is not visible by default
76  setVisible( false );
77  connect( this, SIGNAL(visibilityChanged(bool, QString)), SLOT(enableModel(bool)) );
78 
79  m_annotationDocument->setName( tr("Annotations") );
80  m_annotationDocument->setDocumentRole( UserDocument );
81 
82  GeoDataStyle style;
83  GeoDataPolyStyle polyStyle;
84 
85  polyStyle.setColor( QColor( 0, 255, 255, 80 ) );
86  style.setId( "polygon" );
87  style.setPolyStyle( polyStyle );
88  m_annotationDocument->addStyle( style );
89 }
90 
91 AnnotatePlugin::~AnnotatePlugin()
92 {
93  if ( m_marbleWidget ) {
94  m_marbleWidget->model()->treeModel()->removeDocument( m_annotationDocument );
95  }
96 
97  delete m_annotationDocument;
98  // delete m_networkAccessManager;
99 }
100 
101 QStringList AnnotatePlugin::backendTypes() const
102 {
103  return QStringList( "annotation" );
104 }
105 
106 QString AnnotatePlugin::renderPolicy() const
107 {
108  return QString( "ALWAYS" );
109 }
110 
111 QStringList AnnotatePlugin::renderPosition() const
112 {
113  return QStringList() << "ALWAYS_ON_TOP";
114 }
115 
116 QString AnnotatePlugin::name() const
117 {
118  return tr( "Annotation" );
119 }
120 
121 QString AnnotatePlugin::guiString() const
122 {
123  return tr( "&Annotation" );
124 }
125 
126 QString AnnotatePlugin::nameId() const
127 {
128  return QString( "annotation" );
129 }
130 
131 QString AnnotatePlugin::description() const
132 {
133  return tr( "Draws annotations on maps with placemarks or polygons." );
134 }
135 
136 QString AnnotatePlugin::version() const
137 {
138  return "1.0";
139 }
140 
141 QString AnnotatePlugin::copyrightYears() const
142 {
143  return "2009, 2013";
144 }
145 
146 QList<PluginAuthor> AnnotatePlugin::pluginAuthors() const
147 {
148  return QList<PluginAuthor>()
149  << PluginAuthor( "Andrew Manson", "<g.real.ate@gmail.com>" )
150  << PluginAuthor( "Thibaut Gridel", "<tgridel@free.fr>" );
151 }
152 
153 QIcon AnnotatePlugin::icon() const
154 {
155  return QIcon( ":/icons/draw-placemark.png");
156 }
157 
158 
159 void AnnotatePlugin::initialize()
160 {
161  if ( !m_isInitialized ) {
162  m_widgetInitialized = false;
163 
164  delete m_polygonPlacemark;
165  m_polygonPlacemark = 0;
166 
167  delete m_movedItem;
168  m_movedItem = 0;
169 
170  m_addingPlacemark = false;
171  m_drawingPolygon = false;
172  m_removingItem = false;
173  m_isInitialized = true;
174  }
175 }
176 
177 bool AnnotatePlugin::isInitialized() const
178 {
179  return m_isInitialized;
180 }
181 
182 QString AnnotatePlugin::runtimeTrace() const
183 {
184  return QString("Annotate Items: %1").arg( m_annotationDocument->size() );
185 }
186 
187 const QList<QActionGroup*> *AnnotatePlugin::actionGroups() const
188 {
189  return &m_actions;
190 }
191 
192 const QList<QActionGroup*> *AnnotatePlugin::toolbarActionGroups() const
193 {
194  return &m_toolbarActions;
195 }
196 
197 bool AnnotatePlugin::render( GeoPainter *painter, ViewportParams *viewport, const QString &renderPos, GeoSceneLayer *layer )
198 {
199  Q_UNUSED( renderPos );
200  Q_UNUSED( layer );
201 
202  QListIterator<SceneGraphicsItem*> iter( m_graphicsItems );
203  while ( iter.hasNext() ) {
204  iter.next()->paint( painter, viewport );
205  }
206 
207  return true;
208 }
209 
210 void AnnotatePlugin::enableModel( bool enabled )
211 {
212  if ( enabled ) {
213  if ( m_marbleWidget ) {
214  setupActions( m_marbleWidget );
215  m_marbleWidget->model()->treeModel()->addDocument( m_annotationDocument );
216  }
217  } else {
218  setupActions( 0 );
219  if ( m_marbleWidget ) {
220  m_marbleWidget->model()->treeModel()->removeDocument( m_annotationDocument );
221  }
222  }
223 }
224 
225 void AnnotatePlugin::setAddingPlacemark( bool enabled )
226 {
227  m_addingPlacemark = enabled ;
228 }
229 
230 void AnnotatePlugin::setDrawingPolygon( bool enabled )
231 {
232  m_drawingPolygon = enabled;
233  if ( enabled ) {
234  m_polygonPlacemark = new GeoDataPlacemark;
235 
236  GeoDataPolygon *polygon = new GeoDataPolygon( Tessellate );
237  polygon->outerBoundary().setTessellate( true );
238  m_polygonPlacemark->setGeometry( polygon );
239 
240  m_polygonPlacemark->setParent( m_annotationDocument );
241  m_polygonPlacemark->setStyleUrl( "#polygon" );
242  m_marbleWidget->model()->treeModel()->addFeature( m_annotationDocument, m_polygonPlacemark );
243  } else {
244  const GeoDataPolygon *poly = dynamic_cast<const GeoDataPolygon*>( m_polygonPlacemark->geometry() );
245  Q_ASSERT( poly );
246 
247  if ( !poly->outerBoundary().isEmpty() ) {
248  AreaAnnotation *area = new AreaAnnotation( m_polygonPlacemark );
249  m_graphicsItems.append( area );
250  m_marbleWidget->update();
251  } else {
252  m_marbleWidget->model()->treeModel()->removeFeature( m_polygonPlacemark );
253  delete m_polygonPlacemark;
254  }
255  m_polygonPlacemark = 0;
256  }
257 }
258 
259 void AnnotatePlugin::setAddingPolygonHole( bool enabled )
260 {
261  if ( !enabled && m_holedPolygon &&
262  !m_holedPolygon->innerBoundaries().isEmpty() &&
263  m_holedPolygon->innerBoundaries().last().size() <= 2 ) {
264  m_holedPolygon->innerBoundaries().last().clear();
265  }
266 
267  m_addingPolygonHole = enabled;
268  m_holedPolygon = 0;
269 
270  emit repaintNeeded( QRegion() );
271 }
272 
273 void AnnotatePlugin::setAddingOverlay( bool enabled )
274 {
275  m_addingOverlay = enabled;
276 }
277 
278 void AnnotatePlugin::setMergingNodes( bool enabled )
279 {
280  if ( !enabled && m_mergedArea ) {
281  // Restore the normal state.
282  m_mergedArea->setState( AreaAnnotation::Normal );
283  }
284 
285  m_mergingNodes = enabled;
286  m_mergedArea = 0;
287 }
288 
289 void AnnotatePlugin::setRemovingItems( bool enabled )
290 {
291  m_removingItem = enabled;
292 }
293 
294 void AnnotatePlugin::addOverlay()
295 {
296  if ( !m_addingOverlay ) {
297  return;
298  }
299 
300  GeoDataGroundOverlay *overlay = new GeoDataGroundOverlay();
301  EditGroundOverlayDialog *dialog = new EditGroundOverlayDialog( overlay, m_marbleWidget->textureLayer(), m_marbleWidget );
302  dialog->exec();
303 
304  m_marbleWidget->model()->treeModel()->addFeature( m_annotationDocument, overlay );
305 
306  emit overlayAdded();
307 }
308 
309 //void AnnotatePlugin::receiveNetworkReply( QNetworkReply *reply )
310 //{
311 // if( reply->error() == QNetworkReply::NoError ) {
312 // readOsmFile( reply, false );
313 // } else {
314 // m_errorMessage.showMessage( tr("Error while trying to download the "
315 // "OSM file from the server. The "
316 // "error was:\n %1" ).arg(reply->errorString()) );
317 // }
318 //}
319 
320 //void AnnotatePlugin::downloadOsmFile()
321 //{
322 // QPointF topLeft(0,0);
323 // QPointF bottomRight(m_marbleWidget->size().width(), m_marbleWidget->size().height());
324 
325 // qreal lonTop, latTop;
326 // qreal lonBottom, latBottom;
327 
328 // GeoDataCoordinates topLeftCoordinates;
329 // GeoDataCoordinates bottomRightCoordinates;
330 
331 // bool topIsOnGlobe = m_marbleWidget->geoCoordinates( topLeft.x(),
332 // topLeft.y(),
333 // lonTop, latTop,
334 // GeoDataCoordinates::Radian);
335 // bool bottomIsOnGlobe = m_marbleWidget->geoCoordinates( bottomRight.x(),
336 // bottomRight.y(),
337 // lonBottom, latBottom,
338 // GeoDataCoordinates::Radian );
339 
340 // if( ! ( topIsOnGlobe && bottomIsOnGlobe ) ) {
341 // m_errorMessage.showMessage( tr("One of the selection points is not on"
342 // " the Globe. Please only select a region"
343 // " on the globe.") );
344 // return;
345 // }
346 
347 // topLeftCoordinates = GeoDataCoordinates( lonTop, latTop, 0,
348 // GeoDataCoordinates::Radian );
349 
350 // bottomRightCoordinates = GeoDataCoordinates( lonBottom, latBottom, 0,
351 // GeoDataCoordinates::Radian );
352 
353 // GeoDataLineString tempString;
354 // tempString.append( topLeftCoordinates );
355 // tempString.append( bottomRightCoordinates );
356 
357 // GeoDataLatLonAltBox bounds = GeoDataLatLonAltBox::fromLineString( tempString );
358 
359 // QString request;
360 // request = QString("http://api.openstreetmap.org/api/0.6/map?bbox=%1,%2,%3,%4")
361 // .arg(bounds.west(GeoDataCoordinates::Degree) )
362 // .arg(bounds.south(GeoDataCoordinates::Degree) )
363 // .arg(bounds.east( GeoDataCoordinates::Degree) )
364 // .arg( bounds.north( GeoDataCoordinates::Degree ) );
365 
366 // QNetworkRequest networkRequest;
367 // networkRequest.setUrl(QUrl(request) );
368 
369 // if( ! m_networkAccessManager ) {
370 // m_networkAccessManager = new QNetworkAccessManager( this ) ;
371 // connect( m_networkAccessManager, SIGNAL(finished(QNetworkReply*)),
372 // this, SLOT(receiveNetworkReply(QNetworkReply*)) );
373 // }
374 
375 // m_networkAccessManager->get( networkRequest );
376 //}
377 
378 void AnnotatePlugin::clearAnnotations()
379 {
380 
381  const int result = QMessageBox::question( m_marbleWidget,
382  QObject::tr( "Clear all annotations" ),
383  QObject::tr( "Are you sure you want to clear all annotations?" ),
384  QMessageBox::Yes | QMessageBox::Cancel );
385 
386  if ( result == QMessageBox::Yes ) {
387  // It gets deleted three lines further, when calling qDeleteAll().
388  m_movedItem = 0;
389  delete m_polygonPlacemark;
390  m_polygonPlacemark = 0;
391 
392  qDeleteAll( m_graphicsItems );
393  m_graphicsItems.clear();
394  m_marbleWidget->model()->treeModel()->removeDocument( m_annotationDocument );
395  m_annotationDocument->clear();
396  m_marbleWidget->model()->treeModel()->addDocument( m_annotationDocument );
397  }
398 }
399 
400 void AnnotatePlugin::saveAnnotationFile()
401 {
402  QString const filename = QFileDialog::getSaveFileName( 0, tr("Save Annotation File"),
403  QString(), tr("All Supported Files (*.kml);;KML file (*.kml)"));
404  if ( !filename.isNull() ) {
405  GeoWriter writer;
406  //FIXME: a better way to do this?
407  writer.setDocumentType( kml::kmlTag_nameSpaceOgc22 );
408  QFile file( filename );
409  file.open( QIODevice::WriteOnly );
410  if ( !writer.write( &file, m_annotationDocument ) ) {
411  mDebug() << "Could not write the file " << filename;
412  }
413  file.close();
414  }
415 }
416 
417 void AnnotatePlugin::loadAnnotationFile()
418 {
419  QString const filename = QFileDialog::getOpenFileName(0, tr("Open Annotation File"),
420  QString(), tr("All Supported Files (*.kml);;Kml Annotation file (*.kml)"));
421 
422  if ( filename.isNull() ) {
423  return;
424  }
425 
426  QFile file( filename );
427  if ( !file.exists() ) {
428  mDebug() << "File " << filename << " does not exist!";
429  return;
430  }
431 
432  file.open( QIODevice::ReadOnly );
433  GeoDataParser parser( GeoData_KML );
434  if ( !parser.read( &file ) ) {
435  mDebug() << "Could not parse file " << filename;
436  return;
437  }
438 
439  GeoDataDocument *document = dynamic_cast<GeoDataDocument*>( parser.releaseDocument() );
440  Q_ASSERT( document );
441  file.close();
442 
443  foreach ( GeoDataFeature *feature, document->featureList() ) {
444  if ( feature->nodeType() == GeoDataTypes::GeoDataPlacemarkType ) {
445  GeoDataPlacemark *placemark = static_cast<GeoDataPlacemark*>( feature );
446 
447  if ( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPointType ) {
448  GeoDataPlacemark *newPlacemark = new GeoDataPlacemark( *placemark );
449  PlacemarkTextAnnotation *annotation = new PlacemarkTextAnnotation( newPlacemark );
450  m_graphicsItems.append( annotation );
451  m_marbleWidget->model()->treeModel()->addFeature( m_annotationDocument, newPlacemark );
452  } else if ( placemark->geometry()->nodeType() == GeoDataTypes::GeoDataPolygonType ) {
453  GeoDataPlacemark *newPlacemark = new GeoDataPlacemark( *placemark );
454  newPlacemark->setParent( m_annotationDocument );
455  newPlacemark->setStyleUrl( placemark->styleUrl() );
456  AreaAnnotation *annotation = new AreaAnnotation( newPlacemark );
457  m_graphicsItems.append( annotation );
458  m_marbleWidget->model()->treeModel()->addFeature( m_annotationDocument, newPlacemark );
459  }
460  }
461  }
462  m_marbleWidget->centerOn( document->latLonAltBox() );
463 
464  delete document;
465  emit repaintNeeded( QRegion() );
466 }
467 
468 bool AnnotatePlugin::eventFilter(QObject *watched, QEvent *event)
469 {
470  if ( !m_widgetInitialized ) {
471  MarbleWidget *marbleWidget = qobject_cast<MarbleWidget*>( watched );
472  if ( marbleWidget ) {
473  m_marbleWidget = marbleWidget;
474 
475  setupGroundOverlayModel();
476  setupOverlayRmbMenu();
477  setupPolygonRmbMenu();
478  setupNodeRmbMenu();
479  setupActions( marbleWidget );
480 
481  m_marbleWidget->model()->treeModel()->addDocument( m_annotationDocument );
482  m_widgetInitialized = true;
483 
484  return true;
485  }
486  return false;
487  }
488 
489  // So far only accept mouse events.
490  if ( event->type() != QEvent::MouseButtonPress &&
491  event->type() != QEvent::MouseButtonRelease &&
492  event->type() != QEvent::MouseMove ) {
493  return false;
494  }
495 
496  QMouseEvent *mouseEvent = dynamic_cast<QMouseEvent*>( event );
497  Q_ASSERT( mouseEvent );
498 
499  // Get the geocoordinates from mouse pos screen coordinates.
500  qreal lon, lat;
501  bool isOnGlobe = m_marbleWidget->geoCoordinates( mouseEvent->pos().x(),
502  mouseEvent->pos().y(),
503  lon, lat,
504  GeoDataCoordinates::Radian );
505  if ( !isOnGlobe ) {
506  if ( m_movedItem ) {
507  m_movedItem = 0;
508  return true;
509  }
510  return false;
511  }
512 
513  // Deal with adding placemarks and polygons;
514  if ( ( m_addingPlacemark && handleAddingPlacemark( mouseEvent ) ) ||
515  ( m_drawingPolygon && handleAddingPolygon( mouseEvent ) ) ) {
516  return true;
517  }
518 
519  // It is important to deal with Ground Overlay mouse release event here because it uses the
520  // texture layer in order to make the rendering more efficient.
521  if ( mouseEvent->type() == QEvent::MouseButtonRelease && m_groundOverlayModel.rowCount() ) {
522  handleReleaseOverlay( mouseEvent );
523  }
524 
525  // It is important to deal with the MouseMove event here because it changes the state of the selected
526  // item irrespective of the longitude/latitude the cursor moved to (excepting when it is outside the
527  // globe, which is treated above).
528  if ( mouseEvent->type() == QEvent::MouseMove && m_movedItem &&
529  handleMovingSelectedItem( mouseEvent ) ) {
530  return true;
531  }
532 
533 
534  // Pass the event to Graphic Items.
535  foreach ( SceneGraphicsItem *item, m_graphicsItems ) {
536  QListIterator<QRegion> it( item->regions() );
537 
538  while ( it.hasNext() ) {
539  QRegion region = it.next();
540  if ( !region.contains( mouseEvent->pos() ) )
541  continue;
542 
543  // The flow here is as it follows: first check if there is anything we may want to do
544  // before the item itself handles the event. For example, we don't want the item to handle
545  // the event when having selected "Removing item"; instead, we want to remove the item in
546  // this situation; the same applies for adding polygon holes, merging nodes and showing rmb
547  // menus so far. Then, if there is nothing to do before the item handles the event, let it
548  // handle the event.
549  if ( ( m_removingItem && handleRemovingItem( mouseEvent, item ) ) ||
550 
551  ( m_addingPolygonHole && handleAddingHole( mouseEvent, item ) ) ||
552 
553  ( m_mergingNodes && handleMergingNodes( mouseEvent, item ) ) ||
554 
555  ( handleShowingRmbMenus( mouseEvent, item ) ) ||
556 
557  ( mouseEvent->type() == QEvent::MouseButtonPress &&
558  handleMousePressEvent( mouseEvent, item ) ) ||
559 
560  ( mouseEvent->type() == QEvent::MouseButtonRelease &&
561  handleMouseReleaseEvent( mouseEvent, item ) ) ) {
562  return true;
563  }
564  }
565  }
566 
567  // If the event gets here, it most probably means it is a map interaction event, or something
568  // that has nothing to do with the annotate plugin items. We "deal" with this situation because,
569  // for example, we may need to deselect some selected items.
570  handleUncaughtEvents( mouseEvent );
571 
572  return false;
573 }
574 
575 bool AnnotatePlugin::handleAddingPlacemark( QMouseEvent *mouseEvent )
576 {
577  if ( mouseEvent->button() != Qt::LeftButton ) {
578  return false;
579  }
580 
581  qreal lon, lat;
582  m_marbleWidget->geoCoordinates( mouseEvent->pos().x(),
583  mouseEvent->pos().y(),
584  lon, lat,
585  GeoDataCoordinates::Radian );
586  const GeoDataCoordinates coords( lon, lat );
587 
588 
589  GeoDataPlacemark *placemark = new GeoDataPlacemark;
590  placemark->setCoordinate( coords );
591  m_marbleWidget->model()->treeModel()->addFeature( m_annotationDocument, placemark );
592 
593  PlacemarkTextAnnotation *textAnnotation = new PlacemarkTextAnnotation( placemark );
594  m_graphicsItems.append( textAnnotation );
595 
596  emit placemarkAdded();
597  return true;
598 }
599 
600 bool AnnotatePlugin::handleAddingPolygon( QMouseEvent *mouseEvent )
601 {
602  if ( mouseEvent->button() != Qt::LeftButton ||
603  mouseEvent->type() != QEvent::MouseButtonPress ) {
604  return false;
605  }
606 
607  qreal lon, lat;
608  m_marbleWidget->geoCoordinates( mouseEvent->pos().x(),
609  mouseEvent->pos().y(),
610  lon, lat,
611  GeoDataCoordinates::Radian );
612  const GeoDataCoordinates coords( lon, lat );
613 
614 
615  m_marbleWidget->model()->treeModel()->removeFeature( m_polygonPlacemark );
616  GeoDataPolygon *poly = dynamic_cast<GeoDataPolygon*>( m_polygonPlacemark->geometry() );
617  poly->outerBoundary().append( coords );
618  m_marbleWidget->model()->treeModel()->addFeature( m_annotationDocument, m_polygonPlacemark );
619 
620  return true;
621 }
622 
623 void AnnotatePlugin::handleReleaseOverlay( QMouseEvent *mouseEvent )
624 {
625  qreal lon, lat;
626  m_marbleWidget->geoCoordinates( mouseEvent->pos().x(),
627  mouseEvent->pos().y(),
628  lon, lat,
629  GeoDataCoordinates::Radian );
630  const GeoDataCoordinates coords( lon, lat );
631 
632  // Events caught by ground overlays at mouse release. So far we have: displaying the overlay frame
633  // (marking it as selected), removing it and showing a rmb menu with options.
634  for ( int i = 0; i < m_groundOverlayModel.rowCount(); ++i ) {
635  QModelIndex index = m_groundOverlayModel.index( i, 0 );
636  GeoDataGroundOverlay *overlay = dynamic_cast<GeoDataGroundOverlay*>(
637  qvariant_cast<GeoDataObject*>( index.data( MarblePlacemarkModel::ObjectPointerRole ) ) );
638 
639  if ( overlay->latLonBox().contains( coords ) ) {
640  if ( mouseEvent->button() == Qt::LeftButton ) {
641  if ( m_removingItem ) {
642  m_marbleWidget->model()->treeModel()->removeFeature( overlay );
643  emit itemRemoved();
644  } else {
645  displayOverlayFrame( overlay );
646  }
647  } else if ( mouseEvent->button() == Qt::RightButton ) {
648  showOverlayRmbMenu( overlay, mouseEvent->x(), mouseEvent->y() );
649  }
650  }
651  }
652 }
653 
654 bool AnnotatePlugin::handleMovingSelectedItem( QMouseEvent *mouseEvent )
655 {
656  // Handling easily the mouse move by calling for each scene graphic item their own mouseMoveEvent
657  // handler and updating the placemark geometry.
658  if ( m_movedItem->sceneEvent( mouseEvent ) ) {
659  m_marbleWidget->model()->treeModel()->updateFeature( m_movedItem->placemark() );
660  return true;
661  }
662 
663  return false;
664 }
665 
666 bool AnnotatePlugin::handleMousePressEvent( QMouseEvent *mouseEvent, SceneGraphicsItem *item )
667 {
668  // Return false if the item's mouse press event handler returns false.
669  if ( !item->sceneEvent( mouseEvent ) ) {
670  return false;
671  }
672 
673  // The item gets selected at each mouse press event.
674  m_movedItem = item;
675 
676  // For ground overlays, if the current item is not contained in m_groundOverlayFrames, clear
677  // all frames, which means the overlay gets deselected on each "extern" click.
678  if ( !m_groundOverlayFrames.values().contains( item ) ) {
679  clearOverlayFrames();
680  }
681 
682  m_marbleWidget->model()->treeModel()->updateFeature( item->placemark() );
683  return true;
684 }
685 
686 bool AnnotatePlugin::handleMouseReleaseEvent( QMouseEvent *mouseEvent, SceneGraphicsItem *item )
687 {
688  // Return false if the mouse release event handler of the item returns false.
689  if ( !item->sceneEvent( mouseEvent ) ) {
690  return false;
691  }
692 
693  // The moved item gets deselected at mouse release event.
694  m_movedItem = 0;
695 
696  m_marbleWidget->model()->treeModel()->updateFeature( item->placemark() );
697  return true;
698 }
699 
700 bool AnnotatePlugin::handleRemovingItem( QMouseEvent *mouseEvent, SceneGraphicsItem *item )
701 {
702  if ( mouseEvent->type() != QEvent::MouseButtonPress ||
703  mouseEvent->button() != Qt::LeftButton ) {
704  return false;
705  }
706 
707  const int result = QMessageBox::question( m_marbleWidget,
708  QObject::tr( "Remove current item" ),
709  QObject::tr( "Are you sure you want to remove the current item?" ),
710  QMessageBox::Yes | QMessageBox::No );
711 
712  if ( result == QMessageBox::Yes ) {
713  m_movedItem = 0;
714  m_graphicsItems.removeAll( item );
715  m_marbleWidget->model()->treeModel()->removeFeature( item->feature() );
716  delete item->feature();
717  delete item;
718  emit itemRemoved();
719  }
720 
721  return true;
722 }
723 
724 bool AnnotatePlugin::handleAddingHole( QMouseEvent *mouseEvent, SceneGraphicsItem *item )
725 {
726  // Ignore if it is not a LMB press or if someone by mistake clicks another scene graphic
727  // element while having checked "Add Polygon Hole".
728  if ( mouseEvent->type() != QEvent::MouseButtonPress ||
729  mouseEvent->button() != Qt::LeftButton ||
730  item->graphicType() != SceneGraphicTypes::SceneGraphicAreaAnnotation ) {
731  return false;
732  }
733 
734  qreal lon, lat;
735  m_marbleWidget->geoCoordinates( mouseEvent->pos().x(),
736  mouseEvent->pos().y(),
737  lon, lat,
738  GeoDataCoordinates::Radian );
739  const GeoDataCoordinates coords( lon, lat );
740 
741  // We can now be sure that the scene graphic item is an area annotation and its
742  // geometry is a polygon.
743  AreaAnnotation *area = static_cast<AreaAnnotation*>( item );
744  GeoDataPolygon *poly = dynamic_cast<GeoDataPolygon*>( item->placemark()->geometry() );
745  Q_ASSERT( area );
746  Q_ASSERT( poly );
747 
748  // If it is the first click in the interior of a polygon and the event position is not
749  // a hole of the polygon, we initialize the polygon on which we want to draw a hole.
750  if ( !m_holedPolygon && !area->isInnerBoundsPoint( mouseEvent->pos() ) ) {
751  m_holedPolygon = poly;
752  poly->innerBoundaries().append( GeoDataLinearRing( Tessellate ) );
753  } else if ( m_holedPolygon != poly || area->isInnerBoundsPoint( mouseEvent->pos() ) ) {
754  // Ignore clicks on other polygons if the polygon has already been initialized or
755  // if the event position is contained by one of the polygon's holes.
756  return false;
757  }
758  m_holedPolygon->innerBoundaries().last().append( coords );
759 
760  m_marbleWidget->model()->treeModel()->updateFeature( area->placemark() );
761  return true;
762 }
763 
764 bool AnnotatePlugin::handleMergingNodes( QMouseEvent *mouseEvent, SceneGraphicsItem *item )
765 {
766  if ( mouseEvent->type() != QEvent::MouseButtonPress ||
767  mouseEvent->button() != Qt::LeftButton ||
768  item->graphicType() != SceneGraphicTypes::SceneGraphicAreaAnnotation ) {
769  return false;
770  }
771 
772  // We can now be sure that the scene graphic item is an area annotation and its
773  // geometry is a polygon.
774  AreaAnnotation *area = static_cast<AreaAnnotation*>( item );
775  Q_ASSERT( area );
776 
777  if ( m_mergedArea != area && !area->isInnerBoundsPoint( mouseEvent->pos(), true ) ) {
778  // If the polygon has been initialized but it is different than the previously selected one,
779  // change the state of the older one to Normal and to MergingNodes to the new one. This makes
780  // possible merging nodes in different polygons without unchecking and checking again "Merge
781  // Nodes".
782  if ( m_mergedArea ) {
783  m_mergedArea->setState( AreaAnnotation::Normal );
784  }
785  area->setState( AreaAnnotation::MergingNodes );
786  m_mergedArea = area;
787  } else if ( area->isInnerBoundsPoint( mouseEvent->pos(), true ) ) {
788  // Ignore clicks on polygon's inner boundaries.
789  return false;
790  }
791 
792  // We can now be sure that mousePressEvent in AreaAnnotation will return true.
793  Q_ASSERT( area->sceneEvent( mouseEvent) );
794  QPair<int, int> &mergedNodes = area->mergedNodes();
795 
796  // Ignore event if the first node to be merged is set to -1. This means that actually no node
797  // has been clicked (so far this happens when clicking the interior of the polygon).
798  if ( mergedNodes.first == -1 ) {
799  return false;
800  }
801 
802  // If only one node has been clicked wait for the second one to be clicked.
803  if ( mergedNodes.second == -1 ) {
804  return true;
805  } else if ( mergedNodes.second == mergedNodes.first ) {
806  // Do not allow merging a node with itself. Without dealing with this case, the node got
807  // removed and maybe this is not one might want.
808  area->setMergedNodes( QPair<int, int>(-1, -1) );
809  return true;
810  }
811 
812  // Keep the two nodes sorted.
813  if ( mergedNodes.first > mergedNodes.second ) {
814  qSwap<int>( mergedNodes.first, mergedNodes.second );
815  }
816 
817  GeoDataPolygon *poly = dynamic_cast<GeoDataPolygon*>( area->placemark()->geometry() );
818  Q_ASSERT( poly );
819 
820  // Store the initial inner boundaries and outer boundary in case the polygon will have an invalid
821  // shape after merging two nodes.
822  GeoDataLinearRing initialOuterBoundary = poly->outerBoundary();
823  QVector<GeoDataLinearRing> initialInnerBoundaries = poly->innerBoundaries();
824 
825  GeoDataLinearRing &outer = poly->outerBoundary();
826  if ( ( mergedNodes.first >= outer.size() && mergedNodes.second < outer.size() ) ||
827  ( mergedNodes.first < outer.size() && mergedNodes.second >= outer.size() ) ) {
828  QMessageBox::warning( m_marbleWidget,
829  QString( "Operation not permitted"),
830  QString( "Cannot merge a node from polygon's outer boundary with"
831  " a node from one of its inner boundaries!" ) );
832  area->setMergedNodes( QPair<int, int>(-1, -1) );
833  // Made the user aware of the impossibility of merging those nodes and return true so that
834  // the event do not propagate.
835  return true;
836  }
837 
838  QList<int> &selectedNodes = m_mergedArea->selectedNodes();
839  int sizeOffset = 0;
840 
841  // If the selected nodes are part of one of the polygon's inner boundary.
842  if ( mergedNodes.first - outer.size() >= 0 && mergedNodes.second - outer.size() >= 0 ) {
843  QVector<GeoDataLinearRing> &inners = poly->innerBoundaries();
844 
845  mergedNodes.first -= outer.size();
846  mergedNodes.second -= outer.size();
847  sizeOffset += outer.size();
848 
849  // The merging is done by removing the first selected node and changing the coordinates
850  // of the second one.
851  for ( int i = 0; i < inners.size(); ++i ) {
852  if ( mergedNodes.first - inners.at(i).size() < 0 &&
853  mergedNodes.second - inners.at(i).size() < 0 ) {
854  inners[i].at(mergedNodes.second) = inners.at(i).at(mergedNodes.second).interpolate(
855  inners.at(i).at(mergedNodes.first), 0.5 );
856  inners[i].remove( mergedNodes.first );
857  // If this inner boundary has only two remaining nodes, remove it all.
858  if ( inners.at(i).size() <= 2 ) {
859  inners[i].clear();
860 
861  // Remove any of these three nodes (including the earlier removed one) from the
862  // selectedNodes list.
863  selectedNodes.removeAll( sizeOffset );
864  selectedNodes.removeAll( sizeOffset + 1 );
865  selectedNodes.removeAll( sizeOffset + 2 );
866 
867  // Decrement the indexes of selected nodes from other inner boundaries which have
868  // been drawn after this one.
869  QList<int>::iterator itBegin = selectedNodes.begin();
870  QList<int>::iterator itEnd = selectedNodes.end();
871 
872  for ( ; itBegin != itEnd; ++itBegin ) {
873  if ( *itBegin > sizeOffset + 2 ) {
874  *itBegin -= 3;
875  }
876  }
877 
878  area->setMergedNodes( QPair<int, int>(-1, -1) );
879  return true;
880  }
881 
882  break;
883  } else if ( mergedNodes.first - inners.at(i).size() < 0 ||
884  mergedNodes.second - inners.at(i).size() < 0 ) {
885  // Even though they are set to (-1, -1) below, before the warning takes the focus, the
886  // paint methods are called so we make sure the correct nodes are painted, so that the
887  // user knows which nodes he tried to merge.
888  mergedNodes.first += sizeOffset;
889  mergedNodes.second += sizeOffset;
890 
891  QMessageBox::warning( m_marbleWidget,
892  QString( "Operation not permitted"),
893  QString( "Cannot merge two nodes from two different"
894  " inner boundaries!") );
895  area->setMergedNodes( QPair<int, int>(-1, -1) );
896  return true;
897  } else {
898  mergedNodes.first -= inners.at(i).size();
899  mergedNodes.second -= inners.at(i).size();
900  sizeOffset += inners.at(i).size();
901  }
902  }
903  } else {
904  outer.at(mergedNodes.second) = outer.at(mergedNodes.second).interpolate(
905  outer.at(mergedNodes.first), 0.5 );
906  outer.remove( mergedNodes.first );
907 
908  // If the polygon's outer boundary has only two nodes remained after merging, remove it all.
909  if ( outer.size() <= 2 ) {
910  m_graphicsItems.removeAll( area );
911  m_marbleWidget->model()->treeModel()->removeFeature( area->feature() );
912  delete area->feature();
913  delete area;
914 
915  return true;
916  }
917 
918  // When merging two nodes from polygon's outer boundary, check if the polygon is still valid.
919  if ( !area->isValidPolygon() ) {
920  poly->outerBoundary() = initialOuterBoundary;
921  poly->innerBoundaries() = initialInnerBoundaries;
922 
923  QMessageBox::warning( m_marbleWidget,
924  QString( "Operation not permitted"),
925  QString( "The polygon would have an invalid shape after this"
926  " operation (e.g. its outerboundary would not contain"
927  " all its inner boundaries).") );
928  area->setMergedNodes( QPair<int, int>(-1, -1) );
929  return true;
930  }
931  }
932 
933 
934  // Reconstruct clicked nodes to resemble the indexes stored in selectedNodes list.
935  mergedNodes.first += sizeOffset;
936  mergedNodes.second += sizeOffset;
937 
938  // When having one of the two merged nodes marked as selected, the resulting node will also be
939  // selected.
940  if ( selectedNodes.contains( mergedNodes.first ) || selectedNodes.contains( mergedNodes.second ) ) {
941  selectedNodes.removeAll( mergedNodes.first );
942  selectedNodes.removeAll( mergedNodes.second );
943  selectedNodes.append( mergedNodes.second );
944  }
945 
946  QList<int>::iterator itBegin = selectedNodes.begin();
947  QList<int>::iterator itEnd = selectedNodes.end();
948 
949  // Decrement the indexes of the selected nodes which have bigger indexes than the
950  // node with a smaller index.
951  for ( ; itBegin != itEnd; ++itBegin ) {
952  if ( *itBegin > mergedNodes.first ) {
953  (*itBegin)--;
954  }
955  }
956 
957  area->setMergedNodes( QPair<int, int>(-1, -1) );
958  return true;
959 }
960 
961 bool AnnotatePlugin::handleShowingRmbMenus( QMouseEvent *mouseEvent, SceneGraphicsItem *item )
962 {
963  // We get here when mousePressEvent returns false.
964  if ( item->graphicType() != SceneGraphicTypes::SceneGraphicAreaAnnotation ||
965  mouseEvent->type() != QEvent::MouseButtonPress ||
966  mouseEvent->button() != Qt::RightButton ) {
967  return false;
968  }
969 
970  AreaAnnotation *area = static_cast<AreaAnnotation*>( item );
971  Q_ASSERT( area );
972 
973  // Call AreaAnnotation::mousePressEvent in order to get the node index which has been
974  // right-clicked.
975  area->sceneEvent( mouseEvent );
976 
977  if ( area->rightClickedNode() == -1 ) {
978  showPolygonRmbMenu( area, mouseEvent->x(), mouseEvent->y() );
979  } else if ( area->rightClickedNode() >= 0 ){
980  showNodeRmbMenu( area, mouseEvent->x(), mouseEvent->y() );
981  } else {
982  // If the region clicked is the interior of an innerBoundary of a polygon,
983  // we pass the event handling further. This guarantees that the events are
984  // caught by imbricated polygons irrespective of their number (e.g. we can
985  // have polygon within polygon within polygon, etc ).
986  Q_ASSERT( area->isInnerBoundsPoint( mouseEvent->pos() ) );
987  return false;
988  }
989 
990  m_marbleWidget->model()->treeModel()->updateFeature( area->placemark() );
991  return true;
992 }
993 
994 void AnnotatePlugin::handleUncaughtEvents( QMouseEvent *mouseEvent )
995 {
996  Q_UNUSED( mouseEvent );
997 
998  // If the event is not caught by any of the annotate plugin specific items, clear the frames
999  // (which have the meaning of deselecting the overlay).
1000  if ( !m_groundOverlayFrames.isEmpty() &&
1001  mouseEvent->type() != QEvent::MouseMove && mouseEvent->type() != QEvent::MouseButtonRelease ) {
1002  clearOverlayFrames();
1003  }
1004 }
1005 
1006 void AnnotatePlugin::setupActions(MarbleWidget *widget)
1007 {
1008  qDeleteAll( m_actions );
1009  m_actions.clear();
1010  m_toolbarActions.clear();
1011 
1012  if ( widget ) {
1013  QActionGroup *group = new QActionGroup( 0 );
1014  group->setExclusive( false );
1015 
1016  // QActionGroup *nonExclusiveGroup = new QActionGroup(0);
1017  // nonExclusiveGroup->setExclusive( false );
1018 
1019 
1020  QAction *enableInputAction = new QAction( this );
1021  enableInputAction->setText( tr("Enable Moving Map") );
1022  enableInputAction->setCheckable( true );
1023  enableInputAction->setChecked( true );
1024  enableInputAction->setIcon( QIcon( ":/icons/hand.png") );
1025  connect( enableInputAction, SIGNAL(toggled(bool)),
1026  widget, SLOT(setInputEnabled(bool)) );
1027 
1028  QAction *drawPolygon = new QAction( this );
1029  drawPolygon->setText( tr("Add Polygon") );
1030  drawPolygon->setCheckable( true );
1031  drawPolygon->setIcon( QIcon( ":/icons/draw-polygon.png") );
1032  connect( drawPolygon, SIGNAL(toggled(bool)),
1033  this, SLOT(setDrawingPolygon(bool)) );
1034 
1035  QAction *addHole = new QAction( this );
1036  addHole->setText( tr("Add Polygon Hole") );
1037  // TODO: set icon
1038  addHole->setCheckable( true );
1039  connect( addHole, SIGNAL(toggled(bool)),
1040  this, SLOT(setAddingPolygonHole(bool)) );
1041 
1042  QAction *mergeNodes = new QAction( this );
1043  mergeNodes->setText( tr("Merge Nodes") );
1044  // TODO: est icon
1045  mergeNodes->setCheckable( true );
1046  connect( mergeNodes, SIGNAL(toggled(bool)),
1047  this, SLOT(setMergingNodes(bool)) );
1048 
1049  QAction *addPlacemark= new QAction( this );
1050  addPlacemark->setText( tr("Add Placemark") );
1051  addPlacemark->setCheckable( true );
1052  addPlacemark->setIcon( QIcon( ":/icons/draw-placemark.png") );
1053  connect( addPlacemark, SIGNAL(toggled(bool)),
1054  this, SLOT(setAddingPlacemark(bool)) );
1055  connect( this, SIGNAL(placemarkAdded()) ,
1056  addPlacemark, SLOT(toggle()) );
1057 
1058  QAction *addOverlay = new QAction( this );
1059  addOverlay->setText( tr("Add Ground Overlay") );
1060  addOverlay->setCheckable( true );
1061  addOverlay->setIcon( QIcon( ":/icons/draw-overlay.png") );
1062  connect( addOverlay, SIGNAL(toggled(bool)),
1063  this, SLOT(setAddingOverlay(bool)) );
1064  connect( addOverlay, SIGNAL(toggled(bool)),
1065  this, SLOT(addOverlay()) );
1066  connect( this, SIGNAL(overlayAdded()),
1067  addOverlay, SLOT(toggle()) );
1068 
1069  QAction *removeItem = new QAction( this );
1070  removeItem->setText( tr("Remove Item") );
1071  removeItem->setCheckable( true );
1072  removeItem->setIcon( QIcon( ":/icons/edit-delete-shred.png") );
1073  connect( removeItem, SIGNAL(toggled(bool)),
1074  this, SLOT(setRemovingItems(bool)) );
1075  connect( this, SIGNAL(itemRemoved()),
1076  removeItem, SLOT(toggle()) );
1077 
1078  QAction *loadAnnotationFile = new QAction( this );
1079  loadAnnotationFile->setText( tr("Load Annotation File" ) );
1080  loadAnnotationFile->setIcon( QIcon( ":/icons/document-import.png") );
1081  connect( loadAnnotationFile, SIGNAL(triggered()),
1082  this, SLOT(loadAnnotationFile()) );
1083 
1084  QAction *saveAnnotationFile = new QAction( this );
1085  saveAnnotationFile->setText( tr("Save Annotation File") );
1086  saveAnnotationFile->setIcon( QIcon( ":/icons/document-export.png") );
1087  connect( saveAnnotationFile, SIGNAL(triggered()),
1088  this, SLOT(saveAnnotationFile()) );
1089 
1090  QAction *clearAnnotations = new QAction( this );
1091  clearAnnotations->setText( tr("Clear all Annotations") );
1092  clearAnnotations->setIcon( QIcon( ":/icons/remove.png") );
1093  connect( drawPolygon, SIGNAL(toggled(bool)),
1094  clearAnnotations, SLOT(setDisabled(bool)) );
1095  connect( clearAnnotations, SIGNAL(triggered()),
1096  this, SLOT(clearAnnotations()) );
1097 
1098  QAction *beginSeparator = new QAction( this );
1099  beginSeparator->setSeparator( true );
1100  QAction *polygonEndSeparator = new QAction( this );
1101  polygonEndSeparator->setSeparator( true );
1102  QAction *removeItemBeginSeparator = new QAction( this );
1103  removeItemBeginSeparator->setSeparator( true );
1104  QAction *removeItemEndSeparator = new QAction( this );
1105  removeItemEndSeparator->setSeparator( true );
1106  QAction *endSeparator = new QAction ( this );
1107  endSeparator->setSeparator( true );
1108 
1109 
1110  // QAction* downloadOsm = new QAction( this );
1111  // downloadOsm->setText( tr("Download Osm File") );
1112  // downloadOsm->setToolTip(tr("Download Osm File for selected area"));
1113  // connect( downloadOsm, SIGNAL(triggered()),
1114  // this, SLOT(downloadOsmFile()) );
1115 
1116 
1117  group->addAction( enableInputAction );
1118  group->addAction( beginSeparator );
1119  group->addAction( drawPolygon );
1120  group->addAction( addHole );
1121  group->addAction( mergeNodes );
1122  group->addAction( polygonEndSeparator );
1123  group->addAction( addPlacemark );
1124  group->addAction( addOverlay );
1125  group->addAction( removeItemBeginSeparator );
1126  group->addAction( removeItem );
1127  group->addAction( removeItemEndSeparator );
1128  group->addAction( loadAnnotationFile );
1129  group->addAction( saveAnnotationFile );
1130  group->addAction( clearAnnotations );
1131  group->addAction( endSeparator );
1132 
1133  // nonExclusiveGroup->addAction( downloadOsm );
1134 
1135  m_actions.append( group );
1136  // m_actions.append( nonExclusiveGroup );
1137 
1138  m_toolbarActions.append( group );
1139  // m_toolbarActions.append( nonExclusiveGroup );
1140  }
1141 
1142  emit actionGroupsChanged();
1143 }
1144 
1145 void AnnotatePlugin::setupGroundOverlayModel()
1146 {
1147  m_groundOverlayModel.setSourceModel( m_marbleWidget->model()->groundOverlayModel() );
1148  m_groundOverlayModel.setDynamicSortFilter( true );
1149  m_groundOverlayModel.setSortRole( MarblePlacemarkModel::PopularityIndexRole );
1150  m_groundOverlayModel.sort( 0, Qt::AscendingOrder );
1151 }
1152 
1153 void AnnotatePlugin::setupOverlayRmbMenu()
1154 {
1155  QAction *removeOverlay = new QAction( tr( "Remove Ground Overlay" ), m_overlayRmbMenu );
1156  QAction *editOverlay = new QAction( tr( "Edit Ground Overlay" ), m_overlayRmbMenu );
1157 
1158  m_overlayRmbMenu->addAction( editOverlay );
1159  m_overlayRmbMenu->addAction( removeOverlay );
1160 
1161  connect( editOverlay, SIGNAL(triggered()), this, SLOT(editOverlay()) );
1162  connect( removeOverlay, SIGNAL(triggered()), this, SLOT(removeOverlay()) );
1163 }
1164 
1165 void AnnotatePlugin::showOverlayRmbMenu( GeoDataGroundOverlay *overlay, qreal x, qreal y )
1166 {
1167  m_rmbOverlay = overlay;
1168  m_overlayRmbMenu->popup( m_marbleWidget->mapToGlobal( QPoint( x, y ) ) );
1169 }
1170 
1171 void AnnotatePlugin::editOverlay()
1172 {
1173  displayOverlayFrame( m_rmbOverlay );
1174  displayOverlayEditDialog( m_rmbOverlay );
1175 }
1176 
1177 void AnnotatePlugin::removeOverlay()
1178 {
1179  m_marbleWidget->model()->treeModel()->removeFeature( m_rmbOverlay );
1180  clearOverlayFrames();
1181 }
1182 
1183 void AnnotatePlugin::displayOverlayFrame( GeoDataGroundOverlay *overlay )
1184 {
1185  if ( !m_groundOverlayFrames.keys().contains( overlay ) ) {
1186 
1187  GeoDataPlacemark *rectangle_placemark = new GeoDataPlacemark;
1188  rectangle_placemark->setGeometry( new GeoDataPolygon );
1189  rectangle_placemark->setParent( m_annotationDocument );
1190  rectangle_placemark->setStyleUrl( "#polygon" );
1191 
1192  m_marbleWidget->model()->treeModel()->addFeature( m_annotationDocument, rectangle_placemark );
1193 
1194  GroundOverlayFrame *frame = new GroundOverlayFrame( rectangle_placemark, overlay, m_marbleWidget->textureLayer() );
1195  m_graphicsItems.append( frame );
1196  m_groundOverlayFrames.insert( overlay, frame );
1197  }
1198 }
1199 
1200 void AnnotatePlugin::displayOverlayEditDialog( GeoDataGroundOverlay *overlay )
1201 {
1202  QPointer<EditGroundOverlayDialog> dialog = new EditGroundOverlayDialog(
1203  overlay,
1204  m_marbleWidget->textureLayer(),
1205  m_marbleWidget );
1206 
1207  connect( dialog, SIGNAL(groundOverlayUpdated(GeoDataGroundOverlay*)),
1208  this, SLOT(updateOverlayFrame(GeoDataGroundOverlay*)) );
1209 
1210  dialog->exec();
1211  delete dialog;
1212 }
1213 
1214 
1215 void AnnotatePlugin::updateOverlayFrame( GeoDataGroundOverlay *overlay )
1216 {
1217  GroundOverlayFrame *frame = static_cast<GroundOverlayFrame *>( m_groundOverlayFrames.value( overlay ) );
1218  if ( frame ) {
1219  frame->update();
1220  }
1221 }
1222 
1223 void AnnotatePlugin::clearOverlayFrames()
1224 {
1225 
1226  foreach ( GeoDataGroundOverlay *overlay, m_groundOverlayFrames.keys() ) {
1227  GroundOverlayFrame *frame = static_cast<GroundOverlayFrame *>( m_groundOverlayFrames.value( overlay ) );
1228  m_graphicsItems.removeAll( m_groundOverlayFrames.value( overlay ) );
1229  m_marbleWidget->model()->treeModel()->removeFeature( frame->placemark() );
1230  delete frame->placemark();
1231  delete frame;
1232  }
1233 
1234  m_groundOverlayFrames.clear();
1235 }
1236 
1237 
1238 void AnnotatePlugin::setupPolygonRmbMenu()
1239 {
1240  QAction *unselectNodes = new QAction( tr( "Deselect All Nodes" ), m_polygonRmbMenu );
1241  m_polygonRmbMenu->addAction( unselectNodes );
1242  connect( unselectNodes, SIGNAL(triggered()), this, SLOT(unselectNodes()) );
1243 
1244  QAction *deleteAllSelected = new QAction( tr( "Delete All Selected Nodes" ), m_polygonRmbMenu );
1245  m_polygonRmbMenu->addAction( deleteAllSelected );
1246  connect( deleteAllSelected, SIGNAL(triggered()), this, SLOT(deleteSelectedNodes()) );
1247 
1248  QAction *removePolygon = new QAction( tr( "Remove Polygon" ), m_polygonRmbMenu );
1249  m_polygonRmbMenu->addAction( removePolygon );
1250  connect( removePolygon, SIGNAL(triggered()), this, SLOT(removePolygon()) );
1251 
1252  m_polygonRmbMenu->addSeparator();
1253 
1254  QAction *showEditDialog = new QAction( tr( "Properties" ), m_polygonRmbMenu );
1255  m_polygonRmbMenu->addAction( showEditDialog );
1256  connect( showEditDialog, SIGNAL(triggered()), this, SLOT(editPolygon()) );
1257 }
1258 
1259 
1260 void AnnotatePlugin::showPolygonRmbMenu( AreaAnnotation *selectedArea, qreal x, qreal y )
1261 {
1262  m_rmbSelectedArea = selectedArea;
1263 
1264  if ( selectedArea->selectedNodes().isEmpty() ) {
1265  m_polygonRmbMenu->actions().at(1)->setEnabled( false );
1266  m_polygonRmbMenu->actions().at(0)->setEnabled( false );
1267  } else {
1268  m_polygonRmbMenu->actions().at(1)->setEnabled( true );
1269  m_polygonRmbMenu->actions().at(0)->setEnabled( true );
1270  }
1271 
1272  m_polygonRmbMenu->popup( m_marbleWidget->mapToGlobal( QPoint( x, y ) ) );
1273 }
1274 
1275 
1276 void AnnotatePlugin::unselectNodes()
1277 {
1278  m_rmbSelectedArea->selectedNodes().clear();
1279 }
1280 
1281 void AnnotatePlugin::deleteSelectedNodes()
1282 {
1283  QList<int> &selectedNodes = m_rmbSelectedArea->selectedNodes();
1284 
1285  // If there are no selected nodes, exit the function.
1286  if ( !selectedNodes.size() ) {
1287  return;
1288  }
1289 
1290  GeoDataPolygon *poly = dynamic_cast<GeoDataPolygon*>( m_rmbSelectedArea->placemark()->geometry() );
1291  // Copy the current polygon's inner boundaries and outer boundary, to be able to recover them
1292  // if the deletion fails (the polygon becomes invalid after deleting the selected nodes).
1293  QVector<GeoDataLinearRing> innerBounds = poly->innerBoundaries();
1294  GeoDataLinearRing outerBound = poly->outerBoundary();
1295 
1296  // Sorting and iterating through the list of selected nodes backwards is important because when
1297  // caling {outerBoundary,innerBoundary[i]}.remove, the indexes of the selected nodes bigger than
1298  // the removed one's (in one step of the iteration) should be all decremented due to the way
1299  // QVector::remove works.
1300  // Sorting and iterating backwards is, therefore, faster than iterating through the list and at
1301  // each iteration, iterate one more time through the list in order to decrement the above
1302  // mentioned nodes (O(N * logN) < O(N ^ 2) in terms of complexity).
1303  qSort( selectedNodes.begin(), selectedNodes.end() );
1304 
1305  QListIterator<int> it( selectedNodes );
1306  it.toBack();
1307 
1308  // Deal with removing the selected nodes from the polygon's inner boundaries.
1309  while ( it.hasPrevious() ) {
1310  int nodeIndex = it.previous();
1311 
1312  if ( nodeIndex < poly->outerBoundary().size() ) {
1313  it.next();
1314  break;
1315  }
1316 
1317  nodeIndex -= poly->outerBoundary().size();
1318  for ( int i = 0; i < poly->innerBoundaries().size(); ++i ) {
1319  if ( nodeIndex - poly->innerBoundaries().at(i).size() < 0 ) {
1320  poly->innerBoundaries()[i].remove( nodeIndex );
1321  break;
1322  } else {
1323  nodeIndex -= poly->innerBoundaries().at(i).size();
1324  }
1325  }
1326  }
1327  // If one of the polygon's inner boundaries has 0, 1 or 2 nodes remained after
1328  // removing the selected ones, remove this entire inner boundary.
1329  for ( int i = 0; i < poly->innerBoundaries().size(); ++i ) {
1330  if ( poly->innerBoundaries().at(i).size() <= 2 ) {
1331  poly->innerBoundaries()[i].clear();
1332  }
1333  }
1334 
1335 
1336 
1337  // Deal with removing the selected nodes from the polygon's outer boundaries.
1338  while ( it.hasPrevious() ) {
1339  poly->outerBoundary().remove( it.previous() );
1340  }
1341 
1342  // If the number of nodes remained after deleting the selected ones is 0, 1 or 2, we remove the
1343  // entire polygon.
1344  if ( poly->outerBoundary().size() <= 2 ) {
1345  selectedNodes.clear();
1346 
1347  m_graphicsItems.removeAll( m_rmbSelectedArea );
1348  m_marbleWidget->model()->treeModel()->removeFeature( m_rmbSelectedArea->feature() );
1349  delete m_rmbSelectedArea->feature();
1350  delete m_rmbSelectedArea;
1351 
1352  return;
1353  }
1354 
1355  // If the polygon is no longer valid (e.g. its outer boundary ring itersects one of its inner
1356  // boundaries ring), recover it to the last valid shape and popup a warning.
1357  if ( !m_rmbSelectedArea->isValidPolygon() ) {
1358  poly->innerBoundaries() = innerBounds;
1359  poly->outerBoundary() = outerBound;
1360 
1361  QMessageBox::warning( m_marbleWidget,
1362  QString( "Operation not permitted" ),
1363  QString( "Cannot delete the selected nodes" ) );
1364  } else {
1365  selectedNodes.clear();
1366  }
1367 }
1368 
1369 void AnnotatePlugin::removePolygon()
1370 {
1371  m_graphicsItems.removeAll( m_rmbSelectedArea );
1372  m_marbleWidget->model()->treeModel()->removeFeature( m_rmbSelectedArea->feature() );
1373  delete m_rmbSelectedArea->feature();
1374  delete m_rmbSelectedArea;
1375 }
1376 
1377 void AnnotatePlugin::editPolygon()
1378 {
1379  displayPolygonEditDialog( m_rmbSelectedArea->placemark() );
1380 }
1381 
1382 void AnnotatePlugin::displayPolygonEditDialog( GeoDataPlacemark *placemark )
1383 {
1384  EditPolygonDialog *dialog = new EditPolygonDialog( placemark, m_marbleWidget );
1385 
1386  connect( dialog, SIGNAL(polygonUpdated(GeoDataFeature*)),
1387  this, SIGNAL(repaintNeeded()) );
1388  connect( dialog, SIGNAL(polygonUpdated(GeoDataFeature*)),
1389  m_marbleWidget->model()->treeModel(), SLOT(updateFeature(GeoDataFeature*)) );
1390 
1391  dialog->show();
1392 }
1393 
1394 void AnnotatePlugin::setupNodeRmbMenu()
1395 {
1396  QAction *selectNode = new QAction( tr( "Select Node" ), m_nodeRmbMenu );
1397  QAction *deleteNode = new QAction( tr( "Delete Node" ), m_nodeRmbMenu );
1398 
1399  m_nodeRmbMenu->addAction( selectNode );
1400  m_nodeRmbMenu->addAction( deleteNode );
1401 
1402  connect( selectNode, SIGNAL(triggered()), this, SLOT(selectNode()) );
1403  connect( deleteNode, SIGNAL(triggered()), this, SLOT(deleteNode()) );
1404 }
1405 
1406 void AnnotatePlugin::showNodeRmbMenu( AreaAnnotation *area, qreal x, qreal y )
1407 {
1408  // Check whether the node is already selected; we change the text of the
1409  // action accordingly.
1410  if ( area->selectedNodes().contains( area->rightClickedNode() ) ) {
1411  m_nodeRmbMenu->actions().at(0)->setText( tr("Deselect Node") );
1412  } else {
1413  m_nodeRmbMenu->actions().at(0)->setText( tr("Select Node") );
1414  }
1415 
1416  m_rmbSelectedArea = area;
1417  m_nodeRmbMenu->popup( m_marbleWidget->mapToGlobal( QPoint( x, y ) ) );
1418 }
1419 
1420 void AnnotatePlugin::selectNode()
1421 {
1422  if ( m_rmbSelectedArea->selectedNodes().contains( m_rmbSelectedArea->rightClickedNode() ) ) {
1423  m_rmbSelectedArea->selectedNodes().removeAll( m_rmbSelectedArea->rightClickedNode() );
1424  } else {
1425  m_rmbSelectedArea->selectedNodes().append( m_rmbSelectedArea->rightClickedNode() );
1426  }
1427 }
1428 
1429 
1430 void AnnotatePlugin::deleteNode()
1431 {
1432  GeoDataPolygon *poly = dynamic_cast<GeoDataPolygon*>( m_rmbSelectedArea->placemark()->geometry() );
1433 
1434  // Copy the current polygon's inner boundaries and outer boundary, to be able to recover them
1435  // if the deletion fails (the polygon becomes invalid after deleting the selected nodes).
1436  QVector<GeoDataLinearRing> innerBounds = poly->innerBoundaries();
1437  GeoDataLinearRing outerBound = poly->outerBoundary();
1438 
1439  int index = m_rmbSelectedArea->rightClickedNode();
1440 
1441  // If the right clicked node is one of those nodes which form one of the inner boundaries
1442  // of the polygon.
1443  if ( index - poly->outerBoundary().size() >= 0 ) {
1444  QVector<GeoDataLinearRing> &innerRings = poly->innerBoundaries();
1445 
1446  index -= poly->outerBoundary().size();
1447  for ( int i = 0; i < innerRings.size(); ++i ) {
1448  // If we've found the inner boundary it is a part of, we remove it; also, if the
1449  // linear ring has only 2 nodes remained after deletion, we remove the entire
1450  // inner boundary.
1451  if ( index - innerRings.at(i).size() < 0 ) {
1452  innerRings[i].remove( index );
1453  if ( innerRings.at(i).size() <= 2 ) {
1454  innerRings[i].clear();
1455  }
1456 
1457  break;
1458  } else {
1459  index -= innerRings.at(i).size();
1460  }
1461  }
1462  } else {
1463  poly->outerBoundary().remove( index );
1464 
1465  // If the polygon has only 2 nodes, we remove it all.
1466  if ( poly->outerBoundary().size() <= 2 ) {
1467  m_rmbSelectedArea->selectedNodes().clear();
1468 
1469  m_graphicsItems.removeAll( m_rmbSelectedArea );
1470  m_marbleWidget->model()->treeModel()->removeFeature( m_rmbSelectedArea->feature() );
1471  delete m_rmbSelectedArea->feature();
1472  delete m_rmbSelectedArea;
1473 
1474  return;
1475  }
1476  }
1477 
1478  // If the polygon is no longer valid (e.g. its outer boundary ring itersects one of its inner
1479  // boundaries ring), recover it to the last valid shape and popup a warning.
1480  if ( !m_rmbSelectedArea->isValidPolygon() ) {
1481  poly->innerBoundaries() = innerBounds;
1482  poly->outerBoundary() = outerBound;
1483 
1484  QMessageBox::warning( m_marbleWidget,
1485  QString( "Operation not permitted"),
1486  QString( "Cannot delete the selected node" ) );
1487 
1488  return;
1489  }
1490 
1491  // If the node is selected, remove it from the selected list of nodes as well.
1492  m_rmbSelectedArea->selectedNodes().removeAll( m_rmbSelectedArea->rightClickedNode() );
1493 
1494  QList<int>::iterator itBegin = m_rmbSelectedArea->selectedNodes().begin();
1495  QList<int>::iterator itEnd = m_rmbSelectedArea->selectedNodes().end();
1496 
1497  // Decrement the indexes of the selected nodes which have bigger indexes than the
1498  // removed one's.
1499  for ( ; itBegin != itEnd; ++itBegin ) {
1500  if ( *itBegin > m_rmbSelectedArea->rightClickedNode() ) {
1501  (*itBegin)--;
1502  }
1503  }
1504 }
1505 
1506 //void AnnotatePlugin::readOsmFile( QIODevice *device, bool flyToFile )
1507 //{
1508 //}
1509 
1510 }
1511 
1512 Q_EXPORT_PLUGIN2( AnnotatePlugin, Marble::AnnotatePlugin )
1513 
1514 #include "AnnotatePlugin.moc"
QSortFilterProxyModel::index
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const
QAction::setText
void setText(const QString &text)
GeoDataDocument.h
Marble::AnnotatePlugin::name
QString name() const
Returns the user-visible name of the plugin.
Definition: AnnotatePlugin.cpp:116
QList::clear
void clear()
QModelIndex
QSortFilterProxyModel::setSortRole
void setSortRole(int role)
Marble::AnnotatePlugin::overlayAdded
void overlayAdded()
Marble::AreaAnnotation::Normal
Definition: AreaAnnotation.h:30
Marble::AnnotatePlugin::~AnnotatePlugin
virtual ~AnnotatePlugin()
Definition: AnnotatePlugin.cpp:91
Marble::AnnotatePlugin::itemRemoved
void itemRemoved()
QEvent
Marble::GeoDataLineString::setTessellate
void setTessellate(bool tessellate)
Sets the tessellation property for the LineString.
Definition: GeoDataLineString.cpp:320
Marble::GeoDataGeometry::nodeType
virtual const char * nodeType() const
Provides type information for downcasting a GeoData.
Definition: GeoDataGeometry.cpp:77
SceneGraphicsTypes.h
AnnotatePlugin.h
QEvent::type
Type type() const
Marble::GeoDataCoordinates::Radian
Definition: GeoDataCoordinates.h:65
Marble::GeoDataTreeModel::addFeature
int addFeature(GeoDataContainer *parent, GeoDataFeature *feature, int row=-1)
Definition: GeoDataTreeModel.cpp:792
Marble::GeoDataDocument
A container for Features, Styles and in the future Schemas.
Definition: GeoDataDocument.h:65
Marble::GeoDataTypes::GeoDataPointType
const char * GeoDataPointType
Definition: GeoDataTypes.cpp:68
EditPolygonDialog.h
Marble::GeoDataParser
Definition: GeoDataParser.h:40
QAction::setSeparator
void setSeparator(bool b)
Marble::AnnotatePlugin::isInitialized
bool isInitialized() const
Definition: AnnotatePlugin.cpp:177
Marble::GeoDataDocument::setDocumentRole
void setDocumentRole(DocumentRole role)
Definition: GeoDataDocument.cpp:86
QActionGroup
QListIterator::next
const T & next()
QSortFilterProxyModel::sort
virtual void sort(int column, Qt::SortOrder order)
GeoDataGroundOverlay.h
Marble::AnnotatePlugin::nameId
QString nameId() const
Returns the unique name of the plugin.
Definition: AnnotatePlugin.cpp:126
Marble::GeoDataTypes::GeoDataPolygonType
const char * GeoDataPolygonType
Definition: GeoDataTypes.cpp:69
Marble::RenderPlugin::repaintNeeded
void repaintNeeded(QRegion dirtyRegion=QRegion())
This signal is emitted if an update of the view is needed.
Marble::MarbleModel::treeModel
GeoDataTreeModel * treeModel()
Return the list of Placemarks as a QAbstractItemModel *.
Definition: MarbleModel.cpp:477
QSortFilterProxyModel::setSourceModel
virtual void setSourceModel(QAbstractItemModel *sourceModel)
Marble::GeoPainter
A painter that allows to draw geometric primitives on the map.
Definition: GeoPainter.h:98
QAction::setChecked
void setChecked(bool)
MarbleModel.h
This file contains the headers for MarbleModel.
Marble::AnnotatePlugin::pluginAuthors
QList< PluginAuthor > pluginAuthors() const
Definition: AnnotatePlugin.cpp:146
QMouseEvent::x
int x() const
QMouseEvent::y
int y() const
Marble::EditGroundOverlayDialog
Definition: EditGroundOverlayDialog.h:22
QAction::setIcon
void setIcon(const QIcon &icon)
QList::at
const T & at(int i) const
Marble::GeoDataColorStyle::setColor
void setColor(const QColor &value)
Set a new color.
Definition: GeoDataColorStyle.cpp:84
Marble::PluginAuthor
Definition: PluginInterface.h:28
QMenu::addAction
void addAction(QAction *action)
Marble::GeoDataTypes::GeoDataPlacemarkType
const char * GeoDataPlacemarkType
Definition: GeoDataTypes.cpp:66
QPointer
Marble::AreaAnnotation::selectedNodes
QList< int > & selectedNodes()
Returns the list of selected node indexes.
Definition: AreaAnnotation.cpp:320
Marble::GeoDataTreeModel::removeFeature
bool removeFeature(GeoDataContainer *parent, int index)
Definition: GeoDataTreeModel.cpp:826
GeoDataStyle.h
QWidget::mapToGlobal
QPoint mapToGlobal(const QPoint &pos) const
Marble::AnnotatePlugin::setAddingOverlay
void setAddingOverlay(bool)
Definition: AnnotatePlugin.cpp:273
QDialog::exec
int exec()
Marble::GeoGraphicsItem::feature
const GeoDataFeature * feature() const
Returns the placemark for that item.
Definition: GeoGraphicsItem.cpp:62
QActionGroup::addAction
QAction * addAction(QAction *action)
Marble::AreaAnnotation::rightClickedNode
int rightClickedNode() const
Returns the node index on which the mouse press event (with the right button) has been caught...
Definition: AreaAnnotation.cpp:325
Marble::AnnotatePlugin::loadAnnotationFile
void loadAnnotationFile()
Definition: AnnotatePlugin.cpp:417
GeoDataParser.h
Marble::AreaAnnotation::MergingNodes
Definition: AreaAnnotation.h:31
QPoint
QVector::first
T & first()
QMouseEvent
Marble::GeoDataFeature::styleUrl
QString styleUrl() const
Return the styleUrl of the feature.
Definition: GeoDataFeature.cpp:626
QFile::exists
bool exists() const
Marble::MarblePlacemarkModel::ObjectPointerRole
The pointer to a specific object.
Definition: MarblePlacemarkModel.h:62
MarbleDebug.h
QObject::tr
QString tr(const char *sourceText, const char *disambiguation, int n)
Marble::GeoDataTreeModel::addDocument
int addDocument(GeoDataDocument *document)
Definition: GeoDataTreeModel.cpp:821
QFile
QWidget::update
void update()
AbstractProjection.h
This file contains the headers for AbstractProjection.
QSortFilterProxyModel::rowCount
virtual int rowCount(const QModelIndex &parent) const
QPoint::x
int x() const
QPoint::y
int y() const
QList::size
int size() const
GeoWriter.h
QString::isNull
bool isNull() const
Marble::GeoDataPlacemark::geometry
GeoDataGeometry * geometry()
The geometry of the GeoDataPlacemark is to be rendered to the marble map along with the icon at the c...
Definition: GeoDataPlacemark.cpp:152
Marble::MarbleWidget
A widget class that displays a view of the earth.
Definition: MarbleWidget.h:104
QObject::event
virtual bool event(QEvent *e)
Marble::GeoData_KML
Definition: GeoDataParser.h:36
Marble::GeoDataObject::setParent
virtual void setParent(GeoDataObject *parent)
Sets the parent of the object.
Definition: GeoDataObject.cpp:70
Marble::RenderPlugin::actionGroupsChanged
void actionGroupsChanged()
This signal is emitted if the actions that the plugin supports change in any way. ...
MarbleWidgetInputHandler.h
Marble::AnnotatePlugin::actionGroups
virtual const QList< QActionGroup * > * actionGroups() const
Getting all actions.
Definition: AnnotatePlugin.cpp:187
Marble::SceneGraphicsItem::sceneEvent
bool sceneEvent(QEvent *event)
This function is used to call the event distributer and makes use of the re-implemented virtual funct...
Definition: SceneGraphicsItem.cpp:51
QVector::clear
void clear()
TextureLayer.h
Marble::GeoDataStyle
an addressable style group
Definition: GeoDataStyle.h:55
Marble::AnnotatePlugin::placemarkAdded
void placemarkAdded()
Marble::AnnotatePlugin::setRemovingItems
void setRemovingItems(bool)
Definition: AnnotatePlugin.cpp:289
QList::append
void append(const T &value)
Marble::AnnotatePlugin
This class specifies the Marble layer interface of a plugin which annotates maps with polygons and pl...
Definition: AnnotatePlugin.h:49
Marble::GeoSceneLayer
Layer of a GeoScene document.
Definition: GeoSceneLayer.h:43
EditGroundOverlayDialog.h
Marble::GeoParser::read
bool read(QIODevice *)
Main API for reading the XML document.
Definition: GeoParser.cpp:74
QMenu::popup
void popup(const QPoint &p, QAction *atAction)
Marble::GeoDataFeature::setName
void setName(const QString &value)
Set a new name for this feature.
Definition: GeoDataFeature.cpp:549
QMessageBox::question
StandardButton question(QWidget *parent, const QString &title, const QString &text, QFlags< QMessageBox::StandardButton > buttons, StandardButton defaultButton)
KmlElementDictionary.h
Marble::GeoDataTreeModel::removeDocument
void removeDocument(int index)
Definition: GeoDataTreeModel.cpp:872
QObject
QMouseEvent::button
Qt::MouseButton button() const
Marble::AnnotatePlugin::setDrawingPolygon
void setDrawingPolygon(bool)
Definition: AnnotatePlugin.cpp:230
Marble::AreaAnnotation
Definition: AreaAnnotation.h:24
Marble::SceneGraphicsItem
This is the base class for all scene graphics included within the annotate plugin.
Definition: SceneGraphicsItem.h:34
Marble::MarbleWidget::model
MarbleModel * model()
Return the model that this view shows.
Definition: MarbleWidget.cpp:289
Marble::UserDocument
Definition: GeoDataDocument.h:42
Marble::RenderPlugin::visibilityChanged
void visibilityChanged(bool visible, const QString &nameId)
This signal is emitted if the visibility is changed with.
Marble::GeoDataPolygon
A polygon that can have "holes".
Definition: GeoDataPolygon.h:81
Marble::AnnotatePlugin::eventFilter
bool eventFilter(QObject *watched, QEvent *event)
Definition: AnnotatePlugin.cpp:468
MarbleDirs.h
QList::removeAll
int removeAll(const T &value)
QVector::remove
void remove(int i)
Marble::GeoWriter
Standard Marble way of writing XML This class is intended to be a standardised way of writing XML for...
Definition: GeoWriter.h:29
Marble::AnnotatePlugin::render
bool render(GeoPainter *painter, ViewportParams *viewport, const QString &renderPos, GeoSceneLayer *layer=0)
Renders the content provided by the layer on the viewport.
Definition: AnnotatePlugin.cpp:197
QSortFilterProxyModel::setDynamicSortFilter
void setDynamicSortFilter(bool enable)
Marble::GeoDataDocument::addStyle
void addStyle(const GeoDataStyle &style)
Add a style to the style storage.
Definition: GeoDataDocument.cpp:134
Marble::AreaAnnotation::setState
void setState(ActionState state)
Sets the state of the object.
Definition: AreaAnnotation.cpp:305
Marble::GeoDataContainer::size
int size() const
size of the container
Definition: GeoDataContainer.cpp:286
QList::first
T & first()
Marble::RenderPlugin::setVisible
void setVisible(bool visible)
settting visible
Definition: RenderPlugin.cpp:151
QMenu::addSeparator
QAction * addSeparator()
QString
QList
Marble::AnnotatePlugin::renderPolicy
QString renderPolicy() const
Return how the plugin settings should be used.
Definition: AnnotatePlugin.cpp:106
MarblePlacemarkModel.h
QColor
GeoPainter.h
Marble::AnnotatePlugin::renderPosition
QStringList renderPosition() const
Preferred level in the layer stack for the rendering.
Definition: AnnotatePlugin.cpp:111
Marble::GeoDataContainer::latLonAltBox
GeoDataLatLonAltBox latLonAltBox() const
A convenience function that returns the LatLonAltBox of all placemarks in this container.
Definition: GeoDataContainer.cpp:160
Marble::GeoDataTreeModel::updateFeature
void updateFeature(GeoDataFeature *feature)
Definition: GeoDataTreeModel.cpp:864
GeoDataPlacemark.h
QFile::open
virtual bool open(QFlags< QIODevice::OpenModeFlag > mode)
GeoDataTreeModel.h
Marble::GeoDataPolygon::outerBoundary
GeoDataLinearRing & outerBoundary()
Returns the outer boundary that is represented as a LinearRing.
Definition: GeoDataPolygon.cpp:123
QStringList
Marble::ViewportParams
A public class that controls what is visible in the viewport of a Marble map.
Definition: ViewportParams.h:44
QPair< int, int >
Marble::AnnotatePlugin::clearAnnotations
void clearAnnotations()
Definition: AnnotatePlugin.cpp:378
QRegion::contains
bool contains(const QPoint &p) const
Q_EXPORT_PLUGIN2
#define Q_EXPORT_PLUGIN2(a, b)
Definition: marble_export.h:34
Marble::GeoDataFeature::setStyleUrl
void setStyleUrl(const QString &value)
Set the styleUrl of this feature to value.
Definition: GeoDataFeature.cpp:631
Marble::MarbleWidget::textureLayer
TextureLayer * textureLayer() const
Definition: MarbleWidget.cpp:380
Marble::kml::kmlTag_nameSpaceOgc22
const char * kmlTag_nameSpaceOgc22
Definition: KmlElementDictionary.cpp:34
Marble::AnnotatePlugin::copyrightYears
QString copyrightYears() const
Definition: AnnotatePlugin.cpp:141
QList::end
iterator end()
QMenu
Marble::MarbleWidget::centerOn
void centerOn(const qreal lon, const qreal lat, bool animated=false)
Center the view on a geographical point.
Definition: MarbleWidget.cpp:549
Marble::AnnotatePlugin::description
QString description() const
Returns a user description of the plugin.
Definition: AnnotatePlugin.cpp:131
Marble::GeoWriter::setDocumentType
void setDocumentType(const QString &documentType)
Set the current document type.
Definition: GeoWriter.cpp:79
QList::contains
bool contains(const T &value) const
Marble::AnnotatePlugin::setAddingPlacemark
void setAddingPlacemark(bool)
Definition: AnnotatePlugin.cpp:225
QFile::close
virtual void close()
QAction::setCheckable
void setCheckable(bool)
Marble::MarblePlacemarkModel::PopularityIndexRole
The popularity index.
Definition: MarblePlacemarkModel.h:60
GeoDataLatLonBox.h
Marble::AnnotatePlugin::initialize
void initialize()
Definition: AnnotatePlugin.cpp:159
Marble::PlacemarkTextAnnotation
Definition: PlacemarkTextAnnotation.h:23
QVector::at
const T & at(int i) const
Marble::AnnotatePlugin::addOverlay
void addOverlay()
Definition: AnnotatePlugin.cpp:294
Marble::MarbleModel
The data model (not based on QAbstractModel) for a MarbleWidget.
Definition: MarbleModel.h:97
Marble::SceneGraphicsItem::regions
QList< QRegion > regions() const
Returns the list of regions which form the scene graphic element.
Definition: SceneGraphicsItem.cpp:31
Marble::SceneGraphicTypes::SceneGraphicAreaAnnotation
const char * SceneGraphicAreaAnnotation
Definition: SceneGraphicsTypes.cpp:20
Marble::MarbleModel::groundOverlayModel
QAbstractItemModel * groundOverlayModel()
Definition: MarbleModel.cpp:497
Marble::GeoDataPolygon::innerBoundaries
QVector< GeoDataLinearRing > & innerBoundaries()
Returns a set of inner boundaries which are represented as LinearRings.
Definition: GeoDataPolygon.cpp:139
Marble::RenderPlugin::setEnabled
void setEnabled(bool enabled)
settting enabled
Definition: RenderPlugin.cpp:139
QVector
Marble::GeoDataObject::setId
void setId(const QString &value)
Set the id of the object.
Definition: GeoDataObject.cpp:80
Marble::GeoDataLineString::isEmpty
bool isEmpty() const
Returns whether the LineString has no nodes at all.
Definition: GeoDataLineString.cpp:133
QModelIndex::data
QVariant data(int role) const
Marble::AnnotatePlugin::backendTypes
QStringList backendTypes() const
Returns the name(s) of the backend that the plugin can render This method should return the name of t...
Definition: AnnotatePlugin.cpp:101
Marble::GeoDataFeature
A base class for all geodata features.
Definition: GeoDataFeature.h:57
Marble::GeoDataContainer::featureList
QVector< GeoDataFeature * > featureList() const
A convenience function that returns all features in this container.
Definition: GeoDataContainer.cpp:231
Marble::AnnotatePlugin::setAddingPolygonHole
void setAddingPolygonHole(bool)
Definition: AnnotatePlugin.cpp:259
Marble::MarbleWidget::geoCoordinates
bool geoCoordinates(int x, int y, qreal &lon, qreal &lat, GeoDataCoordinates::Unit=GeoDataCoordinates::Degree) const
Get the earth coordinates corresponding to a pixel in the widget.
Definition: MarbleWidget.cpp:668
QAction
Marble::AnnotatePlugin::toolbarActionGroups
virtual const QList< QActionGroup * > * toolbarActionGroups() const
Getting all actions which should be placed in the toolbar.
Definition: AnnotatePlugin.cpp:192
Marble::AnnotatePlugin::enableModel
void enableModel(bool enabled)
Definition: AnnotatePlugin.cpp:210
Marble::AnnotatePlugin::setMergingNodes
void setMergingNodes(bool)
Definition: AnnotatePlugin.cpp:278
QFileDialog::getSaveFileName
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFlags< QFileDialog::Option > options)
Marble::AnnotatePlugin::icon
QIcon icon() const
Returns an icon for the plugin.
Definition: AnnotatePlugin.cpp:153
Marble::AnnotatePlugin::saveAnnotationFile
void saveAnnotationFile()
Definition: AnnotatePlugin.cpp:400
Marble::GeoDataGroundOverlay
Definition: GeoDataGroundOverlay.h:24
Marble::SceneGraphicsItem::placemark
const GeoDataPlacemark * placemark() const
SceneGraphicItem class, when called from one of its derived classes' constructors, takes as a parameter a pointer to the placemark of the graphic element.
Definition: SceneGraphicsItem.cpp:41
Marble::AnnotatePlugin::AnnotatePlugin
AnnotatePlugin(const MarbleModel *model=0)
Definition: AnnotatePlugin.cpp:56
MarbleWidget.h
This file contains the headers for MarbleWidget.
QMessageBox::warning
StandardButton warning(QWidget *parent, const QString &title, const QString &text, QFlags< QMessageBox::StandardButton > buttons, StandardButton defaultButton)
QListIterator
Marble::RenderPlugin::enabled
bool enabled() const
is enabled
Marble::GeoWriter::write
bool write(QIODevice *device, const GeoNode *feature)
The main API call to use the XML writer.
Definition: GeoWriter.cpp:28
QMouseEvent::pos
const QPoint & pos() const
PlacemarkTextAnnotation.h
QFileDialog::getOpenFileName
QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFlags< QFileDialog::Option > options)
MarbleWidget
Wraps a Marble::MarbleWidget, providing access to important properties and methods.
Definition: MarbleDeclarativeWidget.h:50
GeoDataTypes.h
Marble::AnnotatePlugin::runtimeTrace
virtual QString runtimeTrace() const
Returns a debug line for perfo/tracing issues.
Definition: AnnotatePlugin.cpp:182
Marble::AreaAnnotation::isValidPolygon
bool isValidPolygon() const
Checks if the polygon has a valid shape; an invalid shape would be, for example, if one of its inner ...
Definition: AreaAnnotation.cpp:353
Marble::AnnotatePlugin::version
QString version() const
Definition: AnnotatePlugin.cpp:136
Marble::Tessellate
Definition: MarbleGlobal.h:32
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QWidget::actions
QList< QAction * > actions() const
QVector::size
int size() const
Marble::GeoDataPolyStyle
specifies the style how polygons are drawn
Definition: GeoDataPolyStyle.h:34
QActionGroup::setExclusive
void setExclusive(bool)
Marble::GeoDataFeature::nodeType
virtual const char * nodeType() const
Provides type information for downcasting a GeoData.
Definition: GeoDataFeature.cpp:158
QString::arg
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
Marble::GeoDataPlacemark
a class representing a point of interest on the map
Definition: GeoDataPlacemark.h:54
Marble::mDebug
QDebug mDebug()
a function to replace qDebug() in Marble library code
Definition: MarbleDebug.cpp:36
Marble::GeoDataStyle::setPolyStyle
void setPolyStyle(const GeoDataPolyStyle &style)
set the poly style
Definition: GeoDataStyle.cpp:117
Marble::RenderPlugin
The abstract class that creates a renderable item.
Definition: RenderPlugin.h:43
QList::begin
iterator begin()
QRegion
QIcon
Marble::GeoDataContainer::clear
void clear()
Definition: GeoDataContainer.cpp:324
Marble::AnnotatePlugin::guiString
QString guiString() const
String that should be displayed in GUI.
Definition: AnnotatePlugin.cpp:121
Marble::GeoParser::releaseDocument
GeoDocument * releaseDocument()
retrieve the parsed document and reset the parser If parsing was successful, retrieve the resulting d...
Definition: GeoParser.cpp:205
Marble::GeoDataPlacemark::setGeometry
void setGeometry(GeoDataGeometry *entry)
Sets the current Geometry of this Placemark.
Definition: GeoDataPlacemark.cpp:230
QListIterator::hasNext
bool hasNext() const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:13:38 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

marble

Skip menu "marble"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdeedu API Reference

Skip menu "kdeedu API Reference"
  • Analitza
  •     lib
  • kalgebra
  • kalzium
  •   libscience
  • kanagram
  • kig
  •   lib
  • klettres
  • marble
  • parley
  • rocs
  •   App
  •   RocsCore
  •   VisualEditor
  •   stepcore

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal