From 31ce6f50c679e61dc53f09ee1b1637918da38a82 Mon Sep 17 00:00:00 2001 From: David Faure Date: Wed, 23 Apr 2014 22:59:34 +0200 Subject: [PATCH] Add QUrl::fromUserInput overload with a cwd argument. Useful for any application that can take URLs on the command-line, so that full paths and relative paths can also be accepted. Change-Id: I8a2c50f36d60bdc49c065b3065972fd5d45fa12a Reviewed-by: Thiago Macieira --- src/corelib/io/qurl.cpp | 60 +++++++++++++++++++++++++ src/corelib/io/qurl.h | 9 ++++ tests/auto/corelib/io/qurl/tst_qurl.cpp | 48 ++++++++++++++++++++ 3 files changed, 117 insertions(+) diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index 7018b333f2d..58b169e5885 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -363,6 +363,29 @@ \sa QUrl::FormattingOptions */ +/*! + \enum QUrl::UserInputResolutionOption + \since 5.4 + + The user input resolution options define how fromUserInput() should + interpret strings that could either be a relative path or the short + form of a HTTP URL. For instance \c{file.pl} can be either a local file + or the URL \c{http://file.pl}. + + \value DefaultResolution The default resolution mechanism is to check + whether a local file exists, in the working + directory given to fromUserInput, and only + return a local path in that case. Otherwise a URL + is assumed. + \value AssumeLocalFile This option makes fromUserInput() always return + a local path unless the input contains a scheme, such as + \c{http://file.pl}. This is useful for applications + such as text editors, which are able to create + the file if it doesn't exist. + + \sa fromUserInput() +*/ + /*! \fn QUrl::QUrl(QUrl &&other) @@ -4091,6 +4114,43 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/*! + Returns a valid URL from a user supplied \a userInput string if one can be + deducted. In the case that is not possible, an invalid QUrl() is returned. + + This overload takes a \a workingDirectory path, in order to be able to + handle relative paths. This is especially useful when handling command + line arguments. + If \a workingDirectory is empty, no handling of relative paths will be done, + so this method will behave like its one argument overload. + + By default, an input string that looks like a relative path will only be treated + as such if the file actually exists in the given working directory. + + If the application can handle files that don't exist yet, it should pass the + flag AssumeLocalFile in \a options. + + \since 5.4 +*/ +QUrl QUrl::fromUserInput(const QString &userInput, const QString &workingDirectory, + UserInputResolutionOptions options) +{ + QString trimmedString = userInput.trimmed(); + + if (trimmedString.isEmpty()) + return QUrl(); + + // Check both QUrl::isRelative (to detect full URLs) and QDir::isAbsolutePath (since on Windows drive letters can be interpreted as schemes) + QUrl url = QUrl(trimmedString, QUrl::TolerantMode); + if (url.isRelative() && !QDir::isAbsolutePath(trimmedString)) { + QFileInfo fileInfo(QDir(workingDirectory), trimmedString); + if ((options & AssumeLocalFile) || fileInfo.exists()) + return QUrl::fromLocalFile(fileInfo.absoluteFilePath()); + } + + return fromUserInput(trimmedString); +} + /*! Returns a valid URL from a user supplied \a userInput string if one can be deducted. In the case that is not possible, an invalid QUrl() is returned. diff --git a/src/corelib/io/qurl.h b/src/corelib/io/qurl.h index 602e91ce306..d621d7ef03d 100644 --- a/src/corelib/io/qurl.h +++ b/src/corelib/io/qurl.h @@ -199,7 +199,16 @@ public: QByteArray toEncoded(FormattingOptions options = FullyEncoded) const; static QUrl fromEncoded(const QByteArray &url, ParsingMode mode = TolerantMode); + enum UserInputResolutionOption { + DefaultResolution, + AssumeLocalFile + }; + Q_DECLARE_FLAGS(UserInputResolutionOptions, UserInputResolutionOption) + static QUrl fromUserInput(const QString &userInput); + // ### Qt6 merge with fromUserInput(QString), by adding = QString() + static QUrl fromUserInput(const QString &userInput, const QString &workingDirectory, + UserInputResolutionOptions options = DefaultResolution); bool isValid() const; QString errorString() const; diff --git a/tests/auto/corelib/io/qurl/tst_qurl.cpp b/tests/auto/corelib/io/qurl/tst_qurl.cpp index 92dbb968170..df090c3de9d 100644 --- a/tests/auto/corelib/io/qurl/tst_qurl.cpp +++ b/tests/auto/corelib/io/qurl/tst_qurl.cpp @@ -165,6 +165,8 @@ private slots: void binaryData(); void fromUserInput_data(); void fromUserInput(); + void fromUserInputWithCwd_data(); + void fromUserInputWithCwd(); void fileName_data(); void fileName(); void isEmptyForEncodedUrl(); @@ -2913,6 +2915,52 @@ void tst_QUrl::fromUserInput() QCOMPARE(url, guessUrlFromString); } +void tst_QUrl::fromUserInputWithCwd_data() +{ + QTest::addColumn("string"); + QTest::addColumn("directory"); + QTest::addColumn("guessedUrlDefault"); + QTest::addColumn("guessedUrlAssumeLocalFile"); + + // Null + QTest::newRow("null") << QString() << QString() << QUrl() << QUrl(); + + // Existing file + QDirIterator it(QDir::currentPath(), QDir::NoDotDot | QDir::AllEntries); + int c = 0; + while (it.hasNext()) { + it.next(); + QUrl url = QUrl::fromLocalFile(it.filePath()); + QTest::newRow(QString("file-%1").arg(c++).toLatin1()) << it.fileName() << QDir::currentPath() << url << url; + } + QDir parent = QDir::current(); + QVERIFY(parent.cdUp()); + QUrl parentUrl = QUrl::fromLocalFile(parent.path()); + QTest::newRow("dotdot") << ".." << QDir::currentPath() << parentUrl << parentUrl; + + QTest::newRow("nonexisting") << "nonexisting" << QDir::currentPath() << QUrl("http://nonexisting") << QUrl::fromLocalFile(QDir::currentPath() + "/nonexisting"); + QTest::newRow("short-url") << "example.org" << QDir::currentPath() << QUrl("http://example.org") << QUrl::fromLocalFile(QDir::currentPath() + "/example.org"); + QTest::newRow("full-url") << "http://example.org" << QDir::currentPath() << QUrl("http://example.org") << QUrl("http://example.org"); + QTest::newRow("absolute") << "/doesnotexist.txt" << QDir::currentPath() << QUrl("file:///doesnotexist.txt") << QUrl("file:///doesnotexist.txt"); +#ifdef Q_OS_WIN + QTest::newRow("windows-absolute") << "c:/doesnotexist.txt" << QDir::currentPath() << QUrl("file:///c:/doesnotexist.txt") << QUrl("file:///c:/doesnotexist.txt"); +#endif +} + +void tst_QUrl::fromUserInputWithCwd() +{ + QFETCH(QString, string); + QFETCH(QString, directory); + QFETCH(QUrl, guessedUrlDefault); + QFETCH(QUrl, guessedUrlAssumeLocalFile); + + QUrl url = QUrl::fromUserInput(string, directory); + QCOMPARE(url, guessedUrlDefault); + + url = QUrl::fromUserInput(string, directory, QUrl::AssumeLocalFile); + QCOMPARE(url, guessedUrlAssumeLocalFile); +} + void tst_QUrl::fileName_data() { QTest::addColumn("urlStr");