JobRunner.cpp 25.3 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
24
/*
 * KFontInst - KDE Font Installer
 *
 * Copyright 2003-2007 Craig Drummond <craig@kde.org>
 *
 * ----
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * 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 General Public License
 * along with this program; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "JobRunner.h"
Alexander Lohnau's avatar
Alexander Lohnau committed
25
26
#include "ActionLabel.h"
#include "Fc.h"
27
28
#include "KfiConstants.h"
#include "Misc.h"
Alexander Lohnau's avatar
Alexander Lohnau committed
29
#include "config-fontinst.h"
30
31
#include <KConfigGroup>
#include <KIO/FileCopyJob>
Alexander Lohnau's avatar
Alexander Lohnau committed
32
#include <KIO/StatJob>
33
#include <KJobWidgets>
Alexander Lohnau's avatar
Alexander Lohnau committed
34
35
36
37
38
39
#include <KSharedConfig>
#include <QCheckBox>
#include <QCloseEvent>
#include <QDBusServiceWatcher>
#include <QDebug>
#include <QDialogButtonBox>
40
41
#include <QGridLayout>
#include <QLabel>
Alexander Lohnau's avatar
Alexander Lohnau committed
42
43
44
#include <QProcess>
#include <QProgressBar>
#include <QPushButton>
45
46
#include <QStackedWidget>
#include <QStyle>
Alexander Lohnau's avatar
Alexander Lohnau committed
47
48
#include <QStyleOption>
#include <QTemporaryDir>
49
#include <QTimer>
Alexander Lohnau's avatar
Alexander Lohnau committed
50
51
52
#include <QVBoxLayout>
#include <QX11Info>
#include <X11/Xlib.h>
53
#include <fontconfig/fontconfig.h>
Alexander Lohnau's avatar
Alexander Lohnau committed
54
#include <kio/global.h>
55
56
57
58
#include <sys/resource.h>
#include <sys/types.h>
#include <unistd.h>

Alexander Lohnau's avatar
Alexander Lohnau committed
59
#define CFG_GROUP "Runner Dialog"
60
61
62
63
64
65
#define CFG_DONT_SHOW_FINISHED_MSG "DontShowFinishedMsg"

namespace KFI
{
Q_GLOBAL_STATIC(FontInstInterface, theInterface)

Alexander Lohnau's avatar
Alexander Lohnau committed
66
FontInstInterface *CJobRunner::dbus()
67
68
69
70
71
72
{
    return theInterface;
}

QString CJobRunner::folderName(bool sys)
{
Alexander Lohnau's avatar
Alexander Lohnau committed
73
    if (!theInterface)
74
75
        return QString();

Alexander Lohnau's avatar
Alexander Lohnau committed
76
    QDBusPendingReply<QString> reply = theInterface->folderName(sys);
77
78
79
80
81
82
83
84

    reply.waitForFinished();
    return reply.isError() ? QString() : reply.argumentAt<0>();
}

void CJobRunner::startDbusService()
{
    if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(OrgKdeFontinstInterface::staticInterfaceName())) {
Alexander Lohnau's avatar
Alexander Lohnau committed
85
        const QString fontinst = QStringLiteral(KFONTINST_LIB_EXEC_DIR "/fontinst");
86
87
88
89
90
        qDebug() << "Service " << OrgKdeFontinstInterface::staticInterfaceName() << " not registered, starting" << fontinst;
        QProcess::startDetached(fontinst, QStringList());
    }
}

Alexander Lohnau's avatar
Alexander Lohnau committed
91
92
static const int constDownloadFailed = -1;
static const int constInterfaceCheck = 5 * 1000;
93
94
95

static void decode(const QUrl &url, Misc::TFont &font, bool &system)
{
Alexander Lohnau's avatar
Alexander Lohnau committed
96
    font = FC::decode(url);
97
98
99
100
101
102
103
104
    QUrlQuery query(url);
    system = (query.hasQueryItem("sys") && query.queryItemValue("sys") == QLatin1String("true"));
}

QUrl CJobRunner::encode(const QString &family, quint32 style, bool system)
{
    QUrl url(FC::encode(family, style));

David Edmundson's avatar
David Edmundson committed
105
106
107
    QUrlQuery query(url);
    query.addQueryItem(QStringLiteral("sys"), system ? QStringLiteral("true") : QStringLiteral("false"));
    url.setQuery(query);
108
109
110
    return url;
}

Alexander Lohnau's avatar
Alexander Lohnau committed
111
enum EPages {
112
113
114
115
    PAGE_PROGRESS,
    PAGE_SKIP,
    PAGE_ERROR,
    PAGE_CANCEL,
Nicolas Fella's avatar
Nicolas Fella committed
116
    PAGE_COMPLETE,
117
118
};

Alexander Lohnau's avatar
Alexander Lohnau committed
119
enum Response {
120
121
    RESP_CONTINUE,
    RESP_AUTO,
Nicolas Fella's avatar
Nicolas Fella committed
122
    RESP_CANCEL,
123
124
125
126
};

static void addIcon(QGridLayout *layout, QFrame *page, const char *iconName, int iconSize)
{
Alexander Lohnau's avatar
Alexander Lohnau committed
127
    QLabel *icon = new QLabel(page);
128
129
130
131
132
133
    icon->setPixmap(QIcon::fromTheme(iconName).pixmap(iconSize));
    icon->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
    layout->addWidget(icon, 0, 0);
}

CJobRunner::CJobRunner(QWidget *parent, int xid)
Alexander Lohnau's avatar
Alexander Lohnau committed
134
135
136
137
138
139
140
    : QDialog(parent)
    , itsIt(itsUrls.end())
    , itsEnd(itsIt)
    , itsAutoSkip(false)
    , itsCancelClicked(false)
    , itsModified(false)
    , itsTempDir(nullptr)
141
142
143
{
    setModal(true);

Alexander Lohnau's avatar
Alexander Lohnau committed
144
    if (nullptr == parent && 0 != xid)
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
        XSetTransientForHint(QX11Info::display(), winId(), xid);

    itsButtonBox = new QDialogButtonBox;
    connect(itsButtonBox, &QDialogButtonBox::clicked, this, &CJobRunner::slotButtonClicked);

    itsSkipButton = new QPushButton(i18n("Skip"));
    itsButtonBox->addButton(itsSkipButton, QDialogButtonBox::ActionRole);
    itsSkipButton->hide();
    itsAutoSkipButton = new QPushButton(i18n("AutoSkip"));
    itsButtonBox->addButton(itsAutoSkipButton, QDialogButtonBox::ActionRole);
    itsAutoSkipButton->hide();

    itsStack = new QStackedWidget(this);
    QVBoxLayout *mainLayout = new QVBoxLayout;
    setLayout(mainLayout);
    mainLayout->addWidget(itsStack);
    mainLayout->addWidget(itsButtonBox);

    QStyleOption option;
    option.initFrom(this);
Alexander Lohnau's avatar
Alexander Lohnau committed
165
166
    int iconSize = style()->pixelMetric(QStyle::PM_MessageBoxIconSize, &option, this);

167
    QFrame *page = new QFrame(itsStack);
Alexander Lohnau's avatar
Alexander Lohnau committed
168
169
170
171
    QGridLayout *layout = new QGridLayout(page);
    itsStatusLabel = new QLabel(page);
    itsProgress = new QProgressBar(page);
    //     itsStatusLabel->setWordWrap(true);
172
173
174
175
176
177
    layout->addWidget(itsActionLabel = new CActionLabel(this), 0, 0, 2, 1);
    layout->addWidget(itsStatusLabel, 0, 1);
    layout->addWidget(itsProgress, 1, 1);
    layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding), 2, 0);
    itsStack->insertWidget(PAGE_PROGRESS, page);

Alexander Lohnau's avatar
Alexander Lohnau committed
178
179
180
    page = new QFrame(itsStack);
    layout = new QGridLayout(page);
    itsSkipLabel = new QLabel(page);
181
182
183
184
185
186
    itsSkipLabel->setWordWrap(true);
    addIcon(layout, page, "dialog-error", iconSize);
    layout->addWidget(itsSkipLabel, 0, 1);
    layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding), 1, 0);
    itsStack->insertWidget(PAGE_SKIP, page);

Alexander Lohnau's avatar
Alexander Lohnau committed
187
188
189
    page = new QFrame(itsStack);
    layout = new QGridLayout(page);
    itsErrorLabel = new QLabel(page);
190
191
192
193
194
195
    itsErrorLabel->setWordWrap(true);
    addIcon(layout, page, "dialog-error", iconSize);
    layout->addWidget(itsErrorLabel, 0, 1);
    layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding), 1, 0);
    itsStack->insertWidget(PAGE_ERROR, page);

Alexander Lohnau's avatar
Alexander Lohnau committed
196
197
198
    page = new QFrame(itsStack);
    layout = new QGridLayout(page);
    QLabel *cancelLabel = new QLabel(i18n("<h3>Cancel?</h3><p>Are you sure you wish to cancel?</p>"), page);
199
200
201
202
203
204
    cancelLabel->setWordWrap(true);
    addIcon(layout, page, "dialog-warning", iconSize);
    layout->addWidget(cancelLabel, 0, 1);
    layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding), 1, 0);
    itsStack->insertWidget(PAGE_CANCEL, page);

Alexander Lohnau's avatar
Alexander Lohnau committed
205
206
207
208
209
210
211
212
213
    if (KSharedConfig::openConfig(KFI_UI_CFG_FILE)->group(CFG_GROUP).readEntry(CFG_DONT_SHOW_FINISHED_MSG, false))
        itsDontShowFinishedMsg = nullptr;
    else {
        page = new QFrame(itsStack);
        layout = new QGridLayout(page);
        QLabel *finishedLabel = new QLabel(i18n("<h3>Finished</h3>"
                                                "<p>Please note that any open applications will need to be "
                                                "restarted in order for any changes to be noticed.</p>"),
                                           page);
214
215
216
217
218
219
220
221
222
223
224
        finishedLabel->setWordWrap(true);
        addIcon(layout, page, "dialog-information", iconSize);
        layout->addWidget(finishedLabel, 0, 1);
        layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding), 1, 0);
        itsDontShowFinishedMsg = new QCheckBox(i18n("Do not show this message again"), page);
        itsDontShowFinishedMsg->setChecked(false);
        layout->addItem(new QSpacerItem(0, layout->spacing(), QSizePolicy::Fixed, QSizePolicy::Fixed), 2, 0);
        layout->addWidget(itsDontShowFinishedMsg, 3, 1);
        layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding), 4, 0);
        itsStack->insertWidget(PAGE_COMPLETE, page);
    }
Alexander Lohnau's avatar
Alexander Lohnau committed
225

226
227
    QDBusServiceWatcher *watcher = new QDBusServiceWatcher(QLatin1String(OrgKdeFontinstInterface::staticInterfaceName()),
                                                           QDBusConnection::sessionBus(),
Alexander Lohnau's avatar
Alexander Lohnau committed
228
229
                                                           QDBusServiceWatcher::WatchForOwnerChange,
                                                           this);
230
231
232
233
234
235
236
237
238
239
240
241
242
243

    connect(watcher, &QDBusServiceWatcher::serviceOwnerChanged, this, &CJobRunner::dbusServiceOwnerChanged);
    connect(dbus(), &OrgKdeFontinstInterface::status, this, &CJobRunner::dbusStatus);
    setMinimumSize(420, 160);
}

CJobRunner::~CJobRunner()
{
    delete itsTempDir;
}

void CJobRunner::getAssociatedUrls(const QUrl &url, QList<QUrl> &list, bool afmAndPfm, QWidget *widget)
{
    QString ext(url.path());
Alexander Lohnau's avatar
Alexander Lohnau committed
244
245
    int dotPos(ext.lastIndexOf('.'));
    bool check(false);
246

Alexander Lohnau's avatar
Alexander Lohnau committed
247
248
249
    if (-1 == dotPos) // Hmm, no extension - check anyway...
        check = true;
    else // Cool, got an extension - see if it is a Type1 font...
250
    {
Alexander Lohnau's avatar
Alexander Lohnau committed
251
252
        ext = ext.mid(dotPos + 1);
        check = 0 == ext.compare("pfa", Qt::CaseInsensitive) || 0 == ext.compare("pfb", Qt::CaseInsensitive);
253
254
    }

Alexander Lohnau's avatar
Alexander Lohnau committed
255
256
257
258
    if (check) {
        const char *afm[] = {"afm", "AFM", "Afm", nullptr}, *pfm[] = {"pfm", "PFM", "Pfm", nullptr};
        bool gotAfm(false), localFile(url.isLocalFile());
        int e;
259

Alexander Lohnau's avatar
Alexander Lohnau committed
260
        for (e = 0; afm[e]; ++e) {
261
262
263
264
265
266
267
268
269
270
271
272
273
            QUrl statUrl(url);
            statUrl.setPath(Misc::changeExt(url.path(), afm[e]));

            bool urlExists = false;
            if (localFile) {
                urlExists = Misc::fExists(statUrl.toLocalFile());
            } else {
                auto job = KIO::stat(statUrl);
                KJobWidgets::setWindow(job, widget);
                job->exec();
                urlExists = !job->error();
            }

Alexander Lohnau's avatar
Alexander Lohnau committed
274
            if (urlExists) {
275
                list.append(statUrl);
Alexander Lohnau's avatar
Alexander Lohnau committed
276
                gotAfm = true;
277
278
279
280
                break;
            }
        }

Alexander Lohnau's avatar
Alexander Lohnau committed
281
282
        if (afmAndPfm || !gotAfm)
            for (e = 0; pfm[e]; ++e) {
283
284
285
286
287
288
289
290
291
292
293
294
295
                QUrl statUrl(url);
                statUrl.setPath(Misc::changeExt(url.path(), pfm[e]));

                bool urlExists = false;
                if (localFile) {
                    urlExists = Misc::fExists(statUrl.toLocalFile());
                } else {
                    auto job = KIO::stat(statUrl);
                    KJobWidgets::setWindow(job, widget);
                    job->exec();
                    urlExists = !job->error();
                }

Alexander Lohnau's avatar
Alexander Lohnau committed
296
                if (urlExists) {
297
298
299
300
301
302
303
304
305
                    list.append(statUrl);
                    break;
                }
            }
    }
}

static void addEnableActions(CJobRunner::ItemList &urls)
{
Alexander Lohnau's avatar
Alexander Lohnau committed
306
307
308
309
310
    CJobRunner::ItemList modified;
    CJobRunner::ItemList::ConstIterator it(urls.constBegin()), end(urls.constEnd());

    for (; it != end; ++it) {
        if ((*it).isDisabled) {
311
            CJobRunner::Item item(*it);
Alexander Lohnau's avatar
Alexander Lohnau committed
312
            item.fileName = QLatin1String("--");
313
314
315
316
            modified.append(item);
        }
        modified.append(*it);
    }
Alexander Lohnau's avatar
Alexander Lohnau committed
317
318

    urls = modified;
319
320
321
322
}

int CJobRunner::exec(ECommand cmd, const ItemList &urls, bool destIsSystem)
{
Alexander Lohnau's avatar
Alexander Lohnau committed
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
    itsAutoSkip = itsCancelClicked = itsModified = false;

    switch (cmd) {
    case CMD_INSTALL:
        setWindowTitle(i18n("Installing"));
        break;
    case CMD_DELETE:
        setWindowTitle(i18n("Uninstalling"));
        break;
    case CMD_ENABLE:
        setWindowTitle(i18n("Enabling"));
        break;
    case CMD_MOVE:
        setWindowTitle(i18n("Moving"));
        break;
    case CMD_UPDATE:
        setWindowTitle(i18n("Updating"));
        itsModified = true;
        break;
    case CMD_REMOVE_FILE:
        setWindowTitle(i18n("Removing"));
        break;
    default:
    case CMD_DISABLE:
        setWindowTitle(i18n("Disabling"));
348
349
    }

Alexander Lohnau's avatar
Alexander Lohnau committed
350
351
352
353
354
    itsDestIsSystem = destIsSystem;
    itsUrls = urls;
    if (CMD_INSTALL == cmd)
        std::sort(itsUrls.begin(), itsUrls.end()); // Sort list of fonts so that we have type1 fonts followed by their metrics...
    else if (CMD_MOVE == cmd)
355
        addEnableActions(itsUrls);
Alexander Lohnau's avatar
Alexander Lohnau committed
356
357
358
    itsIt = itsUrls.constBegin();
    itsEnd = itsUrls.constEnd();
    itsPrev = itsEnd;
359
    itsProgress->setValue(0);
Alexander Lohnau's avatar
Alexander Lohnau committed
360
    itsProgress->setRange(0, itsUrls.count() + 1);
361
    itsProgress->show();
Alexander Lohnau's avatar
Alexander Lohnau committed
362
363
    itsCmd = cmd;
    itsCurrentFile = QString();
364
365
366
367
368
    itsStatusLabel->setText(QString());
    setPage(PAGE_PROGRESS);
    QTimer::singleShot(0, this, &CJobRunner::doNext);
    QTimer::singleShot(constInterfaceCheck, this, &CJobRunner::checkInterface);
    itsActionLabel->startAnimation();
Alexander Lohnau's avatar
Alexander Lohnau committed
369
370
    int rv = QDialog::exec();
    if (itsTempDir) {
371
        delete itsTempDir;
Alexander Lohnau's avatar
Alexander Lohnau committed
372
        itsTempDir = nullptr;
373
374
375
376
377
378
    }
    return rv;
}

void CJobRunner::doNext()
{
Alexander Lohnau's avatar
Alexander Lohnau committed
379
380
    if (itsIt == itsEnd /* || CMD_UPDATE==itsCmd*/) {
        if (itsModified) {
381
            // Force reconfig if command was already set to update...
Alexander Lohnau's avatar
Alexander Lohnau committed
382
383
            dbus()->reconfigure(getpid(), CMD_UPDATE == itsCmd);
            itsCmd = CMD_UPDATE;
384
385
386
            itsStatusLabel->setText(i18n("Updating font configuration. Please wait..."));
            itsProgress->setValue(itsProgress->maximum());
            emit configuring();
Alexander Lohnau's avatar
Alexander Lohnau committed
387
        } else {
388
            itsActionLabel->stopAnimation();
Alexander Lohnau's avatar
Alexander Lohnau committed
389
            if (PAGE_ERROR != itsStack->currentIndex())
390
391
                reject();
        }
Alexander Lohnau's avatar
Alexander Lohnau committed
392
    } else {
393
        Misc::TFont font;
Alexander Lohnau's avatar
Alexander Lohnau committed
394
        bool system;
395

Alexander Lohnau's avatar
Alexander Lohnau committed
396
397
398
399
400
401
402
403
404
405
406
407
        switch (itsCmd) {
        case CMD_INSTALL: {
            itsCurrentFile = fileName((*itsIt));

            if (itsCurrentFile.isEmpty()) // Failed to download...
                dbusStatus(getpid(), constDownloadFailed);
            else {
                // Create AFM if this is a PFM, and the previous was not the AFM for this font...
                bool createAfm =
                    Item::TYPE1_PFM == (*itsIt).type && (itsPrev == itsEnd || (*itsIt).fileName != (*itsPrev).fileName || Item::TYPE1_AFM != (*itsPrev).type);

                dbus()->install(itsCurrentFile, createAfm, itsDestIsSystem, getpid(), false);
408
            }
Alexander Lohnau's avatar
Alexander Lohnau committed
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
            break;
        }
        case CMD_DELETE:
            decode(*itsIt, font, system);
            dbus()->uninstall(font.family, font.styleInfo, system, getpid(), false);
            break;
        case CMD_ENABLE:
            decode(*itsIt, font, system);
            dbus()->enable(font.family, font.styleInfo, system, getpid(), false);
            break;
        case CMD_DISABLE:
            decode(*itsIt, font, system);
            dbus()->disable(font.family, font.styleInfo, system, getpid(), false);
            break;
        case CMD_MOVE:
            decode(*itsIt, font, system);
            // To 'Move' a disabled font, we first need to enable it. To accomplish this, JobRunner creates a 'fake' entry
            // with the filename "--"
            if ((*itsIt).fileName == QLatin1String("--")) {
                setWindowTitle(i18n("Enabling"));
429
                dbus()->enable(font.family, font.styleInfo, system, getpid(), false);
Alexander Lohnau's avatar
Alexander Lohnau committed
430
431
432
433
434
435
436
437
438
439
440
441
            } else {
                if (itsPrev != itsEnd && (*itsPrev).fileName == QLatin1String("--"))
                    setWindowTitle(i18n("Moving"));
                dbus()->move(font.family, font.styleInfo, itsDestIsSystem, getpid(), false);
            }
            break;
        case CMD_REMOVE_FILE:
            decode(*itsIt, font, system);
            dbus()->removeFile(font.family, font.styleInfo, (*itsIt).fileName, system, getpid(), false);
            break;
        default:
            break;
442
        }
Alexander Lohnau's avatar
Alexander Lohnau committed
443
444
445
        itsStatusLabel->setText(CMD_INSTALL == itsCmd ? (*itsIt).url() : FC::createName(FC::decode(*itsIt)));
        itsProgress->setValue(itsProgress->value() + 1);

446
        // Keep copy of this iterator - so that can check whether AFM should be created.
Alexander Lohnau's avatar
Alexander Lohnau committed
447
        itsPrev = itsIt;
448
449
450
451
452
    }
}

