~ubuntu-branches/ubuntu/vivid/muon/vivid-proposed

« back to all changes in this revision

Viewing changes to installer/Application.cpp

Tags: upstream-1.3.65
Import upstream version 1.3.65

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/***************************************************************************
2
 
 *   Copyright © 2010-2011 Jonathan Thomas <echidnaman@kubuntu.org>        *
3
 
 *                                                                         *
4
 
 *   This program is free software; you can redistribute it and/or         *
5
 
 *   modify it under the terms of the GNU General Public License as        *
6
 
 *   published by the Free Software Foundation; either version 2 of        *
7
 
 *   the License or (at your option) version 3 or any later version        *
8
 
 *   accepted by the membership of KDE e.V. (or its successor approved     *
9
 
 *   by the membership of KDE e.V.), which shall act as a proxy            *
10
 
 *   defined in Section 14 of version 3 of the license.                    *
11
 
 *                                                                         *
12
 
 *   This program is distributed in the hope that it will be useful,       *
13
 
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
14
 
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
15
 
 *   GNU General Public License for more details.                          *
16
 
 *                                                                         *
17
 
 *   You should have received a copy of the GNU General Public License     *
18
 
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
19
 
 ***************************************************************************/
20
 
 
21
 
#include "Application.h"
22
 
 
23
 
// Qt includes
24
 
#include <QtCore/QFile>
25
 
#include <QtCore/QVector>
26
 
#include <QtCore/QStringList>
27
 
 
28
 
// KDE includes
29
 
#include <KIconLoader>
30
 
#include <KLocale>
31
 
#include <KService>
32
 
#include <KServiceGroup>
33
 
#include <KDebug>
34
 
 
35
 
// QApt includes
36
 
#include <LibQApt/Backend>
37
 
#include <LibQApt/Config>
38
 
 
39
 
Application::Application(const QString &fileName, QApt::Backend *backend)
40
 
        : m_fileName(fileName)
41
 
        , m_backend(backend)
42
 
        , m_package(0)
43
 
        , m_isValid(false)
44
 
        , m_isTechnical(false)
45
 
{
46
 
    m_data = desktopContents();
47
 
}
48
 
 
49
 
Application::Application(QApt::Package *package, QApt::Backend *backend)
50
 
        : m_backend(backend)
51
 
        , m_package(package)
52
 
        , m_isValid(true)
53
 
        , m_isTechnical(true)
54
 
{
55
 
}
56
 
 
57
 
Application::~Application()
58
 
{
59
 
}
60
 
 
61
 
QString Application::name()
62
 
{
63
 
    return i18n(untranslatedName().toUtf8());
64
 
}
65
 
 
66
 
QString Application::untranslatedName()
67
 
{
68
 
    QString name = QString::fromUtf8(getField("Name")).trimmed();
69
 
    if (name.isEmpty()) {
70
 
        // extras.ubuntu.com packages can have this
71
 
        name = package()->controlField(QLatin1String("Appname"));
72
 
 
73
 
        if (!name.isEmpty()) {
74
 
            // Graduate to non-technical, since it has Appname
75
 
            m_isTechnical = false;
76
 
            return name;
77
 
        }
78
 
 
79
 
        if (m_isTechnical) {
80
 
            return package()->shortDescription();
81
 
        } else {
82
 
            return package()->latin1Name();
83
 
        }
84
 
    }
85
 
 
86
 
    return name;
87
 
}
88
 
 
89
 
QString Application::comment()
90
 
{
91
 
    QString comment = getField("Comment");
92
 
    if (comment.isEmpty()) {
93
 
        // Sometimes GenericName is used instead of Comment
94
 
        comment = getField("GenericName");
95
 
        if (comment.isEmpty()) {
96
 
            if (m_isTechnical) {
97
 
                return package()->name();
98
 
            } else {
99
 
                return package()->shortDescription();
100
 
            }
101
 
        }
102
 
    }
103
 
 
104
 
    return i18n(comment.toUtf8());
105
 
}
106
 
 
107
 
QApt::Package *Application::package()
108
 
{
109
 
    if (!m_package) {
110
 
        QLatin1String packageName(getField("X-AppInstall-Package").data());
111
 
        if (m_backend) {
112
 
            m_package = m_backend->package(packageName);
113
 
        }
114
 
    }
115
 
 
116
 
    // Packages removed from archive will remain in app-install-data until the
117
 
    // next refresh, so we can have valid .desktops with no package
118
 
    if (!m_package) {
119
 
        m_isValid = false;
120
 
        // kDebug() << m_fileName;
121
 
    }
122
 
 
123
 
    return m_package;
124
 
}
125
 
 
126
 
QString Application::icon() const
127
 
{
128
 
    QString icon = getField("Icon");
129
 
 
130
 
    if (icon.isEmpty()) {
131
 
        icon = QLatin1String("applications-other");
132
 
    }
133
 
 
134
 
    return icon;
135
 
}
136
 
 
137
 
