Skip to content

Commit

Permalink
Add QUrl::fromUserInput overload with a cwd argument.
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
dfaure-kdab authored and The Qt Project committed May 5, 2014
1 parent da24bfe commit 31ce6f5
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 0 deletions.
60 changes: 60 additions & 0 deletions src/corelib/io/qurl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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.
Expand Down
9 changes: 9 additions & 0 deletions src/corelib/io/qurl.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,16 @@ class Q_CORE_EXPORT QUrl
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;
Expand Down
48 changes: 48 additions & 0 deletions tests/auto/corelib/io/qurl/tst_qurl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -2913,6 +2915,52 @@ void tst_QUrl::fromUserInput()
QCOMPARE(url, guessUrlFromString);
}

void tst_QUrl::fromUserInputWithCwd_data()
{
QTest::addColumn<QString>("string");
QTest::addColumn<QString>("directory");
QTest::addColumn<QUrl>("guessedUrlDefault");
QTest::addColumn<QUrl>("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<QString>("urlStr");
Expand Down

0 comments on commit 31ce6f5

Please sign in to comment.