Skip to content

Commit 2ac6013

Browse files
committedNov 10, 2018
[afs] Fix missing layers/services when connection url does
not point at an individual service endpoint Previously the provider would only show layers if a FeatureService endpoint was used for the url, and would show nothing if users enter the base server url. Fix this by implementing a tree view for AFS items so that if users enter a connection url at a higher level than we show nested services/folders containing the layers. (cherry picked from commit b2d2634)
1 parent 3730579 commit 2ac6013

9 files changed

+389
-83
lines changed
 

‎src/core/qgsstringutils.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ QString QgsStringUtils::insertLinks( const QString &string, bool *foundLinks )
431431
{
432432
found = true;
433433
QString email = emailRegEx.cap( 1 );
434-
QString anchor = QStringLiteral( "<a href=\"mailto:%1\">%1</a>" ).arg( email.toHtmlEscaped(), email.toHtmlEscaped() );
434+
QString anchor = QStringLiteral( "<a href=\"mailto:%1\">%1</a>" ).arg( email.toHtmlEscaped() );
435435
converted.replace( emailRegEx.pos( 1 ), email.length(), anchor );
436436
offset = emailRegEx.pos( 1 ) + anchor.length();
437437
}

‎src/providers/arcgisrest/qgsafsdataitems.cpp

Lines changed: 168 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,65 @@ void QgsAfsRootItem::newConnection()
8484

8585
///////////////////////////////////////////////////////////////////////////////
8686

87+
void addFolderItems( QVector< QgsDataItem * > &items, const QVariantMap &serviceData, const QString &baseUrl, const QString &authcfg, QgsDataItem *parent )
88+
{
89+
QgsArcGisRestUtils::visitFolderItems( [parent, &baseUrl, &items, authcfg]( const QString & name, const QString & url )
90+
{
91+
std::unique_ptr< QgsAfsFolderItem > folderItem = qgis::make_unique< QgsAfsFolderItem >( parent, name, url, baseUrl, authcfg );
92+
items.append( folderItem.release() );
93+
}, serviceData, baseUrl );
94+
}
95+
96+
void addServiceItems( QVector< QgsDataItem * > &items, const QVariantMap &serviceData, const QString &baseUrl, const QString &authcfg, QgsDataItem *parent,
97+
const QString &parentName )
98+
{
99+
QgsArcGisRestUtils::visitServiceItems(
100+
[&items, parent, authcfg]( const QString & name, const QString & url )
101+
{
102+
std::unique_ptr< QgsAfsServiceItem > serviceItem = qgis::make_unique< QgsAfsServiceItem >( parent, name, url, url, authcfg );
103+
items.append( serviceItem.release() );
104+
}, serviceData, baseUrl, parentName );
105+
}
106+
107+
void addLayerItems( QVector< QgsDataItem * > &items, const QVariantMap &serviceData, const QString &parentUrl, const QString &authcfg, QgsDataItem *parent )
108+
{
109+
QMap< QString, QgsDataItem * > layerItems;
110+
QMap< QString, QString > parents;
111+
112+
QgsArcGisRestUtils::addLayerItems( [parent, &layerItems, &parents, authcfg]( const QString & parentLayerId, const QString & id, const QString & name, const QString & description, const QString & url, bool isParent, const QString & authid )
113+
{
114+
Q_UNUSED( description );
115+
116+
if ( !parentLayerId.isEmpty() )
117+
parents.insert( id, parentLayerId );
118+
119+
if ( isParent )
120+
{
121+
std::unique_ptr< QgsAfsParentLayerItem > layerItem = qgis::make_unique< QgsAfsParentLayerItem >( parent, name, url, authcfg );
122+
layerItems.insert( id, layerItem.release() );
123+
}
124+
else
125+
{
126+
std::unique_ptr< QgsAfsLayerItem > layerItem = qgis::make_unique< QgsAfsLayerItem >( parent, name, url, name, authid, authcfg );
127+
layerItems.insert( id, layerItem.release() );
128+
}
129+
130+
}, serviceData, parentUrl );
131+
132+
// create groups
133+
for ( auto it = layerItems.constBegin(); it != layerItems.constEnd(); ++it )
134+
{
135+
const QString id = it.key();
136+
QgsDataItem *item = it.value();
137+
const QString parentId = parents.value( id );
138+
139+
if ( QgsDataItem *layerParent = parentId.isEmpty() ? nullptr : layerItems.value( parentId ) )
140+
layerParent->addChildItem( item );
141+
else
142+
items.append( item );
143+
}
144+
}
145+
87146
QgsAfsConnectionItem::QgsAfsConnectionItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &connectionName )
88147
: QgsDataCollectionItem( parent, name, path )
89148
, mConnName( connectionName )
@@ -98,7 +157,7 @@ QVector<QgsDataItem *> QgsAfsConnectionItem::createChildren()
98157
const QString url = connection.uri().param( QStringLiteral( "url" ) );
99158
const QString authcfg = connection.uri().param( QStringLiteral( "authcfg" ) );
100159

