File indexing completed on 2024-05-12 05:35:54

0001 /*
0002     SPDX-FileCopyrightText: 2009-2010 Trever Fischer <tdfischer@fedoraproject.org>
0003     SPDX-FileCopyrightText: 2015 Kai UWe Broulik <kde@privat.broulik.de>
0004     SPDX-FileCopyrightText: 2021 Ismael Asensio <isma.af@gmail.com>
0005 
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 #include "DeviceAutomounterKCM.h"
0010 #include <QDBusConnection>
0011 #include <QDBusMessage>
0012 #include <QItemSelectionModel>
0013 #include <QStandardItem>
0014 #include <QStandardItemModel>
0015 #include <kconfigwidgets_version.h>
0016 
0017 #include <KAboutData>
0018 #include <KConfigGroup>
0019 #include <Solid/DeviceNotifier>
0020 #include <Solid/StorageVolume>
0021 
0022 #include <KPluginFactory>
0023 
0024 #include "AutomounterSettings.h"
0025 #include "DeviceAutomounterData.h"
0026 #include "DeviceModel.h"
0027 #include "LayoutSettings.h"
0028 
0029 K_PLUGIN_FACTORY_WITH_JSON(DeviceAutomounterKCMFactory, "device_automounter_kcm.json", registerPlugin<DeviceAutomounterKCM>();
0030                            registerPlugin<DeviceAutomounterData>();)
0031 
0032 DeviceAutomounterKCM::DeviceAutomounterKCM(QObject *parent, const KPluginMetaData &data)
0033     : KCModule(parent, data)
0034     , m_settings(new AutomounterSettings(widget()))
0035     , m_devices(new DeviceModel(m_settings, this))
0036 {
0037     setupUi(widget());
0038 
0039     addConfig(m_settings, widget());
0040 
0041     deviceView->setModel(m_devices);
0042 
0043     deviceView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
0044     deviceView->header()->setSectionResizeMode(0, QHeaderView::Stretch);
0045 
0046     connect(kcfg_AutomountUnknownDevices, &QCheckBox::stateChanged, this, [this](int state) {
0047         m_devices->setAutomaticUnknown(state == Qt::Checked);
0048     });
0049 
0050     connect(deviceView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &DeviceAutomounterKCM::updateForgetDeviceButton);
0051     connect(forgetDevice, &QAbstractButton::clicked, this, &DeviceAutomounterKCM::forgetSelectedDevices);
0052 
0053     connect(m_devices, &QAbstractItemModel::dataChanged, this, &DeviceAutomounterKCM::updateState);
0054 }
0055 
0056 DeviceAutomounterKCM::~DeviceAutomounterKCM()
0057 {
0058     saveLayout();
0059 }
0060 
0061 void DeviceAutomounterKCM::updateState()
0062 {
0063     kcfg_AutomountUnknownDevices->setEnabled(m_settings->automountOnLogin() || m_settings->automountOnPlugin());
0064 
0065     unmanagedWidgetChangeState(m_unmanagedChanges || m_settings->usrIsSaveNeeded());
0066     unmanagedWidgetDefaultState(m_settings->isDefaults());
0067 }
0068 
0069 void DeviceAutomounterKCM::updateForgetDeviceButton()
0070 {
0071     const auto selectedIndexes = deviceView->selectionModel()->selectedIndexes();
0072     const bool isAnyDettached = std::any_of(selectedIndexes.cbegin(), selectedIndexes.cend(), [](const auto &idx) {
0073         return idx.data(DeviceModel::TypeRole) == DeviceModel::Detached;
0074     });
0075     forgetDevice->setEnabled(isAnyDettached);
0076 }
0077 
0078 void DeviceAutomounterKCM::forgetSelectedDevices()
0079 {
0080     QItemSelectionModel *selected = deviceView->selectionModel();
0081     int offset = 0;
0082     while (!selected->selectedIndexes().isEmpty() && selected->selectedIndexes().size() > offset) {
0083         if (selected->selectedIndexes()[offset].data(DeviceModel::TypeRole) == DeviceModel::Attached) {
0084             offset++;
0085         } else {
0086             m_devices->forgetDevice(selected->selectedIndexes()[offset].data(DeviceModel::UdiRole).toString());
0087         }
0088     }
0089 
0090     m_unmanagedChanges = true;
0091     updateState();
0092 }
0093 
0094 void DeviceAutomounterKCM::load()
0095 {
0096     KCModule::load();
0097 
0098     m_devices->reload();
0099     loadLayout();
0100 
0101     kcfg_AutomountUnknownDevices->setChecked(m_settings->automountUnknownDevices());
0102 
0103     m_unmanagedChanges = false;
0104     updateState();
0105 }
0106 
0107 void DeviceAutomounterKCM::save()
0108 {
0109     KCModule::save();
0110     saveLayout();
0111 
0112     // Housekeeping before saving.
0113     // 1. Detect if any of the automount options is set to globally enable automounting
0114     // 2. Clean-up removed setting groups
0115     bool enabled = m_settings->automountOnLogin() || m_settings->automountOnPlugin();
0116     QStringList validDevices;
0117 
0118     for (const QModelIndex &idx : {m_devices->index(DeviceModel::RowAttached, 0), m_devices->index(DeviceModel::RowDetached, 0)}) {
0119         for (int j = 0; j < m_devices->rowCount(idx); ++j) {
0120             const QString udi = m_devices->index(j, 0, idx).data(DeviceModel::UdiRole).toString();
0121             validDevices << udi;
0122             enabled |= m_settings->deviceSettings(udi)->mountOnLogin() | m_settings->deviceSettings(udi)->mountOnAttach();
0123         }
0124     }
0125 
0126     m_settings->setAutomountEnabled(enabled);
0127 
0128     const auto knownDevices = m_settings->knownDevices();
0129     for (const QString &possibleDevice : knownDevices) {
0130         if (!validDevices.contains(possibleDevice)) {
0131             m_settings->removeDeviceGroup(possibleDevice);
0132         }
0133     }
0134 
0135     m_settings->save();
0136 
0137     // Now tell kded to automatically load the module if loaded
0138     QDBusConnection dbus = QDBusConnection::sessionBus();
0139     QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.kde.kded6"),
0140                                                       QStringLiteral("/kded"),
0141                                                       QStringLiteral("org.kde.kded6"),
0142                                                       QStringLiteral("setModuleAutoloading"));
0143     msg.setArguments({QVariant(QStringLiteral("device_automounter")), QVariant(enabled)});
0144     dbus.call(msg, QDBus::NoBlock);
0145 
0146     // Load or unload right away
0147     msg = QDBusMessage::createMethodCall(QStringLiteral("org.kde.kded6"),
0148                                          QStringLiteral("/kded"),
0149                                          QStringLiteral("org.kde.kded6"),
0150                                          enabled ? QStringLiteral("loadModule") : QStringLiteral("unloadModule"));
0151     msg.setArguments({QVariant(QStringLiteral("device_automounter"))});
0152     dbus.call(msg, QDBus::NoBlock);
0153 }
0154 
0155 void DeviceAutomounterKCM::defaults()
0156 {
0157     KCModule::defaults();
0158 
0159     m_settings->setDefaults();
0160     m_devices->updateCheckedColumns();
0161 }
0162 
0163 void DeviceAutomounterKCM::saveLayout()
0164 {
0165     QList<int> widths;
0166     const int nbColumn = m_devices->columnCount();
0167     widths.reserve(nbColumn);
0168 
0169     for (int i = 0; i < nbColumn; ++i) {
0170         widths << deviceView->columnWidth(i);
0171     }
0172 
0173     LayoutSettings::setHeaderWidths(widths);
0174     LayoutSettings::setAttachedExpanded(deviceView->isExpanded(m_devices->index(DeviceModel::RowAttached, 0)));
0175     LayoutSettings::setDetachedExpanded(deviceView->isExpanded(m_devices->index(DeviceModel::RowDetached, 0)));
0176     LayoutSettings::self()->save();
0177 }
0178 
0179 void DeviceAutomounterKCM::loadLayout()
0180 {
0181     LayoutSettings::self()->load();
0182     // Reset it first, just in case there isn't any layout saved for a particular column.
0183     int nbColumn = m_devices->columnCount();
0184     for (int i = 0; i < nbColumn; ++i) {
0185         deviceView->resizeColumnToContents(i);
0186     }
0187 
0188     QList<int> widths = LayoutSettings::headerWidths();
0189     nbColumn = m_devices->columnCount();
0190     for (int i = 0; i < nbColumn && i < widths.size(); ++i) {
0191         deviceView->setColumnWidth(i, widths[i]);
0192     }
0193 
0194     deviceView->setExpanded(m_devices->index(DeviceModel::RowAttached, 0), LayoutSettings::attachedExpanded());
0195     deviceView->setExpanded(m_devices->index(DeviceModel::RowDetached, 0), LayoutSettings::detachedExpanded());
0196 }
0197 
0198 #include "DeviceAutomounterKCM.moc"