diff --git a/add-printer/DevicesModel.cpp b/add-printer/DevicesModel.cpp index 74e0838..4ecf6ea 100644 --- a/add-printer/DevicesModel.cpp +++ b/add-printer/DevicesModel.cpp @@ -1,382 +1,393 @@ /*************************************************************************** * Copyright (C) 2010-2018 by Daniel Nicoletti * * dantti12@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; see the file COPYING. If not, write to * * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "DevicesModel.h" #include #include #include #include #include #include #include DevicesModel::DevicesModel(QObject *parent) : QStandardItemModel(parent) , m_request(0) , m_rx(QLatin1String("[a-z]+://.*")) , m_blacklistedURIs({ QLatin1String("hp"), QLatin1String("hpfax"), QLatin1String("hal"), QLatin1String("beh"), QLatin1String("scsi"), QLatin1String("http"), QLatin1String("delete") }) { qDBusRegisterMetaType(); qDBusRegisterMetaType(); // Adds the other device which is meant for manual URI input insertDevice(QLatin1String("other"), QString(), i18nc("@item", "Manual URI"), QString(), QLatin1String("other"), QString()); } void DevicesModel::update() { if (m_request) { return; } // clear the model to don't duplicate items if (rowCount()) { removeRows(1, rowCount() - 1); } m_request = new KCupsRequest; connect(m_request, &KCupsRequest::device, this, &DevicesModel::gotDevice); connect(m_request, &KCupsRequest::finished, this, &DevicesModel::finished); // Get devices with 5 seconds of timeout m_request->getDevices(10); } void DevicesModel::gotDevice(const QString &device_class, const QString &device_id, const QString &device_info, const QString &device_make_and_model, const QString &device_uri, const QString &device_location) { // "direct" qDebug() << device_class; // "MFG:Samsung;CMD:GDI;MDL:SCX-4200 Series;CLS:PRINTER;MODE:PCL;STATUS:IDLE;" qDebug() << device_id; // "Samsung SCX-4200 Series" qDebug() << device_info; // "Samsung SCX-4200 Series" qDebug() << device_make_and_model; // "usb://Samsung/SCX-4200%20Series" qDebug() << device_uri; // "" qDebug() << device_location; if (m_blacklistedURIs.contains(device_uri)) { // ignore black listed uri's return; } // For the protocols, not real devices if (device_id.isEmpty() && device_make_and_model == QLatin1String("Unknown")) { insertDevice(device_class, device_id, device_info, device_make_and_model, device_uri, device_location); } else { // Map the devices so later we try to group them const MapSS mapSS({ {KCUPS_DEVICE_CLASS, device_class}, {KCUPS_DEVICE_ID, device_id}, {KCUPS_DEVICE_INFO, device_info}, {KCUPS_DEVICE_MAKE_AND_MODEL, device_make_and_model}, {KCUPS_DEVICE_LOCATION, device_location} }); m_mappedDevices[device_uri] = mapSS; } } void DevicesModel::finished() { bool hasError = m_request->hasError(); if (hasError) { emit errorMessage(i18n("Failed to get a list of devices: '%1'", m_request->errorMsg())); } m_request->deleteLater(); m_request = 0; if (hasError || m_mappedDevices.isEmpty()) { emit loaded(); return; } QDBusMessage message; message = QDBusMessage::createMethodCall(QLatin1String("org.fedoraproject.Config.Printing"), QLatin1String("/org/fedoraproject/Config/Printing"), QLatin1String("org.fedoraproject.Config.Printing"), QLatin1String("GroupPhysicalDevices")); message << QVariant::fromValue(m_mappedDevices); QDBusConnection::sessionBus().callWithCallback(message, this, SLOT(getGroupedDevicesSuccess(QDBusMessage)), SLOT(getGroupedDevicesFailed(QDBusError,QDBusMessage))); } void DevicesModel::insertDevice(const QString &device_class, const QString &device_id, const QString &device_info, const QString &device_make_and_model, const QString &device_uri, const QString &device_location, const QStringList &grouped_uris) { QStandardItem *stdItem; stdItem = createItem(device_class, device_id, device_info, device_make_and_model, device_uri, device_location, !grouped_uris.isEmpty()); if (!grouped_uris.isEmpty()) { stdItem->setData(grouped_uris, DeviceUris); } } void DevicesModel::insertDevice(const QString &device_class, const QString &device_id, const QString &device_info, const QString &device_make_and_model, const QString &device_uri, const QString &device_location, const KCupsPrinters &grouped_printers) { QStandardItem *stdItem; stdItem = createItem(device_class, device_id, device_info, device_make_and_model, device_uri, device_location, !grouped_printers.isEmpty()); if (!grouped_printers.isEmpty()) { stdItem->setData(qVariantFromValue(grouped_printers), DeviceUris); } } QStandardItem *DevicesModel::createItem(const QString &device_class, const QString &device_id, const QString &device_info, const QString &device_make_and_model, const QString &device_uri, const QString &device_location, bool grouped) { // "direct" qDebug() << device_class; // "MFG:Samsung;CMD:GDI;MDL:SCX-4200 Series;CLS:PRINTER;MODE:PCL;STATUS:IDLE;" qDebug() << device_id; // "Samsung SCX-4200 Series" qDebug() << device_info; // "Samsung SCX-4200 Series" qDebug() << device_make_and_model; // "usb://Samsung/SCX-4200%20Series" qDebug() << device_uri; // "" qDebug() << device_location; Kind kind; // Store the kind of the device if (device_class == QLatin1String("network")) { if (m_rx.indexIn(device_uri) > -1) { kind = Networked; } else { // other network devices looks like // just "http" kind = OtherNetworked; } } else if (device_class == QLatin1String("other") && device_uri == QLatin1String("other")) { kind = Other; } else { // If device class is not network assume local kind = Local; } QString location; if (device_location.isEmpty() && kind == Local) { location = QHostInfo::localHostName(); } else { location = device_location; } QString text; if (!device_make_and_model.isEmpty() && !grouped && device_make_and_model.compare(QLatin1String("unknown"), Qt::CaseInsensitive)) { text = device_info + QLatin1String(" (") + device_make_and_model + QLatin1Char(')'); } else { text = device_info; } QString toolTip; if (!grouped) { if (device_uri.startsWith(QLatin1String("parallel"))) { toolTip = i18nc("@info:tooltip", "A printer connected to the parallel port"); } else if (device_uri.startsWith(QLatin1String("usb"))) { toolTip = i18nc("@info:tooltip", "A printer connected to a USB port"); } else if (device_uri.startsWith(QLatin1String("bluetooth"))) { toolTip = i18nc("@info:tooltip", "A printer connected via Bluetooth"); } else if (device_uri.startsWith(QLatin1String("hal"))) { toolTip = i18nc("@info:tooltip", "Local printer detected by the " "Hardware Abstraction Layer (HAL)"); } else if (device_uri.startsWith(QLatin1String("hp"))) { toolTip = i18nc("@info:tooltip", "HPLIP software driving a printer, " "or the printer function of a multi-function device"); } else if (device_uri.startsWith(QLatin1String("hpfax"))) { toolTip = i18nc("@info:tooltip", "HPLIP software driving a fax machine, " "or the fax function of a multi-function device"); } else if (device_uri.startsWith(QLatin1String("dnssd")) || device_uri.startsWith(QLatin1String("mdns"))) { toolTip = i18nc("@info:tooltip", "Remote CUPS printer via DNS-SD"); } } auto stdItem = new QStandardItem; stdItem->setText(text); stdItem->setToolTip(toolTip); stdItem->setData(device_class, DeviceClass); stdItem->setData(device_id, DeviceId); stdItem->setData(device_info, DeviceInfo); stdItem->setData(device_uri, DeviceUri); stdItem->setData(device_make_and_model, DeviceMakeAndModel); stdItem->setData(device_location, DeviceLocation); // Find the proper category to our item QStandardItem *catItem; switch (kind) { case Networked: - catItem = findCreateCategory(i18nc("@item", "Discovered Network Printers")); + catItem = findCreateCategory(i18nc("@item", "Discovered Network Printers"), kind); catItem->appendRow(stdItem); break; case OtherNetworked: - catItem = findCreateCategory(i18nc("@item", "Other Network Printers")); + catItem = findCreateCategory(i18nc("@item", "Other Network Printers"), kind); catItem->appendRow(stdItem); break; case Local: - catItem = findCreateCategory(i18nc("@item", "Local Printers")); + catItem = findCreateCategory(i18nc("@item", "Local Printers"), kind); catItem->appendRow(stdItem); break; default: + stdItem->setData(kind, Qt::UserRole); appendRow(stdItem); } return stdItem; } void DevicesModel::getGroupedDevicesSuccess(const QDBusMessage &message) { if (message.type() == QDBusMessage::ReplyMessage && message.arguments().size() == 1) { const auto argument = message.arguments().first().value(); const auto groupeDevices = qdbus_cast >(argument); for (const QStringList &list : groupeDevices) { if (list.isEmpty()) { continue; } const QString uri = list.first(); const MapSS device = m_mappedDevices[uri]; insertDevice(device[KCUPS_DEVICE_CLASS], device[KCUPS_DEVICE_ID], device[KCUPS_DEVICE_INFO], device[KCUPS_DEVICE_MAKE_AND_MODEL], uri, device[KCUPS_DEVICE_LOCATION], list.size() > 1 ? list : QStringList()); } } else { qWarning() << "Unexpected message" << message; groupedDevicesFallback(); } emit loaded(); } void DevicesModel::getGroupedDevicesFailed(const QDBusError &error, const QDBusMessage &message) { qWarning() << error << message; groupedDevicesFallback(); emit errorMessage(i18n("Failed to group devices: '%1'",error.message())); emit loaded(); } void DevicesModel::groupedDevicesFallback() { MapSMapSS::const_iterator i = m_mappedDevices.constBegin(); while (i != m_mappedDevices.constEnd()) { const MapSS device = i.value(); insertDevice(device[KCUPS_DEVICE_CLASS], device[KCUPS_DEVICE_ID], device[KCUPS_DEVICE_INFO], device[KCUPS_DEVICE_MAKE_AND_MODEL], i.key(), device[KCUPS_DEVICE_LOCATION]); ++i; } } -QStandardItem* DevicesModel::findCreateCategory(const QString &category) +QStandardItem* DevicesModel::findCreateCategory(const QString &category, Kind kind) { for (int i = 0; i < rowCount(); ++i) { QStandardItem *catItem = item(i); - if (catItem->text() == category) { + if (catItem->data(Qt::UserRole).toInt() == kind) { return catItem; } } + int pos = 0; + for (int i = 0; i < rowCount(); ++i, ++pos) { + QStandardItem *catItem = item(i); + if (catItem->data(Qt::UserRole).toInt() > kind) { + pos = i; + break; + } + } + auto catItem = new QStandardItem(category); QFont font = catItem->font(); font.setBold(true); catItem->setFont(font); + catItem->setData(kind, Qt::UserRole); catItem->setFlags(Qt::ItemIsEnabled); - appendRow(catItem); + insertRow(pos, catItem); // Emit the parent so the view expand the item emit parentAdded(indexFromItem(catItem)); return catItem; } #include "moc_DevicesModel.cpp" diff --git a/add-printer/DevicesModel.h b/add-printer/DevicesModel.h index ab38642..c55983b 100644 --- a/add-printer/DevicesModel.h +++ b/add-printer/DevicesModel.h @@ -1,110 +1,111 @@ /*************************************************************************** * Copyright (C) 2010 by Daniel Nicoletti * * dantti12@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; see the file COPYING. If not, write to * * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301, USA. * ***************************************************************************/ #ifndef DEVICES_MODEL_H #define DEVICES_MODEL_H #include #include #include typedef QMap MapSS; typedef QMap MapSMapSS; class KCupsRequest; class DevicesModel : public QStandardItemModel { Q_OBJECT - Q_ENUMS(Role) public: enum Role { DeviceClass = Qt::UserRole + 2, DeviceId, DeviceInfo, DeviceMakeAndModel, DeviceUri, DeviceUris, DeviceLocation }; + Q_ENUM(Role) enum Kind { + Other, Local, Networked, - OtherNetworked, - Other + OtherNetworked }; + Q_ENUM(Kind) explicit DevicesModel(QObject *parent = 0); signals: void loaded(); void parentAdded(const QModelIndex &index); void errorMessage(const QString &message); public slots: void update(); void insertDevice(const QString &device_class, const QString &device_id, const QString &device_info, const QString &device_make_and_model, const QString &device_uri, const QString &device_location, const QStringList &grouped_uris = QStringList()); void insertDevice(const QString &device_class, const QString &device_id, const QString &device_info, const QString &device_make_and_model, const QString &device_uri, const QString &device_location, const KCupsPrinters &grouped_printers); private slots: QStandardItem* createItem(const QString &device_class, const QString &device_id, const QString &device_info, const QString &device_make_and_model, const QString &device_uri, const QString &device_location, bool grouped); void gotDevice(const QString &device_class, const QString &device_id, const QString &device_info, const QString &device_make_and_model, const QString &device_uri, const QString &device_location); void finished(); void getGroupedDevicesSuccess(const QDBusMessage &message); void getGroupedDevicesFailed(const QDBusError &error, const QDBusMessage &message); void groupedDevicesFallback(); private: - QStandardItem *findCreateCategory(const QString &category); + QStandardItem *findCreateCategory(const QString &category, Kind kind); KCupsRequest *m_request; MapSMapSS m_mappedDevices; QRegExp m_rx; QStringList m_blacklistedURIs; }; Q_DECLARE_METATYPE(MapSS) Q_DECLARE_METATYPE(MapSMapSS) #endif