101-
QVector<QgsDataItem *> layers;
160+
QVector<QgsDataItem *> items;
102161
QString errorTitle, errorMessage;
103162
const QVariantMap serviceData = QgsArcGisRestUtils::getServiceInfo( url, authcfg, errorTitle, errorMessage );
104163
if ( serviceData.isEmpty() )
@@ -107,29 +166,17 @@ QVector<QgsDataItem *> QgsAfsConnectionItem::createChildren()
107166
{
108167
std::unique_ptr< QgsErrorItem > error = qgis::make_unique< QgsErrorItem >( this, tr( "Connection failed: %1" ).arg( errorTitle ), mPath + "/error" );
109168
error->setToolTip( errorMessage );
110-
layers.append( error.release() );
169+
items.append( error.release() );
111170
QgsDebugMsg( "Connection failed - " + errorMessage );
112171
}
113-
return layers;
172+
return items;
114173
}
115-
const QString authid = QgsArcGisRestUtils::parseSpatialReference( serviceData.value( QStringLiteral( "spatialReference" ) ).toMap() ).authid();
116174

117-
const QVariantList layerInfoList = serviceData[QStringLiteral( "layers" )].toList();
118-
for ( const QVariant &layerInfo : layerInfoList )
119-
{
120-
const QVariantMap layerInfoMap = layerInfo.toMap();
121-
if ( !layerInfoMap.value( QStringLiteral( "subLayerIds" ) ).toList().empty() )
122-
{
123-
// group layer - do not show as it is not possible to load
124-
// TODO - show nested groups
125-
continue;
126-
}
127-
const QString id = layerInfoMap.value( QStringLiteral( "id" ) ).toString();
128-
QgsAfsLayerItem *layer = new QgsAfsLayerItem( this, mName, url + '/' + id, layerInfoMap.value( QStringLiteral( "name" ) ).toString(), authid, authcfg );
129-
layers.append( layer );
130-
}
175+
addFolderItems( items, serviceData, url, authcfg, this );
176+
addServiceItems( items, serviceData, url, authcfg, this, QString() );
177+
addLayerItems( items, serviceData, url, authcfg, this );
131178

132-
return layers;
179+
return items;
133180
}
134181

135182
bool QgsAfsConnectionItem::equal( const QgsDataItem *other )
@@ -199,18 +246,117 @@ void QgsAfsConnectionItem::refreshConnection()
199246
}
200247
#endif
201248

202-
///////////////////////////////////////////////////////////////////////////////
203249

