fd681e62ab
This KCM will have to get installed installed in the new plasma namespace eventually. But considering that this app is part of the release service, we should not depend on changes in a not yet released Plasma version. Task: https://phabricator.kde.org/T14501
381 lines
12 KiB
C++
381 lines
12 KiB
C++
/**
|
|
* SPDX-FileCopyrightText: 2013 Albert Vaca <albertvaka@gmail.com>
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
|
*/
|
|
|
|
#include "kcm.h"
|
|
|
|
#include <KPluginInfo>
|
|
#include <KPluginMetaData>
|
|
#include <KAboutData>
|
|
#include <KLocalizedString>
|
|
#include <kcmutils_version.h>
|
|
#include <KColorSchemeManager>
|
|
|
|
#include "ui_kcm.h"
|
|
#include "dbusinterfaces.h"
|
|
#include "devicesmodel.h"
|
|
#include "devicessortproxymodel.h"
|
|
#include "kdeconnect-version.h"
|
|
|
|
K_PLUGIN_CLASS_WITH_JSON(KdeConnectKcm, "kcm_kdeconnect.json")
|
|
|
|
static QString createId() { return QStringLiteral("kcm")+QString::number(QCoreApplication::applicationPid()); }
|
|
|
|
KdeConnectKcm::KdeConnectKcm(QWidget* parent, const QVariantList& args)
|
|
: KCModule(parent)
|
|
, kcmUi(new Ui::KdeConnectKcmUi())
|
|
, daemon(new DaemonDbusInterface(this))
|
|
, devicesModel(new DevicesModel(this))
|
|
, currentDevice(nullptr)
|
|
{
|
|
KAboutData* about = new KAboutData(QStringLiteral("kdeconnect-kcm"),
|
|
i18n("KDE Connect Settings"),
|
|
QStringLiteral(KDECONNECT_VERSION_STRING),
|
|
i18n("KDE Connect Settings module"),
|
|
KAboutLicense::KAboutLicense::GPL_V2,
|
|
i18n("(C) 2015 Albert Vaca Cintora"),
|
|
QString(),
|
|
QStringLiteral("https://community.kde.org/KDEConnect")
|
|
);
|
|
about->addAuthor(i18n("Albert Vaca Cintora"));
|
|
about->setProgramLogo(QIcon(QStringLiteral(":/icons/kdeconnect/kdeconnect.svg")));
|
|
|
|
setAboutData(about);
|
|
|
|
#ifdef Q_OS_WIN
|
|
KColorSchemeManager manager;
|
|
QApplication::setStyle(QStringLiteral("breeze"));
|
|
#endif
|
|
|
|
kcmUi->setupUi(this);
|
|
|
|
sortProxyModel = new DevicesSortProxyModel(devicesModel);
|
|
|
|
kcmUi->deviceList->setModel(sortProxyModel);
|
|
|
|
kcmUi->deviceInfo->setVisible(false);
|
|
kcmUi->progressBar->setVisible(false);
|
|
kcmUi->messages->setVisible(false);
|
|
|
|
//Workaround: If we set this directly (or if we set it in the .ui file), the layout breaks
|
|
kcmUi->noDeviceLinks->setWordWrap(false);
|
|
QTimer::singleShot(0, this, [this] { kcmUi->noDeviceLinks->setWordWrap(true); });
|
|
|
|
setWhenAvailable(daemon->announcedName(), [this](const QString& announcedName) {
|
|
kcmUi->rename_label->setText(announcedName);
|
|
kcmUi->rename_edit->setText(announcedName);
|
|
}, this);
|
|
connect(daemon, SIGNAL(announcedNameChanged(QString)),
|
|
kcmUi->rename_edit, SLOT(setText(QString)));
|
|
connect(daemon, SIGNAL(announcedNameChanged(QString)),
|
|
kcmUi->rename_label, SLOT(setText(QString)));
|
|
setRenameMode(false);
|
|
|
|
setButtons(KCModule::Help | KCModule::NoAdditionalButton);
|
|
|
|
connect(devicesModel, &QAbstractItemModel::dataChanged,
|
|
this, &KdeConnectKcm::resetSelection);
|
|
connect(kcmUi->deviceList->selectionModel(), &QItemSelectionModel::currentChanged,
|
|
this, &KdeConnectKcm::deviceSelected);
|
|
connect(kcmUi->accept_button, &QAbstractButton::clicked,
|
|
this, &KdeConnectKcm::acceptPairing);
|
|
connect(kcmUi->reject_button, &QAbstractButton::clicked,
|
|
this, &KdeConnectKcm::rejectPairing);
|
|
connect(kcmUi->pair_button, &QAbstractButton::clicked,
|
|
this, &KdeConnectKcm::requestPair);
|
|
connect(kcmUi->unpair_button, &QAbstractButton::clicked,
|
|
this, &KdeConnectKcm::unpair);
|
|
connect(kcmUi->ping_button, &QAbstractButton::clicked,
|
|
this, &KdeConnectKcm::sendPing);
|
|
connect(kcmUi->refresh_button,&QAbstractButton::clicked,
|
|
this, &KdeConnectKcm::refresh);
|
|
connect(kcmUi->rename_edit,&QLineEdit::returnPressed,
|
|
this, &KdeConnectKcm::renameDone);
|
|
connect(kcmUi->renameDone_button,&QAbstractButton::clicked,
|
|
this, &KdeConnectKcm::renameDone);
|
|
connect(kcmUi->renameShow_button,&QAbstractButton::clicked,
|
|
this, &KdeConnectKcm::renameShow);
|
|
|
|
daemon->acquireDiscoveryMode(createId());
|
|
|
|
#if KCMUTILS_VERSION >= QT_VERSION_CHECK(5, 45, 0)
|
|
|
|
if (!args.isEmpty() && args.first().type() == QVariant::String) {
|
|
const QString input = args.first().toString();
|
|
const auto colonIdx = input.indexOf(QLatin1Char(':'));
|
|
const QString deviceId = input.left(colonIdx);
|
|
const QString pluginCM = colonIdx < 0 ? QString() : input.mid(colonIdx+1);
|
|
|
|
connect(devicesModel, &DevicesModel::rowsInserted, this, [this, deviceId, pluginCM]() {
|
|
auto row = devicesModel->rowForDevice(deviceId);
|
|
if (row >= 0) {
|
|
const QModelIndex idx = sortProxyModel->mapFromSource(devicesModel->index(row));
|
|
kcmUi->deviceList->selectionModel()->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect);
|
|
}
|
|
if (!pluginCM.isEmpty()) {
|
|
kcmUi->pluginSelector->showConfiguration(pluginCM);
|
|
}
|
|
disconnect(devicesModel, &DevicesModel::rowsInserted, this, nullptr);
|
|
});
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
void KdeConnectKcm::renameShow()
|
|
{
|
|
setRenameMode(true);
|
|
}
|
|
|
|
void KdeConnectKcm::renameDone()
|
|
{
|
|
QString newName = kcmUi->rename_edit->text();
|
|
if (newName.isEmpty()) {
|
|
//Rollback changes
|
|
kcmUi->rename_edit->setText(kcmUi->rename_label->text());
|
|
} else {
|
|
kcmUi->rename_label->setText(newName);
|
|
daemon->setAnnouncedName(newName);
|
|
}
|
|
setRenameMode(false);
|
|
}
|
|
|
|
void KdeConnectKcm::setRenameMode(bool b) {
|
|
kcmUi->renameDone_button->setVisible(b);
|
|
kcmUi->rename_edit->setVisible(b);
|
|
kcmUi->renameShow_button->setVisible(!b);
|
|
kcmUi->rename_label->setVisible(!b);
|
|
}
|
|
|
|
KdeConnectKcm::~KdeConnectKcm()
|
|
{
|
|
daemon->releaseDiscoveryMode(createId());
|
|
delete kcmUi;
|
|
}
|
|
|
|
void KdeConnectKcm::refresh()
|
|
{
|
|
daemon->acquireDiscoveryMode(createId());
|
|
daemon->forceOnNetworkChange();
|
|
}
|
|
|
|
void KdeConnectKcm::resetSelection()
|
|
{
|
|
if (!currentDevice) {
|
|
return;
|
|
}
|
|
kcmUi->deviceList->selectionModel()->setCurrentIndex(sortProxyModel->mapFromSource(currentIndex), QItemSelectionModel::ClearAndSelect);
|
|
}
|
|
|
|
void KdeConnectKcm::deviceSelected(const QModelIndex& current)
|
|
{
|
|
if (currentDevice) {
|
|
disconnect(currentDevice, 0, this, 0);
|
|
}
|
|
|
|
//Store previous device config
|
|
pluginsConfigChanged();
|
|
|
|
if (!current.isValid()) {
|
|
currentDevice = nullptr;
|
|
kcmUi->deviceInfo->setVisible(false);
|
|
return;
|
|
}
|
|
|
|
currentIndex = sortProxyModel->mapToSource(current);
|
|
currentDevice = devicesModel->getDevice(currentIndex.row());
|
|
|
|
kcmUi->noDevicePlaceholder->setVisible(false);
|
|
bool valid = (currentDevice != nullptr && currentDevice->isValid());
|
|
kcmUi->deviceInfo->setVisible(valid);
|
|
if (!valid) {
|
|
return;
|
|
}
|
|
|
|
kcmUi->messages->setVisible(false);
|
|
resetDeviceView();
|
|
|
|
connect(currentDevice, SIGNAL(pluginsChanged()), this, SLOT(resetCurrentDevice()));
|
|
connect(currentDevice, SIGNAL(trustedChanged(bool)), this, SLOT(trustedChanged(bool)));
|
|
connect(currentDevice, SIGNAL(pairingError(QString)), this, SLOT(pairingFailed(QString)));
|
|
connect(currentDevice, &DeviceDbusInterface::hasPairingRequestsChangedProxy, this, &KdeConnectKcm::currentDevicePairingChanged);
|
|
}
|
|
|
|
void KdeConnectKcm::currentDevicePairingChanged(bool pairing)
|
|
{
|
|
if (pairing) {
|
|
setCurrentDeviceTrusted(RequestedByPeer);
|
|
} else {
|
|
setWhenAvailable(currentDevice->isTrusted(), [this](bool trusted) {
|
|
setCurrentDeviceTrusted(trusted ? Trusted : NotTrusted);
|
|
}, this);
|
|
}
|
|
}
|
|
|
|
void KdeConnectKcm::resetCurrentDevice()
|
|
{
|
|
const QStringList supportedPluginNames = currentDevice->supportedPlugins();
|
|
|
|
if (m_oldSupportedPluginNames != supportedPluginNames) {
|
|
resetDeviceView();
|
|
}
|
|
}
|
|
|
|
void KdeConnectKcm::resetDeviceView()
|
|
{
|
|
//KPluginSelector has no way to remove a list of plugins and load another, so we need to destroy and recreate it each time
|
|
delete kcmUi->pluginSelector;
|
|
kcmUi->pluginSelector = new KPluginSelector(this);
|
|
kcmUi->deviceInfo_layout->addWidget(kcmUi->pluginSelector);
|
|
kcmUi->verificationKey->setText(i18n("Key: %1", QString::fromUtf8(currentDevice->verificationKey())));
|
|
|
|
kcmUi->pluginSelector->setConfigurationArguments(QStringList(currentDevice->id()));
|
|
|
|
kcmUi->name_label->setText(currentDevice->name());
|
|
setWhenAvailable(currentDevice->isTrusted(), [this](bool trusted) {
|
|
if (trusted)
|
|
setCurrentDeviceTrusted(Trusted);
|
|
else
|
|
setWhenAvailable(currentDevice->hasPairingRequests(), [this](bool haspr) {
|
|
setCurrentDeviceTrusted(haspr ? RequestedByPeer : NotTrusted);
|
|
}, this);
|
|
}, this);
|
|
|
|
const QList<KPluginInfo> pluginInfo = KPluginInfo::fromMetaData(KPluginLoader::findPlugins(QStringLiteral("kdeconnect/")));
|
|
QList<KPluginInfo> availablePluginInfo;
|
|
|
|
m_oldSupportedPluginNames = currentDevice->supportedPlugins();
|
|
for (auto it = pluginInfo.cbegin(), itEnd = pluginInfo.cend(); it!=itEnd; ++it) {
|
|
if (m_oldSupportedPluginNames.contains(it->pluginName())) {
|
|
availablePluginInfo.append(*it);
|
|
}
|
|
}
|
|
|
|
KSharedConfigPtr deviceConfig = KSharedConfig::openConfig(currentDevice->pluginsConfigFile());
|
|
kcmUi->pluginSelector->addPlugins(availablePluginInfo, KPluginSelector::ReadConfigFile, i18n("Available plugins"), QString(), deviceConfig);
|
|
connect(kcmUi->pluginSelector, &KPluginSelector::changed, this, &KdeConnectKcm::pluginsConfigChanged);
|
|
|
|
}
|
|
|
|
void KdeConnectKcm::requestPair()
|
|
{
|
|
if (!currentDevice) {
|
|
return;
|
|
}
|
|
|
|
kcmUi->messages->hide();
|
|
|
|
setCurrentDeviceTrusted(Requested);
|
|
|
|
currentDevice->requestPair();
|
|
|
|
}
|
|
|
|
void KdeConnectKcm::unpair()
|
|
{
|
|
if (!currentDevice) {
|
|
return;
|
|
}
|
|
|
|
setCurrentDeviceTrusted(NotTrusted);
|
|
currentDevice->unpair();
|
|
}
|
|
|
|
void KdeConnectKcm::acceptPairing()
|
|
{
|
|
if (!currentDevice) {
|
|
return;
|
|
}
|
|
|
|
currentDevice->acceptPairing();
|
|
}
|
|
|
|
void KdeConnectKcm::rejectPairing()
|
|
{
|
|
if (!currentDevice) {
|
|
return;
|
|
}
|
|
|
|
currentDevice->rejectPairing();
|
|
}
|
|
|
|
void KdeConnectKcm::pairingFailed(const QString& error)
|
|
{
|
|
if (sender() != currentDevice) return;
|
|
|
|
setCurrentDeviceTrusted(NotTrusted);
|
|
|
|
kcmUi->messages->setText(i18n("Error trying to pair: %1",error));
|
|
kcmUi->messages->animatedShow();
|
|
}
|
|
|
|
void KdeConnectKcm::trustedChanged(bool trusted)
|
|
{
|
|
DeviceDbusInterface* senderDevice = (DeviceDbusInterface*) sender();
|
|
if (senderDevice == currentDevice)
|
|
setCurrentDeviceTrusted(trusted ? Trusted : NotTrusted);
|
|
}
|
|
|
|
void KdeConnectKcm::setCurrentDeviceTrusted(KdeConnectKcm::TrustStatus trusted)
|
|
{
|
|
kcmUi->accept_button->setVisible(trusted == RequestedByPeer);
|
|
kcmUi->reject_button->setVisible(trusted == RequestedByPeer);
|
|
kcmUi->pair_button->setVisible(trusted == NotTrusted);
|
|
kcmUi->unpair_button->setVisible(trusted == Trusted);
|
|
kcmUi->progressBar->setVisible(trusted == Requested);
|
|
kcmUi->ping_button->setVisible(trusted == Trusted);
|
|
switch (trusted) {
|
|
case Trusted:
|
|
kcmUi->status_label->setText(i18n("(paired)"));
|
|
break;
|
|
case NotTrusted:
|
|
kcmUi->status_label->setText(i18n("(not paired)"));
|
|
break;
|
|
case RequestedByPeer:
|
|
kcmUi->status_label->setText(i18n("(incoming pair request)"));
|
|
break;
|
|
case Requested:
|
|
kcmUi->status_label->setText(i18n("(pairing requested)"));
|
|
break;
|
|
}
|
|
}
|
|
|
|
void KdeConnectKcm::pluginsConfigChanged()
|
|
{
|
|
//Store previous selection
|
|
if (!currentDevice) return;
|
|
|
|
DeviceDbusInterface* auxCurrentDevice = currentDevice;
|
|
currentDevice = nullptr; //HACK to avoid infinite recursion (for some reason calling save on pluginselector emits changed)
|
|
kcmUi->pluginSelector->save();
|
|
currentDevice = auxCurrentDevice;
|
|
|
|
currentDevice->reloadPlugins();
|
|
}
|
|
|
|
void KdeConnectKcm::save()
|
|
{
|
|
pluginsConfigChanged();
|
|
KCModule::save();
|
|
}
|
|
|
|
void KdeConnectKcm::sendPing()
|
|
{
|
|
if (!currentDevice) return;
|
|
currentDevice->pluginCall(QStringLiteral("ping"), QStringLiteral("sendPing"));
|
|
}
|
|
|
|
QSize KdeConnectKcm::sizeHint() const
|
|
{
|
|
return QSize(890,550); //Golden ratio :D
|
|
}
|
|
|
|
QSize KdeConnectKcm::minimumSizeHint() const
|
|
{
|
|
return QSize(500,300);
|
|
}
|
|
|
|
#include "kcm.moc"
|
|
#include "moc_kcm.cpp"
|