File indexing completed on 2024-04-21 03:49:28

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2010 Gaurav Gupta <1989.gaurav@googlemail.com>
0004 // SPDX-FileCopyrightText: 2012 Thibaut Gridel <tgridel@free.fr>
0005 //
0006 
0007 #include "BookmarkManager.h"
0008 #include "BookmarkManager_p.h"
0009 #include "GeoDataParser.h"
0010 #include "GeoDataContainer.h"
0011 #include "GeoDataDocument.h"
0012 #include "GeoDataFolder.h"
0013 #include "GeoDataPlacemark.h"
0014 #include "GeoDataTreeModel.h"
0015 #include "GeoDataDocumentWriter.h"
0016 #include "GeoDataIconStyle.h"
0017 #include "KmlElementDictionary.h"
0018 #include "MarbleDebug.h"
0019 #include "MarbleDirs.h"
0020 #include "StyleBuilder.h"
0021 #include <QFile>
0022 
0023 namespace Marble
0024 {
0025 
0026 BookmarkManagerPrivate::BookmarkManagerPrivate( GeoDataTreeModel *treeModel ) :
0027     m_treeModel( treeModel ),
0028     m_bookmarkDocument( nullptr ),
0029     m_bookmarkFileRelativePath( "bookmarks/bookmarks.kml" ),
0030     m_styleBuilder(nullptr)
0031 {
0032     resetBookmarkDocument();
0033 }
0034 
0035 BookmarkManagerPrivate::~BookmarkManagerPrivate()
0036 {
0037     Q_ASSERT( m_bookmarkDocument && "BookmarkManagerPrivate::m_bookmarkDocument is 0. Please report a Marble bug at https://bugs.kde.org" );
0038     if ( m_bookmarkDocument )
0039     {
0040         m_treeModel->removeDocument( m_bookmarkDocument );
0041     }
0042     delete m_bookmarkDocument;
0043 }
0044 
0045 void BookmarkManagerPrivate::resetBookmarkDocument()
0046 {
0047     if ( m_bookmarkDocument ) {
0048         m_treeModel->removeDocument( m_bookmarkDocument );
0049         delete m_bookmarkDocument;
0050     }
0051 
0052     GeoDataFolder* folder = new GeoDataFolder;
0053     folder->setName( QObject::tr( "Default" ) );
0054 
0055     m_bookmarkDocument = new GeoDataDocument;
0056     m_bookmarkDocument->setDocumentRole( BookmarkDocument );
0057     m_bookmarkDocument->setName( QObject::tr("Bookmarks") );
0058     m_bookmarkDocument->append( folder );
0059     m_treeModel->addDocument( m_bookmarkDocument );
0060 }
0061 
0062 void BookmarkManagerPrivate::setVisualCategory( GeoDataContainer *container ) {
0063     for( GeoDataFolder* folder: container->folderList() ) {
0064         setVisualCategory( folder );
0065     }
0066     for( GeoDataPlacemark* placemark: container->placemarkList() ) {
0067         placemark->setVisualCategory(GeoDataPlacemark::Bookmark);
0068         placemark->setZoomLevel( 1 );
0069     }
0070 
0071 }
0072 
0073 BookmarkManager::BookmarkManager( GeoDataTreeModel *treeModel, QObject *parent ) :
0074     QObject( parent ),
0075     d( new BookmarkManagerPrivate( treeModel ) )
0076 {
0077 }
0078 
0079 BookmarkManager::~BookmarkManager()
0080 {
0081     delete d;
0082 }
0083 
0084 QString BookmarkManager::bookmarkFile() const
0085 {
0086     return MarbleDirs::path( d->m_bookmarkFileRelativePath );
0087 }
0088 
0089 bool BookmarkManager::loadFile( const QString &relativeFilePath )
0090 {
0091     d->m_bookmarkFileRelativePath = relativeFilePath;
0092     QString absoluteFilePath = bookmarkFile();
0093 
0094     mDebug() << "Loading Bookmark File:" << absoluteFilePath;
0095 
0096     if (absoluteFilePath.isEmpty())
0097         return false;
0098 
0099     if ( relativeFilePath.isNull() )
0100         return false;
0101 
0102     GeoDataDocument *document = openFile( absoluteFilePath );
0103     bool recover = false;
0104     if ( !document ) {
0105         mDebug() << "Could not parse file" << absoluteFilePath;
0106         mDebug() << "This could be caused by a previous broken bookmark file. Trying to recover.";
0107         /** @todo: Remove this workaround and return false around Marble 1.4 */
0108         recover = true;
0109         // return false;
0110     }
0111 
0112     d->m_treeModel->removeDocument( d->m_bookmarkDocument );
0113     delete d->m_bookmarkDocument;
0114     d->m_bookmarkDocument = document;
0115 
0116     if ( recover ) {
0117         d->resetBookmarkDocument();
0118         updateBookmarkFile();
0119     } else {
0120         Q_ASSERT( d->m_bookmarkDocument && "d->m_bookmarkDocument is 0 but must not be. Please report a bug at https://bugs.kde.org" );
0121         d->m_treeModel->addDocument( d->m_bookmarkDocument );
0122     }
0123     ensureDefaultFolder();
0124 
0125     emit bookmarksChanged();
0126     return true;
0127 }
0128 
0129 void BookmarkManager::addBookmark( GeoDataContainer *container, const GeoDataPlacemark &placemark )
0130 {
0131     GeoDataPlacemark *bookmark = new GeoDataPlacemark( placemark );
0132     bookmark->setVisualCategory(GeoDataPlacemark::Bookmark);
0133     bookmark->setZoomLevel( 1 );
0134     if (bookmark->name().isEmpty()) {
0135         bookmark->setName(bookmark->coordinate().toString(GeoDataCoordinates::Decimal).trimmed());
0136     }
0137     if (d->m_styleBuilder && bookmark->style()->iconStyle().iconPath().isEmpty()) {
0138         StyleParameters style;
0139         style.placemark = bookmark;
0140         bookmark->setStyle(GeoDataStyle::Ptr(new GeoDataStyle(*d->m_styleBuilder->createStyle(style))));
0141     }
0142     d->m_treeModel->addFeature( container, bookmark );
0143 
0144     updateBookmarkFile();
0145 }
0146 
0147 void BookmarkManager::updateBookmark( GeoDataPlacemark *bookmark )
0148 {
0149     d->m_treeModel->updateFeature( bookmark );
0150 }
0151 
0152 void BookmarkManager::removeBookmark( GeoDataPlacemark *bookmark )
0153 {
0154     d->m_treeModel->removeFeature( bookmark );
0155     delete bookmark;
0156     updateBookmarkFile();
0157 }
0158 
0159 GeoDataPlacemark* BookmarkManager::bookmarkAt(GeoDataContainer *container, const GeoDataCoordinates &coordinate)
0160 {
0161     for ( GeoDataFolder *folder: container->folderList() ) {
0162         GeoDataPlacemark *placemark = bookmarkAt(folder, coordinate);
0163         if ( placemark )
0164             return placemark;
0165     }
0166 
0167     for ( GeoDataPlacemark *placemark: container->placemarkList() ) {
0168         if ( placemark->coordinate() == coordinate )
0169             return placemark;
0170     }
0171 
0172     return Q_NULLPTR;
0173 }
0174 
0175 GeoDataDocument * BookmarkManager::document()
0176 {
0177     return d->m_bookmarkDocument;
0178 }
0179 
0180 const GeoDataDocument * BookmarkManager::document() const
0181 {
0182     return d->m_bookmarkDocument;
0183 }
0184 
0185 bool BookmarkManager::showBookmarks() const
0186 {
0187     return d->m_bookmarkDocument->isVisible();
0188 }
0189 
0190 void BookmarkManager::setShowBookmarks( bool visible )
0191 {
0192     d->m_bookmarkDocument->setVisible( visible );
0193     d->m_treeModel->updateFeature( d->m_bookmarkDocument );
0194 }
0195 
0196 QVector<GeoDataFolder*> BookmarkManager::folders() const
0197 {
0198     return d->m_bookmarkDocument->folderList();
0199 }
0200 
0201 GeoDataFolder* BookmarkManager::addNewBookmarkFolder( GeoDataContainer *container, const QString &name )
0202 {
0203     //If name is empty string
0204     if ( name.isEmpty() ) {
0205         mDebug() << "Folder with empty name is not acceptable, please give it another name" ;
0206         return Q_NULLPTR;
0207     }
0208 
0209     //If folder with same name already exist
0210     QVector<GeoDataFolder*> folderList = container->folderList();
0211 
0212     QVector<GeoDataFolder*>::const_iterator i = folderList.constBegin();
0213     QVector<GeoDataFolder*>::const_iterator end = folderList.constEnd();
0214     for ( ; i != end; ++i ) {
0215         if ( name == ( *i )->name() ) {
0216             mDebug() << "Folder with same name already exist, please give it another name";
0217             return *i;
0218         }
0219     }
0220 
0221     GeoDataFolder *bookmarkFolder = new GeoDataFolder();
0222     bookmarkFolder->setName( name );
0223 
0224     d->m_treeModel->addFeature( container, bookmarkFolder );
0225     updateBookmarkFile();
0226 
0227     return bookmarkFolder;
0228 }
0229 
0230 void BookmarkManager::renameBookmarkFolder( GeoDataFolder *folder, const QString &name )
0231 {
0232     folder->setName( name );
0233     d->m_treeModel->updateFeature( folder );
0234 }
0235 
0236 void BookmarkManager::removeBookmarkFolder( GeoDataFolder *folder )
0237 {
0238     d->m_treeModel->removeFeature( folder );
0239     delete folder;
0240 }
0241 
0242 void BookmarkManager::ensureDefaultFolder()
0243 {
0244     if ( d->m_bookmarkDocument->size() == 0 ) {
0245         addNewBookmarkFolder( d->m_bookmarkDocument, tr("Default") );
0246     }
0247 }
0248 
0249 void BookmarkManager::removeAllBookmarks()
0250 {
0251     d->resetBookmarkDocument();
0252     updateBookmarkFile();
0253 }
0254 
0255 void BookmarkManager::setStyleBuilder(const StyleBuilder *styleBuilder)
0256 {
0257     d->m_styleBuilder = styleBuilder;
0258 }
0259 
0260 bool BookmarkManager::updateBookmarkFile()
0261 {
0262     const QString absoluteLocalFilePath = MarbleDirs::localPath() + QLatin1Char('/') + d->m_bookmarkFileRelativePath;
0263 
0264     if ( ! d->m_bookmarkFileRelativePath.isNull() ) {
0265         QFile file( absoluteLocalFilePath );
0266         if ( !file.exists() ) {
0267             // Extracting directory of file : for bookmarks it will be MarbleDirs::localPath()+/bookmarks/
0268             QFileInfo fileInfo( absoluteLocalFilePath );
0269             QString directoryPath = fileInfo.path();
0270 
0271             //Creating all directories, which doesn't exist
0272             QDir directory(  MarbleDirs::localPath() );
0273             directory.mkpath( directoryPath );
0274         }
0275 
0276         if (!GeoDataDocumentWriter::write(absoluteLocalFilePath, *d->m_bookmarkDocument)) {
0277             mDebug() << "Could not write the bookmarks file" << absoluteLocalFilePath;
0278             file.close();
0279             return false;
0280         }
0281         emit bookmarksChanged();
0282         file.close();
0283         return true;
0284     }
0285     return false;
0286 }
0287 
0288 GeoDataDocument* BookmarkManager::openFile( const QString &fileName )
0289 {
0290     GeoDataParser parser( GeoData_KML );
0291     QFile file( fileName );
0292 
0293     if ( !file.exists() ) {
0294         return nullptr;
0295     }
0296 
0297     if ( !file.open( QIODevice::ReadOnly ) || !parser.read( &file ) ) {
0298         mDebug() << "Could not open/parse file" << fileName;
0299         return nullptr;
0300     }
0301 
0302     GeoDataDocument *result = dynamic_cast<GeoDataDocument*>( parser.releaseDocument() );
0303     if ( !result ) {
0304         return nullptr;
0305     }
0306 
0307     result->setDocumentRole( BookmarkDocument );
0308     for( GeoDataFolder* folder: result->folderList() ) {
0309         BookmarkManagerPrivate::setVisualCategory( folder );
0310     }
0311 
0312     return result;
0313 }
0314 
0315 }
0316 
0317 #include "moc_BookmarkManager.cpp"