Skip to content

Commit b20f4c6

Browse files
authored
Merge pull request #4845 from pblottiere/zip
[FEATURE] New zip format
2 parents 3c58599 + 86c63a1 commit b20f4c6

File tree

19 files changed

+1139
-34
lines changed

19 files changed

+1139
-34
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ matrix:
3535
- poppler-utils
3636
- xvfb
3737
- clang-3.8
38+
- libzip-dev
3839

3940

4041
- os: linux

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ IF(WITH_CORE)
210210
IF (WITH_GUI)
211211
FIND_PACKAGE(Qwt REQUIRED)
212212
ENDIF (WITH_GUI)
213+
FIND_PACKAGE(LibZip REQUIRED)
213214

214215
IF (WITH_INTERNAL_QEXTSERIALPORT)
215216
SET(QEXTSERIALPORT_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/src/core/gps/qextserialport)

cmake/FindLibZip.cmake

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# CMake module to search for libzip
2+
#
3+
# Once done this will define
4+
#
5+
# LIBZIP_FOUND - system has the zip library
6+
# LIBZIP_INCLUDE_DIR - the zip include directory
7+
# LIBZIP_LIBRARY - Link this to use the zip library
8+
#
9+
# Copyright (c) 2017, Paul Blottiere, <paul.blottiere@oslandia.com>
10+
#
11+
# Redistribution and use is allowed according to the terms of the BSD license.
12+
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
13+
14+
FIND_PATH(LIBZIP_INCLUDE_DIR
15+
zip.h
16+
PATHS
17+
/usr/local/include
18+
/usr/include
19+
"$ENV{LIB_DIR}/include"
20+
"$ENV{INCLUDE}"
21+
)
22+
23+
FIND_LIBRARY(LIBZIP_LIBRARY
24+
NAMES zip
25+
PATHS
26+
/usr/local/lib
27+
/usr/lib
28+
"$ENV{LIB_DIR}/lib"
29+
"$ENV{LIB}"
30+
)
31+
32+
IF (LIBZIP_LIBRARY AND LIBZIP_INCLUDE_DIR)
33+
SET(LIBZIP_FOUND TRUE)
34+
ENDIF (LIBZIP_LIBRARY AND LIBZIP_INCLUDE_DIR)
35+
36+
IF (LIBZIP_FOUND)
37+
MESSAGE(STATUS "Found libzip: ${LIBZIP_LIBRARY}")
38+
ELSE (LIPZIP_FOUND)
39+
MESSAGE(FATAL_ERROR "Could not find libzip")
40+
ENDIF (LIBZIP_FOUND)

python/core/core_auto.sip

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@
127127
%Include qgsvirtuallayerdefinitionutils.sip
128128
%Include qgsmapthemecollection.sip
129129
%Include qgsxmlutils.sip
130+
%Include qgsarchive.sip
131+
%Include qgsziputils.sip
130132
%Include qgsvector.sip
131133
%Include auth/qgsauthcertutils.sip
132134
%Include auth/qgsauthconfig.sip

