1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 //
3 // SPDX-FileCopyrightText: 2012 Dennis Nienhüser <nienhueser@kde.org>
4 //
5 
6 #include "Bookmarks.h"
7 
8 #include "Planet.h"
9 #include "MarbleQuickItem.h"
10 #include "MarbleModel.h"
11 #include "MarblePlacemarkModel.h"
12 #include "BookmarkManager.h"
13 #include "GeoDataDocument.h"
14 #include "GeoDataPlacemark.h"
15 #include "GeoDataFolder.h"
16 #include "GeoDataTypes.h"
17 #include "GeoDataExtendedData.h"
18 #include "GeoDataTreeModel.h"
19 #include "kdescendantsproxymodel.h"
20 #include "osm/OsmPlacemarkData.h"
21 
22 
23 namespace Marble {
24 
Bookmarks(QObject * parent)25 Bookmarks::Bookmarks( QObject* parent ) : QObject( parent ),
26     m_marbleQuickItem( nullptr ), m_proxyModel( nullptr )
27 {
28     // nothing to do
29 }
30 
map()31 MarbleQuickItem *Bookmarks::map()
32 {
33     return m_marbleQuickItem;
34 }
35 
setMap(MarbleQuickItem * item)36 void Bookmarks::setMap( MarbleQuickItem* item )
37 {
38     m_marbleQuickItem = item;
39     if (item) {
40         connect(item->model()->bookmarkManager(), SIGNAL(bookmarksChanged()),
41                 this, SLOT(updateBookmarkDocument()));
42     }
43     updateBookmarkDocument();
44     emit modelChanged();
45 }
46 
isBookmark(qreal longitude,qreal latitude) const47 bool Bookmarks::isBookmark( qreal longitude, qreal latitude ) const
48 {
49     if ( !m_marbleQuickItem || !m_marbleQuickItem->model()->bookmarkManager() ) {
50         return false;
51     }
52 
53     Marble::BookmarkManager* manager = m_marbleQuickItem->model()->bookmarkManager();
54     Marble::GeoDataDocument *bookmarks = manager->document();
55     Marble::GeoDataCoordinates const compareTo( longitude, latitude, 0.0, Marble::GeoDataCoordinates::Degree );
56 
57     qreal planetRadius = m_marbleQuickItem->model()->planet()->radius();
58     for( const Marble::GeoDataFolder* folder: bookmarks->folderList() ) {
59         for( const Marble::GeoDataPlacemark * const placemark: folder->placemarkList() ) {
60             if (placemark->coordinate().sphericalDistanceTo(compareTo) * planetRadius < 5) {
61                 return true;
62             }
63         }
64     }
65 
66     return false;
67 }
68 
placemark(int row)69 Placemark *Bookmarks::placemark(int row)
70 {
71     Placemark* placemark = new Placemark;
72 
73     QModelIndex index = model()->index(row, 0);
74     GeoDataObject *object = model()->data(index, MarblePlacemarkModel::ObjectPointerRole ).value<GeoDataObject*>();
75     if (GeoDataPlacemark *geoDataPlacemark = geodata_cast<GeoDataPlacemark>(object)) {
76         placemark->setGeoDataPlacemark(*geoDataPlacemark);
77     }
78 
79     return placemark;
80 }
81 
addBookmark(Placemark * placemark,const QString & folderName)82 void Bookmarks::addBookmark(Placemark *placemark, const QString &folderName )
83 {
84     if ( !m_marbleQuickItem || !m_marbleQuickItem->model()->bookmarkManager() ) {
85         return;
86     }
87 
88     Marble::BookmarkManager* manager = m_marbleQuickItem->model()->bookmarkManager();
89     Marble::GeoDataDocument *bookmarks = manager->document();
90     Marble::GeoDataContainer *target = nullptr;
91     for( Marble::GeoDataFolder* const folder: bookmarks->folderList() ) {
92         if ( folder->name() == folderName ) {
93             target = folder;
94             break;
95         }
96     }
97 
98     if ( !target ) {
99         manager->addNewBookmarkFolder( bookmarks, folderName );
100 
101         for( Marble::GeoDataFolder* const folder: bookmarks->folderList() ) {
102             if ( folder->name() == folderName ) {
103                 target = folder;
104                 break;
105             }
106         }
107 
108         Q_ASSERT( target );
109     }
110 
111     Marble::GeoDataPlacemark bookmark = placemark->placemark();
112     if (bookmark.name().isEmpty()) {
113         bookmark.setName(placemark->address());
114     }
115     if (bookmark.name().isEmpty()) {
116         bookmark.setName(bookmark.coordinate().toString(GeoDataCoordinates::Decimal).trimmed());
117     }
118     bookmark.clearOsmData();
119     bookmark.setCoordinate(bookmark.coordinate()); // replace non-point geometries with their center
120     manager->addBookmark( target, bookmark );
121 }
122 
removeBookmark(qreal longitude,qreal latitude)123 void Bookmarks::removeBookmark( qreal longitude, qreal latitude )
124 {
125     if ( !m_marbleQuickItem || !m_marbleQuickItem->model()->bookmarkManager() ) {
126         return;
127     }
128 
129     Marble::BookmarkManager* manager = m_marbleQuickItem->model()->bookmarkManager();
130     Marble::GeoDataDocument *bookmarks = manager->document();
131     Marble::GeoDataCoordinates const compareTo( longitude, latitude, 0.0, Marble::GeoDataCoordinates::Degree );
132 
133     qreal planetRadius = m_marbleQuickItem->model()->planet()->radius();
134     for( const Marble::GeoDataFolder* folder: bookmarks->folderList() ) {
135         for( Marble::GeoDataPlacemark * placemark: folder->placemarkList() ) {
136             if (placemark->coordinate().sphericalDistanceTo(compareTo) * planetRadius < 5) {
137                 manager->removeBookmark( placemark );
138                 return;
139             }
140         }
141     }
142 }
143 
updateBookmarkDocument()144 void Bookmarks::updateBookmarkDocument()
145 {
146     if (m_marbleQuickItem) {
147         Marble::BookmarkManager* manager = m_marbleQuickItem->model()->bookmarkManager();
148         m_treeModel.setRootDocument( manager->document() );
149     }
150 }
151 
model()152 BookmarksModel *Bookmarks::model()
153 {
154     if ( !m_proxyModel && m_marbleQuickItem && m_marbleQuickItem->model()->bookmarkManager() ) {
155         KDescendantsProxyModel* flattener = new KDescendantsProxyModel( this );
156         flattener->setSourceModel(&m_treeModel);
157 
158         m_proxyModel = new BookmarksModel( this );
159         m_proxyModel->setFilterFixedString( Marble::GeoDataTypes::GeoDataPlacemarkType );
160         m_proxyModel->setFilterKeyColumn( 1 );
161         m_proxyModel->setSourceModel( flattener );
162     }
163 
164     return m_proxyModel;
165 }
166 
BookmarksModel(QObject * parent)167 BookmarksModel::BookmarksModel( QObject *parent ) : QSortFilterProxyModel( parent )
168 {
169     connect( this, SIGNAL(layoutChanged()), this, SIGNAL(countChanged()) );
170     connect( this, SIGNAL(modelReset()), this, SIGNAL(countChanged()) );
171     connect( this, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SIGNAL(countChanged()) );
172     connect( this, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SIGNAL(countChanged()) );
173 }
174 
count() const175 int BookmarksModel::count() const
176 {
177     return rowCount();
178 }
179 
longitude(int idx) const180 qreal BookmarksModel::longitude( int idx ) const
181 {
182     if ( idx >= 0 && idx < rowCount() ) {
183         QVariant const value = data( index( idx, 0 ), Marble::MarblePlacemarkModel::CoordinateRole );
184         Marble::GeoDataCoordinates const coordinates = value.value<Marble::GeoDataCoordinates>();
185         return coordinates.longitude( Marble::GeoDataCoordinates::Degree );
186     }
187     return 0.0;
188 }
189 
latitude(int idx) const190 qreal BookmarksModel::latitude( int idx ) const
191 {
192     if ( idx >= 0 && idx < rowCount() ) {
193         QVariant const value = data( index( idx, 0 ), Marble::MarblePlacemarkModel::CoordinateRole );
194         Marble::GeoDataCoordinates const coordinates = value.value<Marble::GeoDataCoordinates>();
195         return coordinates.latitude( Marble::GeoDataCoordinates::Degree );
196     }
197     return 0.0;
198 }
199 
name(int idx) const200 QString BookmarksModel::name( int idx ) const
201 {
202     if ( idx >= 0 && idx < rowCount() ) {
203         return data( index( idx, 0 ) ).toString();
204     }
205     return QString();
206 }
207 
208 }
209 
210 #include "moc_Bookmarks.cpp"
211