Skip to content

Commit a30646f

Browse files
committedApr 7, 2018
Introduced QgsProjectStorage and QgsProjectStorageRegistry
This is going to be used as an abstraction of how/where project files are stored.
1 parent ce72536 commit a30646f

15 files changed

+565
-0
lines changed
 

‎python/core/core_auto.sip

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@
9191
%Include qgsprojectbadlayerhandler.sip
9292
%Include qgsprojectfiletransform.sip
9393
%Include qgsprojectproperty.sip
94+
%Include qgsprojectstorage.sip
95+
%Include qgsprojectstorageregistry.sip
9496
%Include qgsprojectversion.sip
9597
%Include qgsproperty.sip
9698
%Include qgspropertycollection.sip

‎python/core/qgsapplication.sip.in

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,13 @@ Returns registry of available 3D renderers.
735735
not available in Python bindings
736736

737737
.. versionadded:: 3.0
738+
%End
739+
740+
static QgsProjectStorageRegistry *projectStorageRegistry();
741+
%Docstring
742+
Returns registry of available project storage implementations.
743+
744+
.. versionadded:: 3.2
738745
%End
739746

740747
static QString nullRepresentation();

‎python/core/qgsprojectstorage.sip.in

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/************************************************************************
2+
* This file has been generated automatically from *
3+
* *
4+
* src/core/qgsprojectstorage.h *
5+
* *
6+
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
7+
************************************************************************/
8+
9+
10+
11+
12+
13+
class QgsProjectStorage
14+
{
15+
%Docstring
16+
Abstract interface for project storage - to be implemented by various backends
17+
and registered in QgsProjectStorageRegistry.
18+
19+
.. versionadded:: 3.2
20+
%End
21+
22+
%TypeHeaderCode
23+
#include "qgsprojectstorage.h"
24+
%End
25+
public:
26+
virtual ~QgsProjectStorage();
27+
28+
virtual QString type() = 0;
29+
%Docstring
30+
Unique identifier of the project storage type. If type() returns "memory", all project file names
31+
starting with "memory:" will have read/write redirected through that storage implementation.
32+
%End
33+
34+
virtual QStringList listProjects( const QString &uri ) = 0;
35+
%Docstring
36+
Returns list of all projects for given URI (specific to each storage backend)
37+
%End
38+
39+
virtual bool readProject( const QString &uri, QIODevice *device, QgsReadWriteContext &context ) = 0;
40+
%Docstring
41+
Reads project file content stored in the backend at the specified URI to the given device
42+
(could be e.g. a temporary file or a memory buffer). The device is expected to be empty
43+
when passed to readProject() so that the method can write all data to it and then rewind
44+
it using seek(0) to make it ready for reading in :py:class:`QgsProject`.
45+
%End
46+
47+
virtual bool writeProject( const QString &uri, QIODevice *device, QgsReadWriteContext &context ) = 0;
48+
%Docstring
49+
Writes project file content stored in given device (could be e.g. a temporary file or a memory buffer)
50+
using the backend to the specified URI. The device is expected to contain all project file data
51+
and having position at the start of the content when passed to writeProject() so that the method
52+
can read all data from it until it reaches its end.
53+
%End
54+
55+
56+
};
57+
58+
/************************************************************************
59+
* This file has been generated automatically from *
60+
* *
61+
* src/core/qgsprojectstorage.h *
62+
* *
63+
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
64+
************************************************************************/
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/************************************************************************
2+
* This file has been generated automatically from *
3+
* *
4+
* src/core/qgsprojectstorageregistry.h *
5+
* *
6+
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
7+
************************************************************************/
8+
9+
10+
11+
12+
13+
class QgsProjectStorageRegistry
14+
{
15+
%Docstring
16+
Registry of storage backends that QgsProject may use.
17+
This is a singleton that should be accessed through :py:func:`QgsApplication.projectStorageRegistry()`
18+
19+
.. versionadded:: 3.2
20+
%End
21+
22+
%TypeHeaderCode
23+
#include "qgsprojectstorageregistry.h"
24+
%End
25+
public:
26+
QgsProjectStorageRegistry();
27+
~QgsProjectStorageRegistry();
28+
29+
QgsProjectStorage *projectStorageFromUri( const QString &uri );
30+
%Docstring
31+
Returns storage implementation if the URI matches one. Returns null pointer otherwise (it is a normal file)
32+
%End
33+
34+
QList<QgsProjectStorage *> projectStorages() const;
35+
%Docstring
36+
Returns a list of registered project storage implementations
37+
%End
38+
39+
void registerProjectStorage( QgsProjectStorage *storage /Transfer/ );
40+
%Docstring
41+
Registers a storage backend and takes ownership of it
42+
%End
43+
44+
void unregisterProjectStorage( QgsProjectStorage *storage );
45+
%Docstring
46+
Unregisters a storage backend and destroys its instance
47+
%End
48+
49+
};
50+
51+
/************************************************************************
52+
* This file has been generated automatically from *
53+
* *
54+
* src/core/qgsprojectstorageregistry.h *
55+
* *
56+
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
57+
************************************************************************/