204-
QgsAfsLayerItem::QgsAfsLayerItem( QgsDataItem *parent, const QString &name, const QString &url, const QString &title, const QString &authid, const QString &authcfg )
205-
: QgsLayerItem( parent, title, parent->path() + "/" + name, QString(), QgsLayerItem::Vector, QStringLiteral( "arcgisfeatureserver" ) )
250+
QgsAfsFolderItem::QgsAfsFolderItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &baseUrl, const QString &authcfg )
251+
: QgsDataCollectionItem( parent, name, path )
252+
, mBaseUrl( baseUrl )
253+
, mAuthCfg( authcfg )
254+
{
255+
mIconName = QStringLiteral( "mIconDbSchema.svg" );
256+
mCapabilities |= Collapse;
257+
setToolTip( path );
258+
}
259+
260+
261+
QVector<QgsDataItem *> QgsAfsFolderItem::createChildren()
262+
{
263+
const QString url = mPath;
264+
265+
QVector<QgsDataItem *> items;
266+
QString errorTitle, errorMessage;
267+
const QVariantMap serviceData = QgsArcGisRestUtils::getServiceInfo( url, mAuthCfg, errorTitle, errorMessage );
268+
if ( serviceData.isEmpty() )
269+
{
270+
if ( !errorMessage.isEmpty() )
271+
{
272+
std::unique_ptr< QgsErrorItem > error = qgis::make_unique< QgsErrorItem >( this, tr( "Connection failed: %1" ).arg( errorTitle ), mPath + "/error" );
273+
error->setToolTip( errorMessage );
274+
items.append( error.release() );
275+
QgsDebugMsg( "Connection failed - " + errorMessage );
276+
}
277+
return items;
278+
}
279+
280+
addFolderItems( items, serviceData, mBaseUrl, mAuthCfg, this );
281+
addServiceItems( items, serviceData, mBaseUrl, mAuthCfg, this, mName );
282+
addLayerItems( items, serviceData, mPath, mAuthCfg, this );
283+
return items;
284+
}
285+
286+
bool QgsAfsFolderItem::equal( const QgsDataItem *other )
287+
{
288+
const QgsAfsFolderItem *o = qobject_cast<const QgsAfsFolderItem *>( other );
289+
return ( type() == other->type() && o && mPath == o->mPath && mName == o->mName );
290+
}
291+
292+
QgsAfsServiceItem::QgsAfsServiceItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &baseUrl, const QString &authcfg )
293+
: QgsDataCollectionItem( parent, name, path )
294+
, mBaseUrl( baseUrl )
295+
, mAuthCfg( authcfg )
296+
{
297+
mIconName = QStringLiteral( "mIconDbSchema.svg" );
298+
mCapabilities |= Collapse;
299+
setToolTip( path );
300+
}
301+
302+
QVector<QgsDataItem *> QgsAfsServiceItem::createChildren()
303+
{
304+
const QString url = mPath;
305+
306+
QVector<QgsDataItem *> items;
307+
QString errorTitle, errorMessage;
308+
const QVariantMap serviceData = QgsArcGisRestUtils::getServiceInfo( url, mAuthCfg, errorTitle, errorMessage );
309+
if ( serviceData.isEmpty() )
310+
{
311+
if ( !errorMessage.isEmpty() )
312+
{
313+
std::unique_ptr< QgsErrorItem > error = qgis::make_unique< QgsErrorItem >( this, tr( "Connection failed: %1" ).arg( errorTitle ), mPath + "/error" );
314+
error->setToolTip( errorMessage );
315+
items.append( error.release() );
316+
QgsDebugMsg( "Connection failed - " + errorMessage );
317+
}
318+
return items;
319+
}
320+
321+
addFolderItems( items, serviceData, mBaseUrl, mAuthCfg, this );
322+
addServiceItems( items, serviceData, mBaseUrl, mAuthCfg, this, mName );
323+
addLayerItems( items, serviceData, mPath, mAuthCfg, this );
324+
return items;
325+
}
326+
327+
bool QgsAfsServiceItem::equal( const QgsDataItem *other )
328+
{
329+
const QgsAfsServiceItem *o = qobject_cast<const QgsAfsServiceItem *>( other );
330+
return ( type() == other->type() && o && mPath == o->mPath && mName == o->mName );
331+
}
332+
333+
QgsAfsLayerItem::QgsAfsLayerItem( QgsDataItem *parent, const QString &, const QString &url, const QString &title, const QString &authid, const QString &authcfg )
334+
: QgsLayerItem( parent, title, url, QString(), QgsLayerItem::Vector, QStringLiteral( "arcgisfeatureserver" ) )
206335
{
207336
mUri = QStringLiteral( "crs='%1' url='%2'" ).arg( authid, url );
208337
if ( !authcfg.isEmpty() )
209338
mUri += QStringLiteral( " authcfg='%1'" ).arg( authcfg );
210339
setState( Populated );
211340
mIconName = QStringLiteral( "mIconAfs.svg" );
341+
setToolTip( url );
342+
}
343+
344+
QgsAfsParentLayerItem::QgsAfsParentLayerItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &authcfg )
345+
: QgsDataItem( QgsDataItem::Collection, parent, name, path )
346+
, mAuthCfg( authcfg )
347+
{
348+
mCapabilities |= Fast;
349+
mIconName = QStringLiteral( "mIconDbSchema.svg" );
350+
setToolTip( path );
212351
}
213352

