Skip to content

Commit

Permalink
[FEATURE] Add the possibility to save/open a project in .qgz
Browse files Browse the repository at this point in the history
  • Loading branch information
pblottiere committed Jul 31, 2017
1 parent 15ed34c commit f155030
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 23 deletions.
17 changes: 17 additions & 0 deletions python/core/qgsproject.sip
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,23 @@ Returns the number of registered layers.
:rtype: bool
%End

bool zip();
%Docstring
:rtype: bool
%End

QString zipFileName() const;
%Docstring
:rtype: str
%End

void setZipFileName( const QString &filename );

bool unzipped() const;
%Docstring
:rtype: bool
%End


QList<QgsMapLayer *> addMapLayers( const QList<QgsMapLayer *> &mapLayers /Transfer/,
bool addToLegend = true);
Expand Down
91 changes: 72 additions & 19 deletions src/app/qgisapp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5235,10 +5235,12 @@ void QgisApp::fileOpen()
// Retrieve last used project dir from persistent settings
QgsSettings settings;
QString lastUsedDir = settings.value( QStringLiteral( "UI/lastProjectDir" ), QDir::homePath() ).toString();
const QString qgs_ext = tr( "QGIS files" ) + " (*.qgs *.QGS)";
const QString zip_ext = tr( "QGZ files" ) + " (*.qgz)";
QString fullPath = QFileDialog::getOpenFileName( this,
tr( "Choose a QGIS project file to open" ),
lastUsedDir,
tr( "QGIS files" ) + " (*.qgs *.QGS)" );
qgs_ext + ";;" + zip_ext );
if ( fullPath.isNull() )
{
return;
Expand Down Expand Up @@ -5271,6 +5273,8 @@ void QgisApp::enableProjectMacros()
*/
bool QgisApp::addProject( const QString &projectFile )
{
bool zip = ( QFileInfo( projectFile ).suffix() == "qgz" ) ? true : false;

// close the previous opened project if any
closeProject();

Expand All @@ -5283,7 +5287,17 @@ bool QgisApp::addProject( const QString &projectFile )
bool autoSetupOnFirstLayer = mLayerTreeCanvasBridge->autoSetupOnFirstLayer();
mLayerTreeCanvasBridge->setAutoSetupOnFirstLayer( false );

if ( !QgsProject::instance()->read( projectFile ) )
bool readOk = false;
if ( zip )
{
readOk = QgsProject::instance()->unzip( projectFile );
}
else
{
readOk = QgsProject::instance()->read( projectFile );
}

if ( !readOk && !zip )
{
QString backupFile = projectFile + "~";
QString loadBackupPrompt;
Expand Down Expand Up @@ -5417,34 +5431,47 @@ bool QgisApp::fileSave()
// that the project file name is reset to null in fileNew()
QFileInfo fullPath;

if ( QgsProject::instance()->fileName().isNull() )
if ( QgsProject::instance()->fileName().isNull() && QgsProject::instance()->zipFileName().isNull() )
{
// Retrieve last used project dir from persistent settings
QgsSettings settings;
QString lastUsedDir = settings.value( QStringLiteral( "UI/lastProjectDir" ), QDir::homePath() ).toString();

const QString qgs_ext = tr( "QGIS files" ) + " (*.qgs)";
const QString zip_ext = tr( "QGZ files" ) + " (*.qgz)";
QString filter;
QString path = QFileDialog::getSaveFileName(
this,
tr( "Choose a QGIS project file" ),
lastUsedDir + '/' + QgsProject::instance()->title(),
tr( "QGIS files" ) + " (*.qgs *.QGS)" );
qgs_ext + ";;" + zip_ext, &filter );
if ( path.isEmpty() )
return false;

fullPath.setFile( path );

// make sure we have the .qgs extension in the file name
if ( "qgs" != fullPath.suffix().toLower() )
if ( filter == zip_ext )
{
fullPath.setFile( fullPath.filePath() + ".qgs" );
}
if ( "qgz" != fullPath.suffix().toLower() )
fullPath.setFile( fullPath.filePath() + ".qgz" );

QgsProject::instance()->setZipFileName( fullPath.filePath() );
}
else
{
if ( "qgs" != fullPath.suffix().toLower() )
fullPath.setFile( fullPath.filePath() + ".qgs" );

QgsProject::instance()->setFileName( fullPath.filePath() );
QgsProject::instance()->setFileName( fullPath.filePath() );
}
}
else
{
QFileInfo fi( QgsProject::instance()->fileName() );
if ( QgsProject::instance()->unzipped() )
fi.setFile( QgsProject::instance()->zipFileName() );

fullPath = fi.absoluteFilePath();
if ( fi.exists() && !mProjectLastModified.isNull() && mProjectLastModified != fi.lastModified() )
{
Expand All @@ -5468,20 +5495,34 @@ bool QgisApp::fileSave()
}
}

if ( QgsProject::instance()->write() )
bool writeOk = false;
QString writtenFileName;

if ( QgsProject::instance()->unzipped() )
{
writeOk = QgsProject::instance()->zip();
writtenFileName = QgsProject::instance()->zipFileName();
}
else
{
writeOk = QgsProject::instance()->write();
writtenFileName = QgsProject::instance()->fileName();
}

if ( writeOk )
{
setTitleBarText_( *this ); // update title bar
mStatusBar->showMessage( tr( "Saved project to: %1" ).arg( QDir::toNativeSeparators( QgsProject::instance()->fileName() ) ), 5000 );
mStatusBar->showMessage( tr( "Saved project to: %1" ).arg( QDir::toNativeSeparators( writtenFileName ) ), 5000 );

saveRecentProjectPath( fullPath.filePath() );

QFileInfo fi( QgsProject::instance()->fileName() );
QFileInfo fi( writtenFileName );
mProjectLastModified = fi.lastModified();
}
else
{
QMessageBox::critical( this,
tr( "Unable to save project %1" ).arg( QDir::toNativeSeparators( QgsProject::instance()->fileName() ) ),
tr( "Unable to save project %1" ).arg( QDir::toNativeSeparators( writtenFileName ) ),
QgsProject::instance()->error() );
return false;
}
Expand All @@ -5501,29 +5542,41 @@ void QgisApp::fileSaveAs()
QgsSettings settings;
QString lastUsedDir = settings.value( QStringLiteral( "UI/lastProjectDir" ), QDir::homePath() ).toString();

const QString qgs_ext = tr( "QGIS files" ) + " (*.qgs *.QGS)";
const QString zip_ext = tr( "QGZ files" ) + " (*.qgz)";
QString filter;
QString path = QFileDialog::getSaveFileName( this,
tr( "Choose a file name to save the QGIS project file as" ),
lastUsedDir + '/' + QgsProject::instance()->title(),
tr( "QGIS files" ) + " (*.qgs *.QGS)" );
qgs_ext + ";;" + zip_ext, &filter );
if ( path.isEmpty() )
return;