void CJobRunner::checkInterface()
{
Alexander Lohnau's avatar
Alexander Lohnau committed
453
    if (itsIt == itsUrls.constBegin() && !FontInst::isStarted(dbus())) {
454
455
        setPage(PAGE_ERROR, i18n("Unable to start backend."));
        itsActionLabel->stopAnimation();
Alexander Lohnau's avatar
Alexander Lohnau committed
456
        itsIt = itsEnd;
457
458
459
460
461
    }
}

void CJobRunner::dbusServiceOwnerChanged(const QString &name, const QString &from, const QString &to)
{
Alexander Lohnau's avatar
Alexander Lohnau committed
462
    if (to.isEmpty() && !from.isEmpty() && name == QLatin1String(OrgKdeFontinstInterface::staticInterfaceName()) && itsIt != itsEnd) {
463
464
        setPage(PAGE_ERROR, i18n("Backend died, but has been restarted. Please try again."));
        itsActionLabel->stopAnimation();
Alexander Lohnau's avatar
Alexander Lohnau committed
465
        itsIt = itsEnd;
466
467
468
469
470
    }
}

void CJobRunner::dbusStatus(int pid, int status)
{
Alexander Lohnau's avatar
Alexander Lohnau committed
471
    if (pid != getpid())
472
473
        return;

Alexander Lohnau's avatar
Alexander Lohnau committed
474
    if (CMD_UPDATE == itsCmd) {
475
476
477
478
        setPage(PAGE_COMPLETE);
        return;
    }

Alexander Lohnau's avatar
Alexander Lohnau committed
479
    itsLastDBusStatus = status;
480

Alexander Lohnau's avatar
Alexander Lohnau committed
481
    if (itsCancelClicked) {
482
483
484
485
486
487
488
489
490
491
492
493
494
        itsActionLabel->stopAnimation();
        setPage(PAGE_CANCEL);
        return;
        /*
        if(RESP_CANCEL==itsResponse)
            itsIt=itsEnd;
        itsCancelClicked=false;
        setPage(PAGE_PROGRESS);
        itsActionLabel->startAnimation();
        */
    }

    // itsIt will equal itsEnd if user decided to cancel the current op
Alexander Lohnau's avatar
Alexander Lohnau committed
495
    if (itsIt == itsEnd) {
496
        doNext();
Alexander Lohnau's avatar
Alexander Lohnau committed
497
498
    } else if (0 == status) {
        itsModified = true;
499
500
        ++itsIt;
        doNext();
Alexander Lohnau's avatar
Alexander Lohnau committed
501
502
    } else {
        bool cont(itsAutoSkip && itsUrls.count() > 1);
503
504
        QString currentName((*itsIt).fileName);

Alexander Lohnau's avatar
Alexander Lohnau committed
505
        if (!cont) {
506
507
            itsActionLabel->stopAnimation();

Alexander Lohnau's avatar
Alexander Lohnau committed
508
            if (FontInst::STATUS_SERVICE_DIED == status) {
509
                setPage(PAGE_ERROR, errorString(status));
Alexander Lohnau's avatar
Alexander Lohnau committed
510
511
512
                itsIt = itsEnd;
            } else {
                ItemList::ConstIterator lastPartOfCurrent(itsIt), next(itsIt == itsEnd ? itsEnd : itsIt + 1);
513
514

                // If we're installing a Type1 font, and its already installed - then we need to skip past AFM/PFM
Alexander Lohnau's avatar
Alexander Lohnau committed
515
516
                if (next != itsEnd && Item::TYPE1_FONT == (*itsIt).type && (*next).fileName == currentName
                    && (Item::TYPE1_AFM == (*next).type || Item::TYPE1_PFM == (*next).type)) {
517
                    next++;
Alexander Lohnau's avatar
Alexander Lohnau committed
518
                    if (next != itsEnd && (*next).fileName == currentName && (Item::TYPE1_AFM == (*next).type || Item::TYPE1_PFM == (*next).type))
519
520
                        next++;
                }
Alexander Lohnau's avatar
Alexander Lohnau committed
521
                if (1 == itsUrls.count() || next == itsEnd)
522
                    setPage(PAGE_ERROR, errorString(status));
Alexander Lohnau's avatar
Alexander Lohnau committed
523
                else {
524
525
526
527
528
529
530
531
532
533
534
535
536
                    setPage(PAGE_SKIP, errorString(status));
                    return;
                }
            }
        }

        contineuToNext(cont);
    }
}