353+
bool QgsAfsParentLayerItem::equal( const QgsDataItem *other )
354+
{
355+
const QgsAfsParentLayerItem *o = qobject_cast<const QgsAfsParentLayerItem *>( other );
356+
return ( type() == other->type() && o && mPath == o->mPath && mName == o->mName );
357+
}
358+
359+
214360
//
215361
// QgsAfsDataItemProvider
216362
//

‎src/providers/arcgisrest/qgsafsdataitems.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,56 @@ class QgsAfsConnectionItem : public QgsDataCollectionItem
6464
QString mConnName;
6565
};
6666

67+
class QgsAfsFolderItem : public QgsDataCollectionItem
68+
{
69+
Q_OBJECT
70+
public:
71+
QgsAfsFolderItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &baseUrl, const QString &authcfg );
72+
QVector<QgsDataItem *> createChildren() override;
73+
bool equal( const QgsDataItem *other ) override;
74+
75+
private:
76+
QString mFolder;
77+
QString mBaseUrl;
78+
QString mAuthCfg;
79+
};
80+
81+
class QgsAfsServiceItem : public QgsDataCollectionItem
82+
{
83+
Q_OBJECT
84+
public:
85+
QgsAfsServiceItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &baseUrl, const QString &authcfg );
86+
QVector<QgsDataItem *> createChildren() override;
87+
bool equal( const QgsDataItem *other ) override;
88+
89+
private:
90+
QString mFolder;
91+
QString mBaseUrl;
92+
QString mAuthCfg;
93+
};
94+
95+
class QgsAfsParentLayerItem : public QgsDataItem
96+
{
97+
Q_OBJECT
98+
public:
99+
100+
QgsAfsParentLayerItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &authcfg );
101+
bool equal( const QgsDataItem *other ) override;
102+
103+
private:
104+
105+
QString mAuthCfg;
106+
107+
};
67108

68109
class QgsAfsLayerItem : public QgsLayerItem
69110
{
70111
Q_OBJECT
71112

72113
public:
114+
73115
QgsAfsLayerItem( QgsDataItem *parent, const QString &name, const QString &url, const QString &title, const QString &authid, const QString &authcfg );
116+
74117
};
75118

76119
//! Provider for afs root data item

‎src/providers/arcgisrest/qgsafssourceselect.cpp

Lines changed: 102 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -39,68 +39,116 @@ bool QgsAfsSourceSelect::connectToService( const QgsOwsConnection &connection )
3939
QString errorTitle, errorMessage;
4040

4141
const QString authcfg = connection.uri().param( QStringLiteral( "authcfg" ) );
42-
QVariantMap serviceInfoMap = QgsArcGisRestUtils::getServiceInfo( connection.uri().param( QStringLiteral( "url" ) ), authcfg, errorTitle, errorMessage );
43-
if ( serviceInfoMap.isEmpty() )
44-
{
45-
QMessageBox::warning( this, tr( "Error" ), tr( "Failed to retrieve service capabilities:\n%1: %2" ).arg( errorTitle, errorMessage ) );
46-
return false;
47-
}
42+
const QString baseUrl = connection.uri().param( QStringLiteral( "url" ) );
4843

