diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,6 @@ -DQT_NO_KEYWORDS) add_definitions(-DTRANSLATION_DOMAIN=\"kaccounts-integration\") -add_definitions(-DQT_NO_FOREACH) if (EXISTS "${CMAKE_SOURCE_DIR}/.git" AND AccountsQt5_VERSION VERSION_GREATER 1.15) add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x060000) add_definitions(-DKF_DISABLE_DEPRECATED_BEFORE_AND_AT=0x060000) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,33 @@ add_subdirectory(daemon) add_subdirectory(lib) add_subdirectory(declarative) -add_subdirectory(kcm) + +set(kaccounts_SRCS + kaccounts.cpp + create.cpp + accountwidget.cpp + uipluginsmanager.cpp + models/accountsmodel.cpp + jobs/createaccount.cpp +) + +ki18n_wrap_ui(kaccounts_SRCS kcm.ui types.ui services.ui) + +add_library(kcm_kaccounts MODULE ${kaccounts_SRCS}) +kcoreaddons_desktop_to_json(kcm_kaccounts kcm_kaccounts.desktop) + +target_link_libraries(kcm_kaccounts + Qt5::Core + Qt5::Gui + Qt5::DBus + KF5::I18n + KF5::KCMUtils + ${SIGNONQT_LIBRARIES} + kaccounts +) +target_include_directories(kcm_kaccounts PRIVATE "${SIGNONQT_INCLUDE_DIRS}") + + +install(TARGETS kcm_kaccounts DESTINATION ${PLUGIN_INSTALL_DIR}) + +install(FILES kcm_kaccounts.desktop DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/src/lib/uipluginsmanager.h b/src/accountwidget.h rename from src/lib/uipluginsmanager.h rename to src/accountwidget.h --- a/src/lib/uipluginsmanager.h +++ b/src/accountwidget.h @@ -1,5 +1,5 @@ /************************************************************************************* - * Copyright (C) 2015 by Martin Klapetek * + * Copyright (C) 2012-2013 by Alejandro Fiestas Olivares * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * @@ -16,22 +16,39 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * *************************************************************************************/ -#ifndef UIPLUGINSMANAGER_H -#define UIPLUGINSMANAGER_H +#ifndef ACCOUNTWIDGET_H +#define ACCOUNTWIDGET_H -#include +#include "ui_services.h" +#include "create.h" -class KAccountsUiPlugin; +#include -namespace KAccounts { +namespace Accounts { + class Account; +} + +class QCheckBox; + +class AccountWidget : public QWidget, Ui::Services +{ + Q_OBJECT -class UiPluginsManager { public: - static QList uiPlugins(); - static KAccountsUiPlugin* pluginForService(const QString &service); - static KAccountsUiPlugin* pluginForName(const QString &name); -}; + explicit AccountWidget(Accounts::Account *model, QWidget *parent); + virtual ~AccountWidget(); -} + void setAccount(Accounts::Account *account); + +public Q_SLOTS: + void serviceEnabledChanged(const QString &serviceName, bool enabled); + void serviceChanged(bool enabled); + +private: + QHash m_checkboxes; + QPointer m_account; + Accounts::Manager *m_manager; + QList m_connections; +}; -#endif //UIPLUGINSMANAGER_H +#endif //ACCOUNTWIDGET_H diff --git a/src/accountwidget.cpp b/src/accountwidget.cpp new file mode 100644 --- /dev/null +++ b/src/accountwidget.cpp @@ -0,0 +1,177 @@ +/************************************************************************************* + * Copyright (C) 2012 by Alejandro Fiestas Olivares * + * * + * 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; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * + *************************************************************************************/ + +#include "accountwidget.h" +#include "models/accountsmodel.h" +#include "uipluginsmanager.h" +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +AccountWidget::AccountWidget(Accounts::Account *account, QWidget *parent) + : QWidget(parent) + , m_manager(KAccounts::accountsManager()) +{ + setupUi(this); + + if (!account) { + return; + } + + setAccount(account); +} + +AccountWidget::~AccountWidget() +{ + qDeleteAll(m_checkboxes); + Q_FOREACH (const QMetaObject::Connection &connection, m_connections) { + QObject::disconnect(connection); + } +} + +void AccountWidget::setAccount(Accounts::Account *account) +{ + if (m_account) { + disconnect(m_account.data(), nullptr, this, nullptr); + } + + qDeleteAll(m_checkboxes); + m_checkboxes.clear(); + Q_FOREACH (const QMetaObject::Connection &connection, m_connections) { + QObject::disconnect(connection); + } + m_connections.clear(); + + QLayoutItem *child; + while ((child = d_layout->takeAt(0)) != nullptr) { + if (child->layout() != nullptr) { + QLayoutItem *child2; + while ((child2 = child->layout()->takeAt(0)) != nullptr) { + delete child2->widget(); + delete child2; + } + } + delete child; + } + + if (!account) { + return; + } + + QCheckBox *checkbox = nullptr; + Accounts::ServiceList services = account->services(); + Q_FOREACH(const Accounts::Service &service, services) { + // first select the service we'll be manipulating (enable/disable) + account->selectService(service); + checkbox = new QCheckBox(i18nd(service.trCatalog().toLatin1().constData(), service.displayName().toUtf8().constData()), this); + // if there is a previously selected service (two lines above), + // the account->enabled() is about the service, not the account + checkbox->setChecked(account->enabled()); + checkbox->setProperty("service", service.name()); + + QIcon icon = QIcon::fromTheme(service.iconName()); + if (icon.isNull()) { + icon = QIcon::fromTheme(QStringLiteral("internet-services")); + } + checkbox->setIcon(icon); + + KAccountsUiPlugin *uiPlugin = KAccounts::UiPluginsManager::pluginForService(service.serviceType()); + if (uiPlugin) { + m_connections << connect(uiPlugin, &KAccountsUiPlugin::configUiReady, [=]() { + qDebug() << "Config UI ready" << m_account.data()->id() << m_account.data(); + uiPlugin->showConfigureAccountDialog(m_account.data()->id()); + }); + + QHBoxLayout *hlayout = new QHBoxLayout(); + QPushButton *imConfigButton = new QPushButton(i18n("Configure...")); + m_connections << connect(imConfigButton, &QPushButton::clicked, [=](){ + uiPlugin->init(KAccountsUiPlugin::ConfigureAccountDialog); + }); + + hlayout->addWidget(checkbox); + hlayout->addWidget(imConfigButton); + d_layout->addLayout(hlayout); + } else { + d_layout->addWidget(checkbox); + } + connect(checkbox, SIGNAL(clicked(bool)), SLOT(serviceChanged(bool))); + m_checkboxes.insert(service.name(), checkbox); + } + + m_account = account; + connect(account, SIGNAL(enabledChanged(QString,bool)), SLOT(serviceEnabledChanged(QString,bool))); +} + +void AccountWidget::serviceEnabledChanged(const QString &serviceName, bool enabled) +{ + if (serviceName.isEmpty()) { + return; + } + + Q_ASSERT(m_checkboxes.contains(serviceName)); + m_checkboxes[serviceName]->setChecked(enabled); +} + +void AccountWidget::serviceChanged(bool enabled) +{ + QString service = sender()->property("service").toString(); + if (!m_account) { + return; + } + + qDebug() << "Service" << service << (enabled ? "enabled" : "disabled"); + m_account->selectService(m_manager->service(service)); + m_account->setEnabled(enabled); + + // make sure the underlying account also gets enabled + // or disabled it all services are disabled + if (enabled) { + m_account->selectService(); + m_account->setEnabled(true); + } else { + bool shouldStayEnabled = false; + Q_FOREACH (const Accounts::Service &accountService, m_account->services()) { + // Skip the current service, that is not synced to the account yet + // so it would return the state before the user clicked the checkbox + if (accountService.name() == service) { + continue; + } + m_account->selectService(accountService); + if (m_account->isEnabled()) { + // At least one service is enabled, leave the account enabled + shouldStayEnabled = true; + break; + } + } + + // Make sure we're operating on the global account + m_account->selectService(); + m_account->setEnabled(shouldStayEnabled); + } + + m_account->sync(); +} diff --git a/src/lib/uipluginsmanager.h b/src/create.h copy from src/lib/uipluginsmanager.h copy to src/create.h --- a/src/lib/uipluginsmanager.h +++ b/src/create.h @@ -1,5 +1,5 @@ /************************************************************************************* - * Copyright (C) 2015 by Martin Klapetek * + * Copyright (C) 2012 by Alejandro Fiestas Olivares * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * @@ -16,22 +16,45 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * *************************************************************************************/ -#ifndef UIPLUGINSMANAGER_H -#define UIPLUGINSMANAGER_H +#ifndef CREATE_H +#define CREATE_H -#include +#include -class KAccountsUiPlugin; +class QDialog; +class QWidget; +class Ui_createForm; -namespace KAccounts { +namespace Accounts +{ + class Manager; + class Provider; +} + +class Create : public QObject +{ + Q_OBJECT -class UiPluginsManager { public: - static QList uiPlugins(); - static KAccountsUiPlugin* pluginForService(const QString &service); - static KAccountsUiPlugin* pluginForName(const QString &name); -}; + Create (QWidget *parent); + virtual ~Create(); -} + QWidget* widget(); -#endif //UIPLUGINSMANAGER_H +private: + void createProviderButton(const Accounts::Provider &provider); + +private Q_SLOTS: + void fillInterface(); + void createAccount(); + +Q_SIGNALS: + void newAccount(const QString &type, const QString &name); + +private: + QDialog *m_dialog; + QWidget *m_parent; + Ui_createForm *m_form; + Accounts::Manager *m_manager; +}; +#endif// CREATE_H diff --git a/src/create.cpp b/src/create.cpp new file mode 100644 --- /dev/null +++ b/src/create.cpp @@ -0,0 +1,161 @@ +/************************************************************************************* + * Copyright (C) 2012 by Alejandro Fiestas Olivares * + * * + * 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; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * + *************************************************************************************/ + +#include "create.h" +#include "jobs/createaccount.h" +#include + +#include "ui_types.h" + +#include + +#include +#include +#include + +#include +#include + +#include +#include + +Create::Create(QWidget *parent) + : QObject(parent) + , m_form(nullptr) + , m_manager(KAccounts::accountsManager()) +{ + m_parent = parent; +} + +Create::~Create() +{ +} + +QWidget* Create::widget() +{ + if (!m_form) { + m_form = new Ui_createForm(); + } + + QWidget *widget = new QWidget(m_parent); + m_form->setupUi(widget); + m_form->progressBar->hide(); + + QMetaObject::invokeMethod(this, "fillInterface", Qt::QueuedConnection); + + return widget; +} + +void Create::fillInterface() +{ + Accounts::ProviderList providerList = m_manager->providerList(); + const Accounts::ServiceList serviceList = m_manager->serviceList(); + + if (providerList.isEmpty()) { + auto noProvidersMessageWidget = new KMessageWidget( + xi18n("No account providers found." + "Some providers can be found in packages kaccounts-providers" + " and ktp-accounts-kcm.")); + noProvidersMessageWidget->setMessageType(KMessageWidget::MessageType::Warning); + m_form->verticalLayout_2->insertWidget(0, noProvidersMessageWidget); + return; + } + + QSet wantedProviders; + QSet locatedProviders; + + // sort accounts alphabetically + std::sort(providerList.begin(), providerList.end(), [](const Accounts::Provider &a, const Accounts::Provider &b) { + return QString::localeAwareCompare(b.displayName(), a.displayName()) < 0; + }); + + for(const Accounts::Provider &provider : providerList) { + if (provider.name() == "ktp-generic") { + locatedProviders.insert(provider.name()); + continue; + } + + // Check if there are any services for the given provider + // If not, just skip it and don't allow creating such account + bool shouldSkip = true; + for(const Accounts::Service &service : qAsConst(serviceList)) { + qDebug() << "Checking service " << service.name() << " for provider " << provider.name(); + wantedProviders.insert(service.provider()); + if (service.provider() == provider.name()) { + qDebug() << "Found a service, not skipping:" << service.name(); + locatedProviders.insert(provider.name()); + shouldSkip = false; + break; + } + } + + if (shouldSkip) { + continue; + } + + createProviderButton(provider); + } + + const auto missingProviders = wantedProviders.subtract(locatedProviders); + if (!missingProviders.isEmpty()) { + const auto missingProvidersString = missingProviders.toList().join(" "); + const QString infoMessage = i18n("Following missing providers are required by installed services: %1", missingProvidersString); + + auto missingProvidersMessageWidget = new KMessageWidget(infoMessage); + missingProvidersMessageWidget->setMessageType(KMessageWidget::MessageType::Warning); + m_form->verticalLayout_2->insertWidget(0, missingProvidersMessageWidget); + return; + } +} + +void Create::createProviderButton(const Accounts::Provider &provider) +{ + QCommandLinkButton *button = new QCommandLinkButton(i18nd(provider.trCatalog().toLatin1().constData(), + provider.displayName().toUtf8().constData())); + const QString providerIcon = provider.iconName(); + if (providerIcon.isEmpty()) { + button->setIcon(QIcon::fromTheme("list-add")); + } else { + button->setIcon(QIcon::fromTheme(providerIcon)); + } + button->setProperty("providerName", provider.name()); + button->setToolTip(i18nd(provider.trCatalog().toLatin1().constData(), provider.description().toUtf8().constData())); + + connect(button, SIGNAL(clicked(bool)), SLOT(createAccount())); + m_form->verticalLayout->insertWidget(0, button); +} + +void Create::createAccount() +{ + m_form->progressBar->show(); + m_form->scrollAreaWidgetContents->setEnabled(false); + QString providerName = sender()->property("providerName").toString(); + qDebug() << "Starting new account dialog for" << providerName; + CreateAccount *acc = new CreateAccount(providerName, this); + + connect(acc, &CreateAccount::finished, this, [=](KJob *job) { + m_form->progressBar->hide(); + m_form->scrollAreaWidgetContents->setEnabled(true); + if (job->error() == KJob::UserDefinedError) { + QMessageBox::critical(m_parent, i18nc("Messagebox title; meaning 'Unable to finish the action you started'", "Unable to finish"), job->errorText()); + } + job->deleteLater(); + }); + + acc->start(); +} diff --git a/src/declarative/CMakeLists.txt b/src/declarative/CMakeLists.txt --- a/src/declarative/CMakeLists.txt +++ b/src/declarative/CMakeLists.txt @@ -2,7 +2,7 @@ add_library(kaccountsdeclarativeplugin SHARED kaccountsdeclarativeplugin.cpp ../jobs/createaccount.cpp - ../lib/uipluginsmanager.cpp) + ../uipluginsmanager.cpp) target_link_libraries(kaccountsdeclarativeplugin Qt5::Qml KF5::I18n diff --git a/src/lib/uipluginsmanager.h b/src/kaccounts.h copy from src/lib/uipluginsmanager.h copy to src/kaccounts.h --- a/src/lib/uipluginsmanager.h +++ b/src/kaccounts.h @@ -1,5 +1,5 @@ /************************************************************************************* - * Copyright (C) 2015 by Martin Klapetek * + * Copyright (C) 2012 by Alejandro Fiestas Olivares * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * @@ -16,22 +16,43 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * *************************************************************************************/ -#ifndef UIPLUGINSMANAGER_H -#define UIPLUGINSMANAGER_H +#ifndef KACCOUNTS_H +#define KACCOUNTS_H -#include +#include -class KAccountsUiPlugin; +class Create; +class QModelIndex; +class AccountsModel; +class AccountWidget; +class QStackedLayout; +class QItemSelectionModel; +class QDBusPendingCallWatcher; -namespace KAccounts { +namespace Ui { + class KCMWebAccounts; +} -class UiPluginsManager { +class KAccounts : public KCModule +{ + Q_OBJECT public: - static QList uiPlugins(); - static KAccountsUiPlugin* pluginForService(const QString &service); - static KAccountsUiPlugin* pluginForName(const QString &name); -}; + KAccounts(QWidget *parent, const QVariantList &); + virtual ~KAccounts(); -} +private Q_SLOTS: + void addBtnClicked(); + void rmBtnClicked(); + void currentChanged(const QModelIndex ¤t, const QModelIndex &previous); + void moduleLoadCallFinished(QDBusPendingCallWatcher *watcher); + +private: + Create *m_create; + QStackedLayout *m_layout; + Ui::KCMWebAccounts *m_ui; + AccountsModel *m_model; + AccountWidget *m_accWidget; + QItemSelectionModel *m_selectionModel; +}; -#endif //UIPLUGINSMANAGER_H +#endif // KACCOUNTS_H diff --git a/src/kaccounts.cpp b/src/kaccounts.cpp new file mode 100644 --- /dev/null +++ b/src/kaccounts.cpp @@ -0,0 +1,148 @@ +/************************************************************************************* + * Copyright (C) 2012 by Alejandro Fiestas Olivares * + * * + * 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; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * + *************************************************************************************/ + +#include "kaccounts.h" +#include "create.h" +#include "ui_kcm.h" + +#include "models/accountsmodel.h" +#include "accountwidget.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +K_PLUGIN_FACTORY_WITH_JSON(KAccountsFactory, "kcm_kaccounts.json", registerPlugin();) + +KAccounts::KAccounts(QWidget *parent, const QVariantList &) + : KCModule(parent) + , m_create(nullptr) + , m_layout(new QStackedLayout) +{ + m_ui = new Ui::KCMWebAccounts(); + m_ui->setupUi(this); + + m_ui->accountInfo->setLayout(m_layout); + m_create = new Create(this); + m_layout->addWidget(m_create->widget()); + + m_accWidget = new AccountWidget(nullptr, this); + m_layout->addWidget(m_accWidget); + + m_model = new AccountsModel(this); + m_selectionModel = new QItemSelectionModel(m_model); + connect(m_selectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)), SLOT(currentChanged(QModelIndex,QModelIndex))); + + if (m_model->rowCount() == 0) { + m_layout->setCurrentIndex(0); + } else { + QLabel *label = new QLabel(i18n("Select an account from the left column to configure"), this); + label->setAlignment(Qt::AlignCenter); + m_layout->addWidget(label); + m_layout->setCurrentIndex(2); + } + + m_ui->accountsView->setIconSize(QSize(32,32)); + m_ui->accountsView->setModel(m_model); + m_ui->accountsView->setSelectionModel(m_selectionModel); + + connect(m_ui->removeBtn, SIGNAL(clicked(bool)), this, SLOT(rmBtnClicked())); + connect(m_ui->addBtn, SIGNAL(clicked(bool)), this, SLOT(addBtnClicked())); + + QDBusMessage moduleLoadCall = QDBusMessage::createMethodCall(QStringLiteral("org.kde.kded5"), QStringLiteral("/kded"), + QStringLiteral("org.kde.kded5"), QStringLiteral("loadModule")); + moduleLoadCall.setArguments(QList{QVariant("accounts")}); + + QDBusPendingCall pendingCall = QDBusConnection::sessionBus().asyncCall(moduleLoadCall); + QDBusPendingCallWatcher *pendingCallWatcher = new QDBusPendingCallWatcher(pendingCall, this); + connect(pendingCallWatcher, &QDBusPendingCallWatcher::finished, + this, &KAccounts::moduleLoadCallFinished); +} + +void KAccounts::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) +{ + Q_UNUSED(previous) + + if (!current.isValid()) { + return; + } + + if (current.row() == m_model->rowCount() - 1) { + m_ui->removeBtn->setDisabled(true); + m_layout->setCurrentIndex(0); + m_accWidget->setAccount(nullptr); + return; + } + + Accounts::Account* acc = qobject_cast(m_model->data(current, AccountsModel::Data).value()); + m_accWidget->setAccount(acc); + m_ui->removeBtn->setDisabled(false); + m_layout->setCurrentIndex(1); +} + +KAccounts::~KAccounts() +{ + delete m_ui; +} + +void KAccounts::addBtnClicked() +{ + m_selectionModel->setCurrentIndex(m_model->index(m_model->rowCount() - 1), QItemSelectionModel::SelectCurrent); +} + +void KAccounts::rmBtnClicked() +{ + QModelIndex index = m_selectionModel->currentIndex(); + if (!index.isValid()) { + return; + } + + auto account = qobject_cast(m_model->data(index, AccountsModel::Data).value()); + const auto response = KMessageBox::questionYesNo(this, i18n("Are you sure that you want to remove the account '%1'? This cannot be undone.", account->displayName()), i18n("Account Removal")); + if (response == KMessageBox::Yes) { + m_model->removeRows(index.row(), 1); + } +} + +void KAccounts::moduleLoadCallFinished(QDBusPendingCallWatcher *watcher) +{ + QDBusPendingReply reply = *watcher; + bool loaded; + if (reply.isError()) { + loaded = false; + } else { + loaded = reply.value(); + } + + if (!loaded) { + qWarning() << "Unable to start the kded module, things may (and most probably will) misbehave"; + } +} + +#include "kaccounts.moc" diff --git a/src/kcm.ui b/src/kcm.ui new file mode 100644 --- /dev/null +++ b/src/kcm.ui @@ -0,0 +1,94 @@ + + + KCMWebAccounts + + + + 0 + 0 + + + + + + + + 0 + 0 + + + + + 350 + 16777215 + + + + + 0 + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::MinimumExpanding + + + + 40 + 20 + + + + + + + + + + + + + + + + + + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/kcm/CMakeLists.txt b/src/kcm/CMakeLists.txt deleted file mode 100644 --- a/src/kcm/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -set(accountsettings_SRCS - accounts.cpp -) - -add_library(kcm_kaccounts MODULE ${accountsettings_SRCS}) - -target_link_libraries(kcm_kaccounts - Qt5::Core - KF5::CoreAddons - KF5::I18n - KF5::QuickAddons - ) -kcoreaddons_desktop_to_json(kcm_kaccounts "kcm_kaccounts.desktop") - -install(TARGETS kcm_kaccounts DESTINATION ${KDE_INSTALL_PLUGINDIR}/kcms) - -install(FILES kcm_kaccounts.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) -kpackage_install_package(package kcm_kaccounts kcms) diff --git a/src/kcm/package/contents/ui/AvailableAccounts.qml b/src/kcm/package/contents/ui/AvailableAccounts.qml deleted file mode 100644 --- a/src/kcm/package/contents/ui/AvailableAccounts.qml +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2019 Nicolas Fella - * - * This program 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 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 Library General Public License for more details - * - * You should have received a copy of the GNU Library General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -import QtQuick 2.7 -import QtQuick.Layouts 1.11 -import QtQuick.Controls 2.0 as Controls -import org.kde.kirigami 2.4 as Kirigami -import org.kde.kaccounts 1.0 -import org.kde.kcm 1.2 -import Ubuntu.OnlineAccounts 0.1 as OA - -ScrollViewKCM { - id: root - title: i18n("Add new Account") - - ListView { - anchors.fill: parent - - model: OA.ProviderModel {} - - delegate: Kirigami.BasicListItem { - icon: model.iconName - label: model.displayName - width: parent.width - - onClicked: { - var job = jobComponent.createObject(root, { "providerName": providerId }) - job.start() - } - } - } - - Component { - id: jobComponent - CreateAccount { - onFinished: kcm.pop() - } - } -} diff --git a/src/kcm/package/contents/ui/AvailableServices.qml b/src/kcm/package/contents/ui/AvailableServices.qml deleted file mode 100644 --- a/src/kcm/package/contents/ui/AvailableServices.qml +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2019 Nicolas Fella - * - * This program 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 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 Library General Public License for more details - * - * You should have received a copy of the GNU Library General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -import QtQuick 2.7 -import QtQuick.Layouts 1.11 -import QtQuick.Controls 2.0 as Controls -import org.kde.kirigami 2.4 as Kirigami -import org.kde.kaccounts 1.0 -import org.kde.kcm 1.2 -import Ubuntu.OnlineAccounts 0.1 as OA - -ScrollViewKCM { - - title: i18n("Available Services") - - property alias accountId: servicesModel.accountId - - ListView { - anchors.fill: parent - model: OA.AccountServiceModel { - id: servicesModel - } - delegate: Kirigami.AbstractListItem { - width: parent.width - Controls.CheckBox { - text: model.serviceName - checked: model.enabled - } - } - } -} diff --git a/src/kcm/kcm_kaccounts.desktop b/src/kcm_kaccounts.desktop rename from src/kcm/kcm_kaccounts.desktop rename to src/kcm_kaccounts.desktop diff --git a/src/lib/uipluginsmanager.h b/src/models/accountsmodel.h copy from src/lib/uipluginsmanager.h copy to src/models/accountsmodel.h --- a/src/lib/uipluginsmanager.h +++ b/src/models/accountsmodel.h @@ -1,5 +1,5 @@ /************************************************************************************* - * Copyright (C) 2015 by Martin Klapetek * + * Copyright (C) 2012 by Alejandro Fiestas Olivares * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * @@ -16,22 +16,38 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * *************************************************************************************/ -#ifndef UIPLUGINSMANAGER_H -#define UIPLUGINSMANAGER_H +#ifndef ACCOUNTS_MODEL_H +#define ACCOUNTS_MODEL_H -#include +#include -class KAccountsUiPlugin; +#include -namespace KAccounts { +class AccountsModelPrivate; +class AccountsModel : public QAbstractListModel +{ + Q_OBJECT -class UiPluginsManager { -public: - static QList uiPlugins(); - static KAccountsUiPlugin* pluginForService(const QString &service); - static KAccountsUiPlugin* pluginForName(const QString &name); -}; + public: + enum Roles { + Id = Qt::UserRole, + Data + }; + explicit AccountsModel(QObject* parent = nullptr); + virtual ~AccountsModel(); + + virtual int rowCount(const QModelIndex& parent = QModelIndex()) const; + virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + virtual bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()); -} + public Q_SLOTS: + void accountCreated(Accounts::AccountId accountId); + void accountRemoved(Accounts::AccountId accountId); + void accountUpdated(); + + private: + AccountsModelPrivate *d; +}; -#endif //UIPLUGINSMANAGER_H +#endif //ACCOUNTS_MODEL_H \ No newline at end of file diff --git a/src/models/accountsmodel.cpp b/src/models/accountsmodel.cpp new file mode 100644 --- /dev/null +++ b/src/models/accountsmodel.cpp @@ -0,0 +1,230 @@ +/************************************************************************************* + * Copyright (C) 2012 by Alejandro Fiestas Olivares * + * * + * 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; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * + *************************************************************************************/ + +#include "accountsmodel.h" + +#include + +#include +#include + +#include + +#include +#include + +class AccountsModelPrivate : public QObject +{ + public: + AccountsModelPrivate(AccountsModel *model); + virtual ~AccountsModelPrivate(); + + QVariant createAccountData(int role); + Accounts::Account* accountById(int id); + void removeAccount(Accounts::AccountId accountId); + + Accounts::Manager *m_manager; + Accounts::AccountIdList m_accIdList; + QHash m_accHash; + + private: + AccountsModel* q; +}; + +AccountsModelPrivate::~AccountsModelPrivate() +{ + qDeleteAll(m_accHash); + delete m_manager; +} + +AccountsModelPrivate::AccountsModelPrivate(AccountsModel *model) + : m_manager(new Accounts::Manager(this)) + , q(model) +{ + m_accIdList = m_manager->accountList(); + m_accIdList.append(0); //For the dummy account Create + + connect(m_manager, SIGNAL(accountCreated(Accounts::AccountId)), + q, SLOT(accountCreated(Accounts::AccountId))); + connect(m_manager, SIGNAL(accountRemoved(Accounts::AccountId)), + q, SLOT(accountRemoved(Accounts::AccountId))); +} + +QVariant AccountsModelPrivate::createAccountData(int role) +{ + if (role == Qt::DisplayRole) { + return i18n("Create"); + } + + if (role == Qt::DecorationRole) { + return QIcon::fromTheme("list-add"); + } + + return QVariant(); +} + +Accounts::Account* AccountsModelPrivate::accountById(int id) +{ + if (m_accHash.contains(id)) { + return m_accHash.value(id); + } + + Accounts::Account* account = m_manager->account(id); + if (!account) { + qDebug() << "\t Failed to get the account from manager"; + return nullptr; + } + + connect(account, SIGNAL(displayNameChanged(QString)), q, SLOT(accountUpdated())); + + m_accHash[id] = account; + return account; +} + +void AccountsModelPrivate::removeAccount(Accounts::AccountId accountId) +{ + m_accIdList.removeOne(accountId); + delete m_accHash.take(accountId); +} + +AccountsModel::AccountsModel(QObject* parent) + : QAbstractListModel(parent) + , d(new AccountsModelPrivate(this)) +{ +} + +AccountsModel::~AccountsModel() +{ + delete d; +} + +int AccountsModel::rowCount(const QModelIndex& parent) const +{ + if (parent.isValid()) { + return 0; + } + + return d->m_accIdList.count(); +} + +QVariant AccountsModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + Q_UNUSED(section) + if (role != Qt::DisplayRole) { + return QVariant(); + } + + if (orientation == Qt::Vertical) { + return QVariant(); + } + + return i18n("Accounts"); +} + +QVariant AccountsModel::data(const QModelIndex& index, int role) const +{ + if(!index.isValid()) { + return QVariant(); + } + + if (index.row() >= d->m_accIdList.count()) { + return QVariant(); + } + + Accounts::AccountId accountId = d->m_accIdList.value(index.row()); + if (accountId == 0) { + return d->createAccountData(role); + } + + Accounts::Account *account = d->accountById(accountId); + switch (role) { + case Qt::DisplayRole: + return account->displayName(); + case Qt::DecorationRole: + { + QIcon icon = QIcon::fromTheme(d->m_manager->provider(account->providerName()).iconName()); + if (!icon.isNull()) { + return icon; + } + + return QIcon::fromTheme("system-help"); + } + case Id: + return account->id(); + case Data: + return QVariant::fromValue(account); + } + + return QVariant(); +} + +bool AccountsModel::removeRows(int row, int count, const QModelIndex& parent) +{ + Q_UNUSED(count) + Q_UNUSED(parent) + if (row >= d->m_accIdList.count()) { + return false; + } + Accounts::AccountId accountId = d->m_accIdList.value(row); + if (accountId == 0) { + return false; + } + + Accounts::Account *acc = d->accountById(accountId); + SignOn::Identity *identity = SignOn::Identity::existingIdentity(acc->credentialsId(), this); + if (identity) { + identity->remove(); + identity->deleteLater(); + } + + acc->remove(); + acc->sync(); + + return true; +} + +void AccountsModel::accountCreated(Accounts::AccountId accountId) +{ + qDebug() << "AccountsModel::accountCreated: " << accountId; + int row = d->m_accIdList.count(); + if (accountId) { + row -= 1; // last item will always be the dummy create account + } + + beginInsertRows(QModelIndex(), row, row); + d->m_accIdList.insert(row, accountId); + endInsertRows(); +} + +void AccountsModel::accountRemoved(Accounts::AccountId accountId) +{ + qDebug() << "AccountsModel::accountRemoved: " << accountId; + beginRemoveRows(QModelIndex(), d->m_accIdList.indexOf(accountId), d->m_accIdList.indexOf(accountId)); + d->removeAccount(accountId); + endRemoveRows(); +} + +void AccountsModel::accountUpdated() +{ + Accounts::Account *acc = qobject_cast(sender()); + Accounts::AccountId accountId = acc->id(); + qDebug() << "Account updated: " << accountId; + + QModelIndex accountIndex = index(d->m_accIdList.indexOf(accountId), 0); + Q_EMIT dataChanged(accountIndex, accountIndex); +} diff --git a/src/services.ui b/src/services.ui new file mode 100644 --- /dev/null +++ b/src/services.ui @@ -0,0 +1,85 @@ + + + Services + + + + 0 + 0 + 517 + 408 + + + + + + + + + + 0 + 0 + + + + Select what services you want to activate + + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + QFrame::Plain + + + 0 + + + true + + + + + 0 + 0 + 501 + 173 + + + + + + + + + + Qt::Vertical + + + + 20 + 159 + + + + + + + + + + + + + + + diff --git a/src/types.ui b/src/types.ui new file mode 100644 --- /dev/null +++ b/src/types.ui @@ -0,0 +1,99 @@ + + + createForm + + + + 0 + 0 + 354 + 92 + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + 0 + + + true + + + + + 0 + 0 + 342 + 48 + + + + + + + Qt::Horizontal + + + + 166 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 2 + + + + + + + + + + Qt::Horizontal + + + + 130 + 20 + + + + + + + + + + + + 0 + + + 0 + + + + + + + + diff --git a/src/lib/uipluginsmanager.h b/src/uipluginsmanager.h rename from src/lib/uipluginsmanager.h rename to src/uipluginsmanager.h diff --git a/src/lib/uipluginsmanager.cpp b/src/uipluginsmanager.cpp rename from src/lib/uipluginsmanager.cpp rename to src/uipluginsmanager.cpp