1 /***************************************************************************
2                          qgsprocessingprovider.cpp
3                          --------------------------
4     begin                : December 2016
5     copyright            : (C) 2016 by Nyall Dawson
6     email                : nyall dot dawson at gmail dot com
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 
18 #include "qgsprocessingprovider.h"
19 #include "qgsapplication.h"
20 #include "qgsvectorfilewriter.h"
21 #include "qgsrasterfilewriter.h"
22 #include "qgssettings.h"
23 
QgsProcessingProvider(QObject * parent SIP_TRANSFERTHIS)24 QgsProcessingProvider::QgsProcessingProvider( QObject *parent SIP_TRANSFERTHIS )
25   : QObject( parent )
26 {}
27 
28 
~QgsProcessingProvider()29 QgsProcessingProvider::~QgsProcessingProvider()
30 {
31   qDeleteAll( mAlgorithms );
32 }
33 
icon() const34 QIcon QgsProcessingProvider::icon() const
35 {
36   return QgsApplication::getThemeIcon( "/processingAlgorithm.svg" );
37 }
38 
svgIconPath() const39 QString QgsProcessingProvider::svgIconPath() const
40 {
41   return QgsApplication::iconPath( QStringLiteral( "processingAlgorithm.svg" ) );
42 }
43 
flags() const44 QgsProcessingProvider::Flags QgsProcessingProvider::flags() const
45 {
46   return QgsProcessingProvider::Flags();
47 }
48 
helpId() const49 QString QgsProcessingProvider::helpId() const
50 {
51   return QString();
52 }
53 
longName() const54 QString QgsProcessingProvider::longName() const
55 {
56   return name();
57 }
58 
versionInfo() const59 QString QgsProcessingProvider::versionInfo() const
60 {
61   return QString();
62 }
63 
supportedOutputRasterLayerExtensions() const64 QStringList QgsProcessingProvider::supportedOutputRasterLayerExtensions() const
65 {
66   return QgsRasterFileWriter::supportedFormatExtensions();
67 }
68 
refreshAlgorithms()69 void QgsProcessingProvider::refreshAlgorithms()
70 {
71   qDeleteAll( mAlgorithms );
72   mAlgorithms.clear();
73   if ( isActive() )
74   {
75     loadAlgorithms();
76     emit algorithmsLoaded();
77   }
78 }
79 
algorithms() const80 QList<const QgsProcessingAlgorithm *> QgsProcessingProvider::algorithms() const
81 {
82   return mAlgorithms.values();
83 }
84 
algorithm(const QString & name) const85 const QgsProcessingAlgorithm *QgsProcessingProvider::algorithm( const QString &name ) const
86 {
87   return mAlgorithms.value( name );
88 }
89 
addAlgorithm(QgsProcessingAlgorithm * algorithm)90 bool QgsProcessingProvider::addAlgorithm( QgsProcessingAlgorithm *algorithm )
91 {
92   if ( !algorithm )
93     return false;
94 
95   if ( mAlgorithms.contains( algorithm->name() ) )
96   {
97     QgsMessageLog::logMessage( tr( "Duplicate algorithm name %1 for provider %2" ).arg( algorithm->name(), id() ), QObject::tr( "Processing" ) );
98     return false;
99   }
100 
101   // init the algorithm - this allows direct querying of the algorithm's parameters
102   // and outputs from the provider's copy
103   algorithm->initAlgorithm( QVariantMap() );
104 
105   algorithm->setProvider( this );
106   mAlgorithms.insert( algorithm->name(), algorithm );
107   return true;
108 }
109 
supportedOutputVectorLayerExtensions() const110 QStringList QgsProcessingProvider::supportedOutputVectorLayerExtensions() const
111 {
112   return QgsVectorFileWriter::supportedFormatExtensions();
113 }
114 
supportedOutputTableExtensions() const115 QStringList QgsProcessingProvider::supportedOutputTableExtensions() const
116 {
117   return supportedOutputVectorLayerExtensions();
118 }
119 
isSupportedOutputValue(const QVariant & outputValue,const QgsProcessingDestinationParameter * parameter,QgsProcessingContext & context,QString & error) const120 bool QgsProcessingProvider::isSupportedOutputValue( const QVariant &outputValue, const QgsProcessingDestinationParameter *parameter, QgsProcessingContext &context, QString &error ) const
121 {
122   error.clear();
123   QString outputPath = QgsProcessingParameters::parameterAsOutputLayer( parameter, outputValue, context ).trimmed();
124 
125   if ( outputPath.isEmpty() )
126   {
127     if ( parameter->flags() & QgsProcessingParameterDefinition::FlagOptional )
128     {
129       return true;
130     }
131     else
132     {
133       error = tr( "Missing parameter value %1" ).arg( parameter->description() );
134       return false;
135     }
136   }
137 
138   if ( parameter->type() == QgsProcessingParameterVectorDestination::typeName()
139        ||  parameter->type() == QgsProcessingParameterFeatureSink::typeName() )
140   {
141     if ( outputPath.startsWith( QLatin1String( "memory:" ) ) )
142     {
143       if ( !supportsNonFileBasedOutput() )
144       {
145         error = tr( "This algorithm only supports disk-based outputs" );
146         return false;
147       }
148       return true;
149     }
150 
151     QString providerKey;
152     QString uri;
153     QString layerName;
154     QMap<QString, QVariant> options;
155     bool useWriter = false;
156     QString format;
157     QString extension;
158     QgsProcessingUtils::parseDestinationString( outputPath, providerKey, uri, layerName, format, options, useWriter, extension );
159 
160     if ( providerKey != QLatin1String( "ogr" ) )
161     {
162       if ( !supportsNonFileBasedOutput() )
163       {
164         error = tr( "This algorithm only supports disk-based outputs" );
165         return false;
166       }
167       return true;
168     }
169 
170     if ( !supportedOutputVectorLayerExtensions().contains( extension, Qt::CaseInsensitive ) )
171     {
172       error = tr( "“.%1” files are not supported as outputs for this algorithm" ).arg( extension );
173       return false;
174     }
175     return true;
176   }
177   else if ( parameter->type() == QgsProcessingParameterRasterDestination::typeName() )
178   {
179     QFileInfo fi( outputPath );
180     const QString extension = fi.completeSuffix();
181     if ( !supportedOutputRasterLayerExtensions().contains( extension, Qt::CaseInsensitive ) )
182     {
183       error = tr( "“.%1” files are not supported as outputs for this algorithm" ).arg( extension );
184       return false;
185     }
186     return true;
187   }
188   else
189   {
190     return true;
191   }
192 }
193 
defaultVectorFileExtension(bool hasGeometry) const194 QString QgsProcessingProvider::defaultVectorFileExtension( bool hasGeometry ) const
195 {
196   QgsSettings settings;
197   const QString userDefault = QgsProcessingUtils::defaultVectorExtension();
198 
199   const QStringList supportedExtensions = supportedOutputVectorLayerExtensions();
200   if ( supportedExtensions.contains( userDefault, Qt::CaseInsensitive ) )
201   {
202     // user set default is supported by provider, use that
203     return userDefault;
204   }
205   else if ( !supportedExtensions.empty() )
206   {
207     return supportedExtensions.at( 0 );
208   }
209   else
210   {
211     // who knows? provider says it has no file support at all...
212     // let's say shp. even MapInfo supports shapefiles.
213     return hasGeometry ? QStringLiteral( "shp" ) : QStringLiteral( "dbf" );
214   }
215 }
216 
defaultRasterFileExtension() const217 QString QgsProcessingProvider::defaultRasterFileExtension() const
218 {
219   QgsSettings settings;
220   const QString userDefault = QgsProcessingUtils::defaultRasterExtension();
221 
222   const QStringList supportedExtensions = supportedOutputRasterLayerExtensions();
223   if ( supportedExtensions.contains( userDefault, Qt::CaseInsensitive ) )
224   {
225     // user set default is supported by provider, use that
226     return userDefault;
227   }
228   else if ( !supportedExtensions.empty() )
229   {
230     return supportedExtensions.at( 0 );
231   }
232   else
233   {
234     // who knows? provider says it has no file support at all...
235     return QStringLiteral( "tif" );
236   }
237 }
238 
supportsNonFileBasedOutput() const239 bool QgsProcessingProvider::supportsNonFileBasedOutput() const
240 {
241   return true;
242 }
243