void CJobRunner::contineuToNext(bool cont)
{
    itsActionLabel->startAnimation();
Alexander Lohnau's avatar
Alexander Lohnau committed
537
538
    if (cont) {
        if (CMD_INSTALL == itsCmd && Item::TYPE1_FONT == (*itsIt).type) // Did we error on a pfa/pfb? if so, exclude the afm/pfm...
539
540
541
542
543
544
        {
            QString currentName((*itsIt).fileName);

            ++itsIt;

            // Skip afm/pfm
Alexander Lohnau's avatar
Alexander Lohnau committed
545
            if (itsIt != itsEnd && (*itsIt).fileName == currentName && (Item::TYPE1_AFM == (*itsIt).type || Item::TYPE1_PFM == (*itsIt).type))
546
547
                ++itsIt;
            // Skip pfm/afm
Alexander Lohnau's avatar
Alexander Lohnau committed
548
            if (itsIt != itsEnd && (*itsIt).fileName == currentName && (Item::TYPE1_AFM == (*itsIt).type || Item::TYPE1_PFM == (*itsIt).type))
549
                ++itsIt;
Alexander Lohnau's avatar
Alexander Lohnau committed
550
        } else
551
            ++itsIt;
Alexander Lohnau's avatar
Alexander Lohnau committed
552
    } else {
553
        itsUrls.empty();
Alexander Lohnau's avatar
Alexander Lohnau committed
554
        itsIt = itsEnd = itsUrls.constEnd();
555
556
557
558
559
560
    }
    doNext();
}

