mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-13 00:03:09 -04:00
Followup 0548f4, fixes to layer metadata and metadata widget
Address outstanding review requests so that this PR can be merged
This commit is contained in:
parent
0548f4267e
commit
3d4f6f82bb
@ -223,6 +223,8 @@ will be performed on the x/y extent of the box only.
|
||||
Converts the box to a 2D rectangle.
|
||||
%End
|
||||
|
||||
bool operator==( const QgsBox3d &other ) const;
|
||||
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
|
@ -50,6 +50,8 @@ using QgsNativeMetadataValidator.
|
||||
QgsCoordinateReferenceSystem extentCrs;
|
||||
|
||||
QgsBox3d bounds;
|
||||
|
||||
bool operator==( const QgsLayerMetadata::SpatialExtent &other ) const;
|
||||
};
|
||||
|
||||
struct Extent
|
||||
@ -87,6 +89,8 @@ Sets the temporal ``extents`` of the resource.
|
||||
.. seealso:: :py:func:`temporalExtents`
|
||||
%End
|
||||
|
||||
bool operator==( const Extent &other ) const;
|
||||
|
||||
|
||||
};
|
||||
|
||||
@ -101,6 +105,9 @@ Constructor for Constraint.
|
||||
QString type;
|
||||
|
||||
QString constraint;
|
||||
|
||||
bool operator==( const QgsLayerMetadata::Constraint &other ) const;
|
||||
|
||||
};
|
||||
|
||||
typedef QList< QgsLayerMetadata::Constraint > ConstraintList;
|
||||
@ -125,6 +132,8 @@ Constructor for Address.
|
||||
QString postalCode;
|
||||
|
||||
QString country;
|
||||
|
||||
bool operator==( const QgsLayerMetadata::Address &other ) const;
|
||||
};
|
||||
|
||||
struct Contact
|
||||
@ -150,6 +159,8 @@ Constructor for Contact.
|
||||
QString email;
|
||||
|
||||
QString role;
|
||||
|
||||
bool operator==( const QgsLayerMetadata::Contact &other ) const;
|
||||
};
|
||||
|
||||
typedef QList< QgsLayerMetadata::Contact > ContactList;
|
||||
@ -176,6 +187,8 @@ Constructor for Link.
|
||||
QString mimeType;
|
||||
|
||||
QString size;
|
||||
|
||||
bool operator==( const QgsLayerMetadata::Link &other ) const;
|
||||
};
|
||||
|
||||
typedef QList< QgsLayerMetadata::Link > LinkList;
|
||||
@ -618,6 +631,7 @@ Stores state in Dom node
|
||||
:return: true if successful
|
||||
%End
|
||||
|
||||
bool operator==( const QgsLayerMetadata &metadataOther ) const;
|
||||
|
||||
};
|
||||
|
||||
|
@ -364,19 +364,21 @@ The default implementation does nothing.
|
||||
|
||||
virtual QgsLayerMetadata layerMetadata() const;
|
||||
%Docstring
|
||||
Retrieve collected Metadata from the Provider source
|
||||
A structured metadata store for a map layer.
|
||||
\note
|
||||
Returns layer metadata collected from the provider's source.
|
||||
|
||||
.. seealso:: :py:func:`setLayerMetadata`
|
||||
Individual data providers must implement this method if they support collecting metadata.
|
||||
|
||||
.. seealso:: :py:func:`writeLayerMetadata`
|
||||
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
virtual bool setLayerMetadata( const QgsLayerMetadata &layerMetadata );
|
||||
|
||||
virtual bool writeLayerMetadata( const QgsLayerMetadata &metadata );
|
||||
%Docstring
|
||||
Set collected Metadata from the Provider source
|
||||
A structured metadata store for a map layer.
|
||||
\note
|
||||
Writes layer ``metadata`` to the underlying provider source. Support depends
|
||||
on individual provider capabilities.
|
||||
|
||||
Returns true if metadata was successfully written to the data provider.
|
||||
|
||||
.. seealso:: :py:func:`layerMetadata`
|
||||
|
||||
|
@ -243,6 +243,8 @@ Returns true if this range contains a specified ``element``.
|
||||
Returns true if this range overlaps another range.
|
||||
%End
|
||||
|
||||
bool operator==( const QgsTemporalRange<T> &other ) const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -48,6 +48,8 @@ of feature and attribute information from a spatial datasource.
|
||||
ChangeFeatures,
|
||||
RenameAttributes,
|
||||
FastTruncate,
|
||||
ReadLayerMetadata,
|
||||
WriteLayerMetadata,
|
||||
};
|
||||
|
||||
typedef QFlags<QgsVectorDataProvider::Capability> Capabilities;
|
||||
|
@ -69,6 +69,17 @@ Base class for raster data providers.
|
||||
#include "qgsrasterdataprovider.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
enum ProviderCapability
|
||||
{
|
||||
NoProviderCapabilities,
|
||||
ReadLayerMetadata,
|
||||
WriteLayerMetadata,
|
||||
};
|
||||
|
||||
typedef QFlags<QgsRasterDataProvider::ProviderCapability> ProviderCapabilities;
|
||||
|
||||
|
||||
QgsRasterDataProvider();
|
||||
|
||||
QgsRasterDataProvider( const QString &uri );
|
||||
@ -76,6 +87,13 @@ Base class for raster data providers.
|
||||
virtual QgsRasterInterface *clone() const = 0;
|
||||
|
||||
|
||||
virtual QgsRasterDataProvider::ProviderCapabilities providerCapabilities() const;
|
||||
%Docstring
|
||||
Returns flags containing the supported capabilities of the data provider.
|
||||
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
virtual bool setInput( QgsRasterInterface *input );
|
||||
%Docstring
|
||||
It makes no sense to set input on provider */
|
||||
@ -425,6 +443,9 @@ Copy member variables from other raster data provider. Useful for implementation
|
||||
|
||||
};
|
||||
|
||||
QFlags<QgsRasterDataProvider::ProviderCapability> operator|(QgsRasterDataProvider::ProviderCapability f1, QFlags<QgsRasterDataProvider::ProviderCapability> f2);
|
||||
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
|
@ -26,30 +26,26 @@ class QgsMetadataWidget : QWidget
|
||||
QgsMetadataWidget( QWidget *parent, QgsMapLayer *layer = 0 );
|
||||
%Docstring
|
||||
Constructor for the wizard.
|
||||
\note
|
||||
For use with a source \layer. This constructor automatically sets the widget's metadata() if the ``layer`` pointer is valid.
|
||||
calls setMetadata, using mMetadata
|
||||
|
||||
:param layer: to set the main QgsLayerMetadata with mLayer->metadata() when not None
|
||||
If ``layer`` is set, then this constructor automatically sets the widget's metadata() to match
|
||||
the layer's metadata..
|
||||
|
||||
.. seealso:: :py:func:`setMetadata`
|
||||
%End
|
||||
|
||||
void setMetadata( const QgsLayerMetadata &layerMetadata );
|
||||
void setMetadata( const QgsLayerMetadata &metadata );
|
||||
%Docstring
|
||||
Sets the ``metadata`` to display in the widget
|
||||
\note
|
||||
Called from constructor and initializes child widget on first use
|
||||
Can be called from outside to change the QgsLayerMetadata object.
|
||||
Sets the ``metadata`` to display in the widget.
|
||||
|
||||
This method can be called after constructing a QgsMetadataWidget in order
|
||||
to set the displayed metadata to custom, non-layer based metadata.
|
||||
|
||||
.. seealso:: :py:func:`metadata`
|
||||
%End
|
||||
|
||||
QgsLayerMetadata metadata();
|
||||
%Docstring
|
||||
Retrieves a QgsLayerMetadata object representing the current state of the widget.
|
||||
\note
|
||||
saveMetdata is called before returning :py:class:`QgsLayerMetadata`
|
||||
Returns a QgsLayerMetadata object representing the current state of the widget.
|
||||
|
||||
.. seealso:: :py:func:`saveMetadata`
|
||||
%End
|
||||
@ -58,7 +54,7 @@ saveMetdata is called before returning :py:class:`QgsLayerMetadata`
|
||||
%Docstring
|
||||
Save all fields in a QgsLayerMetadata object.
|
||||
|
||||
.. seealso:: :py:func:`getMetadata`
|
||||
.. seealso:: :py:func:`metadata`
|
||||
|
||||
.. seealso:: :py:func:`acceptMetadata`
|
||||
|
||||
@ -69,8 +65,6 @@ Save all fields in a QgsLayerMetadata object.
|
||||
%Docstring
|
||||
Check if values in the wizard are correct.
|
||||
|
||||
.. seealso:: :py:func:`updatePanel`
|
||||
|
||||
.. seealso:: :py:func:`saveMetadata`
|
||||
%End
|
||||
|
||||
@ -82,11 +76,6 @@ If the CRS is updated.
|
||||
void acceptMetadata();
|
||||
%Docstring
|
||||
Saves the metadata to the layer.
|
||||
%End
|
||||
|
||||
virtual void setMetadata( const QgsLayerMetadata &metadata );
|
||||
%Docstring
|
||||
Sets the layer's ``metadata`` store.
|
||||
%End
|
||||
|
||||
static QMap<QString, QString> parseLanguages();
|
||||
|
@ -117,3 +117,10 @@ bool QgsBox3d::contains( const QgsPoint &p ) const
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QgsBox3d::operator==( const QgsBox3d &other ) const
|
||||
{
|
||||
return mBounds2d == other.mBounds2d &&
|
||||
qgsDoubleNear( mZmin, other.mZmin ) &&
|
||||
qgsDoubleNear( mZmax, other.mZmax );
|
||||
}
|
||||
|
@ -202,6 +202,8 @@ class CORE_EXPORT QgsBox3d
|
||||
*/
|
||||
QgsRectangle toRectangle() const { return mBounds2d; }
|
||||
|
||||
bool operator==( const QgsBox3d &other ) const;
|
||||
|
||||
private:
|
||||
|
||||
QgsRectangle mBounds2d;
|
||||
|
@ -768,25 +768,72 @@ void QgsLayerMetadata::Extent::setTemporalExtents( const QList<QgsDateTimeRange>
|
||||
mTemporalExtents = temporalExtents;
|
||||
}
|
||||
|
||||
bool QgsLayerMetadata::Extent::operator==( const QgsLayerMetadata::Extent &other ) const
|
||||
{
|
||||
return mSpatialExtents == other.mSpatialExtents && mTemporalExtents == other.mTemporalExtents;
|
||||
}
|
||||
|
||||
bool QgsLayerMetadata::operator==( const QgsLayerMetadata &metadataOther ) const
|
||||
{
|
||||
return ( ( parentIdentifier() == metadataOther.parentIdentifier() ) &&
|
||||
( identifier() == metadataOther.identifier() ) &&
|
||||
( language() == metadataOther.language() ) &&
|
||||
( type() == metadataOther.type() ) &&
|
||||
( title() == metadataOther.title() ) &&
|
||||
( abstract() == metadataOther.abstract() ) &&
|
||||
( fees() == metadataOther.fees() ) &&
|
||||
( rights() == metadataOther.rights() ) &&
|
||||
( licenses() == metadataOther.licenses() ) &&
|
||||
( history() == metadataOther.history() ) &&
|
||||
( encoding() == metadataOther.encoding() ) &&
|
||||
( crs() == metadataOther.crs() ) &&
|
||||
( keywords() == metadataOther.keywords() ) &&
|
||||
( categories() == metadataOther.categories() ) &&
|
||||
// QgsLayerMetadata::ConstraintList, LinkList, Extent, ContactList need to be delt with properly
|
||||
( constraints().count() == metadataOther.constraints().count() ) &&
|
||||
( extent().spatialExtents().count() == metadataOther.extent().spatialExtents().count() ) &&
|
||||
( contacts().count() == metadataOther.contacts().count() ) &&
|
||||
( links().count() == metadataOther.links().count() ) );
|
||||
return ( ( mIdentifier == metadataOther.mIdentifier ) &&
|
||||
( mParentIdentifier == metadataOther.mParentIdentifier ) &&
|
||||
( mLanguage == metadataOther.mLanguage ) &&
|
||||
( mType == metadataOther.mType ) &&
|
||||
( mTitle == metadataOther.mTitle ) &&
|
||||
( mAbstract == metadataOther.mAbstract ) &&
|
||||
( mFees == metadataOther.mFees ) &&
|
||||
( mConstraints == metadataOther.mConstraints ) &&
|
||||
( mRights == metadataOther.mRights ) &&
|
||||
( mLicenses == metadataOther.mLicenses ) &&
|
||||
( mHistory == metadataOther.mHistory ) &&
|
||||
( mEncoding == metadataOther.mEncoding ) &&
|
||||
( mCrs == metadataOther.mCrs ) &&
|
||||
( mExtent == metadataOther.mExtent ) &&
|
||||
( mKeywords == metadataOther.mKeywords ) &&
|
||||
( mContacts == metadataOther.mContacts ) &&
|
||||
( mLinks == metadataOther.mLinks ) );
|
||||
}
|
||||
|
||||
bool QgsLayerMetadata::SpatialExtent::operator==( const QgsLayerMetadata::SpatialExtent &other ) const
|
||||
{
|
||||
return extentCrs == other.extentCrs &&
|
||||
bounds == other.bounds;
|
||||
}
|
||||
|
||||
bool QgsLayerMetadata::Constraint::operator==( const QgsLayerMetadata::Constraint &other ) const
|
||||
{
|
||||
return type == other.type && constraint == other.constraint;
|
||||
}
|
||||
|
||||
bool QgsLayerMetadata::Contact::operator==( const QgsLayerMetadata::Contact &other ) const
|
||||
{
|
||||
return name == other.name &&
|
||||
organization == other.organization &&
|
||||
position == other.position &&
|
||||
addresses == other.addresses &&
|
||||
voice == other.voice &&
|
||||
fax == other.fax &&
|
||||
email == other.email &&
|
||||
role == other.role;
|
||||
}
|
||||
|
||||
bool QgsLayerMetadata::Link::operator==( const QgsLayerMetadata::Link &other ) const
|
||||
{
|
||||
return name == other.name &&
|
||||
type == other.type &&
|
||||
description == other.description &&
|
||||
url == other.url &&
|
||||
format == other.format &&
|
||||
mimeType == other.mimeType &&
|
||||
size == other.size;
|
||||
}
|
||||
|
||||
bool QgsLayerMetadata::Address::operator==( const QgsLayerMetadata::Address &other ) const
|
||||
{
|
||||
return type == other.type &&
|
||||
address == other.address &&
|
||||
city == other.city &&
|
||||
administrativeArea == other.administrativeArea &&
|
||||
postalCode == other.postalCode &&
|
||||
country == other.country;
|
||||
}
|
||||
|
@ -84,6 +84,8 @@ class CORE_EXPORT QgsLayerMetadata
|
||||
* \see extentCrs
|
||||
*/
|
||||
QgsBox3d bounds;
|
||||
|
||||
bool operator==( const QgsLayerMetadata::SpatialExtent &other ) const;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -120,6 +122,8 @@ class CORE_EXPORT QgsLayerMetadata
|
||||
*/
|
||||
void setTemporalExtents( const QList< QgsDateTimeRange > &extents );
|
||||
|
||||
bool operator==( const Extent &other ) const;
|
||||
|
||||
#ifndef SIP_RUN
|
||||
private:
|
||||
|
||||
@ -154,6 +158,9 @@ class CORE_EXPORT QgsLayerMetadata
|
||||
* Free-form constraint string.
|
||||
*/
|
||||
QString constraint;
|
||||
|
||||
bool operator==( const QgsLayerMetadata::Constraint &other ) const;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
@ -209,6 +216,8 @@ class CORE_EXPORT QgsLayerMetadata
|
||||
* Free-form country string.
|
||||
*/
|
||||
QString country;
|
||||
|
||||
bool operator==( const QgsLayerMetadata::Address &other ) const;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -266,6 +275,8 @@ class CORE_EXPORT QgsLayerMetadata
|
||||
* E.g. 'custodian', 'owner', 'distributor', etc.
|
||||
*/
|
||||
QString role;
|
||||
|
||||
bool operator==( const QgsLayerMetadata::Contact &other ) const;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -324,6 +335,8 @@ class CORE_EXPORT QgsLayerMetadata
|
||||
* Estimated size (in bytes) of the online resource response.
|
||||
*/
|
||||
QString size;
|
||||
|
||||
bool operator==( const QgsLayerMetadata::Link &other ) const;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -726,10 +739,7 @@ class CORE_EXPORT QgsLayerMetadata
|
||||
*/
|
||||
bool writeMetadataXml( QDomElement &metadataElement, QDomDocument &document ) const;
|
||||
|
||||
/**
|
||||
* Compares two features
|
||||
*/
|
||||
bool operator==( const QgsLayerMetadata &metadataOther ) const SIP_SKIP;
|
||||
bool operator==( const QgsLayerMetadata &metadataOther ) const;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -494,22 +494,24 @@ class CORE_EXPORT QgsDataProvider : public QObject
|
||||
virtual bool renderInPreview( const QgsDataProvider::PreviewContext &context ); // SIP_SKIP
|
||||
|
||||
/**
|
||||
* Retrieve collected Metadata from the Provider source
|
||||
* \brief A structured metadata store for a map layer.
|
||||
* \note
|
||||
* \see setLayerMetadata
|
||||
* \since QGIS 3.0
|
||||
* Returns layer metadata collected from the provider's source.
|
||||
*
|
||||
* Individual data providers must implement this method if they support collecting metadata.
|
||||
*
|
||||
* \see writeLayerMetadata()
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
virtual QgsLayerMetadata layerMetadata() const { return QgsLayerMetadata(); };
|
||||
virtual QgsLayerMetadata layerMetadata() const { return QgsLayerMetadata(); }
|
||||
|
||||
/**
|
||||
* Set collected Metadata from the Provider source
|
||||
* \brief A structured metadata store for a map layer.
|
||||
* \note
|
||||
* \see layerMetadata
|
||||
* \since QGIS 3.0
|
||||
* Writes layer \a metadata to the underlying provider source. Support depends
|
||||
* on individual provider capabilities.
|
||||
*
|
||||
* Returns true if metadata was successfully written to the data provider.
|
||||
* \see layerMetadata()
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
virtual bool setLayerMetadata( const QgsLayerMetadata &layerMetadata ) { Q_UNUSED( layerMetadata ); return false; }
|
||||
virtual bool writeLayerMetadata( const QgsLayerMetadata &metadata ) { Q_UNUSED( metadata ); return false; }
|
||||
|
||||
signals:
|
||||
|
||||
|
@ -393,6 +393,14 @@ class QgsTemporalRange
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator==( const QgsTemporalRange<T> &other ) const
|
||||
{
|
||||
return mLower == other.mLower &&
|
||||
mUpper == other.mUpper &&
|
||||
mIncludeLower == other.mIncludeLower &&
|
||||
mIncludeUpper == other.mIncludeUpper;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
T mLower;
|
||||
|
@ -88,6 +88,8 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider, public QgsFeat
|
||||
* ChangeGeometries | ChangeAttributeValues */
|
||||
RenameAttributes = 1 << 19, //!< Supports renaming attributes (fields). Since QGIS 2.16
|
||||
FastTruncate = 1 << 20, //!< Supports fast truncation of the layer (removing all features). Since QGIS 3.0
|
||||
ReadLayerMetadata = 1 << 21, //!< Provider can read layer metadata from data store. Since QGIS 3.0. See QgsDataProvider::layerMetadata()
|
||||
WriteLayerMetadata = 1 << 22, //!< Provider can write layer metadata to the data store. Since QGIS 3.0. See QgsDataProvider::writeLayerMetadata()
|
||||
};
|
||||
|
||||
Q_DECLARE_FLAGS( Capabilities, Capability )
|
||||
|
@ -1526,8 +1526,11 @@ bool QgsVectorLayer::setDataProvider( QString const &provider )
|
||||
return false;
|
||||
}
|
||||
|
||||
setMetadata( mDataProvider->layerMetadata() );
|
||||
QgsDebugMsgLevel( QString( "Set Data provider QgsLayerMetadata identifier[%1]" ).arg( metadata().identifier() ), 4 );
|
||||
if ( mDataProvider->capabilities() & QgsVectorDataProvider::ReadLayerMetadata )
|
||||
{
|
||||
setMetadata( mDataProvider->layerMetadata() );
|
||||
QgsDebugMsgLevel( QString( "Set Data provider QgsLayerMetadata identifier[%1]" ).arg( metadata().identifier() ), 4 );
|
||||
}
|
||||
|
||||
// TODO: Check if the provider has the capability to send fullExtentCalculated
|
||||
connect( mDataProvider, &QgsVectorDataProvider::fullExtentCalculated, this, [ = ] { updateExtents(); } );
|
||||
|
@ -216,6 +216,11 @@ QgsRasterDataProvider::QgsRasterDataProvider( QString const &uri )
|
||||
{
|
||||
}
|
||||
|
||||
QgsRasterDataProvider::ProviderCapabilities QgsRasterDataProvider::providerCapabilities() const
|
||||
{
|
||||
return QgsRasterDataProvider::NoProviderCapabilities;
|
||||
}
|
||||
|
||||
//
|
||||
//Random Static convenience function
|
||||
//
|
||||
|
@ -87,12 +87,33 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Enumeration with capabilities that raster providers might implement.
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
enum ProviderCapability
|
||||
{
|
||||
NoProviderCapabilities = 0, //!< Provider has no capabilities
|
||||
ReadLayerMetadata = 1 << 1, //!< Provider can read layer metadata from data store. Since QGIS 3.0. See QgsDataProvider::layerMetadata()
|
||||
WriteLayerMetadata = 1 << 2, //!< Provider can write layer metadata to the data store. Since QGIS 3.0. See QgsDataProvider::writeLayerMetadata()
|
||||
};
|
||||
|
||||
//! Provider capabilities
|
||||
Q_DECLARE_FLAGS( ProviderCapabilities, ProviderCapability )
|
||||
|
||||
QgsRasterDataProvider();
|
||||
|
||||
QgsRasterDataProvider( const QString &uri );
|
||||
|
||||
QgsRasterInterface *clone() const override = 0;
|
||||
|
||||
/**
|
||||
* Returns flags containing the supported capabilities of the data provider.
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
virtual QgsRasterDataProvider::ProviderCapabilities providerCapabilities() const;
|
||||
|
||||
/* It makes no sense to set input on provider */
|
||||
bool setInput( QgsRasterInterface *input ) override { Q_UNUSED( input ); return false; }
|
||||
|
||||
@ -540,6 +561,8 @@ class CORE_EXPORT QgsRasterDataProvider : public QgsDataProvider, public QgsRast
|
||||
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS( QgsRasterDataProvider::ProviderCapabilities )
|
||||
|
||||
// clazy:excludeall=qstring-allocations
|
||||
|
||||
#endif
|
||||
|
@ -625,8 +625,11 @@ void QgsRasterLayer::setDataProvider( QString const &provider )
|
||||
return;
|
||||
}
|
||||
|
||||
setMetadata( mDataProvider->layerMetadata() );
|
||||
QgsDebugMsgLevel( QString( "Set Data provider QgsLayerMetadata identifier[%1]" ).arg( metadata().identifier() ), 4 );
|
||||
if ( mDataProvider->providerCapabilities() & QgsRasterDataProvider::ReadLayerMetadata )
|
||||
{
|
||||
setMetadata( mDataProvider->layerMetadata() );
|
||||
QgsDebugMsgLevel( QString( "Set Data provider QgsLayerMetadata identifier[%1]" ).arg( metadata().identifier() ), 4 );
|
||||
}
|
||||
|
||||
if ( provider == QLatin1String( "gdal" ) )
|
||||
{
|
||||
|
@ -114,7 +114,7 @@ QgsMetadataWidget::QgsMetadataWidget( QWidget *parent, QgsMapLayer *layer )
|
||||
{
|
||||
btnAutoSource->setEnabled( false );
|
||||
btnAutoEncoding->setEnabled( false );
|
||||
btnAutoCrs->setEnabled( false );
|
||||
btnSetCrsFromLayer->setEnabled( false );
|
||||
}
|
||||
setMetadata( mMetadata );
|
||||
}
|
||||
@ -127,11 +127,12 @@ void QgsMetadataWidget::setMetadata( const QgsLayerMetadata &layerMetadata )
|
||||
|
||||
QgsLayerMetadata QgsMetadataWidget::metadata()
|
||||
{
|
||||
saveMetadata( mMetadata );
|
||||
return mMetadata;
|
||||
QgsLayerMetadata md;
|
||||
saveMetadata( md );
|
||||
return md;
|
||||
}
|
||||
|
||||
void QgsMetadataWidget::fillSourceFromLayer() const
|
||||
void QgsMetadataWidget::fillSourceFromLayer()
|
||||
{
|
||||
if ( mLayer )
|
||||
{
|
||||
@ -139,7 +140,7 @@ void QgsMetadataWidget::fillSourceFromLayer() const
|
||||
}
|
||||
}
|
||||
|
||||
void QgsMetadataWidget::addVocabulary() const
|
||||
void QgsMetadataWidget::addVocabulary()
|
||||
{
|
||||
int row = tabKeywords->rowCount();
|
||||
tabKeywords->setRowCount( row + 1 );
|
||||
@ -154,7 +155,7 @@ void QgsMetadataWidget::addVocabulary() const
|
||||
tabKeywords->setItem( row, 1, pCell );
|
||||
}
|
||||
|
||||
void QgsMetadataWidget::removeSelectedVocabulary() const
|
||||
void QgsMetadataWidget::removeSelectedVocabulary()
|
||||
{
|
||||
QItemSelectionModel *selectionModel = tabKeywords->selectionModel();
|
||||
const QModelIndexList selectedRows = selectionModel->selectedRows();
|
||||
@ -176,7 +177,7 @@ void QgsMetadataWidget::addLicence()
|
||||
}
|
||||
}
|
||||
|
||||
void QgsMetadataWidget::removeSelectedLicence() const
|
||||
void QgsMetadataWidget::removeSelectedLicence()
|
||||
{
|
||||
QItemSelectionModel *selectionModel = tabLicenses->selectionModel();
|
||||
const QModelIndexList selectedRows = selectionModel->selectedRows();
|
||||
@ -197,7 +198,7 @@ void QgsMetadataWidget::addRight()
|
||||
}
|
||||
}
|
||||
|
||||
void QgsMetadataWidget::removeSelectedRight() const
|
||||
void QgsMetadataWidget::removeSelectedRight()
|
||||
{
|
||||
QItemSelectionModel *selection = listRights->selectionModel();
|
||||
if ( selection->hasSelection() )
|
||||
@ -211,20 +212,20 @@ void QgsMetadataWidget::removeSelectedRight() const
|
||||
}
|
||||
}
|
||||
|
||||
void QgsMetadataWidget::addConstraint() const
|
||||
void QgsMetadataWidget::addConstraint()
|
||||
{
|
||||
int row = mConstraintsModel->rowCount();
|
||||
mConstraintsModel->setItem( row, 0, new QStandardItem( QString( tr( "undefined %1" ) ).arg( row + 1 ) ) );
|
||||
mConstraintsModel->setItem( row, 1, new QStandardItem( QString( tr( "undefined %1" ) ).arg( row + 1 ) ) );
|
||||
}
|
||||
|
||||
void QgsMetadataWidget::removeSelectedConstraint() const
|
||||
void QgsMetadataWidget::removeSelectedConstraint()
|
||||
{
|
||||
const QModelIndexList selectedRows = tabConstraints->selectionModel()->selectedRows();
|
||||
mConstraintsModel->removeRow( selectedRows[0].row() );
|
||||
}
|
||||
|
||||
void QgsMetadataWidget::crsChanged() const
|
||||
void QgsMetadataWidget::crsChanged()
|
||||
{
|
||||
if ( ( mCrs.isValid() ) && ( mLayer ) )
|
||||
{
|
||||
@ -257,7 +258,7 @@ void QgsMetadataWidget::crsChanged() const
|
||||
}
|
||||
}
|
||||
|
||||
void QgsMetadataWidget::addAddress() const
|
||||
void QgsMetadataWidget::addAddress()
|
||||
{
|
||||
int row = tabAddresses->rowCount();
|
||||
tabAddresses->setRowCount( row + 1 );
|
||||
@ -283,7 +284,7 @@ void QgsMetadataWidget::addAddress() const
|
||||
tabAddresses->setItem( row, 5, new QTableWidgetItem() );
|
||||
}
|
||||
|
||||
void QgsMetadataWidget::removeSelectedAddress() const
|
||||
void QgsMetadataWidget::removeSelectedAddress()
|
||||
{
|
||||
QItemSelectionModel *selectionModel = tabAddresses->selectionModel();
|
||||
const QModelIndexList selectedRows = selectionModel->selectedRows();
|
||||
@ -305,7 +306,7 @@ void QgsMetadataWidget::fillCrsFromProvider()
|
||||
crsChanged();
|
||||
}
|
||||
|
||||
void QgsMetadataWidget::addLink() const
|
||||
void QgsMetadataWidget::addLink()
|
||||
{
|
||||
int row = mLinksModel->rowCount();
|
||||
mLinksModel->setItem( row, 0, new QStandardItem( QString( tr( "undefined %1" ) ).arg( row + 1 ) ) );
|
||||
@ -317,7 +318,7 @@ void QgsMetadataWidget::addLink() const
|
||||
mLinksModel->setItem( row, 6, new QStandardItem() );
|
||||
}
|
||||
|
||||
void QgsMetadataWidget::removeSelectedLink() const
|
||||
void QgsMetadataWidget::removeSelectedLink()
|
||||
{
|
||||
const QModelIndexList selectedRows = tabLinks->selectionModel()->selectedRows();
|
||||
mLinksModel->removeRow( selectedRows[0].row() );
|
||||
@ -334,7 +335,7 @@ void QgsMetadataWidget::addHistory()
|
||||
}
|
||||
}
|
||||
|
||||
void QgsMetadataWidget::removeSelectedHistory() const
|
||||
void QgsMetadataWidget::removeSelectedHistory()
|
||||
{
|
||||
QItemSelectionModel *selection = listHistory->selectionModel();
|
||||
if ( selection->hasSelection() )
|
||||
@ -348,7 +349,7 @@ void QgsMetadataWidget::removeSelectedHistory() const
|
||||
}
|
||||
}
|
||||
|
||||
void QgsMetadataWidget::fillComboBox() const
|
||||
void QgsMetadataWidget::fillComboBox()
|
||||
{
|
||||
// Set default values in type combobox
|
||||
// It is advised to use the ISO 19115 MD_ScopeCode values. E.g. 'dataset' or 'series'.
|
||||
@ -546,7 +547,7 @@ void QgsMetadataWidget::setPropertiesFromLayer()
|
||||
mHistoryModel->setStringList( mMetadata.history() );
|
||||
}
|
||||
|
||||
void QgsMetadataWidget::saveMetadata( QgsLayerMetadata &layerMetadata ) const
|
||||
void QgsMetadataWidget::saveMetadata( QgsLayerMetadata &layerMetadata )
|
||||
{
|
||||
layerMetadata.setParentIdentifier( lineEditParentId->text() );
|
||||
layerMetadata.setIdentifier( lineEditIdentifier->text() );
|
||||
@ -659,7 +660,7 @@ void QgsMetadataWidget::saveMetadata( QgsLayerMetadata &layerMetadata ) const
|
||||
layerMetadata.setHistory( mHistoryModel->stringList() );
|
||||
}
|
||||
|
||||
bool QgsMetadataWidget::checkMetadata() const
|
||||
bool QgsMetadataWidget::checkMetadata()
|
||||
{
|
||||
QgsLayerMetadata metadata = QgsLayerMetadata();
|
||||
saveMetadata( metadata );
|
||||
@ -846,13 +847,7 @@ void QgsMetadataWidget::acceptMetadata()
|
||||
}
|
||||
}
|
||||
|
||||
void QgsMetadataWidget::setMetadata( const QgsLayerMetadata &metadata )
|
||||
{
|
||||
mMetadata = metadata;
|
||||
setPropertiesFromLayer();
|
||||
}
|
||||
|
||||
void QgsMetadataWidget::syncFromCategoriesTabToKeywordsTab() const
|
||||
void QgsMetadataWidget::syncFromCategoriesTabToKeywordsTab()
|
||||
{
|
||||
if ( mCategoriesModel->rowCount() > 0 )
|
||||
{
|
||||
@ -873,7 +868,7 @@ void QgsMetadataWidget::syncFromCategoriesTabToKeywordsTab() const
|
||||
}
|
||||
}
|
||||
|
||||
void QgsMetadataWidget::updatePanel() const
|
||||
void QgsMetadataWidget::updatePanel()
|
||||
{
|
||||
int index = tabWidget->currentIndex();
|
||||
QString currentTabText = tabWidget->widget( index )->objectName();
|
||||
|
@ -43,43 +43,41 @@ class GUI_EXPORT QgsMetadataWidget : public QWidget, private Ui::QgsMetadataWidg
|
||||
|
||||
/**
|
||||
* Constructor for the wizard.
|
||||
* \note
|
||||
* For use with a source \layer. This constructor automatically sets the widget's metadata() if the \a layer pointer is valid.
|
||||
* calls setMetadata, using mMetadata
|
||||
* \param layer to set the main QgsLayerMetadata with mLayer->metadata() when not nullptr
|
||||
* \see setMetadata
|
||||
*
|
||||
* If \a layer is set, then this constructor automatically sets the widget's metadata() to match
|
||||
* the layer's metadata..
|
||||
|
||||
* \see setMetadata()
|
||||
*/
|
||||
QgsMetadataWidget( QWidget *parent, QgsMapLayer *layer = nullptr );
|
||||
|
||||
/**
|
||||
* Sets the \a metadata to display in the widget
|
||||
* \note
|
||||
* Called from constructor and initializes child widget on first use
|
||||
* Can be called from outside to change the QgsLayerMetadata object.
|
||||
* Sets the \a metadata to display in the widget.
|
||||
*
|
||||
* This method can be called after constructing a QgsMetadataWidget in order
|
||||
* to set the displayed metadata to custom, non-layer based metadata.
|
||||
*
|
||||
* \see metadata()
|
||||
*/
|
||||
void setMetadata( const QgsLayerMetadata &layerMetadata );
|
||||
void setMetadata( const QgsLayerMetadata &metadata );
|
||||
|
||||
/**
|
||||
* Retrieves a QgsLayerMetadata object representing the current state of the widget.
|
||||
* \note
|
||||
* saveMetdata is called before returning QgsLayerMetadata
|
||||
* \see saveMetadata
|
||||
* Returns a QgsLayerMetadata object representing the current state of the widget.
|
||||
* \see saveMetadata()
|
||||
*/
|
||||
QgsLayerMetadata metadata();
|
||||
|
||||
/**
|
||||
* Save all fields in a QgsLayerMetadata object.
|
||||
* \see getMetadata
|
||||
* \see acceptMetadata
|
||||
* \see checkMetadata
|
||||
* \see metadata()
|
||||
* \see acceptMetadata()
|
||||
* \see checkMetadata()
|
||||
*/
|
||||
void saveMetadata( QgsLayerMetadata &layerMetadata );
|
||||
|
||||
/**
|
||||
* Check if values in the wizard are correct.
|
||||
* \see updatePanel
|
||||
* \see saveMetadata
|
||||
* \see saveMetadata()
|
||||
*/
|
||||
bool checkMetadata();
|
||||
|
||||
@ -93,11 +91,6 @@ class GUI_EXPORT QgsMetadataWidget : public QWidget, private Ui::QgsMetadataWidg
|
||||
*/
|
||||
void acceptMetadata();
|
||||
|
||||
/**
|
||||
* Sets the layer's \a metadata store.
|
||||
*/
|
||||
virtual void setMetadata( const QgsLayerMetadata &metadata );
|
||||
|
||||
/**
|
||||
* Returns a list of languages available by default in the wizard.
|
||||
*/
|
||||
|
@ -173,6 +173,17 @@ class TestQgsBox3d(unittest.TestCase):
|
||||
box = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, -7.0)
|
||||
self.assertTrue(box.is2d())
|
||||
|
||||
def testEquality(self):
|
||||
box1 = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 15.0)
|
||||
box2 = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 15.0)
|
||||
self.assertEqual(box1, box2)
|
||||
self.assertNotEqual(box1, QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 14.0))
|
||||
self.assertNotEqual(box1, QgsBox3d(5.0, 6.0, 7.0, 11.0, 41.0, 15.0))
|
||||
self.assertNotEqual(box1, QgsBox3d(5.0, 6.0, 7.0, 12.0, 13.0, 15.0))
|
||||
self.assertNotEqual(box1, QgsBox3d(5.0, 6.0, 17.0, 11.0, 13.0, 15.0))
|
||||
self.assertNotEqual(box1, QgsBox3d(5.0, 16.0, 7.0, 11.0, 13.0, 15.0))
|
||||
self.assertNotEqual(box1, QgsBox3d(52.0, 6.0, 7.0, 11.0, 13.0, 15.0))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
@ -86,6 +86,161 @@ class TestQgsLayerMetadata(unittest.TestCase):
|
||||
m.setCrs(QgsCoordinateReferenceSystem.fromEpsgId(3111))
|
||||
self.assertEqual(m.crs().authid(), 'EPSG:3111')
|
||||
|
||||
def testEquality(self):
|
||||
# spatial extent
|
||||
extent = QgsLayerMetadata.SpatialExtent()
|
||||
extent.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3111)
|
||||
extent.bounds = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 15.0)
|
||||
extent2 = QgsLayerMetadata.SpatialExtent()
|
||||
extent2.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3111)
|
||||
extent2.bounds = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 15.0)
|
||||
self.assertEqual(extent, extent2)
|
||||
extent2.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3113)
|
||||
self.assertNotEqual(extent, extent2)
|
||||
extent2.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3111)
|
||||
extent2.bounds = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 16.0)
|
||||
self.assertNotEqual(extent, extent2)
|
||||
|
||||
# extent
|
||||
extent = QgsLayerMetadata.Extent()
|
||||
extent1 = QgsLayerMetadata.SpatialExtent()
|
||||
extent1.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3111)
|
||||
extent1.bounds = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 15.0)
|
||||
extent2 = QgsLayerMetadata.SpatialExtent()
|
||||
extent2.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3113)
|
||||
extent2.bounds = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 16.0)
|
||||
extent.setSpatialExtents([extent1, extent2])
|
||||
dates = [
|
||||
QgsDateTimeRange(
|
||||
QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47)),
|
||||
QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47))),
|
||||
QgsDateTimeRange(
|
||||
QDateTime(QDate(2010, 12, 17), QTime(9, 30, 47)),
|
||||
QDateTime(QDate(2020, 12, 17), QTime(9, 30, 47)))
|
||||
]
|
||||
extent.setTemporalExtents(dates)
|
||||
extent_copy = QgsLayerMetadata.Extent(extent)
|
||||
self.assertEqual(extent, extent_copy)
|
||||
extent_copy.setTemporalExtents([
|
||||
QgsDateTimeRange(
|
||||
QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47)),
|
||||
QDateTime(QDate(2001, 12, 17), QTime(9, 30, 47))),
|
||||
QgsDateTimeRange(
|
||||
QDateTime(QDate(2010, 12, 17), QTime(9, 30, 48)),
|
||||
QDateTime(QDate(2020, 12, 17), QTime(9, 30, 49)))
|
||||
])
|
||||
self.assertNotEqual(extent, extent_copy)
|
||||
extent_copy = QgsLayerMetadata.Extent(extent)
|
||||
extent3 = QgsLayerMetadata.SpatialExtent()
|
||||
extent3.extentCrs = QgsCoordinateReferenceSystem.fromEpsgId(3113)
|
||||
extent3.bounds = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 19.0)
|
||||
extent_copy.setSpatialExtents([extent1, extent3])
|
||||
self.assertNotEqual(extent, extent_copy)
|
||||
|
||||
constraint = QgsLayerMetadata.Constraint('c', 'type1')
|
||||
self.assertEqual(constraint, QgsLayerMetadata.Constraint('c', 'type1'))
|
||||
self.assertNotEqual(constraint, QgsLayerMetadata.Constraint('c2', 'type1'))
|
||||
self.assertNotEqual(constraint, QgsLayerMetadata.Constraint('c', 'type2'))
|
||||
|
||||
a = QgsLayerMetadata.Address()
|
||||
a.type = 'postal'
|
||||
a.address = '13 north rd'
|
||||
a.city = 'huxleys haven'
|
||||
a.administrativeArea = 'land of the queens'
|
||||
a.postalCode = '4123'
|
||||
a.country = 'straya!'
|
||||
a2 = QgsLayerMetadata.Address(a)
|
||||
self.assertEqual(a, a2)
|
||||
a2.type = 'postal2'
|
||||
self.assertNotEqual(a, a2)
|
||||
a2 = QgsLayerMetadata.Address(a)
|
||||
a2.address = 'address2'
|
||||
self.assertNotEqual(a, a2)
|
||||
a2 = QgsLayerMetadata.Address(a)
|
||||
a2.city = 'city'
|
||||
self.assertNotEqual(a, a2)
|
||||
a2 = QgsLayerMetadata.Address(a)
|
||||
a2.administrativeArea = 'area2'
|
||||
self.assertNotEqual(a, a2)
|
||||
a2 = QgsLayerMetadata.Address(a)
|
||||
a2.postalCode = 'postal2'
|
||||
self.assertNotEqual(a, a2)
|
||||
a2 = QgsLayerMetadata.Address(a)
|
||||
a2.country = 'country2'
|
||||
self.assertNotEqual(a, a2)
|
||||
|
||||
c = QgsLayerMetadata.Contact()
|
||||
c.name = 'name'
|
||||
c.organization = 'org'
|
||||
c.position = 'pos'
|
||||
c.voice = '1500 515 555'
|
||||
c.fax = 'fax'
|
||||
c.email = 'email'
|
||||
c.role = 'role'
|
||||
a = QgsLayerMetadata.Address()
|
||||
a.type = 'postal'
|
||||
a2 = QgsLayerMetadata.Address()
|
||||
a2.type = 'street'
|
||||
c.addresses = [a, a2]
|
||||
c2 = QgsLayerMetadata.Contact(c)
|
||||
self.assertEqual(c, c2)
|
||||
c2.name = 'name2'
|
||||
self.assertNotEqual(c, c2)
|
||||
c2 = QgsLayerMetadata.Contact(c)
|
||||
c2.organization = 'org2'
|
||||
self.assertNotEqual(c, c2)
|
||||
c2 = QgsLayerMetadata.Contact(c)
|
||||
c2.position = 'pos2'
|
||||
self.assertNotEqual(c, c2)
|
||||
c2 = QgsLayerMetadata.Contact(c)
|
||||
c2.voice = 'voice2'
|
||||
self.assertNotEqual(c, c2)
|
||||
c2 = QgsLayerMetadata.Contact(c)
|
||||
c2.fax = 'fax2'
|
||||
self.assertNotEqual(c, c2)
|
||||
c2 = QgsLayerMetadata.Contact(c)
|
||||
c2.email = 'email2'
|
||||
self.assertNotEqual(c, c2)
|
||||
c2 = QgsLayerMetadata.Contact(c)
|
||||
c2.role = 'role2'
|
||||
self.assertNotEqual(c, c2)
|
||||
c2 = QgsLayerMetadata.Contact(c)
|
||||
c2.addresses = [a2]
|
||||
self.assertNotEqual(c, c2)
|
||||
|
||||
# link
|
||||
l = QgsLayerMetadata.Link()
|
||||
l.name = 'name'
|
||||
l.type = 'type'
|
||||
l.description = 'desc'
|
||||
l.url = 'url'
|
||||
l.format = 'format'
|
||||
l.mimeType = 'mime'
|
||||
l.size = '112'
|
||||
l2 = QgsLayerMetadata.Link(l)
|
||||
self.assertEqual(l, l2)
|
||||
l2 = QgsLayerMetadata.Link(l)
|
||||
l2.name = 'name2'
|
||||
self.assertNotEqual(l, l2)
|
||||
l2 = QgsLayerMetadata.Link(l)
|
||||
l2.type = 'type2'
|
||||
self.assertNotEqual(l, l2)
|
||||
l2 = QgsLayerMetadata.Link(l)
|
||||
l2.description = 'desc2'
|
||||
self.assertNotEqual(l, l2)
|
||||
l2 = QgsLayerMetadata.Link(l)
|
||||
l2.url = 'url2'
|
||||
self.assertNotEqual(l, l2)
|
||||
l2 = QgsLayerMetadata.Link(l)
|
||||
l2.format = 'format2'
|
||||
self.assertNotEqual(l, l2)
|
||||
l2 = QgsLayerMetadata.Link(l)
|
||||
l2.mimeType = 'mime2'
|
||||
self.assertNotEqual(l, l2)
|
||||
l2 = QgsLayerMetadata.Link(l)
|
||||
l2.size = '113'
|
||||
self.assertNotEqual(l, l2)
|
||||
|
||||
def testExtent(self):
|
||||
e = QgsLayerMetadata.Extent()
|
||||
se = QgsLayerMetadata.SpatialExtent()
|
||||
|
@ -348,6 +348,14 @@ class TestQgsDateRange(unittest.TestCase):
|
||||
self.assertTrue(QgsDateRange(QDate(2017, 3, 1), QDate(2010, 6, 2)).isEmpty())
|
||||
self.assertFalse(QgsDateRange(QDate(), QDate()).isEmpty())
|
||||
|
||||
def testEquality(self):
|
||||
range = QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2), False, False)
|
||||
self.assertEqual(range, QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2), False, False))
|
||||
self.assertNotEqual(range, QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2), False, True))
|
||||
self.assertNotEqual(range, QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 2), True, False))
|
||||
self.assertNotEqual(range, QgsDateRange(QDate(2010, 3, 1), QDate(2010, 6, 3), False, False))
|
||||
self.assertNotEqual(range, QgsDateRange(QDate(2010, 3, 2), QDate(2010, 6, 2), False, False))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
Loading…
x
Reference in New Issue
Block a user