diff --git a/libtaskmanager/autotests/launchertasksmodeltest.cpp b/libtaskmanager/autotests/launchertasksmodeltest.cpp --- a/libtaskmanager/autotests/launchertasksmodeltest.cpp +++ b/libtaskmanager/autotests/launchertasksmodeltest.cpp @@ -36,6 +36,7 @@ void shouldRoundTripLauncherUrlList(); void shouldIgnoreInvalidUrls(); + void shouldAcceptSpaces(); void shouldRejectDuplicates(); void shouldAddRemoveLauncher(); void shouldReturnValidLauncherPositions(); @@ -91,6 +92,25 @@ QCOMPARE(m.launcherList(), QStringList()); } +void LauncherTasksModelTest::shouldAcceptSpaces() +{ + LauncherTasksModel m; + + const QStringList urlStrings{ + QLatin1String("applications:App with spaces.desktop") + }; + + QSignalSpy launcherListChangedSpy(&m, &LauncherTasksModel::launcherListChanged); + QVERIFY(launcherListChangedSpy.isValid()); + + const bool added = m.requestAddLauncher(QUrl(urlStrings.at(0))); + + QVERIFY(added); + QCOMPARE(launcherListChangedSpy.count(), 1); + + QCOMPARE(m.launcherList(), QStringList() << urlStrings.at(0)); +} + void LauncherTasksModelTest::shouldRejectDuplicates() { LauncherTasksModel m; diff --git a/libtaskmanager/launchertasksmodel.cpp b/libtaskmanager/launchertasksmodel.cpp --- a/libtaskmanager/launchertasksmodel.cpp +++ b/libtaskmanager/launchertasksmodel.cpp @@ -143,15 +143,13 @@ bool LauncherTasksModel::Private::requestAddLauncherToActivities(const QUrl &_url, const QStringList &_activities) { - // isValid() for the passed-in URL might return true if it was - // constructed in TolerantMode, but we want to reject invalid URLs. - QUrl url(_url.toString(), QUrl::StrictMode); - const auto activities = ActivitiesSet::fromList(_activities); - - if (url.isEmpty() || !url.isValid()) { + QUrl url(_url); + if (!isValidLauncherUrl(url)) { return false; } + const auto activities = ActivitiesSet::fromList(_activities); + if (url.isLocalFile() && KDesktopFile::isDesktopFile(url.toLocalFile())) { KDesktopFile f(url.toLocalFile()); @@ -409,7 +407,9 @@ auto activities = ActivitiesSet::fromList(_activities); // Is url is not valid, ignore it - if (!url.isValid()) continue; + if (!isValidLauncherUrl(url)) { + continue; + } // If we have a null uuid, it means we are on all activities // and we should contain only the null uuid diff --git a/libtaskmanager/launchertasksmodel_p.h b/libtaskmanager/launchertasksmodel_p.h --- a/libtaskmanager/launchertasksmodel_p.h +++ b/libtaskmanager/launchertasksmodel_p.h @@ -29,10 +29,25 @@ #define NULL_UUID "00000000-0000-0000-0000-000000000000" +inline static bool isValidLauncherUrl(const QUrl &url) +{ + if (url.isEmpty() || !url.isValid()) { + return false; + } + + if (!url.isLocalFile() + && url.scheme() != QLatin1String("applications") + && url.scheme() != QLatin1String("preferred")) { + return false; + } + + return true; +} + inline static std::pair deserializeLauncher(const QString &serializedLauncher) { QStringList activities; - QUrl url(serializedLauncher, QUrl::StrictMode); + QUrl url(serializedLauncher); // The storage format is: [list of activity ids]\nURL // The activity IDs list can not be empty, it at least needs @@ -47,7 +62,7 @@ activities = serializedLauncher.mid(1, activitiesBlockEnd - 1).split(",", QString::SkipEmptyParts); if (!activities.isEmpty()) { - url = QUrl(serializedLauncher.mid(activitiesBlockEnd + 2), QUrl::StrictMode); + url = QUrl(serializedLauncher.mid(activitiesBlockEnd + 2)); } } }