Skip to content

Commit

Permalink
[FEATURE] Project may be zipped/unzipped
Browse files Browse the repository at this point in the history
  • Loading branch information
pblottiere committed Jul 31, 2017
1 parent 33247cc commit 86389d1
Show file tree
Hide file tree
Showing 7 changed files with 300 additions and 7 deletions.
18 changes: 18 additions & 0 deletions python/core/qgsproject.sip
Expand Up @@ -612,6 +612,24 @@ Returns the number of registered layers.
:rtype: QMap<str, QgsMapLayer *>
%End

bool unzip( const QString &filename );
%Docstring
Unzip a project
\param filename The project filename to unzip
:return: true if unzip is well performed, false otherwise
.. versionadded:: 3.0
:rtype: bool
%End

bool zip( const QString &filename );
%Docstring
Zip the project
\param filename The zip filename
:return: true if zip is well performed, false otherwise
.. versionadded:: 3.0
:rtype: bool
%End


QList<QgsMapLayer *> addMapLayers( const QList<QgsMapLayer *> &mapLayers /Transfer/,
bool addToLegend = true);
Expand Down
2 changes: 2 additions & 0 deletions src/core/CMakeLists.txt
Expand Up @@ -305,6 +305,7 @@ SET(QGIS_CORE_SRCS
qgsxmlutils.cpp
qgssettings.cpp
qgsstacktrace.cpp
qgsarchive.cpp
qgsziputils.cpp

composer/qgsaddremoveitemcommand.cpp
Expand Down Expand Up @@ -893,6 +894,7 @@ SET(QGIS_CORE_HDRS
qgsvirtuallayerdefinitionutils.h
qgsmapthemecollection.h
qgsxmlutils.h
qgsarchive.h
qgsziputils.h
qgsvector.h
qgslocalec.h
Expand Down
113 changes: 113 additions & 0 deletions src/core/qgsarchive.cpp
@@ -0,0 +1,113 @@
/***************************************************************************
qgsarchive.cpp
----------------
begin : July 07, 2017
copyright : (C) 2017 by Paul Blottiere
email : paul.blottiere@oslandia.com
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgsarchive.h"
#include "qgsziputils.h"
#include "qgsmessagelog.h"

QgsArchive::QgsArchive()
: mDir( new QTemporaryDir() )
{
}

QgsArchive::~QgsArchive()
{
}

QString QgsArchive::dir() const
{
return mDir->path();
}

void QgsArchive::clear()
{
mDir.reset( new QTemporaryDir() );
mFilename.clear();
mFiles.clear();
}

bool QgsArchive::zip( const QString &filename )
{
// create a temporary path
QTemporaryFile tmpFile;
tmpFile.open();
tmpFile.close();

// zip content
if ( ! QgsZipUtils::zip( tmpFile.fileName(), mFiles ) )
{
QString err = QObject::tr( "Unable to zip content" );
QgsMessageLog::logMessage( err, QStringLiteral( "QgsArchive" ) );
return false;
}

// remove existing zip file
if ( QFile::exists( filename ) )
QFile::remove( filename );

// save zip archive
if ( ! tmpFile.rename( filename ) )
{
QString err = QObject::tr( "Unable to save zip file '%1'" ).arg( filename );
QgsMessageLog::logMessage( err, QStringLiteral( "QgsArchive" ) );
return false;
}

// keep the zip filename
tmpFile.setAutoRemove( false );
mFilename = filename;

return true;
}

bool QgsArchive::unzip( const QString &filename )
{
clear();

QgsZipUtils::unzip( filename, mDir->path(), mFiles );
mFilename = filename;

return ! projectFile().isEmpty();
}

void QgsArchive::addFile( const QString &file )
{
mFiles.append( file );
}

QString QgsArchive::filename() const
{
return mFilename;
}

QString QgsArchive::projectFile() const
{
Q_FOREACH ( const QString &file, mFiles )
{
QFileInfo fileInfo( file );
if ( "qgs" == fileInfo.suffix().toLower() )
return file;
}

return QString();
}

QStringList QgsArchive::files() const
{
return mFiles;
}
71 changes: 71 additions & 0 deletions src/core/qgsarchive.h
@@ -0,0 +1,71 @@
/***************************************************************************
qgsarchive.h
----------------
begin : July 07, 2017
copyright : (C) 2017 by Paul Blottiere
email : paul.blottiere@oslandia.com
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSARCHIVE_H
#define QGSARCHIVE_H

#include "qgis_core.h"
#include <QStringList>
#include <QTemporaryFile>
#include <QTemporaryDir>
#include <memory>

/**
* \class QgsArchive
* \ingroup core
* \brief Class allowing to manage the zip/unzip actions on project
* \since QGIS 3.0
*/
class CORE_EXPORT QgsArchive
{
public:

/**
* Constructor for QgsArchive
*/
QgsArchive();
~QgsArchive();

bool zip( const QString &zipFilename );

bool unzip( const QString &zipFilename );

void clear();

void addFile( const QString &filename );

QString filename() const;

QString projectFile() const;

QStringList files() const;

QString dir() const;

private:
// used when unzip is performed
std::unique_ptr<QTemporaryDir> mDir;

// content of the archive
QStringList mFiles;

// zip filename
QString mFilename;
};

#endif
76 changes: 76 additions & 0 deletions src/core/qgsproject.cpp
Expand Up @@ -332,6 +332,7 @@ QgsProject::QgsProject( QObject *parent )
, mLayoutManager( new QgsLayoutManager( this ) )
, mRootGroup( new QgsLayerTree )
, mLabelingEngineSettings( new QgsLabelingEngineSettings )
, mArchive( new QgsArchive() )
, mAutoTransaction( false )
, mEvaluateDefaultValues( false )
, mDirty( false )
Expand Down Expand Up @@ -2064,6 +2065,81 @@ QList<QgsMapLayer *> QgsProject::mapLayersByName( const QString &layerName ) con
return mLayerStore->mapLayersByName( layerName );
}

bool QgsProject::unzip( const QString &filename )
{
clearError();
std::unique_ptr<QgsArchive> archive( new QgsArchive() );

// unzip the archive
if ( !archive->unzip( filename ) )
{
setError( tr( "Unable to unzip file '%1'" ).arg( filename ) );
return false;
}

// test if zip provides a .qgs file
if ( archive->projectFile().isEmpty() )
{
setError( tr( "Zip archive does not provide a project file" ) );
return false;
}

// read the project file
if ( ! read( archive->projectFile() ) )
{
setError( tr( "Cannot read unzipped qgs project file" ) );
return false;
}

// keep the archive
mArchive.reset( archive.release() );

return true;
}

bool QgsProject::zip( const QString &filename )
{
clearError();

// save the current project in a temporary .qgs file
QgsArchive archive;
const QString baseName = QFileInfo( filename ).baseName();
const QString qgsFileName = QString( "%1.qgs" ).arg( baseName );
QFile qgsFile( QDir( archive.dir() ).filePath( qgsFileName ) );

bool writeOk;
if ( qgsFile.open( QIODevice::WriteOnly ) )
{
const QString originalFilename = mFile.fileName();
mFile.setFileName( qgsFile.fileName() );

writeOk = write();

mFile.setFileName( originalFilename );
qgsFile.close();
}

// stop here with an error message
if ( ! writeOk )
{
setError( tr( "Unable to write temporary qgs file" ) );
return false;
}

// create the archive
archive.addFile( qgsFile.fileName() );

// zip
QString errMsg;
if ( !archive.zip( filename ) )
{
setError( tr( "Unable to perform zip" ) );
return false;
}

return true;
}

QList<QgsMapLayer *> QgsProject::addMapLayers(
const QList<QgsMapLayer *> &layers,
bool addToLegend,
Expand Down
19 changes: 19 additions & 0 deletions src/core/qgsproject.h
Expand Up @@ -40,6 +40,7 @@
#include "qgsprojectproperty.h"
#include "qgsmaplayer.h"
#include "qgsmaplayerstore.h"
#include "qgsarchive.h"

class QFileInfo;
class QDomDocument;
Expand Down Expand Up @@ -575,6 +576,22 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
*/
QMap<QString, QgsMapLayer *> mapLayers() const;

/**
* Unzip a project
* \param filename The project filename to unzip
* \returns true if unzip is well performed, false otherwise
* \since QGIS 3.0
*/
bool unzip( const QString &filename );

/**
* Zip the project
* \param filename The zip filename
* \returns true if zip is well performed, false otherwise
* \since QGIS 3.0
*/
bool zip( const QString &filename );

#ifndef SIP_RUN

/** Returns a list of registered map layers with a specified layer type.
Expand Down Expand Up @@ -1048,6 +1065,8 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera

QVariantMap mCustomVariables;

std::unique_ptr<QgsArchive> mArchive;

QFile mFile; // current physical project file
mutable QgsProjectPropertyKey mProperties; // property hierarchy, TODO: this shouldn't be mutable
QString mTitle; // project title
Expand Down
8 changes: 1 addition & 7 deletions src/core/qgsziputils.cpp
Expand Up @@ -115,13 +115,7 @@ bool QgsZipUtils::unzip( const QString &zipFilename, const QString &dir, QString

bool QgsZipUtils::zip( const QString &zipFilename, const QStringList &files )
{
if ( QFileInfo::exists( zipFilename ) )
{
QString err = QObject::tr( "Error zip file yet exist: '%1'" ).arg( zipFilename );
QgsMessageLog::logMessage( err, QStringLiteral( "QgsZipUtils" ) );
return false;
}
else if ( zipFilename.isEmpty() )
if ( zipFilename.isEmpty() )
{
QString err = QObject::tr( "Error zip filename is empty" );
QgsMessageLog::logMessage( err, QStringLiteral( "QgsZipUtils" ) );
Expand Down

0 comments on commit 86389d1

Please sign in to comment.