‎src/core/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,8 @@ SET(QGIS_CORE_SRCS
259259
qgsprojectfiletransform.cpp
260260
qgssnappingconfig.cpp
261261
qgsprojectproperty.cpp
262+
qgsprojectstorage.cpp
263+
qgsprojectstorageregistry.cpp
262264
qgsprojectversion.cpp
263265
qgsproperty.cpp
264266
qgspropertycollection.cpp
@@ -889,6 +891,8 @@ SET(QGIS_CORE_HDRS
889891
qgsprojectbadlayerhandler.h
890892
qgsprojectfiletransform.h
891893
qgsprojectproperty.h
894+
qgsprojectstorage.h
895+
qgsprojectstorageregistry.h
892896
qgsprojectversion.h
893897
qgsproperty.h
894898
qgsproperty_p.h

‎src/core/qgsapplication.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "qgssvgcache.h"
3232
#include "qgscolorschemeregistry.h"
3333
#include "qgspainteffectregistry.h"
34+
#include "qgsprojectstorageregistry.h"
3435
#include "qgsrasterrendererregistry.h"
3536
#include "qgsrendererregistry.h"
3637
#include "qgssymbollayerregistry.h"
@@ -1710,6 +1711,11 @@ Qgs3DRendererRegistry *QgsApplication::renderer3DRegistry()
17101711
return members()->m3DRendererRegistry;
17111712
}
17121713

1714+
QgsProjectStorageRegistry *QgsApplication::projectStorageRegistry()
1715+
{
1716+
return members()->mProjectStorageRegistry;
1717+
}
1718+
17131719
QgsApplication::ApplicationMembers::ApplicationMembers()
17141720
{
17151721
// don't use initializer lists or scoped pointers - as more objects are added here we
@@ -1733,6 +1739,7 @@ QgsApplication::ApplicationMembers::ApplicationMembers()
17331739
mLayoutItemRegistry->populate();
17341740
mAnnotationRegistry = new QgsAnnotationRegistry();
17351741
m3DRendererRegistry = new Qgs3DRendererRegistry();
1742+
mProjectStorageRegistry = new QgsProjectStorageRegistry();
17361743
}
17371744

17381745
QgsApplication::ApplicationMembers::~ApplicationMembers()
@@ -1747,6 +1754,7 @@ QgsApplication::ApplicationMembers::~ApplicationMembers()
17471754
delete mPaintEffectRegistry;
17481755
delete mPluginLayerRegistry;
17491756
delete mProcessingRegistry;
1757+
delete mProjectStorageRegistry;
17501758
delete mPageSizeRegistry;
17511759
delete mLayoutItemRegistry;
17521760
delete mProfiler;

‎src/core/qgsapplication.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class QgsTaskManager;
3030
class QgsFieldFormatterRegistry;
3131
class QgsColorSchemeRegistry;
3232
class QgsPaintEffectRegistry;
33+
class QgsProjectStorageRegistry;
3334
class QgsRendererRegistry;
3435
class QgsSvgCache;
3536
class QgsSymbolLayerRegistry;
@@ -668,6 +669,12 @@ class CORE_EXPORT QgsApplication : public QApplication
668669
*/
669670
static Qgs3DRendererRegistry *renderer3DRegistry();
670671

672+
/**
673+
* Returns registry of available project storage implementations.
674+
* \since QGIS 3.2
675+
*/
676+
static QgsProjectStorageRegistry *projectStorageRegistry();
677+
671678
/**
672679
* This string is used to represent the value `NULL` throughout QGIS.
673680
*
@@ -799,6 +806,7 @@ class CORE_EXPORT QgsApplication : public QApplication
799806
QgsPaintEffectRegistry *mPaintEffectRegistry = nullptr;
800807
QgsPluginLayerRegistry *mPluginLayerRegistry = nullptr;
801808
QgsProcessingRegistry *mProcessingRegistry = nullptr;
809+
QgsProjectStorageRegistry *mProjectStorageRegistry = nullptr;
802810
QgsPageSizeRegistry *mPageSizeRegistry = nullptr;
803811
QgsRasterRendererRegistry *mRasterRendererRegistry = nullptr;
804812
QgsRendererRegistry *mRendererRegistry = nullptr;

‎src/core/qgsproject.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
#include "qgsprojectfiletransform.h"
3030
#include "qgssnappingconfig.h"
3131
#include "qgspathresolver.h"
32+
#include "qgsprojectstorage.h"
33+
#include "qgsprojectstorageregistry.h"
3234
#include "qgsprojectversion.h"
3335
#include "qgsrasterlayer.h"
3436
#include "qgsreadwritecontext.h"
@@ -822,6 +824,26 @@ bool QgsProject::read()
822824
QString filename = mFile.fileName();
823825
bool rc;
824826

827+
QgsProjectStorage *storage = QgsApplication::projectStorageRegistry()->projectStorageFromUri( filename );
828+
if ( storage )
829+
{
830+
QTemporaryFile inDevice;
831+
if ( !inDevice.open() )
832+
{
833+
setError( tr( "Unable to open %1" ).arg( inDevice.fileName() ) );
834+
return false;
835+
}
836+
837+
QgsReadWriteContext context;
838+
if ( !storage->readProject( filename, &inDevice, context ) )
839+
{
840+
setError( tr( "Unable to open %1" ).arg( filename ) );
841+
return false;
842+
}
843+
844+
return unzip( inDevice.fileName() ); // calls setError() if returning false
845+
}
846+
825847
if ( QgsZipUtils::isZipFile( mFile.fileName() ) )
826848
{
827849
rc = unzip( mFile.fileName() );
@@ -1374,6 +1396,39 @@ bool QgsProject::write( const QString &filename )
13741396

13751397
bool QgsProject::write()
13761398
{
1399+
QgsProjectStorage *projectStorage = QgsApplication::projectStorageRegistry()->projectStorageFromUri( mFile.fileName() );
1400+
if ( projectStorage )
1401+
{
1402+
// for projects stored in a custom storage, we cannot use relative paths since the storage most likely
1403+
// will not be in a file system
1404+
writeEntry( QStringLiteral( "Paths" ), QStringLiteral( "/Absolute" ), true );
1405+
1406+
QString tempPath = QStandardPaths::standardLocations( QStandardPaths::TempLocation ).at( 0 );
1407+
QString tmpZipFilename( tempPath + QDir::separator() + QUuid::createUuid().toString() );
1408+
1409+
if ( !zip( tmpZipFilename ) )
1410+
return false; // zip() already calls setError() when returning false
1411+
1412+
QFile tmpZipFile( tmpZipFilename );
1413+
if ( !tmpZipFile.open( QIODevice::ReadOnly ) )
1414+
{
1415+
setError( tr( "Unable to read file %1" ).arg( tmpZipFilename ) );
1416+
return false;
1417+
}
1418+
1419+
QgsReadWriteContext context;
1420+
if ( !projectStorage->writeProject( mFile.fileName(), &tmpZipFile, context ) )
1421+
{
1422+
setError( tr( "Unable to save project to storage %1" ).arg( mFile.fileName() ) );
1423+
return false;
1424+
}
1425+
1426+
tmpZipFile.close();
1427+
QFile::remove( tmpZipFilename );
1428+
1429+
return true;
1430+
}
1431+
13771432
if ( QgsZipUtils::isZipFile( mFile.fileName() ) )
13781433
{
13791434
return zip( mFile.fileName() );

‎src/core/qgsproject.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class QgsMapLayer;
5656
class QgsMapThemeCollection;
5757
class QgsPathResolver;
5858
class QgsProjectBadLayerHandler;
59+
class QgsProjectStorage;
5960
class QgsRelationManager;
6061
class QgsTolerance;
6162
class QgsTransactionGroup;

‎src/core/qgsprojectstorage.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/***************************************************************************
2+
qgsprojectstorage.cpp
3+
--------------------------------------
4+
Date : March 2018
5+
Copyright : (C) 2018 by Martin Dobias
6+
Email : wonder dot sk at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#include "qgsprojectstorage.h"
17+
18+
19+
QgsProjectStorage::~QgsProjectStorage()
20+
{
21+
}

‎src/core/qgsprojectstorage.h

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/***************************************************************************
2+
qgsprojectstorage.h
3+
--------------------------------------
4+
Date : March 2018
5+
Copyright : (C) 2018 by Martin Dobias
6+
Email : wonder dot sk at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#ifndef QGSPROJECTSTORAGE_H
17+
#define QGSPROJECTSTORAGE_H
18+
19+
#include "qgis_core.h"
20+
21+
class QIODevice;
22+
class QString;
23+
class QStringList;
24+
25+
class QgsReadWriteContext;
26+
27+
/**
28+
* Abstract interface for project storage - to be implemented by various backends
29+
* and registered in QgsProjectStorageRegistry.
30+
*
31+
* \since QGIS 3.2
32+
*/
33+
class CORE_EXPORT QgsProjectStorage
34+
{
35+
public:
36+
virtual ~QgsProjectStorage();
37+
38+
/**
39+
* Unique identifier of the project storage type. If type() returns "memory", all project file names
40+
* starting with "memory:" will have read/write redirected through that storage implementation.
41+
*/
42+
virtual QString type() = 0;
43+
44+
//! Returns list of all projects for given URI (specific to each storage backend)
45+
virtual QStringList listProjects( const QString &uri ) = 0;
46+
47+
/**
48+
* Reads project file content stored in the backend at the specified URI to the given device
49+
* (could be e.g. a temporary file or a memory buffer). The device is expected to be empty
50+
* when passed to readProject() so that the method can write all data to it and then rewind
51+
* it using seek(0) to make it ready for reading in QgsProject.
52+
*/
53+
virtual bool readProject( const QString &uri, QIODevice *device, QgsReadWriteContext &context ) = 0;
54+
55+
/**
56+
* Writes project file content stored in given device (could be e.g. a temporary file or a memory buffer)
57+
* using the backend to the specified URI. The device is expected to contain all project file data
58+
* and having position at the start of the content when passed to writeProject() so that the method
59+
* can read all data from it until it reaches its end.
60+
*/
61+
virtual bool writeProject( const QString &uri, QIODevice *device, QgsReadWriteContext &context ) = 0;
62+
63+
// TODO: rename / remove ?
64+
65+
// TODO: load/save GUI
66+
};
67+
68+
#endif // QGSPROJECTSTORAGE_H
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/***************************************************************************
2+
qgsprojectstorageregistry.cpp
3+
--------------------------------------
4+
Date : March 2018
5+
Copyright : (C) 2018 by Martin Dobias
6+
Email : wonder dot sk at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#include "qgsprojectstorageregistry.h"
17+
18+
#include "qgsprojectstorage.h"
19+
20+
QgsProjectStorageRegistry::QgsProjectStorageRegistry()
21+
{
22+
23+
}
24+
25+
QgsProjectStorageRegistry::~QgsProjectStorageRegistry()
26+
{
27+
qDeleteAll( mBackends.values() );
28+
}
29+
30+
QgsProjectStorage *QgsProjectStorageRegistry::projectStorageFromUri( const QString &uri )
31+
{
32+
for ( auto it = mBackends.constBegin(); it != mBackends.constEnd(); ++it )
33+
{
34+
QgsProjectStorage *storage = it.value();
35+
QString scheme = storage->type() + ":";
36+
if ( uri.startsWith( scheme ) )
37+
return storage;
38+
}
39+
return nullptr;
40+
}
41+
42+
QList<QgsProjectStorage *> QgsProjectStorageRegistry::projectStorages() const
43+
{
44+
return mBackends.values();
45+
}
46+
47+
void QgsProjectStorageRegistry::registerProjectStorage( QgsProjectStorage *storage )
48+
{
49+
mBackends.insert( storage->type(), storage );
50+
}
51+
52+
void QgsProjectStorageRegistry::unregisterProjectStorage( QgsProjectStorage *storage )
53+
{
54+
delete mBackends.take( storage->type() );
55+
}

‎src/core/qgsprojectstorageregistry.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/***************************************************************************
2+
qgsprojectstorageregistry.h
3+
--------------------------------------
4+
Date : March 2018
5+
Copyright : (C) 2018 by Martin Dobias
6+
Email : wonder dot sk at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#ifndef QGSPROJECTSTORAGEREGISTRY_H
17+
#define QGSPROJECTSTORAGEREGISTRY_H
18+
19+
#include "qgis_core.h"
20+
#include "qgis_sip.h"
21+
22+
#include <QHash>
23+
24+
class QgsProjectStorage;
25+
26+
/**
27+
* Registry of storage backends that QgsProject may use.
28+
* This is a singleton that should be accessed through QgsApplication::projectStorageRegistry().
29+
*
30+
* \since QGIS 3.2
31+
*/
32+
class CORE_EXPORT QgsProjectStorageRegistry
33+
{
34+
public:
35+
QgsProjectStorageRegistry();
36+
~QgsProjectStorageRegistry();
37+
38+
//! Returns storage implementation if the URI matches one. Returns null pointer otherwise (it is a normal file)
39+
QgsProjectStorage *projectStorageFromUri( const QString &uri );
40+
41+
//! Returns a list of registered project storage implementations
42+
QList<QgsProjectStorage *> projectStorages() const;
43+
44+
//! Registers a storage backend and takes ownership of it
45+
void registerProjectStorage( QgsProjectStorage *storage SIP_TRANSFER );
46+
47+
//! Unregisters a storage backend and destroys its instance
48+
void unregisterProjectStorage( QgsProjectStorage *storage );
49+
50+
private:
51+
QHash<QString, QgsProjectStorage *> mBackends;
52+
};
53+
54+
#endif // QGSPROJECTSTORAGEREGISTRY_H

‎tests/src/core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ SET(TESTS
155155
testqgspointpatternfillsymbol.cpp
156156
testqgspoint.cpp
157157
testqgsproject.cpp
158+
testqgsprojectstorage.cpp
158159
testqgsproperty.cpp
159160
testqgis.cpp
160161
testqgsrasterfilewriter.cpp
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
/***************************************************************************
2+
testqgsprojectstorage.cpp
3+
--------------------------------------
4+
Date : March 2018
5+
Copyright : (C) 2018 by Martin Dobias
6+
Email : wonder.sk at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#include "qgstest.h"
17+
18+
#include "qgsproject.h"
19+
#include "qgsprojectstorage.h"
20+
#include "qgsprojectstorageregistry.h"
21+
#include "qgsvectorlayer.h"
22+
23+
24+
class TestQgsProjectStorage : public QObject
25+
{
26+
Q_OBJECT
27+
private slots:
28+
void initTestCase();// will be called before the first testfunction is executed.
29+
void cleanupTestCase();// will be called after the last testfunction was executed.
30+
void init();// will be called before each testfunction is executed.
31+
void cleanup();// will be called after every testfunction.
32+
33+
void testMemoryStorage();
34+
};
35+
36+
void TestQgsProjectStorage::init()
37+
{
38+
}
39+
40+
void TestQgsProjectStorage::cleanup()
41+
{
42+
// will be called after every testfunction.
43+
}
44+
45+
void TestQgsProjectStorage::initTestCase()
46+
{
47+
// Runs once before any tests are run
48+
49+
// Set up the QgsSettings environment
50+
QCoreApplication::setOrganizationName( QStringLiteral( "QGIS" ) );
51+
QCoreApplication::setOrganizationDomain( QStringLiteral( "qgis.org" ) );
52+
QCoreApplication::setApplicationName( QStringLiteral( "QGIS-TEST" ) );
53+
54+
QgsApplication::init();
55+
QgsApplication::initQgis();
56+
}
57+
58+
59+
void TestQgsProjectStorage::cleanupTestCase()
60+
{
61+
// Runs once after all tests are run
62+
QgsApplication::exitQgis();
63+
}
64+
65+
66+
//! A simple storage implementation that stores projects in memory
67+
class MemoryStorage : public QgsProjectStorage
68+
{
69+
public:
70+
virtual QString type() override
71+
{
72+
return QStringLiteral( "memory" );
73+
}
74+
75+
virtual QStringList listProjects( const QString &uri ) override
76+
{
77+
Q_UNUSED( uri );
78+
return mProjects.keys();
79+
}
80+
81+
virtual bool readProject( const QString &uri, QIODevice *ioDevice, QgsReadWriteContext &context ) override
82+
{
83+
QgsReadWriteContextCategoryPopper popper( context.enterCategory( "memory storage" ) );
84+
85+
QStringList lst = uri.split( ":" );
86+
Q_ASSERT( lst.count() == 2 );
87+
QString projectName = lst[1];
88+
89+
if ( !mProjects.contains( projectName ) )
90+
{
91+
context.pushMessage( "project not found", Qgis::Critical );
92+
return false;
93+
}
94+
95+
QByteArray content = mProjects[projectName];
96+
ioDevice->write( content );
97+
ioDevice->seek( 0 );
98+
return true;
99+
}
100+
101+
virtual bool writeProject( const QString &uri, QIODevice *ioDevice, QgsReadWriteContext &context ) override
102+
{
103+
Q_UNUSED( context );
104+
QStringList lst = uri.split( ":" );
105+
Q_ASSERT( lst.count() == 2 );
106+
QString projectName = lst[1];
107+
108+
mProjects[projectName] = ioDevice->readAll();
109+
return true;
110+
}
111+
112+
private:
113+
QHash<QString, QByteArray> mProjects;
114+
};
115+
116+
117+
void TestQgsProjectStorage::testMemoryStorage()
118+
{
119+
QString dataDir( TEST_DATA_DIR ); // defined in CmakeLists.txt
120+
QString layerPath = dataDir + "/points.shp";
121+
QgsVectorLayer *layer1 = new QgsVectorLayer( layerPath, QStringLiteral( "points" ), QStringLiteral( "ogr" ) );
122+
QVERIFY( layer1->isValid() );
123+
124+
MemoryStorage *memStorage = new MemoryStorage;
125+
126+
QgsApplication::projectStorageRegistry()->registerProjectStorage( memStorage );
127+
128+
QVERIFY( QgsApplication::projectStorageRegistry()->projectStorages().contains( memStorage ) );
129+
130+
QCOMPARE( memStorage->listProjects( QString() ).count(), 0 );
131+
132+
QgsProject prj1;
133+
prj1.setTitle( "best project ever" );
134+
prj1.addMapLayer( layer1 );
135+
prj1.setFileName( "memory:project1" );
136+
bool writeOk = prj1.write();
137+
138+
QVERIFY( writeOk );
139+
QCOMPARE( memStorage->listProjects( QString() ).count(), 1 );
140+
141+
QgsProject prj2;
142+
prj2.setFileName( "memory:project1" );
143+
bool readOk = prj2.read();
144+
145+
QVERIFY( readOk );
146+
QCOMPARE( prj2.mapLayers().count(), 1 );
147+
QCOMPARE( prj2.title(), QString( "best project ever" ) );
148+
149+
QgsProject prj3;
150+
prj3.setFileName( "memory:nooooooooo!" );
151+
bool readInvalidOk = prj3.read();
152+
153+
QVERIFY( !readInvalidOk );
154+
155+
QgsApplication::projectStorageRegistry()->unregisterProjectStorage( memStorage );
156+
}
157+
158+
159+
QGSTEST_MAIN( TestQgsProjectStorage )
160+
#include "testqgsprojectstorage.moc"

0 commit comments

Comments
 (0)
Please sign in to comment.