49-
QStringList layerErrors;
50-
const QVariantList layers = serviceInfoMap.value( QStringLiteral( "layers" ) ).toList();
51-
for ( const QVariant &layerInfo : layers )
44+
std::function< bool( const QString &, QStandardItem *, const QString & )> visitItemsRecursive;
45+
visitItemsRecursive = [this, &visitItemsRecursive, baseUrl, authcfg, &errorTitle, &errorMessage]( const QString & baseItemUrl, QStandardItem * parentItem, const QString & parentName ) -> bool
5246
{
53-
const QVariantMap layerInfoMap = layerInfo.toMap();
54-
if ( !layerInfoMap[QStringLiteral( "id" )].isValid() )
55-
{
56-
continue;
57-
}
47+
const QVariantMap serviceInfoMap = QgsArcGisRestUtils::getServiceInfo( baseItemUrl, authcfg, errorTitle, errorMessage );
5848

59-
if ( !layerInfoMap.value( QStringLiteral( "subLayerIds" ) ).toList().empty() )
49+
if ( serviceInfoMap.isEmpty() )
6050
{
61-
// group layer - do not show as it is not possible to load
62-
// TODO - turn model into a tree and show nested groups
63-
continue;
51+
return false;
6452
}
6553

66-
// Get layer info
67-
const QVariantMap layerData = QgsArcGisRestUtils::getLayerInfo( connection.uri().param( QStringLiteral( "url" ) ) + "/" + layerInfoMap[QStringLiteral( "id" )].toString(), authcfg, errorTitle, errorMessage );
68-
if ( layerData.isEmpty() )
54+
bool res = true;
55+
56+
QgsArcGisRestUtils::visitFolderItems( [ =, &res ]( const QString & name, const QString & url )
6957
{
70-
layerErrors.append( tr( "Layer %1: %2 - %3" ).arg( layerInfoMap[QStringLiteral( "id" )].toString(), errorTitle, errorMessage ) );
71-
continue;
72-
}
73-
if ( !layerData.value( QStringLiteral( "capabilities" ) ).toString().contains( QStringLiteral( "query" ), Qt::CaseInsensitive ) )
58+
QStandardItem *nameItem = new QStandardItem( name );
59+
nameItem->setToolTip( url );
60+
if ( parentItem )
61+
parentItem->appendRow( QList<QStandardItem *>() << nameItem );
62+
else
63+
mModel->appendRow( QList<QStandardItem *>() << nameItem );
64+
65+
if ( !visitItemsRecursive( url, nameItem, name ) )
66+
res = false;
67+
}, serviceInfoMap, baseUrl );
68+
69+
QgsArcGisRestUtils::visitServiceItems(
70+
[ =, &res]( const QString & name, const QString & url )
7471
{
75-
QgsDebugMsg( QStringLiteral( "Layer %1 does not support query capabilities" ).arg( layerInfoMap[QStringLiteral( "id" )].toString() ) );
76-
continue;
77-
}
78-
// insert the typenames, titles and abstracts into the tree view
79-
QStandardItem *idItem = new QStandardItem( layerData[QStringLiteral( "id" )].toString() );
80-
bool ok = false;
81-
int idInt = layerData[QStringLiteral( "id" )].toInt( &ok );
82-
if ( ok )
72+
QStandardItem *nameItem = new QStandardItem( name );
73+
nameItem->setToolTip( url );
74+
if ( parentItem )
75+
parentItem->appendRow( QList<QStandardItem *>() << nameItem );
76+
else
77+
mModel->appendRow( QList<QStandardItem *>() << nameItem );
78+
79+
if ( !visitItemsRecursive( url, nameItem, name ) )
80+
res = false;
81+
}, serviceInfoMap, baseUrl, parentName );
82+
83+
QMap< QString, QList<QStandardItem *> > layerItems;
84+
QMap< QString, QString > parents;
85+
86+
QgsArcGisRestUtils::addLayerItems( [ =, &layerItems, &parents]( const QString & parentLayerId, const QString & layerId, const QString & name, const QString & description, const QString & url, bool isParentLayer, const QString & authid )
87+
{
88+
if ( !parentLayerId.isEmpty() )
89+
parents.insert( layerId, parentLayerId );
90+
91+
if ( isParentLayer )
92+
{
93+
QStandardItem *nameItem = new QStandardItem( name );
94+
nameItem->setToolTip( url );
95+
layerItems.insert( layerId, QList<QStandardItem *>() << nameItem );
96+
}
97+
else
98+
{
99+
// insert the typenames, titles and abstracts into the tree view
100+
QStandardItem *idItem = new QStandardItem( layerId );
101+
bool ok = false;
102+
int idInt = layerId.toInt( &ok );
103+
if ( ok )
104+
{
105+
// force display role to be int value, so that sorting works correctly
106+
idItem->setData( idInt, Qt::DisplayRole );
107+
}
108+
idItem->setData( url, UrlRole );
109+
idItem->setData( true, IsLayerRole );
110+
QStandardItem *nameItem = new QStandardItem( name );
111+
QStandardItem *abstractItem = new QStandardItem( description );
112+
abstractItem->setToolTip( description );
113+
QStandardItem *cachedItem = new QStandardItem();
114+
QStandardItem *filterItem = new QStandardItem();
115+
cachedItem->setCheckable( true );
116+
cachedItem->setCheckState( Qt::Checked );
117+
118+
mAvailableCRS[name] = QList<QString>() << authid;
119+
120+
layerItems.insert( layerId, QList<QStandardItem *>() << idItem << nameItem << abstractItem << cachedItem << filterItem );
121+
}
122+
}, serviceInfoMap, baseItemUrl );
123+
124+
// create layer groups
125+
for ( auto it = layerItems.constBegin(); it != layerItems.constEnd(); ++it )
83126
{
84-
// force display role to be int value, so that sorting works correctly
85-
idItem->setData( idInt, Qt::DisplayRole );
127+
const QString id = it.key();
128+
QList<QStandardItem *> row = it.value();
129+
const QString parentId = parents.value( id );
130+
QList<QStandardItem *> parentRow;
131+
if ( !parentId.isEmpty() )
132+
parentRow = layerItems.value( parentId );
133+
if ( !parentRow.isEmpty() )
134+
{
135+
parentRow.at( 0 )->appendRow( row );
136+
}
137+
else
138+
{
139+
if ( parentItem )
140+
parentItem->appendRow( row );
141+
else
142+
mModel->appendRow( row );
143+
}
86144
}
87-
QStandardItem *nameItem = new QStandardItem( layerData[QStringLiteral( "name" )].toString() );
88-
QStandardItem *abstractItem = new QStandardItem( layerData[QStringLiteral( "description" )].toString() );
89-
abstractItem->setToolTip( layerData[QStringLiteral( "description" )].toString() );
90-
QStandardItem *cachedItem = new QStandardItem();
91-
QStandardItem *filterItem = new QStandardItem();
92-
cachedItem->setCheckable( true );
93-
cachedItem->setCheckState( Qt::Checked );
94-
95-
QgsCoordinateReferenceSystem crs = QgsArcGisRestUtils::parseSpatialReference( serviceInfoMap[QStringLiteral( "spatialReference" )].toMap() );
96-
mAvailableCRS[layerData[QStringLiteral( "name" )].toString()] = QList<QString>() << crs.authid();
97-
98-
mModel->appendRow( QList<QStandardItem *>() << idItem << nameItem << abstractItem << cachedItem << filterItem );
99-
}
100-
if ( !layerErrors.isEmpty() )
101-
{
102-
QMessageBox::warning( this, tr( "Error" ), tr( "Failed to query some layers:\n%1" ).arg( layerErrors.join( QStringLiteral( "\n" ) ) ) );
103-
}
145+
146+
return res;
147+
};
148+
149+
if ( !visitItemsRecursive( baseUrl, nullptr, QString() ) )
150+
QMessageBox::warning( this, tr( "Error" ), tr( "Failed to retrieve service capabilities:\n%1: %2" ).arg( errorTitle, errorMessage ) );
151+
104152
return true;
105153
}
106154

