File indexing completed on 2023-12-03 05:01:47

0001 /*
0002  * This file is part of telepathy-accounts-kcm
0003  *
0004  * Copyright (C) 2009 Collabora Ltd. <info@collabora.com>
0005  * Copyright (C) 2011 Daniele E. Domenichelli <daniele.domenichelli@gmail.com>
0006  *
0007  * This library is free software; you can redistribute it and/or
0008  * modify it under the terms of the GNU Lesser General Public
0009  * License as published by the Free Software Foundation; either
0010  * version 2.1 of the License, or (at your option) any later version.
0011  *
0012  * This library is distributed in the hope that it will be useful,
0013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015  * Lesser General Public License for more details.
0016  *
0017  * You should have received a copy of the GNU Lesser General Public
0018  * License along with this library; if not, write to the Free Software
0019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
0020  */
0021 
0022 #include "kcm-telepathy-accounts.h"
0023 #include "version.h"
0024 
0025 #include "ui_main-widget.h"
0026 
0027 #include "add-account-assistant.h"
0028 #include "edit-account-dialog.h"
0029 #include "accounts-list-delegate.h"
0030 #include "account-identity-dialog.h"
0031 #include "salut-enabler.h"
0032 
0033 #include <QtGui/QLabel>
0034 #include <QtGui/QSortFilterProxyModel>
0035 #include <QtGui/QProgressBar>
0036 #include <QtCore/QPointer>
0037 
0038 #include <KPluginFactory>
0039 #include <KIcon>
0040 #include <KLocale>
0041 #include <KMessageBox>
0042 #include <KAboutData>
0043 #include <KMessageWidget>
0044 #include <KPixmapSequenceOverlayPainter>
0045 #include <KDebug>
0046 #include <KPixmapSequence>
0047 #include <KProgressDialog>
0048 
0049 #include <KTp/wallet-utils.h>
0050 #include <KTp/Models/accounts-list-model.h>
0051 #include <KTp/logs-importer.h>
0052 #include <KTp/global-presence.h>
0053 
0054 #include <TelepathyQt/Account>
0055 #include <TelepathyQt/AccountSet>
0056 #include <TelepathyQt/AccountFactory>
0057 #include <TelepathyQt/PendingOperation>
0058 #include <TelepathyQt/PendingReady>
0059 #include <TelepathyQt/Types>
0060 #include <TelepathyQt/PendingComposite>
0061 #include <TelepathyQt/ConnectionManager>
0062 
0063 #include <KTp/Logger/log-manager.h>
0064 
0065 K_PLUGIN_FACTORY(KCMTelepathyAccountsFactory, registerPlugin<KCMTelepathyAccounts>();)
0066 K_EXPORT_PLUGIN(KCMTelepathyAccountsFactory("kcm_ktp_accounts", "kcm_ktp_accounts"))
0067 
0068 
0069 KCMTelepathyAccounts::KCMTelepathyAccounts(QWidget *parent, const QVariantList& args)
0070  : KCModule(KCMTelepathyAccountsFactory::componentData(), parent, args),
0071    m_accountsListModel(new KTp::AccountsListModel(this)),
0072    m_currentModel(0),
0073    m_currentListView(0)
0074 {
0075     //set up component data.
0076     KAboutData *aboutData = new KAboutData(I18N_NOOP("telepathy_accounts"), 0, ki18n("Instant Messaging and VOIP Accounts"), KTP_ACCOUNTS_KCM_VERSION, KLocalizedString(), KAboutData::License_GPL);
0077 
0078     aboutData->addAuthor(ki18n("George Goldberg"), ki18n("Developer"),"grundleborg@googlemail.com");
0079     aboutData->addAuthor(ki18n("David Edmundson"), ki18n("Developer"), "david@davidedmundson.co.uk");
0080     aboutData->addAuthor(ki18n("Dominik Schmidt"), ki18n("Developer"), "kde@dominik-schmidt.de");
0081     aboutData->addAuthor(ki18n("Thomas Richard"), ki18n("Developer"), "thomas.richard@proan.be");
0082     aboutData->addAuthor(ki18n("Florian Reinhard"), ki18n("Developer"), "florian.reinhard@googlemail.com");
0083     aboutData->addAuthor(ki18n("Daniele E. Domenichelli"), ki18n("Developer"), "daniele.domenichelli@gmail.com");
0084     aboutData->addAuthor(ki18n("Martin Klapetek"), ki18n("Developer"), "martin.klapetek@gmail.com");
0085 
0086     setAboutData(aboutData);
0087 
0088     // The first thing we must do is register Telepathy DBus Types.
0089     Tp::registerTypes();
0090 
0091     // Start setting up the Telepathy AccountManager.
0092     Tp::AccountFactoryPtr  accountFactory = Tp::AccountFactory::create(QDBusConnection::sessionBus(),
0093                                                                        Tp::Features() << Tp::Account::FeatureCore
0094                                                                        << Tp::Account::FeatureAvatar
0095                                                                        << Tp::Account::FeatureCapabilities
0096                                                                        << Tp::Account::FeatureProtocolInfo
0097                                                                        << Tp::Account::FeatureProfile);
0098 
0099     m_accountManager = Tp::AccountManager::create(accountFactory);
0100     m_globalPresence = new KTp::GlobalPresence(this);
0101 
0102     connect(m_accountManager->becomeReady(),
0103             SIGNAL(finished(Tp::PendingOperation*)),
0104             SLOT(onAccountManagerReady(Tp::PendingOperation*)));
0105     connect(m_accountManager.constData(),
0106             SIGNAL(newAccount(Tp::AccountPtr)),
0107             SLOT(onNewAccountAdded(Tp::AccountPtr)));
0108 
0109     // Set up the UI stuff.
0110     m_ui = new Ui::MainWidget;
0111     m_ui->setupUi(this);
0112     m_ui->salutListView->setHidden(true);
0113     m_ui->salutEnableFrame->setHidden(true);
0114     m_ui->salutEnableCheckbox->setIcon(KIcon(QLatin1String("im-local-xmpp")));
0115     m_ui->salutEnableCheckbox->setIconSize(QSize(32, 32));
0116 
0117     // On the kcm_telepathy_account we filter using "local-xmpp" and not using
0118     // "salut" because in this way we can see on top also local-xmpp accounts
0119     // configured using haze
0120     m_salutFilterModel = new QSortFilterProxyModel(this);
0121     m_salutFilterModel->setSourceModel(m_accountsListModel);
0122     m_salutFilterModel->setFilterRole(KTp::AccountsListModel::ConnectionProtocolNameRole);
0123     m_salutFilterModel->setFilterFixedString(QLatin1String("local-xmpp"));
0124     m_ui->salutListView->setModel(m_salutFilterModel);
0125 
0126     m_accountsFilterModel = new QSortFilterProxyModel(this);
0127     m_accountsFilterModel->setSourceModel(m_accountsListModel);
0128     m_accountsFilterModel->setFilterRole(KTp::AccountsListModel::ConnectionProtocolNameRole);
0129     m_accountsFilterModel->setFilterRegExp(QLatin1String("^((?!local-xmpp).)*$"));
0130     m_accountsFilterModel->setSortRole(Qt::DisplayRole);
0131     m_accountsFilterModel->setSortCaseSensitivity(Qt::CaseInsensitive);
0132     m_accountsFilterModel->setDynamicSortFilter(true);
0133     m_accountsFilterModel->sort(0);
0134     m_ui->accountsListView->setModel(m_accountsFilterModel);
0135 
0136     m_ui->addAccountButton->setIcon(KIcon(QLatin1String("list-add")));
0137     m_ui->editAccountButton->setIcon(KIcon(QLatin1String("configure")));
0138     m_ui->removeAccountButton->setIcon(KIcon(QLatin1String("edit-delete")));
0139     m_ui->editAccountIdentityButton->setIcon(KIcon(QLatin1String("user-identity")));
0140 
0141     m_salutBusyWheel = new KPixmapSequenceOverlayPainter(this);
0142     m_salutBusyWheel->setSequence(KPixmapSequence(QLatin1String("process-working"), 22));
0143     m_salutBusyWheel->setWidget(m_ui->salutWidget);
0144     m_salutBusyWheel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
0145 
0146     // parent the delegates to the layout, because KWidgetItemDelegate doesn't like it if the view
0147     // is deleted before the delegate
0148     AccountsListDelegate* accountsDelegate = new AccountsListDelegate(m_ui->accountsListView, layout());
0149     m_ui->accountsListView->setItemDelegate(accountsDelegate);
0150 
0151     AccountsListDelegate* salutDelegate = new AccountsListDelegate(m_ui->salutListView, layout());
0152     m_ui->salutListView->setItemDelegate(salutDelegate);
0153 
0154     int height = salutDelegate->sizeHint(QStyleOptionViewItem(), m_salutFilterModel->index(0,0)).height() + 3*2;
0155     m_ui->salutListView->setMinimumHeight(height);
0156     m_ui->salutListView->setMaximumHeight(height);
0157     m_ui->salutEnableFrame->setMinimumHeight(height);
0158 
0159     connect(accountsDelegate,
0160             SIGNAL(itemChecked(QModelIndex,bool)),
0161             SLOT(onAccountEnabledChanged(QModelIndex,bool)));
0162     connect(salutDelegate,
0163             SIGNAL(itemChecked(QModelIndex,bool)),
0164             SLOT(onAccountEnabledChanged(QModelIndex,bool)));
0165     connect(m_ui->addAccountButton,
0166             SIGNAL(clicked()),
0167             SLOT(onAddAccountClicked()));
0168     connect(m_ui->editAccountButton,
0169             SIGNAL(clicked()),
0170             SLOT(onEditAccountClicked()));
0171     connect(m_ui->editAccountIdentityButton,
0172             SIGNAL(clicked()),
0173             SLOT(onEditIdentityClicked()));
0174     connect(m_ui->accountsListView,
0175             SIGNAL(doubleClicked(QModelIndex)),
0176             SLOT(onEditAccountClicked()));
0177     connect(m_ui->salutListView,
0178             SIGNAL(doubleClicked(QModelIndex)),
0179             SLOT(onEditAccountClicked()));
0180     connect(m_ui->removeAccountButton,
0181             SIGNAL(clicked()),
0182             SLOT(onRemoveAccountClicked()));
0183     connect(m_ui->accountsListView->selectionModel(),
0184             SIGNAL(currentChanged(QModelIndex,QModelIndex)),
0185             SLOT(onSelectedItemChanged(QModelIndex,QModelIndex)));
0186     connect(m_ui->salutListView->selectionModel(),
0187             SIGNAL(currentChanged(QModelIndex,QModelIndex)),
0188             SLOT(onSelectedItemChanged(QModelIndex,QModelIndex)));
0189     connect(m_accountsListModel,
0190             SIGNAL(rowsInserted(QModelIndex,int,int)),
0191             SLOT(onModelDataChanged(QModelIndex)));
0192     connect(m_accountsListModel,
0193             SIGNAL(rowsRemoved(QModelIndex,int,int)),
0194             SLOT(onModelDataChanged(QModelIndex)));
0195     connect(m_ui->salutEnableCheckbox,
0196             SIGNAL(toggled(bool)),
0197             SLOT(onSalutEnableButtonToggled(bool)));
0198     connect(m_accountsListModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
0199             SLOT(onModelDataChanged(QModelIndex)));
0200 
0201     // Check if salut is enabled
0202     Tp::ConnectionManagerPtr cm = Tp::ConnectionManager::create(QLatin1String("salut"));
0203     Tp::PendingReady *op = cm->becomeReady(Tp::Features() << Tp::ConnectionManager::FeatureCore);
0204     connect(op,
0205             SIGNAL(finished(Tp::PendingOperation*)),
0206             SLOT(onSalutConnectionManagerReady(Tp::PendingOperation*)));
0207 }
0208 
0209 KCMTelepathyAccounts::~KCMTelepathyAccounts()
0210 {
0211     delete m_ui;
0212 }
0213 
0214 void KCMTelepathyAccounts::load()
0215 {
0216     // This slot is called whenever the configuration data in this KCM should
0217     // be reloaded from the store. We will not actually do anything here since
0218     // all changes that are made in this KCM are, at the moment, saved
0219     // immediately and cannot be reverted programatically.
0220     return;
0221 }
0222 
0223 void KCMTelepathyAccounts::onAccountEnabledChanged(const QModelIndex &index, bool enabled)
0224 {
0225     QVariant value;
0226     if (enabled) {
0227         value = QVariant(Qt::Checked);
0228     }
0229     else {
0230         value = QVariant(Qt::Unchecked);
0231     }
0232     m_accountsListModel->setData(index, value, KTp::AccountsListModel::EnabledRole);
0233 
0234     if (enabled) {
0235         // connect the account
0236         Tp::AccountPtr account = index.data(KTp::AccountsListModel::AccountRole).value<Tp::AccountPtr>();
0237         if (!account.isNull()) {
0238             account->setRequestedPresence(m_globalPresence->requestedPresence());
0239         }
0240     }
0241 }
0242 
0243 void KCMTelepathyAccounts::onAccountManagerReady(Tp::PendingOperation *op)
0244 {
0245     // Check the pending operation completed successfully.
0246     if (op->isError()) {
0247         kDebug() << "becomeReady() failed:" << op->errorName() << op->errorMessage();
0248         new ErrorOverlay(this, op->errorMessage(), this);
0249         return;
0250     }
0251 
0252     m_accountsListModel->setAccountSet(m_accountManager->validAccounts());
0253     m_globalPresence->setAccountManager(m_accountManager);
0254 
0255 }
0256 
0257 void KCMTelepathyAccounts::onNewAccountAdded(const Tp::AccountPtr& account)
0258 {
0259     QScopedPointer<KTp::LogsImporter> logsImporter(new KTp::LogsImporter(this));
0260     if (!logsImporter->hasKopeteLogs(account)) {
0261         kDebug() << "No Kopete logs for" << account->uniqueIdentifier() << "found";
0262         return;
0263     }
0264 
0265     int ret = KMessageBox::questionYesNo(this,
0266                 i18n("We have found Kopete logs for this account. Do you want to import the logs to KDE Telepathy?"),
0267                 i18n("Import Logs?"),
0268                 KGuiItem(i18n("Import Logs"), QLatin1String("document-import")),
0269                 KGuiItem(i18n("Close"), QLatin1String("dialog-close")));
0270 
0271     if (ret == KMessageBox::No) {
0272         return;
0273     }
0274 
0275     m_importProgressDialog = new KProgressDialog(this);
0276     m_importProgressDialog->setLabelText(i18n("Importing logs..."));
0277     m_importProgressDialog->setAllowCancel(false);
0278     m_importProgressDialog->progressBar()->setMinimum(0);
0279     m_importProgressDialog->progressBar()->setMaximum(0);
0280     m_importProgressDialog->setButtons(KDialog::Close);
0281     m_importProgressDialog->enableButton(KDialog::Close, false);
0282 
0283     connect(logsImporter.data(), SIGNAL(logsImported()), SLOT(onLogsImportDone()));
0284     connect(logsImporter.data(), SIGNAL(error(QString)), SLOT(onLogsImportError(QString)));
0285 
0286     logsImporter->startLogImport(account);
0287     m_importProgressDialog->exec();
0288 
0289     delete m_importProgressDialog;
0290 }
0291 
0292 void KCMTelepathyAccounts::onLogsImportError(const QString &error)
0293 {
0294     KMessageBox::error(this, error, i18n("Kopete Logs Import"));
0295 }
0296 
0297 void KCMTelepathyAccounts::onLogsImportDone()
0298 {
0299     if (m_importProgressDialog) {
0300         m_importProgressDialog->close();
0301     }
0302 
0303     KMessageBox::information(this, i18n("Kopete logs successfully imported"), i18n("Kopete Logs Import"));
0304 }
0305 
0306 void KCMTelepathyAccounts::onSelectedItemChanged(const QModelIndex &current, const QModelIndex &previous)
0307 {
0308     Q_UNUSED(previous);
0309 
0310     /* Only change m_currentModel and "Edit Identity" button state when
0311      * "current" is a selected item, not deselected */
0312     if (current.isValid()) {
0313         m_currentModel = qobject_cast<const QSortFilterProxyModel*>(current.model());
0314 
0315         if (current.data(KTp::AccountsListModel::ConnectionStateRole).toInt() == Tp::ConnectionStatusConnected) {
0316             m_ui->editAccountIdentityButton->setEnabled(true);
0317         } else {
0318             m_ui->editAccountIdentityButton->setEnabled(false);
0319         }
0320     }
0321 
0322     if (m_currentModel == m_salutFilterModel) {
0323         m_currentListView = m_ui->salutListView;
0324         m_ui->accountsListView->clearSelection();
0325         m_ui->accountsListView->setCurrentIndex(QModelIndex());
0326     } else {
0327         m_currentListView = m_ui->accountsListView;
0328         m_ui->salutListView->clearSelection();
0329         m_ui->salutListView->setCurrentIndex(QModelIndex());
0330     }
0331 
0332     m_ui->removeAccountButton->setEnabled(m_currentListView->currentIndex().isValid());
0333     m_ui->editAccountButton->setEnabled(m_currentListView->currentIndex().isValid());
0334 
0335     bool isAccount = (m_currentListView->currentIndex().isValid() || m_ui->salutListView->currentIndex().isValid());
0336     m_ui->removeAccountButton->setEnabled(isAccount);
0337     m_ui->editAccountButton->setEnabled(isAccount);
0338 }
0339 
0340 void KCMTelepathyAccounts::onAddAccountClicked()
0341 {
0342     // Wizard only works if the AccountManager is ready.
0343     if (!m_accountManager->isReady()) {
0344         return;
0345     }
0346 
0347     // ...and finally exec it.
0348     AddAccountAssistant assistant(m_accountManager, this);
0349     assistant.exec();
0350 }
0351 
0352 void KCMTelepathyAccounts::onEditAccountClicked()
0353 {
0354     // Editing accounts is only possible if the Account Manager is ready.
0355     if (!m_accountManager->isReady()) {
0356         return;
0357     }
0358 
0359     QModelIndex index = m_currentListView->currentIndex();
0360     if (!index.isValid()) {
0361         return;
0362     }
0363     Tp::AccountPtr account = index.data(KTp::AccountsListModel::AccountRole).value<Tp::AccountPtr>();
0364 
0365     if (account.isNull()) {
0366         return;
0367     }
0368 
0369     // Item is OK. Edit the item.
0370     QWeakPointer<EditAccountDialog> dialog = new EditAccountDialog(account, this);
0371     dialog.data()->exec();
0372     delete dialog.data();
0373 }
0374 
0375 void KCMTelepathyAccounts::onEditIdentityClicked()
0376 {
0377     if (!m_accountManager->isReady()) {
0378         return;
0379     }
0380 
0381     QModelIndex index = m_currentListView->currentIndex();
0382     if (!index.isValid()) {
0383         return;
0384     }
0385 
0386     Tp::AccountPtr account = index.data(KTp::AccountsListModel::AccountRole).value<Tp::AccountPtr>();
0387 
0388     if (account.isNull()) {
0389         return;
0390     }
0391 
0392     AccountIdentityDialog dialog(account,this);
0393     dialog.exec();
0394 }
0395 
0396 
0397 void KCMTelepathyAccounts::onRemoveAccountClicked()
0398 {
0399     QModelIndex index = m_currentListView->currentIndex();
0400 
0401     QString accountName = index.data(Qt::DisplayRole).toString();
0402 
0403     KDialog *dialog = new KDialog(this); /* will be deleted by KMessageBox::createKMessageBox */
0404     dialog->setButtons(KDialog::Yes | KDialog::Cancel);
0405     dialog->setWindowTitle(i18n("Remove Account"));
0406     dialog->setButtonGuiItem(KDialog::Yes, KGuiItem(i18n("Remove Account"), QLatin1String("edit-delete")));
0407     bool removeLogs = false;
0408 
0409     const QString msg =  i18n("Remove conversations logs");
0410     if (KMessageBox::createKMessageBox(dialog, QMessageBox::Warning, i18n("Are you sure you want to remove the account \"%1\"?", accountName),
0411                 QStringList(), msg , &removeLogs,
0412                 KMessageBox::Dangerous | KMessageBox::Notify) == KDialog::Yes) {
0413 
0414         Tp::AccountPtr account = index.data(KTp::AccountsListModel::AccountRole).value<Tp::AccountPtr>();
0415         if (account.isNull()) {
0416             return;
0417         }
0418 
0419         if (removeLogs) {
0420             KTp::LogManager *logManager = KTp::LogManager::instance();
0421             logManager->clearAccountLogs(account);
0422         }
0423 
0424         QList<Tp::PendingOperation*> ops;
0425         ops.append(KTp::WalletUtils::removeAccountPassword(account));
0426         ops.append(account->remove());
0427         connect(new Tp::PendingComposite(ops, account), SIGNAL(finished(Tp::PendingOperation*)), SLOT(onOperationFinished(Tp::PendingOperation*)));
0428     }
0429 }
0430 
0431 void KCMTelepathyAccounts::onModelDataChanged(const QModelIndex &index)
0432 {
0433     bool salutEnabled = m_salutFilterModel->rowCount() == 0;
0434     m_ui->salutListView->setHidden(salutEnabled);
0435     m_ui->salutEnableFrame->setHidden(!salutEnabled);
0436 
0437     /* When model changes and the change is the currently selected row, update
0438      * state of buttons */
0439     if (m_currentListView && m_currentModel && (index == m_currentModel->mapToSource(m_currentListView->currentIndex()))) {
0440         onSelectedItemChanged(m_currentListView->currentIndex(), m_currentListView->currentIndex());
0441     }
0442 }
0443 
0444 void KCMTelepathyAccounts::onSalutEnableButtonToggled(bool checked)
0445 {
0446     if (checked) {
0447         if (m_salutEnabler.isNull()) {
0448             m_salutEnabler = new SalutEnabler(m_accountManager, this);
0449         }
0450 
0451         connect(m_salutEnabler.data(), SIGNAL(userInfoReady()),
0452                 this, SLOT(onSalutInfoReady()));
0453 
0454         connect(m_salutEnabler.data(), SIGNAL(cancelled()),
0455                 this, SLOT(onSalutSetupDone()));
0456 
0457         connect(m_salutEnabler.data(), SIGNAL(done()),
0458                 this, SLOT(onSalutSetupDone()));
0459 
0460         //FIXME there is no slot to connect feedbackMessage to
0461 //         connect(m_salutEnabler, SIGNAL(feedbackMessage(QString,QString,KTitleWidget::MessageType)),
0462 //                 this, SLOT());
0463 
0464         m_ui->accountsListView->clearSelection();
0465         m_ui->accountsListView->setCurrentIndex(QModelIndex());
0466         m_ui->salutListView->clearSelection();
0467         m_ui->salutListView->setCurrentIndex(QModelIndex());
0468     }
0469 }
0470 
0471 void KCMTelepathyAccounts::onSalutConnectionManagerReady(Tp::PendingOperation* op)
0472 {
0473     bool error = false;
0474     if (op->isError()) {
0475         kWarning() << "Creating salut ConnectionManager failed:" << op->errorName() << op->errorMessage();
0476         error = true;
0477     } else {
0478         Tp::ConnectionManagerPtr cm = Tp::ConnectionManagerPtr::qObjectCast(qobject_cast<Tp::PendingReady*>(op)->proxy());
0479 
0480         if (!cm->isValid()) {
0481             kWarning() << "Invalid salut ConnectionManager";
0482             error = true;
0483         } else if (!cm->supportedProtocols().contains(QLatin1String("local-xmpp"))) {
0484             kWarning() << "salut ConnectionManager doesn't support local-xmpp... this is weird";
0485             error = true;
0486         }
0487     }
0488 
0489     // Salut is not installed or has some problem
0490     if (error) {
0491         m_ui->salutEnableFrame->setDisabled(true);
0492         m_ui->salutEnableStatusLabel->setText(i18n("Install telepathy-salut to enable"));
0493     }
0494 }
0495 
0496 void KCMTelepathyAccounts::onSalutInfoReady()
0497 {
0498     qobject_cast<QVBoxLayout*>(m_ui->salutEnableFrame->layout())->insertWidget(0, m_salutEnabler.data()->frameWidget(m_ui->salutEnableFrame));
0499     m_salutBusyWheel->start();
0500     m_ui->salutWidget->setDisabled(true);
0501 }
0502 
0503 void KCMTelepathyAccounts::onSalutSetupDone()
0504 {
0505     m_salutEnabler.data()->deleteLater();
0506 
0507     m_salutBusyWheel->stop();
0508     m_ui->salutEnableCheckbox->setChecked(false);
0509     m_ui->salutWidget->setEnabled(true);
0510 }
0511 
0512 void KCMTelepathyAccounts::onOperationFinished(Tp::PendingOperation *op)
0513 {
0514     if (op->isError()) {
0515         kDebug() << "operation failed " << op->errorName() << op->errorMessage();
0516     }
0517 }
0518 
0519 /////
0520 
0521 ErrorOverlay::ErrorOverlay(QWidget *baseWidget, const QString &details, QWidget *parent) :
0522     QWidget(parent ? parent : baseWidget->window()),
0523     m_BaseWidget(baseWidget)
0524 {
0525     Q_UNUSED(details)
0526 
0527     // Build the UI
0528     QVBoxLayout *layout = new QVBoxLayout;
0529     layout->setSpacing(10);
0530 
0531     QLabel *pixmap = new QLabel();
0532     pixmap->setPixmap(KIcon(QLatin1String("dialog-error")).pixmap(64));
0533 
0534     QLabel *message = new QLabel(i18n("Something went terribly wrong and the IM system could not be initialized.\n"
0535                                       "It is likely your system is missing Telepathy Mission Control package.\n"
0536                                       "Please install it and restart this module."));
0537 
0538     pixmap->setAlignment(Qt::AlignHCenter);
0539     message->setAlignment(Qt::AlignHCenter);
0540 
0541     layout->addStretch();
0542     layout->addWidget(pixmap);
0543     layout->addWidget(message);
0544     layout->addStretch();
0545 
0546     setLayout(layout);
0547 
0548     // Draw the transparent overlay background
0549     QPalette p = palette();
0550     p.setColor(backgroundRole(), QColor(0, 0, 0, 128));
0551     p.setColor(foregroundRole(), Qt::white);
0552     setPalette(p);
0553     setAutoFillBackground(true);
0554 
0555     m_BaseWidget->installEventFilter(this);
0556 
0557     reposition();
0558 }
0559 
0560 ErrorOverlay::~ErrorOverlay()
0561 {
0562 }
0563 
0564 void ErrorOverlay::reposition()
0565 {
0566     if (!m_BaseWidget) {
0567         return;
0568     }
0569 
0570     // reparent to the current top level widget of the base widget if needed
0571     // needed eg. in dock widgets
0572     if (parentWidget() != m_BaseWidget->window()) {
0573         setParent(m_BaseWidget->window());
0574     }
0575 
0576     // follow base widget visibility
0577     // needed eg. in tab widgets
0578     if (!m_BaseWidget->isVisible()) {
0579         hide();
0580         return;
0581     }
0582 
0583     show();
0584 
0585     // follow position changes
0586     const QPoint topLevelPos = m_BaseWidget->mapTo(window(), QPoint(0, 0));
0587     const QPoint parentPos = parentWidget()->mapFrom(window(), topLevelPos);
0588     move(parentPos);
0589 
0590     // follow size changes
0591     // TODO: hide/scale icon if we don't have enough space
0592     resize(m_BaseWidget->size());
0593 }
0594 
0595 bool ErrorOverlay::eventFilter(QObject * object, QEvent * event)
0596 {
0597     if (object == m_BaseWidget &&
0598         (event->type() == QEvent::Move || event->type() == QEvent::Resize ||
0599         event->type() == QEvent::Show || event->type() == QEvent::Hide ||
0600         event->type() == QEvent::ParentChange)) {
0601         reposition();
0602     }
0603     return QWidget::eventFilter(object, event);
0604 }
0605 
0606 #include "kcm-telepathy-accounts.moc"