diff --git a/src/apps/marble-ui/icons/download.png b/src/apps/marble-ui/icons/download.png
new file mode 100644
index 000000000..e81619b1b
Binary files /dev/null and b/src/apps/marble-ui/icons/download.png differ
diff --git a/src/apps/marble-ui/marble.qrc b/src/apps/marble-ui/marble.qrc
index bceda2acb..ba6b1147e 100644
--- a/src/apps/marble-ui/marble.qrc
+++ b/src/apps/marble-ui/marble.qrc
@@ -1,118 +1,119 @@
icons/route-guidance.png
icons/application-exit.png
icons/arrow-down.png
icons/arrow-left.png
icons/arrow-right.png
icons/arrow-up.png
icons/bookmarks.png
icons/bookmarks-organize.png
icons/bookmark-add-folder.png
icons/bookmark-edit.png
icons/bookmark-new.png
icons/bookmark-remove.png
icons/document-open.png
icons/document-print.png
icons/document-save-as.png
icons/edit-copy.png
icons/folder-bookmark.png
icons/format-text-bold.png
icons/format-text-italic.png
icons/format-text-underline.png
icons/go-home.png
icons/go-home-large.png
icons/get-hot-new-stuff.png
icons/help-about.png
icons/help-contents.png
icons/help-whatsthis.png
icons/insert-image.png
icons/insert-link.png
icons/map-flat.png
icons/map-globe.png
icons/map-mercator.png
icons/marble.png
icons/settings-configure.png
icons/user-online.png
icons/user-offline.png
icons/view-fullscreen.png
icons/view-sidetree.png
icons/view-refresh.png
icons/wikipedia.png
icons/zoom-in.png
icons/zoom-out.png
icons/zoom-in-large.png
icons/zoom-out-large.png
icons/clock.png
icons/clock-large.png
icons/instruction-near.png
icons/instruction-next.png
icons/gps.png
icons/compass.png
icons/worldmap.png
icons/scalebar.png
icons/navigation.png
icons/crosshairs.png
icons/elevationprofile.png
icons/add-placemark.png
icons/draw-path.png
icons/polygon-add-nodes.png
icons/polygon-draw-hole.png
icons/polygon-merge-nodes.png
icons/open-for-editing.png
icons/16x16/task-accepted.png
icons/16x16/document-open.png
icons/16x16/document-save.png
icons/16x16/task-attention.png
icons/16x16/edit-find.png
icons/16x16/configure.png
icons/16x16/edit-clear-list.png
icons/16x16/edit-clear-locationbar-ltr.png
icons/16x16/edit-clear-locationbar-rtl.png
icons/22x22/edit-clear-locationbar-ltr.png
icons/22x22/edit-clear-locationbar-rtl.png
icons/32x32/edit-clear-locationbar-ltr.png
icons/32x32/edit-clear-locationbar-rtl.png
../../../data/editors/potlatch.png
../../../data/editors/merkaartor.png
../../../data/editors/josm.png
icons/aprs.png
icons/lock.png
icons/routeplanning.png
icons/social.png
icons/unlock.png
icons/photo.png
icons/postalcode.png
icons/license.png
icons/earthquake.png
icons/speedometer.png
icons/places.png
icons/document-print-preview.png
icons/create-new-map.png
icons/edit-map.png
icons/measure.png
icons/addressbook-details.png
icons/coordinate.png
icons/positionmarker.png
icons/stars.png
icons/clouds.png
icons/atmosphere.png
icons/copy-coordinates.png
icons/cache.png
icons/plugin.png
icons/transform-move.png
icons/document-export.png
icons/document-import.png
icons/edit-delete-shred.png
icons/hand.png
icons/draw-placemark.png
icons/draw-polygon.png
icons/remove.png
icons/draw-overlay.png
icons/cloud-upload.png
icons/cloud-download.png
icons/16x16/tool-animator.png
icons/map-gnomonic.png
icons/edit-select.png
+ icons/download.png
diff --git a/src/plugins/render/annotate/AnnotatePlugin.cpp b/src/plugins/render/annotate/AnnotatePlugin.cpp
index 6cd14f7a2..64b4423e8 100644
--- a/src/plugins/render/annotate/AnnotatePlugin.cpp
+++ b/src/plugins/render/annotate/AnnotatePlugin.cpp
@@ -1,1769 +1,1792 @@
//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2009 Andrew Manson
// Copyright 2013 Thibaut Gridel
// Copyright 2014 Calin Cruceru
//
// Self
#include "AnnotatePlugin.h"
// Qt
#include
#include
#include
#include
#include
#include
// Marble
#include "MarbleDebug.h"
#include "EditGroundOverlayDialog.h"
#include "EditPlacemarkDialog.h"
#include "EditPolygonDialog.h"
#include "GeoDataDocument.h"
#include "GeoDataGroundOverlay.h"
#include "GeoDataLatLonBox.h"
#include "GeoDataParser.h"
#include "GeoDataPlacemark.h"
#include "GeoDataStyle.h"
#include "GeoDataLabelStyle.h"
#include "GeoDataLineStyle.h"
#include "GeoDataPoint.h"
#include "GeoDataPolyStyle.h"
#include "GeoDataTreeModel.h"
#include "GeoPainter.h"
#include "GeoDataLatLonAltBox.h"
#include "GeoDataLinearRing.h"
#include "GeoDataPolygon.h"
#include "GeoWriter.h"
#include "KmlElementDictionary.h"
#include "MarbleDirs.h"
#include "MarbleModel.h"
#include "MarblePlacemarkModel.h"
#include "MarbleWidget.h"
#include "AreaAnnotation.h"
#include "PlacemarkTextAnnotation.h"
#include "TextureLayer.h"
#include "SceneGraphicsTypes.h"
#include "MergingPolygonNodesAnimation.h"
#include "MergingPolylineNodesAnimation.h"
#include "MarbleWidgetPopupMenu.h"
#include "PolylineAnnotation.h"
#include "EditPolylineDialog.h"
#include "ParsingRunnerManager.h"
#include "ViewportParams.h"
#include "osm/OsmPlacemarkData.h"
+#include "DownloadOsmDialog.h"
namespace Marble
{
AnnotatePlugin::AnnotatePlugin( const MarbleModel *model )
: RenderPlugin( model ),
m_isInitialized( false ),
m_widgetInitialized( false ),
m_marbleWidget( 0 ),
m_overlayRmbMenu(nullptr),
m_polygonRmbMenu(nullptr),
m_nodeRmbMenu(nullptr),
m_textAnnotationRmbMenu(nullptr),
m_polylineRmbMenu(nullptr),
m_annotationDocument(nullptr),
m_movedItem( 0 ),
m_focusItem( 0 ),
m_polylinePlacemark( 0 ),
m_polygonPlacemark( 0 ),
m_clipboardItem( 0 ),
m_drawingPolygon( false ),
m_drawingPolyline( false ),
m_addingPlacemark( false ),
m_editingDialogIsShown( false )
{
setEnabled( true );
setVisible( true );
connect( this, SIGNAL(visibilityChanged(bool,QString)), SLOT(enableModel(bool)) );
}
AnnotatePlugin::~AnnotatePlugin()
{
qDeleteAll( m_graphicsItems );
if ( m_marbleWidget ) {
m_marbleWidget->model()->treeModel()->removeDocument( m_annotationDocument );
}
delete m_overlayRmbMenu;
delete m_polygonRmbMenu;
delete m_nodeRmbMenu;
delete m_textAnnotationRmbMenu;
delete m_polylineRmbMenu;
delete m_annotationDocument;
// delete m_networkAccessManager;
delete m_clipboardItem;
qDeleteAll(m_actions);
disconnect( this, SIGNAL(mouseMoveGeoPosition(QString)), m_marbleWidget, SIGNAL(mouseMoveGeoPosition(QString)) );
}
QStringList AnnotatePlugin::backendTypes() const
{
return QStringList(QStringLiteral("annotation"));
}
QString AnnotatePlugin::renderPolicy() const
{
return QStringLiteral("ALWAYS");
}
QStringList AnnotatePlugin::renderPosition() const
{
return QStringList(QStringLiteral("ALWAYS_ON_TOP"));
}
QString AnnotatePlugin::name() const
{
return tr( "Annotation" );
}
QString AnnotatePlugin::guiString() const
{
return tr( "&Annotation" );
}
QString AnnotatePlugin::nameId() const
{
return QStringLiteral("annotation");
}
QString AnnotatePlugin::description() const
{
return tr( "Draws annotations on maps with placemarks or polygons." );
}
QString AnnotatePlugin::version() const
{
return QStringLiteral("1.0");
}
QString AnnotatePlugin::copyrightYears() const
{
return QStringLiteral("2009, 2013");
}
QVector AnnotatePlugin::pluginAuthors() const
{
return QVector()
<< PluginAuthor(QStringLiteral("Andrew Manson"), QStringLiteral("g.real.ate@gmail.com"))
<< PluginAuthor(QStringLiteral("Thibaut Gridel"), QStringLiteral("tgridel@free.fr"))
<< PluginAuthor(QStringLiteral("Calin Cruceru"), QStringLiteral("crucerucalincristian@gmail.com"));
}
QIcon AnnotatePlugin::icon() const
{
return QIcon(QStringLiteral(":/icons/draw-placemark.png"));
}
void AnnotatePlugin::initialize()
{
if ( !m_isInitialized ) {
m_widgetInitialized = false;
delete m_polygonPlacemark;
m_polygonPlacemark = 0;
delete m_movedItem;
m_movedItem = 0;
m_drawingPolygon = false;
m_drawingPolyline = false;
m_addingPlacemark = false;
delete m_annotationDocument;
m_annotationDocument = new GeoDataDocument;
m_annotationDocument->setName( tr("Annotations") );
m_annotationDocument->setDocumentRole( UserDocument );
// Default polygon style
GeoDataStyle::Ptr defaultPolygonStyle(new GeoDataStyle);
GeoDataPolyStyle polyStyle;
GeoDataLineStyle edgeStyle;
GeoDataLabelStyle labelStyle;
QColor polygonColor = QApplication::palette().highlight().color();
QColor edgeColor = QApplication::palette().light().color();
QColor labelColor = QApplication::palette().brightText().color();
polygonColor.setAlpha( 80 );
polyStyle.setColor( polygonColor );
edgeStyle.setColor( edgeColor );
labelStyle.setColor( labelColor );
defaultPolygonStyle->setId(QStringLiteral("polygon"));
defaultPolygonStyle->setPolyStyle( polyStyle );
defaultPolygonStyle->setLineStyle( edgeStyle );
defaultPolygonStyle->setLabelStyle( labelStyle );
m_annotationDocument->addStyle( defaultPolygonStyle );
// Default polyline style
GeoDataStyle::Ptr defaultPolylineStyle(new GeoDataStyle);
GeoDataLineStyle lineStyle;
QColor polylineColor = Qt::white;
lineStyle.setColor( polylineColor );
lineStyle.setWidth( 1 );
defaultPolylineStyle->setId(QStringLiteral("polyline"));
defaultPolylineStyle->setLineStyle( lineStyle );
defaultPolylineStyle->setLabelStyle( labelStyle );
m_annotationDocument->addStyle( defaultPolylineStyle );
m_isInitialized = true;
}
}
bool AnnotatePlugin::isInitialized() const
{
return m_isInitialized;
}
QString AnnotatePlugin::runtimeTrace() const
{
return QStringLiteral("Annotate Items: %1").arg(m_annotationDocument->size());
}
const QList *AnnotatePlugin::actionGroups() const
{
return &m_actions;
}
bool AnnotatePlugin::render(GeoPainter *painter, ViewportParams *viewport, const QString &renderPos, GeoSceneLayer *layer)
{
Q_UNUSED( renderPos );
Q_UNUSED( layer );
QListIterator iter( m_graphicsItems );
while ( iter.hasNext() ) {
iter.next()->paint( painter, viewport, "Annotation", -1 );
}
return true;
}
void AnnotatePlugin::enableModel( bool enabled )
{
if ( enabled ) {
if ( m_marbleWidget ) {
setupActions( m_marbleWidget );
m_marbleWidget->model()->treeModel()->addDocument( m_annotationDocument );
}
} else {
setupActions( 0 );
if ( m_marbleWidget ) {
m_marbleWidget->model()->treeModel()->removeDocument( m_annotationDocument );
}
}
}
void AnnotatePlugin::setAddingPolygonHole( bool enabled )
{
if ( enabled ) {
announceStateChanged( SceneGraphicsItem::AddingPolygonHole );
} else {
announceStateChanged( SceneGraphicsItem::Editing );
}
}
void AnnotatePlugin::setAddingNodes( bool enabled )
{
if ( enabled ) {
announceStateChanged( SceneGraphicsItem::AddingNodes );
} else {
announceStateChanged( SceneGraphicsItem::Editing );
}
}
void AnnotatePlugin::setAreaAvailable()
{
static_cast( m_focusItem )->setBusy( false );
announceStateChanged( SceneGraphicsItem::Editing );
enableAllActions( m_actions.first() );
disableFocusActions();
enableActionsOnItemType( SceneGraphicsTypes::SceneGraphicAreaAnnotation );
emit repaintNeeded();
}
void AnnotatePlugin::setPolylineAvailable()
{
static_cast( m_focusItem )->setBusy( false );
announceStateChanged( SceneGraphicsItem::Editing );
enableAllActions( m_actions.first() );
disableFocusActions();
enableActionsOnItemType( SceneGraphicsTypes::SceneGraphicPolylineAnnotation );
emit repaintNeeded();
}
void AnnotatePlugin::askToRemoveFocusItem()
{
const int result = QMessageBox::question( m_marbleWidget,
QObject::tr( "Remove current item" ),
QObject::tr( "Are you sure you want to remove the current item?" ),
QMessageBox::Yes | QMessageBox::No );
if ( result == QMessageBox::Yes ) {
removeFocusItem();
}
}
void AnnotatePlugin::removeFocusItem()
{
// Ground Overlays will always be a special case..
if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicGroundOverlay ) {
for ( int i = 0; i < m_groundOverlayModel.rowCount(); ++i ) {
const QModelIndex index = m_groundOverlayModel.index( i, 0 );
GeoDataGroundOverlay *overlay = dynamic_cast(
qvariant_cast( index.data( MarblePlacemarkModel::ObjectPointerRole ) ) );
m_marbleWidget->model()->treeModel()->removeFeature( overlay );
}
clearOverlayFrames();
} else {
disableFocusActions();
m_graphicsItems.removeAll( m_focusItem );
m_marbleWidget->model()->treeModel()->removeFeature( m_focusItem->placemark() );
delete m_focusItem->placemark();
delete m_focusItem;
m_movedItem = 0;
m_focusItem = 0;
}
}
void AnnotatePlugin::clearAnnotations()
{
const int result = QMessageBox::question( m_marbleWidget,
QObject::tr( "Clear all annotations" ),
QObject::tr( "Are you sure you want to clear all annotations?" ),
QMessageBox::Yes | QMessageBox::Cancel );
if ( result == QMessageBox::Yes ) {
disableFocusActions();
qDeleteAll( m_graphicsItems );
m_graphicsItems.clear();
m_marbleWidget->model()->treeModel()->removeDocument( m_annotationDocument );
m_annotationDocument->clear();
m_marbleWidget->model()->treeModel()->addDocument( m_annotationDocument );
m_movedItem = 0;
m_focusItem = 0;
}
}
void AnnotatePlugin::saveAnnotationFile()
{
const QString filename = QFileDialog::getSaveFileName( 0,
tr("Save Annotation File"),
QString(),
tr("All Supported Files (*.kml *.osm);;"
"KML file (*.kml);;"
"Open Street Map file (*.osm)") );
if ( !filename.isNull() ) {
GeoWriter writer;
// FIXME: This should be consistent with the way the loading is done.
if (filename.endsWith(QLatin1String(".kml"), Qt::CaseInsensitive)) {
writer.setDocumentType( kml::kmlTag_nameSpaceOgc22 );
}
else if (filename.endsWith(QLatin1String(".osm"), Qt::CaseInsensitive)) {
// "0.6" is the current version of osm, it is used to identify the osm writer
// The reference value is kept in plugins/runner/osm/OsmElementDictionary.hz
writer.setDocumentType( "0.6" );
}
QFile file( filename );
file.open( QIODevice::WriteOnly );
if ( !writer.write( &file, m_annotationDocument ) ) {
mDebug() << "Could not write the file " << filename;
}
file.close();
}
}
void AnnotatePlugin::loadAnnotationFile()
{
const QString filename = QFileDialog::getOpenFileName( 0,
tr("Open Annotation File"),
QString(),
tr("All Supported Files (*.kml *.osm);;"
"Kml Annotation file (*.kml);;"
"Open Street Map file (*.osm)") );
if ( filename.isNull() ) {
return;
}
+ else{
+ openAnnotationFile(filename);
+ }
+}
+
+void AnnotatePlugin::downloadOsm()
+{
+ QPointer dialog=new DownloadOsmDialog(m_marbleWidget,this);
+ dialog->show();
+}
- ParsingRunnerManager manager( m_marbleWidget->model()->pluginManager() );
- GeoDataDocument *document = manager.openFile( filename );
+void AnnotatePlugin::openAnnotationFile(const QString& filename)
+{
+
+ if ( filename.isNull() ) {
+ return;
+ }
+ ParsingRunnerManager manager( m_marbleWidget->model()->pluginManager(),this );
+ GeoDataDocument *document = manager.openFile( filename);
Q_ASSERT( document );
// FIXME: The same problem as in the case of copying/cutting graphic items applies here:
// the files do not load properly because the geometry copy is not a deep copy.
- for ( GeoDataFeature *feature: document->featureList() ) {
+ foreach ( GeoDataFeature *feature, document->featureList() ) {
if (const GeoDataPlacemark *placemark = geodata_cast(feature)) {
GeoDataPlacemark *newPlacemark = new GeoDataPlacemark( *placemark );
if (geodata_cast(placemark->geometry())) {
PlacemarkTextAnnotation *placemark = new PlacemarkTextAnnotation( newPlacemark );
m_graphicsItems.append( placemark );
} else if (geodata_cast(placemark->geometry())) {
newPlacemark->setParent( m_annotationDocument );
if ( !placemark->styleUrl().isEmpty() ) {
newPlacemark->setStyleUrl( placemark->styleUrl() );
}
AreaAnnotation *polygonAnnotation = new AreaAnnotation( newPlacemark );
m_graphicsItems.append( polygonAnnotation );
} else if (geodata_cast(placemark->geometry())) {
newPlacemark->setParent( m_annotationDocument );
if ( !placemark->styleUrl().isEmpty() ) {
newPlacemark->setStyleUrl( placemark->styleUrl() );
}
PolylineAnnotation *polylineAnnotation = new PolylineAnnotation( newPlacemark );
m_graphicsItems.append( polylineAnnotation );
}
m_marbleWidget->model()->treeModel()->addFeature( m_annotationDocument, newPlacemark );
} else if (const GeoDataGroundOverlay *overlay = geodata_cast(feature)) {
GeoDataGroundOverlay *newOverlay = new GeoDataGroundOverlay( *overlay );
m_marbleWidget->model()->treeModel()->addFeature( m_annotationDocument, newOverlay );
displayOverlayFrame( newOverlay );
}
}
m_marbleWidget->centerOn( document->latLonAltBox() );
delete document;
emit repaintNeeded( QRegion() );
}
bool AnnotatePlugin::eventFilter( QObject *watched, QEvent *event )
{
if ( !m_widgetInitialized ) {
MarbleWidget *marbleWidget = qobject_cast( watched );
if ( marbleWidget ) {
m_marbleWidget = marbleWidget;
addContextItems();
setupGroundOverlayModel();
setupOverlayRmbMenu();
setupPolygonRmbMenu();
setupPolylineRmbMenu();
setupNodeRmbMenu();
setupTextAnnotationRmbMenu();
setupActions( marbleWidget );
m_marbleWidget->model()->treeModel()->addDocument( m_annotationDocument );
m_widgetInitialized = true;
connect( this, SIGNAL(mouseMoveGeoPosition(QString)), m_marbleWidget, SIGNAL(mouseMoveGeoPosition(QString)) );
return true;
}
return false;
}
// Accept mouse and key press events.
if ( event->type() != QEvent::MouseButtonPress &&
event->type() != QEvent::MouseButtonRelease &&
event->type() != QEvent::MouseMove &&
event->type() != QEvent::KeyPress &&
event->type() != QEvent::KeyRelease ) {
return false;
}
// Handle key press events.
if ( event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease ) {
QKeyEvent * const keyEvent = static_cast( event );
Q_ASSERT( keyEvent );
if ( m_focusItem &&
( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicAreaAnnotation ||
m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicPolylineAnnotation ) ) {
if ( keyEvent->type() == QEvent::KeyPress && keyEvent->key() == Qt::Key_Control ) {
announceStateChanged( SceneGraphicsItem::MergingNodes );
}
if ( keyEvent->type() == QEvent::KeyRelease && keyEvent->key() == Qt::Key_Control ) {
if ( ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicAreaAnnotation &&
static_cast( m_focusItem )->isBusy() ) ||
( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicPolylineAnnotation &&
static_cast( m_focusItem )->isBusy() ) ) {
return true;
}
announceStateChanged( SceneGraphicsItem::Editing );
}
}
// If we have an item which has the focus and the Escape key is pressed, set item's focus
// to false.
if ( m_focusItem &&
keyEvent->type() == QEvent::KeyPress && keyEvent->key() == Qt::Key_Escape &&
!m_editingDialogIsShown ) {
disableFocusActions();
m_focusItem->setFocus( false );
m_marbleWidget->model()->treeModel()->updateFeature( m_focusItem->placemark() );
m_focusItem = 0;
return true;
}
// If we have an item which has the focus and the Delete key is pressed, delete the item
if ( m_focusItem && keyEvent->type() == QEvent::KeyPress && keyEvent->key() == Qt::Key_Delete &&
!m_editingDialogIsShown ) {
askToRemoveFocusItem();
return true;
}
return false;
}
// Handle mouse events.
QMouseEvent * const mouseEvent = dynamic_cast( event );
Q_ASSERT( mouseEvent );
// Get the geocoordinates from mouse pos screen coordinates.
qreal lon, lat;
const bool isOnGlobe = m_marbleWidget->geoCoordinates( mouseEvent->pos().x(),
mouseEvent->pos().y(),
lon, lat,
GeoDataCoordinates::Radian );
if ( !isOnGlobe ) {
return false;
}
// Deal with adding polygons and polylines.
if ( ( m_drawingPolygon && handleDrawingPolygon( mouseEvent ) ) ||
( m_drawingPolyline && handleDrawingPolyline( mouseEvent ) ) ) {
return true;
}
// It is important to deal with Ground Overlay mouse release event here because it uses the
// texture layer in order to make the rendering more efficient.
if ( mouseEvent->type() == QEvent::MouseButtonRelease && m_groundOverlayModel.rowCount() ) {
handleReleaseOverlay( mouseEvent );
}
// It is important to deal with the MouseMove event here because it changes the state of the
// selected item irrespective of the longitude/latitude the cursor moved to (excepting when
// it is outside the globe, which is treated above).
if ( mouseEvent->type() == QEvent::MouseMove && m_movedItem &&
handleMovingSelectedItem( mouseEvent ) ) {
setupCursor( m_movedItem );
return true;
}
// Pass the event to Graphic Items.
for ( SceneGraphicsItem *item: m_graphicsItems ) {
if ( !item->containsPoint( mouseEvent->pos() ) ) {
continue;
}
// If an edit dialog is visible, do not permit right clicking on items.
if ( m_editingDialogIsShown && mouseEvent->type() == QEvent::MouseButtonPress &&
mouseEvent->button() == Qt::RightButton) {
return true;
}
if ( !item->hasFocus() &&
item->graphicType() != SceneGraphicsTypes::SceneGraphicGroundOverlay ) {
if ( mouseEvent->type() == QEvent::MouseButtonPress &&
mouseEvent->button() == Qt::LeftButton ) {
item->setFocus( true );
disableFocusActions();
enableActionsOnItemType( item->graphicType() );
if ( m_focusItem && m_focusItem != item ) {
m_focusItem->setFocus( false );
if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicGroundOverlay ) {
clearOverlayFrames();
}
}
m_focusItem = item;
m_marbleWidget->model()->treeModel()->updateFeature( item->placemark() );
return true;
}
return false;
}
if ( item->sceneEvent( event ) ) {
setupCursor( item );
if ( mouseEvent->type() == QEvent::MouseButtonPress ) {
handleSuccessfulPressEvent( mouseEvent, item );
} else if ( mouseEvent->type() == QEvent::MouseMove ) {
handleSuccessfulHoverEvent( mouseEvent, item );
} else if ( mouseEvent->type() == QEvent::MouseButtonRelease ) {
handleSuccessfulReleaseEvent( mouseEvent, item );
}
handleRequests( mouseEvent, item );
return true;
}
}
// If the event gets here, it most probably means it is a map interaction event, or something
// that has nothing to do with the annotate plugin items. We "deal" with this situation because,
// for example, we may need to deselect some selected items.
handleUncaughtEvents( mouseEvent );
return false;
}
bool AnnotatePlugin::handleDrawingPolygon( QMouseEvent *mouseEvent )
{
const GeoDataCoordinates coords = mouseGeoDataCoordinates( mouseEvent );
if ( mouseEvent->type() == QEvent::MouseMove ) {
setupCursor( 0 );
emit mouseMoveGeoPosition( coords.toString() );
return true;
} else if ( mouseEvent->button() == Qt::LeftButton &&
mouseEvent->type() == QEvent::MouseButtonPress ) {
m_marbleWidget->model()->treeModel()->removeFeature( m_polygonPlacemark );
GeoDataPolygon *poly = dynamic_cast( m_polygonPlacemark->geometry() );
poly->outerBoundary().append( coords );
m_marbleWidget->model()->treeModel()->addFeature( m_annotationDocument, m_polygonPlacemark );
emit nodeAdded( coords );
return true;
}
return false;
}
bool AnnotatePlugin::handleDrawingPolyline( QMouseEvent *mouseEvent )
{
const GeoDataCoordinates coords = mouseGeoDataCoordinates( mouseEvent );
if ( mouseEvent->type() == QEvent::MouseMove ) {
setupCursor( 0 );
emit mouseMoveGeoPosition( coords.toString() );
return true;
} else if ( mouseEvent->button() == Qt::LeftButton &&
mouseEvent->type() == QEvent::MouseButtonPress ) {
m_marbleWidget->model()->treeModel()->removeFeature( m_polylinePlacemark );
GeoDataLineString *line = dynamic_cast( m_polylinePlacemark->geometry() );
line->append( coords );
m_marbleWidget->model()->treeModel()->addFeature( m_annotationDocument, m_polylinePlacemark );
emit nodeAdded( coords );
return true;
}
return false;
}
void AnnotatePlugin::handleReleaseOverlay( QMouseEvent *mouseEvent )
{
const GeoDataCoordinates coords = mouseGeoDataCoordinates( mouseEvent );
for ( int i = 0; i < m_groundOverlayModel.rowCount(); ++i ) {
const QModelIndex index = m_groundOverlayModel.index( i, 0 );
GeoDataGroundOverlay *overlay = dynamic_cast(
qvariant_cast( index.data( MarblePlacemarkModel::ObjectPointerRole ) ) );
if ( overlay->latLonBox().contains( coords ) ) {
if ( mouseEvent->button() == Qt::LeftButton ) {
displayOverlayFrame( overlay );
} else if ( mouseEvent->button() == Qt::RightButton ) {
showOverlayRmbMenu( overlay, mouseEvent->x(), mouseEvent->y() );
}
}
}
}
bool AnnotatePlugin::handleMovingSelectedItem( QMouseEvent *mouseEvent )
{
// Handling easily the mouse move by calling for each scene graphic item their own mouseMoveEvent
// handler and updating their feature.
if ( m_movedItem->sceneEvent( mouseEvent ) ) {
m_marbleWidget->model()->treeModel()->updateFeature( m_movedItem->placemark() );
emit itemMoved( m_movedItem->placemark() );
if ( m_movedItem->graphicType() == SceneGraphicsTypes::SceneGraphicTextAnnotation ) {
emit placemarkMoved();
}
const GeoDataCoordinates coords = mouseGeoDataCoordinates( mouseEvent );
emit mouseMoveGeoPosition( coords.toString() );
return true;
}
return false;
}
void AnnotatePlugin::handleSuccessfulPressEvent( QMouseEvent *mouseEvent, SceneGraphicsItem *item )
{
Q_UNUSED( mouseEvent );
// Update the item's placemark.
m_marbleWidget->model()->treeModel()->updateFeature( item->placemark() );
// Store a pointer to the item for possible following move events only if its state is
// either 'Editing' or 'AddingNodes' and the mouse left button has been used.
if ( ( item->state() == SceneGraphicsItem::Editing ||
item->state() == SceneGraphicsItem::AddingNodes ) &&
mouseEvent->button() == Qt::LeftButton ) {
m_movedItem = item;
}
}
void AnnotatePlugin::handleSuccessfulHoverEvent( QMouseEvent *mouseEvent, SceneGraphicsItem *item )
{
Q_UNUSED( mouseEvent );
m_marbleWidget->model()->treeModel()->updateFeature( item->placemark() );
}
void AnnotatePlugin::handleSuccessfulReleaseEvent( QMouseEvent *mouseEvent, SceneGraphicsItem *item )
{
Q_UNUSED( mouseEvent );
// The item gets 'deselected' (from moving) at mouse release.
m_movedItem = 0;
// Update the item's placemark.
m_marbleWidget->model()->treeModel()->updateFeature( item->placemark() );
}
void AnnotatePlugin::handleRequests( QMouseEvent *mouseEvent, SceneGraphicsItem *item )
{
if ( item->graphicType() == SceneGraphicsTypes::SceneGraphicAreaAnnotation ) {
AreaAnnotation * const area = static_cast( item );
if ( area->request() == SceneGraphicsItem::ShowPolygonRmbMenu ) {
showPolygonRmbMenu( mouseEvent->pos().x(), mouseEvent->pos().y() );
} else if ( area->request() == SceneGraphicsItem::ShowNodeRmbMenu ) {
showNodeRmbMenu( mouseEvent->pos().x(), mouseEvent->pos().y() );
} else if ( area->request() == SceneGraphicsItem::StartPolygonAnimation ) {
QPointer animation = area->animation();
connect( animation, SIGNAL(nodesMoved()), this, SIGNAL(repaintNeeded()) );
connect( animation, SIGNAL(animationFinished()),
this, SLOT(setAreaAvailable()) );
area->setBusy( true );
disableActions( m_actions.first() );
animation->startAnimation();
} else if ( area->request() == SceneGraphicsItem::OuterInnerMergingWarning ) {
QMessageBox::warning( m_marbleWidget,
tr( "Operation not permitted" ),
tr( "Cannot merge a node from polygon's outer boundary "
"with a node from one of its inner boundaries." ) );
} else if ( area->request() == SceneGraphicsItem::InnerInnerMergingWarning ) {
QMessageBox::warning( m_marbleWidget,
tr( "Operation not permitted" ),
tr( "Cannot merge two nodes from two different inner "
"boundaries." ) );
} else if ( area->request() == SceneGraphicsItem::InvalidShapeWarning ) {
QMessageBox::warning( m_marbleWidget,
tr( "Operation not permitted" ),
tr( "Cannot merge the selected nodes. Most probably "
"this would make the polygon's outer boundary not "
"contain all its inner boundary nodes." ) );
} else if ( area->request() == SceneGraphicsItem::RemovePolygonRequest ) {
removeFocusItem();
} else if ( area->request() == SceneGraphicsItem::ChangeCursorPolygonNodeHover ) {
m_marbleWidget->setCursor( Qt::PointingHandCursor );
} else if ( area->request() == SceneGraphicsItem::ChangeCursorPolygonBodyHover ) {
m_marbleWidget->setCursor( Qt::SizeAllCursor );
}
} else if ( item->graphicType() == SceneGraphicsTypes::SceneGraphicPolylineAnnotation ) {
PolylineAnnotation * const polyline = static_cast( item );
if ( polyline->request() == SceneGraphicsItem::ShowPolylineRmbMenu ) {
showPolylineRmbMenu( mouseEvent->x(), mouseEvent->y() );
} else if ( polyline->request() == SceneGraphicsItem::ShowNodeRmbMenu ) {
showNodeRmbMenu( mouseEvent->x(), mouseEvent->y() );
} else if ( polyline->request() == SceneGraphicsItem::StartPolylineAnimation ) {
QPointer animation = polyline->animation();
connect( animation, SIGNAL(nodesMoved()), this, SIGNAL(repaintNeeded()) );
connect( animation, SIGNAL(animationFinished()),
this, SLOT(setPolylineAvailable()) );
polyline->setBusy( true );
disableActions( m_actions.first() );
animation->startAnimation();
} else if ( polyline->request() == SceneGraphicsItem::RemovePolylineRequest ) {
removeFocusItem();
} else if ( polyline->request() == SceneGraphicsItem::ChangeCursorPolylineNodeHover ) {
m_marbleWidget->setCursor( Qt::PointingHandCursor );
} else if ( polyline->request() == SceneGraphicsItem::ChangeCursorPolylineLineHover ) {
m_marbleWidget->setCursor( Qt::SizeAllCursor );
}
} else if ( item->graphicType() == SceneGraphicsTypes::SceneGraphicTextAnnotation ) {
PlacemarkTextAnnotation * const textAnnotation = static_cast( item );
if ( textAnnotation->request() == SceneGraphicsItem::ShowPlacemarkRmbMenu ) {
showTextAnnotationRmbMenu( mouseEvent->x(), mouseEvent->y() );
} else if ( textAnnotation->request() == SceneGraphicsItem::ChangeCursorPlacemarkHover ) {
m_marbleWidget->setCursor( Qt::SizeAllCursor );
}
} else if ( item->graphicType() == SceneGraphicsTypes::SceneGraphicGroundOverlay ){
GroundOverlayFrame * const groundOverlay = static_cast( item );
if ( groundOverlay->request() == SceneGraphicsItem::ChangeCursorOverlayVerticalHover ) {
m_marbleWidget->setCursor( Qt::SizeVerCursor );
} else if ( groundOverlay->request() == SceneGraphicsItem::ChangeCursorOverlayHorizontalHover ) {
m_marbleWidget->setCursor( Qt::SizeHorCursor );
} else if ( groundOverlay->request() == SceneGraphicsItem::ChangeCursorOverlayBDiagHover ) {
m_marbleWidget->setCursor( Qt::SizeBDiagCursor );
} else if ( groundOverlay->request() == SceneGraphicsItem::ChangeCursorOverlayFDiagHover ) {
m_marbleWidget->setCursor( Qt::SizeFDiagCursor );
} else if ( groundOverlay->request() == SceneGraphicsItem::ChangeCursorOverlayBodyHover ) {
m_marbleWidget->setCursor( Qt::SizeAllCursor );
} else if ( groundOverlay->request() == SceneGraphicsItem::ChangeCursorOverlayRotateHover ) {
m_marbleWidget->setCursor( Qt::CrossCursor );
}
}
}
void AnnotatePlugin::handleUncaughtEvents( QMouseEvent *mouseEvent )
{
Q_UNUSED( mouseEvent );
// If the event is not caught by any of the annotate plugin specific items, clear the frames
// (which have the meaning of deselecting the overlay).
if ( !m_groundOverlayFrames.isEmpty() &&
mouseEvent->type() != QEvent::MouseMove && mouseEvent->type() != QEvent::MouseButtonRelease ) {
clearOverlayFrames();
}
if ( m_focusItem && m_focusItem->graphicType() != SceneGraphicsTypes::SceneGraphicGroundOverlay ) {
if ( ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicAreaAnnotation &&
static_cast( m_focusItem )->isBusy() ) ||
( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicPolylineAnnotation &&
static_cast( m_focusItem )->isBusy() ) ) {
return;
}
m_focusItem->dealWithItemChange( 0 );
m_marbleWidget->model()->treeModel()->updateFeature( m_focusItem->placemark() );
if ( mouseEvent->type() == QEvent::MouseButtonPress ) {
m_focusItem->setFocus( false );
disableFocusActions();
announceStateChanged( SceneGraphicsItem::Editing );
m_marbleWidget->model()->treeModel()->updateFeature( m_focusItem->placemark() );
m_focusItem = 0;
}
}
}
void AnnotatePlugin::setupActions( MarbleWidget *widget )
{
qDeleteAll( m_actions );
m_actions.clear();
if ( !widget ) {
return;
}
QActionGroup *group = new QActionGroup( 0 );
group->setExclusive( true );
QAction *selectItem = new QAction( QIcon(QStringLiteral(":/icons/edit-select.png")),
tr("Select Item"),
this );
selectItem->setCheckable( true );
selectItem->setChecked( true );
QAction *drawPolygon = new QAction( QIcon(QStringLiteral(":/icons/draw-polygon.png")),
tr("Add Polygon"),
this );
connect( drawPolygon, SIGNAL(triggered()), this, SLOT(addPolygon()) );
QAction *addHole = new QAction( QIcon(QStringLiteral(":/icons/polygon-draw-hole.png")),
tr("Add Polygon Hole"),
this );
addHole->setCheckable( true );
addHole->setEnabled( false );
connect( addHole, SIGNAL(toggled(bool)), this, SLOT(setAddingPolygonHole(bool)) );
QAction *addNodes = new QAction( QIcon(QStringLiteral(":/icons/polygon-add-nodes.png")),
tr("Add Nodes"),
this );
addNodes->setCheckable( true );
addNodes->setEnabled( false );
connect( addNodes, SIGNAL(toggled(bool)), this, SLOT(setAddingNodes(bool)) );
QAction *addTextAnnotation = new QAction( QIcon(QStringLiteral(":/icons/add-placemark.png")),
tr("Add Placemark"),
this );
connect( addTextAnnotation, SIGNAL(triggered()), this, SLOT(addTextAnnotation()) );
QAction *addPath = new QAction( QIcon(QStringLiteral(":/icons/draw-path.png")),
tr("Add Path"),
this );
connect( addPath, SIGNAL(triggered()), this, SLOT(addPolyline()) );
QAction *addOverlay = new QAction( QIcon(QStringLiteral(":/icons/draw-overlay.png")),
tr("Add Ground Overlay"),
this );
connect( addOverlay, SIGNAL(triggered()), this, SLOT(addOverlay()) );
QAction *removeItem = new QAction( QIcon(QStringLiteral(":/icons/edit-delete-shred.png")),
tr("Remove Item"),
this );
removeItem->setEnabled( false );
connect( removeItem, SIGNAL(triggered()), this, SLOT(askToRemoveFocusItem()) );
QAction *loadAnnotationFile = new QAction( QIcon(QStringLiteral(":/icons/open-for-editing.png")),
tr("Load Annotation File" ),
this );
connect( loadAnnotationFile, SIGNAL(triggered()), this, SLOT(loadAnnotationFile()) );
QAction *saveAnnotationFile = new QAction( QIcon(QStringLiteral(":/icons/document-save-as.png")),
tr("Save Annotation File"),
this );
connect( saveAnnotationFile, SIGNAL(triggered()), this, SLOT(saveAnnotationFile()) );
QAction *clearAnnotations = new QAction( QIcon(QStringLiteral(":/icons/remove.png")),
tr("Clear all Annotations"),
this );
+ QAction *downloadOsm = new QAction( QIcon(":/icons/download.png"),
+ tr("Download OpenStreetMap Data"),
+ this );
+ connect( downloadOsm, SIGNAL(triggered(bool)), this, SLOT(downloadOsm()) );
+ downloadOsm->setToolTip(tr("Download OpenStreetMap data of the visible region"));
connect( drawPolygon, SIGNAL(toggled(bool)), clearAnnotations, SLOT(setDisabled(bool)) );
connect( clearAnnotations, SIGNAL(triggered()), this, SLOT(clearAnnotations()) );
QAction *sep1 = new QAction( this );
sep1->setSeparator( true );
QAction *sep2 = new QAction( this );
sep2->setSeparator( true );
sep2->setObjectName( "toolbarSeparator" );
QAction *sep3 = new QAction( this );
sep3->setSeparator( true );
QAction *sep4 = new QAction( this );
sep4->setSeparator( true );
group->addAction( loadAnnotationFile );
group->addAction( saveAnnotationFile );
group->addAction( sep1 );
group->addAction( addTextAnnotation );
group->addAction( drawPolygon );
group->addAction( addPath );
group->addAction( addOverlay );
group->addAction( sep2 );
group->addAction( selectItem );
group->addAction( addHole );
group->addAction( addNodes );
group->addAction( removeItem );
group->addAction( sep3 );
group->addAction( clearAnnotations );
+ group->addAction(downloadOsm);
group->addAction( sep4 );
m_actions.append( group );
emit actionGroupsChanged();
}
void AnnotatePlugin::disableActions( QActionGroup *group )
{
for ( int i = 0; i < group->actions().size(); ++i ) {
if ( group->actions().at(i)->text() != tr("Select Item") ) {
group->actions().at(i)->setEnabled( false );
} else {
group->actions().at(i)->setEnabled( true );
}
}
}
void AnnotatePlugin::enableAllActions( QActionGroup *group )
{
for ( int i = 0; i < group->actions().size(); ++i ) {
group->actions().at(i)->setEnabled( true );
}
}
void AnnotatePlugin::enableActionsOnItemType( const QString &type )
{
if ( type == SceneGraphicsTypes::SceneGraphicAreaAnnotation ) {
m_actions.first()->actions().at(9)->setEnabled( true );
m_actions.first()->actions().at(10)->setEnabled( true );
} else if ( type == SceneGraphicsTypes::SceneGraphicPolylineAnnotation ) {
m_actions.first()->actions().at(10)->setEnabled( true );
}
m_actions.first()->actions().at(11)->setEnabled( true );
}
void AnnotatePlugin::disableFocusActions()
{
m_actions.first()->actions().at(8)->setChecked( true );
m_actions.first()->actions().at(9)->setEnabled( false );
m_actions.first()->actions().at(10)->setEnabled( false );
m_actions.first()->actions().at(11)->setEnabled( false );
}
void AnnotatePlugin::addContextItems()
{
MarbleWidgetPopupMenu * const menu = m_marbleWidget->popupMenu();
m_pasteGraphicItem = new QAction( tr( "Paste" ), this );
m_pasteGraphicItem->setVisible( false );
connect( m_pasteGraphicItem, SIGNAL(triggered()), SLOT(pasteItem()) );
QAction *separator = new QAction( this );
separator->setSeparator( true );
bool const smallScreen = MarbleGlobal::getInstance()->profiles() & MarbleGlobal::SmallScreen;
if ( !smallScreen ) {
menu->addAction( Qt::RightButton, m_pasteGraphicItem );
menu->addAction( Qt::RightButton, separator );
}
}
void AnnotatePlugin::setupTextAnnotationRmbMenu()
{
delete m_textAnnotationRmbMenu;
m_textAnnotationRmbMenu = new QMenu;
QAction *cutItem = new QAction( tr( "Cut"), m_textAnnotationRmbMenu );
m_textAnnotationRmbMenu->addAction( cutItem );
connect( cutItem, SIGNAL(triggered()), this, SLOT(cutItem()) );
QAction *copyItem = new QAction( tr( "Copy"), m_textAnnotationRmbMenu );
m_textAnnotationRmbMenu->addAction( copyItem );
connect( copyItem, SIGNAL(triggered()), this, SLOT(copyItem()) );
QAction *removeItem = new QAction( tr( "Remove" ), m_textAnnotationRmbMenu );
m_textAnnotationRmbMenu->addAction( removeItem );
connect( removeItem, SIGNAL(triggered()), this, SLOT(askToRemoveFocusItem()) );
m_textAnnotationRmbMenu->addSeparator();
QAction *properties = new QAction( tr( "Properties" ), m_textAnnotationRmbMenu );
m_textAnnotationRmbMenu->addAction( properties );
connect( properties, SIGNAL(triggered()), this, SLOT(editTextAnnotation()) );
}
void AnnotatePlugin::showTextAnnotationRmbMenu( qreal x, qreal y )
{
m_textAnnotationRmbMenu->popup( m_marbleWidget->mapToGlobal( QPoint( x, y ) ) );
}
void AnnotatePlugin::editTextAnnotation()
{
QPointer dialog = new EditPlacemarkDialog( m_focusItem->placemark(),
&m_osmRelations,
m_marbleWidget );
connect( dialog, SIGNAL(textAnnotationUpdated(GeoDataFeature*)),
m_marbleWidget->model()->treeModel(), SLOT(updateFeature(GeoDataFeature*)) );
connect( this, SIGNAL(placemarkMoved()),
dialog, SLOT(updateDialogFields()) );
connect( dialog, SIGNAL(finished(int)),
this, SLOT(stopEditingTextAnnotation(int)) );
connect( dialog, SIGNAL( relationCreated( const OsmPlacemarkData& ) ),
this, SLOT( addRelation( const OsmPlacemarkData& ) ) );
dialog->setLabelColor(dynamic_cast(m_focusItem)->labelColor());
disableActions( m_actions.first() );
dialog->show();
m_editingDialogIsShown = true;
m_editedItem = m_focusItem;
}
void AnnotatePlugin::addTextAnnotation()
{
m_addingPlacemark = true;
// Get the normalized coordinates of the focus point. There will be automatically added a new
// placemark.
qreal lat = m_marbleWidget->focusPoint().latitude();
qreal lon = m_marbleWidget->focusPoint().longitude();
GeoDataCoordinates::normalizeLonLat( lon, lat );
GeoDataPlacemark *placemark = new GeoDataPlacemark;
placemark->setCoordinate( lon, lat );
placemark->setVisible( true );
placemark->setBalloonVisible( false );
m_marbleWidget->model()->treeModel()->addFeature( m_annotationDocument, placemark );
PlacemarkTextAnnotation *textAnnotation = new PlacemarkTextAnnotation( placemark );
textAnnotation->setFocus( true );
m_graphicsItems.append( textAnnotation );
QPointer dialog = new EditPlacemarkDialog( placemark, &m_osmRelations, m_marbleWidget );
connect( dialog, SIGNAL(textAnnotationUpdated(GeoDataFeature*)),
m_marbleWidget->model()->treeModel(), SLOT(updateFeature(GeoDataFeature*)) );
connect( this, SIGNAL(placemarkMoved()),
dialog, SLOT(updateDialogFields()) );
connect( dialog, SIGNAL(finished(int)),
this, SLOT(stopEditingTextAnnotation(int)) );
connect( dialog, SIGNAL( relationCreated( const OsmPlacemarkData& ) ),
this, SLOT( addRelation( const OsmPlacemarkData& ) ) );
if ( m_focusItem ) {
m_focusItem->setFocus( false );
if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicGroundOverlay ) {
clearOverlayFrames();
}
}
m_focusItem = textAnnotation;
m_editedItem = textAnnotation;
disableActions( m_actions.first() );
dialog->move( m_marbleWidget->mapToGlobal( QPoint( 0, 0 ) ) );
dialog->show();
m_editingDialogIsShown = true;
}
void AnnotatePlugin::stopEditingTextAnnotation( int result )
{
m_focusItem = m_editedItem;
m_editedItem = 0;
announceStateChanged( SceneGraphicsItem::Editing );
enableAllActions( m_actions.first() );
disableFocusActions();
if ( !result && m_addingPlacemark ) {
removeFocusItem();
} else {
enableActionsOnItemType( SceneGraphicsTypes::SceneGraphicTextAnnotation );
}
m_addingPlacemark = false;
m_editingDialogIsShown = false;
}
void AnnotatePlugin::setupGroundOverlayModel()
{
m_editingDialogIsShown = false;
m_groundOverlayModel.setSourceModel( m_marbleWidget->model()->groundOverlayModel() );
m_groundOverlayModel.setDynamicSortFilter( true );
m_groundOverlayModel.setSortRole( MarblePlacemarkModel::PopularityIndexRole );
m_groundOverlayModel.sort( 0, Qt::AscendingOrder );
}
void AnnotatePlugin::setupOverlayRmbMenu()
{
delete m_overlayRmbMenu;
m_overlayRmbMenu = new QMenu;
QAction *editOverlay = new QAction( tr( "Properties" ), m_overlayRmbMenu );
m_overlayRmbMenu->addAction( editOverlay );
connect( editOverlay, SIGNAL(triggered()), this, SLOT(editOverlay()) );
m_overlayRmbMenu->addSeparator();
QAction *removeOverlay = new QAction( tr( "Remove" ), m_overlayRmbMenu );
m_overlayRmbMenu->addAction( removeOverlay );
connect( removeOverlay, SIGNAL(triggered()), this, SLOT(removeOverlay()) );
}
void AnnotatePlugin::addOverlay()
{
GeoDataGroundOverlay *overlay = new GeoDataGroundOverlay();
qreal centerLongitude = m_marbleWidget->viewport()->centerLongitude()*RAD2DEG;
qreal centerLatitude = m_marbleWidget->viewport()->centerLatitude()*RAD2DEG;
GeoDataLatLonAltBox box = m_marbleWidget->viewport()->viewLatLonAltBox();
qreal maxDelta = 20;
qreal deltaLongitude = qMin(box.width(GeoDataCoordinates::Degree), maxDelta);
qreal deltaLatitude = qMin(box.height(GeoDataCoordinates::Degree), maxDelta);
qreal north = centerLatitude + deltaLatitude/4;
qreal south = centerLatitude - deltaLatitude/4;
qreal west = centerLongitude - deltaLongitude/4;
qreal east = centerLongitude + deltaLongitude/4;
overlay->latLonBox().setBoundaries( north, south, east, west, GeoDataCoordinates::Degree );
overlay->setName( tr( "Untitled Ground Overlay" ) );
QPointer dialog = new EditGroundOverlayDialog(
overlay,
m_marbleWidget->textureLayer(),
m_marbleWidget );
dialog->exec();
if( dialog->result() ) {
m_marbleWidget->model()->treeModel()->addFeature( m_annotationDocument, overlay );
displayOverlayFrame( overlay );
}
else {
delete overlay;
}
delete dialog;
}
void AnnotatePlugin::showOverlayRmbMenu( GeoDataGroundOverlay *overlay, qreal x, qreal y )
{
m_rmbOverlay = overlay;
m_overlayRmbMenu->popup( m_marbleWidget->mapToGlobal( QPoint( x, y ) ) );
}
void AnnotatePlugin::editOverlay()
{
displayOverlayFrame( m_rmbOverlay );
QPointer dialog = new EditGroundOverlayDialog(
m_rmbOverlay,
m_marbleWidget->textureLayer(),
m_marbleWidget );
connect( dialog, SIGNAL(groundOverlayUpdated(GeoDataGroundOverlay*)),
this, SLOT(updateOverlayFrame(GeoDataGroundOverlay*)) );
dialog->exec();
delete dialog;
}
void AnnotatePlugin::removeOverlay()
{
m_marbleWidget->model()->treeModel()->removeFeature( m_rmbOverlay );
clearOverlayFrames();
}
void AnnotatePlugin::displayOverlayFrame( GeoDataGroundOverlay *overlay )
{
if ( m_groundOverlayFrames.keys().contains( overlay ) ) {
return;
}
GeoDataPolygon *polygon = new GeoDataPolygon( Tessellate );
polygon->outerBoundary().setTessellate( true );
GeoDataPlacemark *rectangle_placemark = new GeoDataPlacemark;
rectangle_placemark->setGeometry( polygon );
rectangle_placemark->setParent( m_annotationDocument );
rectangle_placemark->setStyleUrl(QStringLiteral("#polygon"));
m_marbleWidget->model()->treeModel()->addFeature( m_annotationDocument, rectangle_placemark );
GroundOverlayFrame *frame = new GroundOverlayFrame( rectangle_placemark,
overlay,
m_marbleWidget->textureLayer() );
m_graphicsItems.append( frame );
m_groundOverlayFrames.insert( overlay, frame );
if ( m_focusItem ) {
m_focusItem->setFocus( false );
}
m_focusItem = frame;
enableActionsOnItemType( SceneGraphicsTypes::SceneGraphicGroundOverlay );
}
void AnnotatePlugin::updateOverlayFrame( GeoDataGroundOverlay *overlay )
{
GroundOverlayFrame *frame = static_cast( m_groundOverlayFrames.value( overlay ) );
if ( frame ) {
frame->update();
}
}
void AnnotatePlugin::clearOverlayFrames()
{
for ( GeoDataGroundOverlay *overlay: m_groundOverlayFrames.keys() ) {
GroundOverlayFrame *frame = static_cast( m_groundOverlayFrames.value( overlay ) );
m_graphicsItems.removeAll( m_groundOverlayFrames.value( overlay ) );
m_marbleWidget->model()->treeModel()->removeFeature( frame->placemark() );
delete frame->placemark();
delete frame;
}
m_groundOverlayFrames.clear();
m_focusItem = 0;
disableFocusActions();
}
void AnnotatePlugin::setupPolygonRmbMenu()
{
delete m_polygonRmbMenu;
m_polygonRmbMenu = new QMenu;
QAction *deselectNodes = new QAction( tr( "Deselect All Nodes" ), m_polygonRmbMenu );
m_polygonRmbMenu->addAction( deselectNodes );
connect( deselectNodes, SIGNAL(triggered()), this, SLOT(deselectNodes()) );
QAction *deleteAllSelected = new QAction( tr( "Delete All Selected Nodes" ), m_polygonRmbMenu );
m_polygonRmbMenu->addAction( deleteAllSelected );
connect( deleteAllSelected, SIGNAL(triggered()), this, SLOT(deleteSelectedNodes()) );
m_polygonRmbMenu->addSeparator();
QAction *cutPolygon = new QAction( tr( "Cut"), m_polygonRmbMenu );
m_polygonRmbMenu->addAction( cutPolygon );
connect( cutPolygon, SIGNAL(triggered()), this, SLOT(cutItem()) );
QAction *copyPolygon = new QAction( tr( "Copy"), m_polygonRmbMenu );
m_polygonRmbMenu->addAction( copyPolygon );
connect( copyPolygon, SIGNAL(triggered()), this, SLOT(copyItem()) );
QAction *removePolygon = new QAction( tr( "Remove" ), m_polygonRmbMenu );
m_polygonRmbMenu->addAction( removePolygon );
connect( removePolygon, SIGNAL(triggered()), this, SLOT(askToRemoveFocusItem()) );
m_polygonRmbMenu->addSeparator();
QAction *showEditDialog = new QAction( tr( "Properties" ), m_polygonRmbMenu );
m_polygonRmbMenu->addAction( showEditDialog );
connect( showEditDialog, SIGNAL(triggered()), this, SLOT(editPolygon()) );
}
void AnnotatePlugin::showPolygonRmbMenu( qreal x, qreal y )
{
// We need to store the coordinates from where the rmb menu is shown so that in case of
// selecting Copy/Cut, we can move the polygon.
qreal lon, lat;
m_marbleWidget->geoCoordinates( x, y, lon, lat, GeoDataCoordinates::Radian );
m_fromWhereToCopy = GeoDataCoordinates( lon, lat );
if ( !static_cast( m_focusItem )->hasNodesSelected() ) {
m_polygonRmbMenu->actions().at(1)->setEnabled( false );
m_polygonRmbMenu->actions().at(0)->setEnabled( false );
} else {
m_polygonRmbMenu->actions().at(1)->setEnabled( true );
m_polygonRmbMenu->actions().at(0)->setEnabled( true );
}
m_polygonRmbMenu->popup( m_marbleWidget->mapToGlobal( QPoint( x, y ) ) );
}
void AnnotatePlugin::addPolygon()
{
m_drawingPolygon = true;
GeoDataPolygon *poly = new GeoDataPolygon( Tessellate );
poly->outerBoundary().setTessellate( true );
m_polygonPlacemark = new GeoDataPlacemark;
m_polygonPlacemark->setGeometry( poly );
m_polygonPlacemark->setParent( m_annotationDocument );
m_polygonPlacemark->setStyleUrl(QStringLiteral("#polygon"));
m_marbleWidget->model()->treeModel()->addFeature( m_annotationDocument, m_polygonPlacemark );
AreaAnnotation *polygon = new AreaAnnotation( m_polygonPlacemark );
polygon->setState( SceneGraphicsItem::DrawingPolygon );
polygon->setFocus( true );
m_graphicsItems.append( polygon );
m_marbleWidget->update();
QPointer dialog = new EditPolygonDialog( m_polygonPlacemark, &m_osmRelations, m_marbleWidget );
connect( dialog, SIGNAL(polygonUpdated(GeoDataFeature*)),
m_marbleWidget->model()->treeModel(), SLOT(updateFeature(GeoDataFeature*)) );
connect( dialog, SIGNAL(finished(int)),
this, SLOT(stopEditingPolygon(int)) );
connect( this, SIGNAL(nodeAdded(GeoDataCoordinates)), dialog, SLOT(handleAddingNode(GeoDataCoordinates)) );
connect( dialog, SIGNAL( relationCreated( const OsmPlacemarkData& ) ),
this, SLOT( addRelation( const OsmPlacemarkData& ) ) );
// If there is another graphic item marked as 'selected' when pressing 'Add Polygon', change the focus of
// that item.
if ( m_focusItem ) {
m_focusItem->setFocus( false );
if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicGroundOverlay ) {
clearOverlayFrames();
}
}
m_focusItem = polygon;
m_editedItem = polygon;
disableActions( m_actions.first() );
dialog->move( m_marbleWidget->mapToGlobal( QPoint( 0, 0 ) ) );
dialog->show();
m_editingDialogIsShown = true;
}
void AnnotatePlugin::stopEditingPolygon( int result )
{
m_focusItem = m_editedItem;
m_editedItem = 0;
announceStateChanged( SceneGraphicsItem::Editing );
enableAllActions( m_actions.first() );
disableFocusActions();
if ( !result && m_drawingPolygon ) {
removeFocusItem();
} else {
enableActionsOnItemType( SceneGraphicsTypes::SceneGraphicAreaAnnotation );
}
m_editingDialogIsShown = false;
m_drawingPolygon = false;
m_polygonPlacemark = 0;
}
void AnnotatePlugin::deselectNodes()
{
if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicAreaAnnotation ) {
AreaAnnotation * const area = static_cast( m_focusItem );
area->deselectAllNodes();
if ( area->request() == SceneGraphicsItem::NoRequest ) {
m_marbleWidget->model()->treeModel()->updateFeature( area->placemark() );
}
} else if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicPolylineAnnotation ) {
PolylineAnnotation * const polyline = static_cast( m_focusItem );
polyline->deselectAllNodes();
if ( polyline->request() == SceneGraphicsItem::NoRequest ) {
m_marbleWidget->model()->treeModel()->updateFeature( polyline->placemark() );
}
}
}
void AnnotatePlugin::deleteSelectedNodes()
{
if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicAreaAnnotation ) {
AreaAnnotation * const area = static_cast( m_focusItem );
area->deleteAllSelectedNodes();
} else if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicPolylineAnnotation ) {
PolylineAnnotation * const polyline = static_cast( m_focusItem );
polyline->deleteAllSelectedNodes();
}
if ( m_focusItem->request() == SceneGraphicsItem::NoRequest ) {
m_marbleWidget->model()->treeModel()->updateFeature( m_focusItem->placemark() );
} else if ( m_focusItem->request() == SceneGraphicsItem::RemovePolygonRequest ||
m_focusItem->request() == SceneGraphicsItem::RemovePolylineRequest ) {
removeFocusItem();
} else if ( m_focusItem->request() == SceneGraphicsItem::InvalidShapeWarning ) {
QMessageBox::warning( m_marbleWidget,
tr( "Operation not permitted" ),
tr( "Cannot delete one of the selected nodes. Most probably "
"this would make the polygon's outer boundary not "
"contain all its inner boundary nodes." ) );
}
}
void AnnotatePlugin::editPolygon()
{
EditPolygonDialog *dialog = new EditPolygonDialog( m_focusItem->placemark(), &m_osmRelations, m_marbleWidget );
connect( dialog, SIGNAL(polygonUpdated(GeoDataFeature*)),
m_marbleWidget->model()->treeModel(), SLOT(updateFeature(GeoDataFeature*)) );
connect( dialog, SIGNAL(finished(int)),
this, SLOT(stopEditingPolygon(int)) );
connect( this, SIGNAL(itemMoved(GeoDataPlacemark*)), dialog, SLOT(handleItemMoving(GeoDataPlacemark*)) );
connect( dialog, SIGNAL( relationCreated( const OsmPlacemarkData& ) ),
this, SLOT( addRelation( const OsmPlacemarkData& ) ) );
disableActions( m_actions.first() );
dialog->move( m_marbleWidget->mapToGlobal( QPoint( 0, 0 ) ) );
dialog->show();
m_editingDialogIsShown = true;
m_editedItem = m_focusItem;
}
void AnnotatePlugin::setupNodeRmbMenu()
{
delete m_nodeRmbMenu;
m_nodeRmbMenu = new QMenu;
QAction *selectNode = new QAction( tr( "Select Node" ), m_nodeRmbMenu );
m_nodeRmbMenu->addAction( selectNode );
connect( selectNode, SIGNAL(triggered()), this, SLOT(selectNode()) );
QAction *deleteNode = new QAction( tr( "Delete Node" ), m_nodeRmbMenu );
m_nodeRmbMenu->addAction( deleteNode );
connect( deleteNode, SIGNAL(triggered()), this, SLOT(deleteNode()) );
}
void AnnotatePlugin::showNodeRmbMenu( qreal x, qreal y )
{
// Check whether the node is already selected; we change the text of the action
// accordingly.
bool isSelected = false;
if ( ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicAreaAnnotation &&
static_cast( m_focusItem )->clickedNodeIsSelected() ) ||
( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicPolylineAnnotation &&
static_cast( m_focusItem )->clickedNodeIsSelected() ) ) {
isSelected = true;
}
m_nodeRmbMenu->actions().first()->setText( isSelected ? tr("Deselect Node") : tr("Select Node") );
m_nodeRmbMenu->popup( m_marbleWidget->mapToGlobal( QPoint( x, y ) ) );
}
void AnnotatePlugin::selectNode()
{
if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicAreaAnnotation ) {
AreaAnnotation * const area = static_cast( m_focusItem );
area->changeClickedNodeSelection();
} else if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicPolylineAnnotation ) {
PolylineAnnotation *const polyline = static_cast( m_focusItem );
polyline->changeClickedNodeSelection();
}
if ( m_focusItem->request() == SceneGraphicsItem::NoRequest ) {
m_marbleWidget->model()->treeModel()->updateFeature( m_focusItem->placemark() );
}
}
void AnnotatePlugin::deleteNode()
{
if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicAreaAnnotation ) {
AreaAnnotation *area = static_cast( m_focusItem );
area->deleteClickedNode();
} else if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicPolylineAnnotation ) {
PolylineAnnotation *polyline = static_cast( m_focusItem );
polyline->deleteClickedNode();
}
if ( m_focusItem->request() == SceneGraphicsItem::NoRequest ) {
m_marbleWidget->model()->treeModel()->updateFeature( m_focusItem->placemark() );
} else if ( m_focusItem->request() == SceneGraphicsItem::RemovePolygonRequest ||
m_focusItem->request() == SceneGraphicsItem::RemovePolylineRequest ) {
removeFocusItem();
} else if ( m_focusItem->request() == SceneGraphicsItem::InvalidShapeWarning ) {
QMessageBox::warning( m_marbleWidget,
tr( "Operation not permitted" ),
tr( "Cannot delete one of the selected nodes. Most probably "
"this would make the polygon's outer boundary not "
"contain all its inner boundary nodes." ) );
}
}
void AnnotatePlugin::setupPolylineRmbMenu()
{
delete m_polylineRmbMenu;
m_polylineRmbMenu = new QMenu;
QAction *deselectNodes = new QAction( tr( "Deselect All Nodes" ), m_polylineRmbMenu );
m_polylineRmbMenu->addAction( deselectNodes );
connect( deselectNodes, SIGNAL(triggered()), this, SLOT(deselectNodes()) );
QAction *deleteAllSelected = new QAction( tr( "Delete All Selected Nodes" ), m_polylineRmbMenu );
m_polylineRmbMenu->addAction( deleteAllSelected );
connect( deleteAllSelected, SIGNAL(triggered()), this, SLOT(deleteSelectedNodes()) );
m_polylineRmbMenu->addSeparator();
QAction *cutItem = new QAction( tr( "Cut"), m_polylineRmbMenu );
m_polylineRmbMenu->addAction( cutItem );
connect( cutItem, SIGNAL(triggered()), this, SLOT(cutItem()) );
QAction *copyItem = new QAction( tr( "Copy"), m_polylineRmbMenu );
m_polylineRmbMenu->addAction( copyItem );
connect( copyItem, SIGNAL(triggered()), this, SLOT(copyItem()) );
QAction *removeItem = new QAction( tr( "Remove" ), m_polylineRmbMenu );
m_polylineRmbMenu->addAction( removeItem );
connect( removeItem, SIGNAL(triggered()), this, SLOT(askToRemoveFocusItem()) );
m_polylineRmbMenu->addSeparator();
QAction *properties = new QAction( tr( "Properties" ), m_polylineRmbMenu );
m_polylineRmbMenu->addAction( properties );
connect( properties, SIGNAL(triggered()), this, SLOT(editPolyline()) );
}
void AnnotatePlugin::showPolylineRmbMenu( qreal x, qreal y )
{
qreal lon, lat;
m_marbleWidget->geoCoordinates( x, y, lon, lat, GeoDataCoordinates::Radian );
m_fromWhereToCopy = GeoDataCoordinates( lon, lat );
if ( !static_cast( m_focusItem )->hasNodesSelected() ) {
m_polylineRmbMenu->actions().at(1)->setEnabled( false );
m_polylineRmbMenu->actions().at(0)->setEnabled( false );
} else {
m_polylineRmbMenu->actions().at(1)->setEnabled( true );
m_polylineRmbMenu->actions().at(0)->setEnabled( true );
}
m_polylineRmbMenu->popup( m_marbleWidget->mapToGlobal( QPoint( x, y ) ) );
}
void AnnotatePlugin::editPolyline()
{
QPointer dialog = new EditPolylineDialog( m_focusItem->placemark(),
&m_osmRelations,
m_marbleWidget );
connect( dialog, SIGNAL(polylineUpdated(GeoDataFeature*)),
m_marbleWidget->model()->treeModel(), SLOT(updateFeature(GeoDataFeature*)) );
connect( dialog, SIGNAL(finished(int)),
this, SLOT(stopEditingPolyline(int)) );
connect( this, SIGNAL(itemMoved(GeoDataPlacemark*)), dialog, SLOT(handleItemMoving(GeoDataPlacemark*)) );
connect( dialog, SIGNAL( relationCreated( const OsmPlacemarkData& ) ),
this, SLOT( addRelation( const OsmPlacemarkData& ) ) );
disableActions( m_actions.first() );
dialog->show();
m_editingDialogIsShown = true;
m_editedItem = m_focusItem;
}
void AnnotatePlugin::addPolyline()
{
m_drawingPolyline = true;
m_polylinePlacemark = new GeoDataPlacemark;
m_polylinePlacemark->setGeometry( new GeoDataLineString( Tessellate ) );
m_polylinePlacemark->setParent( m_annotationDocument );
m_polylinePlacemark->setStyleUrl(QStringLiteral("#polyline"));
m_marbleWidget->model()->treeModel()->addFeature( m_annotationDocument, m_polylinePlacemark );
PolylineAnnotation *polyline = new PolylineAnnotation( m_polylinePlacemark );
polyline->setState( SceneGraphicsItem::DrawingPolyline );
polyline->setFocus( true );
m_graphicsItems.append( polyline );
m_marbleWidget->update();
QPointer dialog = new EditPolylineDialog( m_polylinePlacemark, &m_osmRelations, m_marbleWidget );
connect( dialog, SIGNAL(polylineUpdated(GeoDataFeature*)),
m_marbleWidget->model()->treeModel(), SLOT(updateFeature(GeoDataFeature*)) );
connect( dialog, SIGNAL(finished(int)),
this, SLOT(stopEditingPolyline(int)) );
connect( this, SIGNAL(nodeAdded(GeoDataCoordinates)), dialog, SLOT(handleAddingNode(GeoDataCoordinates)) );
connect( dialog, SIGNAL( relationCreated( const OsmPlacemarkData& ) ),
this, SLOT( addRelation( const OsmPlacemarkData& ) ) );
if ( m_focusItem ) {
m_focusItem->setFocus( false );
if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicGroundOverlay ) {
clearOverlayFrames();
}
}
m_focusItem = polyline;
m_editedItem = m_focusItem;
disableActions( m_actions.first() );
dialog->move( m_marbleWidget->mapToGlobal( QPoint( 0, 0 ) ) );
dialog->show();
m_editingDialogIsShown = true;
}
void AnnotatePlugin::stopEditingPolyline( int result )
{
m_focusItem = m_editedItem;
m_editedItem = 0;
announceStateChanged( SceneGraphicsItem::Editing );
enableAllActions( m_actions.first() );
disableFocusActions();
if ( !result && m_drawingPolyline ) {
removeFocusItem();
} else {
enableActionsOnItemType( SceneGraphicsTypes::SceneGraphicPolylineAnnotation );
}
m_editingDialogIsShown = false;
m_drawingPolyline = false;
m_polylinePlacemark = 0;
}
void AnnotatePlugin::addRelation( const OsmPlacemarkData &relationData )
{
m_osmRelations.insert( relationData.id(), relationData );
}
void AnnotatePlugin::announceStateChanged( SceneGraphicsItem::ActionState newState )
{
for ( SceneGraphicsItem *item: m_graphicsItems ) {
item->setState( newState );
m_marbleWidget->model()->treeModel()->updateFeature( item->placemark() );
}
}
void AnnotatePlugin::setupCursor( SceneGraphicsItem *item )
{
if ( !item || item->state() == SceneGraphicsItem::AddingNodes ) {
m_marbleWidget->setCursor( Qt::DragCopyCursor );
} else {
// Nothing to do. The other cursor changes were moved to the handleRequests() section.
}
}
void AnnotatePlugin::cutItem()
{
disableFocusActions();
// If there is already an item copied/cut, free its memory and replace it with this one.
// The same applies when copying.
if ( m_clipboardItem ) {
delete m_clipboardItem->placemark();
delete m_clipboardItem;
m_clipboardItem = 0;
}
m_clipboardItem = m_focusItem;
m_pasteGraphicItem->setVisible( true );
m_graphicsItems.removeAll( m_focusItem );
m_marbleWidget->model()->treeModel()->removeFeature( m_focusItem->placemark() );
m_focusItem = 0;
}
void AnnotatePlugin::copyItem()
{
if ( m_clipboardItem ) {
delete m_clipboardItem->placemark();
delete m_clipboardItem;
m_clipboardItem = 0;
}
// Just copy the placemark and instantiate a new object based on its graphic type.
// FIXME: Here is obvious a problem in the case of AreaAnnotation (when copying a
// placemark which has a GeoDataPolygon geometry?). Later Edit: The same applies for
// polylines (GeoDataLineString geometries).
GeoDataPlacemark *placemark = new GeoDataPlacemark( *m_focusItem->placemark() );
if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicAreaAnnotation ) {
m_clipboardItem = new AreaAnnotation( placemark );
} else if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicTextAnnotation ) {
m_clipboardItem = new PlacemarkTextAnnotation( placemark );
} else if ( m_focusItem->graphicType() == SceneGraphicsTypes::SceneGraphicPolylineAnnotation ) {
m_clipboardItem = new PolylineAnnotation( placemark );
}
m_pasteGraphicItem->setVisible( true );
}
void AnnotatePlugin::pasteItem()
{
const QPoint eventPoint = m_marbleWidget->popupMenu()->mousePosition();
qreal lon, lat;
m_marbleWidget->geoCoordinates( eventPoint.x(), eventPoint.y(), lon, lat, GeoDataCoordinates::Radian );
const GeoDataCoordinates newCoords( lon, lat );
m_clipboardItem->move( m_fromWhereToCopy, newCoords );
m_marbleWidget->model()->treeModel()->addFeature( m_annotationDocument, m_clipboardItem->placemark() );
m_graphicsItems.append( m_clipboardItem );
m_clipboardItem->setFocus( true );
enableActionsOnItemType( m_clipboardItem->graphicType() );
m_focusItem = m_clipboardItem;
m_clipboardItem = 0;
m_pasteGraphicItem->setVisible( false );
}
const GeoDataCoordinates AnnotatePlugin::mouseGeoDataCoordinates( QMouseEvent *mouseEvent )
{
qreal lon, lat;
m_marbleWidget->geoCoordinates( mouseEvent->pos().x(),
mouseEvent->pos().y(),
lon, lat,
GeoDataCoordinates::Radian );
return GeoDataCoordinates( lon, lat );
}
}
#include "moc_AnnotatePlugin.cpp"
diff --git a/src/plugins/render/annotate/AnnotatePlugin.h b/src/plugins/render/annotate/AnnotatePlugin.h
index 8c5996ae6..6b8b9b58b 100644
--- a/src/plugins/render/annotate/AnnotatePlugin.h
+++ b/src/plugins/render/annotate/AnnotatePlugin.h
@@ -1,215 +1,217 @@
//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2009 Andrew Manson
// Copyright 2013 Thibaut Gridel
// Copyright 2014 Calin Cruceru
//
#ifndef MARBLE_ANNOTATEPLUGIN_H
#define MARBLE_ANNOTATEPLUGIN_H
#include "RenderPlugin.h"
#include "SceneGraphicsItem.h"
#include "GeoDataGroundOverlay.h"
#include "GroundOverlayFrame.h"
#include
#include
namespace Marble
{
class MarbleWidget;
class GeoDataDocument;
class GeoDataLinearRing;
class AreaAnnotation;
class PolylineAnnotation;
class PlacemarkTextAnnotation;
class OsmPlacemarkData;
/**
* @brief This class specifies the Marble layer interface of a plugin which
* annotates maps with polygons and placemarks.
*/
class AnnotatePlugin : public RenderPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.kde.marble.AnnotatePlugin")
Q_INTERFACES( Marble::RenderPluginInterface )
MARBLE_PLUGIN( AnnotatePlugin )
public:
explicit AnnotatePlugin(const MarbleModel *model = 0);
~AnnotatePlugin() override;
QStringList backendTypes() const override;
QString renderPolicy() const override;
QStringList renderPosition() const override;
QString name() const override;
QString guiString() const override;
QString nameId() const override;
QString version() const override;
QString description() const override;
QIcon icon () const override;
QString copyrightYears() const override;
QVector pluginAuthors() const override;
void initialize () override;
bool isInitialized () const override;
QString runtimeTrace() const override;
const QList *actionGroups() const override;
bool render( GeoPainter *painter, ViewportParams *viewport,
const QString &renderPos, GeoSceneLayer *layer = 0 ) override;
Q_SIGNALS:
void placemarkMoved();
void nodeAdded( const GeoDataCoordinates &coordinates );
void itemMoved( GeoDataPlacemark *placemark );
void mouseMoveGeoPosition( const QString& );
private Q_SLOTS:
void enableModel( bool enabled );
void askToRemoveFocusItem();
void removeFocusItem();
void clearAnnotations();
void saveAnnotationFile();
void loadAnnotationFile();
+ void openAnnotationFile(const QString&);
void copyItem();
void cutItem();
void pasteItem();
void addTextAnnotation();
void editTextAnnotation();
void stopEditingTextAnnotation( int result );
void addOverlay();
void editOverlay();
void removeOverlay();
void updateOverlayFrame( GeoDataGroundOverlay *overlay );
void addPolygon();
void stopEditingPolygon( int result );
void setAddingPolygonHole( bool enabled );
void setAddingNodes( bool enabled );
void editPolygon();
void selectNode();
void deleteNode();
void deselectNodes();
void deleteSelectedNodes();
void setAreaAvailable();
void addPolyline();
void editPolyline();
void stopEditingPolyline( int result );
void setPolylineAvailable();
void addRelation( const OsmPlacemarkData &relationOsmData );
+ void downloadOsm();
protected:
bool eventFilter( QObject *watched, QEvent *event ) override;
private:
void addContextItems();
void setupActions( MarbleWidget *marbleWidget );
void disableActions( QActionGroup *group );
void enableAllActions( QActionGroup *group );
void enableActionsOnItemType( const QString &type );
void disableFocusActions();
void setupTextAnnotationRmbMenu();
void showTextAnnotationRmbMenu( qreal x, qreal y );
void setupGroundOverlayModel();
void setupOverlayRmbMenu();
void showOverlayRmbMenu( GeoDataGroundOverlay *overlay, qreal x, qreal y );
void displayOverlayFrame( GeoDataGroundOverlay *overlay );
void clearOverlayFrames();
void setupPolygonRmbMenu();
void setupNodeRmbMenu();
void showPolygonRmbMenu( qreal x, qreal y );
void showNodeRmbMenu( qreal x, qreal y );
void setupPolylineRmbMenu();
void showPolylineRmbMenu( qreal x, qreal y );
void handleUncaughtEvents( QMouseEvent *mouseEvent );
void handleReleaseOverlay( QMouseEvent *mouseEvent );
bool handleDrawingPolyline( QMouseEvent *mouseEvent );
bool handleDrawingPolygon( QMouseEvent *mouseEvent );
bool handleMovingSelectedItem( QMouseEvent *mouseEvent );
void handleRequests( QMouseEvent *mouseEvent, SceneGraphicsItem *item );
void handleSuccessfulPressEvent( QMouseEvent *mouseEvent, SceneGraphicsItem *item );
void handleSuccessfulHoverEvent( QMouseEvent *mouseEvent, SceneGraphicsItem *item );
void handleSuccessfulReleaseEvent( QMouseEvent *mouseEvent, SceneGraphicsItem *item );
void announceStateChanged( SceneGraphicsItem::ActionState newState );
void setupCursor( SceneGraphicsItem *item );
const GeoDataCoordinates mouseGeoDataCoordinates( QMouseEvent *mouseEvent );
bool m_isInitialized;
bool m_widgetInitialized;
MarbleWidget *m_marbleWidget;
QMenu *m_overlayRmbMenu;
QMenu *m_polygonRmbMenu;
QMenu *m_nodeRmbMenu;
QMenu *m_textAnnotationRmbMenu;
QMenu *m_polylineRmbMenu;
QList m_actions;
QSortFilterProxyModel m_groundOverlayModel;
QMap m_groundOverlayFrames;
// A list of all osm relations
QHash m_osmRelations;
GeoDataDocument* m_annotationDocument;
QList m_graphicsItems;
SceneGraphicsItem *m_movedItem;
SceneGraphicsItem *m_focusItem;
SceneGraphicsItem *m_editedItem;
GeoDataGroundOverlay *m_rmbOverlay;
GeoDataPlacemark *m_polylinePlacemark;
GeoDataPlacemark *m_polygonPlacemark;
GeoDataCoordinates m_fromWhereToCopy;
SceneGraphicsItem *m_clipboardItem;
QAction *m_pasteGraphicItem;
bool m_drawingPolygon;
bool m_drawingPolyline;
bool m_addingPlacemark;
bool m_editingDialogIsShown;
};
}
#endif // MARBLE_ANNOTATEPLUGIN_H
diff --git a/src/plugins/render/annotate/CMakeLists.txt b/src/plugins/render/annotate/CMakeLists.txt
index beefb9071..588041ac2 100644
--- a/src/plugins/render/annotate/CMakeLists.txt
+++ b/src/plugins/render/annotate/CMakeLists.txt
@@ -1,36 +1,38 @@
PROJECT( AnnotatePlugin )
INCLUDE_DIRECTORIES(
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/src/lib/marble/geodata/handlers/kml
${CMAKE_SOURCE_DIR}/src/lib/marble/layers
)
set( annotate_UI
EditGroundOverlayDialog.ui
EditPolygonDialog.ui
EditPolylineDialog.ui
+ DownloadOsmDialog.ui
)
set( annotate_SRCS
AnnotatePlugin.cpp
AreaAnnotation.cpp
+ DownloadOsmDialog.cpp
EditGroundOverlayDialog.cpp
EditPolygonDialog.cpp
NodeItemDelegate.cpp
EditPolylineDialog.cpp
GroundOverlayFrame.cpp
MergingPolygonNodesAnimation.cpp
MergingPolylineNodesAnimation.cpp
PlacemarkTextAnnotation.cpp
PolylineAnnotation.cpp
PolylineNode.cpp
SceneGraphicsItem.cpp
SceneGraphicsTypes.cpp
NodeModel.cpp
)
qt_wrap_ui(annotate_SRCS ${annotate_UI})
marble_add_plugin( AnnotatePlugin ${annotate_SRCS} )
diff --git a/src/plugins/render/annotate/DownloadOsmDialog.cpp b/src/plugins/render/annotate/DownloadOsmDialog.cpp
new file mode 100644
index 000000000..19d98fde4
--- /dev/null
+++ b/src/plugins/render/annotate/DownloadOsmDialog.cpp
@@ -0,0 +1,177 @@
+//
+// This file is part of the Marble Virtual Globe.
+//
+// This program is free software licensed under the GNU LGPL. You can
+// find a copy of this license in LICENSE.txt in the top directory of
+// the source code.
+//
+// Copyright 2017 Sutirtha Ghosh
+//
+
+//Self
+#include "DownloadOsmDialog.h"
+
+//Qt
+#include
+#include
+#include
+#include
+#include
+#include
+
+//Marble
+#include "ui_DownloadOsmDialog.h"
+#include "MarbleWidget.h"
+#include "ViewParams.h"
+#include "ViewportParams.h"
+#include "GeoDataLatLonAltBox.h"
+#include "GeoDataLatLonBox.h"
+#include "MarbleGlobal.h"
+#include "AnnotatePlugin.h"
+#include "LatLonBoxWidget.h"
+
+namespace Marble
+{
+DownloadOsmDialog::DownloadOsmDialog(MarbleWidget *parent,AnnotatePlugin *annotatePlugin) :
+ QDialog(parent),
+ m_marbleWidget(parent),
+ m_latLonBoxWidget(new LatLonBoxWidget)
+{
+ QPushButton *m_quitButton;
+ setupUi(this);
+ horizontalLayout->addWidget(m_latLonBoxWidget);
+ this->setWindowTitle("Download");
+ connect(m_marbleWidget,
+ SIGNAL(visibleLatLonAltBoxChanged(GeoDataLatLonAltBox)),
+ this,
+ SLOT(updateCoordinates(GeoDataLatLonAltBox) )
+ );
+
+ m_downloadButton = new QPushButton(tr("Download"));
+ m_downloadButton->setDefault(true);
+ m_quitButton = new QPushButton(tr("Cancel"));
+ m_quitButton->setAutoDefault(false);
+
+ buttonBox->addButton(m_downloadButton,QDialogButtonBox::ActionRole);
+ buttonBox->addButton(m_quitButton,QDialogButtonBox::RejectRole);
+
+ connect( m_downloadButton, SIGNAL(clicked(bool)), this, SLOT(downloadFile()) );
+ connect( m_quitButton, SIGNAL(clicked(bool)), this, SLOT(close()) );
+ connect( this, SIGNAL(openFile(QString)), annotatePlugin, SLOT(openAnnotationFile(QString)) );
+
+ progressBar->hide();
+ updateCoordinates();
+}
+
+DownloadOsmDialog::~DownloadOsmDialog()
+{
+
+}
+
+void DownloadOsmDialog::updateCoordinates()
+{
+
+ m_latLonBoxWidget->setLatLonBox( m_marbleWidget->viewport()->viewLatLonAltBox() );
+}
+
+void DownloadOsmDialog::updateCoordinates( const GeoDataLatLonAltBox& boundingBox )
+{
+ m_latLonBoxWidget->setLatLonBox( boundingBox );
+}
+
+void DownloadOsmDialog::downloadFile()
+{
+ QString m_west;
+ QString m_south;
+ QString m_east;
+ QString m_north;
+ QString url;
+ m_isDownloadSuccess=false;
+ m_file = new QTemporaryFile(QDir::tempPath()+"/"+"XXXXXXosmdata.osm");
+ if(!m_file->open())
+ {
+ QMessageBox::information(this, tr("ERROR"),
+ "Unable to create temporary file to download OSM data to.");
+ this->close();
+ }
+ m_downloadButton->setEnabled(false);
+
+ m_west=QString::number( m_latLonBoxWidget->latLonBox().west()*RAD2DEG );
+ m_south=QString::number( m_latLonBoxWidget->latLonBox().south()*RAD2DEG );
+ m_east=QString::number( m_latLonBoxWidget->latLonBox().east()*RAD2DEG );
+ m_north=QString::number( m_latLonBoxWidget->latLonBox().north()*RAD2DEG );
+
+ url="http://api.openstreetmap.org/api/0.6/map?bbox=";
+ url+=m_west+",";
+ url+=m_south+",";
+ url+=m_east+",";
+ url+=m_north;
+
+ m_reply = m_qnam.get(QNetworkRequest(QUrl(url)));
+
+ connect( m_reply, SIGNAL(finished()), this, SLOT(httpFinished()) );
+ connect( m_reply, SIGNAL(readyRead()), this, SLOT(httpReadyRead()) );
+
+ progressBar->show();
+ progressBar->setMinimum(0);
+ progressBar->setMaximum(0);
+}
+
+void DownloadOsmDialog::httpReadyRead()
+{
+ //Reads all the data present and writes it to the file whenever data is
+ //available
+ if ( m_file ){
+ m_file->write(m_reply->readAll());
+ }
+}
+
+void DownloadOsmDialog::httpFinished()
+{
+ QVariant statusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
+ int status = statusCode.toInt();
+ //in case download fails due to network error or server not available
+ if ( m_reply->error()==QNetworkReply::NoError ){
+ m_isDownloadSuccess=true;
+ }
+ else {
+ switch(status)
+ {
+ case 400:
+ QMessageBox::information(this, tr("ERROR"),
+ "The selected region contains too much data.Please select a smaller region and try again.");
+ m_downloadButton->setEnabled(true);
+ m_isDownloadSuccess=false;
+ break;
+ case 509:
+ QMessageBox::information(this, tr("ERROR"),
+ "The bandwidth limit exceeded.Please try again later.");
+ m_downloadButton->setEnabled(true);
+ m_isDownloadSuccess=false;
+ break;
+ default:
+ QMessageBox::information(this, tr("ERROR"),"Sorry, a network error occured.Please check your internet connection"
+ " or try again later.");
+ m_downloadButton->setEnabled(true);
+ m_isDownloadSuccess=false;
+ break;
+ }
+ }
+
+ progressBar->hide();
+ m_file->flush();
+ m_file->close();
+ if( m_isDownloadSuccess ) {
+ emit openFile(m_file->fileName());
+ }
+ m_reply->deleteLater();
+ m_reply=0;
+ delete m_file;
+ m_file=0;
+ if( m_isDownloadSuccess ) {
+ this->close();
+ }
+}
+
+}
+#include "moc_DownloadOsmDialog.cpp"
diff --git a/src/plugins/render/annotate/DownloadOsmDialog.h b/src/plugins/render/annotate/DownloadOsmDialog.h
new file mode 100644
index 000000000..c4614a749
--- /dev/null
+++ b/src/plugins/render/annotate/DownloadOsmDialog.h
@@ -0,0 +1,58 @@
+//
+// This file is part of the Marble Virtual Globe.
+//
+// This program is free software licensed under the GNU LGPL. You can
+// find a copy of this license in LICENSE.txt in the top directory of
+// the source code.
+//
+// Copyright 2017 Sutirtha Ghosh
+//
+
+#ifndef DOWNLOADOSMDIALOG_H
+#define DOWNLOADOSMDIALOG_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+#include "LatLonBoxWidget.h"
+#include "ui_DownloadOsmDialog.h"
+
+namespace Marble
+{
+class MarbleWidget;
+class AnnotatePlugin;
+class DownloadOsmDialog : public QDialog,private Ui::DownloadOsmDialog
+{
+ Q_OBJECT
+
+public:
+ explicit DownloadOsmDialog(MarbleWidget *parent = 0,AnnotatePlugin *annotatePlugin = 0);
+ ~DownloadOsmDialog();
+
+Q_SIGNALS:
+ void openFile(const QString &filename);
+
+private:
+ void updateCoordinates();
+ MarbleWidget *m_marbleWidget;
+ QPushButton *m_downloadButton;
+ QNetworkAccessManager m_qnam;
+ QNetworkReply *m_reply;
+ QTemporaryFile *m_file;
+ LatLonBoxWidget *m_latLonBoxWidget;
+ bool m_isDownloadSuccess;
+
+private Q_SLOTS:
+ void downloadFile();
+ void updateCoordinates(const GeoDataLatLonAltBox&);
+ void httpReadyRead();
+ void httpFinished();
+};
+
+}
+#endif // DOWNLOADOSMDIALOG_H
diff --git a/src/plugins/render/annotate/DownloadOsmDialog.ui b/src/plugins/render/annotate/DownloadOsmDialog.ui
new file mode 100644
index 000000000..3e612109d
--- /dev/null
+++ b/src/plugins/render/annotate/DownloadOsmDialog.ui
@@ -0,0 +1,105 @@
+
+
+DownloadOsmDialog
+
+
+
+ 0
+ 0
+ 461
+ 323
+
+
+
+ Dialog
+
+
+
+
+ 10
+ 260
+ 441
+ 32
+
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::NoButton
+
+
+
+
+
+ 20
+ 230
+ 431
+ 23
+
+
+
+ 0
+
+
+
+
+
+ 0
+ 210
+ 701
+ 16
+
+
+
+ Qt::Horizontal
+
+
+
+
+
+ 10
+ 10
+ 441
+ 201
+
+
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ DownloadOsmDialog
+ accept()
+
+
+ 248
+ 254
+
+
+ 157
+ 274
+
+
+
+
+ buttonBox
+ rejected()
+ DownloadOsmDialog
+ reject()
+
+
+ 316
+ 260
+
+
+ 286
+ 274
+
+
+
+
+