@@ -111,11 +159,10 @@ void QgsAfsSourceSelect::buildQuery( const QgsOwsConnection &connection, const Q
111159
return;
112160
}
113161
QModelIndex filterIndex = index.sibling( index.row(), 4 );
114-
QString id = index.sibling( index.row(), 0 ).data().toString();
162+
const QString url = index.sibling( index.row(), 0 ).data( UrlRole ).toString();
115163

116164
// Query available fields
117165
QgsDataSourceUri ds = connection.uri();
118-
QString url = ds.param( QStringLiteral( "url" ) ) + "/" + id;
119166
ds.removeParam( QStringLiteral( "url" ) );
120167
ds.setParam( QStringLiteral( "url" ), url );
121168
QgsDataProvider::ProviderOptions providerOptions;
@@ -146,7 +193,7 @@ QString QgsAfsSourceSelect::getLayerURI( const QgsOwsConnection &connection,
146193
const QgsRectangle &bBox ) const
147194
{
148195
QgsDataSourceUri ds = connection.uri();
149-
QString url = ds.param( QStringLiteral( "url" ) ) + "/" + layerTitle;
196+
QString url = layerTitle;
150197
ds.removeParam( QStringLiteral( "url" ) );
151198
ds.setParam( QStringLiteral( "url" ), url );
152199
ds.setParam( QStringLiteral( "filter" ), filter );

‎src/providers/arcgisrest/qgsamssourceselect.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ bool QgsAmsSourceSelect::connectToService( const QgsOwsConnection &connection )
6868
}
6969
// insert the typenames, titles and abstracts into the tree view
7070
QStandardItem *idItem = new QStandardItem( layerData[QStringLiteral( "id" )].toString() );
71+
idItem->setData( true, IsLayerRole );
7172
bool ok = false;
7273
int idInt = layerData[QStringLiteral( "id" )].toInt( &ok );
7374
if ( ok )