QString Application::mimetypes() const
138
 
{
139
 
    return getField("MimeType");
140
 
}
141
 
 
142
 
QString Application::menuPath()
143
 
{
144
 
    QString path;
145
 
    QString arrow(QString::fromUtf8(" ➜ "));
146
 
 
147
 
    // Take the file name and remove the .desktop ending
148
 
    QString desktopName = m_fileName.split('/').last().remove(QLatin1String(".desktop")).split(':').first();
149
 
    KService::Ptr service = KService::serviceByDesktopName(desktopName);
150
 
    QVector<QPair<QString, QString> > ret;
151
 
 
152
 
    if (service) {
153
 
        ret = locateApplication(QString(), service->menuId());
154
 
    }
155
 
 
156
 
    if (!ret.isEmpty()) {
157
 
        path.append(QString("<img width=\"16\" heigh=\"16\"src=\"%1\"/>")
158
 
                    .arg(KIconLoader::global()->iconPath("kde", KIconLoader::Small)));
159
 
        path.append(QString("&nbsp;%1 <img width=\"16\" heigh=\"16\" src=\"%2\"/>&nbsp;%3")
160
 
                    .arg(arrow)
161
 
                    .arg(KIconLoader::global()->iconPath("applications-other", KIconLoader::Small))
162
 
                    .arg(i18n("Applications")));
163
 
        for (int i = 0; i < ret.size(); i++) {
164
 
            path.append(QString("&nbsp;%1&nbsp;<img width=\"16\" heigh=\"16\" src=\"%2\"/>&nbsp;%3")
165
 
                        .arg(arrow)
166
 
                        .arg(KIconLoader::global()->iconPath(ret.at(i).second, KIconLoader::Small))
167
 
                        .arg(ret.at(i).first));
168
 
        }
169
 
    }
170
 
 
171
 
    return path;
172
 
}
173
 
 
174
 
QVector<QPair<QString, QString> > Application::locateApplication(const QString &_relPath, const QString &menuId) const
175
 
{
176
 
    QVector<QPair<QString, QString> > ret;
177
 
    KServiceGroup::Ptr root = KServiceGroup::group(_relPath);
178
 
 
179
 
    if (!root || !root->isValid()) {
180
 
        return ret;
181
 
    }
182
 
 
183
 
    const KServiceGroup::List list = root->entries(false /* sorted */,
184
 
                                                   true /* exclude no display entries */,
185
 
                                                   false /* allow separators */);
186
 
 
187
 
    for (KServiceGroup::List::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it) {
188
 
        const KSycocaEntry::Ptr p = (*it);
189
 
 
190
 
        if (p->isType(KST_KService)) {
191
 
            const KService::Ptr service = KService::Ptr::staticCast(p);
192
 
 
193
 
            if (service->noDisplay()) {
194
 
                continue;
195
 
            }
196
 
 
197
 
            if (service->menuId() == menuId) {
198
 
                QPair<QString, QString> pair;
199
 
                pair.first  = service->name();
200
 
                pair.second = service->icon();
201
 
                ret << pair;
202
 
                return ret;
203
 
            }
204
 
        } else if (p->isType(KST_KServiceGroup)) {
205
 
            const KServiceGroup::Ptr serviceGroup = KServiceGroup::Ptr::staticCast(p);
206
 
 
207
 
            if (serviceGroup->noDisplay() || serviceGroup->childCount() == 0) {
208
 
                continue;
209
 
            }
210
 
 
211
 
            QVector<QPair<QString, QString> > found;
212
 
            found = locateApplication(serviceGroup->relPath(), menuId);
213
 
            if (!found.isEmpty()) {
214
 
                QPair<QString, QString> pair;
215
 
                pair.first  = serviceGroup->caption();
216
 
                pair.second = serviceGroup->icon();
217
 
                ret << pair;
218
 
                ret << found;
219
 
                return ret;
220
 
            }
221
 
        } else {
222
 
            continue;
223
 
        }
224
 
    }
225
 
 
226
 
    return ret;
227
 
}
228
 
 
229
 
QString Application::categories()
230
 
{
231
 
    QString categories = getField("Categories");
232
 
 
233
 
    if (categories.isEmpty()) {
234
 
        // extras.ubuntu.com packages can have this field
235
 
        categories = package()->controlField(QLatin1String("Category"));
236
 
 
237
 
        if (!categories.isEmpty()) {
238
 
            // Graduate to non-technical, since it has Appname
239
 
            m_isTechnical = false;
240
 
        }
241
 
    }
242
 
    return categories;
243
 
}
244
 
 
245
 
KUrl Application::screenshotUrl(QApt::ScreenshotType type)
246
 
