Warning, file /utilities/print-manager/add-printer/DevicesModel.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2010-2018 Daniel Nicoletti <dantti12@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "DevicesModel.h" 0008 0009 #include <KCupsRequest.h> 0010 0011 #include <KLocalizedString> 0012 #include <KMessageBox> 0013 0014 #include <QHostInfo> 0015 #include <QDBusMetaType> 0016 #include <QDBusConnection> 0017 0018 #include <QDebug> 0019 0020 DevicesModel::DevicesModel(QObject *parent) : QStandardItemModel(parent) 0021 , m_request(nullptr) 0022 , m_rx(QLatin1String("[a-z]+://.*")) 0023 , m_blacklistedURIs({ 0024 QLatin1String("hp"), 0025 QLatin1String("hpfax"), 0026 QLatin1String("hal"), 0027 QLatin1String("beh"), 0028 QLatin1String("scsi"), 0029 QLatin1String("http"), 0030 QLatin1String("delete") 0031 }) 0032 { 0033 qDBusRegisterMetaType<MapSS>(); 0034 qDBusRegisterMetaType<MapSMapSS>(); 0035 0036 // Adds the other device which is meant for manual URI input 0037 insertDevice(QLatin1String("other"), 0038 QString(), 0039 i18nc("@item", "Manual URI"), 0040 QString(), 0041 QLatin1String("other"), 0042 QString()); 0043 } 0044 0045 void DevicesModel::update() 0046 { 0047 if (m_request) { 0048 return; 0049 } 0050 0051 // clear the model to don't duplicate items 0052 if (rowCount()) { 0053 removeRows(1, rowCount() - 1); 0054 } 0055 m_request = new KCupsRequest; 0056 connect(m_request, &KCupsRequest::device, this, &DevicesModel::gotDevice); 0057 connect(m_request, &KCupsRequest::finished, this, &DevicesModel::finished); 0058 0059 // Get devices with 5 seconds of timeout 0060 m_request->getDevices(10); 0061 } 0062 0063 0064 void DevicesModel::gotDevice(const QString &device_class, 0065 const QString &device_id, 0066 const QString &device_info, 0067 const QString &device_make_and_model, 0068 const QString &device_uri, 0069 const QString &device_location) 0070 { 0071 // "direct" 0072 qDebug() << device_class; 0073 // "MFG:Samsung;CMD:GDI;MDL:SCX-4200 Series;CLS:PRINTER;MODE:PCL;STATUS:IDLE;" 0074 qDebug() << device_id; 0075 // "Samsung SCX-4200 Series" 0076 qDebug() << device_info; 0077 // "Samsung SCX-4200 Series" 0078 qDebug() << device_make_and_model; 0079 // "usb://Samsung/SCX-4200%20Series" 0080 qDebug() << device_uri; 0081 // "" 0082 qDebug() << device_location; 0083 0084 if (m_blacklistedURIs.contains(device_uri)) { 0085 // ignore black listed uri's 0086 return; 0087 } 0088 0089 // For the protocols, not real devices 0090 if (device_id.isEmpty() && 0091 device_make_and_model == QLatin1String("Unknown")) { 0092 insertDevice(device_class, 0093 device_id, 0094 device_info, 0095 device_make_and_model, 0096 device_uri, 0097 device_location); 0098 } else { 0099 // Map the devices so later we try to group them 0100 const MapSS mapSS({ 0101 {KCUPS_DEVICE_CLASS, device_class}, 0102 {KCUPS_DEVICE_ID, device_id}, 0103 {KCUPS_DEVICE_INFO, device_info}, 0104 {KCUPS_DEVICE_MAKE_AND_MODEL, device_make_and_model}, 0105 {KCUPS_DEVICE_LOCATION, device_location} 0106 }); 0107 m_mappedDevices[device_uri] = mapSS; 0108 } 0109 } 0110 0111 void DevicesModel::finished() 0112 { 0113 bool hasError = m_request->hasError(); 0114 if (hasError) { 0115 Q_EMIT errorMessage(i18n("Failed to get a list of devices: '%1'", m_request->errorMsg())); 0116 } 0117 m_request->deleteLater(); 0118 m_request = nullptr; 0119 0120 if (hasError || m_mappedDevices.isEmpty()) { 0121 Q_EMIT loaded(); 0122 return; 0123 } 0124 0125 QDBusMessage message; 0126 message = QDBusMessage::createMethodCall(QLatin1String("org.fedoraproject.Config.Printing"), 0127 QLatin1String("/org/fedoraproject/Config/Printing"), 0128 QLatin1String("org.fedoraproject.Config.Printing"), 0129 QLatin1String("GroupPhysicalDevices")); 0130 message << QVariant::fromValue(m_mappedDevices); 0131 QDBusConnection::sessionBus().callWithCallback(message, 0132 this, 0133 SLOT(getGroupedDevicesSuccess(QDBusMessage)), 0134 SLOT(getGroupedDevicesFailed(QDBusError,QDBusMessage))); 0135 } 0136 0137 void DevicesModel::insertDevice(const QString &device_class, 0138 const QString &device_id, 0139 const QString &device_info, 0140 const QString &device_make_and_model, 0141 const QString &device_uri, 0142 const QString &device_location, 0143 const QStringList &grouped_uris) 0144 { 0145 QStandardItem *stdItem; 0146 stdItem = createItem(device_class, 0147 device_id, 0148 device_info, 0149 device_make_and_model, 0150 device_uri, 0151 device_location, 0152 !grouped_uris.isEmpty()); 0153 if (!grouped_uris.isEmpty()) { 0154 stdItem->setData(grouped_uris, DeviceUris); 0155 } 0156 } 0157 0158 void DevicesModel::insertDevice(const QString &device_class, 0159 const QString &device_id, 0160 const QString &device_info, 0161 const QString &device_make_and_model, 0162 const QString &device_uri, 0163 const QString &device_location, 0164 const KCupsPrinters &grouped_printers) 0165 { 0166 QStandardItem *stdItem; 0167 stdItem = createItem(device_class, 0168 device_id, 0169 device_info, 0170 device_make_and_model, 0171 device_uri, 0172 device_location, 0173 !grouped_printers.isEmpty()); 0174 if (!grouped_printers.isEmpty()) { 0175 stdItem->setData(QVariant::fromValue(grouped_printers), DeviceUris); 0176 } 0177 } 0178 0179 QStandardItem *DevicesModel::createItem(const QString &device_class, 0180 const QString &device_id, 0181 const QString &device_info, 0182 const QString &device_make_and_model, 0183 const QString &device_uri, 0184 const QString &device_location, 0185 bool grouped) 0186 { 0187 // "direct" 0188 qDebug() << device_class; 0189 // "MFG:Samsung;CMD:GDI;MDL:SCX-4200 Series;CLS:PRINTER;MODE:PCL;STATUS:IDLE;" 0190 qDebug() << device_id; 0191 // "Samsung SCX-4200 Series" 0192 qDebug() << device_info; 0193 // "Samsung SCX-4200 Series" 0194 qDebug() << device_make_and_model; 0195 // "usb://Samsung/SCX-4200%20Series" 0196 qDebug() << device_uri; 0197 // "" 0198 qDebug() << device_location; 0199 0200 Kind kind; 0201 // Store the kind of the device 0202 if (device_class == QLatin1String("network")) { 0203 if (m_rx.indexIn(device_uri) > -1) { 0204 kind = Networked; 0205 } else { 0206 // other network devices looks like 0207 // just "http" 0208 kind = OtherNetworked; 0209 } 0210 } else if (device_class == QLatin1String("other") && 0211 device_uri == QLatin1String("other")) { 0212 kind = Other; 0213 } else { 0214 // If device class is not network assume local 0215 kind = Local; 0216 } 0217 0218 QString location; 0219 if (device_location.isEmpty() && kind == Local) { 0220 location = QHostInfo::localHostName(); 0221 } else { 0222 location = device_location; 0223 } 0224 0225 QString text; 0226 if (!device_make_and_model.isEmpty() && 0227 !grouped && 0228 device_make_and_model.compare(QLatin1String("unknown"), Qt::CaseInsensitive)) { 0229 text = device_info + QLatin1String(" (") + device_make_and_model + QLatin1Char(')'); 0230 } else { 0231 text = device_info; 0232 } 0233 0234 QString toolTip; 0235 if (!grouped) { 0236 if (device_uri.startsWith(QLatin1String("parallel"))) { 0237 toolTip = i18nc("@info:tooltip", 0238 "A printer connected to the parallel port"); 0239 } else if (device_uri.startsWith(QLatin1String("usb"))) { 0240 toolTip = i18nc("@info:tooltip", 0241 "A printer connected to a USB port"); 0242 } else if (device_uri.startsWith(QLatin1String("bluetooth"))) { 0243 toolTip = i18nc("@info:tooltip", 0244 "A printer connected via Bluetooth"); 0245 } else if (device_uri.startsWith(QLatin1String("hal"))) { 0246 toolTip = i18nc("@info:tooltip", 0247 "Local printer detected by the " 0248 "Hardware Abstraction Layer (HAL)"); 0249 } else if (device_uri.startsWith(QLatin1String("hp"))) { 0250 toolTip = i18nc("@info:tooltip", 0251 "HPLIP software driving a printer, " 0252 "or the printer function of a multi-function device"); 0253 } else if (device_uri.startsWith(QLatin1String("hpfax"))) { 0254 toolTip = i18nc("@info:tooltip", 0255 "HPLIP software driving a fax machine, " 0256 "or the fax function of a multi-function device"); 0257 } else if (device_uri.startsWith(QLatin1String("dnssd")) || 0258 device_uri.startsWith(QLatin1String("mdns"))) { 0259 toolTip = i18nc("@info:tooltip", 0260 "Remote CUPS printer via DNS-SD"); 0261 } 0262 } 0263 0264 auto stdItem = new QStandardItem; 0265 stdItem->setText(text); 0266 stdItem->setToolTip(toolTip); 0267 stdItem->setData(device_class, DeviceClass); 0268 stdItem->setData(device_id, DeviceId); 0269 stdItem->setData(device_info, DeviceInfo); 0270 stdItem->setData(device_uri, DeviceUri); 0271 stdItem->setData(device_make_and_model, DeviceMakeAndModel); 0272 stdItem->setData(device_location, DeviceLocation); 0273 0274 // Find the proper category to our item 0275 QStandardItem *catItem; 0276 switch (kind) { 0277 case Networked: 0278 catItem = findCreateCategory(i18nc("@item", "Discovered Network Printers"), kind); 0279 catItem->appendRow(stdItem); 0280 break; 0281 case OtherNetworked: 0282 catItem = findCreateCategory(i18nc("@item", "Other Network Printers"), kind); 0283 catItem->appendRow(stdItem); 0284 break; 0285 case Local: 0286 catItem = findCreateCategory(i18nc("@item", "Local Printers"), kind); 0287 catItem->appendRow(stdItem); 0288 break; 0289 default: 0290 stdItem->setData(kind, Qt::UserRole); 0291 appendRow(stdItem); 0292 } 0293 0294 return stdItem; 0295 } 0296 0297 void DevicesModel::getGroupedDevicesSuccess(const QDBusMessage &message) 0298 { 0299 if (message.type() == QDBusMessage::ReplyMessage && message.arguments().size() == 1) { 0300 const auto argument = message.arguments().first().value<QDBusArgument>(); 0301 const auto groupeDevices = qdbus_cast<QList<QStringList> >(argument); 0302 for (const QStringList &list : groupeDevices) { 0303 if (list.isEmpty()) { 0304 continue; 0305 } 0306 0307 const QString uri = list.first(); 0308 const MapSS device = m_mappedDevices[uri]; 0309 insertDevice(device[KCUPS_DEVICE_CLASS], 0310 device[KCUPS_DEVICE_ID], 0311 device[KCUPS_DEVICE_INFO], 0312 device[KCUPS_DEVICE_MAKE_AND_MODEL], 0313 uri, 0314 device[KCUPS_DEVICE_LOCATION], 0315 list.size() > 1 ? list : QStringList()); 0316 } 0317 } else { 0318 qWarning() << "Unexpected message" << message; 0319 groupedDevicesFallback(); 0320 } 0321 Q_EMIT loaded(); 0322 } 0323 0324 void DevicesModel::getGroupedDevicesFailed(const QDBusError &error, const QDBusMessage &message) 0325 { 0326 qWarning() << error << message; 0327 groupedDevicesFallback(); 0328 Q_EMIT errorMessage(i18n("Failed to group devices: '%1'", error.message())); 0329 Q_EMIT loaded(); 0330 } 0331 0332 void DevicesModel::groupedDevicesFallback() 0333 { 0334 MapSMapSS::const_iterator i = m_mappedDevices.constBegin(); 0335 while (i != m_mappedDevices.constEnd()) { 0336 const MapSS device = i.value(); 0337 insertDevice(device[KCUPS_DEVICE_CLASS], 0338 device[KCUPS_DEVICE_ID], 0339 device[KCUPS_DEVICE_INFO], 0340 device[KCUPS_DEVICE_MAKE_AND_MODEL], 0341 i.key(), 0342 device[KCUPS_DEVICE_LOCATION]); 0343 ++i; 0344 } 0345 } 0346 0347 QStandardItem* DevicesModel::findCreateCategory(const QString &category, Kind kind) 0348 { 0349 for (int i = 0; i < rowCount(); ++i) { 0350 QStandardItem *catItem = item(i); 0351 if (catItem->data(Qt::UserRole).toInt() == kind) { 0352 return catItem; 0353 } 0354 } 0355 0356 int pos = 0; 0357 for (int i = 0; i < rowCount(); ++i, ++pos) { 0358 QStandardItem *catItem = item(i); 0359 if (catItem->data(Qt::UserRole).toInt() > kind) { 0360 pos = i; 0361 break; 0362 } 0363 } 0364 0365 auto catItem = new QStandardItem(category); 0366 QFont font = catItem->font(); 0367 font.setBold(true); 0368 catItem->setFont(font); 0369 catItem->setData(kind, Qt::UserRole); 0370 catItem->setFlags(Qt::ItemIsEnabled); 0371 insertRow(pos, catItem); 0372 0373 // Emit the parent so the view expand the item 0374 Q_EMIT parentAdded(indexFromItem(catItem)); 0375 0376 return catItem; 0377 } 0378 0379 #include "moc_DevicesModel.cpp"