~ubuntu-branches/debian/stretch/apper/stretch

« back to all changes in this revision

Viewing changes to .pc/01_new-pk-compat.diff/apperd/TransactionWatcher.cpp

  • Committer: Package Import Robot
  • Author(s): Matthias Klumpp
  • Date: 2013-07-30 12:34:46 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20130730123446-cgzujaj03pc61drn
Tags: 0.8.1-1
* New upstream release: 0.8.1
* Depend on software-properties-kde instead of suggesting it (Closes: #696583)
* Add patch to make AppStream loading more failsafe

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/***************************************************************************
2
 
 *   Copyright (C) 2008-2011 by Daniel Nicoletti                           *
3
 
 *   dantti12@gmail.com                                                    *
4
 
 *                                                                         *
5
 
 *   This program is free software; you can redistribute it and/or modify  *
6
 
 *   it under the terms of the GNU General Public License as published by  *
7
 
 *   the Free Software Foundation; either version 2 of the License, or     *
8
 
 *   (at your option) any later version.                                   *
9
 
 *                                                                         *
10
 
 *   This program is distributed in the hope that it will be useful,       *
11
 
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12
 
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13
 
 *   GNU General Public License for more details.                          *
14
 
 *                                                                         *
15
 
 *   You should have received a copy of the GNU General Public License     *
16
 
 *   along with this program; see the file COPYING. If not, write to       *
17
 
 *   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,  *
18
 
 *   Boston, MA 02110-1301, USA.                                           *
19
 
 ***************************************************************************/
20
 
 
21
 
#include "TransactionWatcher.h"
22
 
 
23
 
#include "TransactionJob.h"
24
 
 
25
 
#include <PkStrings.h>
26
 
#include <PkIcons.h>
27
 
#include <PackageImportance.h>
28
 
 
29
 
#include <KNotification>
30
 
#include <KLocale>
31
 
#include <KMessageBox>
32
 
 
33
 
#include <kworkspace/kworkspace.h>
34
 
 
35
 
#include <Solid/PowerManagement>
36
 
#include <QtDBus/QDBusMessage>
37
 
#include <QtDBus/QDBusConnection>
38
 
 
39
 
#include <KDebug>
40
 
 
41
 
#include <Daemon>
42
 
 
43
 
Q_DECLARE_METATYPE(Transaction::Error)
44
 
 
45
 
TransactionWatcher::TransactionWatcher(bool packagekitIsRunning, QObject *parent) :
46
 
    QObject(parent),
47
 
    m_inhibitCookie(-1)
48
 
{
49
 
    m_tracker = new KUiServerJobTracker(this);
50
 
 
51
 
    // keep track of new transactions
52
 
    connect(Daemon::global(), SIGNAL(transactionListChanged(QStringList)),
53
 
            this, SLOT(transactionListChanged(QStringList)));
54
 
 
55
 
    // if PackageKit is running check to see if there are running transactons already
56
 
    if (packagekitIsRunning) {
57
 
        // here we check whether a transaction job should be created or not
58
 
        QList<QDBusObjectPath> paths = Daemon::global()->getTransactionList();
59
 
        QStringList tids;
60
 
        foreach (const QDBusObjectPath &path, paths) {
61
 
            tids << path.path();
62
 
        }
63
 
        transactionListChanged(tids);
64
 
    }
65
 
}
66
 
 
67
 
TransactionWatcher::~TransactionWatcher()
68
 
{
69
 
    // release any cookie that we might have
70
 
    suppressSleep(false, m_inhibitCookie);
71
 
}
72
 
 
73
 
void TransactionWatcher::transactionListChanged(const QStringList &tids)
74
 
{
75
 
    kDebug() << tids.size();
76
 
    if (!tids.isEmpty()) {
77
 
        foreach (const QString &tid, tids) {
78
 
            watchTransaction(QDBusObjectPath(tid), false);
79
 
        }
80
 
    } else {
81
 
        // There is no current transaction, delete the jobs
82
 
        foreach (TransactionJob *job, m_transactionJob) {
83
 
            job->transactionDestroyed();
84
 
            job->deleteLater();
85
 
        }
86
 
 
87
 
        // Avoid leaks delete the jobs
88
 
        foreach (Transaction *transaction, m_transactions) {
89
 
            transaction->deleteLater();
90
 
        }
91
 
        m_transactions.clear();
92
 
        m_transactionJob.clear();
93
 
 
94
 
        // release any cookie that we might have
95
 
        suppressSleep(false, m_inhibitCookie);
96
 
    }
97
 
}
98
 
 
99
 
void TransactionWatcher::watchTransaction(const QDBusObjectPath &tid, bool interactive)
100
 
{
101
 
    Transaction *transaction;
102
 
    if (!m_transactions.contains(tid)) {
103
 
        // Check if the current transaction is still the same
104
 
        transaction = new Transaction(tid, this);
105
 
        if (transaction->error()) {
106
 
            qWarning() << "Could not create a transaction for the path:" << tid.path();
107
 
            delete transaction;
108
 
            return;
109
 
        }
110
 
 
111
 
        // Store the transaction id
112
 
        m_transactions[tid] = transaction;
113
 
 
114
 
        Transaction::Role role = transaction->role();
115
 
        if (role == Transaction::RoleInstallPackages ||
116
 
                role == Transaction::RoleInstallFiles    ||
117
 
                role == Transaction::RoleRemovePackages  ||
118
 
                role == Transaction::RoleUpdatePackages  ||
119
 
                role == Transaction::RoleUpgradeSystem) {
120
 
            // AVOID showing messages and restart requires when
121
 
            // the user was just simulating an instalation
122
 
            // TODO fix yum backend
123
 
            connect(transaction, SIGNAL(message(PackageKit::Transaction::Message,QString)),
124
 
                    this, SLOT(message(PackageKit::Transaction::Message,QString)));
125
 
            connect(transaction, SIGNAL(requireRestart(PackageKit::Transaction::Restart,QString)),
126
 
                    this, SLOT(requireRestart(PackageKit::Transaction::Restart,QString)));
127
 
 
128
 
            // Don't let the system sleep while doing some sensible actions
129
 
            suppressSleep(true, m_inhibitCookie, PkStrings::action(role));
130
 
        }
131
 
        connect(transaction, SIGNAL(changed()), this, SLOT(transactionChanged()));
132
 
        connect(transaction, SIGNAL(finished(PackageKit::Transaction::Exit,uint)),
133
 
                this, SLOT(finished(PackageKit::Transaction::Exit)));
134
 
    } else {
135
 
        transaction = m_transactions[tid];
136
 
    }
137
 
 
138
 
    // force the first changed or create a TransactionJob
139
 
    transactionChanged(transaction, interactive);
140
 
}
141
 
 
142
 
void TransactionWatcher::finished(PackageKit::Transaction::Exit exit)
143
 
{
144
 
    // check if the transaction emitted any require restart
145
 
    Transaction *transaction = qobject_cast<Transaction*>(sender());
146
 
    QDBusObjectPath tid = transaction->tid();
147
 
    disconnect(transaction, SIGNAL(changed()), this, SLOT(transactionChanged()));
148
 
    m_transactions.remove(tid);
149
 
    m_transactionJob.remove(tid);
150
 
 
151
 
    if (exit == Transaction::ExitSuccess && !transaction->property("restartType").isNull()) {
152
 
        Transaction::Restart type = transaction->property("restartType").value<Transaction::Restart>();
153
 
        QStringList restartPackages = transaction->property("restartPackages").toStringList();
154
 
 
155
 
        // Create the notification about this transaction
156
 
        KNotification *notify = new KNotification("RestartRequired", 0, KNotification::Persistent);
157
 
        connect(notify, SIGNAL(activated(uint)), this, SLOT(logout()));
158
 
        notify->setComponentData(KComponentData("apperd"));
159
 
        notify->setProperty("restartType", qVariantFromValue(type));
160
 
        notify->setPixmap(PkIcons::restartIcon(type).pixmap(KPK_ICON_SIZE, KPK_ICON_SIZE));
161
 
        notify->setTitle(PkStrings::restartType(type));
162
 
 
163
 
        // Create a readable text with package names that required the restart
164
 
        if (!restartPackages.isEmpty()) {
165
 
            restartPackages.removeDuplicates();
166
 
            restartPackages.sort();
167
 
 
168
 
            QString text;
169
 
            text = i18np("Package: %2",
170
 
                         "Packages: %2",
171
 
                         restartPackages.size(),
172
 
                         restartPackages.join(QLatin1String(", ")));
173
 
            notify->setText(text);
174
 
        }
175
 
 
176
 
        // TODO RestartApplication should be handled differently
177
 
        QStringList actions;
178
 
        actions << i18n("Restart");
179
 
        notify->setActions(actions);
180
 
 
181
 
        notify->sendEvent();
182
 
    }
183
 
}
184
 
 
185
 
void TransactionWatcher::transactionChanged(Transaction *transaction, bool interactive)
186
 
{
187
 
    if (!transaction) {
188
 
        transaction = qobject_cast<Transaction*>(sender());
189
 
    }
190
 
 
191
 
    QDBusObjectPath tid = transaction->tid();
192
 
    if (!interactive) {
193
 
        interactive = !transaction->isCallerActive();
194
 
    }
195
 
 
196
 
    // If the
197
 
    if (!m_transactionJob.contains(tid) && interactive) {
198
 
        TransactionJob *job = new TransactionJob(transaction, this);
199
 
        connect(transaction, SIGNAL(errorCode(PackageKit::Transaction::Error,QString)),
200
 
                this, SLOT(errorCode(PackageKit::Transaction::Error,QString)));
201
 
        connect(job, SIGNAL(canceled()), this, SLOT(watchedCanceled()));
202
 
        m_tracker->registerJob(job);
203
 
        m_transactionJob[tid] = job;
204
 
        job->start();
205
 
    }
206
 
}
207
 
 
208
 
void TransactionWatcher::message(PackageKit::Transaction::Message type, const QString &message)
209
 
{
210
 
    KNotification *notify;
211
 
    notify = new KNotification("TransactionMessage", 0, KNotification::Persistent);
212
 
    notify->setComponentData(KComponentData("apperd"));
213
 
    notify->setTitle(PkStrings::message(type));
214
 
    notify->setText(message);
215
 
 
216
 
    notify->setPixmap(KIcon("dialog-warning").pixmap(KPK_ICON_SIZE, KPK_ICON_SIZE));
217
 
    notify->sendEvent();
218
 
}
219
 
 
220
 
void TransactionWatcher::errorCode(PackageKit::Transaction::Error err, const QString &details)
221
 
{
222
 
    KNotification *notify;
223
 
    notify = new KNotification("TransactionError", 0, KNotification::Persistent);
224
 
    notify->setComponentData(KComponentData("apperd"));
225
 
    notify->setTitle(PkStrings::error(err));
226
 
    notify->setText(PkStrings::errorMessage(err));
227
 
    notify->setProperty("ErrorType", QVariant::fromValue(err));
228
 
    notify->setProperty("Details", details);
229
 
 
230
 
    QStringList actions;
231
 
    actions << i18n("Details");
232
 
    notify->setActions(actions);
233
 
    notify->setPixmap(KIcon("dialog-error").pixmap(KPK_ICON_SIZE, KPK_ICON_SIZE));
234
 
    connect(notify, SIGNAL(activated(uint)),
235
 
            this, SLOT(errorActivated(uint)));
236
 
    notify->sendEvent();
237
 
}
238
 
 
239
 
void TransactionWatcher::errorActivated(uint action)
240
 
{
241
 
    KNotification *notify = qobject_cast<KNotification*>(sender());
242
 
 
243
 
    // if the user clicked "Details"
244
 
    if (action == 1) {
245
 
        Transaction::Error error = notify->property("ErrorType").value<Transaction::Error>();
246
 
        QString details = notify->property("Details").toString();
247
 
        KMessageBox::detailedSorry(0,
248
 
                                   PkStrings::errorMessage(error),
249
 
                                   details.replace('\n', "<br />"),
250
 
                                   PkStrings::error(error),
251
 
                                   KMessageBox::Notify);
252
 
    }
253
 
 
254
 
    notify->close();
255
 
}
256
 
 
257
 
void TransactionWatcher::requireRestart(PackageKit::Transaction::Restart type, const QString &packageID)
258
 
{
259
 
    Transaction *transaction = qobject_cast<Transaction*>(sender());
260
 
    if (transaction->property("restartType").isNull()) {
261
 
        transaction->setProperty("restartType", qVariantFromValue(type));
262
 
    } else {
263
 
        Transaction::Restart oldType;
264
 
        oldType = transaction->property("restartType").value<Transaction::Restart>();
265
 
        int old = PackageImportance::restartImportance(oldType);
266
 
        int newer = PackageImportance::restartImportance(type);
267
 
        // Check to see which one is more important
268
 
        if (newer > old) {
269
 
            transaction->setProperty("restartType", qVariantFromValue(type));
270
 
        }
271
 
    }
272
 
 
273
 
    if (!Transaction::packageName(packageID).isEmpty()) {
274
 
        QStringList restartPackages = transaction->property("restartPackages").toStringList();
275
 
        restartPackages << Transaction::packageName(packageID);
276
 
        transaction->setProperty("restartPackages", restartPackages);
277
 
    }
278
 
}
279
 
 
280
 
void TransactionWatcher::logout()
281
 
{
282
 
    KNotification *notify = qobject_cast<KNotification*>(sender());
283
 
    Transaction::Restart restartType;
284
 
    restartType = notify->property("restartType").value<Transaction::Restart>();
285
 
 
286
 
    KWorkSpace::ShutdownType shutdownType;
287
 
    switch (restartType) {
288
 
    case Transaction::RestartSystem:
289
 
    case Transaction::RestartSecuritySystem:
290
 
        // The restart type was system
291
 
        shutdownType = KWorkSpace::ShutdownTypeReboot;
292
 
        break;
293
 
    case Transaction::RestartSession:
294
 
    case Transaction::RestartSecuritySession:
295
 
        // The restart type was session
296
 
        shutdownType = KWorkSpace::ShutdownTypeLogout;
297
 
        break;
298
 
    default:
299
 
        kWarning() << "Unknown restart type:" << restartType;
300
 
        return;
301
 
    }
302
 
 
303
 
    // We call KSM server to restart or logout our system
304
 
    KWorkSpace::requestShutDown(KWorkSpace::ShutdownConfirmYes,
305
 
                                shutdownType,
306
 
                                KWorkSpace::ShutdownModeInteractive);
307
 
}
308
 
 
309
 
void TransactionWatcher::watchedCanceled()
310
 
{
311
 
    TransactionJob *job = qobject_cast<TransactionJob*>(sender());
312
 
    if (job->isFinished()) {
313
 
        job->deleteLater();
314
 
        return;
315
 
    }
316
 
 
317
 
    Transaction::Role role = job->transaction()->role();
318
 
    if (role != Transaction::RoleCancel &&
319
 
            role != Transaction::RoleUnknown) {
320
 
        m_tracker->unregisterJob(job);
321
 
        m_tracker->registerJob(job);
322
 
        job->start();
323
 
    }
324
 
}
325
 
 
326
 
void TransactionWatcher::suppressSleep(bool enable, int &inhibitCookie, const QString &reason)
327
 
{
328
 
    if (inhibitCookie == -1) {
329
 
        return;
330
 
    }
331
 
 
332
 
    if (enable) {
333
 
        kDebug() << "Begin Suppressing Sleep";
334
 
        inhibitCookie = Solid::PowerManagement::beginSuppressingSleep(reason);
335
 
        if (inhibitCookie == -1) {
336
 
            kDebug() << "Sleep suppression denied!";
337
 
        }
338
 
    } else {
339
 
        kDebug() << "Stop Suppressing Sleep";
340
 
        if (!Solid::PowerManagement::stopSuppressingSleep(inhibitCookie)) {
341
 
            kDebug() << "Stop failed: invalid cookie.";
342
 
        }
343
 
        inhibitCookie = -1;
344
 
    }
345
 
}