File indexing completed on 2024-05-19 16:31: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 <KAboutData>
0016 
0017 #include <KLocalizedString>
0018 #include <KPluginFactory>
0019 
0020 #include "usbdevices.h"
0021 
0022 K_PLUGIN_CLASS_WITH_JSON(USBViewer, "kcmusb.json")
0023 
0024 USBViewer::USBViewer(QWidget *parent, const QVariantList &)
0025     : KCModule(parent)
0026 {
0027     setQuickHelp(
0028         i18n("This module allows you to see"
0029              " the devices attached to your USB bus(es)."));
0030 
0031     QHBoxLayout *mainLayout = new QHBoxLayout(this);
0032     mainLayout->setContentsMargins(0, 0, 0, 0);
0033     mainLayout->setSpacing(0);
0034 
0035     QSplitter *splitter = new QSplitter(this);
0036     splitter->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
0037     mainLayout->addWidget(splitter);
0038 
0039     _devices = new QTreeWidget(splitter);
0040 
0041     QStringList headers;
0042     headers << i18n("Device");
0043     _devices->setHeaderLabels(headers);
0044     _devices->setRootIsDecorated(true);
0045     _devices->header()->hide();
0046     //_devices->setColumnWidthMode(0, Q3ListView::Maximum);
0047 
0048     QList<int> sizes;
0049     sizes.append(200);
0050     splitter->setSizes(sizes);
0051 
0052     _details = new QTextEdit(splitter);
0053     _details->setReadOnly(true);
0054 
0055     QTimer *refreshTimer = new QTimer(this);
0056     // 1 sec seems to be a good compromise between latency and polling load.
0057     refreshTimer->start(1000);
0058 
0059     connect(refreshTimer, &QTimer::timeout, this, &USBViewer::refresh);
0060     connect(_devices, &QTreeWidget::currentItemChanged, this, &USBViewer::selectionChanged);
0061 
0062     KAboutData *about =
0063         new KAboutData(i18n("kcmusb"), i18n("USB Devices"), QString(), QString(), KAboutLicense::GPL, i18n("(c) 2001 Matthias Hoelzer-Kluepfel"));
0064 
0065     about->addAuthor(i18n("Matthias Hoelzer-Kluepfel"), QString(), QStringLiteral("mhk@kde.org"));
0066     about->addCredit(i18n("Leo Savernik"), i18n("Live Monitoring of USB Bus"), QStringLiteral("l.savernik@aon.at"));
0067     setAboutData(about);
0068 }
0069 
0070 USBViewer::~USBViewer()
0071 {
0072     USBDevice::clear();
0073 }
0074 
0075 void USBViewer::load()
0076 {
0077     _items.clear();
0078     _devices->clear();
0079 
0080     refresh();
0081 }
0082 
0083 static quint32 key(USBDevice &dev)
0084 {
0085     return dev.bus() * 256 + dev.device();
0086 }
0087 
0088 static quint32 key_parent(USBDevice &dev)
0089 {
0090     return dev.bus() * 256 + dev.parent();
0091 }
0092 
0093 static void delete_recursive(QTreeWidgetItem *item, const QMap<int, QTreeWidgetItem *> &new_items)
0094 {
0095     if (!item)
0096         return;
0097 
0098     QTreeWidgetItemIterator it(item, QTreeWidgetItemIterator::All);
0099     while (*it != nullptr) {
0100         QTreeWidgetItem *currentItem = *it;
0101         if (new_items.contains(currentItem->text(1).toUInt()) == false) {
0102             delete_recursive(currentItem->child(0), new_items);
0103             delete currentItem;
0104         }
0105         ++it;
0106     }
0107 }
0108 
0109 void USBViewer::refresh()
0110 {
0111     QMap<int, QTreeWidgetItem *> new_items;
0112 
0113     if (!USBDevice::load())
0114         return;
0115 
0116     int level = 0;
0117     bool found = true;
0118 
0119     while (found) {
0120         found = false;
0121 
0122         foreach (USBDevice *usbDevice, USBDevice::devices()) {
0123             if (usbDevice->level() == level) {
0124                 quint32 k = key(*usbDevice);
0125                 if (level == 0) {
0126                     QTreeWidgetItem *item = _items.value(k);
0127                     if (!item) {
0128                         QStringList itemContent;
0129                         itemContent << usbDevice->product() << QString::number(k);
0130                         item = new QTreeWidgetItem(_devices, itemContent);
0131                     }
0132                     new_items.insert(k, item);
0133                     found = true;
0134                 } else {
0135                     QTreeWidgetItem *parent = new_items.value(key_parent(*usbDevice));
0136                     if (parent) {
0137                         QTreeWidgetItem *item = _items.value(k);
0138 
0139                         if (!item) {
0140                             QStringList itemContent;
0141                             itemContent << usbDevice->product() << QString::number(k);
0142                             item = new QTreeWidgetItem(parent, itemContent);
0143                         }
0144                         new_items.insert(k, item);
0145                         parent->setExpanded(true);
0146                         found = true;
0147                     }
0148                 }
0149             }
0150         }
0151 
0152         ++level;
0153     }
0154 
0155     // recursive delete all items not in new_items
0156     delete_recursive(_devices->topLevelItem(0), new_items);
0157 
0158     _items = new_items;
0159 
0160     if (_devices->selectedItems().isEmpty() == true)
0161         selectionChanged(_devices->topLevelItem(0));
0162 }
0163 
0164 void USBViewer::selectionChanged(QTreeWidgetItem *item)
0165 {
0166     if (item) {
0167         quint32 busdev = item->text(1).toUInt();
0168         USBDevice *dev = USBDevice::find(busdev >> 8, busdev & 255);
0169         if (dev) {
0170             _details->setHtml(dev->dump());
0171             return;
0172         }
0173     }
0174     _details->clear();
0175 }
0176 
0177 #include "kcmusb.moc"