kio_desktop.cpp 8.18 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* This file is part of the KDE project
   Copyright (C) 2008, 2009 Fredrik Höglund <fredrik@kde.org>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

#include "kio_desktop.h"

#include <KConfigGroup>
#include <KDesktopFile>
24
#include <KDirNotify>
25
26
#include <KDiskFreeSpaceInfo>
#include <KIO/UDSEntry>
Ahmad Samir's avatar
Ahmad Samir committed
27
#include <KLocalizedString>
28

29
#include <QCoreApplication>
30
31
32
33
#include <QFile>
#include <QDir>
#include <QStandardPaths>

34
35
36
#include "kded_interface.h"
#include "desktopnotifier_interface.h"

37
38
39
40
41
42
extern "C"
{
    int Q_DECL_EXPORT kdemain(int argc, char **argv)
    {
        // necessary to use other kio slaves
        QCoreApplication app(argc, argv);
43
        app.setApplicationName("kio_desktop");
44
45
46
47
48
49
50
51
52
53
54
55
56

        // start the slave
        DesktopProtocol slave(argv[1], argv[2], argv[3]);
        slave.dispatchLoop();
        return 0;
    }
}

DesktopProtocol::DesktopProtocol(const QByteArray& protocol, const QByteArray &pool, const QByteArray &app)
    : KIO::ForwardingSlaveBase(protocol, pool, app)
{
    checkLocalInstall();

57
58
59
60
61
    org::kde::kded5 kded(QStringLiteral("org.kde.kded5"),
                        QStringLiteral("/kded"),
                        QDBusConnection::sessionBus());
    auto pending = kded.loadModule("desktopnotifier");
    pending.waitForFinished();
62
63
64
65
66
67
68
69
}

DesktopProtocol::~DesktopProtocol()
{
}

void DesktopProtocol::checkLocalInstall()
{
Shubham  .'s avatar
Shubham . committed
70
#ifndef Q_OS_WIN
71
72
73
    // QStandardPaths::writableLocation(QStandardPaths::DesktopLocation) returns the home dir
    // if the desktop folder doesn't exist, so verify its result
    QString desktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
74
75
76
77
78
79
80
81
82
83
84
85
86

    const QDir desktopDir(desktopPath);
    bool desktopIsEmpty;

    // Create the desktop folder if it doesn't exist
    if (!desktopDir.exists()) {
        ::mkdir(QFile::encodeName(desktopPath), S_IRWXU);
        desktopIsEmpty = true;
    } else
        desktopIsEmpty = desktopDir.entryList(QDir::AllEntries | QDir::Hidden | QDir::NoDotAndDotDot).isEmpty();

    if (desktopIsEmpty) {
        // Copy the .directory file
87
        QFile::copy(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kio_desktop/directory.desktop")),
88
89
90
                    desktopPath + "/.directory");

        // Copy the desktop links
91
92
93
94
95
96
97
98
99
        QSet<QString> links;
        const auto dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("kio_desktop/DesktopLinks"), QStandardPaths::LocateDirectory);
        for (const auto &dir : dirs) {
            const auto fileNames = QDir(dir).entryList({QStringLiteral("*.desktop")});
            for (const auto &file : fileNames) {
                links += file;
            }
        }

100
        foreach (const QString &link, links) {
101
102
            const auto fullPath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kio_desktop/DesktopLinks/%1").arg(link));
            KDesktopFile file(fullPath);
103
            if (!file.desktopGroup().readEntry("Hidden", false))
104
                QFile::copy(fullPath, QStringLiteral("%1/%2").arg(desktopPath, link));
105
106
107
108
109
110
111
        }
    }
#endif
}

bool DesktopProtocol::rewriteUrl(const QUrl &url, QUrl &newUrl)
{
112
    newUrl.setScheme(QStringLiteral("file"));
113
114
115
116
117
118
119
120
121
    QString desktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
    if (desktopPath.endsWith('/')) {
        desktopPath.chop(1);
    }
    QString filePath = desktopPath + url.path();
    if (filePath.endsWith('/')) {
        filePath.chop(1); // ForwardingSlaveBase always appends a '/'
    }
    newUrl.setPath(filePath);
122
123
124
125
126
127
128
    return true;
}

void DesktopProtocol::listDir(const QUrl &url)
{
    KIO::ForwardingSlaveBase::listDir(url);

129
    QUrl actual;
130
131
    rewriteUrl(url, actual);

132
133
    org::kde::DesktopNotifier kded(QStringLiteral("org.kde.kded5"), QStringLiteral("/modules/desktopnotifier"), QDBusConnection::sessionBus());
    kded.watchDir(actual.path());
134
135
136
137
138
}

