1 /***************************************************************************
2 qgsamsdataitems.cpp
3 -------------------
4 begin : Nov 26, 2015
5 copyright : (C) 2015 by Sandro Mani
6 email : smani@sourcepole.ch
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17 #include "qgsamsdataitems.h"
18 #include "qgsarcgisrestutils.h"
19 #include "qgsowsconnection.h"
20 #include "qgsproviderregistry.h"
21 #include "qgslogger.h"
22
23 #ifdef HAVE_GUI
24 #include "qgsamssourceselect.h"
25 #endif
26
27 #include <QImageReader>
28
QgsAmsRootItem(QgsDataItem * parent,const QString & name,const QString & path)29 QgsAmsRootItem::QgsAmsRootItem( QgsDataItem *parent, const QString &name, const QString &path )
30 : QgsConnectionsRootItem( parent, name, path, QStringLiteral( "AMS" ) )
31 {
32 mCapabilities |= Fast;
33 mIconName = QStringLiteral( "mIconAms.svg" );
34 populate();
35 }
36
createChildren()37 QVector<QgsDataItem *> QgsAmsRootItem::createChildren()
38 {
39 QVector<QgsDataItem *> connections;
40
41 const QStringList connectionList = QgsOwsConnection::connectionList( QStringLiteral( "ARCGISMAPSERVER" ) );
42 for ( const QString &connName : connectionList )
43 {
44 QString path = "ams:/" + connName;
45 connections.append( new QgsAmsConnectionItem( this, connName, path, connName ) );
46 }
47 return connections;
48 }
49
50 #ifdef HAVE_GUI
paramWidget()51 QWidget *QgsAmsRootItem::paramWidget()
52 {
53 QgsAmsSourceSelect *select = new QgsAmsSourceSelect( nullptr, Qt::WindowFlags(), QgsProviderRegistry::WidgetMode::Manager );
54 connect( select, &QgsArcGisServiceSourceSelect::connectionsChanged, this, &QgsAmsRootItem::onConnectionsChanged );
55 return select;
56 }
57
onConnectionsChanged()58 void QgsAmsRootItem::onConnectionsChanged()
59 {
60 refresh();
61 }
62 #endif
63
64 ///////////////////////////////////////////////////////////////////////////////
65
66
addFolderItems(QVector<QgsDataItem * > & items,const QVariantMap & serviceData,const QString & baseUrl,const QString & authcfg,const QgsStringMap & headers,QgsDataItem * parent)67 void addFolderItems( QVector< QgsDataItem * > &items, const QVariantMap &serviceData, const QString &baseUrl, const QString &authcfg, const QgsStringMap &headers, QgsDataItem *parent )
68 {
69 QgsArcGisRestUtils::visitFolderItems( [parent, &baseUrl, &items, headers, authcfg]( const QString & name, const QString & url )
70 {
71 std::unique_ptr< QgsAmsFolderItem > folderItem = qgis::make_unique< QgsAmsFolderItem >( parent, name, url, baseUrl, authcfg, headers );
72 items.append( folderItem.release() );
73 }, serviceData, baseUrl );
74 }
75
addServiceItems(QVector<QgsDataItem * > & items,const QVariantMap & serviceData,const QString & baseUrl,const QString & authcfg,const QgsStringMap & headers,QgsDataItem * parent)76 void addServiceItems( QVector< QgsDataItem * > &items, const QVariantMap &serviceData, const QString &baseUrl, const QString &authcfg, const QgsStringMap &headers, QgsDataItem *parent )
77 {
78 QgsArcGisRestUtils::visitServiceItems(
79 [&items, parent, authcfg, headers]( const QString & name, const QString & url )
80 {
81 std::unique_ptr< QgsAmsServiceItem > serviceItem = qgis::make_unique< QgsAmsServiceItem >( parent, name, url, url, authcfg, headers );
82 items.append( serviceItem.release() );
83 }, serviceData, baseUrl, QgsArcGisRestUtils::Raster );
84 }
85
addLayerItems(QVector<QgsDataItem * > & items,const QVariantMap & serviceData,const QString & parentUrl,const QString & authcfg,const QgsStringMap & headers,QgsDataItem * parent)86 void addLayerItems( QVector< QgsDataItem * > &items, const QVariantMap &serviceData, const QString &parentUrl, const QString &authcfg, const QgsStringMap &headers, QgsDataItem *parent )
87 {
88 QMap< QString, QgsDataItem * > layerItems;
89 QMap< QString, QString > parents;
90
91 QgsArcGisRestUtils::addLayerItems( [parent, &layerItems, &parents, authcfg, headers]( const QString & parentLayerId, const QString & id, const QString & name, const QString & description, const QString & url, bool, const QString & authid, const QString & format )
92 {
93 Q_UNUSED( description )
94
95 if ( !parentLayerId.isEmpty() )
96 parents.insert( id, parentLayerId );
97
98 std::unique_ptr< QgsAmsLayerItem > layerItem = qgis::make_unique< QgsAmsLayerItem >( parent, name, url, id, name, authid, format, authcfg, headers );
99 layerItems.insert( id, layerItem.release() );
100
101 }, serviceData, parentUrl, QgsArcGisRestUtils::Raster );
102
103 // create groups
104 for ( auto it = layerItems.constBegin(); it != layerItems.constEnd(); ++it )
105 {
106 const QString id = it.key();
107 QgsDataItem *item = it.value();
108 const QString parentId = parents.value( id );
109
110 if ( QgsDataItem *layerParent = parentId.isEmpty() ? nullptr : layerItems.value( parentId ) )
111 layerParent->addChildItem( item );
112 else
113 items.append( item );
114 }
115 }
116
117
QgsAmsConnectionItem(QgsDataItem * parent,const QString & name,const QString & path,const QString & connectionName)118 QgsAmsConnectionItem::QgsAmsConnectionItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &connectionName )
119 : QgsDataCollectionItem( parent, name, path, QStringLiteral( "AMS" ) )
120 , mConnName( connectionName )
121 {
122 mIconName = QStringLiteral( "mIconConnect.svg" );
123 mCapabilities |= Collapse;
124 }
125
createChildren()126 QVector<QgsDataItem *> QgsAmsConnectionItem::createChildren()
127 {
128 const QgsOwsConnection connection( QStringLiteral( "ARCGISMAPSERVER" ), mConnName );
129 const QString url = connection.uri().param( QStringLiteral( "url" ) );
130 const QString authcfg = connection.uri().authConfigId();
131 const QString referer = connection.uri().param( QStringLiteral( "referer" ) );
132 QgsStringMap headers;
133 if ( ! referer.isEmpty() )
134 headers[ QStringLiteral( "Referer" )] = referer;
135
136 QVector<QgsDataItem *> items;
137 QString errorTitle, errorMessage;
138
139 QVariantMap serviceData = QgsArcGisRestUtils::getServiceInfo( url, authcfg, errorTitle, errorMessage, headers );
140 if ( serviceData.isEmpty() )
141 {
142 if ( !errorMessage.isEmpty() )
143 {
144 std::unique_ptr< QgsErrorItem > error = qgis::make_unique< QgsErrorItem >( this, tr( "Connection failed: %1" ).arg( errorTitle ), mPath + "/error" );
145 error->setToolTip( errorMessage );
146 items.append( error.release() );
147 QgsDebugMsg( "Connection failed - " + errorMessage );
148 }
149 return items;
150 }
151
152 addFolderItems( items, serviceData, url, authcfg, headers, this );
153 addServiceItems( items, serviceData, url, authcfg, headers, this );
154 addLayerItems( items, serviceData, url, authcfg, headers, this );
155
156 return items;
157 }
158
equal(const QgsDataItem * other)159 bool QgsAmsConnectionItem::equal( const QgsDataItem *other )
160 {
161 const QgsAmsConnectionItem *o = qobject_cast<const QgsAmsConnectionItem *>( other );
162 return ( type() == other->type() && o && mPath == o->mPath && mName == o->mName );
163 }
164
url() const165 QString QgsAmsConnectionItem::url() const
166 {
167 const QgsOwsConnection connection( QStringLiteral( "ARCGISMAPSERVER" ), mConnName );
168 return connection.uri().param( QStringLiteral( "url" ) );
169 }
170
171
QgsAmsFolderItem(QgsDataItem * parent,const QString & name,const QString & path,const QString & baseUrl,const QString & authcfg,const QgsStringMap & headers)172 QgsAmsFolderItem::QgsAmsFolderItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &baseUrl, const QString &authcfg, const QgsStringMap &headers )
173 : QgsDataCollectionItem( parent, name, path, QStringLiteral( "AMS" ) )
174 , mBaseUrl( baseUrl )
175 , mAuthCfg( authcfg )
176 , mHeaders( headers )
177 {
178 mIconName = QStringLiteral( "mIconDbSchema.svg" );
179 mCapabilities |= Collapse;
180 setToolTip( path );
181 }
182
183
createChildren()184 QVector<QgsDataItem *> QgsAmsFolderItem::createChildren()
185 {
186 const QString url = mPath;
187
188 QVector<QgsDataItem *> items;
189 QString errorTitle, errorMessage;
190 const QVariantMap serviceData = QgsArcGisRestUtils::getServiceInfo( url, mAuthCfg, errorTitle, errorMessage, mHeaders );
191 if ( serviceData.isEmpty() )
192 {
193 if ( !errorMessage.isEmpty() )
194 {
195 std::unique_ptr< QgsErrorItem > error = qgis::make_unique< QgsErrorItem >( this, tr( "Connection failed: %1" ).arg( errorTitle ), mPath + "/error" );
196 error->setToolTip( errorMessage );
197 items.append( error.release() );
198 QgsDebugMsg( "Connection failed - " + errorMessage );
199 }
200 return items;
201 }
202
203 addFolderItems( items, serviceData, mBaseUrl, mAuthCfg, mHeaders, this );
204 addServiceItems( items, serviceData, mBaseUrl, mAuthCfg, mHeaders, this );
205 addLayerItems( items, serviceData, mPath, mAuthCfg, mHeaders, this );
206 return items;
207 }
208
equal(const QgsDataItem * other)209 bool QgsAmsFolderItem::equal( const QgsDataItem *other )
210 {
211 const QgsAmsFolderItem *o = qobject_cast<const QgsAmsFolderItem *>( other );
212 return ( type() == other->type() && o && mPath == o->mPath && mName == o->mName );
213 }
214
215
QgsAmsServiceItem(QgsDataItem * parent,const QString & name,const QString & path,const QString & baseUrl,const QString & authcfg,const QgsStringMap & headers)216 QgsAmsServiceItem::QgsAmsServiceItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &baseUrl, const QString &authcfg, const QgsStringMap &headers )
217 : QgsDataCollectionItem( parent, name, path, QStringLiteral( "AMS" ) )
218 , mBaseUrl( baseUrl )
219 , mAuthCfg( authcfg )
220 , mHeaders( headers )
221 {
222 mIconName = QStringLiteral( "mIconDbSchema.svg" );
223 mCapabilities |= Collapse;
224 setToolTip( path );
225 }
226
createChildren()227 QVector<QgsDataItem *> QgsAmsServiceItem::createChildren()
228 {
229 const QString url = mPath;
230
231 QVector<QgsDataItem *> items;
232 QString errorTitle, errorMessage;
233 const QVariantMap serviceData = QgsArcGisRestUtils::getServiceInfo( url, mAuthCfg, errorTitle, errorMessage, mHeaders );
234 if ( serviceData.isEmpty() )
235 {
236 if ( !errorMessage.isEmpty() )
237 {
238 std::unique_ptr< QgsErrorItem > error = qgis::make_unique< QgsErrorItem >( this, tr( "Connection failed: %1" ).arg( errorTitle ), mPath + "/error" );
239 error->setToolTip( errorMessage );
240 items.append( error.release() );
241 QgsDebugMsg( "Connection failed - " + errorMessage );
242 }
243 return items;
244 }
245
246 addFolderItems( items, serviceData, mBaseUrl, mAuthCfg, mHeaders, this );
247 addServiceItems( items, serviceData, mBaseUrl, mAuthCfg, mHeaders, this );
248 addLayerItems( items, serviceData, mPath, mAuthCfg, mHeaders, this );
249 return items;
250 }
251
equal(const QgsDataItem * other)252 bool QgsAmsServiceItem::equal( const QgsDataItem *other )
253 {
254 const QgsAmsServiceItem *o = qobject_cast<const QgsAmsServiceItem *>( other );
255 return ( type() == other->type() && o && mPath == o->mPath && mName == o->mName );
256 }
257
258
259 ///////////////////////////////////////////////////////////////////////////////
260
QgsAmsLayerItem(QgsDataItem * parent,const QString &,const QString & url,const QString & id,const QString & title,const QString & authid,const QString & format,const QString & authcfg,const QgsStringMap & headers)261 QgsAmsLayerItem::QgsAmsLayerItem( QgsDataItem *parent, const QString &, const QString &url, const QString &id, const QString &title, const QString &authid, const QString &format, const QString &authcfg, const QgsStringMap &headers )
262 : QgsLayerItem( parent, title, url, QString(), QgsLayerItem::Raster, QStringLiteral( "arcgismapserver" ) )
263 {
264 QString trimmedUrl = id.isEmpty() ? url : url.left( url.length() - 1 - id.length() ); // trim '/0' from end of url -- AMS provider requires this omitted
265 mUri = QStringLiteral( "crs='%1' format='%2' layer='%3' url='%4'" ).arg( authid, format, id, trimmedUrl );
266 if ( !authcfg.isEmpty() )
267 mUri += QStringLiteral( " authcfg='%1'" ).arg( authcfg );
268 if ( !headers.value( QStringLiteral( "Referer" ) ).isEmpty() )
269 mUri += QStringLiteral( " referer='%1'" ).arg( headers.value( QStringLiteral( "Referer" ) ) );
270 setState( Populated );
271 mIconName = QStringLiteral( "mIconAms.svg" );
272 setToolTip( mPath );
273 }
274
275 //
276 // QgsAmsDataItemProvider
277 //
278
name()279 QString QgsAmsDataItemProvider::name()
280 {
281 return QStringLiteral( "AMS" );
282 }
283
capabilities() const284 int QgsAmsDataItemProvider::capabilities() const
285 {
286 return QgsDataProvider::Net;
287 }
288
createDataItem(const QString & path,QgsDataItem * parentItem)289 QgsDataItem *QgsAmsDataItemProvider::createDataItem( const QString &path, QgsDataItem *parentItem )
290 {
291 if ( path.isEmpty() )
292 {
293 return new QgsAmsRootItem( parentItem, QObject::tr( "ArcGIS Map Service" ), QStringLiteral( "arcgismapserver:" ) );
294 }
295
296 // path schema: ams:/connection name (used by OWS)
297 if ( path.startsWith( QLatin1String( "ams:/" ) ) )
298 {
299 QString connectionName = path.split( '/' ).last();
300 if ( QgsOwsConnection::connectionList( QStringLiteral( "arcgismapserver" ) ).contains( connectionName ) )
301 {
302 return new QgsAmsConnectionItem( parentItem, QStringLiteral( "ArcGisMapServer" ), path, connectionName );
303 }
304 }
305
306 return nullptr;
307 }
308