{
247
 
    QString appUrl;
248
 
    switch (type) {
249
 
    case QApt::Thumbnail:
250
 
        appUrl = package()->controlField(QLatin1String("Thumbnail-Url"));
251
 
        break;
252
 
    case QApt::Screenshot:
253
 
        appUrl = package()->controlField(QLatin1String("Screenshot-Url"));
254
 
        break;
255
 
    default:
256
 
        break;
257
 
    }
258
 
 
259
 
    KUrl url;
260
 
    if (appUrl.isEmpty()) {
261
 
        url = package()->screenshotUrl(type);
262
 
    } else {
263
 
        url = KUrl(appUrl);
264
 
    }
265
 
 
266
 
    return url;
267
 
}
268
 
 
269
 
QApt::PackageList Application::addons()
270
 
{
271
 
    QApt::PackageList addons;
272
 
 
273
 
    QApt::Package *pkg = package();
274
 
    if (!pkg) {
275
 
        return addons;
276
 
    }
277
 
 
278
 
    QStringList tempList;
279
 
    // Only add recommends or suggests to the list if they aren't already going to be
280
 
    // installed
281
 
    if (!m_backend->config()->readEntry("APT::Install-Recommends", true)) {
282
 
        tempList << m_package->recommendsList();
283
 
    }
284
 
    if (!m_backend->config()->readEntry("APT::Install-Suggests", false)) {
285
 
        tempList << m_package->suggestsList();
286
 
    }
287
 
    tempList << m_package->enhancedByList();
288
 
 
289
 
    QStringList languagePackages;
290
 
    QFile l10nFilterFile("/usr/share/language-selector/data/pkg_depends");
291
 
 
292
 
    if (l10nFilterFile.open(QFile::ReadOnly)) {
293
 
        QString contents = l10nFilterFile.readAll();
294
 
 
295
 
        foreach (const QString &line, contents.split('\n')) {
296
 
            if (line.startsWith(QLatin1Char('#'))) {
297
 
                continue;
298
 
            }
299
 
            languagePackages << line.split(':').last();
300
 
        }
301
 
 
302
 
        languagePackages.removeAll("");
303
 
    }
304
 
 
305
 
    foreach (const QString &addon, tempList) {
306
 
        bool shouldShow = true;
307
 
        QApt::Package *package = m_backend->package(addon);
308
 
 
309
 
        if (!package || package->section().contains("lib") || addons.contains(package)) {
310
 
            continue;
311
 
        }
312
 
 
313
 
        foreach (const QString &langpack, languagePackages) {
314
 
            if (addon.contains(langpack)) {
315
 
                shouldShow = false;
316
 
                break;
317
 
            }
318
 
        }
319
 
 
320
 
        if (shouldShow) {
321
 
            addons << package;
322
 
        }
323
 
    }
324
 
 
325
 
    return addons;
326
 
}
327
 
 
328
 
bool Application::isValid() const
329
 
{
330
 
    return m_isValid;
331
 
}
332
 
 
333
 
bool Application::isTechnical() const
334
 
{
335
 
    return m_isTechnical;
336
 
}
337
 
 
338
 
QByteArray Application::getField(const QByteArray &field) const
339
 
{
340
 
    return m_data.value(field);
341
 
}
342
 
 
343
 
QHash<QByteArray, QByteArray> Application::desktopContents()
344
 
{
345
 
    QHash<QByteArray, QByteArray> contents;
346
 
 
347
 
    QFile file(m_fileName);
348
 
    if (!file.open(QFile::ReadOnly)) {
349
 
        return contents;
350
 
    }
351
 
 
352
 
    int lineIndex = 0;
353
 
    QByteArray buffer = file.readAll();
354
 
 
355
 
    QList<QByteArray> lines = buffer.split('\n');
356
 
 
357
 
    while (lineIndex < lines.size()) {
358
 
        QByteArray line = lines.at(lineIndex);
359
 
        if (line.isEmpty() || line.at(0) == '#') {
360
 
            lineIndex++;
361
 
            continue;
362
 
        }
363
 
 
364
 
        // Looking for a group heading.
365
 
        if (!m_isValid && line.startsWith('[') && line.contains(']')) {
366
 
            m_isValid = true;
367
 
        }
368
 
 
369
 
        QByteArray aKey;
370
 
        QByteArray aValue;
371
 
        int eqpos = line.indexOf('=');
372
 
 
373
 
        if (eqpos < 0) {
374
 
            // Invalid
375
 
            lineIndex++;
376
 
            continue;
377
 
        } else {
378
 
            aKey = line.left(eqpos);
379
 
            aValue = line.right(line.size() - eqpos -1);
380
 
 
381
 
            if (!contents.contains(aKey)) {
382
 
                contents[aKey] = aValue;
383
 
            }
384
 
        }
385
 
 
386
 
        lineIndex++;
387
 
    }
388
 
 
389
 
    return contents;
390
 
}