void CJobRunner::slotButtonClicked(QAbstractButton *button)
{
Alexander Lohnau's avatar
Alexander Lohnau committed
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
    switch (itsStack->currentIndex()) {
    case PAGE_PROGRESS:
        if (itsIt != itsEnd)
            itsCancelClicked = true;
        break;
    case PAGE_SKIP:
        setPage(PAGE_PROGRESS);
        if (button == itsSkipButton) {
            contineuToNext(true);
        } else if (button == itsAutoSkipButton) {
            itsAutoSkip = true;
            contineuToNext(true);
        } else {
            contineuToNext(false);
        }
576

Alexander Lohnau's avatar
Alexander Lohnau committed
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
        break;
    case PAGE_CANCEL:
        if (button == itsButtonBox->button(QDialogButtonBox::Yes))
            itsIt = itsEnd;
        itsCancelClicked = false;
        setPage(PAGE_PROGRESS);
        itsActionLabel->startAnimation();
        // Now continue...
        dbusStatus(getpid(), itsLastDBusStatus);
        break;
    case PAGE_COMPLETE:
        if (itsDontShowFinishedMsg) {
            KConfigGroup grp(KSharedConfig::openConfig(KFI_UI_CFG_FILE)->group(CFG_GROUP));
            grp.writeEntry(CFG_DONT_SHOW_FINISHED_MSG, itsDontShowFinishedMsg->isChecked());
        }
    case PAGE_ERROR:
        QDialog::accept();
        break;
595
596
597
598
599
    }
}

