File indexing completed on 2024-05-19 05:29:59

0001 /*
0002  *   SPDX-FileCopyrightText: 2001 Matthias Hoelzer-Kluepfel <mhk@caldera.de>
0003  *   SPDX-License-Identifier: GPL-2.0-or-later
0004  */
0005 #include "kcmusb.h"
0006 
0007 #include <QHBoxLayout>
0008 #include <QHeaderView>
0009 #include <QList>
0010 #include <QSplitter>
0011 #include <QTextEdit>
0012 #include <QTimer>
0013 #include <QTreeWidget>
0014 
0015 #include <KLocalizedString>
0016 #include <KPluginFactory>
0017 
0018 #include "usbdevices.h"
0019 
0020 K_PLUGIN_CLASS_WITH_JSON(USBViewer, "kcmusb.json")
0021 
0022 USBViewer::USBViewer(QObject *parent, const KPluginMetaData &data)
0023     : KCModule(parent, data)
0024 {
0025     QHBoxLayout *mainLayout = new QHBoxLayout(widget());
0026     mainLayout->setContentsMargins(0, 0, 0, 0);
0027     mainLayout->setSpacing(0);
0028 
0029     QSplitter *splitter = new QSplitter(widget());
0030     splitter->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
0031     mainLayout->addWidget(splitter);
0032 
0033     _devices = new QTreeWidget(splitter);
0034 
0035     QStringList headers{i18n("Device")};
0036     _devices->setHeaderLabels(headers);
0037     _devices->setRootIsDecorated(true);
0038     _devices->header()->hide();
0039     //_devices->setColumnWidthMode(0, Q3ListView::Maximum);
0040 
0041     QList<int> sizes;
0042     sizes.append(200);
0043     splitter->setSizes(sizes);
0044 
0045     _details = new QTextEdit(splitter);
0046     _details->setReadOnly(true);
0047 
0048     QTimer *refreshTimer = new QTimer(this);
0049     // 1 sec seems to be a good compromise between latency and polling load.
0050     refreshTimer->start(1000);
0051 
0052     connect(refreshTimer, &QTimer::timeout, this, &USBViewer::refresh);
0053     connect(_devices, &QTreeWidget::currentItemChanged, this, &USBViewer::selectionChanged);
0054 }
0055 
0056 USBViewer::~USBViewer()
0057 {
0058     USBDevice::clear();
0059 }
0060 
0061 void USBViewer::load()
0062 {
0063     _items.clear();
0064     _devices->clear();
0065 
0066     refresh();
0067 }
0068 
0069 static quint32 key(USBDevice &dev)
0070 {
0071     return dev.bus() * 256 + dev.device();
0072 }
0073 
0074 static quint32 key_parent(USBDevice &dev)
0075 {
0076     return dev.bus() * 256 + dev.parent();
0077 }
0078 
0079 static void delete_recursive(QTreeWidgetItem *item, const QMap<int, QTreeWidgetItem *> &new_items)
0080 {
0081     if (!item)
0082         return;
0083 
0084     QTreeWidgetItemIterator it(item, QTreeWidgetItemIterator::All);
0085     while (*it != nullptr) {
0086         QTreeWidgetItem *currentItem = *it;
0087         if (new_items.contains(currentItem->text(1).toUInt()) == false) {
0088             delete_recursive(currentItem->child(0), new_items);
0089             delete currentItem;
0090         }
0091         ++it;
0092     }
0093 }
0094 
0095 void USBViewer::refresh()
0096 {
0097     QMap<int, QTreeWidgetItem *> new_items;
0098 
0099     if (!USBDevice::load())
0100         return;
0101 
0102     int level = 0;
0103     bool found = true;
0104 
0105     while (found) {
0106         found = false;
0107 
0108         const auto devices = USBDevice::devices();
0109         for (USBDevice *usbDevice : devices) {
0110             if (usbDevice->level() == level) {
0111                 quint32 k = key(*usbDevice);
0112                 if (level == 0) {
0113                     QTreeWidgetItem *item = _items.value(k);
0114                     if (!item) {
0115                         QStringList itemContent;
0116                         itemContent << usbDevice->product() << QString::number(k);
0117                         item = new QTreeWidgetItem(_devices, itemContent);
0118                     }
0119                     new_items.insert(k, item);
0120                     found = true;
0121                 } else {
0122                     QTreeWidgetItem *parent = new_items.value(key_parent(*usbDevice));
0123                     if (parent) {
0124                         QTreeWidgetItem *item = _items.value(k);
0125 
0126                         if (!item) {
0127                             QStringList itemContent;
0128                             itemContent << usbDevice->product() << QString::number(k);
0129                             item = new QTreeWidgetItem(parent, itemContent);
0130                         }
0131                         new_items.insert(k, item);
0132                         parent->setExpanded(true);
0133                         found = true;
0134                     }
0135                 }
0136             }
0137         }
0138 
0139         ++level;
0140     }
0141 
0142     // recursive delete all items not in new_items
0143     delete_recursive(_devices->topLevelItem(0), new_items);
0144 
0145     _items = new_items;
0146 
0147     if (_devices->selectedItems().isEmpty() == true)
0148         selectionChanged(_devices->topLevelItem(0));
0149 }
0150 
0151 void USBViewer::selectionChanged(QTreeWidgetItem *item)
0152 {
0153     if (item) {
0154         quint32 busdev = item->text(1).toUInt();
0155         USBDevice *dev = USBDevice::find(busdev >> 8, busdev & 255);
0156         if (dev) {
0157             _details->setHtml(dev->dump());
0158             return;
0159         }
0160     }
0161     _details->clear();
0162 }
0163 
0164 #include "kcmusb.moc"
0165 
0166 #include "moc_kcmusb.cpp"