‎src/providers/arcgisrest/qgsarcgisrestutils.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -972,3 +972,56 @@ void QgsArcGisAsyncParallelQuery::handleReply()
972972
mErrors.clear();
973973
}
974974
}
975+
976+
void QgsArcGisRestUtils::visitFolderItems( const std::function< void( const QString &, const QString & ) > &visitor, const QVariantMap &serviceData, const QString &baseUrl )
977+
{
978+
const QStringList folderList = serviceData.value( QStringLiteral( "folders" ) ).toStringList();
979+
for ( const QString &folder : folderList )
980+
{
981+
visitor( folder, baseUrl + ( baseUrl.endsWith( '/' ) ? QString() : QString( '/' ) ) + folder );
982+
}
983+
}
984+
985+
void QgsArcGisRestUtils::visitServiceItems( const std::function< void( const QString &, const QString & ) > &visitor, const QVariantMap &serviceData, const QString &baseUrl,
986+
const QString &parentName )
987+
{
988+
const QVariantList serviceList = serviceData.value( QStringLiteral( "services" ) ).toList();
989+
for ( const QVariant &service : serviceList )
990+
{
991+
const QVariantMap serviceMap = service.toMap();
992+
const QString serviceType = serviceMap.value( QStringLiteral( "type" ) ).toString();
993+
if ( serviceType != QLatin1String( "MapServer" ) && serviceType != QLatin1String( "FeatureServer" ) )
994+
continue;
995+
996+
const QString serviceName = serviceMap.value( QStringLiteral( "name" ) ).toString();
997+
QString displayName = serviceName;
998+
if ( displayName.startsWith( parentName + '/' ) )
999+
displayName = displayName.mid( parentName.length() + 1 );
1000+
1001+
visitor( displayName, baseUrl + ( baseUrl.endsWith( '/' ) ? QString() : QString( '/' ) ) + serviceName + '/' + serviceType );
1002+
}
1003+
}
1004+
1005+
void QgsArcGisRestUtils::addLayerItems( const std::function< void( const QString &, const QString &, const QString &, const QString &, const QString &, bool, const QString & )> &visitor, const QVariantMap &serviceData, const QString &parentUrl )
1006+
{
1007+
const QString authid = QgsArcGisRestUtils::parseSpatialReference( serviceData.value( QStringLiteral( "spatialReference" ) ).toMap() ).authid();
1008+
1009+
const QVariantList layerInfoList = serviceData.value( QStringLiteral( "layers" ) ).toList();
1010+
for ( const QVariant &layerInfo : layerInfoList )
1011+
{
1012+
const QVariantMap layerInfoMap = layerInfo.toMap();
1013+
const QString id = layerInfoMap.value( QStringLiteral( "id" ) ).toString();
1014+
const QString parentLayerId = layerInfoMap.value( QStringLiteral( "parentLayerId" ) ).toString();
1015+
const QString name = layerInfoMap.value( QStringLiteral( "name" ) ).toString();
1016+
const QString description = layerInfoMap.value( QStringLiteral( "description" ) ).toString();
1017+
1018+
if ( !layerInfoMap.value( QStringLiteral( "subLayerIds" ) ).toList().empty() )
1019+
{
1020+
visitor( parentLayerId, id, name, description, parentUrl + '/' + id, true, QString() );
1021+
}
1022+
else
1023+
{
1024+
visitor( parentLayerId, id, name, description, parentUrl + '/' + id, false, authid );
1025+
}
1026+
}
1027+
}