QFileInfo fullPath( path );

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

// make sure the .qgs extension is included in the path name. if not, add it...
if ( "qgs" != fullPath.suffix().toLower() )
bool writeOk = false;
if ( filter == zip_ext )
{
fullPath.setFile( fullPath.filePath() + ".qgs" );
if ( "qgz" != fullPath.suffix().toLower() )
fullPath.setFile( fullPath.filePath() + ".qgz" );

writeOk = QgsProject::instance()->zip( fullPath.filePath() );
}
else // .qgs
{
if ( "qgs" != fullPath.suffix().toLower() )
fullPath.setFile( fullPath.filePath() + ".qgs" );

QgsProject::instance()->setFileName( fullPath.filePath() );
QgsProject::instance()->setFileName( fullPath.filePath() );
writeOk = QgsProject::instance()->write();
}

if ( QgsProject::instance()->write() )
if ( writeOk )
{
setTitleBarText_( *this ); // update title bar
mStatusBar->showMessage( tr( "Saved project to: %1" ).arg( QDir::toNativeSeparators( QgsProject::instance()->fileName() ) ), 5000 );
mStatusBar->showMessage( tr( "Saved project to: %1" ).arg( QDir::toNativeSeparators( fullPath.filePath() ) ), 5000 );
// add this to the list of recently used project files
saveRecentProjectPath( fullPath.filePath() );
mProjectLastModified = fullPath.lastModified();
Expand Down
5 changes: 5 additions & 0 deletions src/core/qgsarchive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ QString QgsArchive::filename() const
return mFilename;
}

void QgsArchive::setFileName( const QString &filename )
{
mFilename = filename;
}

QString QgsArchive::projectFile() const
{
Q_FOREACH ( const QString &file, mFiles )
Expand Down
2 changes: 2 additions & 0 deletions src/core/qgsarchive.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ class CORE_EXPORT QgsArchive

void addFile( const QString &filename );

void setFileName( const QString &filename );

QString filename() const;

QString projectFile() const;
Expand Down
43 changes: 39 additions & 4 deletions src/core/qgsproject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,8 @@ void QgsProject::setFileName( const QString &name )
if ( newHomePath != oldHomePath )
emit homePathChanged();

mArchive->clear();

setDirty( true );
}

Expand Down Expand Up @@ -763,6 +765,9 @@ bool QgsProject::read()
{
clearError();

if ( ! mUnzipping )
mArchive->clear();

std::unique_ptr<QDomDocument> doc( new QDomDocument( QStringLiteral( "qgis" ) ) );

if ( !mFile.open( QIODevice::ReadOnly | QIODevice::Text ) )
Expand Down Expand Up @@ -2085,27 +2090,38 @@ bool QgsProject::unzip( const QString &filename )
}

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

// keep the archive
mUnzipping = false;
mArchive.reset( archive.release() );

return true;
}

bool QgsProject::zip()
{
if ( unzipped() )
return zip( mArchive->filename() );

return false;
}

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

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

bool writeOk;
if ( qgsFile.open( QIODevice::WriteOnly ) )
Expand All @@ -2127,19 +2143,38 @@ bool QgsProject::zip( const QString &filename )
}

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

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

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

return true;
}

bool QgsProject::unzipped() const
{
return !mArchive->filename().isEmpty();
}

QString QgsProject::zipFileName() const
{
return mArchive->filename();
}

void QgsProject::setZipFileName( const QString &filename )
{
mArchive.reset( new QgsArchive() );
mArchive->setFileName( filename );
}

QList<QgsMapLayer *> QgsProject::addMapLayers(
const QList<QgsMapLayer *> &layers,
bool addToLegend,
Expand Down
9 changes: 9 additions & 0 deletions src/core/qgsproject.h
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,14 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
*/
bool zip( const QString &filename );

bool zip();

QString zipFileName() const;

void setZipFileName( const QString &filename );

bool unzipped() const;

#ifndef SIP_RUN

/** Returns a list of registered map layers with a specified layer type.
Expand Down Expand Up @@ -1066,6 +1074,7 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
QVariantMap mCustomVariables;

std::unique_ptr<QgsArchive> mArchive;
bool mUnzipping;

QFile mFile; // current physical project file
mutable QgsProjectPropertyKey mProperties; // property hierarchy, TODO: this shouldn't be mutable
Expand Down

0 comments on commit f155030

Please sign in to comment.