QgsProject: cleanup of read/write method + removal of unused bad layer handler class

This commit is contained in:
Martin Dobias 2017-01-04 17:53:26 +08:00
parent 8a166324dc
commit 6c5956b22b
14 changed files with 37 additions and 389 deletions

View File

@ -262,6 +262,7 @@ should now call QgsCoordinateReferenceSystem::invalidateCache() and QgsCoordinat
- QgsMapLayerRegistry. Its functionality has been moved to QgsProject.
- QgsMapRenderer. It has been replaced by QgsMapRendererJob with subclasses and QgsMapSettings.
- QgsPseudoColorShader. This shader has been broken for some time and was replaced by QgsSingleBandPseudoColorRenderer.
- QgsProjectBadLayerGuiHandler was removed. It was unused in QGIS code and barely useful. Implement your own QgsProjectBadLayerHandler subclass if needed.
- QgsRendererV2DataDefinedMenus was removed. Use QgsDataDefinedButton instead.
- QgsLegacyHelpers.
- QgsProviderCountCalcEvent and QgsProviderExtentCalcEvent. These classes were unused in QGIS core and unmaintained.
@ -1381,6 +1382,10 @@ QgsProject {#qgis_api_break_3_0_QgsProject}
- title( const QString & title ) was removed. Use setTitle() instead.
- dirty( bool b ) was removed. Use setDirty() instead.
- clearProperties() was removed. Use clear() instead.
- read( QDomNode& layerNode ) was renamed to readLayer( const QDomNode& layerNode ).
- read( const QFileInfo& file ) was replaced by read( const QString& filename ).
- write( const QFileInfo& file ) was replaced by write( const QString& filename ).
QgsProjectPropertyValue {#qgis_api_break_3_0_QgsProjectPropertyValue}
-----------------------

View File

@ -106,53 +106,37 @@ class QgsProject : QObject, QgsExpressionContextGenerator
*/
void clear();
/** Reads a project file.
/** Reads given project file from the given file.
* @param file name of project file to read
* @note Any current plug-in state is erased
* @note Calling read() performs the following operations:
*
* - Gets the extents
* - Creates maplayers
* - Registers maplayers
*
* @note it's presumed that the caller has already reset the map canvas, map registry, and legend
* @returns true if project file has been read successfully
*/
bool read( const QFileInfo& file );
bool read( const QString& filename );
/** Reads the current project file.
* @note Any current plug-in state is erased
* @note Calling read() performs the following operations:
*
* - Gets the extents
* - Creates maplayers
* - Registers maplayers
*
* @note it's presumed that the caller has already reset the map canvas, map registry, and legend
/** Reads the project from its currently associated file (see fileName() ).
* @returns true if project file has been read successfully
*/
bool read();
/** Reads the layer described in the associated DOM node.
*
* @note This method is mainly for use by QgsProjectBadLayerHandler subclasses
* that may fix definition of bad layers with the user's help in GUI. Calling
* this method with corrected DOM node adds the layer back to the project.
*
* @param layerNode represents a QgsProject DOM node that encodes a specific layer.
*
* QgsProject raises an exception when one of the QgsProject::read()
* implementations fails. Since the read()s are invoked from qgisapp,
* then qgisapp handles the exception. It prompts the user for the new
* location of the data, if any. If there is a new location, the DOM
* node associated with the layer has its datasource tag corrected.
* Then that node is passed to this member function to be re-opened.
*
*/
bool read( QDomNode& layerNode );
bool write(const QString& filename);
bool readLayer( const QDomNode& layerNode );
/** Writes the project to a file.
* @param file destination file
/**
* Writes the project to a file.
* @param filename destination file
* @note calling this implicitly sets the project's filename (see setFileName() )
* @note isDirty() will be set to false if project is successfully written
* @returns true if project was written successfully
*
* \note Added in QGIS 3.0
*/
bool write( const QFileInfo& file );
bool write( const QString& filename );
/** Writes the project to its current associated file (see fileName() ).
* @note isDirty() will be set to false if project is successfully written

View File

@ -32,7 +32,6 @@ class QgsProjectBadLayerHandler
* log.
*
* @note Added in QGIS 3.0
* @see QgsProjectBadLayerGuiHandler
*/
virtual void handleBadLayers( const QList<QDomNode>& layers );
virtual ~QgsProjectBadLayerHandler();

View File

@ -140,7 +140,6 @@
%Include qgspluginmanagerinterface.sip
%Include qgspresetcolorrampdialog.sip
%Include qgsprevieweffect.sip
%Include qgsprojectbadlayerguihandler.sip
%Include qgsprojectionselectionwidget.sip
%Include qgsprojectionselector.sip
%Include qgsquerybuilder.sip

View File

@ -1,47 +0,0 @@
/** \ingroup gui
Handler for missing layers within project.
Gives user a chance to select path to the missing layers.
*/
class QgsProjectBadLayerGuiHandler : QObject, QgsProjectBadLayerHandler
{
%TypeHeaderCode
#include <qgsprojectbadlayerguihandler.h>
%End
public:
QgsProjectBadLayerGuiHandler();
/** Implementation of the handler */
virtual void handleBadLayers( const QList<QDomNode>& layers );
/** Flag to store the Ignore button press of MessageBox used by QgsLegend */
static bool mIgnore;
protected:
/** This is used to locate files that have moved or otherwise are missing */
bool findMissingFile( const QString& fileFilters, QDomNode& layerNode );
/**
* Find relocated data source for the given layer
*
* This QDom object represents a QgsProject node that maps to a specific layer.
*
* @param fileFilters file filters to use
* @param constLayerNode QDom node containing layer project information
*
* @todo
*
* XXX Only implemented for file based layers. It will need to be extended for
* XXX other data source types such as databases.
*/
bool findLayer( const QString& fileFilters, const QDomNode& constLayerNode );
/**
* Find relocated data sources for given layers
* These QDom objects represent QgsProject nodes that map to specific layers.
*/
void findLayers( const QString& fileFilters, const QList<QDomNode>& layerNodes );
};

View File

@ -369,7 +369,7 @@ void QgsHandleBadLayers::apply()
QString datasource = item->text();
node.namedItem( QStringLiteral( "datasource" ) ).toElement().firstChild().toText().setData( datasource );
if ( QgsProject::instance()->read( node ) )
if ( QgsProject::instance()->readLayer( node ) )
{
mLayerList->removeRow( i-- );
}

View File

@ -973,7 +973,7 @@ void QgsOptions::on_cbxProjectDefaultNew_toggled( bool checked )
void QgsOptions::on_pbnProjectDefaultSetCurrent_clicked()
{
QString fileName = QgsApplication::qgisSettingsDirPath() + QStringLiteral( "project_default.qgs" );
if ( QgsProject::instance()->write( QFileInfo( fileName ) ) )
if ( QgsProject::instance()->write( fileName ) )
{
QMessageBox::information( nullptr, tr( "Save default project" ), tr( "Current project saved as default" ) );
}

View File

@ -757,9 +757,9 @@ bool QgsProject::addLayer( const QDomElement &layerElem, QList<QDomNode> &broken
}
}
bool QgsProject::read( const QFileInfo& file )
bool QgsProject::read( const QString& filename )
{
mFile.setFileName( file.filePath() );
mFile.setFileName( filename );
return read();
}
@ -1123,7 +1123,7 @@ void QgsProject::cleanTransactionGroups( bool force )
emit transactionGroupsChanged();
}
bool QgsProject::read( QDomNode &layerNode )
bool QgsProject::readLayer( const QDomNode& layerNode )
{
QList<QDomNode> brokenNodes;
QList< QPair< QgsVectorLayer*, QDomElement > > vectorLayerList;
@ -1154,13 +1154,6 @@ bool QgsProject::write( const QString& filename )
return write();
}
bool QgsProject::write( QFileInfo const &file )
{
mFile.setFileName( file.filePath() );
return write();
}
bool QgsProject::write()
{
clearError();

View File

@ -166,44 +166,26 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
*/
void clear();
/** Reads a project file.
/** Reads given project file from the given file.
* @param file name of project file to read
* @note Any current plug-in state is erased
* @note Calling read() performs the following operations:
*
* - Gets the extents
* - Creates maplayers
* - Registers maplayers
*
* @note it's presumed that the caller has already reset the map canvas, map registry, and legend
* @returns true if project file has been read successfully
*/
bool read( const QFileInfo& file );
bool read( const QString& filename );
/** Reads the current project file.
* @note Any current plug-in state is erased
* @note Calling read() performs the following operations:
*
* - Gets the extents
* - Creates maplayers
* - Registers maplayers
*
* @note it's presumed that the caller has already reset the map canvas, map registry, and legend
/** Reads the project from its currently associated file (see fileName() ).
* @returns true if project file has been read successfully
*/
bool read();
/** Reads the layer described in the associated DOM node.
*
* @note This method is mainly for use by QgsProjectBadLayerHandler subclasses
* that may fix definition of bad layers with the user's help in GUI. Calling
* this method with corrected DOM node adds the layer back to the project.
*
* @param layerNode represents a QgsProject DOM node that encodes a specific layer.
*
* QgsProject raises an exception when one of the QgsProject::read()
* implementations fails. Since the read()s are invoked from qgisapp,
* then qgisapp handles the exception. It prompts the user for the new
* location of the data, if any. If there is a new location, the DOM
* node associated with the layer has its datasource tag corrected.
* Then that node is passed to this member function to be re-opened.
*
*/
bool read( QDomNode& layerNode );
bool readLayer( const QDomNode& layerNode );
/**
* Writes the project to a file.
@ -216,14 +198,6 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
*/
bool write( const QString& filename );
/** Writes the project to a file.
* @param file destination file
* @note calling this implicitly sets the project's filename (see setFileName() )
* @note isDirty() will be set to false if project is successfully written
* @returns true if project was written successfully
*/
bool write( const QFileInfo& file );
/** Writes the project to its current associated file (see fileName() ).
* @note isDirty() will be set to false if project is successfully written
* @returns true if project was written successfully

View File

@ -35,7 +35,6 @@ class CORE_EXPORT QgsProjectBadLayerHandler
* log.
*
* @note Added in QGIS 3.0
* @see QgsProjectBadLayerGuiHandler
*/
virtual void handleBadLayers( const QList<QDomNode>& layers );
virtual ~QgsProjectBadLayerHandler() = default;

View File

@ -287,7 +287,6 @@ SET(QGIS_GUI_SRCS
qgspluginmanagerinterface.cpp
qgspresetcolorrampdialog.cpp
qgsprevieweffect.cpp
qgsprojectbadlayerguihandler.cpp
qgsprojectionselectionwidget.cpp
qgsprojectionselector.cpp
qgsquerybuilder.cpp
@ -450,7 +449,6 @@ SET(QGIS_GUI_MOC_HDRS
qgspluginmanagerinterface.h
qgspresetcolorrampdialog.h
qgsprevieweffect.h
qgsprojectbadlayerguihandler.h
qgsprojectionselectionwidget.h
qgsprojectionselector.h
qgsquerybuilder.h

View File

@ -1,190 +0,0 @@
/***************************************************************************
qgsprojectbadlayerguihandler.cpp - handle bad layers
---------------------
begin : December 2009
copyright : (C) 2009 by Martin Dobias
email : wonder dot sk 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 "qgsprojectbadlayerguihandler.h"
#include <QApplication>
#include <QDomDocument>
#include <QFileInfo>
#include <QMessageBox>
#include <QPushButton>
#include "qgslogger.h"
#include "qgisgui.h"
#include "qgsproviderregistry.h"
#include "qgsproject.h"
#include "qgsapplication.h"
QgsProjectBadLayerGuiHandler::QgsProjectBadLayerGuiHandler()
{
}
bool QgsProjectBadLayerGuiHandler::mIgnore = false;
void QgsProjectBadLayerGuiHandler::handleBadLayers( const QList<QDomNode>& layers )
{
QgsDebugMsg( QString( "%1 bad layers found" ).arg( layers.size() ) );
// make sure we have arrow cursor (and not a wait cursor)
QApplication::setOverrideCursor( Qt::ArrowCursor );
QMessageBox messageBox;
QAbstractButton *ignoreButton =
messageBox.addButton( tr( "Ignore" ), QMessageBox::ActionRole );
QAbstractButton *okButton = messageBox.addButton( QMessageBox :: Ok );
messageBox.addButton( QMessageBox :: Cancel );
messageBox.setWindowTitle( tr( "QGIS Project Read Error" ) );
messageBox.setText( tr( "Unable to open one or more project layers.\nChoose "
"ignore to continue loading without the missing layers. Choose cancel to "
"return to your pre-project load state. Choose OK to try to find the "
"missing layers." ) );
messageBox.setIcon( QMessageBox::Critical );
messageBox.exec();
QgsProjectBadLayerGuiHandler::mIgnore = false;
if ( messageBox.clickedButton() == okButton )
{
QgsDebugMsg( "want to find missing layers is true" );
// attempt to find the new locations for missing layers
// XXX vector file hard-coded -- but what if it's raster?
QString filter = QgsProviderRegistry::instance()->fileVectorFilters();
findLayers( filter, layers );
}
else if ( messageBox.clickedButton() == ignoreButton )
{
QgsProjectBadLayerGuiHandler::mIgnore = true;
}
else
{
// Do nothing
}
QApplication::restoreOverrideCursor();
}
bool QgsProjectBadLayerGuiHandler::findLayer( const QString& fileFilters, const QDomNode& constLayerNode )
{
// XXX actually we could possibly get away with a copy of the node
QDomNode& layerNode = const_cast<QDomNode&>( constLayerNode );
bool retVal = false;
switch ( providerType( layerNode ) )
{
case IS_FILE:
QgsDebugMsg( "layer is file based" );
retVal = findMissingFile( fileFilters, layerNode );
break;
case IS_DATABASE:
QgsDebugMsg( "layer is database based" );
break;
case IS_URL:
QgsDebugMsg( "layer is URL based" );
break;
case IS_Unknown:
QgsDebugMsg( "layer has an unknown type" );
break;
}
return retVal;
}
bool QgsProjectBadLayerGuiHandler::findMissingFile( const QString& fileFilters, QDomNode& layerNode )
{
// Prepend that file name to the valid file format filter list since it
// makes it easier for the user to not only find the original file, but to
// perhaps find a similar file.
QFileInfo originalDataSource( dataSource( layerNode ) );
QString memoryQualifier; // to differentiate between last raster and
// vector directories
switch ( dataType( layerNode ) )
{
case IS_VECTOR:
{
memoryQualifier = QStringLiteral( "lastVectorFileFilter" );
break;
}
case IS_RASTER:
{
memoryQualifier = QStringLiteral( "lastRasterFileFilter" );
break;
}
default:
QgsDebugMsg( "unable to determine data type" );
return false;
}
// Prepend the original data source base name to make it easier to pick it
// out from a list of other files; however the appropriate filter strings
// for the file type will also be added in case the file name itself has
// changed, too.
QString myFileFilters = originalDataSource.fileName() + ";;" + fileFilters;
QStringList selectedFiles;
QString enc;
QString title = QObject::tr( "Where is '%1' (original location: %2)?" )
.arg( originalDataSource.fileName(),
originalDataSource.absoluteFilePath() );
bool retVal = QgisGui::openFilesRememberingFilter( memoryQualifier,
myFileFilters,
selectedFiles,
enc,
title,
true );
if ( selectedFiles.isEmpty() )
{
return retVal;
}
else
{
setDataSource( layerNode, selectedFiles.first() );
if ( ! QgsProject::instance()->read( layerNode ) )
{
QgsDebugMsg( "unable to re-read layer" );
}
}
return retVal;
}
void QgsProjectBadLayerGuiHandler::findLayers( const QString& fileFilters, const QList<QDomNode>& layerNodes )
{
for ( QList<QDomNode>::const_iterator i = layerNodes.begin();
i != layerNodes.end();
++i )
{
if ( findLayer( fileFilters, *i ) )
{
// If findLayer returns true, the user hit Cancel All button
break;
}
}
}

View File

@ -1,65 +0,0 @@
/***************************************************************************
qgsprojectbadlayerguihandler.h - handle bad layers
---------------------
begin : December 2009
copyright : (C) 2009 by Martin Dobias
email : wonder dot sk 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 QGSPROJECTBADLAYERGUIHANDLER_H
#define QGSPROJECTBADLAYERGUIHANDLER_H
#include "qgsprojectbadlayerhandler.h"
#include <QObject>
/** \ingroup gui
Handler for missing layers within project.
Gives user a chance to select path to the missing layers.
*/
class GUI_EXPORT QgsProjectBadLayerGuiHandler : public QObject, public QgsProjectBadLayerHandler
{
Q_OBJECT
public:
QgsProjectBadLayerGuiHandler();
virtual void handleBadLayers( const QList<QDomNode>& layers ) override;
//! Flag to store the Ignore button press of MessageBox used by QgsLegend
static bool mIgnore;
protected:
//! This is used to locate files that have moved or otherwise are missing
bool findMissingFile( const QString& fileFilters, QDomNode& layerNode );
/**
* Find relocated data source for the given layer
*
* This QDom object represents a QgsProject node that maps to a specific layer.
*
* @param fileFilters file filters to use
* @param constLayerNode QDom node containing layer project information
*
* @todo
*
* XXX Only implemented for file based layers. It will need to be extended for
* XXX other data source types such as databases.
*/
bool findLayer( const QString& fileFilters, const QDomNode& constLayerNode );
/**
* Find relocated data sources for given layers
* These QDom objects represent QgsProject nodes that map to specific layers.
*/
void findLayers( const QString& fileFilters, const QList<QDomNode>& layerNodes );
};
#endif // QGSPROJECTBADLAYERGUIHANDLER_H

View File

@ -141,8 +141,7 @@ QgsBench::~QgsBench()
bool QgsBench::openProject( const QString & theFileName )
{
QFileInfo file( theFileName );
if ( ! QgsProject::instance()->read( file ) )
if ( ! QgsProject::instance()->read( theFileName ) )
{
return false;
}