void CJobRunner::closeEvent(QCloseEvent *e)
{
Alexander Lohnau's avatar
Alexander Lohnau committed
600
    if (PAGE_COMPLETE != itsStack->currentIndex()) {
601
        e->ignore();
Alexander Lohnau's avatar
Alexander Lohnau committed
602
603
        slotButtonClicked(PAGE_CANCEL == itsStack->currentIndex() ? itsButtonBox->button(QDialogButtonBox::No)
                                                                  : itsButtonBox->button(QDialogButtonBox::Cancel));
604
605
606
607
608
609
610
    }
}

void CJobRunner::setPage(int page, const QString &msg)
{
    itsStack->setCurrentIndex(page);

Alexander Lohnau's avatar
Alexander Lohnau committed
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
    switch (page) {
    case PAGE_PROGRESS:
        itsButtonBox->setStandardButtons(QDialogButtonBox::Cancel);
        itsSkipButton->hide();
        itsAutoSkipButton->hide();
        break;
    case PAGE_SKIP:
        itsSkipLabel->setText(i18n("<h3>Error</h3>") + QLatin1String("<p>") + msg + QLatin1String("</p>"));
        itsButtonBox->setStandardButtons(QDialogButtonBox::Cancel);
        itsSkipButton->show();
        itsAutoSkipButton->show();
        break;
    case PAGE_ERROR:
        itsErrorLabel->setText(i18n("<h3>Error</h3>") + QLatin1String("<p>") + msg + QLatin1String("</p>"));
        itsButtonBox->setStandardButtons(QDialogButtonBox::Cancel);
        itsSkipButton->hide();
        itsAutoSkipButton->hide();
        break;
    case PAGE_CANCEL:
        itsButtonBox->setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No);
        itsSkipButton->hide();
        itsAutoSkipButton->hide();
        break;
    case PAGE_COMPLETE:
        if (!itsDontShowFinishedMsg || itsDontShowFinishedMsg->isChecked()) {
            QDialog::accept();
        } else {
            itsButtonBox->setStandardButtons(QDialogButtonBox::Close);
639
640
            itsSkipButton->hide();
            itsAutoSkipButton->hide();
Alexander Lohnau's avatar
Alexander Lohnau committed
641
642
        }
        break;
643
644
645
646
647
    }
}

