From eb5749e8d9e873ac5aec2ba042d7a04b894f1421 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 9 Jul 2013 11:39:13 -0700 Subject: [PATCH] Bugfix QDesktopServices on Windows It was doing tricks with URLs that it shouldn't be doing... including running QDir::toNativeSeparators on a URL. Task-number: QTBUG-32311 Change-Id: I5b6f640919956998c00dcf507f931045f21a9e53 Reviewed-by: Friedemann Kleint --- .../platforms/windows/qwindowsservices.cpp | 18 +-- .../qdesktopservices/tst_qdesktopservices.cpp | 1 + tests/manual/manual.pro | 1 + .../qdesktopservices/qdesktopservices.pro | 14 ++ tests/manual/qdesktopservices/test.txt | 1 + .../qdesktopservices/tst_qdesktopservices.cpp | 126 ++++++++++++++++++ 6 files changed, 152 insertions(+), 9 deletions(-) create mode 100644 tests/manual/qdesktopservices/qdesktopservices.pro create mode 100644 tests/manual/qdesktopservices/test.txt create mode 100644 tests/manual/qdesktopservices/tst_qdesktopservices.cpp diff --git a/src/plugins/platforms/windows/qwindowsservices.cpp b/src/plugins/platforms/windows/qwindowsservices.cpp index 250fea56b1..546957a043 100644 --- a/src/plugins/platforms/windows/qwindowsservices.cpp +++ b/src/plugins/platforms/windows/qwindowsservices.cpp @@ -39,6 +39,7 @@ ** ****************************************************************************/ +#define QT_NO_URL_CAST_FROM_STRING #include "qwindowsservices.h" #include "qtwindows_additional.h" @@ -55,19 +56,20 @@ QT_BEGIN_NAMESPACE enum { debug = 0 }; -static inline bool shellExecute(const QString &file) +static inline bool shellExecute(const QUrl &url) { #ifndef Q_OS_WINCE - const QString nativeFilePath = QDir::toNativeSeparators(file); + const QString nativeFilePath = + url.isLocalFile() ? QDir::toNativeSeparators(url.toLocalFile()) : url.toString(QUrl::FullyEncoded); const quintptr result = (quintptr)ShellExecute(0, 0, (wchar_t*)nativeFilePath.utf16(), 0, 0, SW_SHOWNORMAL); // ShellExecute returns a value greater than 32 if successful if (result <= 32) { - qWarning("ShellExecute '%s' failed (error %s).", qPrintable(file), qPrintable(QString::number(result))); + qWarning("ShellExecute '%s' failed (error %s).", qPrintable(url.toString()), qPrintable(QString::number(result))); return false; } return true; #else - Q_UNUSED(file) + Q_UNUSED(url); return false; #endif } @@ -131,7 +133,7 @@ static inline bool launchMail(const QUrl &url) } // Pass the url as the parameter. Should use QProcess::startDetached(), // but that cannot handle a Windows command line [yet]. - command.replace(QStringLiteral("%1"), url.toString()); + command.replace(QStringLiteral("%1"), url.toString(QUrl::FullyEncoded)); if (debug) qDebug() << __FUNCTION__ << "Launching" << command; //start the process @@ -152,16 +154,14 @@ static inline bool launchMail(const QUrl &url) bool QWindowsServices::openUrl(const QUrl &url) { const QString scheme = url.scheme(); - if (scheme.isEmpty()) - return openDocument(url); if (scheme == QStringLiteral("mailto") && launchMail(url)) return true; - return shellExecute(QLatin1String(url.toEncoded())); + return shellExecute(url); } bool QWindowsServices::openDocument(const QUrl &url) { - return shellExecute(url.isLocalFile() ? url.toLocalFile() : url.toString()); + return shellExecute(url); } QT_END_NAMESPACE diff --git a/tests/auto/gui/util/qdesktopservices/tst_qdesktopservices.cpp b/tests/auto/gui/util/qdesktopservices/tst_qdesktopservices.cpp index 8b4e209b1b..56dcdd5698 100644 --- a/tests/auto/gui/util/qdesktopservices/tst_qdesktopservices.cpp +++ b/tests/auto/gui/util/qdesktopservices/tst_qdesktopservices.cpp @@ -82,6 +82,7 @@ void tst_qdesktopservices::openUrl() QCOMPARE(QDesktopServices::openUrl(QUrl()), false); #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) // this test is only valid on windows on other systems it might mean open a new document in the application handling .file + QTest::ignoreMessage(QtWarningMsg, "ShellExecute 'file://invalid.file' failed (error 3)."); QCOMPARE(QDesktopServices::openUrl(QUrl("file://invalid.file")), false); #endif } diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro index d97c69025b..8d99d17e41 100644 --- a/tests/manual/manual.pro +++ b/tests/manual/manual.pro @@ -9,6 +9,7 @@ lance \ network_remote_stresstest \ network_stresstest \ qcursor \ +qdesktopservices \ qdesktopwidget \ qgraphicsitem \ qgraphicsitemgroup \ diff --git a/tests/manual/qdesktopservices/qdesktopservices.pro b/tests/manual/qdesktopservices/qdesktopservices.pro new file mode 100644 index 0000000000..c96287e159 --- /dev/null +++ b/tests/manual/qdesktopservices/qdesktopservices.pro @@ -0,0 +1,14 @@ +QT += testlib + +TARGET = tst_qdesktopservices +CONFIG += console +CONFIG -= app_bundle + +TEMPLATE = app + + +SOURCES += tst_qdesktopservices.cpp +DEFINES += SRCDIR=\\\"$$PWD/\\\" + +OTHER_FILES += \ + test.txt diff --git a/tests/manual/qdesktopservices/test.txt b/tests/manual/qdesktopservices/test.txt new file mode 100644 index 0000000000..002d92488d --- /dev/null +++ b/tests/manual/qdesktopservices/test.txt @@ -0,0 +1 @@ +This is just a plain text file. diff --git a/tests/manual/qdesktopservices/tst_qdesktopservices.cpp b/tests/manual/qdesktopservices/tst_qdesktopservices.cpp new file mode 100644 index 0000000000..534816a01b --- /dev/null +++ b/tests/manual/qdesktopservices/tst_qdesktopservices.cpp @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Intel Corporation. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include + +class tst_QDesktopServices : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void openUrl(); + void openUrl_data(); +}; + +void tst_QDesktopServices::openUrl_data() +{ + QTest::addColumn("data"); + QTest::addColumn("message"); + + QUrl localFile = QUrl::fromLocalFile(QFINDTESTDATA("test.txt")); + + QTest::newRow("text-file") + << localFile + << "This should open test.txt in a text editor"; + + localFile.setQuery("x=y"); + QTest::newRow("text-file-with-query") + << localFile + << "This should open test.txt in a text editor. Queries do not usually show up."; + + localFile.setQuery(QString()); + localFile.setFragment("top"); + QTest::newRow("text-file-with-fragment") + << localFile + << "This should open test.txt in a text editor. Fragments do not usually show up."; + + QTest::newRow("browser-plain") + << QUrl("http://qt-project.org") + << "This should open http://qt-project.org in the default web browser"; + + QTest::newRow("search-url") + << QUrl("http://google.com/search?q=Qt+Project") + << "This should search \"Qt Project\" on Google"; + + QTest::newRow("search-url-with-space") + << QUrl("http://google.com/search?q=Qt Project") + << "This should search \"Qt Project\" on Google"; + + QTest::newRow("search-url-with-quotes") + << QUrl("http://google.com/search?q=\"Qt+Project\"") + << "This should search '\"Qt Project\"' on Google (including the quotes)"; + + QTest::newRow("search-url-with-hashtag") + << QUrl("http://google.com/search?q=%23qtproject") + << "This should search \"#qtproject\" on Google. The # should appear in the Google search field"; + + QTest::newRow("search-url-with-fragment") + << QUrl("http://google.com/search?q=Qt+Project#top") + << "This should search \"Qt Project\" on Google. There should be no # in the Google search field"; + + // see QTBUG-32311 + QTest::newRow("search-url-with-slashes") + << QUrl("http://google.com/search?q=/profile/5") + << "This should search \"/profile/5\" on Google."; + + QTest::newRow("mail") + << QUrl("mailto:development@qt-project.org") + << "This should open an email composer with the destination set to development@qt-project.org"; + + QTest::newRow("mail-subject") + << QUrl("mailto:development@qt-project.org?subject=[Development]%20Test%20Mail") + << "This should open an email composer and tries to set the subject"; +} + +void tst_QDesktopServices::openUrl() +{ + QFETCH(QUrl, data); + QFETCH(QString, message); + qWarning("\n\nOpening \"%s\": %s", qPrintable(data.toString()), qPrintable(message)); + QDesktopServices::openUrl(data); +} + +QTEST_MAIN(tst_QDesktopServices) + +#include "tst_qdesktopservices.moc"