mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-13 00:03:09 -04:00
[FEATURE] Background saving of vector layers
Switches the vector layer save operation to a background task using the task manager framework. Allows layers to saved without blocking the interface.
This commit is contained in:
parent
92091c536b
commit
95d000f662
@ -149,6 +149,7 @@
|
||||
%Include qgsunittypes.sip
|
||||
%Include qgsvectordataprovider.sip
|
||||
%Include qgsvectorfilewriter.sip
|
||||
%Include qgsvectorfilewritertask.sip
|
||||
%Include qgsvectorlayer.sip
|
||||
%Include qgsvectorlayercache.sip
|
||||
%Include qgsvectorlayereditbuffer.sip
|
||||
|
@ -78,14 +78,7 @@ class QgsTask : QObject
|
||||
*/
|
||||
double progress() const;
|
||||
|
||||
/**
|
||||
* Notifies the task that it should terminate. Calling this is not guaranteed
|
||||
* to immediately end the task, rather it sets the isCanceled() flag which
|
||||
* task subclasses can check and terminate their operations at an appropriate
|
||||
* time. Any subtasks owned by this task will also be canceled.
|
||||
* @see isCanceled()
|
||||
*/
|
||||
void cancel();
|
||||
virtual void cancel();
|
||||
|
||||
/**
|
||||
* Places the task on hold. If the task in not queued
|
||||
|
@ -97,6 +97,7 @@ class QgsVectorFileWriter
|
||||
ErrProjection,
|
||||
ErrFeatureWriteFailed,
|
||||
ErrInvalidLayer,
|
||||
Canceled,
|
||||
};
|
||||
|
||||
enum SymbologyExport
|
||||
@ -323,6 +324,8 @@ class QgsVectorFileWriter
|
||||
|
||||
/** Field value converter */
|
||||
QgsVectorFileWriter::FieldValueConverter* fieldValueConverter;
|
||||
|
||||
QgsFeedback* feedback;
|
||||
};
|
||||
|
||||
/** Writes a layer out to a vector file.
|
||||
|
25
python/core/qgsvectorfilewritertask.sip
Normal file
25
python/core/qgsvectorfilewritertask.sip
Normal file
@ -0,0 +1,25 @@
|
||||
class QgsVectorFileWriterTask : QgsTask
|
||||
{
|
||||
%TypeHeaderCode
|
||||
#include <qgsvectorfilewritertask.h>
|
||||
%End
|
||||
|
||||
public:
|
||||
|
||||
QgsVectorFileWriterTask( QgsVectorLayer* layer,
|
||||
const QString& fileName,
|
||||
const QgsVectorFileWriter::SaveVectorOptions& options );
|
||||
|
||||
virtual void cancel();
|
||||
|
||||
signals:
|
||||
|
||||
void writeComplete( const QString& newFilename );
|
||||
void errorOccurred( int error, const QString& errorMessage );
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool run();
|
||||
virtual void finished( bool result );
|
||||
};
|
||||
|
@ -250,6 +250,7 @@
|
||||
#include "qgsvectorlayerjoininfo.h"
|
||||
#include "qgsvectorlayerutils.h"
|
||||
#include "qgshelp.h"
|
||||
#include "qgsvectorfilewritertask.h"
|
||||
|
||||
#include "qgssublayersdialog.h"
|
||||
#include "ogr/qgsopenvectorlayerdialog.h"
|
||||
@ -6477,12 +6478,6 @@ void QgisApp::saveAsVectorFileGeneral( QgsVectorLayer* vlayer, bool symbologyOpt
|
||||
}
|
||||
}
|
||||
|
||||
// ok if the file existed it should be deleted now so we can continue...
|
||||
QApplication::setOverrideCursor( Qt::WaitCursor );
|
||||
|
||||
QgsVectorFileWriter::WriterError error;
|
||||
QString errorMessage;
|
||||
QString newFilename;
|
||||
QgsRectangle filterExtent = dialog->filterExtent();
|
||||
QgisAppFieldValueConverter converter( vlayer, dialog->attributesAsDisplayedValues() );
|
||||
QgisAppFieldValueConverter* converterPtr = nullptr;
|
||||
@ -6510,32 +6505,41 @@ void QgisApp::saveAsVectorFileGeneral( QgsVectorLayer* vlayer, bool symbologyOpt
|
||||
options.attributes = dialog->selectedAttributes();
|
||||
options.fieldValueConverter = converterPtr;
|
||||
|
||||
error = QgsVectorFileWriter::writeAsVectorFormat(
|
||||
vlayer, vectorFilename, options, &newFilename, &errorMessage );
|
||||
bool addToCanvas = dialog->addToCanvas();
|
||||
QString layerName = dialog->layername();
|
||||
QgsVectorFileWriterTask* writerTask = new QgsVectorFileWriterTask( vlayer, vectorFilename, options );
|
||||
|
||||
QApplication::restoreOverrideCursor();
|
||||
|
||||
if ( error == QgsVectorFileWriter::NoError )
|
||||
// when writer is successful:
|
||||
connect( writerTask, &QgsVectorFileWriterTask::writeComplete, this, [this, addToCanvas, layerName, encoding, vectorFilename, vlayer]( const QString& newFilename )
|
||||
{
|
||||
if ( dialog->addToCanvas() )
|
||||
if ( addToCanvas )
|
||||
{
|
||||
QString uri( newFilename );
|
||||
if ( !dialog->layername().isEmpty() )
|
||||
uri += "|layername=" + dialog->layername();
|
||||
addVectorLayers( QStringList( uri ), encoding, QStringLiteral( "file" ) );
|
||||
if ( !layerName.isEmpty() )
|
||||
uri += "|layername=" + layerName;
|
||||
this->addVectorLayers( QStringList( uri ), encoding, QStringLiteral( "file" ) );
|
||||
}
|
||||
emit layerSavedAs( vlayer, vectorFilename );
|
||||
messageBar()->pushMessage( tr( "Saving done" ),
|
||||
tr( "Export to vector file has been completed" ),
|
||||
QgsMessageBar::INFO, messageTimeout() );
|
||||
this->emit layerSavedAs( vlayer, vectorFilename );
|
||||
this->messageBar()->pushMessage( tr( "Saving done" ),
|
||||
tr( "Export to vector file has been completed" ),
|
||||
QgsMessageBar::INFO, messageTimeout() );
|
||||
}
|
||||
else
|
||||
);
|
||||
|
||||
// when an error occurs:
|
||||
connect( writerTask, &QgsVectorFileWriterTask::errorOccurred, this, [=]( int error, const QString & errorMessage )
|
||||
{
|
||||
QgsMessageViewer *m = new QgsMessageViewer( nullptr );
|
||||
m->setWindowTitle( tr( "Save error" ) );
|
||||
m->setMessageAsPlainText( tr( "Export to vector file failed.\nError: %1" ).arg( errorMessage ) );
|
||||
m->exec();
|
||||
if ( error != QgsVectorFileWriter::Canceled )
|
||||
{
|
||||
QgsMessageViewer *m = new QgsMessageViewer( nullptr );
|
||||
m->setWindowTitle( tr( "Save error" ) );
|
||||
m->setMessageAsPlainText( tr( "Export to vector file failed.\nError: %1" ).arg( errorMessage ) );
|
||||
m->exec();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
QgsApplication::taskManager()->addTask( writerTask );
|
||||
}
|
||||
|
||||
delete dialog;
|
||||
|
@ -237,6 +237,7 @@ SET(QGIS_CORE_SRCS
|
||||
qgsunittypes.cpp
|
||||
qgsvectordataprovider.cpp
|
||||
qgsvectorfilewriter.cpp
|
||||
qgsvectorfilewritertask.cpp
|
||||
qgsvectorlayer.cpp
|
||||
qgsvectorlayercache.cpp
|
||||
qgsvectorlayerdiagramprovider.cpp
|
||||
@ -528,6 +529,7 @@ SET(QGIS_CORE_MOC_HDRS
|
||||
qgstransactiongroup.h
|
||||
qgsunittypes.h
|
||||
qgsvectordataprovider.h
|
||||
qgsvectorfilewritertask.h
|
||||
qgsvectorlayercache.h
|
||||
qgsvectorlayereditbuffer.h
|
||||
qgsvectorlayereditpassthrough.h
|
||||
|
@ -116,9 +116,11 @@ class CORE_EXPORT QgsTask : public QObject
|
||||
* to immediately end the task, rather it sets the isCanceled() flag which
|
||||
* task subclasses can check and terminate their operations at an appropriate
|
||||
* time. Any subtasks owned by this task will also be canceled.
|
||||
* Derived classes must ensure that the base class implementation is called
|
||||
* from any overridden version.
|
||||
* @see isCanceled()
|
||||
*/
|
||||
void cancel();
|
||||
virtual void cancel();
|
||||
|
||||
/**
|
||||
* Places the task on hold. If the task in not queued
|
||||
|
@ -2426,6 +2426,12 @@ QgsVectorFileWriter::writeAsVectorFormat( QgsVectorLayer* layer,
|
||||
// write all features
|
||||
while ( fit.nextFeature( fet ) )
|
||||
{
|
||||
if ( options.feedback && options.feedback->isCanceled() )
|
||||
{
|
||||
delete writer;
|
||||
return Canceled;
|
||||
}
|
||||
|
||||
if ( shallTransform )
|
||||
{
|
||||
try
|
||||
@ -3085,3 +3091,4 @@ bool QgsVectorFileWriter::areThereNewFieldsToCreate( const QString& datasetName,
|
||||
OGR_DS_Destroy( hDS );
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,10 @@
|
||||
|
||||
#include "qgis_core.h"
|
||||
#include "qgsfields.h"
|
||||
#include "qgsfeedback.h"
|
||||
#include "qgssymbol.h"
|
||||
#include "qgstaskmanager.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include <ogr_api.h>
|
||||
|
||||
#include <QPair>
|
||||
@ -164,6 +167,7 @@ class CORE_EXPORT QgsVectorFileWriter
|
||||
ErrProjection,
|
||||
ErrFeatureWriteFailed,
|
||||
ErrInvalidLayer,
|
||||
Canceled, //!< Writing was interrupted by manual cancelation
|
||||
};
|
||||
|
||||
enum SymbologyExport
|
||||
@ -391,6 +395,9 @@ class CORE_EXPORT QgsVectorFileWriter
|
||||
|
||||
//! Field value converter
|
||||
FieldValueConverter* fieldValueConverter;
|
||||
|
||||
//! Optional feedback object allowing cancelation of layer save
|
||||
QgsFeedback* feedback = nullptr;
|
||||
};
|
||||
|
||||
/** Writes a layer out to a vector file.
|
||||
@ -616,4 +623,5 @@ class CORE_EXPORT QgsVectorFileWriter
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS( QgsVectorFileWriter::EditionCapabilities )
|
||||
|
||||
|
||||
#endif
|
||||
|
57
src/core/qgsvectorfilewritertask.cpp
Normal file
57
src/core/qgsvectorfilewritertask.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
/***************************************************************************
|
||||
qgsvectorfilewritertask.cpp
|
||||
---------------------------
|
||||
begin : Feb 2017
|
||||
copyright : (C) 2017 by Nyall Dawson
|
||||
email : nyall dot dawson at gmail dot 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 "qgsvectorfilewritertask.h"
|
||||
|
||||
|
||||
QgsVectorFileWriterTask::QgsVectorFileWriterTask( QgsVectorLayer* layer, const QString& fileName, const QgsVectorFileWriter::SaveVectorOptions& options )
|
||||
: QgsTask( tr( "Saving %1 " ).arg( fileName ), QgsTask::CanCancel )
|
||||
, mLayer( layer )
|
||||
, mDestFileName( fileName )
|
||||
, mOptions( options )
|
||||
{
|
||||
if ( !mOptions.feedback )
|
||||
{
|
||||
mOwnedFeedback.reset( new QgsFeedback() );
|
||||
mOptions.feedback = mOwnedFeedback.get();
|
||||
}
|
||||
}
|
||||
|
||||
void QgsVectorFileWriterTask::cancel()
|
||||
{
|
||||
mOptions.feedback->cancel();
|
||||
QgsTask::cancel();
|
||||
}
|
||||
|
||||
bool QgsVectorFileWriterTask::run()
|
||||
{
|
||||
if ( !mLayer )
|
||||
return false;
|
||||
|
||||
|
||||
mError = QgsVectorFileWriter::writeAsVectorFormat(
|
||||
mLayer, mDestFileName, mOptions, &mNewFilename, &mErrorMessage );
|
||||
return mError == QgsVectorFileWriter::NoError;
|
||||
}
|
||||
|
||||
void QgsVectorFileWriterTask::finished( bool result )
|
||||
{
|
||||
if ( result )
|
||||
emit writeComplete( mNewFilename );
|
||||
else
|
||||
emit errorOccurred( mError, mErrorMessage );
|
||||
}
|
85
src/core/qgsvectorfilewritertask.h
Normal file
85
src/core/qgsvectorfilewritertask.h
Normal file
@ -0,0 +1,85 @@
|
||||
/***************************************************************************
|
||||
qgsvectorfilewritertask.h
|
||||
-------------------------
|
||||
begin : Feb 2017
|
||||
copyright : (C) 2017 by Nyall Dawson
|
||||
email : nyall dot dawson at gmail dot 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 QGSVECTORFILEWRITERTASK_H
|
||||
#define QGSVECTORFILEWRITERTASK_H
|
||||
|
||||
#include "qgis_core.h"
|
||||
#include "qgsvectorfilewriter.h"
|
||||
#include "qgstaskmanager.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
|
||||
/**
|
||||
* \class QgsVectorFileWriterTask
|
||||
* \ingroup core
|
||||
* QgsTask task which performs a QgsVectorFileWriter layer saving operation as a background
|
||||
* task. This can be used to save a vector layer out to a file without blocking the
|
||||
* QGIS interface.
|
||||
* \note Added in QGIS 3.0
|
||||
*/
|
||||
class CORE_EXPORT QgsVectorFileWriterTask : public QgsTask
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for QgsVectorFileWriterTask. Takes a source \a layer, destination \a fileName
|
||||
* and save \a options.
|
||||
*/
|
||||
QgsVectorFileWriterTask( QgsVectorLayer* layer,
|
||||
const QString& fileName,
|
||||
const QgsVectorFileWriter::SaveVectorOptions& options );
|
||||
|
||||
virtual void cancel() override;
|
||||
|
||||
signals:
|
||||
|
||||
/**
|
||||
* Emitted when writing the layer is successfully completed. The \a newFilename
|
||||
* parameter indicates the file path for the written file.
|
||||
*/
|
||||
void writeComplete( const QString& newFilename );
|
||||
|
||||
/**
|
||||
* Emitted when an error occurs which prevented the file being written (or if
|
||||
* the task is canceled). The writing \a error and \a errorMessage will be reported.
|
||||
*/
|
||||
void errorOccurred( int error, const QString& errorMessage );
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool run() override;
|
||||
virtual void finished( bool result ) override;
|
||||
|
||||
private:
|
||||
|
||||
QPointer< QgsVectorLayer > mLayer = nullptr;
|
||||
|
||||
QString mDestFileName;
|
||||
|
||||
std::unique_ptr< QgsFeedback > mOwnedFeedback;
|
||||
|
||||
QgsVectorFileWriter::WriterError mError = QgsVectorFileWriter::NoError;
|
||||
|
||||
QString mNewFilename;
|
||||
QString mErrorMessage;
|
||||
|
||||
QgsVectorFileWriter::SaveVectorOptions mOptions;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user