python/core/qgsarchive.sip

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/************************************************************************
2+
* This file has been generated automatically from *
3+
* *
4+
* src/core/qgsarchive.h *
5+
* *
6+
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
7+
************************************************************************/
8+
9+
10+
11+
12+
class QgsArchive
13+
{
14+
%Docstring
15+
Class allowing to manage the zip/unzip actions
16+
.. versionadded:: 3.0
17+
%End
18+
19+
%TypeHeaderCode
20+
#include "qgsarchive.h"
21+
%End
22+
public:
23+
24+
QgsArchive();
25+
%Docstring
26+
Constructor
27+
%End
28+
29+
QgsArchive( const QgsArchive &other );
30+
%Docstring
31+
Copy constructor
32+
%End
33+
34+
35+
virtual ~QgsArchive();
36+
%Docstring
37+
Destructor
38+
%End
39+
40+
bool zip( const QString &zipFilename );
41+
%Docstring
42+
Zip the content of this archive
43+
\param zipFilename The name of the zip to generate
44+
:return: false if something goes wrong, true otherwise
45+
:rtype: bool
46+
%End
47+
48+
virtual bool unzip( const QString &zipFilename );
49+
%Docstring
50+
Clear the current content of this archive and unzip. Files are unzipped
51+
in the temporary directory.
52+
\param zipFilename The zip file to unzip
53+
:return: true if unzip action is a success, false otherwise
54+
:rtype: bool
55+
%End
56+
57+
void clear();
58+
%Docstring
59+
Clear the current content of this archive and create a new temporary
60+
directory.
61+
%End
62+
63+
void addFile( const QString &filename );
64+
%Docstring
65+
Add a new file to this archive. During a zip action, this file will be
66+
part of the resulting zipped file.
67+
\param filename A file to add when zipping this archive
68+
%End
69+
70+
bool removeFile( const QString &filename );
71+
%Docstring
72+
Remove a file from this archive and from the filesystem.
73+
\param filename The path of the file to remove
74+
:return: true if the file has been removed from the filesystem, false otherwise
75+
:rtype: bool
76+
%End
77+
78+
QStringList files() const;
79+
%Docstring
80+
Returns the list of files within this archive
81+
:rtype: list of str
82+
%End
83+
84+
QString dir() const;
85+
%Docstring
86+
Returns the current temporary directory.
87+
:rtype: str
88+
%End
89+
90+
};
91+
92+
class QgsProjectArchive : QgsArchive
93+
{
94+
%Docstring
95+
Class allowing to manage the zip/unzip actions on project file
96+
.. versionadded:: 3.0
97+
%End
98+
99+
%TypeHeaderCode
100+
#include "qgsarchive.h"
101+
%End
102+
public:
103+
104+
virtual bool unzip( const QString &zipFilename );
105+
106+
%Docstring
107+
Clear the current content of this archive and unzip. If a project file
108+
is found in the content, then this archive may be considered as a valid
109+
one. Files are unzipped in the temporary directory.
110+
\param zipFilename The zip file to unzip
111+
:return: true if a project file has been found, false otherwise
112+
:rtype: bool
113+
%End
114+
115+
QString projectFile() const;
116+
%Docstring
117+
Returns the current .qgs project file or an empty string if there's none
118+
:rtype: str
119+
%End
120+
121+
bool clearProjectFile();
122+
%Docstring
123+
Remove the current .qgs project file from the temporary directory.
124+
:return: true if the file is well removed, false otherwise
125+
:rtype: bool
126+
%End
127+
};
128+
129+
/************************************************************************
130+
* This file has been generated automatically from *
131+
* *
132+
* src/core/qgsarchive.h *
133+
* *
134+
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
135+
************************************************************************/

python/core/qgsproject.sip

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,12 @@ Returns the number of registered layers.
612612
:rtype: QMap<str, QgsMapLayer *>
613613
%End
614614

615+
bool isZipped() const;
616+
%Docstring
617+
Returns true if the project comes from a zip archive, false otherwise.
618+
:rtype: bool
619+
%End
620+
615621

616622
QList<QgsMapLayer *> addMapLayers( const QList<QgsMapLayer *> &mapLayers /Transfer/,
617623
bool addToLegend = true);

