Attach a global bookmark manager to QgsApplication

This commit is contained in:
Nyall Dawson 2019-09-03 07:52:30 +10:00
parent 3c9af9ecf0
commit 5db08f0c75
7 changed files with 168 additions and 6 deletions

View File

@ -718,6 +718,12 @@ Returns the application's classification methods registry, used in graduated ren
.. versionadded:: 3.10
%End
static QgsBookmarkManager *bookmarkManager();
%Docstring
Returns the application's bookmark manager, used for storing installation-wide bookmarks.
.. versionadded:: 3.10
%End
static QgsMessageLog *messageLog();
%Docstring

View File

@ -121,6 +121,16 @@ rather accessed through a QgsProject via :py:func:`QgsProject.bookmarkManager()`
explicit QgsBookmarkManager( QgsProject *project /TransferThis/ = 0 );
%Docstring
Constructor for QgsBookmarkManager, with the specified ``parent`` project.
This constructor creates a bookmark manager which stores bookmarks in a QgsProject instance.
%End
explicit QgsBookmarkManager( const QString &settingKey, QObject *parent /TransferThis/ = 0 );
%Docstring
Constructor for QgsBookmarkManager, with the specified ``parent`` object.
This constructor creates a bookmark manager which stores bookmarks in :py:class:`QgsSettings`, using
the specified ``settingKey``.
%End
~QgsBookmarkManager();

View File

@ -41,7 +41,7 @@
#include "qgssymbollayerutils.h"
#include "callouts/qgscalloutsregistry.h"
#include "qgspluginlayerregistry.h"
#include "qgsclassificationmethodregistry.h"
#include "classification/qgsclassificationmethodregistry.h"
#include "qgsmessagelog.h"
#include "qgsannotationregistry.h"
#include "qgssettings.h"
@ -56,6 +56,7 @@
#include "qgsprojutils.h"
#include "qgsvaliditycheckregistry.h"
#include "qgsnewsfeedparser.h"
#include "qgsbookmarkmanager.h"
#include "gps/qgsgpsconnectionregistry.h"
#include "processing/qgsprocessingregistry.h"
@ -1926,6 +1927,11 @@ QgsClassificationMethodRegistry *QgsApplication::classificationMethodRegistry()
return members()->mClassificationMethodRegistry;
}
QgsBookmarkManager *QgsApplication::bookmarkManager()
{
return members()->mBookmarkManager;
}
QgsMessageLog *QgsApplication::messageLog()
{
return members()->mMessageLog;
@ -1990,6 +1996,7 @@ QgsApplication::ApplicationMembers::ApplicationMembers()
mNetworkContentFetcherRegistry = new QgsNetworkContentFetcherRegistry();
mValidityCheckRegistry = new QgsValidityCheckRegistry();
mClassificationMethodRegistry = new QgsClassificationMethodRegistry();
mBookmarkManager = new QgsBookmarkManager( QStringLiteral( "bookmarks" ), nullptr );
}
QgsApplication::ApplicationMembers::~ApplicationMembers()
@ -2018,6 +2025,7 @@ QgsApplication::ApplicationMembers::~ApplicationMembers()
delete mTaskManager;
delete mNetworkContentFetcherRegistry;
delete mClassificationMethodRegistry;
delete mBookmarkManager;
}
QgsApplication::ApplicationMembers *QgsApplication::members()

View File

