File indexing completed on 2025-01-05 05:09:31
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 "SelectMakeModel.h" 0008 #include "ui_SelectMakeModel.h" 0009 0010 #include "KCupsRequest.h" 0011 #include "NoSelectionRectDelegate.h" 0012 #include "kcupslib_log.h" 0013 0014 #include <QItemSelection> 0015 #include <QLineEdit> 0016 #include <QStandardItemModel> 0017 0018 #include <QDBusConnection> 0019 #include <QDBusMetaType> 0020 #include <QDBusReply> 0021 0022 #include <KLocalizedString> 0023 #include <KMessageBox> 0024 0025 // Marshall the MyStructure data into a D-Bus argument 0026 QDBusArgument &operator<<(QDBusArgument &argument, const DriverMatch &driverMatch) 0027 { 0028 argument.beginStructure(); 0029 argument << driverMatch.ppd << driverMatch.match; 0030 argument.endStructure(); 0031 return argument; 0032 } 0033 0034 // Retrieve the MyStructure data from the D-Bus argument 0035 const QDBusArgument &operator>>(const QDBusArgument &argument, DriverMatch &driverMatch) 0036 { 0037 argument.beginStructure(); 0038 argument >> driverMatch.ppd >> driverMatch.match; 0039 argument.endStructure(); 0040 return argument; 0041 } 0042 0043 SelectMakeModel::SelectMakeModel(QWidget *parent) 0044 : QWidget(parent) 0045 , ui(new Ui::SelectMakeModel) 0046 { 0047 ui->setupUi(this); 0048 0049 // Configure the error message widget 0050 ui->messageWidget->setWordWrap(true); 0051 ui->messageWidget->setMessageType(KMessageWidget::Error); 0052 ui->messageWidget->hide(); 0053 0054 m_sourceModel = new PPDModel(this); 0055 0056 ui->makeView->setModel(m_sourceModel); 0057 ui->makeView->setItemDelegate(new NoSelectionRectDelegate(this)); 0058 // Updates the PPD view to the selected Make 0059 connect(ui->makeView->selectionModel(), &QItemSelectionModel::currentChanged, ui->ppdsLV, &QListView::setRootIndex); 0060 0061 ui->ppdsLV->setModel(m_sourceModel); 0062 ui->ppdsLV->setItemDelegate(new NoSelectionRectDelegate(this)); 0063 connect(m_sourceModel, &PPDModel::dataChanged, this, &SelectMakeModel::checkChanged); 0064 0065 // Clear the PPD view selection, so the Next/Finish button gets disabled 0066 connect(ui->makeView->selectionModel(), &QItemSelectionModel::currentChanged, ui->ppdsLV->selectionModel(), &QItemSelectionModel::clearSelection); 0067 0068 // Make sure we update the Next/Finish button if a PPD is selected 0069 connect(ui->ppdsLV->selectionModel(), &QItemSelectionModel::selectionChanged, this, &SelectMakeModel::checkChanged); 0070 0071 // When the radio button changes the signal must be emitted 0072 connect(ui->ppdFileRB, &QRadioButton::toggled, this, &SelectMakeModel::checkChanged); 0073 connect(ui->ppdFilePathUrl, &KUrlRequester::textChanged, this, &SelectMakeModel::checkChanged); 0074 0075 qDBusRegisterMetaType<DriverMatch>(); 0076 qDBusRegisterMetaType<DriverMatchList>(); 0077 } 0078 0079 SelectMakeModel::~SelectMakeModel() 0080 { 0081 delete ui; 0082 } 0083 0084 void SelectMakeModel::setDeviceInfo(const QString &deviceId, const QString &make, const QString &makeAndModel, const QString &deviceUri) 0085 { 0086 qCDebug(LIBKCUPS) << "===================================" << deviceId << makeAndModel << deviceUri; 0087 m_gotBestDrivers = false; 0088 m_hasRecommended = false; 0089 m_make = make; 0090 m_makeAndModel = makeAndModel; 0091 0092 // Get the best drivers 0093 QDBusMessage message; 0094 message = QDBusMessage::createMethodCall(QLatin1String("org.fedoraproject.Config.Printing"), 0095 QLatin1String("/org/fedoraproject/Config/Printing"), 0096 QLatin1String("org.fedoraproject.Config.Printing"), 0097 QLatin1String("GetBestDrivers")); 0098 message << deviceId; 0099 message << makeAndModel; 0100 message << deviceUri; 0101 QDBusConnection::sessionBus().callWithCallback(message, 0102 this, 0103 SLOT(getBestDriversFinished(QDBusMessage)), 0104 SLOT(getBestDriversFailed(QDBusError, QDBusMessage))); 0105 0106 if (!m_ppdRequest) { 0107 m_ppdRequest = new KCupsRequest; 0108 connect(m_ppdRequest, &KCupsRequest::finished, this, &SelectMakeModel::ppdsLoaded); 0109 m_ppdRequest->getPPDS(); 0110 } 0111 } 0112 0113 void SelectMakeModel::setMakeModel(const QString &make, const QString &makeAndModel) 0114 { 0115 ui->radioButtonSelectDriver->setText(i18n("Choose the driver for %1", makeAndModel)); 0116 if (!m_ppdRequest) { 0117 // We won't try to get the best driver 0118 // we should be we need more info and testing 0119 // TODO 0120 m_gotBestDrivers = true; 0121 m_hasRecommended = false; 0122 m_make = make; 0123 m_makeAndModel = makeAndModel; 0124 0125 m_ppdRequest = new KCupsRequest; 0126 connect(m_ppdRequest, &KCupsRequest::finished, this, &SelectMakeModel::ppdsLoaded); 0127 m_ppdRequest->getPPDS(); 0128 } else { 0129 // TODO test this 0130 setModelData(); 0131 } 0132 } 0133 0134 void SelectMakeModel::ppdsLoaded(KCupsRequest *request) 0135 { 0136 if (request->hasError()) { 0137 qCWarning(LIBKCUPS) << "Failed to get PPDs" << request->errorMsg(); 0138 ui->messageWidget->setText(i18n("Failed to get a list of drivers: '%1'", request->errorMsg())); 0139 ui->messageWidget->animatedShow(); 0140 0141 // Force the changed signal to be sent 0142 checkChanged(); 0143 0144 } else { 0145 m_ppds = request->ppds(); 0146 0147 // Try to show the PPDs 0148 setModelData(); 0149 } 0150 m_ppdRequest = nullptr; 0151 request->deleteLater(); 0152 } 0153 0154 void SelectMakeModel::checkChanged() 0155 { 0156 qCDebug(LIBKCUPS); 0157 if (isFileSelected()) { 0158 Q_EMIT changed(!selectedPPDFileName().isNull()); 0159 } else { 0160 // enable or disable the job action buttons if something is selected 0161 Q_EMIT changed(!selectedPPDName().isNull()); 0162 0163 selectFirstMake(); 0164 } 0165 } 0166 0167 QString SelectMakeModel::selectedPPDName() const 0168 { 0169 QItemSelection ppdSelection = ui->ppdsLV->selectionModel()->selection(); 0170 if (!isFileSelected() && !ppdSelection.indexes().isEmpty()) { 0171 QModelIndex index = ppdSelection.indexes().first(); 0172 return index.data(PPDModel::PPDName).toString(); 0173 } 0174 return QString(); 0175 } 0176 0177 QString SelectMakeModel::selectedPPDMakeAndModel() const 0178 { 0179 QItemSelection ppdSelection = ui->ppdsLV->selectionModel()->selection(); 0180 if (!isFileSelected() && !ppdSelection.indexes().isEmpty()) { 0181 QModelIndex index = ppdSelection.indexes().first(); 0182 return index.data(PPDModel::PPDMakeAndModel).toString(); 0183 } 0184 return QString(); 0185 } 0186 0187 QString SelectMakeModel::selectedPPDFileName() const 0188 { 0189 if (isFileSelected()) { 0190 QFileInfo file = QFileInfo(ui->ppdFilePathUrl->url().toLocalFile()); 0191 qCDebug(LIBKCUPS) << ui->ppdFilePathUrl->url().toLocalFile() << file.isFile() << file.filePath(); 0192 if (file.isFile()) { 0193 return file.filePath(); 0194 } 0195 } 0196 return QString(); 0197 } 0198 0199 bool SelectMakeModel::isFileSelected() const 0200 { 0201 qCDebug(LIBKCUPS) << ui->ppdFileRB->isChecked(); 0202 return ui->ppdFileRB->isChecked(); 0203 } 0204 0205 void SelectMakeModel::getBestDriversFinished(const QDBusMessage &message) 0206 { 0207 if (message.type() == QDBusMessage::ReplyMessage && message.arguments().size() == 1) { 0208 QDBusArgument arg = message.arguments().first().value<QDBusArgument>(); 0209 const DriverMatchList driverMatchList = qdbus_cast<DriverMatchList>(arg); 0210 m_driverMatchList = driverMatchList; 0211 m_hasRecommended = !m_driverMatchList.isEmpty(); 0212 for (const DriverMatch &driverMatch : driverMatchList) { 0213 qCDebug(LIBKCUPS) << driverMatch.ppd << driverMatch.match; 0214 } 0215 } else { 0216 qCWarning(LIBKCUPS) << "Unexpected message" << message; 0217 } 0218 m_gotBestDrivers = true; 0219 setModelData(); 0220 } 0221 0222 void SelectMakeModel::getBestDriversFailed(const QDBusError &error, const QDBusMessage &message) 0223 { 0224 qCWarning(LIBKCUPS) << "Failed to get best drivers" << error << message; 0225 0226 // Show the PPDs anyway 0227 m_gotBestDrivers = true; 0228 ui->messageWidget->setText(i18n("Failed to search for a recommended driver: '%1'", error.message())); 0229 ui->messageWidget->animatedShow(); 0230 setModelData(); 0231 } 0232 0233 void SelectMakeModel::setModelData() 0234 { 0235 if (!m_ppds.isEmpty() && m_gotBestDrivers) { 0236 m_sourceModel->setPPDs(m_ppds, m_driverMatchList); 0237 0238 // Pre-select the first Recommended PPD 0239 if (m_hasRecommended) { 0240 selectRecommendedPPD(); 0241 } else if (!m_ppds.isEmpty() && !m_make.isEmpty()) { 0242 selectMakeModelPPD(); 0243 } 0244 0245 // Force changed signal to be emitted 0246 checkChanged(); 0247 } 0248 } 0249 0250 void SelectMakeModel::selectFirstMake() 0251 { 0252 QItemSelection selection; 0253 selection = ui->makeView->selectionModel()->selection(); 0254 // Make sure the first make is selected 0255 if (selection.indexes().isEmpty() && m_sourceModel->rowCount() > 0) { 0256 ui->makeView->selectionModel()->setCurrentIndex(m_sourceModel->index(0, 0), QItemSelectionModel::SelectCurrent); 0257 } 0258 } 0259 0260 void SelectMakeModel::selectMakeModelPPD() 0261 { 0262 const QList<QStandardItem *> makes = m_sourceModel->findItems(m_make); 0263 for (QStandardItem *make : makes) { 0264 // Check if the item is in this make 0265 for (int i = 0; i < make->rowCount(); i++) { 0266 if (make->child(i)->data(PPDModel::PPDMakeAndModel).toString() == m_makeAndModel) { 0267 ui->makeView->selectionModel()->setCurrentIndex(make->index(), QItemSelectionModel::SelectCurrent); 0268 ui->ppdsLV->selectionModel()->setCurrentIndex(make->child(i)->index(), QItemSelectionModel::SelectCurrent); 0269 return; 0270 } 0271 } 0272 } 0273 0274 // the exact PPD wasn't found try to select just the make 0275 if (!makes.isEmpty()) { 0276 ui->makeView->selectionModel()->setCurrentIndex(makes.first()->index(), QItemSelectionModel::SelectCurrent); 0277 } 0278 } 0279 0280 void SelectMakeModel::selectRecommendedPPD() 0281 { 0282 // Force the first make to be selected 0283 selectFirstMake(); 0284 0285 QItemSelection ppdSelection = ui->ppdsLV->selectionModel()->selection(); 0286 if (ppdSelection.indexes().isEmpty()) { 0287 QItemSelection makeSelection = ui->makeView->selectionModel()->selection(); 0288 QModelIndex parent = makeSelection.indexes().first(); 0289 if (parent.isValid()) { 0290 ui->ppdsLV->selectionModel()->setCurrentIndex(m_sourceModel->index(0, 0, parent), QItemSelectionModel::SelectCurrent); 0291 } 0292 } 0293 } 0294 0295 #include "moc_SelectMakeModel.cpp"