diff --git a/src/gui/qgsfilewidget.cpp b/src/gui/qgsfilewidget.cpp index 8952a79c2f4..12cc727536b 100644 --- a/src/gui/qgsfilewidget.cpp +++ b/src/gui/qgsfilewidget.cpp @@ -82,17 +82,46 @@ QString QgsFileWidget::filePath() QStringList QgsFileWidget::splitFilePaths( const QString &path ) { - QStringList paths; - const thread_local QRegularExpression partsRegex = QRegularExpression( QStringLiteral( "\"\\s+\"" ) ); - const QStringList pathParts = path.split( partsRegex, Qt::SkipEmptyParts ); + QStringList pathParts; + // Iterate over regular expression matches in the path instead of splitting the path on an expression. + // Splitting on an expression discards the string parts matching the expression. + // We want to split on spaces between double quotes without discarding double quotes around spaces. + // The decision whether to discard double quotes is made later, based on each isolated split path. + const thread_local QRegularExpression partSeparatorsRegex = QRegularExpression( QStringLiteral( "(?:\")(\\s+)(?:\")" ) ); + QRegularExpressionMatchIterator partSeparatorMatches = partSeparatorsRegex.globalMatch( path ); + int substringStart = 0; + while ( partSeparatorMatches.hasNext() ) + { + QRegularExpressionMatch match = partSeparatorMatches.next(); + int substringEnd = match.capturedStart() + 1; + int substringLength = substringEnd - substringStart; + pathParts.append( path.mid( substringStart, substringLength ) ); + substringStart = match.capturedEnd() - 1; + if ( !partSeparatorMatches.hasNext() ) + { + pathParts.append( path.mid( substringStart ) ); + } + } + if ( pathParts.length() == 0 ) + { + pathParts.append( path ); + } - const thread_local QRegularExpression cleanRe( QStringLiteral( "(^\\s*\")|(\"\\s*)" ) ); - paths.reserve( pathParts.size() ); + QStringList paths; + const thread_local QRegularExpression doubleQuoteWrappedRegex( QStringLiteral( "(?:^\\s*\")(.+)(?:\"\\s*$)" ) ); for ( const QString &pathsPart : pathParts ) { - QString cleaned = pathsPart; - cleaned.remove( cleanRe ); - paths.append( cleaned ); + QRegularExpressionMatch match = doubleQuoteWrappedRegex.match( pathsPart ); + QString finalPath; + if ( match.hasMatch() ) + { + finalPath = match.captured( 1 ); + } + else + { + finalPath = pathsPart; + } + paths.append( finalPath ); } return paths; } diff --git a/tests/src/gui/testqgsfilewidget.cpp b/tests/src/gui/testqgsfilewidget.cpp index f1e1a0113b6..fdbd53c58b9 100644 --- a/tests/src/gui/testqgsfilewidget.cpp +++ b/tests/src/gui/testqgsfilewidget.cpp @@ -209,6 +209,26 @@ void TestQgsFileWidget::testSplitFilePaths() QCOMPARE( QgsFileWidget::splitFilePaths( QStringLiteral( " \"%1\" \"%1\" " ).arg( path ) ), QStringList() << path << path ); QCOMPARE( QgsFileWidget::splitFilePaths( QStringLiteral( "\"%1\" \"%1\" " ).arg( path ) ), QStringList() << path << path ); QCOMPARE( QgsFileWidget::splitFilePaths( path ), QStringList() << path ); + + const QString pathPrefixed = QString( TEST_DATA_DIR + QStringLiteral( "ZARR:\"/path/to/store.zarr\"" ) ); + QCOMPARE( QgsFileWidget::splitFilePaths( QStringLiteral( "\"%1\" \"%1\"" ).arg( pathPrefixed ) ), QStringList() << pathPrefixed << pathPrefixed ); + QCOMPARE( QgsFileWidget::splitFilePaths( QStringLiteral( "\"%1\" \"%1\"" ).arg( pathPrefixed ) ), QStringList() << pathPrefixed << pathPrefixed ); + QCOMPARE( QgsFileWidget::splitFilePaths( QStringLiteral( " \"%1\" \"%1\"" ).arg( pathPrefixed ) ), QStringList() << pathPrefixed << pathPrefixed ); + QCOMPARE( QgsFileWidget::splitFilePaths( QStringLiteral( " \"%1\" \"%1\" " ).arg( pathPrefixed ) ), QStringList() << pathPrefixed << pathPrefixed ); + QCOMPARE( QgsFileWidget::splitFilePaths( QStringLiteral( "\"%1\" \"%1\" " ).arg( pathPrefixed ) ), QStringList() << pathPrefixed << pathPrefixed ); + QCOMPARE( QgsFileWidget::splitFilePaths( pathPrefixed ), QStringList() << pathPrefixed ); + + QCOMPARE( QgsFileWidget::splitFilePaths( QStringLiteral( "\"%1\" \"%2\"" ).arg( path, pathPrefixed ) ), QStringList() << path << pathPrefixed ); + QCOMPARE( QgsFileWidget::splitFilePaths( QStringLiteral( "\"%1\" \"%2\"" ).arg( path, pathPrefixed ) ), QStringList() << path << pathPrefixed ); + QCOMPARE( QgsFileWidget::splitFilePaths( QStringLiteral( " \"%1\" \"%2\"" ).arg( path, pathPrefixed ) ), QStringList() << path << pathPrefixed ); + QCOMPARE( QgsFileWidget::splitFilePaths( QStringLiteral( " \"%1\" \"%2\" " ).arg( path, pathPrefixed ) ), QStringList() << path << pathPrefixed ); + QCOMPARE( QgsFileWidget::splitFilePaths( QStringLiteral( "\"%1\" \"%2\" " ).arg( path, pathPrefixed ) ), QStringList() << path << pathPrefixed ); + + QCOMPARE( QgsFileWidget::splitFilePaths( QStringLiteral( "\"%1\" \"%2\"" ).arg( pathPrefixed, path ) ), QStringList() << pathPrefixed << path ); + QCOMPARE( QgsFileWidget::splitFilePaths( QStringLiteral( "\"%1\" \"%2\"" ).arg( pathPrefixed, path ) ), QStringList() << pathPrefixed << path ); + QCOMPARE( QgsFileWidget::splitFilePaths( QStringLiteral( " \"%1\" \"%2\"" ).arg( pathPrefixed, path ) ), QStringList() << pathPrefixed << path ); + QCOMPARE( QgsFileWidget::splitFilePaths( QStringLiteral( " \"%1\" \"%2\" " ).arg( pathPrefixed, path ) ), QStringList() << pathPrefixed << path ); + QCOMPARE( QgsFileWidget::splitFilePaths( QStringLiteral( "\"%1\" \"%2\" " ).arg( pathPrefixed, path ) ), QStringList() << pathPrefixed << path ); } QGSTEST_MAIN( TestQgsFileWidget )