mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
Merge pull request #8359 from elpaso/handle-bad-layers2
[needs-docs][feature] Deferred handling of bad layers
This commit is contained in:
commit
c8b26771cf
@ -56,7 +56,14 @@ Returns true if any of the layers is modified
|
||||
|
||||
static void removeInvalidLayers( QgsLayerTreeGroup *group );
|
||||
%Docstring
|
||||
Remove layer nodes that refer to invalid layers
|
||||
Removes layer nodes that refer to invalid layers
|
||||
%End
|
||||
|
||||
static void storeOriginalLayersProperties( QgsLayerTreeGroup *group, const QDomDocument *doc );
|
||||
%Docstring
|
||||
Stores in a layer's originalXmlProperties the layer properties information
|
||||
|
||||
.. versionadded:: 3.6
|
||||
%End
|
||||
|
||||
static void replaceChildrenOfEmbeddedGroups( QgsLayerTreeGroup *group );
|
||||
|
@ -180,7 +180,7 @@ Returns the display name of the layer.
|
||||
|
||||
virtual QgsDataProvider *dataProvider();
|
||||
%Docstring
|
||||
Returns the layer's data provider.
|
||||
Returns the layer's data provider, it may be null.
|
||||
%End
|
||||
|
||||
|
||||
@ -966,6 +966,31 @@ Write just the symbology information for the layer into the document
|
||||
.. versionadded:: 2.16
|
||||
%End
|
||||
|
||||
|
||||
virtual void setDataSource( const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, bool loadDefaultStyleFlag = false );
|
||||
%Docstring
|
||||
Updates the data source of the layer. The layer's renderer and legend will be preserved only
|
||||
if the geometry type of the new data source matches the current geometry type of the layer.
|
||||
|
||||
Subclasses should override this method: default implementation does nothing.
|
||||
|
||||
:param dataSource: new layer data source
|
||||
:param baseName: base name of the layer
|
||||
:param provider: provider string
|
||||
:param options: provider options
|
||||
:param loadDefaultStyleFlag: set to true to reset the layer's style to the default for the
|
||||
data source
|
||||
|
||||
.. seealso:: :py:func:`dataSourceChanged`
|
||||
|
||||
.. versionadded:: 3.6
|
||||
%End
|
||||
|
||||
QString providerType() const;
|
||||
%Docstring
|
||||
Returns the provider type (provider key) for this layer
|
||||
%End
|
||||
|
||||
QUndoStack *undoStack();
|
||||
%Docstring
|
||||
Returns pointer to layer's undo stack
|
||||
@ -1210,6 +1235,25 @@ Returns the message that should be notified by the provider to triggerRepaint
|
||||
Returns true if the refresh on provider nofification is enabled
|
||||
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
QString originalXmlProperties() const;
|
||||
%Docstring
|
||||
Returns the XML properties of the original layer as they were when the layer
|
||||
was first read from the project file. In case of new layers this is normally empty.
|
||||
|
||||
The storage format for the XML is qlr
|
||||
|
||||
.. versionadded:: 3.6
|
||||
%End
|
||||
|
||||
void setOriginalXmlProperties( const QString &originalXmlProperties );
|
||||
%Docstring
|
||||
Sets the original XML properties for the layer to ``originalXmlProperties``
|
||||
|
||||
The storage format for the XML is qlr
|
||||
|
||||
.. versionadded:: 3.6
|
||||
%End
|
||||
|
||||
public slots:
|
||||
@ -1432,6 +1476,15 @@ Emitted when layer's flags have been modified.
|
||||
.. seealso:: :py:func:`flags`
|
||||
|
||||
.. versionadded:: 3.4
|
||||
%End
|
||||
|
||||
void dataSourceChanged();
|
||||
%Docstring
|
||||
Emitted whenever the layer's data source has been changed.
|
||||
|
||||
.. seealso:: :py:func:`setDataSource`
|
||||
|
||||
.. versionadded:: 3.5
|
||||
%End
|
||||
|
||||
protected:
|
||||
@ -1535,6 +1588,11 @@ Read style data common to all layer types
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
void setProviderType( const QString &providerType );
|
||||
%Docstring
|
||||
Sets the ``providerType`` (provider key)
|
||||
%End
|
||||
|
||||
|
||||
void appendError( const QgsErrorMessage &error );
|
||||
%Docstring
|
||||
@ -1563,6 +1621,8 @@ Checks whether a new set of dependencies will introduce a cycle
|
||||
%End
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
QFlags<QgsMapLayer::LayerFlag> operator|(QgsMapLayer::LayerFlag f1, QFlags<QgsMapLayer::LayerFlag> f2);
|
||||
|
@ -37,6 +37,13 @@ Constructor for QgsMapLayerStore.
|
||||
Returns the number of layers contained in the store.
|
||||
%End
|
||||
|
||||
int validCount() const;
|
||||
%Docstring
|
||||
Returns the number of valid layers contained in the store.
|
||||
|
||||
.. versionadded:: 3.6
|
||||
%End
|
||||
|
||||
|
||||
int __len__() const;
|
||||
%Docstring
|
||||
@ -89,6 +96,19 @@ Returns a map of all layers by layer ID.
|
||||
.. seealso:: :py:func:`layers`
|
||||
%End
|
||||
|
||||
QMap<QString, QgsMapLayer *> validMapLayers() const;
|
||||
%Docstring
|
||||
Returns a map of all valid layers by layer ID.
|
||||
|
||||
.. seealso:: :py:func:`mapLayer`
|
||||
|
||||
.. seealso:: :py:func:`mapLayersByName`
|
||||
|
||||
.. seealso:: :py:func:`layers`
|
||||
|
||||
.. versionadded:: 3.6
|
||||
%End
|
||||
|
||||
|
||||
QList<QgsMapLayer *> addMapLayers( const QList<QgsMapLayer *> &layers /Transfer/);
|
||||
|
||||
@ -104,7 +124,7 @@ The layersAdded() and layerWasAdded() signals will always be emitted.
|
||||
the layers yourself. Not available in Python.
|
||||
|
||||
:return: a list of the map layers that were added
|
||||
successfully. If a layer is invalid, or already exists in the store,
|
||||
successfully. If a layer already exists in the store,
|
||||
it will not be part of the returned list.
|
||||
|
||||
|
||||
|
@ -700,6 +700,11 @@ Returns a pointer to the project's internal layer store.
|
||||
int count() const;
|
||||
%Docstring
|
||||
Returns the number of registered layers.
|
||||
%End
|
||||
|
||||
int validCount() const;
|
||||
%Docstring
|
||||
Returns the number of registered valid layers.
|
||||
%End
|
||||
|
||||
QgsMapLayer *mapLayer( const QString &layerId ) const;
|
||||
@ -728,10 +733,12 @@ Retrieve a list of matching registered layers by layer name.
|
||||
.. seealso:: :py:func:`mapLayers`
|
||||
%End
|
||||
|
||||
QMap<QString, QgsMapLayer *> mapLayers() const;
|
||||
QMap<QString, QgsMapLayer *> mapLayers( const bool validOnly = false ) const;
|
||||
%Docstring
|
||||
Returns a map of all registered layers by layer ID.
|
||||
|
||||
:param validOnly: if set only valid layers will be returned
|
||||
|
||||
.. seealso:: :py:func:`mapLayer`
|
||||
|
||||
.. seealso:: :py:func:`mapLayersByName`
|
||||
@ -763,7 +770,7 @@ The legendLayersAdded() signal is emitted only if addToLegend is true.
|
||||
the layers yourself. Not available in Python.
|
||||
|
||||
:return: a list of the map layers that were added
|
||||
successfully. If a layer is invalid, or already exists in the registry,
|
||||
successfully. If a layer or already exists in the registry,
|
||||
it will not be part of the returned QList.
|
||||
|
||||
|
||||
|
@ -273,6 +273,7 @@ Returns a list of attributes used to form the referencing fields
|
||||
bool isValid() const;
|
||||
%Docstring
|
||||
Returns the validity of this relation. Don't use the information if it's not valid.
|
||||
A relation is considered valid if both referenced and referencig layers are valid.
|
||||
|
||||
:return: true if the relation is valid
|
||||
%End
|
||||
@ -300,6 +301,14 @@ Gets the referenced field counterpart given a referencing field.
|
||||
Gets the referencing field counterpart given a referenced field.
|
||||
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
void updateRelationStatus();
|
||||
%Docstring
|
||||
Updates the validity status of this relation.
|
||||
Will be called internally whenever a member is changed.
|
||||
|
||||
.. versionadded:: 3.6
|
||||
%End
|
||||
|
||||
};
|
||||
|
@ -45,6 +45,8 @@ Gets access to the relations managed by this class.
|
||||
void addRelation( const QgsRelation &relation );
|
||||
%Docstring
|
||||
Add a relation.
|
||||
Invalid relations are added only if both referencing layer and referenced
|
||||
layer exist.
|
||||
|
||||
:param relation: The relation to add.
|
||||
%End
|
||||
@ -134,6 +136,13 @@ This signal is emitted when the relations were loaded after reading a project
|
||||
Emitted when relations are added or removed to the manager.
|
||||
|
||||
.. versionadded:: 2.5
|
||||
%End
|
||||
|
||||
public slots:
|
||||
|
||||
void updateRelationsStatus();
|
||||
%Docstring
|
||||
Updates relations status
|
||||
%End
|
||||
|
||||
};
|
||||
|
@ -736,11 +736,6 @@ Returns point, line or polygon
|
||||
|
||||
%Docstring
|
||||
Returns the WKBType or WKBUnknown in case of error
|
||||
%End
|
||||
|
||||
QString providerType() const;
|
||||
%Docstring
|
||||
Returns the provider type for this layer
|
||||
%End
|
||||
|
||||
virtual QgsCoordinateReferenceSystem sourceCrs() const ${SIP_FINAL};
|
||||
@ -988,7 +983,8 @@ if the geometry type of the new data source matches the current geometry type of
|
||||
.. deprecated:: Use version with ProviderOptions argument instead
|
||||
%End
|
||||
|
||||
void setDataSource( const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, bool loadDefaultStyleFlag = false );
|
||||
virtual void setDataSource( const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, bool loadDefaultStyleFlag = false );
|
||||
|
||||
%Docstring
|
||||
Updates the data source of the layer. The layer's renderer and legend will be preserved only
|
||||
if the geometry type of the new data source matches the current geometry type of the layer.
|
||||
@ -2326,15 +2322,6 @@ by the backend data provider).
|
||||
|
||||
signals:
|
||||
|
||||
void dataSourceChanged();
|
||||
%Docstring
|
||||
Emitted whenever the layer's data source has been changed.
|
||||
|
||||
.. seealso:: :py:func:`setDataSource`
|
||||
|
||||
.. versionadded:: 3.4
|
||||
%End
|
||||
|
||||
void selectionChanged( const QgsFeatureIds &selected, const QgsFeatureIds &deselected, bool clearAndSelect );
|
||||
%Docstring
|
||||
This signal is emitted when selection was changed
|
||||
|
@ -114,7 +114,7 @@ Constructor for LayerOptions.
|
||||
|
||||
explicit QgsRasterLayer( const QString &uri,
|
||||
const QString &baseName = QString(),
|
||||
const QString &providerKey = "gdal",
|
||||
const QString &providerType = "gdal",
|
||||
const QgsRasterLayer::LayerOptions &options = QgsRasterLayer::LayerOptions() );
|
||||
%Docstring
|
||||
This is the constructor for the RasterLayer class.
|
||||
@ -192,6 +192,24 @@ Set the data provider.
|
||||
:param options: provider options
|
||||
|
||||
.. versionadded:: 3.2
|
||||
%End
|
||||
|
||||
virtual void setDataSource( const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, bool loadDefaultStyleFlag = false );
|
||||
|
||||
%Docstring
|
||||
Updates the data source of the layer. The layer's renderer and legend will be preserved only
|
||||
if the geometry type of the new data source matches the current geometry type of the layer.
|
||||
|
||||
:param dataSource: new layer data source
|
||||
:param baseName: base name of the layer
|
||||
:param provider: provider string
|
||||
:param options: provider options
|
||||
:param loadDefaultStyleFlag: set to true to reset the layer's style to the default for the
|
||||
data source
|
||||
|
||||
.. seealso:: :py:func:`dataSourceChanged`
|
||||
|
||||
.. versionadded:: 3.6
|
||||
%End
|
||||
|
||||
LayerType rasterType();
|
||||
|
@ -31,17 +31,22 @@ will return a (possibly invalid) QgsMimeDataUtils.Uri.
|
||||
%End
|
||||
public:
|
||||
|
||||
QgsDataSourceSelectDialog( bool setFilterByLayerType = false,
|
||||
QgsDataSourceSelectDialog( QgsBrowserModel *browserModel = 0,
|
||||
bool setFilterByLayerType = false,
|
||||
const QgsMapLayer::LayerType &layerType = QgsMapLayer::LayerType::VectorLayer,
|
||||
QWidget *parent = 0 );
|
||||
%Docstring
|
||||
Constructs a QgsDataSourceSelectDialog, optionally filtering by layer type
|
||||
|
||||
:param browserModel: an existing browser model (typically from app), if null an instance will be created
|
||||
:param setFilterByLayerType: activates filtering by layer type
|
||||
:param layerType: sets the layer type filter, this is in effect only if filtering by layer type is also active
|
||||
:param parent: the object
|
||||
%End
|
||||
|
||||
|
||||
~QgsDataSourceSelectDialog();
|
||||
|
||||
void setLayerTypeFilter( QgsMapLayer::LayerType layerType );
|
||||
%Docstring
|
||||
Sets layer type filter to ``layerType`` and activates the filtering
|
||||
|
@ -101,6 +101,7 @@
|
||||
|
||||
#include "qgsgui.h"
|
||||
#include "qgsnative.h"
|
||||
#include "qgsdatasourceselectdialog.h"
|
||||
|
||||
#ifdef HAVE_OPENCL
|
||||
#include "qgsopenclutils.h"
|
||||
@ -3941,7 +3942,8 @@ void QgisApp::initLayerTreeView()
|
||||
new QgsLayerTreeViewFilterIndicatorProvider( mLayerTreeView ); // gets parented to the layer view
|
||||
new QgsLayerTreeViewEmbeddedIndicatorProvider( mLayerTreeView ); // gets parented to the layer view
|
||||
new QgsLayerTreeViewMemoryIndicatorProvider( mLayerTreeView ); // gets parented to the layer view
|
||||
new QgsLayerTreeViewBadLayerIndicatorProvider( mLayerTreeView ); // gets parented to the layer view
|
||||
QgsLayerTreeViewBadLayerIndicatorProvider *badLayerIndicatorProvider = new QgsLayerTreeViewBadLayerIndicatorProvider( mLayerTreeView ); // gets parented to the layer view
|
||||
connect( badLayerIndicatorProvider, &QgsLayerTreeViewBadLayerIndicatorProvider::requestChangeDataSource, this, &QgisApp::changeDataSource );
|
||||
new QgsLayerTreeViewNonRemovableIndicatorProvider( mLayerTreeView ); // gets parented to the layer view
|
||||
|
||||
setupLayerTreeViewFromSettings();
|
||||
@ -6935,6 +6937,62 @@ void QgisApp::refreshFeatureActions()
|
||||
updateDefaultFeatureAction( mFeatureActionMenu->activeAction() );
|
||||
}
|
||||
|
||||
void QgisApp::changeDataSource( QgsMapLayer *layer )
|
||||
{
|
||||
// Get provider type
|
||||
QString providerType( layer->providerType() );
|
||||
QgsMapLayer::LayerType layerType( layer->type() );
|
||||
|
||||
QgsDataSourceSelectDialog dlg( mBrowserModel, true, layerType );
|
||||
|
||||
if ( dlg.exec() == QDialog::Accepted )
|
||||
{
|
||||
QgsMimeDataUtils::Uri uri( dlg.uri() );
|
||||
if ( uri.isValid() )
|
||||
{
|
||||
bool layerIsValid( layer->isValid() );
|
||||
layer->setDataSource( uri.uri, layer->name(), uri.providerKey, QgsDataProvider::ProviderOptions() );
|
||||
// Re-apply style
|
||||
if ( !( layerIsValid || layer->originalXmlProperties().isEmpty() ) )
|
||||
{
|
||||
QgsReadWriteContext context;
|
||||
context.setPathResolver( QgsProject::instance()->pathResolver() );
|
||||
context.setProjectTranslator( QgsProject::instance() );
|
||||
QString errorMsg;
|
||||
QDomDocument doc;
|
||||
if ( doc.setContent( layer->originalXmlProperties() ) )
|
||||
{
|
||||
QDomNode layer_node( doc.firstChild( ) );
|
||||
if ( ! layer->readSymbology( layer_node, errorMsg, context ) )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "Failed to restore original layer style from stored XML for layer %1: %2" )
|
||||
.arg( layer->name( ) )
|
||||
.arg( errorMsg ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "Failed to create XML QDomDocument for layer %1: %2" )
|
||||
.arg( layer->name( ) )
|
||||
.arg( errorMsg ) );
|
||||
}
|
||||
}
|
||||
|
||||
// All the following code is necessary to refresh the layer
|
||||
QgsLayerTreeModel *model = qobject_cast<QgsLayerTreeModel *>( mLayerTreeView->model() );
|
||||
if ( model )
|
||||
{
|
||||
QgsLayerTreeLayer *tl( model->rootGroup()->findLayer( layer->id() ) );
|
||||
if ( tl && tl->itemVisibilityChecked() )
|
||||
{
|
||||
tl->setItemVisibilityChecked( false );
|
||||
tl->setItemVisibilityChecked( true );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgisApp::measure()
|
||||
{
|
||||
mMapCanvas->setMapTool( mMapTools.mMeasureDist );
|
||||
|
@ -942,6 +942,16 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
|
||||
*/
|
||||
QgsBrowserModel *browserModel();
|
||||
|
||||
/*
|
||||
* Change data source for \a layer, a data source selection dialog
|
||||
* will be opened and if accepted the data selected source will be
|
||||
* applied.
|
||||
*
|
||||
* In case the layer was originally invalid and it had the original
|
||||
* XML layer properties, the properties will be applied.
|
||||
*/
|
||||
void changeDataSource( QgsMapLayer *layer );
|
||||
|
||||
/**
|
||||
* Add a raster layer directly without prompting user for location
|
||||
The caller must provide information compatible with the provider plugin
|
||||
@ -971,9 +981,9 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
|
||||
/**
|
||||
* \brief overloaded version of the private addLayer method that takes a list of
|
||||
* file names instead of prompting user with a dialog.
|
||||
\param enc encoding type for the layer
|
||||
\param dataSourceType type of ogr datasource
|
||||
\returns true if successfully added layer
|
||||
* \param enc encoding type for the layer
|
||||
* \param dataSourceType type of ogr datasource
|
||||
* \returns true if successfully added layer
|
||||
*/
|
||||
bool addVectorLayers( const QStringList &layerQStringList, const QString &enc, const QString &dataSourceType );
|
||||
|
||||
|
@ -199,6 +199,18 @@ QMenu *QgsAppLayerTreeViewMenuProvider::createContextMenu()
|
||||
|
||||
menu->addSeparator();
|
||||
|
||||
// change data source is only supported for vectors and rasters
|
||||
if ( vlayer || rlayer )
|
||||
{
|
||||
|
||||
QAction *a = new QAction( tr( "Change data source…" ), menu );
|
||||
connect( a, &QAction::triggered, [ = ]
|
||||
{
|
||||
QgisApp::instance()->changeDataSource( layer );
|
||||
} );
|
||||
menu->addAction( a );
|
||||
}
|
||||
|
||||
if ( vlayer )
|
||||
{
|
||||
QAction *toggleEditingAction = QgisApp::instance()->actionToggleEditing();
|
||||
@ -210,7 +222,7 @@ QMenu *QgsAppLayerTreeViewMenuProvider::createContextMenu()
|
||||
QgisApp::instance(), [ = ] { QgisApp::instance()->attributeTable(); } );
|
||||
|
||||
// allow editing
|
||||
int cap = vlayer->dataProvider()->capabilities();
|
||||
unsigned int cap = vlayer->dataProvider()->capabilities();
|
||||
if ( cap & QgsVectorDataProvider::EditingCapabilities )
|
||||
{
|
||||
if ( toggleEditingAction )
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "qgsproviderregistry.h"
|
||||
#include "qgsmessagebar.h"
|
||||
#include "qgssettings.h"
|
||||
#include "qgslayertreeregistrybridge.h"
|
||||
|
||||
#include <QDomDocument>
|
||||
#include <QDomElement>
|
||||
@ -33,6 +34,7 @@
|
||||
#include <QPushButton>
|
||||
#include <QToolButton>
|
||||
#include <QMessageBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QUrl>
|
||||
|
||||
void QgsHandleBadLayersHandler::handleBadLayers( const QList<QDomNode> &layers )
|
||||
@ -40,6 +42,10 @@ void QgsHandleBadLayersHandler::handleBadLayers( const QList<QDomNode> &layers )
|
||||
QApplication::setOverrideCursor( Qt::ArrowCursor );
|
||||
QgsHandleBadLayers *dialog = new QgsHandleBadLayers( layers );
|
||||
|
||||
dialog->buttonBox->button( QDialogButtonBox::Ignore )->setToolTip( tr( "Import all bad layers unmodified (you can fix them later)." ) );
|
||||
dialog->buttonBox->button( QDialogButtonBox::Apply )->setToolTip( tr( "Apply fixes to bad layers (remaining bad layers will be removed from the project)." ) );
|
||||
dialog->buttonBox->button( QDialogButtonBox::Discard )->setToolTip( tr( "Remove all bad layers from the project" ) );
|
||||
|
||||
if ( dialog->layerCount() < layers.size() )
|
||||
QgisApp::instance()->messageBar()->pushMessage(
|
||||
tr( "Handle bad layers" ),
|
||||
@ -72,6 +78,8 @@ QgsHandleBadLayers::QgsHandleBadLayers( const QList<QDomNode> &layers )
|
||||
connect( mLayerList, &QTableWidget::itemSelectionChanged, this, &QgsHandleBadLayers::selectionChanged );
|
||||
connect( mBrowseButton, &QAbstractButton::clicked, this, &QgsHandleBadLayers::browseClicked );
|
||||
connect( buttonBox->button( QDialogButtonBox::Apply ), &QAbstractButton::clicked, this, &QgsHandleBadLayers::apply );
|
||||
connect( buttonBox->button( QDialogButtonBox::Ignore ), &QPushButton::clicked, this, &QgsHandleBadLayers::reject );
|
||||
connect( buttonBox->button( QDialogButtonBox::Discard ), &QPushButton::clicked, this, &QgsHandleBadLayers::accept );
|
||||
|
||||
mLayerList->clear();
|
||||
mLayerList->setSortingEnabled( true );
|
||||
@ -340,6 +348,17 @@ void QgsHandleBadLayers::editAuthCfg()
|
||||
|
||||
void QgsHandleBadLayers::apply()
|
||||
{
|
||||
QgsProject::instance()->layerTreeRegistryBridge()->setEnabled( true );
|
||||
|
||||
QList<QgsMapLayer *> toRemove;
|
||||
for ( const auto &l : QgsProject::instance()->mapLayers( ) )
|
||||
{
|
||||
if ( ! l->isValid() )
|
||||
toRemove << l;
|
||||
}
|
||||
|
||||
QgsProject::instance()->removeMapLayers( toRemove );
|
||||
|
||||
for ( int i = 0; i < mLayerList->rowCount(); i++ )
|
||||
{
|
||||
int idx = mLayerList->item( i, 0 )->data( Qt::UserRole ).toInt();
|
||||
@ -358,11 +377,15 @@ void QgsHandleBadLayers::apply()
|
||||
item->setForeground( QBrush( Qt::red ) );
|
||||
}
|
||||
}
|
||||
QgsProject::instance()->layerTreeRegistryBridge()->setEnabled( false );
|
||||
|
||||
if ( mLayerList->rowCount() == 0 )
|
||||
accept();
|
||||
|
||||
}
|
||||
|
||||
void QgsHandleBadLayers::accept()
|
||||
{
|
||||
apply();
|
||||
|
||||
if ( mLayerList->rowCount() > 0 &&
|
||||
QMessageBox::warning( this,
|
||||
@ -375,28 +398,20 @@ void QgsHandleBadLayers::accept()
|
||||
{
|
||||
return;
|
||||
}
|
||||
QList<QgsMapLayer *> toRemove;
|
||||
for ( const auto &l : QgsProject::instance()->mapLayers( ) )
|
||||
{
|
||||
if ( ! l->isValid() )
|
||||
toRemove << l;
|
||||
}
|
||||
QgsProject::instance()->layerTreeRegistryBridge()->setEnabled( true );
|
||||
QgsProject::instance()->removeMapLayers( toRemove );
|
||||
QgsProject::instance()->layerTreeRegistryBridge()->setEnabled( false );
|
||||
mLayerList->clear();
|
||||
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void QgsHandleBadLayers::reject()
|
||||
{
|
||||
|
||||
if ( mLayerList->rowCount() > 0 &&
|
||||
QMessageBox::warning( this,
|
||||
tr( "Unhandled layer will be lost." ),
|
||||
tr( "There are still %n unhandled layer(s), that will be lost if you closed now.",
|
||||
"unhandled layers",
|
||||
mLayerList->rowCount() ),
|
||||
QMessageBox::Ok | QMessageBox::Cancel,
|
||||
QMessageBox::Cancel ) == QMessageBox::Cancel )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
int QgsHandleBadLayers::layerCount()
|
||||
{
|
||||
return mLayerList->rowCount();
|
||||
|
@ -39,7 +39,7 @@ class QPushButton;
|
||||
|
||||
class APP_EXPORT QgsHandleBadLayers
|
||||
: public QDialog
|
||||
, private Ui::QgsHandleBadLayersBase
|
||||
, public Ui::QgsHandleBadLayersBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@ -54,7 +54,6 @@ class APP_EXPORT QgsHandleBadLayers
|
||||
void editAuthCfg();
|
||||
void apply();
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
|
||||
private:
|
||||
QPushButton *mBrowseButton = nullptr;
|
||||
|
@ -20,7 +20,16 @@
|
||||
#include "qgslayertreeutils.h"
|
||||
#include "qgslayertreemodel.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsrasterlayer.h"
|
||||
#include "qgisapp.h"
|
||||
#include "qgsbrowsermodel.h"
|
||||
#include "qgsbrowsertreeview.h"
|
||||
#include "qgsbrowserproxymodel.h"
|
||||
|
||||
#include <functional>
|
||||
#include <QDialog>
|
||||
#include <QVBoxLayout>
|
||||
#include <QDialogButtonBox>
|
||||
|
||||
QgsLayerTreeViewBadLayerIndicatorProvider::QgsLayerTreeViewBadLayerIndicatorProvider( QgsLayerTreeView *view )
|
||||
: QgsLayerTreeViewIndicatorProvider( view )
|
||||
@ -33,11 +42,12 @@ void QgsLayerTreeViewBadLayerIndicatorProvider::onIndicatorClicked( const QModel
|
||||
if ( !QgsLayerTree::isLayer( node ) )
|
||||
return;
|
||||
|
||||
QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( QgsLayerTree::toLayer( node )->layer() );
|
||||
if ( !vlayer )
|
||||
QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( QgsLayerTree::toLayer( node )->layer() );
|
||||
|
||||
if ( !layer )
|
||||
return;
|
||||
|
||||
// TODO: open source select dialog
|
||||
emit requestChangeDataSource( layer );
|
||||
}
|
||||
|
||||
QString QgsLayerTreeViewBadLayerIndicatorProvider::iconName( QgsMapLayer *layer )
|
||||
@ -49,8 +59,7 @@ QString QgsLayerTreeViewBadLayerIndicatorProvider::iconName( QgsMapLayer *layer
|
||||
QString QgsLayerTreeViewBadLayerIndicatorProvider::tooltipText( QgsMapLayer *layer )
|
||||
{
|
||||
Q_UNUSED( layer );
|
||||
// TODO, click here to set a new data source.
|
||||
return tr( "<b>Bad layer!</b><br>Layer data source could not be found." );
|
||||
return tr( "<b>Bad layer!</b><br>Layer data source could not be found. Click to set a new data source" );
|
||||
}
|
||||
|
||||
bool QgsLayerTreeViewBadLayerIndicatorProvider::acceptLayer( QgsMapLayer *layer )
|
||||
|
@ -29,9 +29,18 @@ class QgsLayerTreeViewBadLayerIndicatorProvider : public QgsLayerTreeViewIndicat
|
||||
public:
|
||||
explicit QgsLayerTreeViewBadLayerIndicatorProvider( QgsLayerTreeView *view );
|
||||
|
||||
signals:
|
||||
|
||||
/**
|
||||
* This signal is emitted when the user clicks on the bad layer indicator icon
|
||||
* \param maplayer for change data source request
|
||||
*/
|
||||
void requestChangeDataSource( QgsMapLayer *maplayer );
|
||||
|
||||
protected slots:
|
||||
void onIndicatorClicked( const QModelIndex &index ) override;
|
||||
|
||||
|
||||
private:
|
||||
QString iconName( QgsMapLayer *layer ) override;
|
||||
QString tooltipText( QgsMapLayer *layer ) override;
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "qgslayertreeutils.h"
|
||||
#include "qgslayertreeview.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsrasterlayer.h"
|
||||
#include "qgisapp.h"
|
||||
|
||||
QgsLayerTreeViewIndicatorProvider::QgsLayerTreeViewIndicatorProvider( QgsLayerTreeView *view )
|
||||
@ -89,16 +90,20 @@ void QgsLayerTreeViewIndicatorProvider::onWillRemoveChildren( QgsLayerTreeNode *
|
||||
|
||||
void QgsLayerTreeViewIndicatorProvider::onLayerLoaded()
|
||||
{
|
||||
|
||||
QgsLayerTreeLayer *layerNode = qobject_cast<QgsLayerTreeLayer *>( sender() );
|
||||
if ( !layerNode )
|
||||
return;
|
||||
|
||||
if ( QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layerNode->layer() ) )
|
||||
if ( !( qobject_cast<QgsVectorLayer *>( layerNode->layer() ) || qobject_cast<QgsRasterLayer *>( layerNode->layer() ) ) )
|
||||
return;
|
||||
|
||||
if ( QgsMapLayer *mapLayer = qobject_cast<QgsMapLayer *>( layerNode->layer() ) )
|
||||
{
|
||||
if ( vlayer )
|
||||
if ( mapLayer )
|
||||
{
|
||||
connectSignals( vlayer );
|
||||
addOrRemoveIndicator( layerNode, vlayer );
|
||||
connectSignals( mapLayer );
|
||||
addOrRemoveIndicator( layerNode, mapLayer );
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -123,18 +128,18 @@ void QgsLayerTreeViewIndicatorProvider::onLayerChanged()
|
||||
|
||||
void QgsLayerTreeViewIndicatorProvider::connectSignals( QgsMapLayer *layer )
|
||||
{
|
||||
QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
|
||||
if ( !vlayer )
|
||||
if ( !( qobject_cast<QgsVectorLayer *>( layer ) || qobject_cast<QgsRasterLayer *>( layer ) ) )
|
||||
return;
|
||||
connect( vlayer, &QgsVectorLayer::dataSourceChanged, this, &QgsLayerTreeViewIndicatorProvider::onLayerChanged );
|
||||
QgsMapLayer *mapLayer = qobject_cast<QgsMapLayer *>( layer );
|
||||
connect( mapLayer, &QgsMapLayer::dataSourceChanged, this, &QgsLayerTreeViewIndicatorProvider::onLayerChanged );
|
||||
}
|
||||
|
||||
void QgsLayerTreeViewIndicatorProvider::disconnectSignals( QgsMapLayer *layer )
|
||||
{
|
||||
QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
|
||||
if ( !vlayer )
|
||||
if ( !( qobject_cast<QgsVectorLayer *>( layer ) || qobject_cast<QgsRasterLayer *>( layer ) ) )
|
||||
return;
|
||||
disconnect( vlayer, &QgsVectorLayer::dataSourceChanged, this, &QgsLayerTreeViewIndicatorProvider::onLayerChanged );
|
||||
QgsMapLayer *mapLayer = qobject_cast<QgsMapLayer *>( layer );
|
||||
disconnect( mapLayer, &QgsMapLayer::dataSourceChanged, this, &QgsLayerTreeViewIndicatorProvider::onLayerChanged );
|
||||
}
|
||||
|
||||
std::unique_ptr< QgsLayerTreeViewIndicator > QgsLayerTreeViewIndicatorProvider::newIndicator( QgsMapLayer *layer )
|
||||
|
@ -38,8 +38,8 @@ class QgsMapLayer;
|
||||
*
|
||||
* Subclasses may override:
|
||||
* - onIndicatorClicked() default implementation does nothing
|
||||
* - connectSignals() default implementation connects vector layers to dataSourceChanged()
|
||||
* - disconnectSignals() default implementation disconnects vector layers from dataSourceChanged()
|
||||
* - connectSignals() default implementation connects layers to dataSourceChanged()
|
||||
* - disconnectSignals() default implementation disconnects layers from dataSourceChanged()
|
||||
*/
|
||||
class QgsLayerTreeViewIndicatorProvider : public QObject
|
||||
{
|
||||
@ -51,9 +51,9 @@ class QgsLayerTreeViewIndicatorProvider : public QObject
|
||||
protected:
|
||||
|
||||
// Subclasses MAY override:
|
||||
//! Connect signals, default implementation connects vector layers to dataSourceChanged()
|
||||
//! Connect signals, default implementation connects layers to dataSourceChanged()
|
||||
virtual void connectSignals( QgsMapLayer *layer );
|
||||
//! Disconnect signals, default implementation disconnects vector layers from dataSourceChanged()
|
||||
//! Disconnect signals, default implementation disconnects layers from dataSourceChanged()
|
||||
virtual void disconnectSignals( QgsMapLayer *layer );
|
||||
|
||||
protected slots:
|
||||
|
@ -49,6 +49,9 @@ void QgsRelationManagerDialog::setLayers( const QList< QgsVectorLayer * > &layer
|
||||
|
||||
void QgsRelationManagerDialog::addRelation( const QgsRelation &rel )
|
||||
{
|
||||
if ( ! rel.isValid() )
|
||||
return;
|
||||
|
||||
mRelationsTable->setSortingEnabled( false );
|
||||
int row = mRelationsTable->rowCount();
|
||||
mRelationsTable->insertRow( row );
|
||||
|
@ -636,10 +636,13 @@ QImage QgsWmsLegendNode::getLegendGraphic() const
|
||||
|
||||
QgsRasterLayer *layer = qobject_cast<QgsRasterLayer *>( mLayerNode->layer() );
|
||||
const QgsLayerTreeModel *mod = model();
|
||||
if ( ! mod ) return mImage;
|
||||
if ( ! mod )
|
||||
return mImage;
|
||||
const QgsMapSettings *ms = mod->legendFilterMapSettings();
|
||||
|
||||
QgsRasterDataProvider *prov = layer->dataProvider();
|
||||
if ( ! prov )
|
||||
return mImage;
|
||||
|
||||
Q_ASSERT( ! mFetcher );
|
||||
mFetcher.reset( prov->getLegendGraphicFetcher( ms ) );
|
||||
|
@ -306,6 +306,40 @@ void QgsLayerTreeUtils::removeInvalidLayers( QgsLayerTreeGroup *group )
|
||||
group->removeChildNode( node );
|
||||
}
|
||||
|
||||
void QgsLayerTreeUtils::storeOriginalLayersProperties( QgsLayerTreeGroup *group, const QDomDocument *doc )
|
||||
{
|
||||
const QDomNodeList mlNodeList( doc->documentElement()
|
||||
.firstChildElement( QStringLiteral( "projectlayers" ) )
|
||||
.elementsByTagName( QStringLiteral( "maplayer" ) ) );
|
||||
for ( QgsLayerTreeNode *node : group->children() )
|
||||
{
|
||||
if ( QgsLayerTree::isLayer( node ) )
|
||||
{
|
||||
QgsMapLayer *l( QgsLayerTree::toLayer( node )->layer() );
|
||||
if ( l )
|
||||
{
|
||||
for ( int i = 0; i < mlNodeList.count(); i++ )
|
||||
{
|
||||
QDomNode mlNode( mlNodeList.at( i ) );
|
||||
QString id( mlNode.firstChildElement( QStringLiteral( "id" ) ).firstChild().nodeValue() );
|
||||
if ( id == l->id() )
|
||||
{
|
||||
QDomImplementation DomImplementation;
|
||||
QDomDocumentType documentType = DomImplementation.createDocumentType( QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
|
||||
QDomDocument document( documentType );
|
||||
QDomElement element = mlNode.toElement();
|
||||
document.appendChild( element );
|
||||
QString str;
|
||||
QTextStream stream( &str );
|
||||
document.save( stream, 4 /*indent*/ );
|
||||
l->setOriginalXmlProperties( str );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QStringList QgsLayerTreeUtils::invisibleLayerList( QgsLayerTreeNode *node )
|
||||
{
|
||||
QStringList list;
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <qnamespace.h>
|
||||
#include <QList>
|
||||
#include <QPair>
|
||||
#include <QDomNodeList>
|
||||
#include "qgis_core.h"
|
||||
|
||||
class QDomElement;
|
||||
@ -58,9 +59,15 @@ class CORE_EXPORT QgsLayerTreeUtils
|
||||
//! Returns true if any of the layers is modified
|
||||
static bool layersModified( const QList<QgsLayerTreeLayer *> &layerNodes );
|
||||
|
||||
//! Remove layer nodes that refer to invalid layers
|
||||
//! Removes layer nodes that refer to invalid layers
|
||||
static void removeInvalidLayers( QgsLayerTreeGroup *group );
|
||||
|
||||
/**
|
||||
* Stores in a layer's originalXmlProperties the layer properties information
|
||||
* \since 3.6
|
||||
*/
|
||||
static void storeOriginalLayersProperties( QgsLayerTreeGroup *group, const QDomDocument *doc );
|
||||
|
||||
//! Remove subtree of embedded groups and replaces it with a custom property embedded-visible-layers
|
||||
static void replaceChildrenOfEmbeddedGroups( QgsLayerTreeGroup *group );
|
||||
|
||||
|
@ -283,12 +283,6 @@ bool QgsMapLayer::readLayerXml( const QDomElement &layerElement, QgsReadWriteCon
|
||||
QgsCoordinateReferenceSystem::setCustomCrsValidation( savedValidation );
|
||||
mCRS = savedCRS;
|
||||
|
||||
// Abort if any error in layer, such as not found.
|
||||
if ( layerError )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// the internal name is just the data source basename
|
||||
//QFileInfo dataSourceFileInfo( mDataSource );
|
||||
//internalName = dataSourceFileInfo.baseName();
|
||||
@ -387,7 +381,7 @@ bool QgsMapLayer::readLayerXml( const QDomElement &layerElement, QgsReadWriteCon
|
||||
QDomElement metadataElem = layerElement.firstChildElement( QStringLiteral( "resourceMetadata" ) );
|
||||
mMetadata.readMetadataXml( metadataElem );
|
||||
|
||||
return true;
|
||||
return ! layerError;
|
||||
} // bool QgsMapLayer::readLayerXML
|
||||
|
||||
|
||||
@ -1579,6 +1573,21 @@ bool QgsMapLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &errorM
|
||||
return false;
|
||||
}
|
||||
|
||||
void QgsMapLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, bool loadDefaultStyleFlag )
|
||||
{
|
||||
Q_UNUSED( dataSource );
|
||||
Q_UNUSED( baseName );
|
||||
Q_UNUSED( provider );
|
||||
Q_UNUSED( options );
|
||||
Q_UNUSED( loadDefaultStyleFlag );
|
||||
}
|
||||
|
||||
|
||||
QString QgsMapLayer::providerType() const
|
||||
{
|
||||
return mProviderKey;
|
||||
}
|
||||
|
||||
void QgsMapLayer::readCommonStyle( const QDomElement &layerElement, const QgsReadWriteContext &context,
|
||||
QgsMapLayer::StyleCategories categories )
|
||||
{
|
||||
@ -1824,6 +1833,21 @@ bool QgsMapLayer::isReadOnly() const
|
||||
return true;
|
||||
}
|
||||
|
||||
QString QgsMapLayer::originalXmlProperties() const
|
||||
{
|
||||
return mOriginalXmlProperties;
|
||||
}
|
||||
|
||||
void QgsMapLayer::setOriginalXmlProperties( const QString &originalXmlProperties )
|
||||
{
|
||||
mOriginalXmlProperties = originalXmlProperties;
|
||||
}
|
||||
|
||||
void QgsMapLayer::setProviderType( const QString &providerType )
|
||||
{
|
||||
mProviderKey = providerType;
|
||||
}
|
||||
|
||||
QSet<QgsMapLayerDependency> QgsMapLayer::dependencies() const
|
||||
{
|
||||
return mDependencies;
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include "qgslayermetadata.h"
|
||||
#include "qgsmaplayerstyle.h"
|
||||
#include "qgsreadwritecontext.h"
|
||||
#include "qgsdataprovider.h"
|
||||
|
||||
class QgsAbstract3DRenderer;
|
||||
class QgsDataProvider;
|
||||
@ -231,12 +232,12 @@ class CORE_EXPORT QgsMapLayer : public QObject
|
||||
QString name() const;
|
||||
|
||||
/**
|
||||
* Returns the layer's data provider.
|
||||
* Returns the layer's data provider, it may be null.
|
||||
*/
|
||||
virtual QgsDataProvider *dataProvider();
|
||||
|
||||
/**
|
||||
* Returns the layer's data provider in a const-correct manner
|
||||
* Returns the layer's data provider in a const-correct manner, it may be null.
|
||||
* \note not available in Python bindings
|
||||
*/
|
||||
virtual const QgsDataProvider *dataProvider() const SIP_SKIP;
|
||||
@ -886,6 +887,29 @@ class CORE_EXPORT QgsMapLayer : public QObject
|
||||
virtual bool writeStyle( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context,
|
||||
StyleCategories categories = AllStyleCategories ) const;
|
||||
|
||||
|
||||
/**
|
||||
* Updates the data source of the layer. The layer's renderer and legend will be preserved only
|
||||
* if the geometry type of the new data source matches the current geometry type of the layer.
|
||||
*
|
||||
* Subclasses should override this method: default implementation does nothing.
|
||||
*
|
||||
* \param dataSource new layer data source
|
||||
* \param baseName base name of the layer
|
||||
* \param provider provider string
|
||||
* \param options provider options
|
||||
* \param loadDefaultStyleFlag set to true to reset the layer's style to the default for the
|
||||
* data source
|
||||
* \see dataSourceChanged()
|
||||
* \since QGIS 3.6
|
||||
*/
|
||||
virtual void setDataSource( const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, bool loadDefaultStyleFlag = false );
|
||||
|
||||
/**
|
||||
* Returns the provider type (provider key) for this layer
|
||||
*/
|
||||
QString providerType() const;
|
||||
|
||||
//! Returns pointer to layer's undo stack
|
||||
QUndoStack *undoStack();
|
||||
|
||||
@ -1077,6 +1101,25 @@ class CORE_EXPORT QgsMapLayer : public QObject
|
||||
*/
|
||||
bool isRefreshOnNotifyEnabled() const { return mIsRefreshOnNofifyEnabled; }
|
||||
|
||||
/**
|
||||
* Returns the XML properties of the original layer as they were when the layer
|
||||
* was first read from the project file. In case of new layers this is normally empty.
|
||||
*
|
||||
* The storage format for the XML is qlr
|
||||
*
|
||||
* \since QGIS 3.6
|
||||
*/
|
||||
QString originalXmlProperties() const;
|
||||
|
||||
/**
|
||||
* Sets the original XML properties for the layer to \a originalXmlProperties
|
||||
*
|
||||
* The storage format for the XML is qlr
|
||||
*
|
||||
* \since QGIS 3.6
|
||||
*/
|
||||
void setOriginalXmlProperties( const QString &originalXmlProperties );
|
||||
|
||||
public slots:
|
||||
|
||||
/**
|
||||
@ -1253,6 +1296,15 @@ class CORE_EXPORT QgsMapLayer : public QObject
|
||||
*/
|
||||
void flagsChanged();
|
||||
|
||||
/**
|
||||
* Emitted whenever the layer's data source has been changed.
|
||||
*
|
||||
* \see setDataSource()
|
||||
*
|
||||
* \since QGIS 3.5
|
||||
*/
|
||||
void dataSourceChanged();
|
||||
|
||||
private slots:
|
||||
|
||||
void onNotifiedTriggerRepaint( const QString &message );
|
||||
@ -1340,6 +1392,9 @@ class CORE_EXPORT QgsMapLayer : public QObject
|
||||
void readCommonStyle( const QDomElement &layerElement, const QgsReadWriteContext &context,
|
||||
StyleCategories categories = AllStyleCategories );
|
||||
|
||||
//! Sets the \a providerType (provider key)
|
||||
void setProviderType( const QString &providerType );
|
||||
|
||||
#ifndef SIP_RUN
|
||||
#if 0
|
||||
//! Debugging member - invoked when a connect() is made to this object
|
||||
@ -1400,6 +1455,10 @@ class CORE_EXPORT QgsMapLayer : public QObject
|
||||
bool mIsRefreshOnNofifyEnabled = false;
|
||||
QString mRefreshOnNofifyMessage;
|
||||
|
||||
//! Data provider key (name of the data provider)
|
||||
QString mProviderKey;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
virtual QString baseURI( PropertyType type ) const;
|
||||
@ -1465,6 +1524,13 @@ class CORE_EXPORT QgsMapLayer : public QObject
|
||||
//! Renderer for 3D views
|
||||
QgsAbstract3DRenderer *m3DRenderer = nullptr;
|
||||
|
||||
/**
|
||||
* Stores the original XML properties of the layer when loaded from the project
|
||||
*
|
||||
* This information can be used to pass through the bad layers or to reset changes on a good layer
|
||||
*/
|
||||
QString mOriginalXmlProperties;
|
||||
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE( QgsMapLayer * )
|
||||
|
@ -307,7 +307,7 @@ QList<QgsLayerTreeModelLegendNode *> QgsDefaultRasterLayerLegend::createLayerTre
|
||||
QList<QgsLayerTreeModelLegendNode *> nodes;
|
||||
|
||||
// temporary solution for WMS. Ideally should be done with a delegate.
|
||||
if ( mLayer->dataProvider()->supportsLegendGraphic() )
|
||||
if ( mLayer->dataProvider() && mLayer->dataProvider()->supportsLegendGraphic() )
|
||||
{
|
||||
nodes << new QgsWmsLegendNode( nodeLayer );
|
||||
}
|
||||
|
@ -16,7 +16,9 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsmaplayerstore.h"
|
||||
#include "qgsmaplayer.h"
|
||||
#include "qgslogger.h"
|
||||
#include <QList>
|
||||
|
||||
QgsMapLayerStore::QgsMapLayerStore( QObject *parent )
|
||||
: QObject( parent )
|
||||
@ -32,6 +34,18 @@ int QgsMapLayerStore::count() const
|
||||
return mMapLayers.size();
|
||||
}
|
||||
|
||||
int QgsMapLayerStore::validCount() const
|
||||
{
|
||||
int i = 0;
|
||||
const QList<QgsMapLayer *> cLayers = mMapLayers.values();
|
||||
for ( const auto l : cLayers )
|
||||
{
|
||||
if ( l->isValid() )
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
QgsMapLayer *QgsMapLayerStore::mapLayer( const QString &layerId ) const
|
||||
{
|
||||
return mMapLayers.value( layerId );
|
||||
@ -55,9 +69,9 @@ QList<QgsMapLayer *> QgsMapLayerStore::addMapLayers( const QList<QgsMapLayer *>
|
||||
QList<QgsMapLayer *> myResultList;
|
||||
Q_FOREACH ( QgsMapLayer *myLayer, layers )
|
||||
{
|
||||
if ( !myLayer || !myLayer->isValid() )
|
||||
if ( !myLayer )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "Cannot add invalid layers" ) );
|
||||
QgsDebugMsg( QStringLiteral( "Cannot add null layers" ) );
|
||||
continue;
|
||||
}
|
||||
//check the layer is not already registered!
|
||||
@ -212,3 +226,14 @@ QMap<QString, QgsMapLayer *> QgsMapLayerStore::mapLayers() const
|
||||
{
|
||||
return mMapLayers;
|
||||
}
|
||||
|
||||
QMap<QString, QgsMapLayer *> QgsMapLayerStore::validMapLayers() const
|
||||
{
|
||||
QMap<QString, QgsMapLayer *> validLayers;
|
||||
for ( const auto &id : mMapLayers.keys() )
|
||||
{
|
||||
if ( mMapLayers[id]->isValid() )
|
||||
validLayers[id] = mMapLayers[id];
|
||||
}
|
||||
return validLayers;
|
||||
}
|
||||
|
@ -50,6 +50,12 @@ class CORE_EXPORT QgsMapLayerStore : public QObject
|
||||
*/
|
||||
int count() const;
|
||||
|
||||
/**
|
||||
* Returns the number of valid layers contained in the store.
|
||||
* \since QGIS 3.6
|
||||
*/
|
||||
int validCount() const;
|
||||
|
||||
#ifdef SIP_RUN
|
||||
|
||||
/**
|
||||
@ -93,6 +99,15 @@ class CORE_EXPORT QgsMapLayerStore : public QObject
|
||||
*/
|
||||
QMap<QString, QgsMapLayer *> mapLayers() const;
|
||||
|
||||
/**
|
||||
* Returns a map of all valid layers by layer ID.
|
||||
* \see mapLayer()
|
||||
* \see mapLayersByName()
|
||||
* \see layers()
|
||||
* \since QGIS 3.6
|
||||
*/
|
||||
QMap<QString, QgsMapLayer *> validMapLayers() const;
|
||||
|
||||
#ifndef SIP_RUN
|
||||
|
||||
/**
|
||||
@ -135,7 +150,7 @@ class CORE_EXPORT QgsMapLayerStore : public QObject
|
||||
* the layers yourself. Not available in Python.
|
||||
*
|
||||
* \returns a list of the map layers that were added
|
||||
* successfully. If a layer is invalid, or already exists in the store,
|
||||
* successfully. If a layer already exists in the store,
|
||||
* it will not be part of the returned list.
|
||||
*
|
||||
* \see addMapLayer()
|
||||
|
@ -368,6 +368,20 @@ QgsProject::QgsProject( QObject *parent )
|
||||
connect( mLayerStore.get(), &QgsMapLayerStore::layerWasAdded, this, &QgsProject::layerWasAdded );
|
||||
if ( QgsApplication::instance() )
|
||||
connect( QgsApplication::instance(), &QgsApplication::requestForTranslatableObjects, this, &QgsProject::registerTranslatableObjects );
|
||||
connect( mLayerStore.get(), static_cast<void ( QgsMapLayerStore::* )( const QList<QgsMapLayer *> & )>( &QgsMapLayerStore::layersWillBeRemoved ),
|
||||
[ = ]( const QList<QgsMapLayer *> &layers )
|
||||
{
|
||||
for ( const auto &layer : layers )
|
||||
disconnect( layer, &QgsMapLayer::dataSourceChanged, mRelationManager, &QgsRelationManager::updateRelationsStatus );
|
||||
}
|
||||
);
|
||||
connect( mLayerStore.get(), static_cast<void ( QgsMapLayerStore::* )( const QList<QgsMapLayer *> & )>( &QgsMapLayerStore::layersAdded ),
|
||||
[ = ]( const QList<QgsMapLayer *> &layers )
|
||||
{
|
||||
for ( const auto &layer : layers )
|
||||
connect( layer, &QgsMapLayer::dataSourceChanged, mRelationManager, &QgsRelationManager::updateRelationsStatus );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -926,31 +940,29 @@ bool QgsProject::addLayer( const QDomElement &layerElem, QList<QDomNode> &broken
|
||||
if ( !mapLayer )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "Unable to create layer" ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Q_CHECK_PTR( mapLayer ); // NOLINT
|
||||
|
||||
// have the layer restore state that is stored in Dom node
|
||||
if ( mapLayer->readLayerXml( layerElem, context ) && mapLayer->isValid() )
|
||||
bool layerIsValid = mapLayer->readLayerXml( layerElem, context ) && mapLayer->isValid();
|
||||
QList<QgsMapLayer *> newLayers;
|
||||
newLayers << mapLayer;
|
||||
if ( layerIsValid )
|
||||
{
|
||||
emit readMapLayer( mapLayer, layerElem );
|
||||
|
||||
QList<QgsMapLayer *> myLayers;
|
||||
myLayers << mapLayer;
|
||||
addMapLayers( myLayers );
|
||||
|
||||
return true;
|
||||
addMapLayers( newLayers );
|
||||
}
|
||||
else
|
||||
{
|
||||
delete mapLayer;
|
||||
|
||||
// It's a bad layer: do not add to legend (the user will decide if she wants to do so)
|
||||
addMapLayers( newLayers, false );
|
||||
newLayers.first();
|
||||
QgsDebugMsg( "Unable to load " + type + " layer" );
|
||||
brokenNodes.push_back( layerElem );
|
||||
return false;
|
||||
}
|
||||
return layerIsValid;
|
||||
}
|
||||
|
||||
bool QgsProject::read( const QString &filename )
|
||||
@ -1293,8 +1305,10 @@ bool QgsProject::readProjectFile( const QString &filename )
|
||||
}
|
||||
}
|
||||
|
||||
// make sure the are just valid layers
|
||||
QgsLayerTreeUtils::removeInvalidLayers( mRootGroup );
|
||||
// After bad layer handling we might still have invalid layers,
|
||||
// store them in case the user wanted to handle them later
|
||||
// or wanted to pass them through when saving
|
||||
QgsLayerTreeUtils::storeOriginalLayersProperties( mRootGroup, doc.get() );
|
||||
|
||||
mRootGroup->removeCustomProperty( QStringLiteral( "loading" ) );
|
||||
|
||||
@ -1500,43 +1514,46 @@ void QgsProject::onMapLayersAdded( const QList<QgsMapLayer *> &layers )
|
||||
|
||||
Q_FOREACH ( QgsMapLayer *layer, layers )
|
||||
{
|
||||
QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
|
||||
if ( vlayer )
|
||||
if ( layer->isValid() )
|
||||
{
|
||||
if ( autoTransaction() )
|
||||
QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
|
||||
if ( vlayer )
|
||||
{
|
||||
if ( QgsTransaction::supportsTransaction( vlayer ) )
|
||||
if ( autoTransaction() )
|
||||
{
|
||||
QString connString = QgsDataSourceUri( vlayer->source() ).connectionInfo();
|
||||
QString key = vlayer->providerType();
|
||||
|
||||
QgsTransactionGroup *tg = mTransactionGroups.value( qMakePair( key, connString ) );
|
||||
|
||||
if ( !tg )
|
||||
if ( QgsTransaction::supportsTransaction( vlayer ) )
|
||||
{
|
||||
tg = new QgsTransactionGroup();
|
||||
mTransactionGroups.insert( qMakePair( key, connString ), tg );
|
||||
tgChanged = true;
|
||||
QString connString = QgsDataSourceUri( vlayer->source() ).connectionInfo();
|
||||
QString key = vlayer->providerType();
|
||||
|
||||
QgsTransactionGroup *tg = mTransactionGroups.value( qMakePair( key, connString ) );
|
||||
|
||||
if ( !tg )
|
||||
{
|
||||
tg = new QgsTransactionGroup();
|
||||
mTransactionGroups.insert( qMakePair( key, connString ), tg );
|
||||
tgChanged = true;
|
||||
}
|
||||
tg->addLayer( vlayer );
|
||||
}
|
||||
tg->addLayer( vlayer );
|
||||
}
|
||||
vlayer->dataProvider()->setProviderProperty( QgsVectorDataProvider::EvaluateDefaultValues, evaluateDefaultValues() );
|
||||
}
|
||||
vlayer->dataProvider()->setProviderProperty( QgsVectorDataProvider::EvaluateDefaultValues, evaluateDefaultValues() );
|
||||
}
|
||||
|
||||
if ( tgChanged )
|
||||
emit transactionGroupsChanged();
|
||||
if ( tgChanged )
|
||||
emit transactionGroupsChanged();
|
||||
|
||||
connect( layer, &QgsMapLayer::configChanged, this, [ = ] { setDirty(); } );
|
||||
connect( layer, &QgsMapLayer::configChanged, this, [ = ] { setDirty(); } );
|
||||
|
||||
// check if we have to update connections for layers with dependencies
|
||||
for ( QMap<QString, QgsMapLayer *>::iterator it = existingMaps.begin(); it != existingMaps.end(); it++ )
|
||||
{
|
||||
QSet<QgsMapLayerDependency> deps = it.value()->dependencies();
|
||||
if ( deps.contains( layer->id() ) )
|
||||
// check if we have to update connections for layers with dependencies
|
||||
for ( QMap<QString, QgsMapLayer *>::iterator it = existingMaps.begin(); it != existingMaps.end(); it++ )
|
||||
{
|
||||
// reconnect to change signals
|
||||
it.value()->setDependencies( deps );
|
||||
QSet<QgsMapLayerDependency> deps = it.value()->dependencies();
|
||||
if ( deps.contains( layer->id() ) )
|
||||
{
|
||||
// reconnect to change signals
|
||||
it.value()->setDependencies( deps );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1751,10 +1768,26 @@ bool QgsProject::writeProjectFile( const QString &filename )
|
||||
QHash< QString, QPair< QString, bool> >::const_iterator emIt = mEmbeddedLayers.constFind( ml->id() );
|
||||
if ( emIt == mEmbeddedLayers.constEnd() )
|
||||
{
|
||||
// general layer metadata
|
||||
QDomElement maplayerElem = doc->createElement( QStringLiteral( "maplayer" ) );
|
||||
|
||||
ml->writeLayerXml( maplayerElem, *doc, context );
|
||||
QDomElement maplayerElem;
|
||||
// If layer is not valid, let's try to restore saved properties from invalidLayerProperties
|
||||
if ( ml->isValid() )
|
||||
{
|
||||
// general layer metadata
|
||||
maplayerElem = doc->createElement( QStringLiteral( "maplayer" ) );
|
||||
ml->writeLayerXml( maplayerElem, *doc, context );
|
||||
}
|
||||
else if ( ! ml->originalXmlProperties().isEmpty() )
|
||||
{
|
||||
QDomDocument document;
|
||||
if ( document.setContent( ml->originalXmlProperties() ) )
|
||||
{
|
||||
maplayerElem = document.firstChildElement();
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "Could not restore layer properties for layer %1" ).arg( ml->id() ) );
|
||||
}
|
||||
}
|
||||
|
||||
emit writeMapLayer( ml, maplayerElem, *doc );
|
||||
|
||||
@ -2534,6 +2567,11 @@ int QgsProject::count() const
|
||||
return mLayerStore->count();
|
||||
}
|
||||
|
||||
int QgsProject::validCount() const
|
||||
{
|
||||
return mLayerStore->validCount();
|
||||
}
|
||||
|
||||
QgsMapLayer *QgsProject::mapLayer( const QString &layerId ) const
|
||||
{
|
||||
return mLayerStore->mapLayer( layerId );
|
||||
@ -2723,9 +2761,9 @@ void QgsProject::reloadAllLayers()
|
||||
}
|
||||
}
|
||||
|
||||
QMap<QString, QgsMapLayer *> QgsProject::mapLayers() const
|
||||
QMap<QString, QgsMapLayer *> QgsProject::mapLayers( const bool validOnly ) const
|
||||
{
|
||||
return mLayerStore->mapLayers();
|
||||
return validOnly ? mLayerStore->validMapLayers() : mLayerStore->mapLayers();
|
||||
}
|
||||
|
||||
QgsTransactionGroup *QgsProject::transactionGroup( const QString &providerKey, const QString &connString )
|
||||
|
@ -690,6 +690,9 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
|
||||
//! Returns the number of registered layers.
|
||||
int count() const;
|
||||
|
||||
//! Returns the number of registered valid layers.
|
||||
int validCount() const;
|
||||
|
||||
/**
|
||||
* Retrieve a pointer to a registered layer by layer ID.
|
||||
* \param layerId ID of layer to retrieve
|
||||
@ -710,11 +713,13 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
|
||||
|
||||
/**
|
||||
* Returns a map of all registered layers by layer ID.
|
||||
*
|
||||
* \param validOnly if set only valid layers will be returned
|
||||
* \see mapLayer()
|
||||
* \see mapLayersByName()
|
||||
* \see layers()
|
||||
*/
|
||||
QMap<QString, QgsMapLayer *> mapLayers() const;
|
||||
QMap<QString, QgsMapLayer *> mapLayers( const bool validOnly = false ) const;
|
||||
|
||||
/**
|
||||
* Returns true if the project comes from a zip archive, false otherwise.
|
||||
@ -757,7 +762,7 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
|
||||
* the layers yourself. Not available in Python.
|
||||
*
|
||||
* \returns a list of the map layers that were added
|
||||
* successfully. If a layer is invalid, or already exists in the registry,
|
||||
* successfully. If a layer or already exists in the registry,
|
||||
* it will not be part of the returned QList.
|
||||
*
|
||||
* \note As a side-effect QgsProject is made dirty.
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
void QgsProjectBadLayerHandler::handleBadLayers( const QList<QDomNode> &layers )
|
||||
{
|
||||
QgsApplication::messageLog()->logMessage( QObject::tr( "%1 bad layers dismissed:" ).arg( layers.size() ) );
|
||||
QgsApplication::messageLog()->logMessage( QObject::tr( "%1 bad layers found:" ).arg( layers.size() ) );
|
||||
Q_FOREACH ( const QDomNode &layer, layers )
|
||||
{
|
||||
QgsApplication::messageLog()->logMessage( QObject::tr( " * %1" ).arg( dataSource( layer ) ) );
|
||||
|
@ -325,7 +325,7 @@ QgsAttributeList QgsRelation::referencingFields() const
|
||||
|
||||
bool QgsRelation::isValid() const
|
||||
{
|
||||
return d->mValid && !d->mReferencingLayer.isNull() && !d->mReferencedLayer.isNull();
|
||||
return d->mValid && !d->mReferencingLayer.isNull() && !d->mReferencedLayer.isNull() && d->mReferencingLayer.data()->isValid() && d->mReferencedLayer.data()->isValid();
|
||||
}
|
||||
|
||||
bool QgsRelation::hasEqualDefinition( const QgsRelation &other ) const
|
||||
|
@ -338,6 +338,7 @@ class CORE_EXPORT QgsRelation
|
||||
|
||||
/**
|
||||
* Returns the validity of this relation. Don't use the information if it's not valid.
|
||||
* A relation is considered valid if both referenced and referencig layers are valid.
|
||||
*
|
||||
* \returns true if the relation is valid
|
||||
*/
|
||||
@ -366,14 +367,16 @@ class CORE_EXPORT QgsRelation
|
||||
*/
|
||||
Q_INVOKABLE QString resolveReferencingField( const QString &referencedField ) const;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Updates the validity status of this relation.
|
||||
* Will be called internally whenever a member is changed.
|
||||
*
|
||||
* \since QGIS 3.6
|
||||
*/
|
||||
void updateRelationStatus();
|
||||
|
||||
private:
|
||||
|
||||
mutable QExplicitlySharedDataPointer<QgsRelationPrivate> d;
|
||||
};
|
||||
|
||||
|
@ -50,7 +50,8 @@ QMap<QString, QgsRelation> QgsRelationManager::relations() const
|
||||
|
||||
void QgsRelationManager::addRelation( const QgsRelation &relation )
|
||||
{
|
||||
if ( !relation.isValid() )
|
||||
// Do not add relations to layers that do not exist
|
||||
if ( !( relation.referencingLayer() && relation.referencedLayer() ) )
|
||||
return;
|
||||
|
||||
mRelations.insert( relation.id(), relation );
|
||||
@ -60,6 +61,16 @@ void QgsRelationManager::addRelation( const QgsRelation &relation )
|
||||
emit changed();
|
||||
}
|
||||
|
||||
|
||||
void QgsRelationManager::updateRelationsStatus()
|
||||
{
|
||||
for ( auto relation : mRelations )
|
||||
{
|
||||
relation.updateRelationStatus();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void QgsRelationManager::removeRelation( const QString &id )
|
||||
{
|
||||
mRelations.remove( id );
|
||||
|
@ -59,6 +59,8 @@ class CORE_EXPORT QgsRelationManager : public QObject
|
||||
|
||||
/**
|
||||
* Add a relation.
|
||||
* Invalid relations are added only if both referencing layer and referenced
|
||||
* layer exist.
|
||||
*
|
||||
* \param relation The relation to add.
|
||||
*/
|
||||
@ -141,6 +143,13 @@ class CORE_EXPORT QgsRelationManager : public QObject
|
||||
*/
|
||||
void changed();
|
||||
|
||||
public slots:
|
||||
|
||||
/**
|
||||
* Updates relations status
|
||||
*/
|
||||
void updateRelationsStatus();
|
||||
|
||||
private slots:
|
||||
void readProject( const QDomDocument &doc, QgsReadWriteContext &context );
|
||||
void writeProject( QDomDocument &doc );
|
||||
|
@ -143,11 +143,13 @@ QgsVectorLayer::QgsVectorLayer( const QString &vectorLayerPath,
|
||||
const QString &providerKey,
|
||||
const LayerOptions &options )
|
||||
: QgsMapLayer( VectorLayer, baseName, vectorLayerPath )
|
||||
, mProviderKey( providerKey )
|
||||
, mAuxiliaryLayer( nullptr )
|
||||
, mAuxiliaryLayerKey( QString() )
|
||||
, mReadExtentFromXml( options.readExtentFromXml )
|
||||
{
|
||||
|
||||
setProviderType( providerKey );
|
||||
|
||||
mGeometryOptions = qgis::make_unique<QgsGeometryOptions>();
|
||||
mActions = new QgsActionManager( this );
|
||||
mConditionalStyles = new QgsConditionalLayerStyles();
|
||||
@ -313,12 +315,6 @@ QString QgsVectorLayer::dataComment() const
|
||||
return QString();
|
||||
}
|
||||
|
||||
|
||||
QString QgsVectorLayer::providerType() const
|
||||
{
|
||||
return mProviderKey;
|
||||
}
|
||||
|
||||
QgsCoordinateReferenceSystem QgsVectorLayer::sourceCrs() const
|
||||
{
|
||||
return crs();
|
||||
@ -599,16 +595,7 @@ QgsWkbTypes::GeometryType QgsVectorLayer::geometryType() const
|
||||
{
|
||||
QgsDebugMsgLevel( QStringLiteral( "invalid layer or pointer to mDataProvider is null" ), 3 );
|
||||
}
|
||||
|
||||
// We shouldn't get here, and if we have, other things are likely to
|
||||
// go wrong. Code that uses the type() return value should be
|
||||
// rewritten to cope with a value of Qgis::Unknown. To make this
|
||||
// need known, the following message is printed every time we get
|
||||
// here.
|
||||
// AP: it looks like we almost always get here, since 2.x ... either we remove this
|
||||
// warning of take care of the problems that may occur
|
||||
QgsDebugMsg( QStringLiteral( "WARNING: This code should never be reached. Problems may occur..." ) );
|
||||
|
||||
QgsDebugMsgLevel( QStringLiteral( "Vector layer with unknown geometry type." ), 3 );
|
||||
return QgsWkbTypes::UnknownGeometry;
|
||||
}
|
||||
|
||||
@ -1425,14 +1412,14 @@ bool QgsVectorLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &c
|
||||
QgsDataProvider::ProviderOptions options;
|
||||
if ( !setDataProvider( mProviderKey, options ) )
|
||||
{
|
||||
return false;
|
||||
QgsDebugMsg( QStringLiteral( "Could not set data provider for layer %1" ).arg( publicSource() ) );
|
||||
}
|
||||
|
||||
QDomElement pkeyElem = pkeyNode.toElement();
|
||||
if ( !pkeyElem.isNull() )
|
||||
{
|
||||
QString encodingString = pkeyElem.attribute( QStringLiteral( "encoding" ) );
|
||||
if ( !encodingString.isEmpty() )
|
||||
if ( mDataProvider && !encodingString.isEmpty() )
|
||||
{
|
||||
mDataProvider->setEncoding( encodingString );
|
||||
}
|
||||
@ -1591,6 +1578,7 @@ bool QgsVectorLayer::setDataProvider( QString const &provider, const QgsDataProv
|
||||
mDataProvider = qobject_cast<QgsVectorDataProvider *>( QgsProviderRegistry::instance()->createProvider( provider, dataSource, options ) );
|
||||
if ( !mDataProvider )
|
||||
{
|
||||
mValid = false;
|
||||
QgsDebugMsgLevel( QStringLiteral( "Unable to get data provider" ), 2 );
|
||||
return false;
|
||||
}
|
||||
@ -1604,7 +1592,6 @@ bool QgsVectorLayer::setDataProvider( QString const &provider, const QgsDataProv
|
||||
if ( !mValid )
|
||||
{
|
||||
QgsDebugMsgLevel( QStringLiteral( "Invalid provider plugin %1" ).arg( QString( mDataSource.toUtf8() ) ), 2 );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( mDataProvider->capabilities() & QgsVectorDataProvider::ReadLayerMetadata )
|
||||
|
@ -763,9 +763,6 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
|
||||
//! Returns the WKBType or WKBUnknown in case of error
|
||||
QgsWkbTypes::Type wkbType() const FINAL;
|
||||
|
||||
//! Returns the provider type for this layer
|
||||
QString providerType() const;
|
||||
|
||||
QgsCoordinateReferenceSystem sourceCrs() const FINAL;
|
||||
QString sourceName() const FINAL;
|
||||
|
||||
@ -987,7 +984,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
|
||||
* \see dataSourceChanged()
|
||||
* \since QGIS 3.2
|
||||
*/
|
||||
void setDataSource( const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, bool loadDefaultStyleFlag = false );
|
||||
void setDataSource( const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, bool loadDefaultStyleFlag = false ) override;
|
||||
|
||||
QString loadDefaultStyle( bool &resultFlag SIP_OUT ) FINAL;
|
||||
|
||||
@ -2135,15 +2132,6 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
|
||||
|
||||
signals:
|
||||
|
||||
/**
|
||||
* Emitted whenever the layer's data source has been changed.
|
||||
*
|
||||
* \see setDataSource()
|
||||
*
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
void dataSourceChanged();
|
||||
|
||||
/**
|
||||
* This signal is emitted when selection was changed
|
||||
*
|
||||
@ -2444,9 +2432,6 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
|
||||
|
||||
QString mMapTipTemplate;
|
||||
|
||||
//! Data provider key
|
||||
QString mProviderKey;
|
||||
|
||||
//! The user-defined actions that are accessed from the Identify Results dialog box
|
||||
QgsActionManager *mActions = nullptr;
|
||||
|
||||
|
@ -116,29 +116,14 @@ QgsRasterLayer::QgsRasterLayer( const QString &uri,
|
||||
// Constant that signals property not used.
|
||||
, QSTRING_NOT_SET( QStringLiteral( "Not Set" ) )
|
||||
, TRSTRING_NOT_SET( tr( "Not Set" ) )
|
||||
, mProviderKey( providerKey )
|
||||
{
|
||||
QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
|
||||
init();
|
||||
setProviderType( providerKey );
|
||||
|
||||
QgsDataProvider::ProviderOptions providerOptions;
|
||||
setDataProvider( providerKey, providerOptions );
|
||||
if ( !mValid ) return;
|
||||
|
||||
// load default style
|
||||
bool defaultLoadedFlag = false;
|
||||
if ( mValid && options.loadDefaultStyle )
|
||||
{
|
||||
loadDefaultStyle( defaultLoadedFlag );
|
||||
}
|
||||
if ( !defaultLoadedFlag )
|
||||
{
|
||||
setDefaultContrastEnhancement();
|
||||
}
|
||||
setDataSource( uri, baseName, providerKey, providerOptions, options.loadDefaultStyle );
|
||||
|
||||
// TODO: Connect signals from the dataprovider to the qgisapp
|
||||
|
||||
emit statusChanged( tr( "QgsRasterLayer created" ) );
|
||||
} // QgsRasterLayer ctor
|
||||
|
||||
QgsRasterLayer::~QgsRasterLayer()
|
||||
@ -797,7 +782,81 @@ void QgsRasterLayer::setDataProvider( QString const &provider, const QgsDataProv
|
||||
mValid = true;
|
||||
|
||||
QgsDebugMsgLevel( QStringLiteral( "exiting." ), 4 );
|
||||
} // QgsRasterLayer::setDataProvider
|
||||
}
|
||||
|
||||
void QgsRasterLayer::setDataSource( const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, bool loadDefaultStyleFlag )
|
||||
{
|
||||
|
||||
bool wasValid( isValid() );
|
||||
|
||||
QDomImplementation domImplementation;
|
||||
QDomDocumentType documentType;
|
||||
QDomDocument doc;
|
||||
QString errorMsg;
|
||||
QDomElement rootNode;
|
||||
|
||||
// Store the original style
|
||||
if ( wasValid && ! loadDefaultStyleFlag )
|
||||
{
|
||||
documentType = domImplementation.createDocumentType(
|
||||
QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
|
||||
doc = QDomDocument( documentType );
|
||||
rootNode = doc.createElement( QStringLiteral( "qgis" ) );
|
||||
rootNode.setAttribute( QStringLiteral( "version" ), Qgis::QGIS_VERSION );
|
||||
doc.appendChild( rootNode );
|
||||
QgsReadWriteContext writeContext;
|
||||
if ( ! writeSymbology( rootNode, doc, errorMsg, writeContext ) )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "Could not store symbology for layer %1: %2" )
|
||||
.arg( name() )
|
||||
.arg( errorMsg ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( mDataProvider )
|
||||
closeDataProvider();
|
||||
|
||||
init();
|
||||
|
||||
for ( int i = mPipe.size() - 1; i >= 0; --i )
|
||||
{
|
||||
mPipe.remove( i );
|
||||
}
|
||||
|
||||
mDataSource = dataSource;
|
||||
mLayerName = baseName;
|
||||
|
||||
setDataProvider( provider, options );
|
||||
|
||||
if ( mValid )
|
||||
{
|
||||
// load default style
|
||||
bool defaultLoadedFlag = false;
|
||||
if ( loadDefaultStyleFlag )
|
||||
{
|
||||
loadDefaultStyle( defaultLoadedFlag );
|
||||
}
|
||||
else if ( wasValid && errorMsg.isEmpty() ) // Restore the style
|
||||
{
|
||||
QgsReadWriteContext readContext;
|
||||
if ( ! readSymbology( rootNode, errorMsg, readContext ) )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "Could not restore symbology for layer %1: %2" )
|
||||
.arg( name() )
|
||||
.arg( errorMsg ) );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if ( !defaultLoadedFlag )
|
||||
{
|
||||
setDefaultContrastEnhancement();
|
||||
}
|
||||
emit statusChanged( tr( "QgsRasterLayer created" ) );
|
||||
}
|
||||
emit dataSourceChanged();
|
||||
emit dataChanged();
|
||||
}
|
||||
|
||||
void QgsRasterLayer::closeDataProvider()
|
||||
{
|
||||
@ -1251,9 +1310,13 @@ QImage QgsRasterLayer::previewAsImage( QSize size, const QColor &bgColor, QImage
|
||||
{
|
||||
QImage myQImage( size, format );
|
||||
|
||||
if ( ! isValid( ) )
|
||||
return QImage();
|
||||
|
||||
myQImage.setColor( 0, bgColor.rgba() );
|
||||
myQImage.fill( 0 ); //defaults to white, set to transparent for rendering on a map
|
||||
|
||||
|
||||
QgsRasterViewPort *myRasterViewPort = new QgsRasterViewPort();
|
||||
|
||||
double myMapUnitsPerPixel;
|
||||
@ -1474,7 +1537,12 @@ bool QgsRasterLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &c
|
||||
|
||||
QgsDataProvider::ProviderOptions providerOptions;
|
||||
setDataProvider( mProviderKey, providerOptions );
|
||||
if ( !mValid ) return false;
|
||||
|
||||
if ( ! mDataProvider )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "Raster data provider could not be created for %1" ).arg( mDataSource ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
QString error;
|
||||
bool res = readSymbology( layer_node, error, context );
|
||||
|
@ -199,7 +199,7 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
|
||||
* */
|
||||
explicit QgsRasterLayer( const QString &uri,
|
||||
const QString &baseName = QString(),
|
||||
const QString &providerKey = "gdal",
|
||||
const QString &providerType = "gdal",
|
||||
const QgsRasterLayer::LayerOptions &options = QgsRasterLayer::LayerOptions() );
|
||||
|
||||
~QgsRasterLayer() override;
|
||||
@ -259,6 +259,20 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
|
||||
*/
|
||||
void setDataProvider( const QString &provider, const QgsDataProvider::ProviderOptions &options );
|
||||
|
||||
/**
|
||||
* Updates the data source of the layer. The layer's renderer and legend will be preserved only
|
||||
* if the geometry type of the new data source matches the current geometry type of the layer.
|
||||
* \param dataSource new layer data source
|
||||
* \param baseName base name of the layer
|
||||
* \param provider provider string
|
||||
* \param options provider options
|
||||
* \param loadDefaultStyleFlag set to true to reset the layer's style to the default for the
|
||||
* data source
|
||||
* \see dataSourceChanged()
|
||||
* \since QGIS 3.6
|
||||
*/
|
||||
void setDataSource( const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, bool loadDefaultStyleFlag = false ) override;
|
||||
|
||||
/**
|
||||
* Returns the raster layer type (which is a read only property).
|
||||
*/
|
||||
@ -453,9 +467,6 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
|
||||
|
||||
QgsRasterViewPort mLastViewPort;
|
||||
|
||||
//! [ data provider interface ] Data provider key
|
||||
QString mProviderKey;
|
||||
|
||||
LayerType mRasterType;
|
||||
|
||||
QgsRasterPipe mPipe;
|
||||
|
@ -22,17 +22,30 @@
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
QgsDataSourceSelectDialog::QgsDataSourceSelectDialog( bool setFilterByLayerType,
|
||||
const QgsMapLayer::LayerType &layerType,
|
||||
QWidget *parent )
|
||||
QgsDataSourceSelectDialog::QgsDataSourceSelectDialog(
|
||||
QgsBrowserModel *browserModel,
|
||||
bool setFilterByLayerType,
|
||||
const QgsMapLayer::LayerType &layerType,
|
||||
QWidget *parent )
|
||||
: QDialog( parent )
|
||||
{
|
||||
if ( ! browserModel )
|
||||
{
|
||||
mBrowserModel = qgis::make_unique<QgsBrowserModel>();
|
||||
mOwnModel = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
mBrowserModel.reset( browserModel );
|
||||
mOwnModel = false;
|
||||
}
|
||||
|
||||
setupUi( this );
|
||||
setWindowTitle( tr( "Select a Data Source" ) );
|
||||
QgsGui::enableAutoGeometryRestore( this );
|
||||
|
||||
mBrowserModel.initialize();
|
||||
mBrowserProxyModel.setBrowserModel( &mBrowserModel );
|
||||
mBrowserModel->initialize();
|
||||
mBrowserProxyModel.setBrowserModel( mBrowserModel.get() );
|
||||
mBrowserTreeView->setHeaderHidden( true );
|
||||
|
||||
if ( setFilterByLayerType )
|
||||
@ -47,6 +60,12 @@ QgsDataSourceSelectDialog::QgsDataSourceSelectDialog( bool setFilterByLayerType,
|
||||
connect( mBrowserTreeView, &QgsBrowserTreeView::clicked, this, &QgsDataSourceSelectDialog::onLayerSelected );
|
||||
}
|
||||
|
||||
QgsDataSourceSelectDialog::~QgsDataSourceSelectDialog()
|
||||
{
|
||||
if ( ! mOwnModel )
|
||||
mBrowserModel.release();
|
||||
}
|
||||
|
||||
void QgsDataSourceSelectDialog::setLayerTypeFilter( QgsMapLayer::LayerType layerType )
|
||||
{
|
||||
mBrowserProxyModel.setFilterByLayerType( true );
|
||||
|
@ -50,14 +50,19 @@ class GUI_EXPORT QgsDataSourceSelectDialog: public QDialog, private Ui::QgsDataS
|
||||
/**
|
||||
* Constructs a QgsDataSourceSelectDialog, optionally filtering by layer type
|
||||
*
|
||||
* \param browserModel an existing browser model (typically from app), if null an instance will be created
|
||||
* \param setFilterByLayerType activates filtering by layer type
|
||||
* \param layerType sets the layer type filter, this is in effect only if filtering by layer type is also active
|
||||
* \param parent the object
|
||||
*/
|
||||
QgsDataSourceSelectDialog( bool setFilterByLayerType = false,
|
||||
QgsDataSourceSelectDialog( QgsBrowserModel *browserModel = nullptr,
|
||||
bool setFilterByLayerType = false,
|
||||
const QgsMapLayer::LayerType &layerType = QgsMapLayer::LayerType::VectorLayer,
|
||||
QWidget *parent = nullptr );
|
||||
|
||||
|
||||
~QgsDataSourceSelectDialog() override;
|
||||
|
||||
/**
|
||||
* Sets layer type filter to \a layerType and activates the filtering
|
||||
*/
|
||||
@ -75,8 +80,9 @@ class GUI_EXPORT QgsDataSourceSelectDialog: public QDialog, private Ui::QgsDataS
|
||||
|
||||
private:
|
||||
|
||||
QgsBrowserModel mBrowserModel;
|
||||
QgsBrowserProxyModel mBrowserProxyModel;
|
||||
std::unique_ptr<QgsBrowserModel> mBrowserModel;
|
||||
bool mOwnModel = true;
|
||||
QgsMimeDataUtils::Uri mUri;
|
||||
|
||||
};
|
||||
|
@ -70,6 +70,8 @@ QgsRasterTransparencyWidget::QgsRasterTransparencyWidget( QgsRasterLayer *layer,
|
||||
|
||||
void QgsRasterTransparencyWidget::syncToLayer()
|
||||
{
|
||||
if ( ! mRasterLayer->isValid() )
|
||||
return;
|
||||
QgsRasterDataProvider *provider = mRasterLayer->dataProvider();
|
||||
QgsRasterRenderer *renderer = mRasterLayer->renderer();
|
||||
if ( provider )
|
||||
|
@ -57,7 +57,8 @@ QgsRendererRasterPropertiesWidget::QgsRendererRasterPropertiesWidget( QgsMapLaye
|
||||
|
||||
{
|
||||
mRasterLayer = qobject_cast<QgsRasterLayer *>( layer );
|
||||
if ( !mRasterLayer )
|
||||
|
||||
if ( !( mRasterLayer && mRasterLayer->isValid() ) )
|
||||
return;
|
||||
|
||||
setupUi( this );
|
||||
@ -126,6 +127,10 @@ void QgsRendererRasterPropertiesWidget::rendererChanged()
|
||||
|
||||
void QgsRendererRasterPropertiesWidget::apply()
|
||||
{
|
||||
|
||||
if ( ! mRasterLayer->isValid() )
|
||||
return;
|
||||
|
||||
mRasterLayer->brightnessFilter()->setBrightness( mSliderBrightness->value() );
|
||||
mRasterLayer->brightnessFilter()->setContrast( mSliderContrast->value() );
|
||||
|
||||
|
@ -892,7 +892,9 @@ QStringList QgsOgrProvider::_subLayers( bool withFeatureCount ) const
|
||||
void QgsOgrProvider::setEncoding( const QString &e )
|
||||
{
|
||||
QgsSettings settings;
|
||||
if ( ( mGDALDriverName == QLatin1String( "ESRI Shapefile" ) && settings.value( QStringLiteral( "qgis/ignoreShapeEncoding" ), true ).toBool() ) || !mOgrLayer->TestCapability( OLCStringsAsUTF8 ) )
|
||||
if ( ( mGDALDriverName == QLatin1String( "ESRI Shapefile" ) &&
|
||||
settings.value( QStringLiteral( "qgis/ignoreShapeEncoding" ), true ).toBool() ) ||
|
||||
( mOgrLayer && !mOgrLayer->TestCapability( OLCStringsAsUTF8 ) ) )
|
||||
{
|
||||
QgsVectorDataProvider::setEncoding( e );
|
||||
}
|
||||
@ -900,7 +902,6 @@ void QgsOgrProvider::setEncoding( const QString &e )
|
||||
{
|
||||
QgsVectorDataProvider::setEncoding( QStringLiteral( "UTF-8" ) );
|
||||
}
|
||||
|
||||
loadFields();
|
||||
}
|
||||
|
||||
|
@ -27,45 +27,12 @@
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
<set>QDialogButtonBox::Apply|QDialogButtonBox::Discard|QDialogButtonBox::Ignore</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>QgsHandleBadLayersBase</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>QgsHandleBadLayersBase</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
@ -55,6 +55,7 @@ ADD_PYTHON_TEST(PyQgsFieldComboBoxTest test_qgsfieldcombobox.py)
|
||||
ADD_PYTHON_TEST(PyQgsFieldFormattersTest test_qgsfieldformatters.py)
|
||||
ADD_PYTHON_TEST(PyQgsFillSymbolLayers test_qgsfillsymbollayers.py)
|
||||
ADD_PYTHON_TEST(PyQgsProject test_qgsproject.py)
|
||||
ADD_PYTHON_TEST(PyQgsProjectBadLayers test_qgsprojectbadlayers.py)
|
||||
ADD_PYTHON_TEST(PyQgsFeatureIterator test_qgsfeatureiterator.py)
|
||||
ADD_PYTHON_TEST(PyQgsFeedback test_qgsfeedback.py)
|
||||
ADD_PYTHON_TEST(PyQgsFields test_qgsfields.py)
|
||||
|
@ -66,9 +66,11 @@ class TestQgsMapLayerStore(unittest.TestCase):
|
||||
""" test that invalid map layers can't be added to store """
|
||||
store = QgsMapLayerStore()
|
||||
|
||||
self.assertEqual(store.addMapLayer(QgsVectorLayer("Point?field=x:string", 'test', "xxx")), None)
|
||||
self.assertEqual(len(store.mapLayersByName('test')), 0)
|
||||
self.assertEqual(store.count(), 0)
|
||||
vl = QgsVectorLayer("Point?field=x:string", 'test', "xxx")
|
||||
self.assertEqual(store.addMapLayer(vl), vl)
|
||||
self.assertEqual(len(store.mapLayersByName('test')), 1)
|
||||
self.assertEqual(store.count(), 1)
|
||||
self.assertEqual(store.validCount(), 0)
|
||||
|
||||
def test_addMapLayerSignals(self):
|
||||
""" test that signals are correctly emitted when adding map layer"""
|
||||
@ -120,12 +122,14 @@ class TestQgsMapLayerStore(unittest.TestCase):
|
||||
store.removeAllMapLayers()
|
||||
|
||||
def test_addMapLayersInvalid(self):
|
||||
""" test that invalid map layersd can't be added to store """
|
||||
""" test that invalid map layers can be added to store """
|
||||
store = QgsMapLayerStore()
|
||||
|
||||
self.assertEqual(store.addMapLayers([QgsVectorLayer("Point?field=x:string", 'test', "xxx")]), [])
|
||||
self.assertEqual(len(store.mapLayersByName('test')), 0)
|
||||
self.assertEqual(store.count(), 0)
|
||||
vl = QgsVectorLayer("Point?field=x:string", 'test', "xxx")
|
||||
self.assertEqual(store.addMapLayers([vl]), [vl])
|
||||
self.assertEqual(len(store.mapLayersByName('test')), 1)
|
||||
self.assertEqual(store.count(), 1)
|
||||
self.assertEqual(store.validCount(), 0)
|
||||
|
||||
def test_addMapLayersAlreadyAdded(self):
|
||||
""" test that already added layers can't be readded to store """
|
||||
|
@ -249,12 +249,17 @@ class TestQgsProject(unittest.TestCase):
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
def test_addMapLayerInvalid(self):
|
||||
""" test that invalid map layersd can't be added to registry """
|
||||
""" test that invalid map layers can be added to registry """
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
self.assertEqual(QgsProject.instance().addMapLayer(QgsVectorLayer("Point?field=x:string", 'test', "xxx")), None)
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 0)
|
||||
self.assertEqual(QgsProject.instance().count(), 0)
|
||||
vl = QgsVectorLayer("Point?field=x:string", 'test', "xxx")
|
||||
self.assertEqual(QgsProject.instance().addMapLayer(vl), vl)
|
||||
self.assertFalse(vl in QgsProject.instance().mapLayers(True).values())
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1)
|
||||
self.assertEqual(QgsProject.instance().count(), 1)
|
||||
self.assertEqual(QgsProject.instance().validCount(), 0)
|
||||
|
||||
self.assertEqual(len(QgsProject.instance().mapLayers(True)), 0)
|
||||
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
@ -313,12 +318,15 @@ class TestQgsProject(unittest.TestCase):
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
def test_addMapLayersInvalid(self):
|
||||
""" test that invalid map layersd can't be added to registry """
|
||||
""" test that invalid map layers can be added to registry """
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
self.assertEqual(QgsProject.instance().addMapLayers([QgsVectorLayer("Point?field=x:string", 'test', "xxx")]), [])
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 0)
|
||||
self.assertEqual(QgsProject.instance().count(), 0)
|
||||
vl = QgsVectorLayer("Point?field=x:string", 'test', "xxx")
|
||||
self.assertEqual(QgsProject.instance().addMapLayers([vl]), [vl])
|
||||
self.assertFalse(vl in QgsProject.instance().mapLayers(True).values())
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1)
|
||||
self.assertEqual(QgsProject.instance().count(), 1)
|
||||
self.assertEqual(QgsProject.instance().validCount(), 0)
|
||||
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
|
298
tests/src/python/test_qgsprojectbadlayers.py
Normal file
298
tests/src/python/test_qgsprojectbadlayers.py
Normal file
@ -0,0 +1,298 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""QGIS Unit tests for QgsProject bad layers handling.
|
||||
|
||||
.. note:: 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.
|
||||
"""
|
||||
from builtins import chr
|
||||
from builtins import range
|
||||
__author__ = 'Alessandro Pasotti'
|
||||
__date__ = '20/10/2018'
|
||||
__copyright__ = 'Copyright 2018, The QGIS Project'
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
import os
|
||||
import filecmp
|
||||
|
||||
import qgis # NOQA
|
||||
|
||||
from qgis.core import (QgsProject,
|
||||
QgsVectorLayer,
|
||||
QgsCoordinateTransform,
|
||||
QgsMapSettings,
|
||||
QgsRasterLayer,
|
||||
QgsMapLayer,
|
||||
QgsRectangle,
|
||||
QgsDataProvider,
|
||||
QgsCoordinateReferenceSystem,
|
||||
)
|
||||
from qgis.gui import (QgsLayerTreeMapCanvasBridge,
|
||||
QgsMapCanvas)
|
||||
|
||||
from qgis.PyQt.QtGui import QFont, QColor
|
||||
from qgis.PyQt.QtTest import QSignalSpy
|
||||
from qgis.PyQt.QtCore import QT_VERSION_STR, QTemporaryDir, QSize
|
||||
|
||||
from qgis.testing import start_app, unittest
|
||||
from utilities import (unitTestDataPath, renderMapToImage)
|
||||
from shutil import copyfile
|
||||
|
||||
app = start_app()
|
||||
TEST_DATA_DIR = unitTestDataPath()
|
||||
|
||||
|
||||
class TestQgsProjectBadLayers(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
p = QgsProject.instance()
|
||||
p.removeAllMapLayers()
|
||||
|
||||
@classmethod
|
||||
def getBaseMapSettings(cls):
|
||||
"""
|
||||
:rtype: QgsMapSettings
|
||||
"""
|
||||
ms = QgsMapSettings()
|
||||
crs = QgsCoordinateReferenceSystem()
|
||||
""":type: QgsCoordinateReferenceSystem"""
|
||||
crs.createFromSrid(4326)
|
||||
ms.setBackgroundColor(QColor(152, 219, 249))
|
||||
ms.setOutputSize(QSize(420, 280))
|
||||
ms.setOutputDpi(72)
|
||||
ms.setFlag(QgsMapSettings.Antialiasing, True)
|
||||
ms.setFlag(QgsMapSettings.UseAdvancedEffects, False)
|
||||
ms.setFlag(QgsMapSettings.ForceVectorOutput, False) # no caching?
|
||||
ms.setDestinationCrs(crs)
|
||||
return ms
|
||||
|
||||
def test_project_roundtrip(self):
|
||||
"""Tests that a project with bad layers can be saved and restored"""
|
||||
|
||||
p = QgsProject.instance()
|
||||
temp_dir = QTemporaryDir()
|
||||
for ext in ('shp', 'dbf', 'shx', 'prj'):
|
||||
copyfile(os.path.join(TEST_DATA_DIR, 'lines.%s' % ext), os.path.join(temp_dir.path(), 'lines.%s' % ext))
|
||||
copyfile(os.path.join(TEST_DATA_DIR, 'raster', 'band1_byte_ct_epsg4326.tif'), os.path.join(temp_dir.path(), 'band1_byte_ct_epsg4326.tif'))
|
||||
copyfile(os.path.join(TEST_DATA_DIR, 'raster', 'band1_byte_ct_epsg4326.tif'), os.path.join(temp_dir.path(), 'band1_byte_ct_epsg4326_copy.tif'))
|
||||
l = QgsVectorLayer(os.path.join(temp_dir.path(), 'lines.shp'), 'lines', 'ogr')
|
||||
self.assertTrue(l.isValid())
|
||||
|
||||
rl = QgsRasterLayer(os.path.join(temp_dir.path(), 'band1_byte_ct_epsg4326.tif'), 'raster', 'gdal')
|
||||
self.assertTrue(rl.isValid())
|
||||
rl_copy = QgsRasterLayer(os.path.join(temp_dir.path(), 'band1_byte_ct_epsg4326_copy.tif'), 'raster_copy', 'gdal')
|
||||
self.assertTrue(rl_copy.isValid())
|
||||
self.assertTrue(p.addMapLayers([l, rl, rl_copy]))
|
||||
|
||||
# Save project
|
||||
project_path = os.path.join(temp_dir.path(), 'project.qgs')
|
||||
self.assertTrue(p.write(project_path))
|
||||
|
||||
# Re-load the project, checking for the XML properties
|
||||
self.assertTrue(p.read(project_path))
|
||||
vector = list(p.mapLayersByName('lines'))[0]
|
||||
raster = list(p.mapLayersByName('raster'))[0]
|
||||
raster_copy = list(p.mapLayersByName('raster_copy'))[0]
|
||||
self.assertTrue(vector.originalXmlProperties() != '')
|
||||
self.assertTrue(raster.originalXmlProperties() != '')
|
||||
self.assertTrue(raster_copy.originalXmlProperties() != '')
|
||||
# Test setter
|
||||
raster.setOriginalXmlProperties('pippo')
|
||||
self.assertEqual(raster.originalXmlProperties(), 'pippo')
|
||||
|
||||
# Now create and invalid project:
|
||||
bad_project_path = os.path.join(temp_dir.path(), 'project_bad.qgs')
|
||||
with open(project_path, 'r') as infile:
|
||||
with open(bad_project_path, 'w+') as outfile:
|
||||
outfile.write(infile.read().replace('./lines.shp', './lines-BAD_SOURCE.shp').replace('band1_byte_ct_epsg4326_copy.tif', 'band1_byte_ct_epsg4326_copy-BAD_SOURCE.tif'))
|
||||
|
||||
# Load the bad project
|
||||
self.assertTrue(p.read(bad_project_path))
|
||||
# Check layer is invalid
|
||||
vector = list(p.mapLayersByName('lines'))[0]
|
||||
raster = list(p.mapLayersByName('raster'))[0]
|
||||
raster_copy = list(p.mapLayersByName('raster_copy'))[0]
|
||||
self.assertIsNotNone(vector.dataProvider())
|
||||
self.assertIsNotNone(raster.dataProvider())
|
||||
self.assertIsNotNone(raster_copy.dataProvider())
|
||||
self.assertFalse(vector.isValid())
|
||||
self.assertFalse(raster_copy.isValid())
|
||||
# Try a getFeatures
|
||||
self.assertEqual([f for f in vector.getFeatures()], [])
|
||||
self.assertTrue(raster.isValid())
|
||||
self.assertEqual(vector.providerType(), 'ogr')
|
||||
|
||||
# Save the project
|
||||
bad_project_path2 = os.path.join(temp_dir.path(), 'project_bad2.qgs')
|
||||
p.write(bad_project_path2)
|
||||
# Re-save the project, with fixed paths
|
||||
good_project_path = os.path.join(temp_dir.path(), 'project_good.qgs')
|
||||
with open(bad_project_path2, 'r') as infile:
|
||||
with open(good_project_path, 'w+') as outfile:
|
||||
outfile.write(infile.read().replace('./lines-BAD_SOURCE.shp', './lines.shp').replace('band1_byte_ct_epsg4326_copy-BAD_SOURCE.tif', 'band1_byte_ct_epsg4326_copy.tif'))
|
||||
|
||||
# Load the good project
|
||||
self.assertTrue(p.read(good_project_path))
|
||||
# Check layer is valid
|
||||
vector = list(p.mapLayersByName('lines'))[0]
|
||||
raster = list(p.mapLayersByName('raster'))[0]
|
||||
raster_copy = list(p.mapLayersByName('raster_copy'))[0]
|
||||
self.assertTrue(vector.isValid())
|
||||
self.assertTrue(raster.isValid())
|
||||
self.assertTrue(raster_copy.isValid())
|
||||
|
||||
def test_project_relations(self):
|
||||
"""Tests that a project with bad layers and relations can be saved with relations"""
|
||||
|
||||
temp_dir = QTemporaryDir()
|
||||
p = QgsProject.instance()
|
||||
for ext in ('qgs', 'gpkg'):
|
||||
copyfile(os.path.join(TEST_DATA_DIR, 'projects', 'relation_reference_test.%s' % ext), os.path.join(temp_dir.path(), 'relation_reference_test.%s' % ext))
|
||||
|
||||
# Load the good project
|
||||
project_path = os.path.join(temp_dir.path(), 'relation_reference_test.qgs')
|
||||
self.assertTrue(p.read(project_path))
|
||||
point_a = list(p.mapLayersByName('point_a'))[0]
|
||||
point_b = list(p.mapLayersByName('point_b'))[0]
|
||||
point_a_source = point_a.publicSource()
|
||||
point_b_source = point_b.publicSource()
|
||||
self.assertTrue(point_a.isValid())
|
||||
self.assertTrue(point_b.isValid())
|
||||
|
||||
# Check relations
|
||||
def _check_relations():
|
||||
relation = list(p.relationManager().relations().values())[0]
|
||||
self.assertTrue(relation.isValid())
|
||||
self.assertEqual(relation.referencedLayer().id(), point_b.id())
|
||||
self.assertEqual(relation.referencingLayer().id(), point_a.id())
|
||||
|
||||
_check_relations()
|
||||
|
||||
# Now build a bad project
|
||||
bad_project_path = os.path.join(temp_dir.path(), 'relation_reference_test_bad.qgs')
|
||||
with open(project_path, 'r') as infile:
|
||||
with open(bad_project_path, 'w+') as outfile:
|
||||
outfile.write(infile.read().replace('./relation_reference_test.gpkg', './relation_reference_test-BAD_SOURCE.gpkg'))
|
||||
|
||||
# Load the bad project
|
||||
self.assertTrue(p.read(bad_project_path))
|
||||
point_a = list(p.mapLayersByName('point_a'))[0]
|
||||
point_b = list(p.mapLayersByName('point_b'))[0]
|
||||
self.assertFalse(point_a.isValid())
|
||||
self.assertFalse(point_b.isValid())
|
||||
|
||||
# This fails because relations are not valid anymore
|
||||
with self.assertRaises(AssertionError):
|
||||
_check_relations()
|
||||
|
||||
# Changing data source, relations should be restored:
|
||||
point_a.setDataSource(point_a_source, 'point_a', 'ogr')
|
||||
point_b.setDataSource(point_b_source, 'point_b', 'ogr')
|
||||
self.assertTrue(point_a.isValid())
|
||||
self.assertTrue(point_b.isValid())
|
||||
|
||||
# Check if relations were restored
|
||||
_check_relations()
|
||||
|
||||
# Reload the bad project
|
||||
self.assertTrue(p.read(bad_project_path))
|
||||
point_a = list(p.mapLayersByName('point_a'))[0]
|
||||
point_b = list(p.mapLayersByName('point_b'))[0]
|
||||
self.assertFalse(point_a.isValid())
|
||||
self.assertFalse(point_b.isValid())
|
||||
|
||||
# This fails because relations are not valid anymore
|
||||
with self.assertRaises(AssertionError):
|
||||
_check_relations()
|
||||
|
||||
# Save the bad project
|
||||
bad_project_path2 = os.path.join(temp_dir.path(), 'relation_reference_test_bad2.qgs')
|
||||
p.write(bad_project_path2)
|
||||
|
||||
# Now fix the bad project
|
||||
bad_project_path_fixed = os.path.join(temp_dir.path(), 'relation_reference_test_bad_fixed.qgs')
|
||||
with open(bad_project_path2, 'r') as infile:
|
||||
with open(bad_project_path_fixed, 'w+') as outfile:
|
||||
outfile.write(infile.read().replace('./relation_reference_test-BAD_SOURCE.gpkg', './relation_reference_test.gpkg'))
|
||||
|
||||
# Load the fixed project
|
||||
self.assertTrue(p.read(bad_project_path_fixed))
|
||||
point_a = list(p.mapLayersByName('point_a'))[0]
|
||||
point_b = list(p.mapLayersByName('point_b'))[0]
|
||||
point_a_source = point_a.publicSource()
|
||||
point_b_source = point_b.publicSource()
|
||||
self.assertTrue(point_a.isValid())
|
||||
self.assertTrue(point_b.isValid())
|
||||
_check_relations()
|
||||
|
||||
def testStyles(self):
|
||||
"""Test that styles for rasters and vectors are kept when setDataSource is called"""
|
||||
|
||||
options = QgsDataProvider.ProviderOptions()
|
||||
temp_dir = QTemporaryDir()
|
||||
p = QgsProject.instance()
|
||||
project_path = os.path.join(temp_dir.path(), 'good_layers_test.qgs')
|
||||
copyfile(os.path.join(TEST_DATA_DIR, 'projects', 'good_layers_test.qgs'), project_path)
|
||||
copyfile(os.path.join(TEST_DATA_DIR, 'projects', 'bad_layers_test.gpkg'), os.path.join(temp_dir.path(), 'bad_layers_test.gpkg'))
|
||||
for f in (
|
||||
'bad_layer_raster_test.tfw',
|
||||
'bad_layer_raster_test.tiff',
|
||||
'bad_layer_raster_test.tiff.aux.xml',
|
||||
'bad_layers_test.gpkg',
|
||||
'good_layers_test.qgs'):
|
||||
copyfile(os.path.join(TEST_DATA_DIR, 'projects', f), os.path.join(temp_dir.path(), f))
|
||||
|
||||
p = QgsProject().instance()
|
||||
self.assertTrue(p.read(project_path))
|
||||
self.assertEqual(p.count(), 3)
|
||||
|
||||
ms = self.getBaseMapSettings()
|
||||
point_a = list(p.mapLayersByName('point_a'))[0]
|
||||
point_b = list(p.mapLayersByName('point_b'))[0]
|
||||
raster = list(p.mapLayersByName('bad_layer_raster_test'))[0]
|
||||
self.assertTrue(point_a.isValid())
|
||||
self.assertTrue(point_b.isValid())
|
||||
self.assertTrue(raster.isValid())
|
||||
ms.setExtent(QgsRectangle(2.81861, 41.98138, 2.81952, 41.9816))
|
||||
ms.setLayers([point_a, point_b, raster])
|
||||
image = renderMapToImage(ms)
|
||||
print(os.path.join(temp_dir.path(), 'expected.png'))
|
||||
self.assertTrue(image.save(os.path.join(temp_dir.path(), 'expected.png'), 'PNG'))
|
||||
|
||||
point_a_source = point_a.publicSource()
|
||||
point_b_source = point_b.publicSource()
|
||||
raster_source = raster.publicSource()
|
||||
point_a.setDataSource(point_a_source, point_a.name(), 'ogr', options)
|
||||
point_b.setDataSource(point_b_source, point_b.name(), 'ogr', options)
|
||||
raster.setDataSource(raster_source, raster.name(), 'gdal', options)
|
||||
self.assertTrue(image.save(os.path.join(temp_dir.path(), 'actual.png'), 'PNG'))
|
||||
|
||||
self.assertTrue(filecmp.cmp(os.path.join(temp_dir.path(), 'actual.png'), os.path.join(temp_dir.path(), 'expected.png')), False)
|
||||
|
||||
# Now build a bad project
|
||||
bad_project_path = os.path.join(temp_dir.path(), 'bad_layers_test.qgs')
|
||||
with open(project_path, 'r') as infile:
|
||||
with open(bad_project_path, 'w+') as outfile:
|
||||
outfile.write(infile.read().replace('./bad_layers_test.', './bad_layers_test-BAD_SOURCE.').replace('bad_layer_raster_test.tiff', 'bad_layer_raster_test-BAD_SOURCE.tiff'))
|
||||
|
||||
self.assertTrue(p.read(bad_project_path))
|
||||
self.assertEqual(p.count(), 3)
|
||||
point_a = list(p.mapLayersByName('point_a'))[0]
|
||||
point_b = list(p.mapLayersByName('point_b'))[0]
|
||||
raster = list(p.mapLayersByName('bad_layer_raster_test'))[0]
|
||||
self.assertFalse(point_a.isValid())
|
||||
self.assertFalse(point_b.isValid())
|
||||
self.assertFalse(raster.isValid())
|
||||
|
||||
point_a.setDataSource(point_a_source, point_a.name(), 'ogr', options)
|
||||
point_b.setDataSource(point_b_source, point_b.name(), 'ogr', options)
|
||||
raster.setDataSource(raster_source, raster.name(), 'gdal', options)
|
||||
self.assertTrue(image.save(os.path.join(temp_dir.path(), 'actual_fixed.png'), 'PNG'))
|
||||
|
||||
self.assertTrue(filecmp.cmp(os.path.join(temp_dir.path(), 'actual_fixed.png'), os.path.join(temp_dir.path(), 'expected.png')), False)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@ -16,16 +16,25 @@ __revision__ = '$Format:%H$'
|
||||
import qgis # NOQA
|
||||
|
||||
import os
|
||||
import filecmp
|
||||
|
||||
from qgis.PyQt.QtCore import QFileInfo
|
||||
from qgis.PyQt.QtGui import QColor
|
||||
from qgis.PyQt.QtCore import QSize, QFileInfo, Qt, QTemporaryDir
|
||||
|
||||
from qgis.PyQt.QtGui import (
|
||||
QColor,
|
||||
QImage,
|
||||
QPainter,
|
||||
QResizeEvent
|
||||
)
|
||||
from qgis.PyQt.QtXml import QDomDocument
|
||||
|
||||
|
||||
from qgis.core import (QgsRaster,
|
||||
QgsRasterLayer,
|
||||
QgsReadWriteContext,
|
||||
QgsColorRampShader,
|
||||
QgsContrastEnhancement,
|
||||
QgsDataProvider,
|
||||
QgsProject,
|
||||
QgsMapSettings,
|
||||
QgsPointXY,
|
||||
@ -40,6 +49,7 @@ from qgis.core import (QgsRaster,
|
||||
QgsGradientColorRamp)
|
||||
from utilities import unitTestDataPath
|
||||
from qgis.testing import start_app, unittest
|
||||
from qgis.testing.mocked import get_iface
|
||||
|
||||
# Convenience instances in case you may need them
|
||||
# not used in this test
|
||||
@ -48,6 +58,14 @@ start_app()
|
||||
|
||||
class TestQgsRasterLayer(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.iface = get_iface()
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
self.iface.mapCanvas().viewport().resize(400, 400)
|
||||
# For some reason the resizeEvent is not delivered, fake it
|
||||
self.iface.mapCanvas().resizeEvent(QResizeEvent(QSize(400, 400), self.iface.mapCanvas().size()))
|
||||
|
||||
def testIdentify(self):
|
||||
myPath = os.path.join(unitTestDataPath(), 'landsat.tif')
|
||||
myFileInfo = QFileInfo(myPath)
|
||||
@ -694,6 +712,35 @@ class TestQgsRasterLayer(unittest.TestCase):
|
||||
# compare xml documents
|
||||
self.assertEqual(layer_doc.toString(), clone_doc.toString())
|
||||
|
||||
def testSetDataSource(self):
|
||||
"""Test change data source"""
|
||||
|
||||
temp_dir = QTemporaryDir()
|
||||
options = QgsDataProvider.ProviderOptions()
|
||||
myPath = os.path.join(unitTestDataPath('raster'),
|
||||
'band1_float32_noct_epsg4326.tif')
|
||||
myFileInfo = QFileInfo(myPath)
|
||||
myBaseName = myFileInfo.baseName()
|
||||
layer = QgsRasterLayer(myPath, myBaseName)
|
||||
renderer = QgsSingleBandGrayRenderer(layer.dataProvider(), 2)
|
||||
|
||||
image = layer.previewAsImage(QSize(400, 400))
|
||||
self.assertFalse(image.isNull())
|
||||
self.assertTrue(image.save(os.path.join(temp_dir.path(), 'expected.png'), "PNG"))
|
||||
|
||||
layer.setDataSource(myPath.replace('4326.tif', '4326-BAD_SOURCE.tif'), 'bad_layer', 'gdal', options)
|
||||
self.assertFalse(layer.isValid())
|
||||
image = layer.previewAsImage(QSize(400, 400))
|
||||
self.assertTrue(image.isNull())
|
||||
|
||||
layer.setDataSource(myPath.replace('4326-BAD_SOURCE.tif', '4326.tif'), 'bad_layer', 'gdal', options)
|
||||
self.assertTrue(layer.isValid())
|
||||
image = layer.previewAsImage(QSize(400, 400))
|
||||
self.assertFalse(image.isNull())
|
||||
self.assertTrue(image.save(os.path.join(temp_dir.path(), 'actual.png'), "PNG"))
|
||||
|
||||
self.assertTrue(filecmp.cmp(os.path.join(temp_dir.path(), 'actual.png'), os.path.join(temp_dir.path(), 'expected.png')), False)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
@ -20,6 +20,7 @@ from qgis.core import (QgsVectorLayer,
|
||||
QgsGeometry,
|
||||
QgsPointXY,
|
||||
QgsAttributeEditorElement,
|
||||
QgsAttributeEditorRelation,
|
||||
QgsProject
|
||||
)
|
||||
from utilities import unitTestDataPath
|
||||
@ -162,7 +163,10 @@ class TestQgsRelation(unittest.TestCase):
|
||||
def testValidRelationAfterChangingStyle(self):
|
||||
# load project
|
||||
myPath = os.path.join(unitTestDataPath(), 'relations.qgs')
|
||||
QgsProject.instance().read(myPath)
|
||||
p = QgsProject.instance()
|
||||
self.assertTrue(p.read(myPath))
|
||||
for l in p.mapLayers().values():
|
||||
self.assertTrue(l.isValid())
|
||||
|
||||
# get referenced layer
|
||||
relations = QgsProject.instance().relationManager().relations()
|
||||
@ -171,6 +175,7 @@ class TestQgsRelation(unittest.TestCase):
|
||||
|
||||
# check that the relation is valid
|
||||
valid = False
|
||||
self.assertEqual(len(referencedLayer.editFormConfig().tabs()[0].children()), 7)
|
||||
for tab in referencedLayer.editFormConfig().tabs():
|
||||
for t in tab.children():
|
||||
if (t.type() == QgsAttributeEditorElement.AeTypeRelation):
|
||||
@ -180,6 +185,11 @@ class TestQgsRelation(unittest.TestCase):
|
||||
# update style
|
||||
referencedLayer.styleManager().setCurrentStyle("custom")
|
||||
|
||||
for l in p.mapLayers().values():
|
||||
self.assertTrue(l.isValid())
|
||||
|
||||
self.assertEqual(len(referencedLayer.editFormConfig().tabs()[0].children()), 7)
|
||||
|
||||
# check that the relation is still valid
|
||||
referencedLayer = relation.referencedLayer()
|
||||
valid = False
|
||||
|
6
tests/testdata/projects/bad_layer_raster_test.tfw
vendored
Normal file
6
tests/testdata/projects/bad_layer_raster_test.tfw
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
0.00000055284657534
|
||||
0
|
||||
0
|
||||
-0.00000055284657534
|
||||
2.8182844964232876
|
||||
41.98181469976164948
|
BIN
tests/testdata/projects/bad_layer_raster_test.tiff
vendored
Normal file
BIN
tests/testdata/projects/bad_layer_raster_test.tiff
vendored
Normal file
Binary file not shown.
36
tests/testdata/projects/bad_layer_raster_test.tiff.aux.xml
vendored
Normal file
36
tests/testdata/projects/bad_layer_raster_test.tiff.aux.xml
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
<PAMDataset>
|
||||
<PAMRasterBand band="1">
|
||||
<Histograms>
|
||||
<HistItem>
|
||||
<HistMin>-0.498046875</HistMin>
|
||||
<HistMax>255.498046875</HistMax>
|
||||
<BucketCount>256</BucketCount>
|
||||
<IncludeOutOfRange>0</IncludeOutOfRange>
|
||||
<Approximate>0</Approximate>
|
||||
<HistCounts>13|18|50|12|7|13|16|15|14|20|6|13|13|8|9|58|31|15|21|16|15|25|51|20|19|22|16|47|30|20|29|32|22|38|24|32|32|39|35|47|70|68|52|35|121|46|42|60|53|37|39|44|49|83|52|63|54|67|77|73|61|72|56|76|63|73|72|76|99|69|93|90|80|85|92|110|100|106|112|109|100|99|92|113|137|151|136|129|182|156|152|146|126|147|162|163|195|157|145|202|219|164|180|175|213|187|206|193|195|214|211|208|192|211|191|925|454|420|397|455|428|333|414|313|402|378|392|418|364|400|427|420|453|444|477|403|447|513|438|537|510|527|530|544|570|546|619|530|595|651|597|660|738|714|668|876|828|20253|2012|1713|1589|1342|1401|1213|1242|1274|1335|1360|1307|1406|1363|1342|3316|1661|1674|1552|1719|1705|1667|1638|1449|1642|1468|1484|1550|1517|1605|1545|1617|1599|1683|2325|2934|3369|3918|4835|5909|7068|7857|148605|9058|10029|10103|9572|9936|10530|10904|11245|10726|10940|10999|11303|11583|12851|13863|15968|20827|1929455|12350|9950|9683|9843|10560|14977|666396|5951|5178|4871|4578|4364|4380|4142|4039|3754|3589|4403|3554|3073|2813|2513|2423|2209|2196|2167|2204|2215|2434|115706|1815|1722|1771|1920|2175|2521|3127|120133</HistCounts>
|
||||
</HistItem>
|
||||
</Histograms>
|
||||
<Metadata>
|
||||
<MDI key="STATISTICS_MAXIMUM">255</MDI>
|
||||
<MDI key="STATISTICS_MEAN">217.8975575084</MDI>
|
||||
<MDI key="STATISTICS_MINIMUM">0</MDI>
|
||||
<MDI key="STATISTICS_STDDEV">16.402309158646</MDI>
|
||||
</Metadata>
|
||||
</PAMRasterBand>
|
||||
<PAMRasterBand band="2">
|
||||
<Metadata>
|
||||
<MDI key="STATISTICS_MAXIMUM">255</MDI>
|
||||
<MDI key="STATISTICS_MEAN">211.56457158206</MDI>
|
||||
<MDI key="STATISTICS_MINIMUM">0</MDI>
|
||||
<MDI key="STATISTICS_STDDEV">19.453039894122</MDI>
|
||||
</Metadata>
|
||||
</PAMRasterBand>
|
||||
<PAMRasterBand band="3">
|
||||
<Metadata>
|
||||
<MDI key="STATISTICS_MAXIMUM">255</MDI>
|
||||
<MDI key="STATISTICS_MEAN">203.74267168054</MDI>
|
||||
<MDI key="STATISTICS_MINIMUM">8</MDI>
|
||||
<MDI key="STATISTICS_STDDEV">21.479123268522</MDI>
|
||||
</Metadata>
|
||||
</PAMRasterBand>
|
||||
</PAMDataset>
|
BIN
tests/testdata/projects/bad_layers_test.gpkg
vendored
Normal file
BIN
tests/testdata/projects/bad_layers_test.gpkg
vendored
Normal file
Binary file not shown.
832
tests/testdata/projects/good_layers_test.qgs
vendored
Normal file
832
tests/testdata/projects/good_layers_test.qgs
vendored
Normal file
@ -0,0 +1,832 @@
|
||||
<!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM'>
|
||||
<qgis version="3.5.0-Master" projectname="">
|
||||
<homePath path=""/>
|
||||
<title></title>
|
||||
<autotransaction active="0"/>
|
||||
<evaluateDefaultValues active="0"/>
|
||||
<trust active="0"/>
|
||||
<projectCrs>
|
||||
<spatialrefsys>
|
||||
<proj4>+proj=longlat +datum=WGS84 +no_defs</proj4>
|
||||
<srsid>3452</srsid>
|
||||
<srid>4326</srid>
|
||||
<authid>EPSG:4326</authid>
|
||||
<description>WGS 84</description>
|
||||
<projectionacronym>longlat</projectionacronym>
|
||||
<ellipsoidacronym>WGS84</ellipsoidacronym>
|
||||
<geographicflag>true</geographicflag>
|
||||
</spatialrefsys>
|
||||
</projectCrs>
|
||||
<layer-tree-group>
|
||||
<customproperties/>
|
||||
<layer-tree-layer providerKey="ogr" id="point_b_d23a7df9_c9d6_4b48_9162_5fc1a7db2b96" name="point_b" checked="Qt::Checked" source="./bad_layers_test.gpkg|layername=point_b" expanded="1">
|
||||
<customproperties/>
|
||||
</layer-tree-layer>
|
||||
<layer-tree-layer providerKey="ogr" id="point_a_e99cf1b1_e13e_44a8_b912_58505e7ac967" name="point_a" checked="Qt::Checked" source="./bad_layers_test.gpkg|layername=point_a" expanded="1">
|
||||
<customproperties/>
|
||||
</layer-tree-layer>
|
||||
<layer-tree-layer providerKey="gdal" id="bad_layer_raster_test_18978e96_6781_4a5d_b0bc_474994ed231a" name="bad_layer_raster_test" checked="Qt::Checked" source="./bad_layer_raster_test.tiff" expanded="1">
|
||||
<customproperties/>
|
||||
</layer-tree-layer>
|
||||
<custom-order enabled="0">
|
||||
<item>point_a_e99cf1b1_e13e_44a8_b912_58505e7ac967</item>
|
||||
<item>point_b_d23a7df9_c9d6_4b48_9162_5fc1a7db2b96</item>
|
||||
<item>bad_layer_raster_test_18978e96_6781_4a5d_b0bc_474994ed231a</item>
|
||||
</custom-order>
|
||||
</layer-tree-group>
|
||||
<snapping-settings unit="1" enabled="0" mode="2" intersection-snapping="0" type="1" tolerance="12">
|
||||
<individual-layer-settings>
|
||||
<layer-setting id="point_b_d23a7df9_c9d6_4b48_9162_5fc1a7db2b96" enabled="0" units="1" type="1" tolerance="12"/>
|
||||
<layer-setting id="point_a_e99cf1b1_e13e_44a8_b912_58505e7ac967" enabled="0" units="1" type="1" tolerance="12"/>
|
||||
</individual-layer-settings>
|
||||
</snapping-settings>
|
||||
<relations>
|
||||
<relation id="point_a_e9_point_b_ref_point_b_d2_fid" name="point a to b" strength="Association" referencingLayer="point_a_e99cf1b1_e13e_44a8_b912_58505e7ac967" referencedLayer="point_b_d23a7df9_c9d6_4b48_9162_5fc1a7db2b96">
|
||||
<fieldRef referencingField="point_b_ref" referencedField="fid"/>
|
||||
</relation>
|
||||
</relations>
|
||||
<mapcanvas name="theMapCanvas" annotationsVisible="1">
|
||||
<units>degrees</units>
|
||||
<extent>
|
||||
<xmin>2.81828421961071651</xmin>
|
||||
<ymin>41.9812628573046851</ymin>
|
||||
<xmax>2.82010032075159867</xmax>
|
||||
<ymax>41.9817810775760023</ymax>
|
||||
</extent>
|
||||
<rotation>0</rotation>
|
||||
<destinationsrs>
|
||||
<spatialrefsys>
|
||||
<proj4>+proj=longlat +datum=WGS84 +no_defs</proj4>
|
||||
<srsid>3452</srsid>
|
||||
<srid>4326</srid>
|
||||
<authid>EPSG:4326</authid>
|
||||
<description>WGS 84</description>
|
||||
<projectionacronym>longlat</projectionacronym>
|
||||
<ellipsoidacronym>WGS84</ellipsoidacronym>
|
||||
<geographicflag>true</geographicflag>
|
||||
</spatialrefsys>
|
||||
</destinationsrs>
|
||||
<rendermaptile>0</rendermaptile>
|
||||
</mapcanvas>
|
||||
<projectModels/>
|
||||
<legend updateDrawingOrder="true">
|
||||
<legendlayer name="point_b" checked="Qt::Checked" drawingOrder="-1" showFeatureCount="0" open="true">
|
||||
<filegroup open="true" hidden="false">
|
||||
<legendlayerfile visible="1" layerid="point_b_d23a7df9_c9d6_4b48_9162_5fc1a7db2b96" isInOverview="0"/>
|
||||
</filegroup>
|
||||
</legendlayer>
|
||||
<legendlayer name="point_a" checked="Qt::Checked" drawingOrder="-1" showFeatureCount="0" open="true">
|
||||
<filegroup open="true" hidden="false">
|
||||
<legendlayerfile visible="1" layerid="point_a_e99cf1b1_e13e_44a8_b912_58505e7ac967" isInOverview="0"/>
|
||||
</filegroup>
|
||||
</legendlayer>
|
||||
<legendlayer name="bad_layer_raster_test" checked="Qt::Checked" drawingOrder="-1" showFeatureCount="0" open="true">
|
||||
<filegroup open="true" hidden="false">
|
||||
<legendlayerfile visible="1" layerid="bad_layer_raster_test_18978e96_6781_4a5d_b0bc_474994ed231a" isInOverview="0"/>
|
||||
</filegroup>
|
||||
</legendlayer>
|
||||
</legend>
|
||||
<mapViewDocks/>
|
||||
<mapViewDocks3D/>
|
||||
<projectlayers>
|
||||
<maplayer autoRefreshTime="0" minScale="1e+8" autoRefreshEnabled="0" maxScale="0" refreshOnNotifyMessage="" hasScaleBasedVisibilityFlag="0" type="raster" refreshOnNotifyEnabled="0" styleCategories="AllStyleCategories">
|
||||
<extent>
|
||||
<xmin>2.81828421999999978</xmin>
|
||||
<ymin>41.98122895881507333</ymin>
|
||||
<xmax>2.82010032099999153</xmax>
|
||||
<ymax>41.98181497618493552</ymax>
|
||||
</extent>
|
||||
<id>bad_layer_raster_test_18978e96_6781_4a5d_b0bc_474994ed231a</id>
|
||||
<datasource>./bad_layer_raster_test.tiff</datasource>
|
||||
<keywordList>
|
||||
<value></value>
|
||||
</keywordList>
|
||||
<layername>bad_layer_raster_test</layername>
|
||||
<srs>
|
||||
<spatialrefsys>
|
||||
<proj4>+proj=longlat +datum=WGS84 +no_defs</proj4>
|
||||
<srsid>3452</srsid>
|
||||
<srid>4326</srid>
|
||||
<authid>EPSG:4326</authid>
|
||||
<description>WGS 84</description>
|
||||
<projectionacronym>longlat</projectionacronym>
|
||||
<ellipsoidacronym>WGS84</ellipsoidacronym>
|
||||
<geographicflag>true</geographicflag>
|
||||
</spatialrefsys>
|
||||
</srs>
|
||||
<resourceMetadata>
|
||||
<identifier></identifier>
|
||||
<parentidentifier></parentidentifier>
|
||||
<language></language>
|
||||
<type></type>
|
||||
<title></title>
|
||||
<abstract></abstract>
|
||||
<contact>
|
||||
<name></name>
|
||||
<organization></organization>
|
||||
<position></position>
|
||||
<voice></voice>
|
||||
<fax></fax>
|
||||
<email></email>
|
||||
<role></role>
|
||||
</contact>
|
||||
<links/>
|
||||
<fees></fees>
|
||||
<encoding></encoding>
|
||||
<crs>
|
||||
<spatialrefsys>
|
||||
<proj4></proj4>
|
||||
<srsid>0</srsid>
|
||||
<srid>0</srid>
|
||||
<authid></authid>
|
||||
<description></description>
|
||||
<projectionacronym></projectionacronym>
|
||||
<ellipsoidacronym></ellipsoidacronym>
|
||||
<geographicflag>true</geographicflag>
|
||||
</spatialrefsys>
|
||||
</crs>
|
||||
<extent>
|
||||
<spatial minz="0" maxx="0" maxy="0" dimensions="2" crs="" minx="0" miny="0" maxz="0"/>
|
||||
<temporal>
|
||||
<period>
|
||||
<start></start>
|
||||
<end></end>
|
||||
</period>
|
||||
</temporal>
|
||||
</extent>
|
||||
</resourceMetadata>
|
||||
<provider>gdal</provider>
|
||||
<noData>
|
||||
<noDataList bandNo="1" useSrcNoData="0"/>
|
||||
<noDataList bandNo="2" useSrcNoData="0"/>
|
||||
<noDataList bandNo="3" useSrcNoData="0"/>
|
||||
<noDataList bandNo="4" useSrcNoData="0"/>
|
||||
</noData>
|
||||
<map-layer-style-manager current="default">
|
||||
<map-layer-style name="default"/>
|
||||
</map-layer-style-manager>
|
||||
<flags>
|
||||
<Identifiable>1</Identifiable>
|
||||
<Removable>1</Removable>
|
||||
<Searchable>1</Searchable>
|
||||
</flags>
|
||||
<customproperties>
|
||||
<property value="false" key="WMSBackgroundLayer"/>
|
||||
<property value="false" key="WMSPublishDataSourceUrl"/>
|
||||
<property value="0" key="embeddedWidgets/count"/>
|
||||
<property value="Value" key="identify/format"/>
|
||||
</customproperties>
|
||||
<pipe>
|
||||
<rasterrenderer grayBand="1" opacity="1" alphaBand="4" gradient="BlackToWhite" type="singlebandgray">
|
||||
<rasterTransparency/>
|
||||
<minMaxOrigin>
|
||||
<limits>MinMax</limits>
|
||||
<extent>WholeRaster</extent>
|
||||
<statAccuracy>Estimated</statAccuracy>
|
||||
<cumulativeCutLower>0.02</cumulativeCutLower>
|
||||
<cumulativeCutUpper>0.98</cumulativeCutUpper>
|
||||
<stdDevFactor>2</stdDevFactor>
|
||||
</minMaxOrigin>
|
||||
<contrastEnhancement>
|
||||
<minValue>0</minValue>
|
||||
<maxValue>255</maxValue>
|
||||
<algorithm>StretchToMinimumMaximum</algorithm>
|
||||
</contrastEnhancement>
|
||||
</rasterrenderer>
|
||||
<brightnesscontrast brightness="0" contrast="0"/>
|
||||
<huesaturation colorizeGreen="128" colorizeStrength="100" colorizeBlue="128" saturation="0" colorizeRed="255" colorizeOn="0" grayscaleMode="0"/>
|
||||
<rasterresampler maxOversampling="2"/>
|
||||
</pipe>
|
||||
<blendMode>0</blendMode>
|
||||
</maplayer>
|
||||
<maplayer autoRefreshTime="0" geometry="Point" minScale="1e+8" labelsEnabled="0" autoRefreshEnabled="0" maxScale="0" refreshOnNotifyMessage="" simplifyAlgorithm="0" simplifyDrawingTol="1" simplifyMaxScale="1" hasScaleBasedVisibilityFlag="0" type="vector" simplifyDrawingHints="0" refreshOnNotifyEnabled="0" styleCategories="AllStyleCategories" readOnly="0" simplifyLocal="1">
|
||||
<extent>
|
||||
<xmin>2.81884431838989258</xmin>
|
||||
<ymin>41.9814453125</ymin>
|
||||
<xmax>2.81894969940185547</xmax>
|
||||
<ymax>41.98154067993164063</ymax>
|
||||
</extent>
|
||||
<id>point_a_e99cf1b1_e13e_44a8_b912_58505e7ac967</id>
|
||||
<datasource>./bad_layers_test.gpkg|layername=point_a</datasource>
|
||||
<keywordList>
|
||||
<value></value>
|
||||
</keywordList>
|
||||
<layername>point_a</layername>
|
||||
<srs>
|
||||
<spatialrefsys>
|
||||
<proj4>+proj=longlat +datum=WGS84 +no_defs</proj4>
|
||||
<srsid>3452</srsid>
|
||||
<srid>4326</srid>
|
||||
<authid>EPSG:4326</authid>
|
||||
<description>WGS 84</description>
|
||||
<projectionacronym>longlat</projectionacronym>
|
||||
<ellipsoidacronym>WGS84</ellipsoidacronym>
|
||||
<geographicflag>true</geographicflag>
|
||||
</spatialrefsys>
|
||||
</srs>
|
||||
<resourceMetadata>
|
||||
<identifier></identifier>
|
||||
<parentidentifier></parentidentifier>
|
||||
<language></language>
|
||||
<type></type>
|
||||
<title></title>
|
||||
<abstract></abstract>
|
||||
<contact>
|
||||
<name></name>
|
||||
<organization></organization>
|
||||
<position></position>
|
||||
<voice></voice>
|
||||
<fax></fax>
|
||||
<email></email>
|
||||
<role></role>
|
||||
</contact>
|
||||
<links/>
|
||||
<fees></fees>
|
||||
<encoding></encoding>
|
||||
<crs>
|
||||
<spatialrefsys>
|
||||
<proj4></proj4>
|
||||
<srsid>0</srsid>
|
||||
<srid>0</srid>
|
||||
<authid></authid>
|
||||
<description></description>
|
||||
<projectionacronym></projectionacronym>
|
||||
<ellipsoidacronym></ellipsoidacronym>
|
||||
<geographicflag>false</geographicflag>
|
||||
</spatialrefsys>
|
||||
</crs>
|
||||
<extent>
|
||||
<spatial minz="0" maxx="0" maxy="0" dimensions="2" crs="" minx="0" miny="0" maxz="0"/>
|
||||
<temporal>
|
||||
<period>
|
||||
<start></start>
|
||||
<end></end>
|
||||
</period>
|
||||
</temporal>
|
||||
</extent>
|
||||
</resourceMetadata>
|
||||
<provider encoding="UTF-8">ogr</provider>
|
||||
<vectorjoins/>
|
||||
<layerDependencies/>
|
||||
<dataDependencies/>
|
||||
<legend type="default-vector"/>
|
||||
<expressionfields/>
|
||||
<map-layer-style-manager current="default">
|
||||
<map-layer-style name="default"/>
|
||||
</map-layer-style-manager>
|
||||
<auxiliaryLayer/>
|
||||
<flags>
|
||||
<Identifiable>1</Identifiable>
|
||||
<Removable>1</Removable>
|
||||
<Searchable>1</Searchable>
|
||||
</flags>
|
||||
<renderer-v2 forceraster="0" symbollevels="0" enableorderby="0" type="singleSymbol">
|
||||
<symbols>
|
||||
<symbol alpha="1" name="0" clip_to_extent="1" type="marker">
|
||||
<layer locked="0" pass="0" enabled="1" class="SimpleMarker">
|
||||
<prop k="angle" v="0"/>
|
||||
<prop k="color" v="219,30,42,255"/>
|
||||
<prop k="horizontal_anchor_point" v="1"/>
|
||||
<prop k="joinstyle" v="bevel"/>
|
||||
<prop k="name" v="diamond"/>
|
||||
<prop k="offset" v="0,0"/>
|
||||
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="offset_unit" v="MM"/>
|
||||
<prop k="outline_color" v="128,17,25,255"/>
|
||||
<prop k="outline_style" v="solid"/>
|
||||
<prop k="outline_width" v="0.4"/>
|
||||
<prop k="outline_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="outline_width_unit" v="MM"/>
|
||||
<prop k="scale_method" v="diameter"/>
|
||||
<prop k="size" v="4.4"/>
|
||||
<prop k="size_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="size_unit" v="MM"/>
|
||||
<prop k="vertical_anchor_point" v="1"/>
|
||||
<data_defined_properties>
|
||||
<Option type="Map">
|
||||
<Option value="" name="name" type="QString"/>
|
||||
<Option name="properties"/>
|
||||
<Option value="collection" name="type" type="QString"/>
|
||||
</Option>
|
||||
</data_defined_properties>
|
||||
</layer>
|
||||
</symbol>
|
||||
</symbols>
|
||||
<rotation/>
|
||||
<sizescale/>
|
||||
</renderer-v2>
|
||||
<customproperties>
|
||||
<property value="0" key="embeddedWidgets/count"/>
|
||||
<property key="variableNames"/>
|
||||
<property key="variableValues"/>
|
||||
</customproperties>
|
||||
<blendMode>0</blendMode>
|
||||
<featureBlendMode>0</featureBlendMode>
|
||||
<layerOpacity>1</layerOpacity>
|
||||
<SingleCategoryDiagramRenderer diagramType="Histogram" attributeLegend="1">
|
||||
<DiagramCategory enabled="0" labelPlacementMethod="XHeight" lineSizeScale="3x:0,0,0,0,0,0" minimumSize="0" penAlpha="255" lineSizeType="MM" minScaleDenominator="0" sizeScale="3x:0,0,0,0,0,0" height="15" maxScaleDenominator="1e+8" opacity="1" barWidth="5" diagramOrientation="Up" width="15" scaleBasedVisibility="0" backgroundColor="#ffffff" scaleDependency="Area" sizeType="MM" rotationOffset="270" penColor="#000000" penWidth="0" backgroundAlpha="255">
|
||||
<fontProperties description="Noto Sans,9,-1,5,50,0,0,0,0,0" style=""/>
|
||||
<attribute color="#000000" label="" field=""/>
|
||||
</DiagramCategory>
|
||||
</SingleCategoryDiagramRenderer>
|
||||
<DiagramLayerSettings priority="0" obstacle="0" placement="0" zIndex="0" showAll="1" linePlacementFlags="18" dist="0">
|
||||
<properties>
|
||||
<Option type="Map">
|
||||
<Option value="" name="name" type="QString"/>
|
||||
<Option name="properties"/>
|
||||
<Option value="collection" name="type" type="QString"/>
|
||||
</Option>
|
||||
</properties>
|
||||
</DiagramLayerSettings>
|
||||
<geometryOptions geometryPrecision="0" removeDuplicateNodes="0">
|
||||
<activeChecks/>
|
||||
<checkConfiguration/>
|
||||
</geometryOptions>
|
||||
<fieldConfiguration>
|
||||
<field name="fid">
|
||||
<editWidget type="TextEdit">
|
||||
<config>
|
||||
<Option/>
|
||||
</config>
|
||||
</editWidget>
|
||||
</field>
|
||||
<field name="name">
|
||||
<editWidget type="TextEdit">
|
||||
<config>
|
||||
<Option/>
|
||||
</config>
|
||||
</editWidget>
|
||||
</field>
|
||||
<field name="point_b_ref">
|
||||
<editWidget type="RelationReference">
|
||||
<config>
|
||||
<Option type="Map">
|
||||
<Option value="false" name="AllowAddFeatures" type="bool"/>
|
||||
<Option value="false" name="AllowNULL" type="bool"/>
|
||||
<Option value="false" name="MapIdentification" type="bool"/>
|
||||
<Option value="false" name="OrderByValue" type="bool"/>
|
||||
<Option value="false" name="ReadOnly" type="bool"/>
|
||||
<Option value="point_a_e9_point_b_ref_point_b_d2_fid" name="Relation" type="QString"/>
|
||||
<Option value="false" name="ShowForm" type="bool"/>
|
||||
<Option value="true" name="ShowOpenFormButton" type="bool"/>
|
||||
</Option>
|
||||
</config>
|
||||
</editWidget>
|
||||
</field>
|
||||
</fieldConfiguration>
|
||||
<aliases>
|
||||
<alias index="0" name="" field="fid"/>
|
||||
<alias index="1" name="" field="name"/>
|
||||
<alias index="2" name="" field="point_b_ref"/>
|
||||
</aliases>
|
||||
<excludeAttributesWMS/>
|
||||
<excludeAttributesWFS/>
|
||||
<defaults>
|
||||
<default applyOnUpdate="0" expression="" field="fid"/>
|
||||
<default applyOnUpdate="0" expression="" field="name"/>
|
||||
<default applyOnUpdate="0" expression="" field="point_b_ref"/>
|
||||
</defaults>
|
||||
<constraints>
|
||||
<constraint constraints="3" exp_strength="0" unique_strength="1" notnull_strength="1" field="fid"/>
|
||||
<constraint constraints="0" exp_strength="0" unique_strength="0" notnull_strength="0" field="name"/>
|
||||
<constraint constraints="0" exp_strength="0" unique_strength="0" notnull_strength="0" field="point_b_ref"/>
|
||||
</constraints>
|
||||
<constraintExpressions>
|
||||
<constraint exp="" field="fid" desc=""/>
|
||||
<constraint exp="" field="name" desc=""/>
|
||||
<constraint exp="" field="point_b_ref" desc=""/>
|
||||
</constraintExpressions>
|
||||
<expressionfields/>
|
||||
<attributeactions>
|
||||
<defaultAction value="{00000000-0000-0000-0000-000000000000}" key="Canvas"/>
|
||||
</attributeactions>
|
||||
<attributetableconfig actionWidgetStyle="dropDown" sortExpression="" sortOrder="0">
|
||||
<columns>
|
||||
<column width="-1" name="fid" type="field" hidden="0"/>
|
||||
<column width="-1" name="name" type="field" hidden="0"/>
|
||||
<column width="-1" name="point_b_ref" type="field" hidden="0"/>
|
||||
<column width="-1" type="actions" hidden="1"/>
|
||||
</columns>
|
||||
</attributetableconfig>
|
||||
<conditionalstyles>
|
||||
<rowstyles/>
|
||||
<fieldstyles/>
|
||||
</conditionalstyles>
|
||||
<editform tolerant="1"></editform>
|
||||
<editforminit/>
|
||||
<editforminitcodesource>0</editforminitcodesource>
|
||||
<editforminitfilepath></editforminitfilepath>
|
||||
<editforminitcode><![CDATA[# -*- coding: utf-8 -*-
|
||||
"""
|
||||
QGIS forms can have a Python function that is called when the form is
|
||||
opened.
|
||||
|
||||
Use this function to add extra logic to your forms.
|
||||
|
||||
Enter the name of the function in the "Python Init function"
|
||||
field.
|
||||
An example follows:
|
||||
"""
|
||||
from qgis.PyQt.QtWidgets import QWidget
|
||||
|
||||
def my_form_open(dialog, layer, feature):
|
||||
geom = feature.geometry()
|
||||
control = dialog.findChild(QWidget, "MyLineEdit")
|
||||
]]></editforminitcode>
|
||||
<featformsuppress>0</featformsuppress>
|
||||
<editorlayout>generatedlayout</editorlayout>
|
||||
<editable>
|
||||
<field name="fid" editable="1"/>
|
||||
<field name="name" editable="1"/>
|
||||
<field name="point_b_ref" editable="1"/>
|
||||
</editable>
|
||||
<labelOnTop>
|
||||
<field labelOnTop="0" name="fid"/>
|
||||
<field labelOnTop="0" name="name"/>
|
||||
<field labelOnTop="0" name="point_b_ref"/>
|
||||
</labelOnTop>
|
||||
<widgets/>
|
||||
<previewExpression>fid</previewExpression>
|
||||
<mapTip></mapTip>
|
||||
</maplayer>
|
||||
<maplayer autoRefreshTime="0" geometry="Point" minScale="1e+8" labelsEnabled="0" autoRefreshEnabled="0" maxScale="0" refreshOnNotifyMessage="" simplifyAlgorithm="0" simplifyDrawingTol="1" simplifyMaxScale="1" hasScaleBasedVisibilityFlag="0" type="vector" simplifyDrawingHints="0" refreshOnNotifyEnabled="0" styleCategories="AllStyleCategories" readOnly="0" simplifyLocal="1">
|
||||
<extent>
|
||||
<xmin>2.81895375251770108</xmin>
|
||||
<ymin>41.98152542114257813</ymin>
|
||||
<xmax>2.81904959678649902</xmax>
|
||||
<ymax>41.981597900390625</ymax>
|
||||
</extent>
|
||||
<id>point_b_d23a7df9_c9d6_4b48_9162_5fc1a7db2b96</id>
|
||||
<datasource>./bad_layers_test.gpkg|layername=point_b</datasource>
|
||||
<keywordList>
|
||||
<value></value>
|
||||
</keywordList>
|
||||
<layername>point_b</layername>
|
||||
<srs>
|
||||
<spatialrefsys>
|
||||
<proj4>+proj=longlat +datum=WGS84 +no_defs</proj4>
|
||||
<srsid>3452</srsid>
|
||||
<srid>4326</srid>
|
||||
<authid>EPSG:4326</authid>
|
||||
<description>WGS 84</description>
|
||||
<projectionacronym>longlat</projectionacronym>
|
||||
<ellipsoidacronym>WGS84</ellipsoidacronym>
|
||||
<geographicflag>true</geographicflag>
|
||||
</spatialrefsys>
|
||||
</srs>
|
||||
<resourceMetadata>
|
||||
<identifier></identifier>
|
||||
<parentidentifier></parentidentifier>
|
||||
<language></language>
|
||||
<type></type>
|
||||
<title></title>
|
||||
<abstract></abstract>
|
||||
<contact>
|
||||
<name></name>
|
||||
<organization></organization>
|
||||
<position></position>
|
||||
<voice></voice>
|
||||
<fax></fax>
|
||||
<email></email>
|
||||
<role></role>
|
||||
</contact>
|
||||
<links/>
|
||||
<fees></fees>
|
||||
<encoding></encoding>
|
||||
<crs>
|
||||
<spatialrefsys>
|
||||
<proj4></proj4>
|
||||
<srsid>0</srsid>
|
||||
<srid>0</srid>
|
||||
<authid></authid>
|
||||
<description></description>
|
||||
<projectionacronym></projectionacronym>
|
||||
<ellipsoidacronym></ellipsoidacronym>
|
||||
<geographicflag>false</geographicflag>
|
||||
</spatialrefsys>
|
||||
</crs>
|
||||
<extent>
|
||||
<spatial minz="0" maxx="0" maxy="0" dimensions="2" crs="" minx="0" miny="0" maxz="0"/>
|
||||
<temporal>
|
||||
<period>
|
||||
<start></start>
|
||||
<end></end>
|
||||
</period>
|
||||
</temporal>
|
||||
</extent>
|
||||
</resourceMetadata>
|
||||
<provider encoding="UTF-8">ogr</provider>
|
||||
<vectorjoins/>
|
||||
<layerDependencies/>
|
||||
<dataDependencies/>
|
||||
<legend type="default-vector"/>
|
||||
<expressionfields/>
|
||||
<map-layer-style-manager current="default">
|
||||
<map-layer-style name="default"/>
|
||||
</map-layer-style-manager>
|
||||
<auxiliaryLayer/>
|
||||
<flags>
|
||||
<Identifiable>1</Identifiable>
|
||||
<Removable>1</Removable>
|
||||
<Searchable>1</Searchable>
|
||||
</flags>
|
||||
<renderer-v2 forceraster="0" symbollevels="0" enableorderby="0" type="singleSymbol">
|
||||
<symbols>
|
||||
<symbol alpha="1" name="0" clip_to_extent="1" type="marker">
|
||||
<layer locked="0" pass="0" enabled="1" class="SimpleMarker">
|
||||
<prop k="angle" v="0"/>
|
||||
<prop k="color" v="84,176,74,255"/>
|
||||
<prop k="horizontal_anchor_point" v="1"/>
|
||||
<prop k="joinstyle" v="bevel"/>
|
||||
<prop k="name" v="diamond"/>
|
||||
<prop k="offset" v="0,0"/>
|
||||
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="offset_unit" v="MM"/>
|
||||
<prop k="outline_color" v="61,128,53,255"/>
|
||||
<prop k="outline_style" v="solid"/>
|
||||
<prop k="outline_width" v="0.4"/>
|
||||
<prop k="outline_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="outline_width_unit" v="MM"/>
|
||||
<prop k="scale_method" v="diameter"/>
|
||||
<prop k="size" v="4.4"/>
|
||||
<prop k="size_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="size_unit" v="MM"/>
|
||||
<prop k="vertical_anchor_point" v="1"/>
|
||||
<data_defined_properties>
|
||||
<Option type="Map">
|
||||
<Option value="" name="name" type="QString"/>
|
||||
<Option name="properties"/>
|
||||
<Option value="collection" name="type" type="QString"/>
|
||||
</Option>
|
||||
</data_defined_properties>
|
||||
</layer>
|
||||
</symbol>
|
||||
</symbols>
|
||||
<rotation/>
|
||||
<sizescale/>
|
||||
</renderer-v2>
|
||||
<customproperties>
|
||||
<property value="0" key="embeddedWidgets/count"/>
|
||||
<property key="variableNames"/>
|
||||
<property key="variableValues"/>
|
||||
</customproperties>
|
||||
<blendMode>0</blendMode>
|
||||
<featureBlendMode>0</featureBlendMode>
|
||||
<layerOpacity>1</layerOpacity>
|
||||
<SingleCategoryDiagramRenderer diagramType="Histogram" attributeLegend="1">
|
||||
<DiagramCategory enabled="0" labelPlacementMethod="XHeight" lineSizeScale="3x:0,0,0,0,0,0" minimumSize="0" penAlpha="255" lineSizeType="MM" minScaleDenominator="0" sizeScale="3x:0,0,0,0,0,0" height="15" maxScaleDenominator="1e+8" opacity="1" barWidth="5" diagramOrientation="Up" width="15" scaleBasedVisibility="0" backgroundColor="#ffffff" scaleDependency="Area" sizeType="MM" rotationOffset="270" penColor="#000000" penWidth="0" backgroundAlpha="255">
|
||||
<fontProperties description="Noto Sans,9,-1,5,50,0,0,0,0,0" style=""/>
|
||||
<attribute color="#000000" label="" field=""/>
|
||||
</DiagramCategory>
|
||||
</SingleCategoryDiagramRenderer>
|
||||
<DiagramLayerSettings priority="0" obstacle="0" placement="0" zIndex="0" showAll="1" linePlacementFlags="18" dist="0">
|
||||
<properties>
|
||||
<Option type="Map">
|
||||
<Option value="" name="name" type="QString"/>
|
||||
<Option name="properties"/>
|
||||
<Option value="collection" name="type" type="QString"/>
|
||||
</Option>
|
||||
</properties>
|
||||
</DiagramLayerSettings>
|
||||
<geometryOptions geometryPrecision="0" removeDuplicateNodes="0">
|
||||
<activeChecks/>
|
||||
<checkConfiguration/>
|
||||
</geometryOptions>
|
||||
<fieldConfiguration>
|
||||
<field name="fid">
|
||||
<editWidget type="TextEdit">
|
||||
<config>
|
||||
<Option/>
|
||||
</config>
|
||||
</editWidget>
|
||||
</field>
|
||||
<field name="name">
|
||||
<editWidget type="TextEdit">
|
||||
<config>
|
||||
<Option/>
|
||||
</config>
|
||||
</editWidget>
|
||||
</field>
|
||||
</fieldConfiguration>
|
||||
<aliases>
|
||||
<alias index="0" name="" field="fid"/>
|
||||
<alias index="1" name="" field="name"/>
|
||||
</aliases>
|
||||
<excludeAttributesWMS/>
|
||||
<excludeAttributesWFS/>
|
||||
<defaults>
|
||||
<default applyOnUpdate="0" expression="" field="fid"/>
|
||||
<default applyOnUpdate="0" expression="" field="name"/>
|
||||
</defaults>
|
||||
<constraints>
|
||||
<constraint constraints="3" exp_strength="0" unique_strength="1" notnull_strength="1" field="fid"/>
|
||||
<constraint constraints="0" exp_strength="0" unique_strength="0" notnull_strength="0" field="name"/>
|
||||
</constraints>
|
||||
<constraintExpressions>
|
||||
<constraint exp="" field="fid" desc=""/>
|
||||
<constraint exp="" field="name" desc=""/>
|
||||
</constraintExpressions>
|
||||
<expressionfields/>
|
||||
<attributeactions>
|
||||
<defaultAction value="{00000000-0000-0000-0000-000000000000}" key="Canvas"/>
|
||||
</attributeactions>
|
||||
<attributetableconfig actionWidgetStyle="dropDown" sortExpression="" sortOrder="0">
|
||||
<columns>
|
||||
<column width="-1" name="fid" type="field" hidden="0"/>
|
||||
<column width="-1" name="name" type="field" hidden="0"/>
|
||||
<column width="-1" type="actions" hidden="1"/>
|
||||
</columns>
|
||||
</attributetableconfig>
|
||||
<conditionalstyles>
|
||||
<rowstyles/>
|
||||
<fieldstyles/>
|
||||
</conditionalstyles>
|
||||
<editform tolerant="1"></editform>
|
||||
<editforminit/>
|
||||
<editforminitcodesource>0</editforminitcodesource>
|
||||
<editforminitfilepath></editforminitfilepath>
|
||||
<editforminitcode><![CDATA[# -*- coding: utf-8 -*-
|
||||
"""
|
||||
QGIS forms can have a Python function that is called when the form is
|
||||
opened.
|
||||
|
||||
Use this function to add extra logic to your forms.
|
||||
|
||||
Enter the name of the function in the "Python Init function"
|
||||
field.
|
||||
An example follows:
|
||||
"""
|
||||
from qgis.PyQt.QtWidgets import QWidget
|
||||
|
||||
def my_form_open(dialog, layer, feature):
|
||||
geom = feature.geometry()
|
||||
control = dialog.findChild(QWidget, "MyLineEdit")
|
||||
]]></editforminitcode>
|
||||
<featformsuppress>0</featformsuppress>
|
||||
<editorlayout>generatedlayout</editorlayout>
|
||||
<editable>
|
||||
<field name="fid" editable="1"/>
|
||||
<field name="name" editable="1"/>
|
||||
</editable>
|
||||
<labelOnTop>
|
||||
<field labelOnTop="0" name="fid"/>
|
||||
<field labelOnTop="0" name="name"/>
|
||||
</labelOnTop>
|
||||
<widgets>
|
||||
<widget name="point_a_e9_point_b_ref_point_b_d2_fid">
|
||||
<config type="Map">
|
||||
<Option value="" name="nm-rel" type="QString"/>
|
||||
</config>
|
||||
</widget>
|
||||
</widgets>
|
||||
<previewExpression>fid</previewExpression>
|
||||
<mapTip></mapTip>
|
||||
</maplayer>
|
||||
</projectlayers>
|
||||
<layerorder>
|
||||
<layer id="point_a_e99cf1b1_e13e_44a8_b912_58505e7ac967"/>
|
||||
<layer id="point_b_d23a7df9_c9d6_4b48_9162_5fc1a7db2b96"/>
|
||||
<layer id="bad_layer_raster_test_18978e96_6781_4a5d_b0bc_474994ed231a"/>
|
||||
</layerorder>
|
||||
<properties>
|
||||
<Macros>
|
||||
<pythonCode type="QString"></pythonCode>
|
||||
</Macros>
|
||||
<WFSTLayers>
|
||||
<Delete type="QStringList"/>
|
||||
<Insert type="QStringList"/>
|
||||
<Update type="QStringList"/>
|
||||
</WFSTLayers>
|
||||
<WMTSMinScale type="int">5000</WMTSMinScale>
|
||||
<WMSAddWktGeometry type="bool">false</WMSAddWktGeometry>
|
||||
<Legend>
|
||||
<filterByMap type="bool">false</filterByMap>
|
||||
</Legend>
|
||||
<WFSLayers type="QStringList"/>
|
||||
<WMSPrecision type="QString">8</WMSPrecision>
|
||||
<WMTSUrl type="QString"></WMTSUrl>
|
||||
<WMSFees type="QString">conditions unknown</WMSFees>
|
||||
<PositionPrecision>
|
||||
<Automatic type="bool">true</Automatic>
|
||||
<DecimalPlaces type="int">2</DecimalPlaces>
|
||||
<DegreeFormat type="QString">MU</DegreeFormat>
|
||||
</PositionPrecision>
|
||||
<WMSImageQuality type="int">90</WMSImageQuality>
|
||||
<Measure>
|
||||
<Ellipsoid type="QString">WGS84</Ellipsoid>
|
||||
</Measure>
|
||||
<SpatialRefSys>
|
||||
<ProjectionsEnabled type="int">1</ProjectionsEnabled>
|
||||
</SpatialRefSys>
|
||||
<WMTSPngLayers>
|
||||
<Layer type="QStringList"/>
|
||||
<Project type="bool">false</Project>
|
||||
<Group type="QStringList"/>
|
||||
</WMTSPngLayers>
|
||||
<WMSAccessConstraints type="QString">None</WMSAccessConstraints>
|
||||
<WMSSegmentizeFeatureInfoGeometry type="bool">false</WMSSegmentizeFeatureInfoGeometry>
|
||||
<WMSRequestDefinedDataSources type="bool">false</WMSRequestDefinedDataSources>
|
||||
<WMSServiceCapabilities type="bool">false</WMSServiceCapabilities>
|
||||
<WMSUrl type="QString"></WMSUrl>
|
||||
<WCSLayers type="QStringList"/>
|
||||
<WMSContactPerson type="QString"></WMSContactPerson>
|
||||
<WMSContactOrganization type="QString"></WMSContactOrganization>
|
||||
<Identify>
|
||||
<disabledLayers type="QStringList"/>
|
||||
</Identify>
|
||||
<DefaultStyles>
|
||||
<Fill type="QString"></Fill>
|
||||
<Line type="QString"></Line>
|
||||
<Opacity type="double">1</Opacity>
|
||||
<RandomColors type="bool">true</RandomColors>
|
||||
<Marker type="QString"></Marker>
|
||||
<ColorRamp type="QString"></ColorRamp>
|
||||
</DefaultStyles>
|
||||
<WMSKeywordList type="QStringList">
|
||||
<value></value>
|
||||
</WMSKeywordList>
|
||||
<WFSUrl type="QString"></WFSUrl>
|
||||
<WMTSJpegLayers>
|
||||
<Layer type="QStringList"/>
|
||||
<Project type="bool">false</Project>
|
||||
<Group type="QStringList"/>
|
||||
</WMTSJpegLayers>
|
||||
<Paths>
|
||||
<Absolute type="bool">false</Absolute>
|
||||
</Paths>
|
||||
<WMSServiceAbstract type="QString"></WMSServiceAbstract>
|
||||
<WMSUseLayerIDs type="bool">false</WMSUseLayerIDs>
|
||||
<WMSServiceTitle type="QString"></WMSServiceTitle>
|
||||
<PAL>
|
||||
<DrawOutlineLabels type="bool">true</DrawOutlineLabels>
|
||||
<CandidatesPolygon type="int">30</CandidatesPolygon>
|
||||
<ShowingPartialsLabels type="bool">true</ShowingPartialsLabels>
|
||||
<CandidatesLine type="int">50</CandidatesLine>
|
||||
<SearchMethod type="int">0</SearchMethod>
|
||||
<CandidatesPoint type="int">16</CandidatesPoint>
|
||||
<ShowingCandidates type="bool">false</ShowingCandidates>
|
||||
<ShowingAllLabels type="bool">false</ShowingAllLabels>
|
||||
<DrawRectOnly type="bool">false</DrawRectOnly>
|
||||
</PAL>
|
||||
<Measurement>
|
||||
<AreaUnits type="QString">m2</AreaUnits>
|
||||
<DistanceUnits type="QString">meters</DistanceUnits>
|
||||
</Measurement>
|
||||
<WMSOnlineResource type="QString"></WMSOnlineResource>
|
||||
<WCSUrl type="QString"></WCSUrl>
|
||||
<WMTSLayers>
|
||||
<Layer type="QStringList"/>
|
||||
<Project type="bool">false</Project>
|
||||
<Group type="QStringList"/>
|
||||
</WMTSLayers>
|
||||
<WMSContactPhone type="QString"></WMSContactPhone>
|
||||
<RequiredLayers>
|
||||
<Layers type="QStringList"/>
|
||||
</RequiredLayers>
|
||||
<Variables>
|
||||
<variableNames type="QStringList">
|
||||
<value>qgisce_catalog_autoload</value>
|
||||
<value>qgisce_template_version</value>
|
||||
</variableNames>
|
||||
<variableValues type="QStringList">
|
||||
<value>true</value>
|
||||
<value>1.0</value>
|
||||
</variableValues>
|
||||
</Variables>
|
||||
<WMSContactMail type="QString"></WMSContactMail>
|
||||
<Gui>
|
||||
<CanvasColorBluePart type="int">255</CanvasColorBluePart>
|
||||
<SelectionColorAlphaPart type="int">255</SelectionColorAlphaPart>
|
||||
<SelectionColorRedPart type="int">255</SelectionColorRedPart>
|
||||
<CanvasColorGreenPart type="int">255</CanvasColorGreenPart>
|
||||
<SelectionColorBluePart type="int">0</SelectionColorBluePart>
|
||||
<SelectionColorGreenPart type="int">255</SelectionColorGreenPart>
|
||||
<CanvasColorRedPart type="int">255</CanvasColorRedPart>
|
||||
</Gui>
|
||||
<WMSContactPosition type="QString"></WMSContactPosition>
|
||||
</properties>
|
||||
<visibility-presets/>
|
||||
<transformContext/>
|
||||
<projectMetadata>
|
||||
<identifier></identifier>
|
||||
<parentidentifier></parentidentifier>
|
||||
<language></language>
|
||||
<type></type>
|
||||
<title></title>
|
||||
<abstract></abstract>
|
||||
<contact>
|
||||
<name></name>
|
||||
<organization></organization>
|
||||
<position></position>
|
||||
<voice></voice>
|
||||
<fax></fax>
|
||||
<email></email>
|
||||
<role></role>
|
||||
</contact>
|
||||
<links/>
|
||||
<author>Alessandro Pasotti</author>
|
||||
<creation>2018-07-06T13:56:35</creation>
|
||||
</projectMetadata>
|
||||
<Annotations/>
|
||||
<Layouts/>
|
||||
</qgis>
|
BIN
tests/testdata/projects/relation_reference_test.gpkg
vendored
Normal file
BIN
tests/testdata/projects/relation_reference_test.gpkg
vendored
Normal file
Binary file not shown.
710
tests/testdata/projects/relation_reference_test.qgs
vendored
Normal file
710
tests/testdata/projects/relation_reference_test.qgs
vendored
Normal file
@ -0,0 +1,710 @@
|
||||
<!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM'>
|
||||
<qgis projectname="" version="3.5.0-Master">
|
||||
<homePath path=""/>
|
||||
<title></title>
|
||||
<autotransaction active="0"/>
|
||||
<evaluateDefaultValues active="0"/>
|
||||
<trust active="0"/>
|
||||
<projectCrs>
|
||||
<spatialrefsys>
|
||||
<proj4>+proj=utm +zone=30 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs</proj4>
|
||||
<srsid>2103</srsid>
|
||||
<srid>25830</srid>
|
||||
<authid>EPSG:25830</authid>
|
||||
<description>ETRS89 / UTM zone 30N</description>
|
||||
<projectionacronym>utm</projectionacronym>
|
||||
<ellipsoidacronym>GRS80</ellipsoidacronym>
|
||||
<geographicflag>false</geographicflag>
|
||||
</spatialrefsys>
|
||||
</projectCrs>
|
||||
<layer-tree-group>
|
||||
<customproperties/>
|
||||
<layer-tree-layer providerKey="ogr" checked="Qt::Checked" name="point_b" source="./relation_reference_test.gpkg|layername=point_b" expanded="1" id="point_b_d23a7df9_c9d6_4b48_9162_5fc1a7db2b96">
|
||||
<customproperties/>
|
||||
</layer-tree-layer>
|
||||
<layer-tree-layer providerKey="ogr" checked="Qt::Checked" name="point_a" source="./relation_reference_test.gpkg|layername=point_a" expanded="1" id="point_a_e99cf1b1_e13e_44a8_b912_58505e7ac967">
|
||||
<customproperties/>
|
||||
</layer-tree-layer>
|
||||
<custom-order enabled="0">
|
||||
<item>point_a_e99cf1b1_e13e_44a8_b912_58505e7ac967</item>
|
||||
<item>point_b_d23a7df9_c9d6_4b48_9162_5fc1a7db2b96</item>
|
||||
</custom-order>
|
||||
</layer-tree-group>
|
||||
<snapping-settings unit="1" enabled="0" type="1" tolerance="12" mode="2" intersection-snapping="0">
|
||||
<individual-layer-settings>
|
||||
<layer-setting enabled="0" type="1" tolerance="12" id="point_b_d23a7df9_c9d6_4b48_9162_5fc1a7db2b96" units="1"/>
|
||||
<layer-setting enabled="0" type="1" tolerance="12" id="point_a_e99cf1b1_e13e_44a8_b912_58505e7ac967" units="1"/>
|
||||
</individual-layer-settings>
|
||||
</snapping-settings>
|
||||
<relations>
|
||||
<relation strength="Association" referencingLayer="point_a_e99cf1b1_e13e_44a8_b912_58505e7ac967" referencedLayer="point_b_d23a7df9_c9d6_4b48_9162_5fc1a7db2b96" name="point a to b" id="point_a_e9_point_b_ref_point_b_d2_fid">
|
||||
<fieldRef referencingField="point_b_ref" referencedField="fid"/>
|
||||
</relation>
|
||||
</relations>
|
||||
<mapcanvas annotationsVisible="1" name="theMapCanvas">
|
||||
<units>meters</units>
|
||||
<extent>
|
||||
<xmin>982072.13989259675145149</xmin>
|
||||
<ymin>4664077.95563993975520134</ymin>
|
||||
<xmax>982298.28138825763016939</xmax>
|
||||
<ymax>4664173.45214581862092018</ymax>
|
||||
</extent>
|
||||
<rotation>0</rotation>
|
||||
<destinationsrs>
|
||||
<spatialrefsys>
|
||||
<proj4>+proj=utm +zone=30 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs</proj4>
|
||||
<srsid>2103</srsid>
|
||||
<srid>25830</srid>
|
||||
<authid>EPSG:25830</authid>
|
||||
<description>ETRS89 / UTM zone 30N</description>
|
||||
<projectionacronym>utm</projectionacronym>
|
||||
<ellipsoidacronym>GRS80</ellipsoidacronym>
|
||||
<geographicflag>false</geographicflag>
|
||||
</spatialrefsys>
|
||||
</destinationsrs>
|
||||
<rendermaptile>0</rendermaptile>
|
||||
</mapcanvas>
|
||||
<projectModels/>
|
||||
<legend updateDrawingOrder="true">
|
||||
<legendlayer showFeatureCount="0" checked="Qt::Checked" name="point_b" drawingOrder="-1" open="true">
|
||||
<filegroup hidden="false" open="true">
|
||||
<legendlayerfile visible="1" layerid="point_b_d23a7df9_c9d6_4b48_9162_5fc1a7db2b96" isInOverview="0"/>
|
||||
</filegroup>
|
||||
</legendlayer>
|
||||
<legendlayer showFeatureCount="0" checked="Qt::Checked" name="point_a" drawingOrder="-1" open="true">
|
||||
<filegroup hidden="false" open="true">
|
||||
<legendlayerfile visible="1" layerid="point_a_e99cf1b1_e13e_44a8_b912_58505e7ac967" isInOverview="0"/>
|
||||
</filegroup>
|
||||
</legendlayer>
|
||||
</legend>
|
||||
<mapViewDocks/>
|
||||
<mapViewDocks3D/>
|
||||
<projectlayers>
|
||||
<maplayer autoRefreshTime="0" type="vector" geometry="Point" styleCategories="AllStyleCategories" minScale="1e+8" readOnly="0" simplifyDrawingHints="0" refreshOnNotifyMessage="" labelsEnabled="0" simplifyMaxScale="1" refreshOnNotifyEnabled="0" autoRefreshEnabled="0" simplifyAlgorithm="0" hasScaleBasedVisibilityFlag="0" maxScale="0" simplifyDrawingTol="1" simplifyLocal="1">
|
||||
<extent>
|
||||
<xmin>2.81884431838989258</xmin>
|
||||
<ymin>41.9814453125</ymin>
|
||||
<xmax>2.81894969940185547</xmax>
|
||||
<ymax>41.98154067993164063</ymax>
|
||||
</extent>
|
||||
<id>point_a_e99cf1b1_e13e_44a8_b912_58505e7ac967</id>
|
||||
<datasource>./relation_reference_test.gpkg|layername=point_a</datasource>
|
||||
<keywordList>
|
||||
<value></value>
|
||||
</keywordList>
|
||||
<layername>point_a</layername>
|
||||
<srs>
|
||||
<spatialrefsys>
|
||||
<proj4>+proj=longlat +datum=WGS84 +no_defs</proj4>
|
||||
<srsid>3452</srsid>
|
||||
<srid>4326</srid>
|
||||
<authid>EPSG:4326</authid>
|
||||
<description>WGS 84</description>
|
||||
<projectionacronym>longlat</projectionacronym>
|
||||
<ellipsoidacronym>WGS84</ellipsoidacronym>
|
||||
<geographicflag>true</geographicflag>
|
||||
</spatialrefsys>
|
||||
</srs>
|
||||
<resourceMetadata>
|
||||
<identifier></identifier>
|
||||
<parentidentifier></parentidentifier>
|
||||
<language></language>
|
||||
<type></type>
|
||||
<title></title>
|
||||
<abstract></abstract>
|
||||
<contact>
|
||||
<name></name>
|
||||
<organization></organization>
|
||||
<position></position>
|
||||
<voice></voice>
|
||||
<fax></fax>
|
||||
<email></email>
|
||||
<role></role>
|
||||
</contact>
|
||||
<links/>
|
||||
<fees></fees>
|
||||
<encoding></encoding>
|
||||
<crs>
|
||||
<spatialrefsys>
|
||||
<proj4></proj4>
|
||||
<srsid>0</srsid>
|
||||
<srid>0</srid>
|
||||
<authid></authid>
|
||||
<description></description>
|
||||
<projectionacronym></projectionacronym>
|
||||
<ellipsoidacronym></ellipsoidacronym>
|
||||
<geographicflag>false</geographicflag>
|
||||
</spatialrefsys>
|
||||
</crs>
|
||||
<extent>
|
||||
<spatial miny="0" maxz="0" crs="" maxy="0" dimensions="2" maxx="0" minz="0" minx="0"/>
|
||||
<temporal>
|
||||
<period>
|
||||
<start></start>
|
||||
<end></end>
|
||||
</period>
|
||||
</temporal>
|
||||
</extent>
|
||||
</resourceMetadata>
|
||||
<provider encoding="UTF-8">ogr</provider>
|
||||
<vectorjoins/>
|
||||
<layerDependencies/>
|
||||
<dataDependencies/>
|
||||
<legend type="default-vector"/>
|
||||
<expressionfields/>
|
||||
<map-layer-style-manager current="default">
|
||||
<map-layer-style name="default"/>
|
||||
</map-layer-style-manager>
|
||||
<auxiliaryLayer/>
|
||||
<flags>
|
||||
<Identifiable>1</Identifiable>
|
||||
<Removable>1</Removable>
|
||||
<Searchable>1</Searchable>
|
||||
</flags>
|
||||
<renderer-v2 forceraster="0" enableorderby="0" symbollevels="0" type="singleSymbol">
|
||||
<symbols>
|
||||
<symbol alpha="1" type="marker" name="0" clip_to_extent="1">
|
||||
<layer pass="0" enabled="1" locked="0" class="SimpleMarker">
|
||||
<prop k="angle" v="0"/>
|
||||
<prop k="color" v="145,82,45,255"/>
|
||||
<prop k="horizontal_anchor_point" v="1"/>
|
||||
<prop k="joinstyle" v="bevel"/>
|
||||
<prop k="name" v="circle"/>
|
||||
<prop k="offset" v="0,0"/>
|
||||
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="offset_unit" v="MM"/>
|
||||
<prop k="outline_color" v="35,35,35,255"/>
|
||||
<prop k="outline_style" v="solid"/>
|
||||
<prop k="outline_width" v="0"/>
|
||||
<prop k="outline_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="outline_width_unit" v="MM"/>
|
||||
<prop k="scale_method" v="diameter"/>
|
||||
<prop k="size" v="2"/>
|
||||
<prop k="size_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="size_unit" v="MM"/>
|
||||
<prop k="vertical_anchor_point" v="1"/>
|
||||
<data_defined_properties>
|
||||
<Option type="Map">
|
||||
<Option type="QString" name="name" value=""/>
|
||||
<Option name="properties"/>
|
||||
<Option type="QString" name="type" value="collection"/>
|
||||
</Option>
|
||||
</data_defined_properties>
|
||||
</layer>
|
||||
</symbol>
|
||||
</symbols>
|
||||
<rotation/>
|
||||
<sizescale/>
|
||||
</renderer-v2>
|
||||
<customproperties>
|
||||
<property key="embeddedWidgets/count" value="0"/>
|
||||
<property key="variableNames"/>
|
||||
<property key="variableValues"/>
|
||||
</customproperties>
|
||||
<blendMode>0</blendMode>
|
||||
<featureBlendMode>0</featureBlendMode>
|
||||
<layerOpacity>1</layerOpacity>
|
||||
<SingleCategoryDiagramRenderer diagramType="Histogram" attributeLegend="1">
|
||||
<DiagramCategory backgroundColor="#ffffff" scaleBasedVisibility="0" sizeType="MM" width="15" maxScaleDenominator="1e+8" diagramOrientation="Up" backgroundAlpha="255" enabled="0" penAlpha="255" barWidth="5" lineSizeType="MM" height="15" penWidth="0" labelPlacementMethod="XHeight" minScaleDenominator="0" rotationOffset="270" penColor="#000000" lineSizeScale="3x:0,0,0,0,0,0" opacity="1" minimumSize="0" scaleDependency="Area" sizeScale="3x:0,0,0,0,0,0">
|
||||
<fontProperties description="Noto Sans,9,-1,5,50,0,0,0,0,0" style=""/>
|
||||
</DiagramCategory>
|
||||
</SingleCategoryDiagramRenderer>
|
||||
<DiagramLayerSettings linePlacementFlags="18" showAll="1" priority="0" obstacle="0" zIndex="0" dist="0" placement="0">
|
||||
<properties>
|
||||
<Option type="Map">
|
||||
<Option type="QString" name="name" value=""/>
|
||||
<Option name="properties"/>
|
||||
<Option type="QString" name="type" value="collection"/>
|
||||
</Option>
|
||||
</properties>
|
||||
</DiagramLayerSettings>
|
||||
<geometryOptions geometryPrecision="0" removeDuplicateNodes="0">
|
||||
<activeChecks/>
|
||||
<checkConfiguration/>
|
||||
</geometryOptions>
|
||||
<fieldConfiguration>
|
||||
<field name="fid">
|
||||
<editWidget type="TextEdit">
|
||||
<config>
|
||||
<Option/>
|
||||
</config>
|
||||
</editWidget>
|
||||
</field>
|
||||
<field name="name">
|
||||
<editWidget type="TextEdit">
|
||||
<config>
|
||||
<Option/>
|
||||
</config>
|
||||
</editWidget>
|
||||
</field>
|
||||
<field name="point_b_ref">
|
||||
<editWidget type="RelationReference">
|
||||
<config>
|
||||
<Option type="Map">
|
||||
<Option type="bool" name="AllowAddFeatures" value="false"/>
|
||||
<Option type="bool" name="AllowNULL" value="false"/>
|
||||
<Option type="bool" name="MapIdentification" value="false"/>
|
||||
<Option type="bool" name="OrderByValue" value="false"/>
|
||||
<Option type="bool" name="ReadOnly" value="false"/>
|
||||
<Option type="QString" name="Relation" value="point_a_e9_point_b_ref_point_b_d2_fid"/>
|
||||
<Option type="bool" name="ShowForm" value="false"/>
|
||||
<Option type="bool" name="ShowOpenFormButton" value="true"/>
|
||||
</Option>
|
||||
</config>
|
||||
</editWidget>
|
||||
</field>
|
||||
</fieldConfiguration>
|
||||
<aliases>
|
||||
<alias name="" index="0" field="fid"/>
|
||||
<alias name="" index="1" field="name"/>
|
||||
<alias name="" index="2" field="point_b_ref"/>
|
||||
</aliases>
|
||||
<excludeAttributesWMS/>
|
||||
<excludeAttributesWFS/>
|
||||
<defaults>
|
||||
<default expression="" applyOnUpdate="0" field="fid"/>
|
||||
<default expression="" applyOnUpdate="0" field="name"/>
|
||||
<default expression="" applyOnUpdate="0" field="point_b_ref"/>
|
||||
</defaults>
|
||||
<constraints>
|
||||
<constraint exp_strength="0" notnull_strength="1" field="fid" unique_strength="1" constraints="3"/>
|
||||
<constraint exp_strength="0" notnull_strength="0" field="name" unique_strength="0" constraints="0"/>
|
||||
<constraint exp_strength="0" notnull_strength="0" field="point_b_ref" unique_strength="0" constraints="0"/>
|
||||
</constraints>
|
||||
<constraintExpressions>
|
||||
<constraint exp="" desc="" field="fid"/>
|
||||
<constraint exp="" desc="" field="name"/>
|
||||
<constraint exp="" desc="" field="point_b_ref"/>
|
||||
</constraintExpressions>
|
||||
<expressionfields/>
|
||||
<attributeactions>
|
||||
<defaultAction key="Canvas" value="{00000000-0000-0000-0000-000000000000}"/>
|
||||
</attributeactions>
|
||||
<attributetableconfig sortExpression="" sortOrder="0" actionWidgetStyle="dropDown">
|
||||
<columns>
|
||||
<column type="field" hidden="0" name="fid" width="-1"/>
|
||||
<column type="field" hidden="0" name="name" width="-1"/>
|
||||
<column type="field" hidden="0" name="point_b_ref" width="-1"/>
|
||||
<column type="actions" hidden="1" width="-1"/>
|
||||
</columns>
|
||||
</attributetableconfig>
|
||||
<conditionalstyles>
|
||||
<rowstyles/>
|
||||
<fieldstyles/>
|
||||
</conditionalstyles>
|
||||
<editform tolerant="1"></editform>
|
||||
<editforminit/>
|
||||
<editforminitcodesource>0</editforminitcodesource>
|
||||
<editforminitfilepath></editforminitfilepath>
|
||||
<editforminitcode><![CDATA[# -*- coding: utf-8 -*-
|
||||
"""
|
||||
QGIS forms can have a Python function that is called when the form is
|
||||
opened.
|
||||
|
||||
Use this function to add extra logic to your forms.
|
||||
|
||||
Enter the name of the function in the "Python Init function"
|
||||
field.
|
||||
An example follows:
|
||||
"""
|
||||
from qgis.PyQt.QtWidgets import QWidget
|
||||
|
||||
def my_form_open(dialog, layer, feature):
|
||||
geom = feature.geometry()
|
||||
control = dialog.findChild(QWidget, "MyLineEdit")
|
||||
]]></editforminitcode>
|
||||
<featformsuppress>0</featformsuppress>
|
||||
<editorlayout>generatedlayout</editorlayout>
|
||||
<editable>
|
||||
<field editable="1" name="fid"/>
|
||||
<field editable="1" name="name"/>
|
||||
<field editable="1" name="point_b_ref"/>
|
||||
</editable>
|
||||
<labelOnTop>
|
||||
<field name="fid" labelOnTop="0"/>
|
||||
<field name="name" labelOnTop="0"/>
|
||||
<field name="point_b_ref" labelOnTop="0"/>
|
||||
</labelOnTop>
|
||||
<widgets/>
|
||||
<previewExpression>fid</previewExpression>
|
||||
<mapTip></mapTip>
|
||||
</maplayer>
|
||||
<maplayer autoRefreshTime="0" type="vector" geometry="Point" styleCategories="AllStyleCategories" minScale="1e+8" readOnly="0" simplifyDrawingHints="0" refreshOnNotifyMessage="" labelsEnabled="0" simplifyMaxScale="1" refreshOnNotifyEnabled="0" autoRefreshEnabled="0" simplifyAlgorithm="0" hasScaleBasedVisibilityFlag="0" maxScale="0" simplifyDrawingTol="1" simplifyLocal="1">
|
||||
<extent>
|
||||
<xmin>2.81895381989531746</xmin>
|
||||
<ymin>41.9815272025749664</ymin>
|
||||
<xmax>2.81904954416376663</xmax>
|
||||
<ymax>41.98159776111032926</ymax>
|
||||
</extent>
|
||||
<id>point_b_d23a7df9_c9d6_4b48_9162_5fc1a7db2b96</id>
|
||||
<datasource>./relation_reference_test.gpkg|layername=point_b</datasource>
|
||||
<keywordList>
|
||||
<value></value>
|
||||
</keywordList>
|
||||
<layername>point_b</layername>
|
||||
<srs>
|
||||
<spatialrefsys>
|
||||
<proj4>+proj=longlat +datum=WGS84 +no_defs</proj4>
|
||||
<srsid>3452</srsid>
|
||||
<srid>4326</srid>
|
||||
<authid>EPSG:4326</authid>
|
||||
<description>WGS 84</description>
|
||||
<projectionacronym>longlat</projectionacronym>
|
||||
<ellipsoidacronym>WGS84</ellipsoidacronym>
|
||||
<geographicflag>true</geographicflag>
|
||||
</spatialrefsys>
|
||||
</srs>
|
||||
<resourceMetadata>
|
||||
<identifier></identifier>
|
||||
<parentidentifier></parentidentifier>
|
||||
<language></language>
|
||||
<type></type>
|
||||
<title></title>
|
||||
<abstract></abstract>
|
||||
<contact>
|
||||
<name></name>
|
||||
<organization></organization>
|
||||
<position></position>
|
||||
<voice></voice>
|
||||
<fax></fax>
|
||||
<email></email>
|
||||
<role></role>
|
||||
</contact>
|
||||
<links/>
|
||||
<fees></fees>
|
||||
<encoding></encoding>
|
||||
<crs>
|
||||
<spatialrefsys>
|
||||
<proj4></proj4>
|
||||
<srsid>0</srsid>
|
||||
<srid>0</srid>
|
||||
<authid></authid>
|
||||
<description></description>
|
||||
<projectionacronym></projectionacronym>
|
||||
<ellipsoidacronym></ellipsoidacronym>
|
||||
<geographicflag>false</geographicflag>
|
||||
</spatialrefsys>
|
||||
</crs>
|
||||
<extent>
|
||||
<spatial miny="0" maxz="0" crs="" maxy="0" dimensions="2" maxx="0" minz="0" minx="0"/>
|
||||
<temporal>
|
||||
<period>
|
||||
<start></start>
|
||||
<end></end>
|
||||
</period>
|
||||
</temporal>
|
||||
</extent>
|
||||
</resourceMetadata>
|
||||
<provider encoding="UTF-8">ogr</provider>
|
||||
<vectorjoins/>
|
||||
<layerDependencies/>
|
||||
<dataDependencies/>
|
||||
<legend type="default-vector"/>
|
||||
<expressionfields/>
|
||||
<map-layer-style-manager current="default">
|
||||
<map-layer-style name="default"/>
|
||||
</map-layer-style-manager>
|
||||
<auxiliaryLayer/>
|
||||
<flags>
|
||||
<Identifiable>1</Identifiable>
|
||||
<Removable>1</Removable>
|
||||
<Searchable>1</Searchable>
|
||||
</flags>
|
||||
<renderer-v2 forceraster="0" enableorderby="0" symbollevels="0" type="singleSymbol">
|
||||
<symbols>
|
||||
<symbol alpha="1" type="marker" name="0" clip_to_extent="1">
|
||||
<layer pass="0" enabled="1" locked="0" class="SimpleMarker">
|
||||
<prop k="angle" v="0"/>
|
||||
<prop k="color" v="196,60,57,255"/>
|
||||
<prop k="horizontal_anchor_point" v="1"/>
|
||||
<prop k="joinstyle" v="bevel"/>
|
||||
<prop k="name" v="circle"/>
|
||||
<prop k="offset" v="0,0"/>
|
||||
<prop k="offset_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="offset_unit" v="MM"/>
|
||||
<prop k="outline_color" v="35,35,35,255"/>
|
||||
<prop k="outline_style" v="solid"/>
|
||||
<prop k="outline_width" v="0"/>
|
||||
<prop k="outline_width_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="outline_width_unit" v="MM"/>
|
||||
<prop k="scale_method" v="diameter"/>
|
||||
<prop k="size" v="2"/>
|
||||
<prop k="size_map_unit_scale" v="3x:0,0,0,0,0,0"/>
|
||||
<prop k="size_unit" v="MM"/>
|
||||
<prop k="vertical_anchor_point" v="1"/>
|
||||
<data_defined_properties>
|
||||
<Option type="Map">
|
||||
<Option type="QString" name="name" value=""/>
|
||||
<Option name="properties"/>
|
||||
<Option type="QString" name="type" value="collection"/>
|
||||
</Option>
|
||||
</data_defined_properties>
|
||||
</layer>
|
||||
</symbol>
|
||||
</symbols>
|
||||
<rotation/>
|
||||
<sizescale/>
|
||||
</renderer-v2>
|
||||
<customproperties>
|
||||
<property key="embeddedWidgets/count" value="0"/>
|
||||
<property key="variableNames"/>
|
||||
<property key="variableValues"/>
|
||||
</customproperties>
|
||||
<blendMode>0</blendMode>
|
||||
<featureBlendMode>0</featureBlendMode>
|
||||
<layerOpacity>1</layerOpacity>
|
||||
<SingleCategoryDiagramRenderer diagramType="Histogram" attributeLegend="1">
|
||||
<DiagramCategory backgroundColor="#ffffff" scaleBasedVisibility="0" sizeType="MM" width="15" maxScaleDenominator="1e+8" diagramOrientation="Up" backgroundAlpha="255" enabled="0" penAlpha="255" barWidth="5" lineSizeType="MM" height="15" penWidth="0" labelPlacementMethod="XHeight" minScaleDenominator="0" rotationOffset="270" penColor="#000000" lineSizeScale="3x:0,0,0,0,0,0" opacity="1" minimumSize="0" scaleDependency="Area" sizeScale="3x:0,0,0,0,0,0">
|
||||
<fontProperties description="Noto Sans,9,-1,5,50,0,0,0,0,0" style=""/>
|
||||
</DiagramCategory>
|
||||
</SingleCategoryDiagramRenderer>
|
||||
<DiagramLayerSettings linePlacementFlags="18" showAll="1" priority="0" obstacle="0" zIndex="0" dist="0" placement="0">
|
||||
<properties>
|
||||
<Option type="Map">
|
||||
<Option type="QString" name="name" value=""/>
|
||||
<Option name="properties"/>
|
||||
<Option type="QString" name="type" value="collection"/>
|
||||
</Option>
|
||||
</properties>
|
||||
</DiagramLayerSettings>
|
||||
<geometryOptions geometryPrecision="0" removeDuplicateNodes="0">
|
||||
<activeChecks/>
|
||||
<checkConfiguration/>
|
||||
</geometryOptions>
|
||||
<fieldConfiguration>
|
||||
<field name="fid">
|
||||
<editWidget type="TextEdit">
|
||||
<config>
|
||||
<Option/>
|
||||
</config>
|
||||
</editWidget>
|
||||
</field>
|
||||
<field name="name">
|
||||
<editWidget type="TextEdit">
|
||||
<config>
|
||||
<Option/>
|
||||
</config>
|
||||
</editWidget>
|
||||
</field>
|
||||
</fieldConfiguration>
|
||||
<aliases>
|
||||
<alias name="" index="0" field="fid"/>
|
||||
<alias name="" index="1" field="name"/>
|
||||
</aliases>
|
||||
<excludeAttributesWMS/>
|
||||
<excludeAttributesWFS/>
|
||||
<defaults>
|
||||
<default expression="" applyOnUpdate="0" field="fid"/>
|
||||
<default expression="" applyOnUpdate="0" field="name"/>
|
||||
</defaults>
|
||||
<constraints>
|
||||
<constraint exp_strength="0" notnull_strength="1" field="fid" unique_strength="1" constraints="3"/>
|
||||
<constraint exp_strength="0" notnull_strength="0" field="name" unique_strength="0" constraints="0"/>
|
||||
</constraints>
|
||||
<constraintExpressions>
|
||||
<constraint exp="" desc="" field="fid"/>
|
||||
<constraint exp="" desc="" field="name"/>
|
||||
</constraintExpressions>
|
||||
<expressionfields/>
|
||||
<attributeactions>
|
||||
<defaultAction key="Canvas" value="{00000000-0000-0000-0000-000000000000}"/>
|
||||
</attributeactions>
|
||||
<attributetableconfig sortExpression="" sortOrder="0" actionWidgetStyle="dropDown">
|
||||
<columns>
|
||||
<column type="field" hidden="0" name="fid" width="-1"/>
|
||||
<column type="field" hidden="0" name="name" width="-1"/>
|
||||
<column type="actions" hidden="1" width="-1"/>
|
||||
</columns>
|
||||
</attributetableconfig>
|
||||
<conditionalstyles>
|
||||
<rowstyles/>
|
||||
<fieldstyles/>
|
||||
</conditionalstyles>
|
||||
<editform tolerant="1"></editform>
|
||||
<editforminit/>
|
||||
<editforminitcodesource>0</editforminitcodesource>
|
||||
<editforminitfilepath></editforminitfilepath>
|
||||
<editforminitcode><![CDATA[# -*- coding: utf-8 -*-
|
||||
"""
|
||||
QGIS forms can have a Python function that is called when the form is
|
||||
opened.
|
||||
|
||||
Use this function to add extra logic to your forms.
|
||||
|
||||
Enter the name of the function in the "Python Init function"
|
||||
field.
|
||||
An example follows:
|
||||
"""
|
||||
from qgis.PyQt.QtWidgets import QWidget
|
||||
|
||||
def my_form_open(dialog, layer, feature):
|
||||
geom = feature.geometry()
|
||||
control = dialog.findChild(QWidget, "MyLineEdit")
|
||||
]]></editforminitcode>
|
||||
<featformsuppress>0</featformsuppress>
|
||||
<editorlayout>generatedlayout</editorlayout>
|
||||
<editable>
|
||||
<field editable="1" name="fid"/>
|
||||
<field editable="1" name="name"/>
|
||||
</editable>
|
||||
<labelOnTop>
|
||||
<field name="fid" labelOnTop="0"/>
|
||||
<field name="name" labelOnTop="0"/>
|
||||
</labelOnTop>
|
||||
<widgets>
|
||||
<widget name="point_a_e9_point_b_ref_point_b_d2_fid">
|
||||
<config type="Map">
|
||||
<Option type="QString" name="nm-rel" value=""/>
|
||||
</config>
|
||||
</widget>
|
||||
</widgets>
|
||||
<previewExpression>fid</previewExpression>
|
||||
<mapTip></mapTip>
|
||||
</maplayer>
|
||||
</projectlayers>
|
||||
<layerorder>
|
||||
<layer id="point_a_e99cf1b1_e13e_44a8_b912_58505e7ac967"/>
|
||||
<layer id="point_b_d23a7df9_c9d6_4b48_9162_5fc1a7db2b96"/>
|
||||
</layerorder>
|
||||
<properties>
|
||||
<WMSAddWktGeometry type="bool">false</WMSAddWktGeometry>
|
||||
<WMSAccessConstraints type="QString">None</WMSAccessConstraints>
|
||||
<Macros>
|
||||
<pythonCode type="QString"></pythonCode>
|
||||
</Macros>
|
||||
<WFSLayers type="QStringList"/>
|
||||
<PositionPrecision>
|
||||
<DecimalPlaces type="int">2</DecimalPlaces>
|
||||
<DegreeFormat type="QString">MU</DegreeFormat>
|
||||
<Automatic type="bool">true</Automatic>
|
||||
</PositionPrecision>
|
||||
<WMSContactPhone type="QString"></WMSContactPhone>
|
||||
<WMSRequestDefinedDataSources type="bool">false</WMSRequestDefinedDataSources>
|
||||
<WMTSLayers>
|
||||
<Project type="bool">false</Project>
|
||||
<Group type="QStringList"/>
|
||||
<Layer type="QStringList"/>
|
||||
</WMTSLayers>
|
||||
<Identify>
|
||||
<disabledLayers type="QStringList"/>
|
||||
</Identify>
|
||||
<Measurement>
|
||||
<AreaUnits type="QString">m2</AreaUnits>
|
||||
<DistanceUnits type="QString">meters</DistanceUnits>
|
||||
</Measurement>
|
||||
<WMSImageQuality type="int">90</WMSImageQuality>
|
||||
<WMSServiceCapabilities type="bool">false</WMSServiceCapabilities>
|
||||
<WMTSUrl type="QString"></WMTSUrl>
|
||||
<WMSPrecision type="QString">8</WMSPrecision>
|
||||
<WMTSMinScale type="int">5000</WMTSMinScale>
|
||||
<WMSContactMail type="QString"></WMSContactMail>
|
||||
<RequiredLayers>
|
||||
<Layers type="QStringList"/>
|
||||
</RequiredLayers>
|
||||
<WMSContactPerson type="QString"></WMSContactPerson>
|
||||
<SpatialRefSys>
|
||||
<ProjectionsEnabled type="int">1</ProjectionsEnabled>
|
||||
</SpatialRefSys>
|
||||
<WMSFees type="QString">conditions unknown</WMSFees>
|
||||
<WMSKeywordList type="QStringList">
|
||||
<value></value>
|
||||
</WMSKeywordList>
|
||||
<WMTSPngLayers>
|
||||
<Project type="bool">false</Project>
|
||||
<Group type="QStringList"/>
|
||||
<Layer type="QStringList"/>
|
||||
</WMTSPngLayers>
|
||||
<WMSSegmentizeFeatureInfoGeometry type="bool">false</WMSSegmentizeFeatureInfoGeometry>
|
||||
<Measure>
|
||||
<Ellipsoid type="QString">GRS80</Ellipsoid>
|
||||
</Measure>
|
||||
<WMSOnlineResource type="QString"></WMSOnlineResource>
|
||||
<WMSServiceAbstract type="QString"></WMSServiceAbstract>
|
||||
<WMSUrl type="QString"></WMSUrl>
|
||||
<WFSTLayers>
|
||||
<Delete type="QStringList"/>
|
||||
<Update type="QStringList"/>
|
||||
<Insert type="QStringList"/>
|
||||
</WFSTLayers>
|
||||
<WFSUrl type="QString"></WFSUrl>
|
||||
<WCSLayers type="QStringList"/>
|
||||
<Variables>
|
||||
<variableNames type="QStringList">
|
||||
<value>qgisce_catalog_autoload</value>
|
||||
<value>qgisce_template_version</value>
|
||||
</variableNames>
|
||||
<variableValues type="QStringList">
|
||||
<value>true</value>
|
||||
<value>1.0</value>
|
||||
</variableValues>
|
||||
</Variables>
|
||||
<WMSContactPosition type="QString"></WMSContactPosition>
|
||||
<Legend>
|
||||
<filterByMap type="bool">false</filterByMap>
|
||||
</Legend>
|
||||
<WMSUseLayerIDs type="bool">false</WMSUseLayerIDs>
|
||||
<WMSServiceTitle type="QString"></WMSServiceTitle>
|
||||
<Gui>
|
||||
<CanvasColorBluePart type="int">255</CanvasColorBluePart>
|
||||
<SelectionColorAlphaPart type="int">255</SelectionColorAlphaPart>
|
||||
<CanvasColorRedPart type="int">255</CanvasColorRedPart>
|
||||
<SelectionColorRedPart type="int">255</SelectionColorRedPart>
|
||||
<SelectionColorBluePart type="int">0</SelectionColorBluePart>
|
||||
<CanvasColorGreenPart type="int">255</CanvasColorGreenPart>
|
||||
<SelectionColorGreenPart type="int">255</SelectionColorGreenPart>
|
||||
</Gui>
|
||||
<PAL>
|
||||
<SearchMethod type="int">0</SearchMethod>
|
||||
<CandidatesPoint type="int">16</CandidatesPoint>
|
||||
<ShowingCandidates type="bool">false</ShowingCandidates>
|
||||
<ShowingAllLabels type="bool">false</ShowingAllLabels>
|
||||
<ShowingPartialsLabels type="bool">true</ShowingPartialsLabels>
|
||||
<CandidatesPolygon type="int">30</CandidatesPolygon>
|
||||
<CandidatesLine type="int">50</CandidatesLine>
|
||||
<DrawRectOnly type="bool">false</DrawRectOnly>
|
||||
<DrawOutlineLabels type="bool">true</DrawOutlineLabels>
|
||||
</PAL>
|
||||
<DefaultStyles>
|
||||
<Marker type="QString"></Marker>
|
||||
<RandomColors type="bool">true</RandomColors>
|
||||
<Line type="QString"></Line>
|
||||
<Opacity type="double">1</Opacity>
|
||||
<ColorRamp type="QString"></ColorRamp>
|
||||
<Fill type="QString"></Fill>
|
||||
</DefaultStyles>
|
||||
<Paths>
|
||||
<Absolute type="bool">false</Absolute>
|
||||
</Paths>
|
||||
<WMSContactOrganization type="QString"></WMSContactOrganization>
|
||||
<WMTSJpegLayers>
|
||||
<Project type="bool">false</Project>
|
||||
<Group type="QStringList"/>
|
||||
<Layer type="QStringList"/>
|
||||
</WMTSJpegLayers>
|
||||
<WCSUrl type="QString"></WCSUrl>
|
||||
</properties>
|
||||
<visibility-presets/>
|
||||
<transformContext/>
|
||||
<projectMetadata>
|
||||
<identifier></identifier>
|
||||
<parentidentifier></parentidentifier>
|
||||
<language></language>
|
||||
<type></type>
|
||||
<title></title>
|
||||
<abstract></abstract>
|
||||
<contact>
|
||||
<name></name>
|
||||
<organization></organization>
|
||||
<position></position>
|
||||
<voice></voice>
|
||||
<fax></fax>
|
||||
<email></email>
|
||||
<role></role>
|
||||
</contact>
|
||||
<links/>
|
||||
<author>Alessandro Pasotti</author>
|
||||
<creation>2018-07-06T13:56:35</creation>
|
||||
</projectMetadata>
|
||||
<Annotations/>
|
||||
<Layouts/>
|
||||
</qgis>
|
Loading…
x
Reference in New Issue
Block a user