19 #if QT_CONFIG(process)
35 QString QgsConvertGpxFeatureTypeAlgorithm::name()
const
37 return QStringLiteral(
"convertgpxfeaturetype" );
40 QString QgsConvertGpxFeatureTypeAlgorithm::displayName()
const
42 return QObject::tr(
"Convert GPX feature type" );
45 QStringList QgsConvertGpxFeatureTypeAlgorithm::tags()
const
47 return QObject::tr(
"gps,tools,babel,tracks,waypoints,routes" ).split(
',' );
50 QString QgsConvertGpxFeatureTypeAlgorithm::group()
const
52 return QObject::tr(
"GPS" );
55 QString QgsConvertGpxFeatureTypeAlgorithm::groupId()
const
57 return QStringLiteral(
"gps" );
60 void QgsConvertGpxFeatureTypeAlgorithm::initAlgorithm(
const QVariantMap & )
63 QObject::tr(
"GPX files" ) + QStringLiteral(
" (*.gpx *.GPX)" ) ) );
67 QObject::tr(
"Waypoints from a Route" ),
68 QObject::tr(
"Waypoints from a Track" ),
69 QObject::tr(
"Route from Waypoints" ),
70 QObject::tr(
"Track from Waypoints" )
78 QIcon QgsConvertGpxFeatureTypeAlgorithm::icon()
const
83 QString QgsConvertGpxFeatureTypeAlgorithm::svgIconPath()
const
88 QString QgsConvertGpxFeatureTypeAlgorithm::shortHelpString()
const
90 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)." );
93 QgsConvertGpxFeatureTypeAlgorithm *QgsConvertGpxFeatureTypeAlgorithm::createInstance()
const
95 return new QgsConvertGpxFeatureTypeAlgorithm();
101 const QStringList convertStrings;
103 const QString inputPath = parameterAsString( parameters, QStringLiteral(
"INPUT" ), context );
104 const QString outputPath = parameterAsString( parameters, QStringLiteral(
"OUTPUT" ), context );
106 const ConversionType convertType =
static_cast< ConversionType
>( parameterAsEnum( parameters, QStringLiteral(
"CONVERSION" ), context ) );
109 if ( babelPath.isEmpty() )
110 babelPath = QStringLiteral(
"gpsbabel" );
112 QStringList processArgs;
114 createArgumentLists( inputPath, outputPath, convertType, processArgs, logArgs );
115 feedback->
pushCommandInfo( QObject::tr(
"Conversion command: " ) + babelPath +
' ' + logArgs.join(
' ' ) );
117 QgsBlockingProcess babelProcess( babelPath, processArgs );
118 babelProcess.setStdErrHandler( [ = ](
const QByteArray & ba )
122 babelProcess.setStdOutHandler( [ = ](
const QByteArray & 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, QStringLiteral(
"gpx" ) );
158 case QgsConvertGpxFeatureTypeAlgorithm::RouteFromWaypoints:
159 layer = std::make_unique< QgsVectorLayer >( outputPath +
"?type=route", layerName, QStringLiteral(
"gpx" ) );
161 case QgsConvertGpxFeatureTypeAlgorithm::TrackFromWaypoints:
162 layer = std::make_unique< QgsVectorLayer >( outputPath +
"?type=track", layerName, QStringLiteral(
"gpx" ) );
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( QStringLiteral(
"OUTPUT_LAYER" ), layerId );
180 outputs.insert( QStringLiteral(
"OUTPUT" ), outputPath );
184 void 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 : { QStringLiteral(
"-i" ), QStringLiteral(
"gpx" ), QStringLiteral(
"-f" ) } )
195 logArgs << QStringLiteral(
"\"%1\"" ).arg( inputPath );
196 processArgs << inputPath;
198 QStringList convertStrings;
199 switch ( conversion )
201 case QgsConvertGpxFeatureTypeAlgorithm::WaypointsFromRoute:
202 convertStrings << QStringLiteral(
"-x" ) << QStringLiteral(
"transform,wpt=rte,del" );
204 case QgsConvertGpxFeatureTypeAlgorithm::WaypointsFromTrack:
205 convertStrings << QStringLiteral(
"-x" ) << QStringLiteral(
"transform,wpt=trk,del" );
207 case QgsConvertGpxFeatureTypeAlgorithm::RouteFromWaypoints:
208 convertStrings << QStringLiteral(
"-x" ) << QStringLiteral(
"transform,rte=wpt,del" );
210 case QgsConvertGpxFeatureTypeAlgorithm::TrackFromWaypoints:
211 convertStrings << QStringLiteral(
"-x" ) << QStringLiteral(
"transform,trk=wpt,del" );
214 logArgs << convertStrings;
215 processArgs << convertStrings;
217 for (
const QString &arg : { QStringLiteral(
"-o" ), QStringLiteral(
"gpx" ), QStringLiteral(
"-F" ) } )
223 logArgs << QStringLiteral(
"\"%1\"" ).arg( outputPath );
224 processArgs << outputPath;
233 QString QgsConvertGpsDataAlgorithm::name()
const
235 return QStringLiteral(
"convertgpsdata" );
238 QString QgsConvertGpsDataAlgorithm::displayName()
const
240 return QObject::tr(
"Convert GPS data" );
243 QStringList QgsConvertGpsDataAlgorithm::tags()
const
245 return QObject::tr(
"gps,tools,babel,tracks,waypoints,routes,gpx,import,export" ).split(
',' );
248 QString QgsConvertGpsDataAlgorithm::group()
const
250 return QObject::tr(
"GPS" );
253 QString QgsConvertGpsDataAlgorithm::groupId()
const
255 return QStringLiteral(
"gps" );
258 void QgsConvertGpsDataAlgorithm::initAlgorithm(
const QVariantMap & )
263 std::unique_ptr< QgsProcessingParameterString > formatParam = std::make_unique< QgsProcessingParameterString >( QStringLiteral(
"FORMAT" ), QObject::tr(
"Format" ) );
267 for (
const QString &format : formatNames )
270 std::sort( formats.begin(), formats.end(), [](
const QString & a,
const QString & b )
272 return a.compare( b, Qt::CaseInsensitive ) < 0;
275 formatParam->setMetadata( {{
276 QStringLiteral(
"widget_wrapper" ), QVariantMap(
277 {{QStringLiteral(
"value_hints" ), formats }}
281 addParameter( formatParam.release() );
285 QObject::tr(
"Waypoints" ),
286 QObject::tr(
"Routes" ),
287 QObject::tr(
"Tracks" )
295 QIcon QgsConvertGpsDataAlgorithm::icon()
const
300 QString QgsConvertGpsDataAlgorithm::svgIconPath()
const
305 QString QgsConvertGpsDataAlgorithm::shortHelpString()
const
307 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." );
310 QgsConvertGpsDataAlgorithm *QgsConvertGpsDataAlgorithm::createInstance()
const
312 return new QgsConvertGpsDataAlgorithm();
317 const QStringList convertStrings;
319 const QString inputPath = parameterAsString( parameters, QStringLiteral(
"INPUT" ), context );
320 const QString outputPath = parameterAsString( parameters, QStringLiteral(
"OUTPUT" ), context );
325 if ( babelPath.isEmpty() )
326 babelPath = QStringLiteral(
"gpsbabel" );
328 const QString formatName = parameterAsString( parameters, QStringLiteral(
"FORMAT" ), context );
340 switch ( featureType )
345 throw QgsProcessingException( QObject::tr(
"The GPSBabel format “%1” does not support converting waypoints." )
346 .arg( formatName ) );
353 throw QgsProcessingException( QObject::tr(
"The GPSBabel format “%1” does not support converting routes." )
354 .arg( formatName ) );
361 throw QgsProcessingException( QObject::tr(
"The GPSBabel format “%1” does not support converting tracks." )
362 .arg( formatName ) );
370 const QStringList processCommand = format->
importCommand( babelPath, featureType, inputPath, outputPath );
371 feedback->
pushCommandInfo( QObject::tr(
"Conversion command: " ) + logCommand.join(
' ' ) );
373 QgsBlockingProcess babelProcess( processCommand.value( 0 ), processCommand.mid( 1 ) );
374 babelProcess.setStdErrHandler( [ = ](
const QByteArray & ba )
378 babelProcess.setStdOutHandler( [ = ](
const QByteArray & ba )
383 const int res = babelProcess.run( feedback );
386 feedback->
pushInfo( QObject::tr(
"Process was canceled and did not complete" ) ) ;
388 else if ( !feedback->
isCanceled() && babelProcess.exitStatus() == QProcess::CrashExit )
394 feedback->
pushInfo( QObject::tr(
"Process completed successfully" ) );
396 else if ( babelProcess.processError() == QProcess::FailedToStart )
398 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 ) );
405 std::unique_ptr< QgsVectorLayer > layer;
408 switch ( featureType )
411 layer = std::make_unique< QgsVectorLayer >( outputPath +
"?type=waypoint", layerName, QStringLiteral(
"gpx" ) );
414 layer = std::make_unique< QgsVectorLayer >( outputPath +
"?type=route", layerName, QStringLiteral(
"gpx" ) );
417 layer = std::make_unique< QgsVectorLayer >( outputPath +
"?type=track", layerName, QStringLiteral(
"gpx" ) );
422 if ( !layer->isValid() )
424 feedback->
reportError( QObject::tr(
"Resulting file is not a valid GPX layer" ) );
428 const QString layerId = layer->id();
429 outputs.insert( QStringLiteral(
"OUTPUT_LAYER" ), layerId );
435 outputs.insert( QStringLiteral(
"OUTPUT" ), outputPath );
443 QString QgsDownloadGpsDataAlgorithm::name()
const
445 return QStringLiteral(
"downloadgpsdata" );
448 QString QgsDownloadGpsDataAlgorithm::displayName()
const
450 return QObject::tr(
"Download GPS data from device" );
453 QStringList QgsDownloadGpsDataAlgorithm::tags()
const
455 return QObject::tr(
"gps,tools,babel,tracks,waypoints,routes,gpx,import,export,export,device,serial" ).split(
',' );
458 QString QgsDownloadGpsDataAlgorithm::group()
const
460 return QObject::tr(
"GPS" );
463 QString QgsDownloadGpsDataAlgorithm::groupId()
const
465 return QStringLiteral(
"gps" );
468 void QgsDownloadGpsDataAlgorithm::initAlgorithm(
const QVariantMap & )
470 std::unique_ptr< QgsProcessingParameterString > deviceParam = std::make_unique< QgsProcessingParameterString >( QStringLiteral(
"DEVICE" ), QObject::tr(
"Device" ) );
473 std::sort( deviceNames.begin(), deviceNames.end(), [](
const QString & a,
const QString & b )
475 return a.compare( b, Qt::CaseInsensitive ) < 0;
478 deviceParam->setMetadata( {{
479 QStringLiteral(
"widget_wrapper" ), QVariantMap(
480 {{QStringLiteral(
"value_hints" ), deviceNames }}
484 addParameter( deviceParam.release() );
487 const QList< QPair<QString, QString> > devices =
QgsGpsDetector::availablePorts() << QPair<QString, QString>( QStringLiteral(
"usb:" ), QStringLiteral(
"usb:" ) );
488 std::unique_ptr< QgsProcessingParameterString > portParam = std::make_unique< QgsProcessingParameterString >( QStringLiteral(
"PORT" ), QObject::tr(
"Port" ) );
491 for (
auto it = devices.constBegin(); it != devices.constEnd(); ++ it )
493 std::sort( ports.begin(), ports.end(), [](
const QString & a,
const QString & b )
495 return a.compare( b, Qt::CaseInsensitive ) < 0;
498 portParam->setMetadata( {{
499 QStringLiteral(
"widget_wrapper" ), QVariantMap(
500 {{QStringLiteral(
"value_hints" ), ports }}
504 addParameter( portParam.release() );
508 QObject::tr(
"Waypoints" ),
509 QObject::tr(
"Routes" ),
510 QObject::tr(
"Tracks" )
518 QIcon QgsDownloadGpsDataAlgorithm::icon()
const
523 QString QgsDownloadGpsDataAlgorithm::svgIconPath()
const
528 QString QgsDownloadGpsDataAlgorithm::shortHelpString()
const
530 return QObject::tr(
"This algorithm uses the GPSBabel tool to download data from a GPS device into the GPX standard format." );
533 QgsDownloadGpsDataAlgorithm *QgsDownloadGpsDataAlgorithm::createInstance()
const
535 return new QgsDownloadGpsDataAlgorithm();
540 const QString outputPath = parameterAsString( parameters, QStringLiteral(
"OUTPUT" ), context );
544 if ( babelPath.isEmpty() )
545 babelPath = QStringLiteral(
"gpsbabel" );
547 const QString deviceName = parameterAsString( parameters, QStringLiteral(
"DEVICE" ), context );
556 const QString portName = parameterAsString( parameters, QStringLiteral(
"PORT" ), context );
558 const QList< QPair<QString, QString> > devices =
QgsGpsDetector::availablePorts() << QPair<QString, QString>( QStringLiteral(
"usb:" ), QStringLiteral(
"usb:" ) );
559 QStringList validPorts;
560 for (
auto it = devices.constBegin(); it != devices.constEnd(); ++it )
562 if ( it->first.compare( portName, Qt::CaseInsensitive ) == 0 || it->second.compare( portName, Qt::CaseInsensitive ) == 0 )
564 inputPort = it->first;
566 validPorts << it->first;
568 if ( inputPort.isEmpty() )
572 validPorts.join( QLatin1String(
", " ) ) ) );
575 switch ( featureType )
580 throw QgsProcessingException( QObject::tr(
"The GPSBabel format “%1” does not support converting waypoints." )
581 .arg( deviceName ) );
588 throw QgsProcessingException( QObject::tr(
"The GPSBabel format “%1” does not support converting routes." )
589 .arg( deviceName ) );
596 throw QgsProcessingException( QObject::tr(
"The GPSBabel format “%1” does not support converting tracks." )
597 .arg( deviceName ) );
605 const QStringList processCommand = format->
importCommand( babelPath, featureType, inputPort, outputPath );
606 feedback->
pushCommandInfo( QObject::tr(
"Download command: " ) + logCommand.join(
' ' ) );
608 QgsBlockingProcess babelProcess( processCommand.value( 0 ), processCommand.mid( 1 ) );
609 babelProcess.setStdErrHandler( [ = ](
const QByteArray & ba )
613 babelProcess.setStdOutHandler( [ = ](
const QByteArray & ba )
618 const int res = babelProcess.run( feedback );
621 feedback->
pushInfo( QObject::tr(
"Process was canceled and did not complete" ) ) ;
623 else if ( !feedback->
isCanceled() && babelProcess.exitStatus() == QProcess::CrashExit )
629 feedback->
pushInfo( QObject::tr(
"Process completed successfully" ) );
631 else if ( babelProcess.processError() == QProcess::FailedToStart )
633 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 ) );
640 std::unique_ptr< QgsVectorLayer > layer;
643 switch ( featureType )
646 layer = std::make_unique< QgsVectorLayer >( outputPath +
"?type=waypoint", layerName, QStringLiteral(
"gpx" ) );
649 layer = std::make_unique< QgsVectorLayer >( outputPath +
"?type=route", layerName, QStringLiteral(
"gpx" ) );
652 layer = std::make_unique< QgsVectorLayer >( outputPath +
"?type=track", layerName, QStringLiteral(
"gpx" ) );
657 if ( !layer->isValid() )
659 feedback->
reportError( QObject::tr(
"Resulting file is not a valid GPX layer" ) );
663 const QString layerId = layer->id();
664 outputs.insert( QStringLiteral(
"OUTPUT_LAYER" ), layerId );
670 outputs.insert( QStringLiteral(
"OUTPUT" ), outputPath );
679 QString QgsUploadGpsDataAlgorithm::name()
const
681 return QStringLiteral(
"uploadgpsdata" );
684 QString QgsUploadGpsDataAlgorithm::displayName()
const
686 return QObject::tr(
"Upload GPS data to device" );
689 QStringList QgsUploadGpsDataAlgorithm::tags()
const
691 return QObject::tr(
"gps,tools,babel,tracks,waypoints,routes,gpx,import,export,export,device,serial" ).split(
',' );
694 QString QgsUploadGpsDataAlgorithm::group()
const
696 return QObject::tr(
"GPS" );
699 QString QgsUploadGpsDataAlgorithm::groupId()
const
701 return QStringLiteral(
"gps" );
704 void QgsUploadGpsDataAlgorithm::initAlgorithm(
const QVariantMap & )
707 QObject::tr(
"GPX files" ) + QStringLiteral(
" (*.gpx *.GPX)" ) ) );
709 std::unique_ptr< QgsProcessingParameterString > deviceParam = std::make_unique< QgsProcessingParameterString >( QStringLiteral(
"DEVICE" ), QObject::tr(
"Device" ) );
712 std::sort( deviceNames.begin(), deviceNames.end(), [](
const QString & a,
const QString & b )
714 return a.compare( b, Qt::CaseInsensitive ) < 0;
717 deviceParam->setMetadata( {{
718 QStringLiteral(
"widget_wrapper" ), QVariantMap(
719 {{QStringLiteral(
"value_hints" ), deviceNames }}
723 addParameter( deviceParam.release() );
725 const QList< QPair<QString, QString> > devices =
QgsGpsDetector::availablePorts() << QPair<QString, QString>( QStringLiteral(
"usb:" ), QStringLiteral(
"usb:" ) );
726 std::unique_ptr< QgsProcessingParameterString > portParam = std::make_unique< QgsProcessingParameterString >( QStringLiteral(
"PORT" ), QObject::tr(
"Port" ) );
729 for (
auto it = devices.constBegin(); it != devices.constEnd(); ++ it )
731 std::sort( ports.begin(), ports.end(), [](
const QString & a,
const QString & b )
733 return a.compare( b, Qt::CaseInsensitive ) < 0;
736 portParam->setMetadata( {{
737 QStringLiteral(
"widget_wrapper" ), QVariantMap(
738 {{QStringLiteral(
"value_hints" ), ports }}
742 addParameter( portParam.release() );
746 QObject::tr(
"Waypoints" ),
747 QObject::tr(
"Routes" ),
748 QObject::tr(
"Tracks" )
753 QIcon QgsUploadGpsDataAlgorithm::icon()
const
758 QString QgsUploadGpsDataAlgorithm::svgIconPath()
const
763 QString QgsUploadGpsDataAlgorithm::shortHelpString()
const
765 return QObject::tr(
"This algorithm uses the GPSBabel tool to upload data to a GPS device from the GPX standard format." );
768 QgsUploadGpsDataAlgorithm *QgsUploadGpsDataAlgorithm::createInstance()
const
770 return new QgsUploadGpsDataAlgorithm();
775 const QString inputPath = parameterAsString( parameters, QStringLiteral(
"INPUT" ), context );
779 if ( babelPath.isEmpty() )
780 babelPath = QStringLiteral(
"gpsbabel" );
782 const QString deviceName = parameterAsString( parameters, QStringLiteral(
"DEVICE" ), context );
791 const QString portName = parameterAsString( parameters, QStringLiteral(
"PORT" ), context );
793 const QList< QPair<QString, QString> > devices =
QgsGpsDetector::availablePorts() << QPair<QString, QString>( QStringLiteral(
"usb:" ), QStringLiteral(
"usb:" ) );
794 QStringList validPorts;
795 for (
auto it = devices.constBegin(); it != devices.constEnd(); ++it )
797 if ( it->first.compare( portName, Qt::CaseInsensitive ) == 0 || it->second.compare( portName, Qt::CaseInsensitive ) == 0 )
799 outputPort = it->first;
801 validPorts << it->first;
803 if ( outputPort.isEmpty() )
807 validPorts.join( QLatin1String(
", " ) ) ) );
811 switch ( featureType )
817 .arg( deviceName ) );
825 .arg( deviceName ) );
833 .arg( deviceName ) );
841 const QStringList processCommand = format->
exportCommand( babelPath, featureType, inputPath, outputPort );
842 feedback->
pushCommandInfo( QObject::tr(
"Upload command: " ) + logCommand.join(
' ' ) );
844 QgsBlockingProcess babelProcess( processCommand.value( 0 ), processCommand.mid( 1 ) );
845 babelProcess.setStdErrHandler( [ = ](
const QByteArray & ba )
849 babelProcess.setStdOutHandler( [ = ](
const QByteArray & ba )
854 const int res = babelProcess.run( feedback );
857 feedback->
pushInfo( QObject::tr(
"Process was canceled and did not complete" ) ) ;
859 else if ( !feedback->
isCanceled() && babelProcess.exitStatus() == QProcess::CrashExit )
865 feedback->
pushInfo( QObject::tr(
"Process completed successfully" ) );
867 else if ( babelProcess.processError() == QProcess::FailedToStart )
869 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 ) );