locationrunner.cpp 6.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 *   Copyright (C) 2007 Teemu Rytilahti <tpr@iki.fi>
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Library General Public License version 2 as
 *   published by the Free Software Foundation
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details
 *
 *   You should have received a copy of the GNU Library General Public
 *   License along with this program; if not, write to the
 *   Free Software Foundation, Inc.,
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "locationrunner.h"

#include <QMimeData>
Vishesh Handa's avatar
Vishesh Handa committed
22
#include <QIcon>
23
#include <QUrl>
24
#include <QDir>
25 26

#include <QDebug>
27
#include <KApplicationTrader>
28
#include <KLocalizedString>
29 30
#include <KProtocolInfo>
#include <KUriFilter>
31
#include <KIO/DesktopExecParser>
32
#include <KIO/Global>
33
#include <KShell>
34 35
#include <KIO/OpenUrlJob>
#include <KNotificationJobUiDelegate>
36

37
K_EXPORT_PLASMA_RUNNER_WITH_JSON(LocationsRunner, "plasma-runner-locations.json")
38 39


40 41
LocationsRunner::LocationsRunner(QObject *parent, const KPluginMetaData &metaData, const QVariantList& args)
    : Plasma::AbstractRunner(parent, metaData, args)
42 43
{
    // set the name shown after the result in krunner window
44 45
    setObjectName(QStringLiteral("Locations"));
    addSyntax(Plasma::RunnerSyntax(QStringLiteral(":q:"),
46 47 48 49 50 51 52 53 54 55 56 57
              i18n("Finds local directories and files, network locations and Internet sites with paths matching :q:.")));
}

LocationsRunner::~LocationsRunner()
{
}

void LocationsRunner::match(Plasma::RunnerContext &context)
{
    QString term = context.query();
    Plasma::RunnerContext::Type type = context.type();

58 59
    QFileInfo fileInfo(KShell::tildeExpand(term));
    if (fileInfo.exists()) {
60 61 62 63 64
        Plasma::QueryMatch match(this);
        match.setType(Plasma::QueryMatch::ExactMatch);
        match.setText(i18n("Open %1", term));

        if (type == Plasma::RunnerContext::File) {
65
            match.setIconName(KIO::iconNameForUrl(QUrl(term)));
66
        } else {
67
            match.setIconName(QStringLiteral("system-file-manager"));
68 69 70 71 72 73
        }

        match.setRelevance(1);
        match.setData(term);
        match.setType(Plasma::QueryMatch::ExactMatch);

74
        if (fileInfo.isDir()) {
75
            match.setId(QStringLiteral("opendir"));
76
        } else {
77
            match.setId(QStringLiteral("openfile"));
78 79 80
        }
        context.addMatch(match);
    } else if (type == Plasma::RunnerContext::NetworkLocation || type == Plasma::RunnerContext::UnknownType) {
81
        const bool filtered = KUriFilter::self()->filterUri(term, QStringList() << QStringLiteral("kshorturifilter"));
82 83 84 85 86

        if (!filtered) {
            return;
        }

87
        QUrl url(term);
88

89
        if (url.isEmpty()) {
90 91 92 93 94 95
            return;
        }

        Plasma::QueryMatch match(this);
        match.setData(url.url());

96 97 98 99 100 101 102 103 104 105 106 107
        const QString protocol = url.scheme();

        if (!KProtocolInfo::isKnownProtocol(protocol) || KProtocolInfo::isHelperProtocol(protocol)) {
            const KService::Ptr service = KApplicationTrader::preferredService(QLatin1String("x-scheme-handler/") + protocol);
            if (service) {
                match.setIconName(service->icon());
                match.setText(i18n("Launch with %1", service->name()));
            } else if (KProtocolInfo::isKnownProtocol(protocol)) {
                Q_ASSERT(KProtocolInfo::isHelperProtocol(protocol));
                match.setIconName(KProtocolInfo::icon(protocol));
                match.setText(i18n("Launch with %1", KIO::DesktopExecParser::executableName(
                                       KProtocolInfo::exec(protocol))));
108
            } else {
109
                return;
110 111
            }
        } else {
112 113 114 115 116 117
            match.setIconName(KProtocolInfo::icon(protocol));
            match.setText(i18n("Go to %1", url.toDisplayString(QUrl::PreferLocalFile)));
        }

        if (url.scheme() == QLatin1String("mailto")) {
            match.setText(i18n("Send email to %1", url.path()));
118 119 120
        }

        if (type == Plasma::RunnerContext::UnknownType) {
121
            match.setId(QStringLiteral("openunknown"));
122 123 124
            match.setRelevance(0.5);
            match.setType(Plasma::QueryMatch::PossibleMatch);
        } else {
125
            match.setId(QStringLiteral("opennetwork"));
126 127 128 129 130 131 132 133
            match.setRelevance(0.7);
            match.setType(Plasma::QueryMatch::ExactMatch);
        }

        context.addMatch(match);
    }
}

Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
134
static QString convertCaseInsensitivePath(const QString &path)
135 136
{
    // Split the string on /
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
137
    const auto dirNames = path.splitRef(QDir::separator(), QString::SkipEmptyParts);
138

Xuetian Weng's avatar
Xuetian Weng committed
139 140 141 142 143
    // if split result is empty, path string can only contain separator.
    if (dirNames.empty()) {
        return QStringLiteral("/");
    }

144
    // Match folders
145
    QDir dir(QStringLiteral("/"));
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
146 147
    for (int i = 0; i < dirNames.size() - 1; ++i) {
        const QStringRef dirName = dirNames.at(i);
148 149

        bool foundMatch = false;
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
150 151
        const QStringList entries = dir.entryList(QDir::Dirs);
        for (const QString &entry : entries) {
152 153 154 155 156 157 158 159 160 161 162 163 164
            if (entry.compare(dirName, Qt::CaseInsensitive) == 0) {
                foundMatch = dir.cd(entry);
                if (foundMatch) {
                    break;
                }
            }
        }

        if (!foundMatch) {
            return path;
        }
    }

Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
165 166 167
    const QStringRef finalName = dirNames.last();
    const QStringList entries = dir.entryList();
    for (const QString &entry : entries) {
168 169 170 171 172 173 174 175
        if (entry.compare(finalName, Qt::CaseInsensitive) == 0) {
            return dir.absoluteFilePath(entry);
        }
    }

    return path;
}

176 177 178 179 180 181 182 183 184 185
void LocationsRunner::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match)
{
    Q_UNUSED(match)

    QString location = context.query();

    if (location.isEmpty()) {
        return;
    }

186 187
    location = convertCaseInsensitivePath(location);

188 189 190 191 192 193
    const QUrl urlToRun(KUriFilter::self()->filteredUri(location, {QStringLiteral("kshorturifilter")}));

    auto *job = new KIO::OpenUrlJob(urlToRun);
    job->setUiDelegate(new KNotificationJobUiDelegate(KJobUiDelegate::AutoErrorHandlingEnabled));
    job->setRunExecutables(false);
    job->start();
194 195 196

}

197
QMimeData * LocationsRunner::mimeDataForMatch(const Plasma::QueryMatch &match)
198
{
199
    const QString data = match.data().toString();
200 201
    if (!data.isEmpty()) {
        QMimeData *result = new QMimeData();
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
202
        result->setUrls({QUrl(data)});
203 204 205
        return result;
    }

Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
206
    return nullptr;
207 208 209 210
}


#include "locationrunner.moc"