QString DesktopProtocol::desktopFile(KIO::UDSEntry &entry) const
{
    const QString name = entry.stringValue(KIO::UDSEntry::UDS_NAME);
Laurent Montel's avatar
Laurent Montel committed
139
    if (name == QLatin1Char('.') || name == QLatin1String(".."))
140
141
        return QString();

142
143
    QUrl url = processedUrl();
    url.setPath(QStringLiteral("%1/%2").arg(url.path(), name));
144
145

    if (entry.isDir()) {
146
147
        url.setPath(QStringLiteral("%1/.directory").arg(url.path()));
        if (!QFileInfo::exists(url.path()))
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
            return QString();

        return url.path();
    }

    if (KDesktopFile::isDesktopFile(url.path()))
        return url.path();

    return QString();
}

void DesktopProtocol::prepareUDSEntry(KIO::UDSEntry &entry, bool listing) const
{
    ForwardingSlaveBase::prepareUDSEntry(entry, listing);
    const QString path = desktopFile(entry);

    if (!path.isEmpty()) {
        KDesktopFile file(path);

        const QString name = file.readName();
        if (!name.isEmpty())
169
            entry.replace(KIO::UDSEntry::UDS_DISPLAY_NAME, name);
170
171

        if (file.noDisplay() || !file.tryExec())
172
            entry.replace(KIO::UDSEntry::UDS_HIDDEN, 1);
173
174
    }

175
176
    // Set a descriptive display name for the root item
    if (requestedUrl().path() == QLatin1String("/")
Laurent Montel's avatar
Laurent Montel committed
177
        && entry.stringValue(KIO::UDSEntry::UDS_NAME) == QLatin1Char('.')) {
178
        entry.replace(KIO::UDSEntry::UDS_DISPLAY_NAME, i18n("Desktop Folder"));
179
180
    }

181
    // Set the target URL to the local path 
182
    QUrl localUrl(QUrl::fromLocalFile(entry.stringValue(KIO::UDSEntry::UDS_LOCAL_PATH)));
183
    entry.replace(KIO::UDSEntry::UDS_TARGET_URL, localUrl.toString());
184
185
}

186
void DesktopProtocol::rename(const QUrl &_src, const QUrl &_dest, KIO::JobFlags flags)
187
{
188
    Q_UNUSED(flags)
189

190
191
    if (_src == _dest) {
        finished();
192
193
194
        return;
    }

195
196
197
    QUrl src;
    rewriteUrl(_src, src);
    const QString srcPath = src.toLocalFile();
198

199
200
201
202
203
204
    QUrl dest;
    rewriteUrl(_dest, dest);
    const QString destPath = dest.toLocalFile();

    if (KDesktopFile::isDesktopFile(srcPath)) {
        QString friendlyName;
205

206
207
208
209
210
211
        if (destPath.endsWith(QLatin1String(".desktop"))) {
            const QString fileName = dest.fileName();
            friendlyName = KIO::decodeFileName(fileName.left(fileName.length() - 8));
        } else {
            friendlyName = KIO::decodeFileName(dest.fileName());
        }
212

213
214
215
216
217
218
219
220
221
222
        // Update the value of the Name field in the file.
        KDesktopFile file(src.toLocalFile());
        KConfigGroup cg(file.desktopGroup());
        cg.writeEntry("Name", friendlyName);
        cg.writeEntry("Name", friendlyName, KConfigGroup::Persistent | KConfigGroup::Localized);
        cg.sync();
    }

    if (QFile(srcPath).rename(destPath)) {
        org::kde::KDirNotify::emitFileRenamedWithLocalPath(_src, _dest, destPath);
223
        finished();
224
225
226
    } else {
        error(KIO::ERR_CANNOT_RENAME, srcPath);
    }
227
228
}

229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
void DesktopProtocol::virtual_hook(int id, void *data)
{
    switch(id) {
        case SlaveBase::GetFileSystemFreeSpace: {
            QUrl *url = static_cast<QUrl *>(data);
            fileSystemFreeSpace(*url);
        }   break;
        default:
            SlaveBase::virtual_hook(id, data);
    }
}

void DesktopProtocol::fileSystemFreeSpace(const QUrl &url)
{
    const QString desktopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
    const KDiskFreeSpaceInfo spaceInfo = KDiskFreeSpaceInfo::freeSpaceInfo(desktopPath);
    if (spaceInfo.isValid()) {
        setMetaData(QStringLiteral("total"), QString::number(spaceInfo.size()));
        setMetaData(QStringLiteral("available"), QString::number(spaceInfo.available()));
        finished();
    } else {
        error(KIO::ERR_CANNOT_STAT, desktopPath);
    }
}