‎src/providers/arcgisrest/qgsarcgisrestutils.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ class QgsArcGisRestUtils
6464
static QDateTime parseDateTime( const QVariant &value );
6565

6666
static QUrl parseUrl( const QUrl &url );
67+
static void visitFolderItems( const std::function<void ( const QString &folderName, const QString &url )> &visitor, const QVariantMap &serviceData, const QString &baseUrl );
68+
static void visitServiceItems( const std::function<void ( const QString &serviceName, const QString &url )> &visitor, const QVariantMap &serviceData, const QString &baseUrl, const QString &parentName );
69+
static void addLayerItems( const std::function<void ( const QString &parentLayerId, const QString &layerId, const QString &name, const QString &description, const QString &url, bool isParentLayer, const QString &authid )> &visitor, const QVariantMap &serviceData, const QString &parentUrl );
6770
};
6871

6972
class QgsArcGisAsyncQuery : public QObject
@@ -91,6 +94,7 @@ class QgsArcGisAsyncParallelQuery : public QObject
9194
public:
9295
QgsArcGisAsyncParallelQuery( QObject *parent = nullptr );
9396
void start( const QVector<QUrl> &urls, QVector<QByteArray> *results, bool allowCache = false );
97+
9498
signals:
9599
void finished( QStringList errors );
96100
private slots:

‎src/providers/arcgisrest/qgsarcgisservicesourceselect.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -338,11 +338,16 @@ void QgsArcGisServiceSourceSelect::addButtonClicked()
338338
{
339339
continue;
340340
}
341+
341342
int row = idx.row();
342-
QString layerTitle = mModel->item( row, 0 )->text(); //layer title/id
343-
QString layerName = mModel->item( row, 1 )->text(); //layer name
344-
bool cacheFeatures = mServiceType == FeatureService ? mModel->item( row, 3 )->checkState() == Qt::Checked : false;
345-
QString filter = mServiceType == FeatureService ? mModel->item( row, 4 )->text() : QString(); //optional filter specified by user
343+
if ( !mModel->itemFromIndex( mModel->index( row, 0, idx.parent() ) )->data( IsLayerRole ).toBool() )
344+
continue;
345+
346+
QString layerTitle = mModel->itemFromIndex( mModel->index( row, 0, idx.parent() ) )->text(); //layer title/id
347+
QString layerName = mModel->itemFromIndex( mModel->index( row, 1, idx.parent() ) )->text(); //layer name
348+
const QString layerUri = mModel->itemFromIndex( mModel->index( row, 0, idx.parent() ) )->data( UrlRole ).toString();
349+
bool cacheFeatures = mServiceType == FeatureService ? mModel->itemFromIndex( mModel->index( row, 3, idx.parent() ) )->checkState() == Qt::Checked : false;
350+
QString filter = mServiceType == FeatureService ? mModel->itemFromIndex( mModel->index( row, 4, idx.parent() ) )->text() : QString(); //optional filter specified by user
346351
if ( cbxUseTitleLayerName->isChecked() && !layerTitle.isEmpty() )
347352
{
348353
layerName = layerTitle;
@@ -352,7 +357,7 @@ void QgsArcGisServiceSourceSelect::addButtonClicked()
352357
{
353358
layerExtent = extent;
354359
}
355-
QString uri = getLayerURI( connection, layerTitle, layerName, pCrsString, filter, layerExtent );
360+
QString uri = getLayerURI( connection, layerUri.isEmpty() ? layerTitle : layerUri, layerName, pCrsString, filter, layerExtent );
356361

357362
QgsDebugMsg( "Layer " + layerName + ", uri: " + uri );
358363
addServiceLayer( uri, layerName );

‎src/providers/arcgisrest/qgsarcgisservicesourceselect.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ class QgsArcGisServiceSourceSelect : public QgsAbstractDataSourceWidget, protect
3939
Q_OBJECT
4040

4141
public:
42+
43+
enum Roles
44+
{
45+
UrlRole = Qt::UserRole + 1,
46+
IsLayerRole,
47+
};
48+
4249
//! Whether the dialog is for a map service or a feature service
4350
enum ServiceType { MapService, FeatureService };
4451

0 commit comments

Comments
 (0)
Please sign in to comment.