@ -53,6 +53,7 @@ class QgsNetworkContentFetcherRegistry;
class QgsValidityCheckRegistry;
class QTranslator;
class QgsCalloutRegistry;
class QgsBookmarkManager;
/**
* \ingroup core
@ -644,6 +645,11 @@ class CORE_EXPORT QgsApplication : public QApplication
*/
static QgsClassificationMethodRegistry *classificationMethodRegistry() SIP_KEEPREFERENCE;
/**
* Returns the application's bookmark manager, used for storing installation-wide bookmarks.
* \since QGIS 3.10
*/
static QgsBookmarkManager *bookmarkManager();
/**
* Returns the application's message log.
@ -891,6 +897,7 @@ class CORE_EXPORT QgsApplication : public QApplication
QgsTaskManager *mTaskManager = nullptr;
QgsLayoutItemRegistry *mLayoutItemRegistry = nullptr;
QgsUserProfileManager *mUserConfigManager = nullptr;
QgsBookmarkManager *mBookmarkManager = nullptr;
QString mNullRepresentation;
ApplicationMembers();

View File

@ -15,6 +15,7 @@
#include "qgsbookmarkmanager.h"
#include "qgsproject.h"
#include "qgssettings.h"
#include <QUuid>
//
@ -91,6 +92,25 @@ QgsBookmarkManager::QgsBookmarkManager( QgsProject *project )
}
QgsBookmarkManager::QgsBookmarkManager( const QString &settingKey, QObject *parent )
: QObject( parent )
, mSettingKey( settingKey )
{
// restore state
const QString textXml = QgsSettings().value( settingKey, QString(), QgsSettings::Core ).toString();
if ( !textXml.isEmpty() )
{
QDomDocument doc;
doc.setContent( textXml );
QDomElement elem = doc.documentElement();
readXml( elem, doc );
}
// TODO - convert old bookmarks from db
}
QgsBookmarkManager::~QgsBookmarkManager()
{
clear();
@ -122,7 +142,7 @@ QString QgsBookmarkManager::addBookmark( const QgsBookmark &b, bool *ok )
emit bookmarkAboutToBeAdded( bookmark.id() );
mBookmarks << bookmark;
emit bookmarkAdded( bookmark.id() );
mProject->setDirty( true );
store();
return bookmark.id();
}
@ -149,7 +169,7 @@ bool QgsBookmarkManager::removeBookmark( const QString &id )
emit bookmarkAboutToBeRemoved( id );
mBookmarks.removeAt( pos );
emit bookmarkRemoved( id );
mProject->setDirty( true );
store();
return true;
}
@ -163,7 +183,7 @@ bool QgsBookmarkManager::updateBookmark( const QgsBookmark &bookmark )
{
mBookmarks[i] = bookmark;
emit bookmarkChanged( bookmark.id() );
mProject->setDirty( true );
store();
return true;
}
i++;
@ -205,7 +225,7 @@ bool QgsBookmarkManager::readXml( const QDomElement &element, const QDomDocument
bookmarksElem = element.firstChildElement( QStringLiteral( "Bookmarks" ) );
}
bool result = true;
if ( bookmarksElem.isNull() )
if ( mProject && bookmarksElem.isNull() )
{
// handle legacy projects
const int count = mProject->readNumEntry( QStringLiteral( "Bookmarks" ), QStringLiteral( "/count" ) );
@ -252,3 +272,22 @@ QDomElement QgsBookmarkManager::writeXml( QDomDocument &doc ) const
}
return bookmarksElem;
}
void QgsBookmarkManager::store()
{
if ( mProject )
{
mProject->setDirty( true );
}
else if ( !mSettingKey.isEmpty() )
{
// yeah, fine, whatever... storing xml in settings IS kinda ugly. But the alternative
// is a second marshalling implementation designed just for that, and I'd rather avoid the
// duplicate code. Plus, this is all internal anyway... just use the public stable API and don't
// concern your pretty little mind about all these technical details.
QDomDocument textDoc;
QDomElement textElem = writeXml( textDoc );
textDoc.appendChild( textElem );
QgsSettings().setValue( mSettingKey, textDoc.toString(), QgsSettings::Core );
}
}

View File

@ -133,9 +133,19 @@ class CORE_EXPORT QgsBookmarkManager : public QObject
/**
* Constructor for QgsBookmarkManager, with the specified \a parent project.
*
* This constructor creates a bookmark manager which stores bookmarks in a QgsProject instance.
*/
explicit QgsBookmarkManager( QgsProject *project SIP_TRANSFERTHIS = nullptr );
/**
* Constructor for QgsBookmarkManager, with the specified \a parent object.
*
* This constructor creates a bookmark manager which stores bookmarks in QgsSettings, using
* the specified \a settingKey.
*/
explicit QgsBookmarkManager( const QString &settingKey, QObject *parent SIP_TRANSFERTHIS = nullptr );
~QgsBookmarkManager() override;
/**
@ -228,8 +238,11 @@ class CORE_EXPORT QgsBookmarkManager : public QObject
private:
QgsProject *mProject = nullptr;
QString mSettingKey;
QList< QgsBookmark > mBookmarks;
void store();
};
#endif // QGSBOOKMARKMANAGER_H

View File

@ -13,6 +13,7 @@ __copyright__ = 'Copyright 2019, The QGIS Project'
import qgis # NOQA
import os
from qgis.PyQt.QtCore import QCoreApplication, QLocale
from qgis.PyQt.QtXml import QDomDocument
from qgis.core import (QgsBookmark,
@ -20,7 +21,9 @@ from qgis.core import (QgsBookmark,
QgsProject,
QgsReferencedRectangle,
QgsRectangle,
QgsCoordinateReferenceSystem)
QgsCoordinateReferenceSystem,
QgsSettings,
QgsApplication)
from qgis.testing import start_app, unittest
from utilities import unitTestDataPath
@ -33,6 +36,16 @@ TEST_DATA_DIR = unitTestDataPath()
class TestQgsBookmarkManager(unittest.TestCase):
@classmethod
def setUpClass(cls):
"""Run before all tests"""
QCoreApplication.setOrganizationName("QGIS_Test")
QCoreApplication.setOrganizationDomain("QGIS_TestQgsBookmarkManager.com")
QCoreApplication.setApplicationName("QGIS_TestQgsBookmarkManager")
QgsSettings().clear()
QLocale.setDefault(QLocale(QLocale.English))
start_app()
def setUp(self):
"""Run before each test."""
self.manager = None
@ -344,6 +357,72 @@ class TestQgsBookmarkManager(unittest.TestCase):
self.assertEqual(p.bookmarkManager().bookmarkById('bookmark_2').extent().crs().authid(), 'EPSG:28355')
self.assertEqual(p.bookmarkManager().bookmarkById('bookmark_2').extent().toString(1), '807985.7,7450916.9 : 876080.0,7564407.4')
def testQSettingsStorage(self):
"""
Test QSettings bound manager
"""
manager = QgsBookmarkManager('test_key')
# add a bunch of bookmarks
b = QgsBookmark()
b.setId('1')
b.setName('b1')
b.setExtent(QgsReferencedRectangle(QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem('EPSG:4326')))
b2 = QgsBookmark()
b2.setId('2')
b2.setName('b2')
b2.setExtent(QgsReferencedRectangle(QgsRectangle(12, 22, 32, 42), QgsCoordinateReferenceSystem('EPSG:4326')))
b3 = QgsBookmark()
b3.setId('3')
b3.setName('b3')
b3.setExtent(QgsReferencedRectangle(QgsRectangle(32, 32, 33, 43), QgsCoordinateReferenceSystem('EPSG:4326')))
manager.addBookmark(b)
manager.addBookmark(b2)
manager.addBookmark(b3)
# create another new manager with same key, should contain existing bookmarks
manager2 = QgsBookmarkManager('test_key')
self.assertEqual(manager2.bookmarks(), [b, b2, b3])
# but a manager with a different key should not...
manager3 = QgsBookmarkManager('test_key2')
self.assertEqual(manager3.bookmarks(), [])
def testApplicationInstance(self):
"""
Test storage in the application instance
"""
manager = QgsApplication.bookmarkManager()
# add a bunch of bookmarks
b = QgsBookmark()
b.setId('1')
b.setName('b1')
b.setExtent(QgsReferencedRectangle(QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem('EPSG:4326')))
b2 = QgsBookmark()
b2.setId('2')
b2.setName('b2')
b2.setExtent(QgsReferencedRectangle(QgsRectangle(12, 22, 32, 42), QgsCoordinateReferenceSystem('EPSG:4326')))
b3 = QgsBookmark()
b3.setId('3')
b3.setName('b3')
b3.setExtent(QgsReferencedRectangle(QgsRectangle(32, 32, 33, 43), QgsCoordinateReferenceSystem('EPSG:4326')))
manager.addBookmark(b)
manager.addBookmark(b2)
manager.addBookmark(b3)
manager2 = QgsApplication.bookmarkManager()
self.assertEqual(manager2.bookmarks(), [b, b2, b3])
manager3 = QgsBookmarkManager(QgsProject.instance())
self.assertEqual(manager3.bookmarks(), [])
if __name__ == '__main__':
unittest.main()