python/core/qgsziputils.sip

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/qgsziputils.h *
5+
* *
6+
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
7+
************************************************************************/
8+
9+
10+
11+
%ModuleHeaderCode
12+
#include "qgsziputils.h"
13+
%End
14+
15+
namespace QgsZipUtils
16+
{
17+
18+
bool isZipFile( const QString &filename );
19+
%Docstring
20+
Returns true if the file name is a zipped file ( i.e with a '.qgz'
21+
extension, false otherwise.
22+
\param filename The name of the file
23+
:return: true if the file is zipped, false otherwise
24+
:rtype: bool
25+
%End
26+
27+
bool unzip( const QString &zip, const QString &dir, QStringList &files /Out/ );
28+
%Docstring
29+
Unzip a zip file in an output directory. An error is returned if the zip
30+
filename does not exist, the output directory does not exist or is
31+
not writable.
32+
\param zip The zip filename
33+
\param dir The output directory
34+
\param files The absolute path of unzipped files
35+
.. versionadded:: 3.0
36+
:rtype: bool
37+
%End
38+
39+
bool zip( const QString &zip, const QStringList &files );
40+
%Docstring
41+
Zip the list of files in the zip file. If the zip file already exists or is
42+
empty, an error is returned. If an input file does not exist, an error is
43+
also returned.
44+
\param zip The zip filename
45+
\param files The absolute path to files to embed within the zip
46+
.. versionadded:: 3.0
47+
:rtype: bool
48+
%End
49+
};
50+
51+
/************************************************************************
52+
* This file has been generated automatically from *
53+
* *
54+
* src/core/qgsziputils.h *
55+
* *
56+
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
57+
************************************************************************/

scripts/spell_check/spelling.dat

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2943,6 +2943,8 @@ fiel:field
29432943
fiels:fields
29442944
fiercly:fiercely
29452945
fightings:fighting
2946+
fille:file
2947+
filles:files
29462948
filesytem:filesystem
29472949
filesytems:filesystems
29482950
fileystem:filesystem

src/app/qgisapp.cpp

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
#include <qgscomposition.h>
7878
#include <qgslayerstylingwidget.h>
7979
#include "qgstaskmanager.h"
80+
#include "qgsziputils.h"
8081

8182
#include <QNetworkReply>
8283
#include <QNetworkProxy>
@@ -5230,7 +5231,7 @@ void QgisApp::fileOpen()
52305231
QString fullPath = QFileDialog::getOpenFileName( this,
52315232
tr( "Choose a QGIS project file to open" ),
52325233
lastUsedDir,
5233-
tr( "QGIS files" ) + " (*.qgs *.QGS)" );
5234+
tr( "QGIS files" ) + " (*.qgs *.qgz *.QGS)" );
52345235
if ( fullPath.isNull() )
52355236
{
52365237
return;
@@ -5275,7 +5276,7 @@ bool QgisApp::addProject( const QString &projectFile )
52755276
bool autoSetupOnFirstLayer = mLayerTreeCanvasBridge->autoSetupOnFirstLayer();
52765277
mLayerTreeCanvasBridge->setAutoSetupOnFirstLayer( false );
52775278

5278-
if ( !QgsProject::instance()->read( projectFile ) )
5279+
if ( !QgsProject::instance()->read( projectFile ) && !QgsZipUtils::isZipFile( projectFile ) )
52795280
{
52805281
QString backupFile = projectFile + "~";
52815282
QString loadBackupPrompt;
@@ -5415,22 +5416,30 @@ bool QgisApp::fileSave()
54155416
QgsSettings settings;
54165417
QString lastUsedDir = settings.value( QStringLiteral( "UI/lastProjectDir" ), QDir::homePath() ).toString();
54175418

5419+
const QString qgsExt = tr( "QGIS files" ) + " (*.qgs)";
5420+
const QString zipExt = tr( "QGZ files" ) + " (*.qgz)";
5421+
QString filter;
54185422
QString path = QFileDialog::getSaveFileName(
54195423
this,
54205424
tr( "Choose a QGIS project file" ),
54215425
lastUsedDir + '/' + QgsProject::instance()->title(),
5422-
tr( "QGIS files" ) + " (*.qgs *.QGS)" );
5426+
qgsExt + ";;" + zipExt, &filter );
54235427
if ( path.isEmpty() )
54245428
return false;
54255429

54265430
fullPath.setFile( path );
54275431

54285432
// make sure we have the .qgs extension in the file name
5429-
if ( "qgs" != fullPath.suffix().toLower() )
5433+
if ( filter == zipExt )
54305434
{
5431-
fullPath.setFile( fullPath.filePath() + ".qgs" );
5435+
if ( fullPath.suffix().compare( QLatin1String( "qgz" ), Qt::CaseInsensitive ) != 0 )
5436+
fullPath.setFile( fullPath.filePath() + ".qgz" );
5437+
}
5438+
else
5439+
{
5440+
if ( fullPath.suffix().compare( QLatin1String( "qgs" ), Qt::CaseInsensitive ) != 0 )
5441+
fullPath.setFile( fullPath.filePath() + ".qgs" );
54325442
}
5433-
54345443

54355444
QgsProject::instance()->setFileName( fullPath.filePath() );
54365445
}
@@ -5493,21 +5502,29 @@ void QgisApp::fileSaveAs()
54935502
QgsSettings settings;
54945503
QString lastUsedDir = settings.value( QStringLiteral( "UI/lastProjectDir" ), QDir::homePath() ).toString();
54955504

5505+
const QString qgsExt = tr( "QGIS files" ) + " (*.qgs *.QGS)";
5506+
const QString zipExt = tr( "QGZ files" ) + " (*.qgz)";
5507+
QString filter;
54965508
QString path = QFileDialog::getSaveFileName( this,
54975509
tr( "Choose a file name to save the QGIS project file as" ),
54985510
lastUsedDir + '/' + QgsProject::instance()->title(),
5499-
tr( "QGIS files" ) + " (*.qgs *.QGS)" );
5511+
qgsExt + ";;" + zipExt, &filter );
55005512
if ( path.isEmpty() )
55015513
return;
55025514

55035515
QFileInfo fullPath( path );
55045516

55055517
settings.setValue( QStringLiteral( "UI/lastProjectDir" ), fullPath.path() );
55065518

5507-
// make sure the .qgs extension is included in the path name. if not, add it...
5508-
if ( "qgs" != fullPath.suffix().toLower() )
5519+
if ( filter == zipExt )
5520+
{
5521+
if ( fullPath.suffix().compare( QLatin1String( "qgz" ), Qt::CaseInsensitive ) != 0 )
5522+
fullPath.setFile( fullPath.filePath() + ".qgz" );
5523+
}
5524+
else // .qgs
55095525
{
5510-
fullPath.setFile( fullPath.filePath() + ".qgs" );
5526+
if ( fullPath.suffix().compare( QLatin1String( "qgs" ), Qt::CaseInsensitive ) != 0 )
5527+
fullPath.setFile( fullPath.filePath() + ".qgs" );
55115528
}
55125529

55135530
QgsProject::instance()->setFileName( fullPath.filePath() );

0 commit comments

Comments
 (0)