File indexing completed on 2024-04-28 08:49:05
0001 /** 0002 * SPDX-FileCopyrightText: 2013 Albert Vaca <albertvaka@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #include "kcm.h" 0008 0009 #include <KAboutData> 0010 #include <KColorSchemeManager> 0011 #include <KConfigGroup> 0012 #include <KLocalizedString> 0013 #include <KPluginFactory> 0014 #include <KPluginMetaData> 0015 #include <kcmutils_version.h> 0016 0017 #include "dbushelpers.h" 0018 #include "dbusinterfaces.h" 0019 #include "devicesmodel.h" 0020 #include "devicessortproxymodel.h" 0021 #include "kdeconnect-version.h" 0022 0023 K_PLUGIN_CLASS_WITH_JSON(KdeConnectKcm, "kcm_kdeconnect.json") 0024 0025 KdeConnectKcm::KdeConnectKcm(QObject *parent, const QVariantList &args) 0026 : KCModule(qobject_cast<QWidget *>(parent)) 0027 , daemon(new DaemonDbusInterface(this)) 0028 , devicesModel(new DevicesModel(this)) 0029 , currentDevice(nullptr) 0030 { 0031 #ifdef Q_OS_WIN 0032 KColorSchemeManager manager; 0033 QApplication::setStyle(QStringLiteral("breeze")); 0034 #endif 0035 0036 kcmUi.setupUi(widget()); 0037 0038 sortProxyModel = new DevicesSortProxyModel(devicesModel); 0039 0040 kcmUi.deviceList->setModel(sortProxyModel); 0041 0042 kcmUi.deviceInfo->setVisible(false); 0043 kcmUi.progressBar->setVisible(false); 0044 kcmUi.messages->setVisible(false); 0045 0046 // Workaround: If we set this directly (or if we set it in the .ui file), the layout breaks 0047 kcmUi.noDeviceLinks->setWordWrap(false); 0048 QTimer::singleShot(0, this, [this] { 0049 kcmUi.noDeviceLinks->setWordWrap(true); 0050 }); 0051 0052 setWhenAvailable( 0053 daemon->announcedName(), 0054 [this](const QString &announcedName) { 0055 kcmUi.rename_label->setText(announcedName); 0056 kcmUi.rename_edit->setText(announcedName); 0057 }, 0058 this); 0059 connect(daemon, &DaemonDbusInterface::announcedNameChanged, kcmUi.rename_edit, &QLineEdit::setText); 0060 connect(daemon, &DaemonDbusInterface::announcedNameChanged, kcmUi.rename_label, &QLabel::setText); 0061 setRenameMode(false); 0062 0063 setButtons(KCModule::Help | KCModule::NoAdditionalButton); 0064 0065 connect(devicesModel, &QAbstractItemModel::dataChanged, this, &KdeConnectKcm::resetSelection); 0066 connect(kcmUi.deviceList->selectionModel(), &QItemSelectionModel::currentChanged, this, &KdeConnectKcm::deviceSelected); 0067 connect(kcmUi.accept_button, &QAbstractButton::clicked, this, &KdeConnectKcm::acceptPairing); 0068 connect(kcmUi.reject_button, &QAbstractButton::clicked, this, &KdeConnectKcm::cancelPairing); 0069 connect(kcmUi.cancel_button, &QAbstractButton::clicked, this, &KdeConnectKcm::cancelPairing); 0070 connect(kcmUi.pair_button, &QAbstractButton::clicked, this, &KdeConnectKcm::requestPairing); 0071 connect(kcmUi.unpair_button, &QAbstractButton::clicked, this, &KdeConnectKcm::unpair); 0072 connect(kcmUi.ping_button, &QAbstractButton::clicked, this, &KdeConnectKcm::sendPing); 0073 connect(kcmUi.refresh_button, &QAbstractButton::clicked, this, &KdeConnectKcm::refresh); 0074 connect(kcmUi.rename_edit, &QLineEdit::returnPressed, this, &KdeConnectKcm::renameDone); 0075 connect(kcmUi.renameDone_button, &QAbstractButton::clicked, this, &KdeConnectKcm::renameDone); 0076 connect(kcmUi.renameShow_button, &QAbstractButton::clicked, this, &KdeConnectKcm::renameShow); 0077 connect(kcmUi.pluginSelector, &KPluginWidget::changed, this, &KdeConnectKcm::pluginsConfigChanged); 0078 0079 if (!args.isEmpty() && args.first().type() == QVariant::String) { 0080 const QString input = args.first().toString(); 0081 const auto colonIdx = input.indexOf(QLatin1Char(':')); 0082 const QString deviceId = input.left(colonIdx); 0083 const QString pluginCM = colonIdx < 0 ? QString() : input.mid(colonIdx + 1); 0084 0085 connect(devicesModel, &DevicesModel::rowsInserted, this, [this, deviceId, pluginCM]() { 0086 auto row = devicesModel->rowForDevice(deviceId); 0087 if (row >= 0) { 0088 const QModelIndex idx = sortProxyModel->mapFromSource(devicesModel->index(row)); 0089 kcmUi.deviceList->selectionModel()->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect); 0090 } 0091 if (!pluginCM.isEmpty()) { 0092 kcmUi.pluginSelector->showConfiguration(pluginCM); 0093 } 0094 disconnect(devicesModel, &DevicesModel::rowsInserted, this, nullptr); 0095 }); 0096 } 0097 } 0098 0099 void KdeConnectKcm::renameShow() 0100 { 0101 setRenameMode(true); 0102 } 0103 0104 void KdeConnectKcm::renameDone() 0105 { 0106 QString newName = kcmUi.rename_edit->text(); 0107 if (newName.isEmpty()) { 0108 // Rollback changes 0109 kcmUi.rename_edit->setText(kcmUi.rename_label->text()); 0110 } else { 0111 kcmUi.rename_label->setText(newName); 0112 daemon->setAnnouncedName(newName); 0113 } 0114 setRenameMode(false); 0115 } 0116 0117 void KdeConnectKcm::setRenameMode(bool b) 0118 { 0119 kcmUi.renameDone_button->setVisible(b); 0120 kcmUi.rename_edit->setVisible(b); 0121 kcmUi.renameShow_button->setVisible(!b); 0122 kcmUi.rename_label->setVisible(!b); 0123 } 0124 0125 KdeConnectKcm::~KdeConnectKcm() 0126 { 0127 } 0128 0129 void KdeConnectKcm::refresh() 0130 { 0131 daemon->forceOnNetworkChange(); 0132 } 0133 0134 void KdeConnectKcm::resetSelection() 0135 { 0136 if (!currentDevice) { 0137 return; 0138 } 0139 kcmUi.deviceList->selectionModel()->setCurrentIndex(sortProxyModel->mapFromSource(currentIndex), QItemSelectionModel::ClearAndSelect); 0140 } 0141 0142 void KdeConnectKcm::deviceSelected(const QModelIndex ¤t) 0143 { 0144 if (currentDevice) { 0145 disconnect(currentDevice, nullptr, this, nullptr); 0146 } 0147 0148 if (!current.isValid()) { 0149 currentDevice = nullptr; 0150 kcmUi.deviceInfo->setVisible(false); 0151 return; 0152 } 0153 0154 currentIndex = sortProxyModel->mapToSource(current); 0155 currentDevice = devicesModel->getDevice(currentIndex.row()); 0156 0157 kcmUi.noDevicePlaceholder->setVisible(false); 0158 bool valid = (currentDevice != nullptr && currentDevice->isValid()); 0159 kcmUi.deviceInfo->setVisible(valid); 0160 if (!valid) { 0161 return; 0162 } 0163 0164 kcmUi.messages->setVisible(false); 0165 resetDeviceView(); 0166 0167 connect(currentDevice, &DeviceDbusInterface::pluginsChanged, this, &KdeConnectKcm::resetCurrentDevice); 0168 connect(currentDevice, &DeviceDbusInterface::pairingFailed, this, &KdeConnectKcm::pairingFailed); 0169 connect(currentDevice, &DeviceDbusInterface::pairStateChanged, this, &KdeConnectKcm::setCurrentDevicePairState); 0170 } 0171 0172 void KdeConnectKcm::resetCurrentDevice() 0173 { 0174 const QStringList supportedPluginNames = currentDevice->supportedPlugins(); 0175 0176 if (m_oldSupportedPluginNames != supportedPluginNames) { 0177 resetDeviceView(); 0178 } 0179 } 0180 0181 void KdeConnectKcm::resetDeviceView() 0182 { 0183 kcmUi.verificationKey->setText(i18n("Key: %1", QString::fromUtf8(currentDevice->verificationKey()))); 0184 0185 kcmUi.name_label->setText(currentDevice->name()); 0186 setWhenAvailable( 0187 currentDevice->pairStateAsInt(), 0188 [this](int pairStateAsInt) { 0189 setCurrentDevicePairState(pairStateAsInt); 0190 }, 0191 this); 0192 0193 const QVector<KPluginMetaData> pluginInfo = KPluginMetaData::findPlugins(QStringLiteral("kdeconnect")); 0194 QVector<KPluginMetaData> availablePluginInfo; 0195 0196 m_oldSupportedPluginNames = currentDevice->supportedPlugins(); 0197 for (auto it = pluginInfo.cbegin(), itEnd = pluginInfo.cend(); it != itEnd; ++it) { 0198 if (m_oldSupportedPluginNames.contains(it->pluginId())) { 0199 availablePluginInfo.append(*it); 0200 } 0201 } 0202 0203 KSharedConfigPtr deviceConfig = KSharedConfig::openConfig(currentDevice->pluginsConfigFile()); 0204 kcmUi.pluginSelector->clear(); 0205 kcmUi.pluginSelector->setConfigurationArguments({currentDevice->id()}); 0206 kcmUi.pluginSelector->addPlugins(availablePluginInfo, i18n("Available plugins")); 0207 kcmUi.pluginSelector->setConfig(deviceConfig->group(QStringLiteral("Plugins"))); 0208 } 0209 0210 void KdeConnectKcm::requestPairing() 0211 { 0212 if (!currentDevice) { 0213 return; 0214 } 0215 0216 kcmUi.messages->hide(); 0217 0218 currentDevice->requestPairing(); 0219 } 0220 0221 void KdeConnectKcm::unpair() 0222 { 0223 if (!currentDevice) { 0224 return; 0225 } 0226 0227 currentDevice->unpair(); 0228 } 0229 0230 void KdeConnectKcm::acceptPairing() 0231 { 0232 if (!currentDevice) { 0233 return; 0234 } 0235 0236 currentDevice->acceptPairing(); 0237 } 0238 0239 void KdeConnectKcm::cancelPairing() 0240 { 0241 if (!currentDevice) { 0242 return; 0243 } 0244 0245 currentDevice->cancelPairing(); 0246 } 0247 0248 void KdeConnectKcm::pairingFailed(const QString &error) 0249 { 0250 if (sender() != currentDevice) 0251 return; 0252 0253 kcmUi.messages->setText(i18n("Error trying to pair: %1", error)); 0254 kcmUi.messages->animatedShow(); 0255 } 0256 0257 void KdeConnectKcm::setCurrentDevicePairState(int pairStateAsInt) 0258 { 0259 PairState state = (PairState)pairStateAsInt; // Hack because qdbus doesn't like enums 0260 kcmUi.accept_button->setVisible(state == PairState::RequestedByPeer); 0261 kcmUi.reject_button->setVisible(state == PairState::RequestedByPeer); 0262 kcmUi.cancel_button->setVisible(state == PairState::Requested); 0263 kcmUi.pair_button->setVisible(state == PairState::NotPaired); 0264 kcmUi.unpair_button->setVisible(state == PairState::Paired); 0265 kcmUi.progressBar->setVisible(state == PairState::Requested); 0266 kcmUi.ping_button->setVisible(state == PairState::Paired); 0267 switch (state) { 0268 case PairState::Paired: 0269 kcmUi.status_label->setText(i18n("(paired)")); 0270 break; 0271 case PairState::NotPaired: 0272 kcmUi.status_label->setText(i18n("(not paired)")); 0273 break; 0274 case PairState::RequestedByPeer: 0275 kcmUi.status_label->setText(i18n("(incoming pair request)")); 0276 break; 0277 case PairState::Requested: 0278 kcmUi.status_label->setText(i18n("(pairing requested)")); 0279 break; 0280 } 0281 } 0282 0283 void KdeConnectKcm::pluginsConfigChanged(bool changed) 0284 { 0285 if (!changed) 0286 return; 0287 0288 if (!currentDevice) 0289 return; 0290 0291 kcmUi.pluginSelector->save(); 0292 currentDevice->reloadPlugins(); 0293 } 0294 0295 void KdeConnectKcm::save() 0296 { 0297 KCModule::save(); 0298 } 0299 0300 void KdeConnectKcm::sendPing() 0301 { 0302 if (!currentDevice) 0303 return; 0304 currentDevice->pluginCall(QStringLiteral("ping"), QStringLiteral("sendPing")); 0305 } 0306 0307 #include "kcm.moc" 0308 #include "moc_kcm.cpp"