21using namespace Qt::StringLiterals;
23#if QT_CONFIG( process )
39QString QgsConvertGpxFeatureTypeAlgorithm::name()
const
41 return u
"convertgpxfeaturetype"_s;
44QString QgsConvertGpxFeatureTypeAlgorithm::displayName()
const
46 return QObject::tr(
"Convert GPX feature type" );
49QStringList QgsConvertGpxFeatureTypeAlgorithm::tags()
const
51 return QObject::tr(
"gps,tools,babel,tracks,waypoints,routes" ).split(
',' );
54QString QgsConvertGpxFeatureTypeAlgorithm::group()
const
56 return QObject::tr(
"GPS" );
59QString QgsConvertGpxFeatureTypeAlgorithm::groupId()
const
64void QgsConvertGpxFeatureTypeAlgorithm::initAlgorithm(
const QVariantMap & )
71 new QgsProcessingParameterEnum( u
"CONVERSION"_s, QObject::tr(
"Conversion" ), { QObject::tr(
"Waypoints from a Route" ), QObject::tr(
"Waypoints from a Track" ), QObject::tr(
"Route from Waypoints" ), QObject::tr(
"Track from Waypoints" ) },
false, 0 )
79QIcon QgsConvertGpxFeatureTypeAlgorithm::icon()
const
84QString QgsConvertGpxFeatureTypeAlgorithm::svgIconPath()
const
89QString QgsConvertGpxFeatureTypeAlgorithm::shortHelpString()
const
91 return QObject::tr(
"This algorithm uses the GPSBabel tool to convert GPX features from one type to another (e.g. converting all waypoint features to a route feature)." );
94QString QgsConvertGpxFeatureTypeAlgorithm::shortDescription()
const
96 return QObject::tr(
"Converts GPX features from one type to another." );
99QgsConvertGpxFeatureTypeAlgorithm *QgsConvertGpxFeatureTypeAlgorithm::createInstance()
const
101 return new QgsConvertGpxFeatureTypeAlgorithm();
107 QGS_MARK_ALGORITHM_SOURCE
109 const QString inputPath = parameterAsString( parameters, u
"INPUT"_s, context );
110 const QString outputPath = parameterAsString( parameters, u
"OUTPUT"_s, context );
112 const ConversionType convertType =
static_cast<ConversionType
>( parameterAsEnum( parameters, u
"CONVERSION"_s, context ) );
115 if ( babelPath.isEmpty() )
116 babelPath = u
"gpsbabel"_s;
118 QStringList processArgs;
120 createArgumentLists( inputPath, outputPath, convertType, processArgs, logArgs );
121 feedback->
pushCommandInfo( QObject::tr(
"Conversion command: " ) + babelPath +
' ' + logArgs.join(
' ' ) );
123 QgsBlockingProcess babelProcess( babelPath, processArgs );
124 babelProcess.setStdErrHandler( [feedback](
const QByteArray &ba ) { feedback->
reportError( ba ); } );
125 babelProcess.setStdOutHandler( [feedback](
const QByteArray &ba ) { feedback->
pushDebugInfo( ba ); } );
127 const int res = babelProcess.run( feedback );
130 feedback->
pushInfo( QObject::tr(
"Process was canceled and did not complete" ) );
132 else if ( !feedback->
isCanceled() && babelProcess.exitStatus() == QProcess::CrashExit )
138 feedback->
pushInfo( QObject::tr(
"Process completed successfully" ) );
140 else if ( babelProcess.processError() == QProcess::FailedToStart )
142 throw QgsProcessingException( QObject::tr(
"Process %1 failed to start. Either %1 is missing, or you may have insufficient permissions to run the program." ).arg( babelPath ) );
149 std::unique_ptr<QgsVectorLayer> layer;
152 switch ( convertType )
154 case QgsConvertGpxFeatureTypeAlgorithm::WaypointsFromRoute:
155 case QgsConvertGpxFeatureTypeAlgorithm::WaypointsFromTrack:
156 layer = std::make_unique<QgsVectorLayer>( outputPath +
"?type=waypoint", layerName, u
"gpx"_s );
158 case QgsConvertGpxFeatureTypeAlgorithm::RouteFromWaypoints:
159 layer = std::make_unique<QgsVectorLayer>( outputPath +
"?type=route", layerName, u
"gpx"_s );
161 case QgsConvertGpxFeatureTypeAlgorithm::TrackFromWaypoints:
162 layer = std::make_unique<QgsVectorLayer>( outputPath +
"?type=track", layerName, u
"gpx"_s );
167 if ( !layer->isValid() )
169 feedback->
reportError( QObject::tr(
"Resulting file is not a valid GPX layer" ) );
173 const QString layerId = layer->id();
174 outputs.insert( u
"OUTPUT_LAYER"_s, layerId );
180 outputs.insert( u
"OUTPUT"_s, outputPath );
184void QgsConvertGpxFeatureTypeAlgorithm::createArgumentLists(
const QString &inputPath,
const QString &outputPath, ConversionType conversion, QStringList &processArgs, QStringList &logArgs )
186 logArgs.reserve( 10 );
187 processArgs.reserve( 10 );
188 for (
const QString &arg : { u
"-i"_s, u
"gpx"_s, u
"-f"_s } )
195 logArgs << u
"\"%1\""_s.arg( inputPath );
196 processArgs << inputPath;
198 QStringList convertStrings;
199 switch ( conversion )
201 case QgsConvertGpxFeatureTypeAlgorithm::WaypointsFromRoute:
202 convertStrings << u
"-x"_s << u
"transform,wpt=rte,del"_s;
204 case QgsConvertGpxFeatureTypeAlgorithm::WaypointsFromTrack:
205 convertStrings << u
"-x"_s << u
"transform,wpt=trk,del"_s;
207 case QgsConvertGpxFeatureTypeAlgorithm::RouteFromWaypoints:
208 convertStrings << u
"-x"_s << u
"transform,rte=wpt,del"_s;
210 case QgsConvertGpxFeatureTypeAlgorithm::TrackFromWaypoints:
211 convertStrings << u
"-x"_s << u
"transform,trk=wpt,del"_s;
214 logArgs << convertStrings;
215 processArgs << convertStrings;
217 for (
const QString &arg : { u
"-o"_s, u
"gpx"_s, u
"-F"_s } )
223 logArgs << u
"\"%1\""_s.arg( outputPath );
224 processArgs << outputPath;
232QString QgsConvertGpsDataAlgorithm::name()
const
234 return u
"convertgpsdata"_s;
237QString QgsConvertGpsDataAlgorithm::displayName()
const
239 return QObject::tr(
"Convert GPS data" );
242QStringList QgsConvertGpsDataAlgorithm::tags()
const
244 return QObject::tr(
"gps,tools,babel,tracks,waypoints,routes,gpx,import,export" ).split(
',' );
247QString QgsConvertGpsDataAlgorithm::group()
const
249 return QObject::tr(
"GPS" );
252QString QgsConvertGpsDataAlgorithm::groupId()
const
257void QgsConvertGpsDataAlgorithm::initAlgorithm(
const QVariantMap & )
261 QObject::tr(
"Input file" ),
269 auto formatParam = std::make_unique<QgsProcessingParameterString>( u
"FORMAT"_s, QObject::tr(
"Format" ) );
273 for (
const QString &format : formatNames )
276 std::sort( formats.begin(), formats.end(), [](
const QString &a,
const QString &b ) { return a.compare( b, Qt::CaseInsensitive ) < 0; } );
278 formatParam->setMetadata( { { u
"widget_wrapper"_s, QVariantMap( { { u
"value_hints"_s, formats } } ) } } );
279 addParameter( formatParam.release() );
281 addParameter(
new QgsProcessingParameterEnum( u
"FEATURE_TYPE"_s, QObject::tr(
"Feature type" ), { QObject::tr(
"Waypoints" ), QObject::tr(
"Routes" ), QObject::tr(
"Tracks" ) },
false, 0 ) );
288QIcon QgsConvertGpsDataAlgorithm::icon()
const
293QString QgsConvertGpsDataAlgorithm::svgIconPath()
const
298QString QgsConvertGpsDataAlgorithm::shortHelpString()
const
300 return QObject::tr(
"This algorithm uses the GPSBabel tool to convert a GPS data file from a range of formats to the GPX standard format." );
303QString QgsConvertGpsDataAlgorithm::shortDescription()
const
305 return QObject::tr(
"Converts a GPS data file from a range of formats to the GPX standard format." );
308QgsConvertGpsDataAlgorithm *QgsConvertGpsDataAlgorithm::createInstance()
const
310 return new QgsConvertGpsDataAlgorithm();
315 QGS_MARK_ALGORITHM_SOURCE
317 const QString inputPath = parameterAsString( parameters, u
"INPUT"_s, context );
318 const QString outputPath = parameterAsString( parameters, u
"OUTPUT"_s, context );
323 if ( babelPath.isEmpty() )
324 babelPath = u
"gpsbabel"_s;
326 const QString formatName = parameterAsString( parameters, u
"FORMAT"_s, context );
336 switch ( featureType )
341 throw QgsProcessingException( QObject::tr(
"The GPSBabel format “%1” does not support converting waypoints." ).arg( formatName ) );
348 throw QgsProcessingException( QObject::tr(
"The GPSBabel format “%1” does not support converting routes." ).arg( formatName ) );
355 throw QgsProcessingException( QObject::tr(
"The GPSBabel format “%1” does not support converting tracks." ).arg( formatName ) );
363 const QStringList processCommand = format->
importCommand( babelPath, featureType, inputPath, outputPath );
364 feedback->
pushCommandInfo( QObject::tr(
"Conversion command: " ) + logCommand.join(
' ' ) );
366 QgsBlockingProcess babelProcess( processCommand.value( 0 ), processCommand.mid( 1 ) );
367 babelProcess.setStdErrHandler( [feedback](
const QByteArray &ba ) { feedback->
reportError( ba ); } );
368 babelProcess.setStdOutHandler( [feedback](
const QByteArray &ba ) { feedback->
pushDebugInfo( ba ); } );
370 const int res = babelProcess.run( feedback );
373 feedback->
pushInfo( QObject::tr(
"Process was canceled and did not complete" ) );
375 else if ( !feedback->
isCanceled() && babelProcess.exitStatus() == QProcess::CrashExit )
381 feedback->
pushInfo( QObject::tr(
"Process completed successfully" ) );
383 else if ( babelProcess.processError() == QProcess::FailedToStart )
385 throw QgsProcessingException( QObject::tr(
"Process %1 failed to start. Either %1 is missing, or you may have insufficient permissions to run the program." ).arg( babelPath ) );
392 std::unique_ptr<QgsVectorLayer> layer;
395 switch ( featureType )
398 layer = std::make_unique<QgsVectorLayer>( outputPath +
"?type=waypoint", layerName, u
"gpx"_s );
401 layer = std::make_unique<QgsVectorLayer>( outputPath +
"?type=route", layerName, u
"gpx"_s );
404 layer = std::make_unique<QgsVectorLayer>( outputPath +
"?type=track", layerName, u
"gpx"_s );
409 if ( !layer->isValid() )
411 feedback->
reportError( QObject::tr(
"Resulting file is not a valid GPX layer" ) );
415 const QString layerId = layer->id();
416 outputs.insert( u
"OUTPUT_LAYER"_s, layerId );
422 outputs.insert( u
"OUTPUT"_s, outputPath );
430QString QgsDownloadGpsDataAlgorithm::name()
const
432 return u
"downloadgpsdata"_s;
435QString QgsDownloadGpsDataAlgorithm::displayName()
const
437 return QObject::tr(
"Download GPS data from device" );
440QStringList QgsDownloadGpsDataAlgorithm::tags()
const
442 return QObject::tr(
"gps,tools,babel,tracks,waypoints,routes,gpx,import,export,export,device,serial" ).split(
',' );
445QString QgsDownloadGpsDataAlgorithm::group()
const
447 return QObject::tr(
"GPS" );
450QString QgsDownloadGpsDataAlgorithm::groupId()
const
455void QgsDownloadGpsDataAlgorithm::initAlgorithm(
const QVariantMap & )
457 auto deviceParam = std::make_unique<QgsProcessingParameterString>( u
"DEVICE"_s, QObject::tr(
"Device" ) );
460 std::sort( deviceNames.begin(), deviceNames.end(), [](
const QString &a,
const QString &b ) { return a.compare( b, Qt::CaseInsensitive ) < 0; } );
462 deviceParam->setMetadata( { { u
"widget_wrapper"_s, QVariantMap( { { u
"value_hints"_s, deviceNames } } ) } } );
463 addParameter( deviceParam.release() );
467 auto portParam = std::make_unique<QgsProcessingParameterString>( u
"PORT"_s, QObject::tr(
"Port" ) );
470 for (
auto it = devices.constBegin(); it != devices.constEnd(); ++it )
472 std::sort( ports.begin(), ports.end(), [](
const QString &a,
const QString &b ) { return a.compare( b, Qt::CaseInsensitive ) < 0; } );
474 portParam->setMetadata( { { u
"widget_wrapper"_s, QVariantMap( { { u
"value_hints"_s, ports } } ) } } );
475 addParameter( portParam.release() );
477 addParameter(
new QgsProcessingParameterEnum( u
"FEATURE_TYPE"_s, QObject::tr(
"Feature type" ), { QObject::tr(
"Waypoints" ), QObject::tr(
"Routes" ), QObject::tr(
"Tracks" ) },
false, 0 ) );
484QIcon QgsDownloadGpsDataAlgorithm::icon()
const
489QString QgsDownloadGpsDataAlgorithm::svgIconPath()
const
494QString QgsDownloadGpsDataAlgorithm::shortHelpString()
const
496 return QObject::tr(
"This algorithm uses the GPSBabel tool to download data from a GPS device into the GPX standard format." );
499QString QgsDownloadGpsDataAlgorithm::shortDescription()
const
501 return QObject::tr(
"Downloads data from a GPS device into the GPX standard format." );
504QgsDownloadGpsDataAlgorithm *QgsDownloadGpsDataAlgorithm::createInstance()
const
506 return new QgsDownloadGpsDataAlgorithm();
511 QGS_MARK_ALGORITHM_SOURCE
513 const QString outputPath = parameterAsString( parameters, u
"OUTPUT"_s, context );
517 if ( babelPath.isEmpty() )
518 babelPath = u
"gpsbabel"_s;
520 const QString deviceName = parameterAsString( parameters, u
"DEVICE"_s, context );
527 const QString portName = parameterAsString( parameters, u
"PORT"_s, context );
530 QStringList validPorts;
531 for (
auto it = devices.constBegin(); it != devices.constEnd(); ++it )
533 if ( it->first.compare( portName, Qt::CaseInsensitive ) == 0 || it->second.compare( portName, Qt::CaseInsensitive ) == 0 )
535 inputPort = it->first;
537 validPorts << it->first;
539 if ( inputPort.isEmpty() )
541 throw QgsProcessingException( QObject::tr(
"Unknown port “%1”. Valid ports are: %2" ).arg( portName, validPorts.join(
", "_L1 ) ) );
544 switch ( featureType )
549 throw QgsProcessingException( QObject::tr(
"The GPSBabel format “%1” does not support converting waypoints." ).arg( deviceName ) );
556 throw QgsProcessingException( QObject::tr(
"The GPSBabel format “%1” does not support converting routes." ).arg( deviceName ) );
563 throw QgsProcessingException( QObject::tr(
"The GPSBabel format “%1” does not support converting tracks." ).arg( deviceName ) );
571 const QStringList processCommand = format->
importCommand( babelPath, featureType, inputPort, outputPath );
572 feedback->
pushCommandInfo( QObject::tr(
"Download command: " ) + logCommand.join(
' ' ) );
574 QgsBlockingProcess babelProcess( processCommand.value( 0 ), processCommand.mid( 1 ) );
575 babelProcess.setStdErrHandler( [feedback](
const QByteArray &ba ) { feedback->
reportError( ba ); } );
576 babelProcess.setStdOutHandler( [feedback](
const QByteArray &ba ) { feedback->
pushDebugInfo( ba ); } );
578 const int res = babelProcess.run( feedback );
581 feedback->
pushInfo( QObject::tr(
"Process was canceled and did not complete" ) );
583 else if ( !feedback->
isCanceled() && babelProcess.exitStatus() == QProcess::CrashExit )
589 feedback->
pushInfo( QObject::tr(
"Process completed successfully" ) );
591 else if ( babelProcess.processError() == QProcess::FailedToStart )
593 throw QgsProcessingException( QObject::tr(
"Process %1 failed to start. Either %1 is missing, or you may have insufficient permissions to run the program." ).arg( babelPath ) );
600 std::unique_ptr<QgsVectorLayer> layer;
603 switch ( featureType )
606 layer = std::make_unique<QgsVectorLayer>( outputPath +
"?type=waypoint", layerName, u
"gpx"_s );
609 layer = std::make_unique<QgsVectorLayer>( outputPath +
"?type=route", layerName, u
"gpx"_s );
612 layer = std::make_unique<QgsVectorLayer>( outputPath +
"?type=track", layerName, u
"gpx"_s );
617 if ( !layer->isValid() )
619 feedback->
reportError( QObject::tr(
"Resulting file is not a valid GPX layer" ) );
623 const QString layerId = layer->id();
624 outputs.insert( u
"OUTPUT_LAYER"_s, layerId );
630 outputs.insert( u
"OUTPUT"_s, outputPath );
639QString QgsUploadGpsDataAlgorithm::name()
const
641 return u
"uploadgpsdata"_s;
644QString QgsUploadGpsDataAlgorithm::displayName()
const
646 return QObject::tr(
"Upload GPS data to device" );
649QStringList QgsUploadGpsDataAlgorithm::tags()
const
651 return QObject::tr(
"gps,tools,babel,tracks,waypoints,routes,gpx,import,export,export,device,serial" ).split(
',' );
654QString QgsUploadGpsDataAlgorithm::group()
const
656 return QObject::tr(
"GPS" );
659QString QgsUploadGpsDataAlgorithm::groupId()
const
664void QgsUploadGpsDataAlgorithm::initAlgorithm(
const QVariantMap & )
670 auto deviceParam = std::make_unique<QgsProcessingParameterString>( u
"DEVICE"_s, QObject::tr(
"Device" ) );
673 std::sort( deviceNames.begin(), deviceNames.end(), [](
const QString &a,
const QString &b ) { return a.compare( b, Qt::CaseInsensitive ) < 0; } );
675 deviceParam->setMetadata( { { u
"widget_wrapper"_s, QVariantMap( { { u
"value_hints"_s, deviceNames } } ) } } );
676 addParameter( deviceParam.release() );
679 auto portParam = std::make_unique<QgsProcessingParameterString>( u
"PORT"_s, QObject::tr(
"Port" ) );
682 for (
auto it = devices.constBegin(); it != devices.constEnd(); ++it )
684 std::sort( ports.begin(), ports.end(), [](
const QString &a,
const QString &b ) { return a.compare( b, Qt::CaseInsensitive ) < 0; } );
686 portParam->setMetadata( { { u
"widget_wrapper"_s, QVariantMap( { { u
"value_hints"_s, ports } } ) } } );
687 addParameter( portParam.release() );
689 addParameter(
new QgsProcessingParameterEnum( u
"FEATURE_TYPE"_s, QObject::tr(
"Feature type" ), { QObject::tr(
"Waypoints" ), QObject::tr(
"Routes" ), QObject::tr(
"Tracks" ) },
false, 0 ) );
692QIcon QgsUploadGpsDataAlgorithm::icon()
const
697QString QgsUploadGpsDataAlgorithm::svgIconPath()
const
702QString QgsUploadGpsDataAlgorithm::shortHelpString()
const
704 return QObject::tr(
"This algorithm uses the GPSBabel tool to upload data to a GPS device from the GPX standard format." );
707QString QgsUploadGpsDataAlgorithm::shortDescription()
const
709 return QObject::tr(
"Uploads data to a GPS device from the GPX standard format." );
712QgsUploadGpsDataAlgorithm *QgsUploadGpsDataAlgorithm::createInstance()
const
714 return new QgsUploadGpsDataAlgorithm();
719 QGS_MARK_ALGORITHM_SOURCE
721 const QString inputPath = parameterAsString( parameters, u
"INPUT"_s, context );
725 if ( babelPath.isEmpty() )
726 babelPath = u
"gpsbabel"_s;
728 const QString deviceName = parameterAsString( parameters, u
"DEVICE"_s, context );
735 const QString portName = parameterAsString( parameters, u
"PORT"_s, context );
738 QStringList validPorts;
739 for (
auto it = devices.constBegin(); it != devices.constEnd(); ++it )
741 if ( it->first.compare( portName, Qt::CaseInsensitive ) == 0 || it->second.compare( portName, Qt::CaseInsensitive ) == 0 )
743 outputPort = it->first;
745 validPorts << it->first;
747 if ( outputPort.isEmpty() )
749 throw QgsProcessingException( QObject::tr(
"Unknown port “%1”. Valid ports are: %2" ).arg( portName, validPorts.join(
", "_L1 ) ) );
753 switch ( featureType )
758 throw QgsProcessingException( QObject::tr(
"The GPSBabel format “%1” does not support waypoints." ).arg( deviceName ) );
765 throw QgsProcessingException( QObject::tr(
"The GPSBabel format “%1” does not support routes." ).arg( deviceName ) );
772 throw QgsProcessingException( QObject::tr(
"The GPSBabel format “%1” does not support tracks." ).arg( deviceName ) );
780 const QStringList processCommand = format->
exportCommand( babelPath, featureType, inputPath, outputPort );
781 feedback->
pushCommandInfo( QObject::tr(
"Upload command: " ) + logCommand.join(
' ' ) );
783 QgsBlockingProcess babelProcess( processCommand.value( 0 ), processCommand.mid( 1 ) );
784 babelProcess.setStdErrHandler( [feedback](
const QByteArray &ba ) { feedback->
reportError( ba ); } );
785 babelProcess.setStdOutHandler( [feedback](
const QByteArray &ba ) { feedback->
pushDebugInfo( ba ); } );
787 const int res = babelProcess.run( feedback );
790 feedback->
pushInfo( QObject::tr(
"Process was canceled and did not complete" ) );
792 else if ( !feedback->
isCanceled() && babelProcess.exitStatus() == QProcess::CrashExit )
798 feedback->
pushInfo( QObject::tr(
"Process completed successfully" ) );
800 else if ( babelProcess.processError() == QProcess::FailedToStart )
802 throw QgsProcessingException( QObject::tr(
"Process %1 failed to start. Either %1 is missing, or you may have insufficient permissions to run the program." ).arg( babelPath ) );
@ File
Parameter is a single file.
@ QuoteFilePaths
File paths should be enclosed in quotations and escaped.
GpsFeatureType
GPS feature types.
@ Tracks
Format supports tracks.
@ Waypoints
Format supports waypoints.
@ Routes
Format supports routes.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QgsBabelFormatRegistry * gpsBabelFormatRegistry()
Returns the application's GPSBabel format registry, used for managing GPSBabel formats.
static QString iconPath(const QString &iconFile)
Returns path to the desired icon file.
bool isCanceled() const
Tells whether the operation has been canceled already.
static QList< QPair< QString, QString > > availablePorts()
QgsMapLayer * addMapLayer(QgsMapLayer *layer, bool takeOwnership=true)
Add a layer to the store.
Details for layers to load into projects.
Contains information about the context in which a processing algorithm is executed.
void addLayerToLoadOnCompletion(const QString &layer, const QgsProcessingContext::LayerDetails &details)
Adds a layer to load (by ID or datasource) into the canvas upon completion of the algorithm or model.
QgsProject * project() const
Returns the project in which the algorithm is being executed.
QgsMapLayerStore * temporaryLayerStore()
Returns a reference to the layer store used for storing temporary layers during algorithm execution.
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
virtual void pushCommandInfo(const QString &info)
Pushes an informational message containing a command from the algorithm.
virtual void pushInfo(const QString &info)
Pushes a general informational message from the algorithm.
virtual void pushDebugInfo(const QString &info)
Pushes an informational message containing debugging helpers from the algorithm.
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
A vector layer output for processing algorithms.
An enum based parameter for processing algorithms, allowing for selection from predefined values.
A generic file based destination parameter, for specifying the destination path for a file (non-map l...
An input file or folder parameter for processing algorithms.
@ Vector
Vector layer type.
static QString suggestLayerNameFromFilePath(const QString &path)
Suggests a suitable layer name given only a file path.
static const QgsSettingsEntryString * settingsGpsBabelPath
Settings entry path to GPSBabel executable.