QString CJobRunner::fileName(const QUrl &url)
{
Alexander Lohnau's avatar
Alexander Lohnau committed
648
    if (url.isLocalFile())
649
        return url.toLocalFile();
Alexander Lohnau's avatar
Alexander Lohnau committed
650
    else {
651
652
653
654
        auto job = KIO::mostLocalUrl(url);
        job->exec();
        QUrl local = job->mostLocalUrl();

Alexander Lohnau's avatar
Alexander Lohnau committed
655
        if (local.isLocalFile())
656
            return local.toLocalFile(); // Yipee! no need to download!!
Alexander Lohnau's avatar
Alexander Lohnau committed
657
        else {
658
            // Need to do actual download...
Alexander Lohnau's avatar
Alexander Lohnau committed
659
660
            if (!itsTempDir) {
                itsTempDir = new QTemporaryDir(QDir::tempPath() + "/fontinst");
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
                itsTempDir->setAutoRemove(true);
            }

            QString tempName(itsTempDir->filePath(Misc::getFile(url.path())));
            auto job = KIO::file_copy(url, QUrl::fromLocalFile(tempName), -1, KIO::Overwrite);
            if (job->exec())
                return tempName;
            else
                return QString();
        }
    }
}

QString CJobRunner::errorString(int value) const
{
    Misc::TFont font(FC::decode(*itsIt));
Alexander Lohnau's avatar
Alexander Lohnau committed
677
    QString urlStr;
678

Alexander Lohnau's avatar
Alexander Lohnau committed
679
680
681
682
    if (CMD_REMOVE_FILE == itsCmd)
        urlStr = (*itsIt).fileName;
    else if (font.family.isEmpty())
        urlStr = (*itsIt).url();
683
    else
Alexander Lohnau's avatar
Alexander Lohnau committed
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
        urlStr = FC::createName(font.family, font.styleInfo);

    switch (value) {
    case constDownloadFailed:
        return i18n("Failed to download <i>%1</i>", urlStr);
    case FontInst::STATUS_SERVICE_DIED:
        return i18n("System backend died. Please try again.<br><i>%1</i>", urlStr);
    case FontInst::STATUS_BITMAPS_DISABLED:
        return i18n("<i>%1</i> is a bitmap font, and these have been disabled on your system.", urlStr);
    case FontInst::STATUS_ALREADY_INSTALLED:
        return i18n("<i>%1</i> contains the font <b>%2</b>, which is already installed on your system.", urlStr, FC::getName(itsCurrentFile));
    case FontInst::STATUS_NOT_FONT_FILE:
        return i18n("<i>%1</i> is not a font.", urlStr);
    case FontInst::STATUS_PARTIAL_DELETE:
        return i18n("Could not remove all files associated with <i>%1</i>", urlStr);
    case FontInst::STATUS_NO_SYS_CONNECTION:
        return i18n("Failed to start the system daemon.<br><i>%1</i>", urlStr);
    case KIO::ERR_FILE_ALREADY_EXIST: {
        QString name(Misc::modifyName(Misc::getFile((*itsIt).fileName))), destFolder(Misc::getDestFolder(folderName(itsDestIsSystem), name));
        return i18n("<i>%1</i> already exists.", destFolder + name);
    }
    case KIO::ERR_DOES_NOT_EXIST:
        return i18n("<i>%1</i> does not exist.", urlStr);
    case KIO::ERR_WRITE_ACCESS_DENIED:
        return i18n("Permission denied.<br><i>%1</i>", urlStr);
    case KIO::ERR_UNSUPPORTED_ACTION:
        return i18n("Unsupported action.<br><i>%1</i>", urlStr);
    case KIO::ERR_CANNOT_AUTHENTICATE:
        return i18n("Authentication failed.<br><i>%1</i>", urlStr);
    default:
        return i18n("Unexpected error while processing: <i>%1</i>", urlStr);
715
716
717
718
    }
}

