mirror of
https://github.com/qgis/QGIS.git
synced 2025-07-03 00:03:10 -04:00
Compare commits
17 Commits
ba2070b3e3
...
1ae5196805
Author | SHA1 | Date | |
---|---|---|---|
|
1ae5196805 | ||
|
74549aad26 | ||
|
eac401c009 | ||
|
1f0166d35e | ||
|
ada589bb1d | ||
|
b1c8ef3265 | ||
|
f4cf09d4b0 | ||
|
9db58e3726 | ||
|
551aa20f20 | ||
|
24bbdda539 | ||
|
c3641ecdad | ||
|
a36f64edba | ||
|
7181b40dea | ||
|
37b2f2257d | ||
|
30798bb462 | ||
|
52a05a08bd | ||
|
a156c43f7b |
@ -979,7 +979,31 @@ if (WITH_CORE)
|
|||||||
else()
|
else()
|
||||||
# UNIX
|
# UNIX
|
||||||
set (DEFAULT_BIN_SUBDIR bin)
|
set (DEFAULT_BIN_SUBDIR bin)
|
||||||
set (DEFAULT_CGIBIN_SUBDIR bin)
|
|
||||||
|
# From https://www.cyberciti.biz/faq/how-do-i-find-the-url-for-my-cgi-bin/
|
||||||
|
execute_process(COMMAND lsb_release -a OUTPUT_VARIABLE LSB_RELEASE_A)
|
||||||
|
if(EXISTS "/etc/fedora-release")
|
||||||
|
# in /var/www/cgi-bin
|
||||||
|
set (DEFAULT_CGIBIN_SUBDIR www/cgi-bin)
|
||||||
|
|
||||||
|
elseif (${CMAKE_HOST_SYSTEM_NAME} MATCHES "FreeBSD")
|
||||||
|
# in /usr/local/www/cgi-bin/
|
||||||
|
set (DEFAULT_CGIBIN_SUBDIR www/cgi-bin)
|
||||||
|
|
||||||
|
elseif (${CMAKE_HOST_SYSTEM_NAME} MATCHES "BSD")
|
||||||
|
# in /usr/local/libexec/cgi-bin/
|
||||||
|
set (DEFAULT_CGIBIN_SUBDIR libexec/cgi-bin)
|
||||||
|
|
||||||
|
elseif ("${LSB_RELEASE_A}" MATCHES "Ubuntu" OR "${LSB_RELEASE_A}" MATCHES "Debian" OR "${LSB_RELEASE_A}" MATCHES "Mint")
|
||||||
|
# in /usr/lib/cgi-bin/
|
||||||
|
set (DEFAULT_CGIBIN_SUBDIR lib/cgi-bin)
|
||||||
|
|
||||||
|
else()
|
||||||
|
# others: Red Hat/CentOS/Rocky/Alma Linux
|
||||||
|
# in /var/www/cgi-bin/
|
||||||
|
set (DEFAULT_CGIBIN_SUBDIR www/cgi-bin)
|
||||||
|
endif()
|
||||||
|
|
||||||
set (DEFAULT_LIB_SUBDIR lib${LIB_SUFFIX})
|
set (DEFAULT_LIB_SUBDIR lib${LIB_SUFFIX})
|
||||||
set (DEFAULT_DATA_SUBDIR share/qgis)
|
set (DEFAULT_DATA_SUBDIR share/qgis)
|
||||||
set (DEFAULT_LIBEXEC_SUBDIR lib${LIB_SUFFIX}/qgis)
|
set (DEFAULT_LIBEXEC_SUBDIR lib${LIB_SUFFIX}/qgis)
|
||||||
|
@ -4,6 +4,7 @@ QgsProjectServerValidator.LayerShortName = QgsProjectServerValidator.ValidationE
|
|||||||
QgsProjectServerValidator.LayerEncoding = QgsProjectServerValidator.ValidationError.LayerEncoding
|
QgsProjectServerValidator.LayerEncoding = QgsProjectServerValidator.ValidationError.LayerEncoding
|
||||||
QgsProjectServerValidator.ProjectShortName = QgsProjectServerValidator.ValidationError.ProjectShortName
|
QgsProjectServerValidator.ProjectShortName = QgsProjectServerValidator.ValidationError.ProjectShortName
|
||||||
QgsProjectServerValidator.ProjectRootNameConflict = QgsProjectServerValidator.ValidationError.ProjectRootNameConflict
|
QgsProjectServerValidator.ProjectRootNameConflict = QgsProjectServerValidator.ValidationError.ProjectRootNameConflict
|
||||||
|
QgsProjectServerValidator.OnlyMaptipTrueButEmptyMaptip = QgsProjectServerValidator.ValidationError.OnlyMaptipTrueButEmptyMaptip
|
||||||
try:
|
try:
|
||||||
QgsProjectServerValidator.ValidationResult.__attribute_docs__ = {'error': 'Error which occurred during the validation process.', 'identifier': 'Identifier related to the error. It can be a layer/group name.'}
|
QgsProjectServerValidator.ValidationResult.__attribute_docs__ = {'error': 'Error which occurred during the validation process.', 'identifier': 'Identifier related to the error. It can be a layer/group name.'}
|
||||||
QgsProjectServerValidator.ValidationResult.__annotations__ = {'error': 'QgsProjectServerValidator.ValidationError', 'identifier': 'object'}
|
QgsProjectServerValidator.ValidationResult.__annotations__ = {'error': 'QgsProjectServerValidator.ValidationError', 'identifier': 'object'}
|
||||||
|
@ -33,6 +33,7 @@ project.
|
|||||||
LayerEncoding,
|
LayerEncoding,
|
||||||
ProjectShortName,
|
ProjectShortName,
|
||||||
ProjectRootNameConflict,
|
ProjectRootNameConflict,
|
||||||
|
OnlyMaptipTrueButEmptyMaptip,
|
||||||
};
|
};
|
||||||
|
|
||||||
static QString displayValidationError( QgsProjectServerValidator::ValidationError error );
|
static QString displayValidationError( QgsProjectServerValidator::ValidationError error );
|
||||||
|
@ -23,6 +23,7 @@ try:
|
|||||||
QgsServerProjectUtils.wmsInfoFormatSia2045 = staticmethod(QgsServerProjectUtils.wmsInfoFormatSia2045)
|
QgsServerProjectUtils.wmsInfoFormatSia2045 = staticmethod(QgsServerProjectUtils.wmsInfoFormatSia2045)
|
||||||
QgsServerProjectUtils.wmsFeatureInfoAddWktGeometry = staticmethod(QgsServerProjectUtils.wmsFeatureInfoAddWktGeometry)
|
QgsServerProjectUtils.wmsFeatureInfoAddWktGeometry = staticmethod(QgsServerProjectUtils.wmsFeatureInfoAddWktGeometry)
|
||||||
QgsServerProjectUtils.wmsFeatureInfoUseAttributeFormSettings = staticmethod(QgsServerProjectUtils.wmsFeatureInfoUseAttributeFormSettings)
|
QgsServerProjectUtils.wmsFeatureInfoUseAttributeFormSettings = staticmethod(QgsServerProjectUtils.wmsFeatureInfoUseAttributeFormSettings)
|
||||||
|
QgsServerProjectUtils.wmsHTMLFeatureInfoUseOnlyMaptip = staticmethod(QgsServerProjectUtils.wmsHTMLFeatureInfoUseOnlyMaptip)
|
||||||
QgsServerProjectUtils.wmsFeatureInfoSegmentizeWktGeometry = staticmethod(QgsServerProjectUtils.wmsFeatureInfoSegmentizeWktGeometry)
|
QgsServerProjectUtils.wmsFeatureInfoSegmentizeWktGeometry = staticmethod(QgsServerProjectUtils.wmsFeatureInfoSegmentizeWktGeometry)
|
||||||
QgsServerProjectUtils.wmsAddLegendGroupsLegendGraphic = staticmethod(QgsServerProjectUtils.wmsAddLegendGroupsLegendGraphic)
|
QgsServerProjectUtils.wmsAddLegendGroupsLegendGraphic = staticmethod(QgsServerProjectUtils.wmsAddLegendGroupsLegendGraphic)
|
||||||
QgsServerProjectUtils.wmsSkipNameForGroup = staticmethod(QgsServerProjectUtils.wmsSkipNameForGroup)
|
QgsServerProjectUtils.wmsSkipNameForGroup = staticmethod(QgsServerProjectUtils.wmsSkipNameForGroup)
|
||||||
|
@ -252,6 +252,20 @@ the feature info response
|
|||||||
feature info response
|
feature info response
|
||||||
%End
|
%End
|
||||||
|
|
||||||
|
static bool wmsHTMLFeatureInfoUseOnlyMaptip( const QgsProject &project );
|
||||||
|
%Docstring
|
||||||
|
Returns if only the maptip should be used for HTML feature info response
|
||||||
|
so that the HTML response to the feature info request only contains the
|
||||||
|
maptip. If no maptip is set, the HTML response is empty.
|
||||||
|
|
||||||
|
:param project: the QGIS project
|
||||||
|
|
||||||
|
:return: true if only the maptip should be used for the feature info
|
||||||
|
response only
|
||||||
|
|
||||||
|
.. versionadded:: 4.0
|
||||||
|
%End
|
||||||
|
|
||||||
static bool wmsFeatureInfoSegmentizeWktGeometry( const QgsProject &project );
|
static bool wmsFeatureInfoSegmentizeWktGeometry( const QgsProject &project );
|
||||||
%Docstring
|
%Docstring
|
||||||
Returns if the geometry has to be segmentize in GetFeatureInfo request.
|
Returns if the geometry has to be segmentize in GetFeatureInfo request.
|
||||||
|
@ -33,6 +33,7 @@ project.
|
|||||||
LayerEncoding,
|
LayerEncoding,
|
||||||
ProjectShortName,
|
ProjectShortName,
|
||||||
ProjectRootNameConflict,
|
ProjectRootNameConflict,
|
||||||
|
OnlyMaptipTrueButEmptyMaptip,
|
||||||
};
|
};
|
||||||
|
|
||||||
static QString displayValidationError( QgsProjectServerValidator::ValidationError error );
|
static QString displayValidationError( QgsProjectServerValidator::ValidationError error );
|
||||||
|
@ -659,6 +659,9 @@ class Repositories(QObject):
|
|||||||
.strip()
|
.strip()
|
||||||
)
|
)
|
||||||
if not qgisMaximumVersion:
|
if not qgisMaximumVersion:
|
||||||
|
if qgisMinimumVersion[0] == "3" and supports_qt6:
|
||||||
|
qgisMaximumVersion = "4.99"
|
||||||
|
else:
|
||||||
qgisMaximumVersion = qgisMinimumVersion[0] + ".99"
|
qgisMaximumVersion = qgisMinimumVersion[0] + ".99"
|
||||||
# if compatible, add the plugin to the list
|
# if compatible, add the plugin to the list
|
||||||
if not pluginNodes.item(i).firstChildElement(
|
if not pluginNodes.item(i).firstChildElement(
|
||||||
@ -845,6 +848,9 @@ class Plugins(QObject):
|
|||||||
qgisMinimumVersion = "0"
|
qgisMinimumVersion = "0"
|
||||||
qgisMaximumVersion = pluginMetadata("qgisMaximumVersion").strip()
|
qgisMaximumVersion = pluginMetadata("qgisMaximumVersion").strip()
|
||||||
if not qgisMaximumVersion:
|
if not qgisMaximumVersion:
|
||||||
|
if qgisMinimumVersion[0] == "3" and supports_qt6:
|
||||||
|
qgisMaximumVersion = "4.99"
|
||||||
|
else:
|
||||||
qgisMaximumVersion = qgisMinimumVersion[0] + ".99"
|
qgisMaximumVersion = qgisMinimumVersion[0] + ".99"
|
||||||
# if compatible, add the plugin to the list
|
# if compatible, add the plugin to the list
|
||||||
if not isCompatible(
|
if not isCompatible(
|
||||||
|
@ -23,6 +23,7 @@ try:
|
|||||||
QgsServerProjectUtils.wmsInfoFormatSia2045 = staticmethod(QgsServerProjectUtils.wmsInfoFormatSia2045)
|
QgsServerProjectUtils.wmsInfoFormatSia2045 = staticmethod(QgsServerProjectUtils.wmsInfoFormatSia2045)
|
||||||
QgsServerProjectUtils.wmsFeatureInfoAddWktGeometry = staticmethod(QgsServerProjectUtils.wmsFeatureInfoAddWktGeometry)
|
QgsServerProjectUtils.wmsFeatureInfoAddWktGeometry = staticmethod(QgsServerProjectUtils.wmsFeatureInfoAddWktGeometry)
|
||||||
QgsServerProjectUtils.wmsFeatureInfoUseAttributeFormSettings = staticmethod(QgsServerProjectUtils.wmsFeatureInfoUseAttributeFormSettings)
|
QgsServerProjectUtils.wmsFeatureInfoUseAttributeFormSettings = staticmethod(QgsServerProjectUtils.wmsFeatureInfoUseAttributeFormSettings)
|
||||||
|
QgsServerProjectUtils.wmsHTMLFeatureInfoUseOnlyMaptip = staticmethod(QgsServerProjectUtils.wmsHTMLFeatureInfoUseOnlyMaptip)
|
||||||
QgsServerProjectUtils.wmsFeatureInfoSegmentizeWktGeometry = staticmethod(QgsServerProjectUtils.wmsFeatureInfoSegmentizeWktGeometry)
|
QgsServerProjectUtils.wmsFeatureInfoSegmentizeWktGeometry = staticmethod(QgsServerProjectUtils.wmsFeatureInfoSegmentizeWktGeometry)
|
||||||
QgsServerProjectUtils.wmsAddLegendGroupsLegendGraphic = staticmethod(QgsServerProjectUtils.wmsAddLegendGroupsLegendGraphic)
|
QgsServerProjectUtils.wmsAddLegendGroupsLegendGraphic = staticmethod(QgsServerProjectUtils.wmsAddLegendGroupsLegendGraphic)
|
||||||
QgsServerProjectUtils.wmsSkipNameForGroup = staticmethod(QgsServerProjectUtils.wmsSkipNameForGroup)
|
QgsServerProjectUtils.wmsSkipNameForGroup = staticmethod(QgsServerProjectUtils.wmsSkipNameForGroup)
|
||||||
|
@ -252,6 +252,20 @@ the feature info response
|
|||||||
feature info response
|
feature info response
|
||||||
%End
|
%End
|
||||||
|
|
||||||
|
static bool wmsHTMLFeatureInfoUseOnlyMaptip( const QgsProject &project );
|
||||||
|
%Docstring
|
||||||
|
Returns if only the maptip should be used for HTML feature info response
|
||||||
|
so that the HTML response to the feature info request only contains the
|
||||||
|
maptip. If no maptip is set, the HTML response is empty.
|
||||||
|
|
||||||
|
:param project: the QGIS project
|
||||||
|
|
||||||
|
:return: true if only the maptip should be used for the feature info
|
||||||
|
response only
|
||||||
|
|
||||||
|
.. versionadded:: 4.0
|
||||||
|
%End
|
||||||
|
|
||||||
static bool wmsFeatureInfoSegmentizeWktGeometry( const QgsProject &project );
|
static bool wmsFeatureInfoSegmentizeWktGeometry( const QgsProject &project );
|
||||||
%Docstring
|
%Docstring
|
||||||
Returns if the geometry has to be segmentize in GetFeatureInfo request.
|
Returns if the geometry has to be segmentize in GetFeatureInfo request.
|
||||||
|
@ -727,19 +727,25 @@ bool QgsPluginRegistry::checkPythonPlugin( const QString &packageName )
|
|||||||
bool QgsPluginRegistry::isPythonPluginCompatible( const QString &packageName ) const
|
bool QgsPluginRegistry::isPythonPluginCompatible( const QString &packageName ) const
|
||||||
{
|
{
|
||||||
#ifdef WITH_BINDINGS
|
#ifdef WITH_BINDINGS
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
|
bool supportsQgis4 = true;
|
||||||
const QString supportsQt6 = mPythonUtils->getPluginMetadata( packageName, QStringLiteral( "supportsQt6" ) ).trimmed();
|
const QString supportsQt6 = mPythonUtils->getPluginMetadata( packageName, QStringLiteral( "supportsQt6" ) ).trimmed();
|
||||||
if ( supportsQt6.compare( QLatin1String( "YES" ), Qt::CaseInsensitive ) != 0 && supportsQt6.compare( QLatin1String( "TRUE" ), Qt::CaseInsensitive ) != 0 )
|
if ( supportsQt6.compare( QLatin1String( "YES" ), Qt::CaseInsensitive ) != 0 && supportsQt6.compare( QLatin1String( "TRUE" ), Qt::CaseInsensitive ) != 0 )
|
||||||
{
|
{
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
|
||||||
if ( !getenv( "QGIS_DISABLE_SUPPORTS_QT6_CHECK" ) )
|
if ( !getenv( "QGIS_DISABLE_SUPPORTS_QT6_CHECK" ) )
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
supportsQgis4 = false;
|
||||||
|
}
|
||||||
const QString minVersion = mPythonUtils->getPluginMetadata( packageName, QStringLiteral( "qgisMinimumVersion" ) );
|
const QString minVersion = mPythonUtils->getPluginMetadata( packageName, QStringLiteral( "qgisMinimumVersion" ) );
|
||||||
// try to read qgisMaximumVersion. Note checkQgisVersion can cope with "__error__" value.
|
// try to read qgisMaximumVersion. Note checkQgisVersion can cope with "__error__" value.
|
||||||
const QString maxVersion = mPythonUtils->getPluginMetadata( packageName, QStringLiteral( "qgisMaximumVersion" ) );
|
QString maxVersion = mPythonUtils->getPluginMetadata( packageName, QStringLiteral( "qgisMaximumVersion" ) );
|
||||||
|
if ( maxVersion == QLatin1String( "__error__" ) && minVersion.startsWith( QLatin1String( "3." ) ) && supportsQgis4 )
|
||||||
|
{
|
||||||
|
maxVersion = QLatin1String( "4.99.0" );
|
||||||
|
}
|
||||||
return minVersion != QLatin1String( "__error__" ) && checkQgisVersion( minVersion, maxVersion );
|
return minVersion != QLatin1String( "__error__" ) && checkQgisVersion( minVersion, maxVersion );
|
||||||
#else
|
#else
|
||||||
Q_UNUSED( packageName )
|
Q_UNUSED( packageName )
|
||||||
|
@ -736,6 +736,9 @@ QgsProjectProperties::QgsProjectProperties( QgsMapCanvas *mapCanvas, QWidget *pa
|
|||||||
bool useAttributeFormSettings = QgsProject::instance()->readBoolEntry( QStringLiteral( "WMSFeatureInfoUseAttributeFormSettings" ), QStringLiteral( "/" ) );
|
bool useAttributeFormSettings = QgsProject::instance()->readBoolEntry( QStringLiteral( "WMSFeatureInfoUseAttributeFormSettings" ), QStringLiteral( "/" ) );
|
||||||
mUseAttributeFormSettingsCheckBox->setChecked( useAttributeFormSettings );
|
mUseAttributeFormSettingsCheckBox->setChecked( useAttributeFormSettings );
|
||||||
|
|
||||||
|
bool useOnlyMaptip = QgsProject::instance()->readBoolEntry( QStringLiteral( "WMSHTMLFeatureInfoUseOnlyMaptip" ), QStringLiteral( "/" ) );
|
||||||
|
mHTMLFiOnlyMaptip->setChecked( useOnlyMaptip );
|
||||||
|
|
||||||
bool addWktGeometry = QgsProject::instance()->readBoolEntry( QStringLiteral( "WMSAddWktGeometry" ), QStringLiteral( "/" ) );
|
bool addWktGeometry = QgsProject::instance()->readBoolEntry( QStringLiteral( "WMSAddWktGeometry" ), QStringLiteral( "/" ) );
|
||||||
mAddWktGeometryCheckBox->setChecked( addWktGeometry );
|
mAddWktGeometryCheckBox->setChecked( addWktGeometry );
|
||||||
|
|
||||||
@ -1566,6 +1569,7 @@ void QgsProjectProperties::apply()
|
|||||||
}
|
}
|
||||||
|
|
||||||
QgsProject::instance()->writeEntry( QStringLiteral( "WMSFeatureInfoUseAttributeFormSettings" ), QStringLiteral( "/" ), mUseAttributeFormSettingsCheckBox->isChecked() );
|
QgsProject::instance()->writeEntry( QStringLiteral( "WMSFeatureInfoUseAttributeFormSettings" ), QStringLiteral( "/" ), mUseAttributeFormSettingsCheckBox->isChecked() );
|
||||||
|
QgsProject::instance()->writeEntry( QStringLiteral( "WMSHTMLFeatureInfoUseOnlyMaptip" ), QStringLiteral( "/" ), mHTMLFiOnlyMaptip->isChecked() );
|
||||||
QgsProject::instance()->writeEntry( QStringLiteral( "WMSAddWktGeometry" ), QStringLiteral( "/" ), mAddWktGeometryCheckBox->isChecked() );
|
QgsProject::instance()->writeEntry( QStringLiteral( "WMSAddWktGeometry" ), QStringLiteral( "/" ), mAddWktGeometryCheckBox->isChecked() );
|
||||||
QgsProject::instance()->writeEntry( QStringLiteral( "WMSSegmentizeFeatureInfoGeometry" ), QStringLiteral( "/" ), mSegmentizeFeatureInfoGeometryCheckBox->isChecked() );
|
QgsProject::instance()->writeEntry( QStringLiteral( "WMSSegmentizeFeatureInfoGeometry" ), QStringLiteral( "/" ), mSegmentizeFeatureInfoGeometryCheckBox->isChecked() );
|
||||||
QgsProject::instance()->writeEntry( QStringLiteral( "WMSAddLayerGroupsLegendGraphic" ), QStringLiteral( "/" ), mAddLayerGroupsLegendGraphicCheckBox->isChecked() );
|
QgsProject::instance()->writeEntry( QStringLiteral( "WMSAddLayerGroupsLegendGraphic" ), QStringLiteral( "/" ), mAddLayerGroupsLegendGraphicCheckBox->isChecked() );
|
||||||
|
@ -1532,6 +1532,7 @@ void QgsLineString::visitPointsByRegularDistance( const double distance, const s
|
|||||||
double pZ = std::numeric_limits<double>::quiet_NaN();
|
double pZ = std::numeric_limits<double>::quiet_NaN();
|
||||||
double pM = std::numeric_limits<double>::quiet_NaN();
|
double pM = std::numeric_limits<double>::quiet_NaN();
|
||||||
double nextPointDistance = distance;
|
double nextPointDistance = distance;
|
||||||
|
const double eps = 4 * nextPointDistance * std::numeric_limits<double>::epsilon ();
|
||||||
for ( int i = 1; i < totalPoints; ++i )
|
for ( int i = 1; i < totalPoints; ++i )
|
||||||
{
|
{
|
||||||
double thisX = *x++;
|
double thisX = *x++;
|
||||||
@ -1540,7 +1541,7 @@ void QgsLineString::visitPointsByRegularDistance( const double distance, const s
|
|||||||
double thisM = m ? *m++ : 0.0;
|
double thisM = m ? *m++ : 0.0;
|
||||||
|
|
||||||
const double segmentLength = QgsGeometryUtilsBase::distance2D( thisX, thisY, prevX, prevY );
|
const double segmentLength = QgsGeometryUtilsBase::distance2D( thisX, thisY, prevX, prevY );
|
||||||
while ( nextPointDistance < distanceTraversed + segmentLength || qgsDoubleNear( nextPointDistance, distanceTraversed + segmentLength ) )
|
while ( nextPointDistance < distanceTraversed + segmentLength || qgsDoubleNear( nextPointDistance, distanceTraversed + segmentLength, eps ) )
|
||||||
{
|
{
|
||||||
// point falls on this segment - truncate to segment length if qgsDoubleNear test was actually > segment length
|
// point falls on this segment - truncate to segment length if qgsDoubleNear test was actually > segment length
|
||||||
const double distanceToPoint = std::min( nextPointDistance - distanceTraversed, segmentLength );
|
const double distanceToPoint = std::min( nextPointDistance - distanceTraversed, segmentLength );
|
||||||
|
@ -116,21 +116,6 @@ QStringList makeKeyTokens_( const QString &scope, const QString &key )
|
|||||||
// be sure to include the canonical root node
|
// be sure to include the canonical root node
|
||||||
keyTokens.push_front( QStringLiteral( "properties" ) );
|
keyTokens.push_front( QStringLiteral( "properties" ) );
|
||||||
|
|
||||||
//check validy of keys since an invalid xml name will will be dropped upon saving the xml file. If not valid, we print a message to the console.
|
|
||||||
for ( int i = 0; i < keyTokens.size(); ++i )
|
|
||||||
{
|
|
||||||
const QString keyToken = keyTokens.at( i );
|
|
||||||
|
|
||||||
//invalid chars in XML are found at http://www.w3.org/TR/REC-xml/#NT-NameChar
|
|
||||||
//note : it seems \x10000-\xEFFFF is valid, but it when added to the regexp, a lot of unwanted characters remain
|
|
||||||
const thread_local QRegularExpression sInvalidRegexp = QRegularExpression( QStringLiteral( "([^:A-Z_a-z\\x{C0}-\\x{D6}\\x{D8}-\\x{F6}\\x{F8}-\\x{2FF}\\x{370}-\\x{37D}\\x{37F}-\\x{1FFF}\\x{200C}-\\x{200D}\\x{2070}-\\x{218F}\\x{2C00}-\\x{2FEF}\\x{3001}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFFD}\\-\\.0-9\\x{B7}\\x{0300}-\\x{036F}\\x{203F}-\\x{2040}]|^[^:A-Z_a-z\\x{C0}-\\x{D6}\\x{D8}-\\x{F6}\\x{F8}-\\x{2FF}\\x{370}-\\x{37D}\\x{37F}-\\x{1FFF}\\x{200C}-\\x{200D}\\x{2070}-\\x{218F}\\x{2C00}-\\x{2FEF}\\x{3001}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFFD}])" ) );
|
|
||||||
if ( keyToken.contains( sInvalidRegexp ) )
|
|
||||||
{
|
|
||||||
const QString errorString = QObject::tr( "Entry token invalid : '%1'. The token will not be saved to file." ).arg( keyToken );
|
|
||||||
QgsMessageLog::logMessage( errorString, QString(), Qgis::MessageLevel::Critical );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return keyTokens;
|
return keyTokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1322,20 +1307,20 @@ void dump_( const QgsProjectPropertyKey &topQgsPropertyKey )
|
|||||||
* scope. "layers" is a list containing three string values.
|
* scope. "layers" is a list containing three string values.
|
||||||
*
|
*
|
||||||
* \code{.xml}
|
* \code{.xml}
|
||||||
* <properties>
|
* <properties name="properties">
|
||||||
* <fsplugin>
|
* <properties name="fsplugin">
|
||||||
* <foo type="int" >42</foo>
|
* <properties name="foo" type="int" >42</properties>
|
||||||
* <baz type="int" >1</baz>
|
* <properties name="baz" type="int" >1</properties>
|
||||||
* <layers type="QStringList" >
|
* <properties name="layers" type="QStringList">
|
||||||
* <value>railroad</value>
|
* <value>railroad</value>
|
||||||
* <value>airport</value>
|
* <value>airport</value>
|
||||||
* </layers>
|
* </properties>
|
||||||
* <xyqzzy type="int" >1</xyqzzy>
|
* <properties name="xyqzzy" type="int" >1</properties>
|
||||||
* <bar type="double" >123.456</bar>
|
* <properties name="bar" type="double" >123.456</properties>
|
||||||
* <feature_types type="QStringList" >
|
* <properties name="feature_types" type="QStringList">
|
||||||
* <value>type</value>
|
* <value>type</value>
|
||||||
* </feature_types>
|
* </properties>
|
||||||
* </fsplugin>
|
* </properties>
|
||||||
* </properties>
|
* </properties>
|
||||||
* \endcode
|
* \endcode
|
||||||
*
|
*
|
||||||
@ -3992,10 +3977,25 @@ bool QgsProject::createEmbeddedLayer( const QString &layerId, const QString &pro
|
|||||||
const QDomElement propertiesElem = sProjectDocument.documentElement().firstChildElement( QStringLiteral( "properties" ) );
|
const QDomElement propertiesElem = sProjectDocument.documentElement().firstChildElement( QStringLiteral( "properties" ) );
|
||||||
if ( !propertiesElem.isNull() )
|
if ( !propertiesElem.isNull() )
|
||||||
{
|
{
|
||||||
const QDomElement absElem = propertiesElem.firstChildElement( QStringLiteral( "Paths" ) ).firstChildElement( QStringLiteral( "Absolute" ) );
|
QDomElement e = propertiesElem.firstChildElement( QStringLiteral( "Paths" ) );
|
||||||
if ( !absElem.isNull() )
|
if ( e.isNull() )
|
||||||
{
|
{
|
||||||
useAbsolutePaths = absElem.text().compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0;
|
e = propertiesElem.firstChildElement( QStringLiteral( "properties" ) );
|
||||||
|
while ( !e.isNull() && e.attribute( QStringLiteral( "name" ) ) != QStringLiteral( "Paths" ) )
|
||||||
|
e = e.nextSiblingElement( QStringLiteral( "properties" ) );
|
||||||
|
|
||||||
|
e = e.firstChildElement( QStringLiteral( "properties" ) );
|
||||||
|
while ( !e.isNull() && e.attribute( QStringLiteral( "name" ) ) != QStringLiteral( "Absolute" ) )
|
||||||
|
e = e.nextSiblingElement( QStringLiteral( "properties" ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
e = e.firstChildElement( QStringLiteral( "Absolute" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !e.isNull() )
|
||||||
|
{
|
||||||
|
useAbsolutePaths = e.text().compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,12 +236,12 @@ bool QgsProjectPropertyValue::writeXml( QString const &nodeName,
|
|||||||
QDomElement &keyElement,
|
QDomElement &keyElement,
|
||||||
QDomDocument &document )
|
QDomDocument &document )
|
||||||
{
|
{
|
||||||
QDomElement valueElement = document.createElement( nodeName );
|
QDomElement valueElement = document.createElement( QStringLiteral( "properties" ) );
|
||||||
|
|
||||||
// remember the type so that we can rebuild it when the project is read in
|
// remember the type so that we can rebuild it when the project is read in
|
||||||
|
valueElement.setAttribute( QStringLiteral( "name" ), nodeName );
|
||||||
valueElement.setAttribute( QStringLiteral( "type" ), mValue.typeName() );
|
valueElement.setAttribute( QStringLiteral( "type" ), mValue.typeName() );
|
||||||
|
|
||||||
|
|
||||||
// we handle string lists differently from other types in that we
|
// we handle string lists differently from other types in that we
|
||||||
// create a sequence of repeated elements to cover all the string list
|
// create a sequence of repeated elements to cover all the string list
|
||||||
// members; each value will be in a <value></value> tag.
|
// members; each value will be in a <value></value> tag.
|
||||||
@ -362,33 +362,41 @@ bool QgsProjectPropertyKey::readXml( const QDomNode &keyNode )
|
|||||||
|
|
||||||
while ( i < subkeys.count() )
|
while ( i < subkeys.count() )
|
||||||
{
|
{
|
||||||
|
const QDomNode subkey = subkeys.item( i );
|
||||||
|
QString name;
|
||||||
|
|
||||||
|
if ( subkey.nodeName() == QStringLiteral( "properties" ) &&
|
||||||
|
subkey.hasAttributes() && // if we have attributes
|
||||||
|
subkey.isElement() && // and we're an element
|
||||||
|
subkey.toElement().hasAttribute( QStringLiteral( "name" ) ) ) // and we have a "name" attribute
|
||||||
|
name = subkey.toElement().attribute( QStringLiteral( "name" ) );
|
||||||
|
else
|
||||||
|
name = subkey.nodeName();
|
||||||
|
|
||||||
// if the current node is an element that has a "type" attribute,
|
// if the current node is an element that has a "type" attribute,
|
||||||
// then we know it's a leaf node; i.e., a subkey _value_, and not
|
// then we know it's a leaf node; i.e., a subkey _value_, and not
|
||||||
// a subkey
|
// a subkey
|
||||||
if ( subkeys.item( i ).hasAttributes() && // if we have attributes
|
if ( subkey.hasAttributes() && // if we have attributes
|
||||||
subkeys.item( i ).isElement() && // and we're an element
|
subkey.isElement() && // and we're an element
|
||||||
subkeys.item( i ).toElement().hasAttribute( QStringLiteral( "type" ) ) ) // and we have a "type" attribute
|
subkey.toElement().hasAttribute( QStringLiteral( "type" ) ) ) // and we have a "type" attribute
|
||||||
{
|
{
|
||||||
// then we're a key value
|
// then we're a key value
|
||||||
delete mProperties.take( subkeys.item( i ).nodeName() );
|
//
|
||||||
mProperties.insert( subkeys.item( i ).nodeName(), new QgsProjectPropertyValue );
|
delete mProperties.take( name );
|
||||||
|
mProperties.insert( name, new QgsProjectPropertyValue );
|
||||||
|
|
||||||
QDomNode subkey = subkeys.item( i );
|
if ( !mProperties[name]->readXml( subkey ) )
|
||||||
|
|
||||||
if ( !mProperties[subkeys.item( i ).nodeName()]->readXml( subkey ) )
|
|
||||||
{
|
{
|
||||||
QgsDebugError( QStringLiteral( "unable to parse key value %1" ).arg( subkeys.item( i ).nodeName() ) );
|
QgsDebugError( QStringLiteral( "unable to parse key value %1" ).arg( name ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // otherwise it's a subkey, so just recurse on down the remaining keys
|
else // otherwise it's a subkey, so just recurse on down the remaining keys
|
||||||
{
|
{
|
||||||
addKey( subkeys.item( i ).nodeName() );
|
addKey( name );
|
||||||
|
|
||||||
QDomNode subkey = subkeys.item( i );
|
if ( !mProperties[name]->readXml( subkey ) )
|
||||||
|
|
||||||
if ( !mProperties[subkeys.item( i ).nodeName()]->readXml( subkey ) )
|
|
||||||
{
|
{
|
||||||
QgsDebugError( QStringLiteral( "unable to parse subkey %1" ).arg( subkeys.item( i ).nodeName() ) );
|
QgsDebugError( QStringLiteral( "unable to parse subkey %1" ).arg( name ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,7 +416,8 @@ bool QgsProjectPropertyKey::writeXml( QString const &nodeName, QDomElement &elem
|
|||||||
// If it's an _empty_ node (i.e., one with no properties) we need to emit
|
// If it's an _empty_ node (i.e., one with no properties) we need to emit
|
||||||
// an empty place holder; else create new Dom elements as necessary.
|
// an empty place holder; else create new Dom elements as necessary.
|
||||||
|
|
||||||
QDomElement keyElement = document.createElement( nodeName ); // Dom element for this property key
|
QDomElement keyElement = document.createElement( "properties" ); // Dom element for this property key
|
||||||
|
keyElement.toElement().setAttribute( QStringLiteral( "name" ), nodeName );
|
||||||
|
|
||||||
if ( ! mProperties.isEmpty() )
|
if ( ! mProperties.isEmpty() )
|
||||||
{
|
{
|
||||||
|
@ -37,6 +37,8 @@ QString QgsProjectServerValidator::displayValidationError( QgsProjectServerValid
|
|||||||
return QObject::tr( "The project root name (either the project short name or project title) is not valid. It must start with an unaccented alphabetical letter, followed by any alphanumeric letters, dot, dash or underscore" );
|
return QObject::tr( "The project root name (either the project short name or project title) is not valid. It must start with an unaccented alphabetical letter, followed by any alphanumeric letters, dot, dash or underscore" );
|
||||||
case QgsProjectServerValidator::ProjectRootNameConflict:
|
case QgsProjectServerValidator::ProjectRootNameConflict:
|
||||||
return QObject::tr( "The project root name (either the project short name or project title) is already used by a layer or a group" );
|
return QObject::tr( "The project root name (either the project short name or project title) is already used by a layer or a group" );
|
||||||
|
case QgsProjectServerValidator::OnlyMaptipTrueButEmptyMaptip:
|
||||||
|
return QObject::tr( "Use only maptip for HTML GetFeatureInfo response is enabled but the HTML maptip is empty" );
|
||||||
}
|
}
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
@ -49,7 +51,7 @@ QString getShortName( T *node )
|
|||||||
return shortName.isEmpty() ? node->name() : shortName;
|
return shortName.isEmpty() ? node->name() : shortName;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QgsProjectServerValidator::browseLayerTree( QgsLayerTreeGroup *treeGroup, QStringList &owsNames, QStringList &encodingMessages )
|
void QgsProjectServerValidator::browseLayerTree( QgsLayerTreeGroup *treeGroup, QStringList &owsNames, QStringList &encodingMessages, QStringList &layerNames, QStringList &maptipTemplates )
|
||||||
{
|
{
|
||||||
const QList< QgsLayerTreeNode * > treeGroupChildren = treeGroup->children();
|
const QList< QgsLayerTreeNode * > treeGroupChildren = treeGroup->children();
|
||||||
for ( int i = 0; i < treeGroupChildren.size(); ++i )
|
for ( int i = 0; i < treeGroupChildren.size(); ++i )
|
||||||
@ -59,7 +61,7 @@ void QgsProjectServerValidator::browseLayerTree( QgsLayerTreeGroup *treeGroup, Q
|
|||||||
{
|
{
|
||||||
QgsLayerTreeGroup *treeGroupChild = static_cast<QgsLayerTreeGroup *>( treeNode );
|
QgsLayerTreeGroup *treeGroupChild = static_cast<QgsLayerTreeGroup *>( treeNode );
|
||||||
owsNames << getShortName( treeGroupChild );
|
owsNames << getShortName( treeGroupChild );
|
||||||
browseLayerTree( treeGroupChild, owsNames, encodingMessages );
|
browseLayerTree( treeGroupChild, owsNames, encodingMessages, layerNames, maptipTemplates );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -74,11 +76,22 @@ void QgsProjectServerValidator::browseLayerTree( QgsLayerTreeGroup *treeGroup, Q
|
|||||||
if ( vl->dataProvider() && vl->dataProvider()->encoding() == QLatin1String( "System" ) )
|
if ( vl->dataProvider() && vl->dataProvider()->encoding() == QLatin1String( "System" ) )
|
||||||
encodingMessages << layer->name();
|
encodingMessages << layer->name();
|
||||||
}
|
}
|
||||||
|
layerNames << treeLayer->name();
|
||||||
|
maptipTemplates << layer->mapTipTemplate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QgsProjectServerValidator::isOnlyMaptipEnabled( QgsProject *project )
|
||||||
|
{
|
||||||
|
return project->readBoolEntry(
|
||||||
|
QStringLiteral( "WMSHTMLFeatureInfoUseOnlyMaptip" ),
|
||||||
|
QString(),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
bool QgsProjectServerValidator::validate( QgsProject *project, QList<QgsProjectServerValidator::ValidationResult> &results )
|
bool QgsProjectServerValidator::validate( QgsProject *project, QList<QgsProjectServerValidator::ValidationResult> &results )
|
||||||
{
|
{
|
||||||
results.clear();
|
results.clear();
|
||||||
@ -90,8 +103,8 @@ bool QgsProjectServerValidator::validate( QgsProject *project, QList<QgsProjectS
|
|||||||
if ( !project->layerTreeRoot() )
|
if ( !project->layerTreeRoot() )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
QStringList owsNames, encodingMessages;
|
QStringList owsNames, encodingMessages, layerNames, maptipTemplates;
|
||||||
browseLayerTree( project->layerTreeRoot(), owsNames, encodingMessages );
|
browseLayerTree( project->layerTreeRoot(), owsNames, encodingMessages, layerNames, maptipTemplates );
|
||||||
|
|
||||||
QStringList duplicateNames, regExpMessages;
|
QStringList duplicateNames, regExpMessages;
|
||||||
const thread_local QRegularExpression snRegExp = QgsApplication::shortNameRegularExpression();
|
const thread_local QRegularExpression snRegExp = QgsApplication::shortNameRegularExpression();
|
||||||
@ -152,6 +165,24 @@ bool QgsProjectServerValidator::validate( QgsProject *project, QList<QgsProjectS
|
|||||||
results << ValidationResult( QgsProjectServerValidator::ProjectShortName, rootLayerName );
|
results << ValidationResult( QgsProjectServerValidator::ProjectShortName, rootLayerName );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ( isOnlyMaptipEnabled( project ) )
|
||||||
|
{
|
||||||
|
QStringList emptyLayers;
|
||||||
|
for ( int i = 0; i < maptipTemplates.size(); ++i )
|
||||||
|
{
|
||||||
|
if ( maptipTemplates[i].trimmed().isEmpty() )
|
||||||
|
emptyLayers << layerNames[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !emptyLayers.isEmpty() )
|
||||||
|
{
|
||||||
|
result = false;
|
||||||
|
QString details = emptyLayers.join( QLatin1String( ", " ) ).toHtmlEscaped();
|
||||||
|
results << ValidationResult(
|
||||||
|
QgsProjectServerValidator::OnlyMaptipTrueButEmptyMaptip,
|
||||||
|
details );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,7 @@ class CORE_EXPORT QgsProjectServerValidator
|
|||||||
LayerEncoding = 2, //!< Encoding is not correctly set on a vector layer.
|
LayerEncoding = 2, //!< Encoding is not correctly set on a vector layer.
|
||||||
ProjectShortName = 3, //!< The project short name is not valid.
|
ProjectShortName = 3, //!< The project short name is not valid.
|
||||||
ProjectRootNameConflict = 4, //!< The project root name is already used by a layer or a group.
|
ProjectRootNameConflict = 4, //!< The project root name is already used by a layer or a group.
|
||||||
|
OnlyMaptipTrueButEmptyMaptip = 5, //!< Use only maptip for HTML GetFeatureInfo response is enabled but HTML maptip is empty
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -92,7 +93,8 @@ class CORE_EXPORT QgsProjectServerValidator
|
|||||||
static bool validate( QgsProject *project, QList< QgsProjectServerValidator::ValidationResult > &results SIP_OUT );
|
static bool validate( QgsProject *project, QList< QgsProjectServerValidator::ValidationResult > &results SIP_OUT );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void browseLayerTree( QgsLayerTreeGroup *treeGroup, QStringList &owsNames, QStringList &encodingMessages );
|
static void browseLayerTree( QgsLayerTreeGroup *treeGroup, QStringList &owsNames, QStringList &encodingMessages, QStringList &layerNames, QStringList &maptipTemplates );
|
||||||
|
static bool isOnlyMaptipEnabled( QgsProject *project );
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -180,6 +180,12 @@ bool QgsServerProjectUtils::wmsFeatureInfoUseAttributeFormSettings( const QgsPro
|
|||||||
|| useFormSettings.compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0;
|
|| useFormSettings.compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QgsServerProjectUtils::wmsHTMLFeatureInfoUseOnlyMaptip( const QgsProject &project )
|
||||||
|
{
|
||||||
|
const QString useFormSettings = project.readEntry( QStringLiteral( "WMSHTMLFeatureInfoUseOnlyMaptip" ), QStringLiteral( "/" ), "" );
|
||||||
|
return useFormSettings.compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool QgsServerProjectUtils::wmsFeatureInfoSegmentizeWktGeometry( const QgsProject &project )
|
bool QgsServerProjectUtils::wmsFeatureInfoSegmentizeWktGeometry( const QgsProject &project )
|
||||||
{
|
{
|
||||||
const QString segmGeom = project.readEntry( QStringLiteral( "WMSSegmentizeFeatureInfoGeometry" ), QStringLiteral( "/" ), "" );
|
const QString segmGeom = project.readEntry( QStringLiteral( "WMSSegmentizeFeatureInfoGeometry" ), QStringLiteral( "/" ), "" );
|
||||||
|
@ -222,6 +222,16 @@ class SERVER_EXPORT QgsServerProjectUtils
|
|||||||
*/
|
*/
|
||||||
static bool wmsFeatureInfoUseAttributeFormSettings( const QgsProject &project );
|
static bool wmsFeatureInfoUseAttributeFormSettings( const QgsProject &project );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if only the maptip should be used for HTML feature info response so
|
||||||
|
* that the HTML response to the feature info request only contains the maptip.
|
||||||
|
* If no maptip is set, the HTML response is empty.
|
||||||
|
* \param project the QGIS project
|
||||||
|
* \returns true if only the maptip should be used for the feature info response only
|
||||||
|
* \since QGIS 4.0
|
||||||
|
*/
|
||||||
|
static bool wmsHTMLFeatureInfoUseOnlyMaptip( const QgsProject &project );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns if the geometry has to be segmentize in GetFeatureInfo request.
|
* Returns if the geometry has to be segmentize in GetFeatureInfo request.
|
||||||
* \param project the QGIS project
|
* \param project the QGIS project
|
||||||
|
@ -2009,7 +2009,7 @@ namespace QgsWms
|
|||||||
|
|
||||||
//add maptip attribute based on html/expression (in case there is no maptip attribute)
|
//add maptip attribute based on html/expression (in case there is no maptip attribute)
|
||||||
QString mapTip = layer->mapTipTemplate();
|
QString mapTip = layer->mapTipTemplate();
|
||||||
if ( !mapTip.isEmpty() && ( mWmsParameters.withMapTip() || mWmsParameters.htmlInfoOnlyMapTip() ) )
|
if ( !mapTip.isEmpty() && ( mWmsParameters.withMapTip() || mWmsParameters.htmlInfoOnlyMapTip() || QgsServerProjectUtils::wmsHTMLFeatureInfoUseOnlyMaptip( *mProject ) ) )
|
||||||
{
|
{
|
||||||
QDomElement maptipElem = infoDocument.createElement( QStringLiteral( "Attribute" ) );
|
QDomElement maptipElem = infoDocument.createElement( QStringLiteral( "Attribute" ) );
|
||||||
maptipElem.setAttribute( QStringLiteral( "name" ), QStringLiteral( "maptip" ) );
|
maptipElem.setAttribute( QStringLiteral( "name" ), QStringLiteral( "maptip" ) );
|
||||||
@ -2325,7 +2325,7 @@ namespace QgsWms
|
|||||||
}
|
}
|
||||||
//add maptip attribute based on html/expression
|
//add maptip attribute based on html/expression
|
||||||
QString mapTip = layer->mapTipTemplate();
|
QString mapTip = layer->mapTipTemplate();
|
||||||
if ( !mapTip.isEmpty() && ( mWmsParameters.withMapTip() || mWmsParameters.htmlInfoOnlyMapTip() ) )
|
if ( !mapTip.isEmpty() && ( mWmsParameters.withMapTip() || mWmsParameters.htmlInfoOnlyMapTip() || QgsServerProjectUtils::wmsHTMLFeatureInfoUseOnlyMaptip( *mProject ) ) )
|
||||||
{
|
{
|
||||||
QDomElement maptipElem = infoDocument.createElement( QStringLiteral( "Attribute" ) );
|
QDomElement maptipElem = infoDocument.createElement( QStringLiteral( "Attribute" ) );
|
||||||
maptipElem.setAttribute( QStringLiteral( "name" ), QStringLiteral( "maptip" ) );
|
maptipElem.setAttribute( QStringLiteral( "name" ), QStringLiteral( "maptip" ) );
|
||||||
@ -2586,7 +2586,7 @@ namespace QgsWms
|
|||||||
|
|
||||||
QByteArray QgsRenderer::convertFeatureInfoToHtml( const QDomDocument &doc ) const
|
QByteArray QgsRenderer::convertFeatureInfoToHtml( const QDomDocument &doc ) const
|
||||||
{
|
{
|
||||||
const bool onlyMapTip = mWmsParameters.htmlInfoOnlyMapTip();
|
const bool onlyMapTip = mWmsParameters.htmlInfoOnlyMapTip() || QgsServerProjectUtils::wmsHTMLFeatureInfoUseOnlyMaptip( *mProject );
|
||||||
QString featureInfoString = QStringLiteral( " <!DOCTYPE html>" );
|
QString featureInfoString = QStringLiteral( " <!DOCTYPE html>" );
|
||||||
if ( !onlyMapTip )
|
if ( !onlyMapTip )
|
||||||
{
|
{
|
||||||
@ -3203,7 +3203,7 @@ namespace QgsWms
|
|||||||
{
|
{
|
||||||
QString mapTip = layer->mapTipTemplate();
|
QString mapTip = layer->mapTipTemplate();
|
||||||
|
|
||||||
if ( !mapTip.isEmpty() && ( mWmsParameters.withMapTip() || mWmsParameters.htmlInfoOnlyMapTip() ) )
|
if ( !mapTip.isEmpty() && ( mWmsParameters.withMapTip() || mWmsParameters.htmlInfoOnlyMapTip() || QgsServerProjectUtils::wmsHTMLFeatureInfoUseOnlyMaptip( *mProject ) ) )
|
||||||
{
|
{
|
||||||
QString fieldTextString = QgsExpression::replaceExpressionText( mapTip, &expressionContext );
|
QString fieldTextString = QgsExpression::replaceExpressionText( mapTip, &expressionContext );
|
||||||
QDomElement fieldElem = doc.createElement( QStringLiteral( "qgs:maptip" ) );
|
QDomElement fieldElem = doc.createElement( QStringLiteral( "qgs:maptip" ) );
|
||||||
|
@ -2730,6 +2730,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QCheckBox" name="mHTMLFiOnlyMaptip">
|
||||||
|
<property name="text">
|
||||||
|
<string>Use only maptip for HTML GetFeatureInfo (empty response when maptip template is missing)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QCheckBox" name="mWmsUseLayerIDs">
|
<widget class="QCheckBox" name="mWmsUseLayerIDs">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -2737,7 +2744,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="0">
|
<item row="5" column="0">
|
||||||
<layout class="QHBoxLayout" name="grpWMSPrecision">
|
<layout class="QHBoxLayout" name="grpWMSPrecision">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label_5">
|
<widget class="QLabel" name="label_5">
|
||||||
@ -2761,21 +2768,21 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
<item row="4" column="0">
|
||||||
<widget class="QCheckBox" name="mSegmentizeFeatureInfoGeometryCheckBox">
|
<widget class="QCheckBox" name="mSegmentizeFeatureInfoGeometryCheckBox">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Segmentize feature info geometry</string>
|
<string>Segmentize feature info geometry</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="3" column="0">
|
||||||
<widget class="QCheckBox" name="mAddWktGeometryCheckBox">
|
<widget class="QCheckBox" name="mAddWktGeometryCheckBox">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Add geometry to feature response</string>
|
<string>Add geometry to feature response</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="0">
|
<item row="6" column="0">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="mWMSUrlLabel">
|
<widget class="QLabel" name="mWMSUrlLabel">
|
||||||
@ -3765,6 +3772,7 @@
|
|||||||
<tabstop>mWMSInspireMetadataDate</tabstop>
|
<tabstop>mWMSInspireMetadataDate</tabstop>
|
||||||
<tabstop>mWmsUseLayerIDs</tabstop>
|
<tabstop>mWmsUseLayerIDs</tabstop>
|
||||||
<tabstop>mUseAttributeFormSettingsCheckBox</tabstop>
|
<tabstop>mUseAttributeFormSettingsCheckBox</tabstop>
|
||||||
|
<tabstop>mHTMLFiOnlyMaptip</tabstop>
|
||||||
<tabstop>mAddWktGeometryCheckBox</tabstop>
|
<tabstop>mAddWktGeometryCheckBox</tabstop>
|
||||||
<tabstop>mSegmentizeFeatureInfoGeometryCheckBox</tabstop>
|
<tabstop>mSegmentizeFeatureInfoGeometryCheckBox</tabstop>
|
||||||
<tabstop>mWMSPrecisionSpinBox</tabstop>
|
<tabstop>mWMSPrecisionSpinBox</tabstop>
|
||||||
|
@ -65,84 +65,6 @@ class TestQgsProject(QgisTestCase):
|
|||||||
QgisTestCase.__init__(self, methodName)
|
QgisTestCase.__init__(self, methodName)
|
||||||
self.messageCaught = False
|
self.messageCaught = False
|
||||||
|
|
||||||
def test_makeKeyTokens_(self):
|
|
||||||
# see http://www.w3.org/TR/REC-xml/#d0e804 for a list of valid characters
|
|
||||||
|
|
||||||
invalidTokens = []
|
|
||||||
validTokens = []
|
|
||||||
|
|
||||||
# all test tokens will be generated by prepending or inserting characters to this token
|
|
||||||
validBase = "valid"
|
|
||||||
|
|
||||||
# some invalid characters, not allowed anywhere in a token
|
|
||||||
# note that '/' must not be added here because it is taken as a separator by makeKeyTokens_()
|
|
||||||
invalidChars = "+*,;<>|!$%()=?#\x01"
|
|
||||||
|
|
||||||
# generate the characters that are allowed at the start of a token (and at every other position)
|
|
||||||
validStartChars = ":_"
|
|
||||||
charRanges = [
|
|
||||||
(ord("a"), ord("z")),
|
|
||||||
(ord("A"), ord("Z")),
|
|
||||||
(0x00F8, 0x02FF),
|
|
||||||
(0x0370, 0x037D),
|
|
||||||
(0x037F, 0x1FFF),
|
|
||||||
(0x200C, 0x200D),
|
|
||||||
(0x2070, 0x218F),
|
|
||||||
(0x2C00, 0x2FEF),
|
|
||||||
(0x3001, 0xD7FF),
|
|
||||||
(0xF900, 0xFDCF),
|
|
||||||
(0xFDF0, 0xFFFD),
|
|
||||||
# (0x10000, 0xEFFFF), while actually valid, these are not yet accepted by makeKeyTokens_()
|
|
||||||
]
|
|
||||||
for r in charRanges:
|
|
||||||
for c in range(r[0], r[1]):
|
|
||||||
validStartChars += chr(c)
|
|
||||||
|
|
||||||
# generate the characters that are only allowed inside a token, not at the start
|
|
||||||
validInlineChars = "-.\xB7"
|
|
||||||
charRanges = [
|
|
||||||
(ord("0"), ord("9")),
|
|
||||||
(0x0300, 0x036F),
|
|
||||||
(0x203F, 0x2040),
|
|
||||||
]
|
|
||||||
for r in charRanges:
|
|
||||||
for c in range(r[0], r[1]):
|
|
||||||
validInlineChars += chr(c)
|
|
||||||
|
|
||||||
# test forbidden start characters
|
|
||||||
for c in invalidChars + validInlineChars:
|
|
||||||
invalidTokens.append(c + validBase)
|
|
||||||
|
|
||||||
# test forbidden inline characters
|
|
||||||
for c in invalidChars:
|
|
||||||
invalidTokens.append(validBase[:4] + c + validBase[4:])
|
|
||||||
|
|
||||||
# test each allowed start character
|
|
||||||
for c in validStartChars:
|
|
||||||
validTokens.append(c + validBase)
|
|
||||||
|
|
||||||
# test each allowed inline character
|
|
||||||
for c in validInlineChars:
|
|
||||||
validTokens.append(validBase[:4] + c + validBase[4:])
|
|
||||||
|
|
||||||
logger = QgsApplication.messageLog()
|
|
||||||
logger.messageReceived.connect(self.catchMessage)
|
|
||||||
prj = QgsProject.instance()
|
|
||||||
|
|
||||||
for token in validTokens:
|
|
||||||
self.messageCaught = False
|
|
||||||
prj.readEntry("test", token)
|
|
||||||
myMessage = f"valid token '{token}' not accepted"
|
|
||||||
assert not self.messageCaught, myMessage
|
|
||||||
|
|
||||||
for token in invalidTokens:
|
|
||||||
self.messageCaught = False
|
|
||||||
prj.readEntry("test", token)
|
|
||||||
myMessage = f"invalid token '{token}' accepted"
|
|
||||||
assert self.messageCaught, myMessage
|
|
||||||
|
|
||||||
logger.messageReceived.disconnect(self.catchMessage)
|
|
||||||
|
|
||||||
def catchMessage(self):
|
def catchMessage(self):
|
||||||
self.messageCaught = True
|
self.messageCaught = True
|
||||||
|
|
||||||
|
@ -124,6 +124,60 @@ class TestQgsprojectServerValidator(QgisTestCase):
|
|||||||
results[0].error,
|
results[0].error,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_empty_maptip_enabled(self):
|
||||||
|
"""Empty maptip must fail when only‐maptip is enabled."""
|
||||||
|
project = QgsProject()
|
||||||
|
layer = QgsVectorLayer("Point?field=fldtxt:string", "testlayer", "memory")
|
||||||
|
project.addMapLayers([layer])
|
||||||
|
layer.setMapTipTemplate("")
|
||||||
|
project.writeEntry("WMSHTMLFeatureInfoUseOnlyMaptip", "", True)
|
||||||
|
valid, results = QgsProjectServerValidator.validate(project)
|
||||||
|
self.assertFalse(valid)
|
||||||
|
self.assertEqual(1, len(results))
|
||||||
|
self.assertEqual(
|
||||||
|
QgsProjectServerValidator.ValidationError.OnlyMaptipTrueButEmptyMaptip,
|
||||||
|
results[0].error,
|
||||||
|
)
|
||||||
|
# Explicitly enable MapTips — should still fail
|
||||||
|
layer.setMapTipsEnabled(True)
|
||||||
|
valid2, results2 = QgsProjectServerValidator.validate(project)
|
||||||
|
self.assertFalse(valid2)
|
||||||
|
self.assertEqual(1, len(results2))
|
||||||
|
self.assertEqual(
|
||||||
|
QgsProjectServerValidator.ValidationError.OnlyMaptipTrueButEmptyMaptip,
|
||||||
|
results2[0].error,
|
||||||
|
)
|
||||||
|
# Explicitly disable MapTips — should still fail
|
||||||
|
layer.setMapTipsEnabled(False)
|
||||||
|
valid3, results3 = QgsProjectServerValidator.validate(project)
|
||||||
|
self.assertFalse(valid3)
|
||||||
|
self.assertEqual(1, len(results3))
|
||||||
|
self.assertEqual(
|
||||||
|
QgsProjectServerValidator.ValidationError.OnlyMaptipTrueButEmptyMaptip,
|
||||||
|
results3[0].error,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_empty_maptip_disabled(self):
|
||||||
|
"""Empty maptip must pass when only‐maptip is disabled."""
|
||||||
|
project = QgsProject()
|
||||||
|
layer = QgsVectorLayer("Point?field=fldtxt:string", "testlayer", "memory")
|
||||||
|
project.addMapLayers([layer])
|
||||||
|
layer.setMapTipTemplate("")
|
||||||
|
project.writeEntry("WMSHTMLFeatureInfoUseOnlyMaptip", "", False)
|
||||||
|
valid, results = QgsProjectServerValidator.validate(project)
|
||||||
|
self.assertTrue(valid)
|
||||||
|
self.assertEqual(0, len(results))
|
||||||
|
# Explicitly enable MapTips — should still pass
|
||||||
|
layer.setMapTipsEnabled(True)
|
||||||
|
valid2, results2 = QgsProjectServerValidator.validate(project)
|
||||||
|
self.assertTrue(valid2)
|
||||||
|
self.assertEqual(0, len(results2))
|
||||||
|
# Explicitly disable MapTips — should still pass
|
||||||
|
layer.setMapTipsEnabled(False)
|
||||||
|
valid3, results3 = QgsProjectServerValidator.validate(project)
|
||||||
|
self.assertTrue(valid3)
|
||||||
|
self.assertEqual(0, len(results3))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@ -174,7 +174,7 @@ class TestQgsServerWMSGetFeatureInfo(TestQgsServerWMSTestBase):
|
|||||||
"wms_getfeatureinfo-text-html-maptip",
|
"wms_getfeatureinfo-text-html-maptip",
|
||||||
)
|
)
|
||||||
|
|
||||||
# Test getfeatureinfo response html only with maptip for vector layer
|
# Test getfeatureinfo response html only with maptip for vector layer (URL parameter)
|
||||||
self.wms_request_compare(
|
self.wms_request_compare(
|
||||||
"GetFeatureInfo",
|
"GetFeatureInfo",
|
||||||
"&layers=testlayer%20%C3%A8%C3%A9&styles=&"
|
"&layers=testlayer%20%C3%A8%C3%A9&styles=&"
|
||||||
@ -186,6 +186,18 @@ class TestQgsServerWMSGetFeatureInfo(TestQgsServerWMSTestBase):
|
|||||||
"wms_getfeatureinfo-html-only-with-maptip-vector",
|
"wms_getfeatureinfo-html-only-with-maptip-vector",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Test getfeatureinfo response html only with maptip for vector layer (project settings)
|
||||||
|
self.wms_request_compare(
|
||||||
|
"GetFeatureInfo",
|
||||||
|
"&layers=testlayer%20%C3%A8%C3%A9&styles=&"
|
||||||
|
+ "info_format=text%2Fhtml&transparent=true&"
|
||||||
|
+ "width=600&height=400&srs=EPSG%3A3857&bbox=913190.6389747962%2C"
|
||||||
|
+ "5606005.488876367%2C913235.426296057%2C5606035.347090538&"
|
||||||
|
+ "query_layers=testlayer%20%C3%A8%C3%A9&X=190&Y=320",
|
||||||
|
"wms_getfeatureinfo-html-only-with-maptip-vector",
|
||||||
|
"test_project_html_gfi_maptip_only.qgs",
|
||||||
|
)
|
||||||
|
|
||||||
# Test getfeatureinfo response html with maptip and display name in text mode for vector layer
|
# Test getfeatureinfo response html with maptip and display name in text mode for vector layer
|
||||||
self.wms_request_compare(
|
self.wms_request_compare(
|
||||||
"GetFeatureInfo",
|
"GetFeatureInfo",
|
||||||
@ -352,7 +364,7 @@ class TestQgsServerWMSGetFeatureInfo(TestQgsServerWMSTestBase):
|
|||||||
"wms_getfeatureinfo-raster-text-xml-maptip",
|
"wms_getfeatureinfo-raster-text-xml-maptip",
|
||||||
)
|
)
|
||||||
|
|
||||||
# Test GetFeatureInfo on raster layer HTML only with maptip
|
# Test GetFeatureInfo on raster layer HTML only with maptip (URL parameter)
|
||||||
self.wms_request_compare(
|
self.wms_request_compare(
|
||||||
"GetFeatureInfo",
|
"GetFeatureInfo",
|
||||||
"&layers=landsat&styles=&"
|
"&layers=landsat&styles=&"
|
||||||
@ -364,6 +376,18 @@ class TestQgsServerWMSGetFeatureInfo(TestQgsServerWMSTestBase):
|
|||||||
"wms_getfeatureinfo-html-only-with-maptip-raster",
|
"wms_getfeatureinfo-html-only-with-maptip-raster",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Test GetFeatureInfo on raster layer HTML only with maptip (project settings)
|
||||||
|
self.wms_request_compare(
|
||||||
|
"GetFeatureInfo",
|
||||||
|
"&layers=landsat&styles=&"
|
||||||
|
+ "info_format=text%2Fhtml&transparent=true&"
|
||||||
|
+ "width=500&height=500&srs=EPSG%3A3857&"
|
||||||
|
+ "bbox=1989139.6,3522745.0,2015014.9,3537004.5&"
|
||||||
|
+ "query_layers=landsat&X=250&Y=250",
|
||||||
|
"wms_getfeatureinfo-html-only-with-maptip-raster",
|
||||||
|
"test_project_html_gfi_maptip_only.qgs",
|
||||||
|
)
|
||||||
|
|
||||||
def testGetFeatureInfoValueRelation(self):
|
def testGetFeatureInfoValueRelation(self):
|
||||||
"""Test GetFeatureInfo resolves "value relation" widget values. regression 18518"""
|
"""Test GetFeatureInfo resolves "value relation" widget values. regression 18518"""
|
||||||
mypath = self.testdata_path + "test_project_values.qgz"
|
mypath = self.testdata_path + "test_project_values.qgz"
|
||||||
|
4860
tests/testdata/qgis_server/test_project_html_gfi_maptip_only.qgs
vendored
Normal file
4860
tests/testdata/qgis_server/test_project_html_gfi_maptip_only.qgs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user