CJobRunner::Item::Item(const QUrl &u, const QString &n, bool dis)
Alexander Lohnau's avatar
Alexander Lohnau committed
719
720
721
722
    : QUrl(u)
    , name(n)
    , fileName(Misc::getFile(u.path()))
    , isDisabled(dis)
723
{
Alexander Lohnau's avatar
Alexander Lohnau committed
724
725
726
727
728
    type = Misc::checkExt(fileName, "pfa") || Misc::checkExt(fileName, "pfb")
        ? TYPE1_FONT
        : Misc::checkExt(fileName, "afm") ? TYPE1_AFM : Misc::checkExt(fileName, "pfm") ? TYPE1_PFM : OTHER_FONT;

    if (OTHER_FONT != type) {
729
730
        int pos(fileName.lastIndexOf('.'));

Alexander Lohnau's avatar
Alexander Lohnau committed
731
        if (-1 != pos)
732
733
734
735
736
            fileName.truncate(pos);
    }
}

CJobRunner::Item::Item(const QString &file, const QString &family, quint32 style, bool system)
Alexander Lohnau's avatar
Alexander Lohnau committed
737
738
739
    : QUrl(CJobRunner::encode(family, style, system))
    , fileName(file)
    , type(OTHER_FONT)
740
741
742
743
744
745
746
{
}

bool CJobRunner::Item::operator<(const Item &o) const
{
    int nameComp(fileName.compare(o.fileName));

Alexander Lohnau's avatar
Alexander Lohnau committed
747
    return nameComp < 0 || (0 == nameComp && type < o.type);
748
749
750
}

}