diff --git a/add-printer/AddPrinter.cpp b/add-printer/AddPrinter.cpp index 3cf3d15..5f9879f 100644 --- a/add-printer/AddPrinter.cpp +++ b/add-printer/AddPrinter.cpp @@ -1,112 +1,115 @@ /*************************************************************************** * 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 "AddPrinter.h" #include "AddPrinterAssistant.h" #include +#include #include -#include -#include +#include + +Q_DECLARE_LOGGING_CATEGORY(PM_ADD_PRINTER) AddPrinter::AddPrinter(int &argc, char **argv) : QApplication(argc, argv) { setQuitOnLastWindowClosed(true); } AddPrinter::~AddPrinter() { } void AddPrinter::addPrinter(qulonglong wid) { auto wizard = new AddPrinterAssistant(); wizard->initAddPrinter(); show(wizard, wid); } void AddPrinter::addClass(qulonglong wid) { auto wizard = new AddPrinterAssistant(); wizard->initAddClass(); show(wizard, wid); } void AddPrinter::changePPD(qulonglong wid, const QString &name) { // Fist we need to get the printer attributes QPointer request = new KCupsRequest; - QStringList attr; - attr << KCUPS_PRINTER_TYPE; // needed to know if it's a remote printer - attr << KCUPS_PRINTER_MAKE_AND_MODEL; - attr << KCUPS_DEVICE_URI; + const QStringList attr({ + KCUPS_PRINTER_TYPE, // needed to know if it's a remote printer + KCUPS_PRINTER_MAKE_AND_MODEL, + KCUPS_DEVICE_URI + }); request->getPrinterAttributes(name, false, attr); request->waitTillFinished(); if (request) { if (!request->hasError() && request->printers().size() == 1) { - KCupsPrinter printer = request->printers().first(); + const KCupsPrinter printer = request->printers().first(); if (printer.type() & CUPS_PRINTER_REMOTE) { - qWarning() << "Ignoring request, can not change PPD of remote printer" << name; + qCWarning(PM_ADD_PRINTER) << "Ignoring request, can not change PPD of remote printer" << name; } else { auto wizard = new AddPrinterAssistant(); wizard->initChangePPD(name, printer.deviceUri(), printer.makeAndModel()); show(wizard, wid); } } else { qWarning() << "Ignoring request, printer not found" << name << request->errorMsg(); } request->deleteLater(); } } void AddPrinter::newPrinterFromDevice(qulonglong wid, const QString &name, const QString &device_id) { // Example of data // "direct" // "MFG:Samsung;CMD:GDI;MDL:SCX-4200 Series;CLS:PRINTER;MODE:PCL;STATUS:IDLE;" // "Samsung SCX-4200 Series" // "Samsung SCX-4200 Series" // "usb://Samsung/SCX-4200%20Series" // "" // printer = "Samsung SCX-3400 Series"; // deviceId = "MFG:Samsung;CMD:SPL,FWV,PIC,BDN,EXT;MDL:SCX-3400 Series;CLS:PRINTER;MODE:SCN,SPL3,R000105;STATUS:BUSY;"; // printer = "Samsung SCX-4200 Series"; // deviceId = "MFG:Samsung;CMD:GDI;MDL:SCX-4200 Series;CLS:PRINTER;MODE:PCL;STATUS:IDLE;"; // printer = "HP PSC 1400 series"; // deviceId = "MFG:HP;MDL:PSC 1400 series;DES:;CMD:LDL,MLC,PML,DYN;"; auto wizard = new AddPrinterAssistant(); wizard->initAddPrinter(name, device_id); show(wizard, wid); } void AddPrinter::show(QWidget *widget, qulonglong wid) const { widget->show(); KWindowSystem::forceActiveWindow(widget->winId()); KWindowSystem::setMainWindow(widget, wid); } diff --git a/add-printer/AddPrinterAssistant.cpp b/add-printer/AddPrinterAssistant.cpp index c0347ea..a2ef956 100644 --- a/add-printer/AddPrinterAssistant.cpp +++ b/add-printer/AddPrinterAssistant.cpp @@ -1,246 +1,244 @@ /*************************************************************************** * 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 "AddPrinterAssistant.h" #include "PageDestinations.h" #include "PageChoosePrinters.h" #include "PageChoosePPD.h" #include "PageAddPrinter.h" #include #include #include #include #include #include #include #include -AddPrinterAssistant::AddPrinterAssistant() : - KAssistantDialog(), - m_devicesPage(0), - m_chooseClassPage(0), - m_choosePPDPage(0), - m_addPrinterPage(0) +AddPrinterAssistant::AddPrinterAssistant() { setWindowTitle(i18nc("@title:window", "Add a New Printer")); setWindowIcon(QIcon::fromTheme(QLatin1String("printer"))); buttonBox()->removeButton(buttonBox()->button(QDialogButtonBox::Cancel)); // Needed so we have our dialog size saved setAttribute(Qt::WA_DeleteOnClose); - QPushButton * helpButton = buttonBox()->addButton(QDialogButtonBox::Help); + QPushButton *helpButton = buttonBox()->addButton(QDialogButtonBox::Help); // Configure the help button to be flat, disabled and empty helpButton->setFlat(true); helpButton->setEnabled(false); helpButton->setIcon(QIcon()); helpButton->setText(QString()); // Setup the busy cursor m_busySeq = new KPixmapSequenceOverlayPainter(this); m_busySeq->setSequence(KIconLoader::global()->loadPixmapSequence(QLatin1String("process-working"), KIconLoader::SizeSmallMedium)); m_busySeq->setAlignment(Qt::AlignHCenter | Qt::AlignBottom); m_busySeq->setWidget(helpButton); connect(finishButton(), &QPushButton::clicked, this, &AddPrinterAssistant::slotFinishButtonClicked); // Restore the dialog size KConfigGroup configGroup(KSharedConfig::openConfig(QLatin1String("print-manager")), "AddPrinterAssistant"); KWindowConfig::restoreWindowSize(windowHandle(), configGroup); } AddPrinterAssistant::~AddPrinterAssistant() { KConfigGroup configGroup(KSharedConfig::openConfig(QLatin1String("print-manager")), "AddPrinterAssistant"); KWindowConfig::saveWindowSize(windowHandle(), configGroup); } void AddPrinterAssistant::initAddPrinter(const QString &printer, const QString &deviceId) { // setup our hash args with the information if we are // adding a new printer or a class - QVariantHash args; - args[ADDING_PRINTER] = true; + QVariantHash args({ + {ADDING_PRINTER, true} + }); KPageWidgetItem *currentPage; if (deviceId.isEmpty()) { m_devicesPage = new KPageWidgetItem(new PageDestinations(args), i18nc("@title:window", "Select a Printer to Add")); addPage(m_devicesPage); currentPage = m_devicesPage; m_choosePPDPage = new KPageWidgetItem(new PageChoosePPD, i18nc("@title:window", "Pick a Driver")); addPage(m_choosePPDPage); } else { args[KCUPS_DEVICE_URI] = printer; args[KCUPS_DEVICE_ID] = deviceId; args[KCUPS_DEVICE_LOCATION] = QHostInfo::localHostName(); m_choosePPDPage = new KPageWidgetItem(new PageChoosePPD(args), i18nc("@title:window", "Pick a Driver")); addPage(m_choosePPDPage); currentPage = m_choosePPDPage; } m_addPrinterPage = new KPageWidgetItem(new PageAddPrinter, i18nc("@title:window", "Please describe you printer")); addPage(m_addPrinterPage); // Set this later so that all m_*Pages are created setCurrentPage(currentPage); } void AddPrinterAssistant::initAddClass() { // setup our hash args with the information if we are // adding a new printer or a class - QVariantHash args; - args[ADDING_PRINTER] = false; - args[KCUPS_DEVICE_LOCATION] = QHostInfo::localHostName(); + const QVariantHash args({ + {ADDING_PRINTER, false}, + {KCUPS_DEVICE_LOCATION, QHostInfo::localHostName()} + }); KPageWidgetItem *currentPage; m_chooseClassPage = new KPageWidgetItem(new PageChoosePrinters(args), i18nc("@title:window", "Configure your connection")); addPage(m_chooseClassPage); currentPage = m_chooseClassPage; m_addPrinterPage = new KPageWidgetItem(new PageAddPrinter, i18nc("@title:window", "Please describe you printer")); addPage(m_addPrinterPage); // Set this later so that all m_*Pages are created setCurrentPage(currentPage); } void AddPrinterAssistant::initChangePPD(const QString &printer, const QString &deviceUri, const QString &makeAndModel) { // setup our hash args with the information if we are // adding a new printer or a class - QVariantHash args; - args[ADDING_PRINTER] = true; - args[KCUPS_DEVICE_URI] = deviceUri; - args[KCUPS_PRINTER_NAME] = printer; - args[KCUPS_PRINTER_MAKE_AND_MODEL] = makeAndModel; + const QVariantHash args({ + {ADDING_PRINTER, true}, + {KCUPS_DEVICE_URI, deviceUri}, + {KCUPS_PRINTER_NAME, printer}, + {KCUPS_PRINTER_MAKE_AND_MODEL, makeAndModel} + }); m_choosePPDPage = new KPageWidgetItem(new PageChoosePPD(args), i18nc("@title:window", "Pick a Driver")); addPage(m_choosePPDPage); setCurrentPage(m_choosePPDPage); } void AddPrinterAssistant::back() { KAssistantDialog::back(); auto currPage = qobject_cast(currentPage()->widget()); enableNextButton(currPage->canProceed()); if (!qobject_cast(currentPage()->widget())->isValid()) { back(); } } void AddPrinterAssistant::next() { next(currentPage()); } void AddPrinterAssistant::next(KPageWidgetItem *currentPage) { // Each page has all it's settings and previous pages // settings stored, so when going backwards // we don't set (or even unset values), // and we only call setValues on the next page if // the currentPage() has changes. - QVariantHash args = qobject_cast(currentPage->widget())->values(); + const QVariantHash args = qobject_cast(currentPage->widget())->values(); if (currentPage == m_devicesPage) { qobject_cast(m_choosePPDPage->widget())->setValues(args); setCurrentPage(m_choosePPDPage); } else if (currentPage == m_chooseClassPage ||currentPage == m_choosePPDPage) { qobject_cast(m_addPrinterPage->widget())->setValues(args); setCurrentPage(m_addPrinterPage); } } void AddPrinterAssistant::setCurrentPage(KPageWidgetItem *page) { // if after setting the values the page is still valid show // it up, if not call next with it so we can find the next page if (qobject_cast(page->widget())->isValid()) { KAssistantDialog::setCurrentPage(page); auto currPage = qobject_cast(currentPage()->widget()); auto nextPage = qobject_cast(page->widget()); // Disconnect the current page slots disconnect(currPage, &GenericPage::allowProceed, this, &AddPrinterAssistant::enableNextButton); disconnect(currPage, &GenericPage::allowProceed, this, &AddPrinterAssistant::enableFinishButton); disconnect(currPage, &GenericPage::proceed, this, static_cast(&AddPrinterAssistant::next)); disconnect(currPage, &GenericPage::startWorking, m_busySeq, &KPixmapSequenceOverlayPainter::start); disconnect(currPage, &GenericPage::stopWorking, m_busySeq, &KPixmapSequenceOverlayPainter::stop); // Connect next page signals connect(nextPage, &GenericPage::startWorking, m_busySeq, &KPixmapSequenceOverlayPainter::start); connect(nextPage, &GenericPage::stopWorking, m_busySeq, &KPixmapSequenceOverlayPainter::stop); connect(nextPage, &GenericPage::proceed, this, static_cast(&AddPrinterAssistant::next)); // check the working property if (nextPage->isWorking()) { m_busySeq->start(); } else { m_busySeq->stop(); } // When ChangePPD() is called addPrinterPage is zero if (page == m_addPrinterPage || m_addPrinterPage == 0) { connect(nextPage, &GenericPage::allowProceed, this, &AddPrinterAssistant::enableFinishButton); enableNextButton(false); enableFinishButton(nextPage->canProceed()); } else { connect(nextPage, &GenericPage::allowProceed, this, &AddPrinterAssistant::enableNextButton); enableNextButton(nextPage->canProceed()); } } else { // In case page is not valid try the next one next(page); } } void AddPrinterAssistant::showEvent(QShowEvent *event) { KAssistantDialog::showEvent(event); enableNextButton(false); enableFinishButton(false); } void AddPrinterAssistant::slotFinishButtonClicked() { auto page = qobject_cast(currentPage()->widget()); enableFinishButton(false); if (page->finishClicked()) { //KAssistantDialog::slotButtonClicked(button); // FIXME next() really? next(); } else { enableFinishButton(true); } } void AddPrinterAssistant::enableNextButton(bool enable) { nextButton()->setEnabled(enable); } void AddPrinterAssistant::enableFinishButton(bool enable) { finishButton()->setEnabled(enable); } diff --git a/add-printer/AddPrinterAssistant.h b/add-printer/AddPrinterAssistant.h index 3901430..c67d0da 100644 --- a/add-printer/AddPrinterAssistant.h +++ b/add-printer/AddPrinterAssistant.h @@ -1,58 +1,58 @@ /*************************************************************************** * 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 ADD_PRINTER_ASSISTANT_H #define ADD_PRINTER_ASSISTANT_H #include #include class AddPrinterAssistant : public KAssistantDialog { Q_OBJECT public: AddPrinterAssistant(); virtual ~AddPrinterAssistant(); void initAddPrinter(const QString &printer = QString(), const QString &deviceId = QString()); void initAddClass(); void initChangePPD(const QString &printer, const QString &deviceUri, const QString &makeAndModel); public slots: void back() Q_DECL_OVERRIDE; void next() Q_DECL_OVERRIDE; void enableNextButton(bool enable); void enableFinishButton(bool enable); void slotFinishButtonClicked(); private: void next(KPageWidgetItem *currentPage); void setCurrentPage(KPageWidgetItem *page); void showEvent(QShowEvent * event) Q_DECL_OVERRIDE; - KPageWidgetItem *m_devicesPage; - KPageWidgetItem *m_chooseClassPage; - KPageWidgetItem *m_choosePPDPage; - KPageWidgetItem *m_addPrinterPage; + KPageWidgetItem *m_devicesPage = nullptr; + KPageWidgetItem *m_chooseClassPage = nullptr; + KPageWidgetItem *m_choosePPDPage = nullptr; + KPageWidgetItem *m_addPrinterPage = nullptr; KPixmapSequenceOverlayPainter *m_busySeq; }; #endif diff --git a/add-printer/ChooseLpd.cpp b/add-printer/ChooseLpd.cpp index e4aeb67..1b9d6d0 100644 --- a/add-printer/ChooseLpd.cpp +++ b/add-printer/ChooseLpd.cpp @@ -1,93 +1,91 @@ /*************************************************************************** * 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. * ***************************************************************************/ #include "ChooseLpd.h" #include "ui_ChooseLpd.h" #include #include -#include -#include #include ChooseLpd::ChooseLpd(QWidget *parent) : GenericPage(parent), ui(new Ui::ChooseLpd), m_isValid(false) { ui->setupUi(this); // setup default options setWindowTitle(i18nc("@title:window", "Select a Printer to Add")); } ChooseLpd::~ChooseLpd() { delete ui; } void ChooseLpd::on_addressLE_textChanged(const QString &text) { - qDebug() << text; + Q_UNUSED(text); +// qDebug() << text; } void ChooseLpd::setValues(const QVariantHash &args) { m_args = args; const QString deviceUri = args[KCUPS_DEVICE_URI].toString(); - qDebug() << deviceUri; if (deviceUri.contains(QLatin1Char('/'))) { m_isValid = false; return; } m_isValid = true; ui->addressLE->setText(deviceUri); ui->addressLE->setFocus(); } QVariantHash ChooseLpd::values() const { QVariantHash ret = m_args; - ret[KCUPS_DEVICE_URI] = static_cast(QLatin1String("lpd://") % ui->addressLE->text()); + ret[KCUPS_DEVICE_URI] = static_cast(QLatin1String("lpd://") + ui->addressLE->text()); return ret; } bool ChooseLpd::canProceed() const { bool allow = false; if (!ui->addressLE->text().isEmpty()) { - QUrl url = QUrl(QStringLiteral("lpd://") % ui->addressLE->text()); + const QUrl url = QUrl(QLatin1String("lpd://") + ui->addressLE->text()); allow = url.isValid(); } return allow; } bool ChooseLpd::isValid() const { return m_isValid; } void ChooseLpd::checkSelected() { // emit allowProceed(!devicesLV->selectionModel()->selection().isEmpty()); } diff --git a/add-printer/ChooseSamba.cpp b/add-printer/ChooseSamba.cpp index e4421ff..638afe9 100644 --- a/add-printer/ChooseSamba.cpp +++ b/add-printer/ChooseSamba.cpp @@ -1,132 +1,131 @@ /*************************************************************************** * 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. * ***************************************************************************/ #include "ChooseSamba.h" #include "ui_ChooseSamba.h" #include #include -#include #include #include ChooseSamba::ChooseSamba(QWidget *parent) : GenericPage(parent), ui(new Ui::ChooseSamba) { ui->setupUi(this); // setup default options setWindowTitle(i18nc("@title:window", "Select a Printer to Add")); connect(ui->addressLE, &QLineEdit::textChanged, this, &ChooseSamba::checkSelected); connect(ui->usernameLE, &QLineEdit::textChanged, this, &ChooseSamba::checkSelected); connect(ui->passwordLE, &QLineEdit::textChanged, this, &ChooseSamba::checkSelected); } ChooseSamba::~ChooseSamba() { delete ui; } void ChooseSamba::setValues(const QVariantHash &args) { m_args = args; ui->addressLE->setFocus(); } QVariantHash ChooseSamba::values() const { QVariantHash ret = m_args; - QString address = ui->addressLE->text().trimmed(); + const QString address = ui->addressLE->text().trimmed(); QUrl url; if (address.startsWith(QLatin1String("//"))) { - url = QUrl(QLatin1String("smb:") % address); + url = QUrl(QLatin1String("smb:") + address); } else if (address.startsWith(QLatin1String("/"))) { - url = QUrl(QLatin1String("smb:/") % address); + url = QUrl(QLatin1String("smb:/") + address); } else if (address.startsWith(QLatin1String("://"))) { - url = QUrl(QLatin1String("smb") % address); + url = QUrl(QLatin1String("smb") + address); } else if (address.startsWith(QLatin1String("smb://"))) { url = QUrl(address); } else if (!QUrl::fromUserInput(address).scheme().isEmpty() && QUrl::fromUserInput(address).scheme() != QStringLiteral("smb")) { url = QUrl::fromUserInput(address); url.setScheme(QStringLiteral("smb")); } else { - url = QUrl(QStringLiteral("smb://") % address); + url = QUrl(QStringLiteral("smb://") + address); } qDebug() << 1 << url; if (!ui->usernameLE->text().isEmpty()) { url.setUserName(ui->usernameLE->text()); } if (!ui->passwordLE->text().isEmpty()) { url.setPassword(ui->passwordLE->text()); } qDebug() << 2 << url; qDebug() << 3 << url.url() << url.path().section(QLatin1Char('/'), -1, -1);// same as url.fileName() qDebug() << 4 << url.fileName(); qDebug() << 5 << url.host() << url.url().section(QLatin1Char('/'), 3, 3).toLower(); ret[KCUPS_DEVICE_URI] = url.url(); ret[KCUPS_DEVICE_INFO] = url.fileName(); // if there is 4 '/' means the url is like // smb://group/host/printer, so the location is at a different place if (url.url().count(QLatin1Char('/') == 4)) { ret[KCUPS_DEVICE_LOCATION] = url.url().section(QLatin1Char('/'), 3, 3).toLower(); } else { ret[KCUPS_DEVICE_LOCATION] = url.host(); } return ret; } bool ChooseSamba::isValid() const { - QVariantHash args = values(); - QUrl url(args[KCUPS_DEVICE_URI].toString()); + const QVariantHash args = values(); + const QUrl url(args[KCUPS_DEVICE_URI].toString()); return url.isValid() && !url.isEmpty() && !url.scheme().isEmpty() && !url.host().isEmpty() && !url.path().isEmpty() && !url.fileName().isEmpty() && url.url().count(QLatin1Char('/')) <= 4; } bool ChooseSamba::canProceed() const { return isValid(); } void ChooseSamba::load() { } void ChooseSamba::checkSelected() { emit allowProceed(isValid()); } diff --git a/add-printer/ChooseSerial.cpp b/add-printer/ChooseSerial.cpp index 672fe72..c212449 100644 --- a/add-printer/ChooseSerial.cpp +++ b/add-printer/ChooseSerial.cpp @@ -1,121 +1,120 @@ /*************************************************************************** * 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. * ***************************************************************************/ #include "ChooseSerial.h" #include "ui_ChooseSerial.h" #include #include ChooseSerial::ChooseSerial(QWidget *parent) : GenericPage(parent), ui(new Ui::ChooseSerial), - m_rx(QLatin1String("\\?baud=(\\d+)")), - m_isValid(false) + m_rx(QLatin1String("\\?baud=(\\d+)")) { ui->setupUi(this); // setup default options setWindowTitle(i18nc("@title:window", "Select a Printer to Add")); ui->parityCB->addItem(i18nc("@label:listbox", "None"), QLatin1String("none")); ui->parityCB->addItem(i18nc("@label:listbox", "Even"), QLatin1String("even")); ui->parityCB->addItem(i18nc("@label:listbox", "Odd"), QLatin1String("odd")); ui->flowCB->addItem(i18nc("@label:listbox", "None"), QLatin1String("none")); ui->flowCB->addItem(i18nc("@label:listbox", "XON/XOFF (Software)"), QLatin1String("soft")); ui->flowCB->addItem(i18nc("@label:listbox", "RTS/CTS (Hardware)"), QLatin1String("hard")); ui->flowCB->addItem(i18nc("@label:listbox", "DTR/DSR (Hardware)"), QLatin1String("dtrdsr")); } ChooseSerial::~ChooseSerial() { delete ui; } bool ChooseSerial::isValid() const { return m_isValid; } void ChooseSerial::setValues(const QVariantHash &args) { m_args = args; QString deviceUri = args[KCUPS_DEVICE_URI].toString(); if (!deviceUri.startsWith(QLatin1String("serial:"))) { m_isValid = false; return; } m_isValid = true; static int baudrates[] = /* Baud rates */ { 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800 }; // Find out the max baud rate int maxrate; if (m_rx.indexIn(deviceUri) != -1) { maxrate = m_rx.cap(1).toInt(); } else { maxrate = 19200; } ui->baudRateCB->clear(); for (int i = 0; i < 10; i ++) { if (baudrates[i] > maxrate) { break; } else { ui->baudRateCB->addItem(QString::number(baudrates[i])); } } // Set the current index to the maxrate ui->baudRateCB->setCurrentIndex(ui->baudRateCB->count() - 1); } void ChooseSerial::load() { } QVariantHash ChooseSerial::values() const { QVariantHash ret = m_args; QString deviceUri = m_args[KCUPS_DEVICE_URI].toString(); - int pos = deviceUri.indexOf(QLatin1Char('?')); - QString baudRate = ui->baudRateCB->currentText(); - QString bits = ui->bitsCB->currentText(); - QString parity = ui->baudRateCB->itemData(ui->baudRateCB->currentIndex()).toString(); - QString flow = ui->flowCB->itemData(ui->flowCB->currentIndex()).toString(); - QString replace = QString::fromLatin1("?baud=%1+bits=%2+parity=%3+flow=%4") + const int pos = deviceUri.indexOf(QLatin1Char('?')); + const QString baudRate = ui->baudRateCB->currentText(); + const QString bits = ui->bitsCB->currentText(); + const QString parity = ui->baudRateCB->itemData(ui->baudRateCB->currentIndex()).toString(); + const QString flow = ui->flowCB->itemData(ui->flowCB->currentIndex()).toString(); + const QString replace = QString::fromLatin1("?baud=%1+bits=%2+parity=%3+flow=%4") .arg(baudRate, bits, parity, flow); deviceUri.replace(pos, deviceUri.size() - pos, replace); ret[KCUPS_DEVICE_URI] = deviceUri; return ret; } diff --git a/add-printer/ChooseSerial.h b/add-printer/ChooseSerial.h index 8bcb7b9..1bda95c 100644 --- a/add-printer/ChooseSerial.h +++ b/add-printer/ChooseSerial.h @@ -1,52 +1,52 @@ /*************************************************************************** * 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 CHOOSE_SERIAL_H #define CHOOSE_SERIAL_H #include "GenericPage.h" #include namespace Ui { class ChooseSerial; } class ChooseSerial : public GenericPage { Q_OBJECT public: explicit ChooseSerial(QWidget *parent = 0); ~ChooseSerial(); void setValues(const QVariantHash &args) Q_DECL_OVERRIDE; QVariantHash values() const Q_DECL_OVERRIDE; bool isValid() const Q_DECL_OVERRIDE; public slots: void load(); private: Ui::ChooseSerial *ui; QRegExp m_rx; - bool m_isValid; + bool m_isValid = false; }; #endif diff --git a/add-printer/ChooseSocket.cpp b/add-printer/ChooseSocket.cpp index 68e0c07..5da3761 100644 --- a/add-printer/ChooseSocket.cpp +++ b/add-printer/ChooseSocket.cpp @@ -1,89 +1,87 @@ /*************************************************************************** * 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. * ***************************************************************************/ #include "ChooseSocket.h" #include "ui_ChooseSocket.h" #include -#include #include #include ChooseSocket::ChooseSocket(QWidget *parent) : GenericPage(parent), - ui(new Ui::ChooseSocket), - m_isValid(false) + ui(new Ui::ChooseSocket) { ui->setupUi(this); // setup default options setWindowTitle(i18nc("@title:window", "Select a Printer to Add")); } ChooseSocket::~ChooseSocket() { delete ui; } void ChooseSocket::setValues(const QVariantHash &args) { if (m_args == args) { return; } m_args = args; ui->addressLE->clear(); ui->portISB->setValue(9100); - QString deviceUri = args[KCUPS_DEVICE_URI].toString(); + const QString deviceUri = args[KCUPS_DEVICE_URI].toString(); QUrl url(deviceUri); - if (url.scheme() == QStringLiteral("socket")) { + if (url.scheme() == QLatin1String("socket")) { ui->addressLE->setText(url.host()); ui->portISB->setValue(url.port(9100)); } ui->addressLE->setFocus(); m_isValid = true; } QVariantHash ChooseSocket::values() const { QVariantHash ret = m_args; - QUrl url = QUrl(QStringLiteral("socket://") % ui->addressLE->text()); + QUrl url = QUrl(QLatin1String("socket://") + ui->addressLE->text()); url.setPort(ui->portISB->value()); ret[KCUPS_DEVICE_URI] = url.toDisplayString(); return ret; } bool ChooseSocket::isValid() const { return m_isValid; } bool ChooseSocket::canProceed() const { return !ui->addressLE->text().isEmpty(); } void ChooseSocket::on_addressLE_textChanged(const QString &text) { Q_UNUSED(text) emit allowProceed(canProceed()); } diff --git a/add-printer/ChooseSocket.h b/add-printer/ChooseSocket.h index 778734c..5f03574 100644 --- a/add-printer/ChooseSocket.h +++ b/add-printer/ChooseSocket.h @@ -1,49 +1,49 @@ /*************************************************************************** * 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 CHOOSE_SOCKET_H #define CHOOSE_SOCKET_H #include "GenericPage.h" namespace Ui { class ChooseSocket; } class ChooseSocket : public GenericPage { Q_OBJECT public: explicit ChooseSocket(QWidget *parent = 0); ~ChooseSocket(); void setValues(const QVariantHash &args) Q_DECL_OVERRIDE; QVariantHash values() const Q_DECL_OVERRIDE; bool isValid() const Q_DECL_OVERRIDE; bool canProceed() const Q_DECL_OVERRIDE; private slots: void on_addressLE_textChanged(const QString &text); private: Ui::ChooseSocket *ui; - bool m_isValid; + bool m_isValid = false; }; #endif diff --git a/add-printer/ChooseUri.cpp b/add-printer/ChooseUri.cpp index 6d7c75d..eba8e03 100644 --- a/add-printer/ChooseUri.cpp +++ b/add-printer/ChooseUri.cpp @@ -1,174 +1,171 @@ /*************************************************************************** * 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 "ChooseUri.h" #include "ui_ChooseUri.h" #include -#include -#include - ChooseUri::ChooseUri(QWidget *parent) : GenericPage(parent), ui(new Ui::ChooseUri) { ui->setupUi(this); ui->searchTB->setIcon(QIcon::fromTheme(QLatin1String("edit-find"))); // setup default options setWindowTitle(i18nc("@title:window", "Select a Printer to Add")); connect(ui->addressLE, &QLineEdit::textChanged, this, &ChooseUri::checkSelected); connect(ui->addressLE, &QLineEdit::returnPressed, this, &ChooseUri::findPrinters); connect(ui->searchTB, &QToolButton::clicked, this, &ChooseUri::findPrinters); } ChooseUri::~ChooseUri() { delete ui; } void ChooseUri::setValues(const QVariantHash &args) { m_args = args; bool visible = false; - QUrl url(args[KCUPS_DEVICE_URI].toString()); + const QUrl url(args[KCUPS_DEVICE_URI].toString()); if (url.url() == QLatin1String("other")) { ui->addressLE->clear(); visible = true; } else if (url.scheme().isEmpty() && url.authority().isEmpty()) { - ui->addressLE->setText(url.url() % QLatin1String("://")); + ui->addressLE->setText(url.url() + QLatin1String("://")); } else { ui->addressLE->setText(url.url()); } ui->searchTB->setVisible(visible); ui->addressLE->setFocus(); } QVariantHash ChooseUri::values() const { QVariantHash ret = m_args; ret[KCUPS_DEVICE_URI] = parsedURL(ui->addressLE->text()).url(); return ret; } bool ChooseUri::isValid() const { QVariantHash args = values(); QUrl url(args[KCUPS_DEVICE_URI].toString()); //qDebug() << url << url.isValid() << url.isEmpty() << url.scheme().isEmpty() << url.host(); return url.isValid() && !url.isEmpty() && !url.scheme().isEmpty() && !url.host().isEmpty(); } bool ChooseUri::canProceed() const { return isValid(); } void ChooseUri::load() { } void ChooseUri::checkSelected() { emit allowProceed(isValid()); } void ChooseUri::on_addressLE_textChanged(const QString &text) { QUrl url = parsedURL(text); if (url.isValid() && (url.scheme().isEmpty() || url.scheme() == QStringLiteral("http") || url.scheme() == QStringLiteral("https") || url.scheme() == QStringLiteral("ipp"))) { // TODO maybe cups library can connect to more protocols ui->searchTB->setEnabled(true); } else { ui->searchTB->setEnabled(false); } } void ChooseUri::findPrinters() { QUrl url = parsedURL(ui->addressLE->text()); auto conn = new KCupsConnection(url, this); auto request = new KCupsRequest(conn); connect(request, &KCupsRequest::finished, this, &ChooseUri::getPrintersFinished); QStringList attr; attr << KCUPS_PRINTER_NAME; attr << KCUPS_PRINTER_STATE; attr << KCUPS_PRINTER_IS_SHARED; attr << KCUPS_PRINTER_IS_ACCEPTING_JOBS; attr << KCUPS_PRINTER_TYPE; attr << KCUPS_PRINTER_LOCATION; attr << KCUPS_PRINTER_INFO; attr << KCUPS_PRINTER_MAKE_AND_MODEL; request->setProperty("URI", url); emit startWorking(); request->getPrinters(attr); } void ChooseUri::getPrintersFinished(KCupsRequest *request) { QUrl uri = request->property("URI").value(); QUrl url; url.setScheme(QStringLiteral("ipp")); url.setAuthority(uri.authority()); KCupsPrinters printers = request->printers(); if (request->hasError()) { emit errorMessage(request->errorMsg()); } else { emit insertDevice(QLatin1String("network"), url.authority(), url.authority(), QString(), url.url(), QString(), printers); } request->deleteLater(); request->connection()->deleteLater(); emit stopWorking(); } QUrl ChooseUri::parsedURL(const QString &text) const { QUrl url(QUrl::fromUserInput(text)); if (url.host().isEmpty() && !text.contains(QLatin1String("://"))) { url = QUrl(); // URI might be scsi, network on anything that didn't match before if (m_args[KCUPS_DEVICE_URI].toString() != QLatin1String("other")) { url.setScheme(m_args[KCUPS_DEVICE_URI].toString()); } url.setAuthority(text); } return url; } diff --git a/add-printer/DevicesModel.cpp b/add-printer/DevicesModel.cpp index b1bbb21..7d0661b 100644 --- a/add-printer/DevicesModel.cpp +++ b/add-printer/DevicesModel.cpp @@ -1,380 +1,380 @@ /*************************************************************************** * 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 #include -DevicesModel::DevicesModel(QObject *parent) - : QStandardItemModel(parent), - m_request(0), - m_rx(QLatin1String("[a-z]+://.*")) +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(); - m_blacklistedURIs << QLatin1String("hp"); - m_blacklistedURIs << QLatin1String("hpfax"); - m_blacklistedURIs << QLatin1String("hal"); - m_blacklistedURIs << QLatin1String("beh"); - m_blacklistedURIs << QLatin1String("scsi"); - m_blacklistedURIs << QLatin1String("http"); - m_blacklistedURIs << QLatin1String("delete"); - // 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 - MapSS mapSS; - mapSS[KCUPS_DEVICE_CLASS] = device_class; - mapSS[KCUPS_DEVICE_ID] = device_id; - mapSS[KCUPS_DEVICE_INFO] = device_info; - mapSS[KCUPS_DEVICE_MAKE_AND_MODEL] = device_make_and_model; - mapSS[KCUPS_DEVICE_LOCATION] = device_location; + 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 << qVariantFromValue(m_mappedDevices); + 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(')'); + 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->appendRow(stdItem); break; case OtherNetworked: catItem = findCreateCategory(i18nc("@item", "Other Network Printers")); catItem->appendRow(stdItem); break; case Local: catItem = findCreateCategory(i18nc("@item", "Local Printers")); catItem->appendRow(stdItem); break; default: 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; } - QString uri = list.first(); - MapSS device = m_mappedDevices[uri]; + 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()) { - MapSS device = i.value(); + 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) { for (int i = 0; i < rowCount(); ++i) { QStandardItem *catItem = item(i); if (catItem->text() == category) { return catItem; } } auto catItem = new QStandardItem(category); QFont font = catItem->font(); font.setBold(true); catItem->setFont(font); catItem->setFlags(Qt::ItemIsEnabled); appendRow(catItem); // Emit the parent so the view expand the item emit parentAdded(indexFromItem(catItem)); return catItem; } diff --git a/add-printer/PageChoosePPD.cpp b/add-printer/PageChoosePPD.cpp index 25160b9..745d74d 100644 --- a/add-printer/PageChoosePPD.cpp +++ b/add-printer/PageChoosePPD.cpp @@ -1,207 +1,205 @@ /*************************************************************************** * 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 "PageChoosePPD.h" #include "ui_PageChoosePPD.h" #include "DevicesModel.h" #include #include #include #include -#include #include #include #include PageChoosePPD::PageChoosePPD(const QVariantHash &args, QWidget *parent) : GenericPage(parent), - ui(new Ui::PageChoosePPD), - m_isValid(false) + ui(new Ui::PageChoosePPD) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); // setup default options setWindowTitle(i18nc("@title:window", "Select a Printer to Add")); m_layout = new QStackedLayout; m_layout->setContentsMargins(0, 0, 0, 0); ui->gridLayout->addLayout(m_layout, 1, 3); m_selectMM = new SelectMakeModel(this); connect(m_selectMM, &SelectMakeModel::changed, this, &PageChoosePPD::checkSelected); m_layout->addWidget(m_selectMM); // Setup the busy cursor connect(m_selectMM, &SelectMakeModel::changed, this, &PageChoosePPD::notWorking); if (!args.isEmpty()) { // set our args setValues(args); } } PageChoosePPD::~PageChoosePPD() { removeTempPPD(); delete ui; } void PageChoosePPD::setValues(const QVariantHash &args) { m_args = args; if (args[ADDING_PRINTER].toBool()) { qDebug() << args; working(); removeTempPPD(); QString deviceId = args[KCUPS_DEVICE_ID].toString(); QString make; QString makeAndModel = args[KCUPS_DEVICE_MAKE_AND_MODEL].toString(); QString deviceURI = args[KCUPS_DEVICE_URI].toString(); // If - QUrl url(deviceURI % QStringLiteral(".ppd")); - if (url.scheme() == QStringLiteral("ipp")) { + QUrl url(deviceURI + QLatin1String(".ppd")); + if (url.scheme() == QLatin1String("ipp")) { auto tempFile = new QTemporaryFile; - tempFile->setFileTemplate(QStringLiteral("print-manager-XXXXXX.ppd")); + tempFile->setFileTemplate(QLatin1String("print-manager-XXXXXX.ppd")); tempFile->open(); - url.setScheme(QStringLiteral("http")); + url.setScheme(QLatin1String("http")); if (url.port() < 0) { url.setPort(631); } qDebug() << deviceURI << url; KJob *job = KIO::file_copy(url, QUrl::fromLocalFile(tempFile->fileName()), -1, KIO::Overwrite | KIO::HideProgressInfo); job->setProperty("URI", deviceURI); connect(job, &KJob::result, this, &PageChoosePPD::resultJob); } // Get the make from the device id for (const QString &pair : deviceId.split(QLatin1Char(';'))) { - if (pair.startsWith(QStringLiteral("MFG:"))) { + if (pair.startsWith(QLatin1String("MFG:"))) { make = pair.section(QLatin1Char(':'), 1); break; } } if (makeAndModel.isEmpty()) { // Get the model from the device id for (const QString &pair : deviceId.split(QLatin1Char(';'))) { - if (pair.startsWith(QStringLiteral("MDL:"))) { + if (pair.startsWith(QLatin1String("MDL:"))) { // Build the make and model string if (make.isNull()) { makeAndModel = pair.section(QLatin1Char(':'), 1); } else { - makeAndModel = make % QLatin1Char(' ') % pair.section(QLatin1Char(':'), 1); + makeAndModel = make + QLatin1Char(' ') + pair.section(QLatin1Char(':'), 1); } break; } } } // if the device info is empty use the make and model // so we can have a nice name for the new printer on the next page if (!args.contains(KCUPS_DEVICE_INFO) && !makeAndModel.isEmpty()) { m_args[KCUPS_DEVICE_INFO] = makeAndModel; } m_selectMM->setDeviceInfo(deviceId, make, makeAndModel, deviceURI); m_isValid = true; } else { m_isValid = false; } } bool PageChoosePPD::isValid() const { return m_isValid; } QVariantHash PageChoosePPD::values() const { if (!isValid()) { return m_args; } QVariantHash ret = m_args; if (canProceed()) { if (!m_ppdFile.isNull()) { ret[FILENAME] = m_ppdFile; } else if (m_selectMM->isFileSelected()) { ret[FILENAME] = m_selectMM->selectedPPDFileName(); } else { ret[PPD_NAME] = m_selectMM->selectedPPDName(); } } return ret; } bool PageChoosePPD::canProceed() const { // It can proceed if a PPD file (local or not) is provided bool changed = false; bool allow = false; if (m_selectMM->isFileSelected()) { allow = !m_selectMM->selectedPPDFileName().isNull(); } else if (!m_ppdFile.isNull()) { allow = true; } else { allow = !m_selectMM->selectedPPDName().isNull(); } qDebug() << allow; return allow; } void PageChoosePPD::checkSelected() { emit allowProceed(canProceed()); } void PageChoosePPD::selectDefault() { } void PageChoosePPD::resultJob(KJob *job) { if (!job->error() && job->property("URI").toString() == m_args[KCUPS_DEVICE_URI].toString()) { auto fileCopyJob = qobject_cast(job); // Make sure this job is for the current device m_ppdFile = fileCopyJob->destUrl().toLocalFile(); m_isValid = false; emit proceed(); } } void PageChoosePPD::removeTempPPD() { if (!m_ppdFile.isEmpty()) { QFile::remove(m_ppdFile); m_ppdFile.clear(); } } diff --git a/add-printer/PageChoosePPD.h b/add-printer/PageChoosePPD.h index 6332c8e..ccfdc3c 100644 --- a/add-printer/PageChoosePPD.h +++ b/add-printer/PageChoosePPD.h @@ -1,62 +1,62 @@ /*************************************************************************** * 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 PAGE_CHOOSE_PPD_H #define PAGE_CHOOSE_PPD_H #include "GenericPage.h" #include #include namespace Ui { class PageChoosePPD; } class SelectMakeModel; class PageChoosePPD : public GenericPage { Q_OBJECT public: explicit PageChoosePPD(const QVariantHash &args = QVariantHash(), QWidget *parent = 0); ~PageChoosePPD(); bool canProceed() const Q_DECL_OVERRIDE; void setValues(const QVariantHash &args) Q_DECL_OVERRIDE; QVariantHash values() const Q_DECL_OVERRIDE; bool isValid() const Q_DECL_OVERRIDE; private slots: void checkSelected(); void selectDefault(); void resultJob(KJob *job); private: void removeTempPPD(); Ui::PageChoosePPD *ui; - bool m_isValid; + bool m_isValid = false; SelectMakeModel *m_selectMM; QStackedLayout *m_layout; QString m_ppdFile; }; #endif diff --git a/add-printer/PageDestinations.cpp b/add-printer/PageDestinations.cpp index 168acef..a91fdb3 100644 --- a/add-printer/PageDestinations.cpp +++ b/add-printer/PageDestinations.cpp @@ -1,401 +1,400 @@ /*************************************************************************** * 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 "PageDestinations.h" #include "ui_PageDestinations.h" #include "DevicesModel.h" #include "ChooseLpd.h" #include "ChooseSamba.h" #include "ChooseSerial.h" #include "ChooseSocket.h" #include "ChooseUri.h" #include #include #include -#include #include // system-config-printer --setup-printer='file:/tmp/printout' --devid='MFG:Ricoh;MDL:Aficio SP C820DN' PageDestinations::PageDestinations(const QVariantHash &args, QWidget *parent) : GenericPage(parent), ui(new Ui::PageDestinations), m_chooseLpd(new ChooseLpd(this)), m_chooseSamba(new ChooseSamba(this)), m_chooseSerial(new ChooseSerial(this)), m_chooseSocket(new ChooseSocket(this)), m_chooseUri(new ChooseUri(this)), m_chooseLabel(new QLabel(this)) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); ui->stackedWidget->addWidget(m_chooseLpd); connect(m_chooseLpd, &ChooseLpd::allowProceed, this, &PageDestinations::allowProceed); connect(m_chooseLpd, &ChooseLpd::startWorking, this, &PageDestinations::working); connect(m_chooseLpd, &ChooseLpd::stopWorking, this, &PageDestinations::notWorking); ui->stackedWidget->addWidget(m_chooseSamba); connect(m_chooseSamba, &ChooseSamba::allowProceed, this, &PageDestinations::allowProceed); connect(m_chooseSamba, &ChooseSamba::startWorking, this, &PageDestinations::working); connect(m_chooseSamba, &ChooseSamba::stopWorking, this, &PageDestinations::notWorking); ui->stackedWidget->addWidget(m_chooseSerial); connect(m_chooseSerial, &ChooseSerial::allowProceed, this, &PageDestinations::allowProceed); connect(m_chooseSerial, &ChooseSerial::startWorking, this, &PageDestinations::working); connect(m_chooseSerial, &ChooseSerial::stopWorking, this, &PageDestinations::notWorking); ui->stackedWidget->addWidget(m_chooseSocket); connect(m_chooseSocket, &ChooseSocket::allowProceed, this, &PageDestinations::allowProceed); connect(m_chooseSocket, &ChooseSocket::startWorking, this, &PageDestinations::working); connect(m_chooseSocket, &ChooseSocket::stopWorking, this, &PageDestinations::notWorking); ui->stackedWidget->addWidget(m_chooseUri); connect(m_chooseUri, &ChooseUri::allowProceed, this, &PageDestinations::allowProceed); connect(m_chooseUri, &ChooseUri::startWorking, this, &PageDestinations::working); connect(m_chooseUri, &ChooseUri::stopWorking, this, &PageDestinations::notWorking); connect(m_chooseUri, &ChooseUri::errorMessage, ui->messageWidget, &KMessageWidget::setText); connect(m_chooseUri, &ChooseUri::errorMessage, ui->messageWidget, &KMessageWidget::animatedShow); connect(m_chooseUri, &ChooseUri::insertDevice, this, &PageDestinations::insertDevice); m_chooseLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); ui->stackedWidget->addWidget(m_chooseLabel); // Hide the message widget ui->messageWidget->setMessageType(KMessageWidget::Error); ui->messageWidget->hide(); // setup default options setWindowTitle(i18nc("@title:window", "Select a Printer to Add")); m_model = new DevicesModel(this); ui->devicesTV->setModel(m_model); ui->devicesTV->setItemDelegate(new NoSelectionRectDelegate(this)); connect(ui->devicesTV->selectionModel(), &QItemSelectionModel::selectionChanged, this, &PageDestinations::deviceChanged); connect(m_model, &DevicesModel::errorMessage, ui->messageWidget, &KMessageWidget::setText); connect(m_model, &DevicesModel::errorMessage, ui->messageWidget, &KMessageWidget::animatedShow); // Expand when a parent is added connect(m_model, &DevicesModel::parentAdded, ui->devicesTV, &QTreeView::expand); // Update the view when the device URI combo box changed connect(ui->connectionsCB, static_cast(&QComboBox::currentIndexChanged), this, &PageDestinations::deviceUriChanged); ui->connectionsGB->setVisible(false); // Setup the busy cursor working(); connect(m_model, &DevicesModel::loaded, this, &PageDestinations::notWorking); if (!args.isEmpty()) { // set our args setValues(args); } } PageDestinations::~PageDestinations() { delete ui; } void PageDestinations::setValues(const QVariantHash &args) { m_args = args; if (args[ADDING_PRINTER].toBool()) { // m_isValid = true; m_model->update(); // m_busySeq->start(); } else { // m_isValid = false; } } bool PageDestinations::isValid() const { return true; } QVariantHash PageDestinations::values() const { QVariantHash ret = m_args; auto page = qobject_cast(ui->stackedWidget->currentWidget()); if (page) { ret = page->values(); } else if (canProceed()) { ret = selectedItemValues(); } return ret; } bool PageDestinations::canProceed() const { bool ret = ui->stackedWidget->currentIndex() != 0; auto page = qobject_cast(ui->stackedWidget->currentWidget()); if (page) { ret = page->canProceed(); } return ret; } void PageDestinations::deviceChanged() { QItemSelectionModel *selection = ui->devicesTV->selectionModel(); if (!selection->selectedIndexes().isEmpty() && selection->selectedIndexes().size() == 1) { QModelIndex index = selection->selectedIndexes().first(); QVariant uris = index.data(DevicesModel::DeviceUris); if (uris.isNull()) { ui->connectionsGB->setVisible(false); } else if (uris.type() == QVariant::StringList) { ui->connectionsCB->clear(); for (const QString &uri : uris.toStringList()) { ui->connectionsCB->addItem(uriText(uri), uri); } ui->connectionsGB->setVisible(true); } else { ui->connectionsCB->clear(); const auto printers = uris.value(); for (const KCupsPrinter &printer : printers) { ui->connectionsCB->addItem(printer.name(), qVariantFromValue(printer)); } ui->connectionsGB->setVisible(true); } } else { ui->connectionsGB->setVisible(false); setCurrentPage(0, selectedItemValues()); return; } deviceUriChanged(); } void PageDestinations::deviceUriChanged() { // Get the selected values QVariantHash args = selectedItemValues(); // "beh" is excluded from the list QString deviceUri = args[KCUPS_DEVICE_URI].toString(); qDebug() << deviceUri; if (deviceUri.startsWith(QLatin1String("parallel"))) { m_chooseLabel->setText(i18n("A printer connected to the parallel port.")); setCurrentPage(m_chooseLabel, args); } else if (deviceUri.startsWith(QLatin1String("usb"))) { m_chooseLabel->setText(i18n("A printer connected to a USB port.")); setCurrentPage(m_chooseLabel, args); } else if (deviceUri.startsWith(QLatin1String("bluetooth"))) { m_chooseLabel->setText(i18n("A printer connected via Bluetooth.")); setCurrentPage(m_chooseLabel, args); } else if (deviceUri.startsWith(QLatin1String("hal"))) { m_chooseLabel->setText(i18n("Local printer detected by the " "Hardware Abstraction Layer (HAL).")); setCurrentPage(m_chooseLabel, args); } else if (deviceUri.startsWith(QLatin1String("hp"))) { m_chooseLabel->setText(i18n("HPLIP software driving a printer, " "or the printer function of a multi-function device.")); setCurrentPage(m_chooseLabel, args); } else if (deviceUri.startsWith(QLatin1String("hpfax"))) { m_chooseLabel->setText(i18n("HPLIP software driving a fax machine, " "or the fax function of a multi-function device.")); setCurrentPage(m_chooseLabel, args); } else if (deviceUri.startsWith(QLatin1String("dnssd")) || deviceUri.startsWith(QLatin1String("mdns"))) { // TODO this needs testing... QString text; if (deviceUri.contains(QLatin1String("cups"))) { text = i18n("Remote CUPS printer via DNS-SD"); } else { QString protocol; if (deviceUri.contains(QLatin1String("._ipp"))) { protocol = QLatin1String("IPP"); } else if (deviceUri.contains(QLatin1String("._printer"))) { protocol = QLatin1String("LPD"); } else if (deviceUri.contains(QLatin1String("._pdl-datastream"))) { protocol = QLatin1String("AppSocket/JetDirect"); } if (protocol.isNull()) { text = i18n("Network printer via DNS-SD"); } else { text = i18n("%1 network printer via DNS-SD", protocol); } } m_chooseLabel->setText(text); setCurrentPage(m_chooseLabel, args); } else if (deviceUri.startsWith(QLatin1String("socket"))) { qDebug() << "SOCKET"; setCurrentPage(m_chooseSocket, args); } else if (deviceUri.startsWith(QLatin1String("ipp")) || deviceUri.startsWith(QLatin1String("ipps")) || deviceUri.startsWith(QLatin1String("http")) || deviceUri.startsWith(QLatin1String("https"))) { setCurrentPage(m_chooseUri, args); } else if (deviceUri.startsWith(QLatin1String("lpd"))) { setCurrentPage(m_chooseLpd, args); } else if (deviceUri.startsWith(QLatin1String("scsi"))) { // TODO setCurrentPage(m_chooseUri, args); } else if (deviceUri.startsWith(QLatin1String("serial"))) { setCurrentPage(m_chooseSerial, args); } else if (deviceUri.startsWith(QLatin1String("smb"))) { setCurrentPage(m_chooseSamba, args); } else if (deviceUri.startsWith(QLatin1String("network"))) { setCurrentPage(m_chooseUri, args); } else { setCurrentPage(m_chooseUri, args); } emit allowProceed(canProceed()); } void PageDestinations::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) { m_model->insertDevice(device_class, device_id, device_info, device_make_and_model, device_uri, device_location, grouped_printers); } QVariantHash PageDestinations::selectedItemValues() const { QVariantHash ret = m_args; if (!ui->devicesTV->selectionModel()->selectedIndexes().isEmpty() && ui->devicesTV->selectionModel()->selectedIndexes().size() == 1) { QModelIndex index = ui->devicesTV->selectionModel()->selectedIndexes().first(); QVariant uri = index.data(DevicesModel::DeviceUri); QVariant uris = index.data(DevicesModel::DeviceUris); // if the devicesTV holds an item with grouped URIs // get the selected value from the connections combo box if (uris.isNull() || uris.type() == QVariant::StringList) { if (uris.type() == QVariant::StringList) { uri = ui->connectionsCB->itemData(ui->connectionsCB->currentIndex()); } ret[KCUPS_DEVICE_URI] = uri; ret[KCUPS_DEVICE_ID] = index.data(DevicesModel::DeviceId); ret[KCUPS_DEVICE_MAKE_AND_MODEL] = index.data(DevicesModel::DeviceMakeAndModel); ret[KCUPS_DEVICE_INFO] = index.data(DevicesModel::DeviceInfo); ret[KCUPS_DEVICE_LOCATION] = index.data(DevicesModel::DeviceLocation); } else { QVariant aux = ui->connectionsCB->itemData(ui->connectionsCB->currentIndex()); KCupsPrinter printer = aux.value(); QUrl url(uri.toString()); - url.setPath(QLatin1String("printers/") % printer.name()); + url.setPath(QLatin1String("printers/") + printer.name()); ret[KCUPS_DEVICE_URI] = url.url(); ret[KCUPS_DEVICE_ID] = index.data(DevicesModel::DeviceId); ret[KCUPS_PRINTER_INFO] = printer.info(); qDebug() << KCUPS_PRINTER_INFO << printer.info(); ret[KCUPS_PRINTER_NAME] = printer.name(); ret[KCUPS_DEVICE_LOCATION] = printer.location(); } qDebug() << uri << ret; } return ret; } void PageDestinations::setCurrentPage(QWidget *widget, const QVariantHash &args) { auto page = qobject_cast(widget); if (page) { page->setValues(args); if (ui->stackedWidget->currentWidget() != page) {; ui->stackedWidget->setCurrentWidget(page); } } else if (qobject_cast(widget)) { if (ui->connectionsGB->isVisible() && ui->connectionsCB->currentText() == m_chooseLabel->text()) { // Don't show duplicated text for the user m_chooseLabel->clear(); } if (ui->stackedWidget->currentWidget() != widget) {; ui->stackedWidget->setCurrentWidget(widget); } } else { ui->stackedWidget->setCurrentIndex(0); } } QString PageDestinations::uriText(const QString &uri) const { QString ret; if (uri.startsWith(QLatin1String("parallel"))) { ret = i18n("Parallel Port"); } else if (uri.startsWith(QLatin1String("serial"))) { ret = i18n("Serial Port"); } else if (uri.startsWith(QLatin1String("usb"))) { ret = i18n("USB"); } else if (uri.startsWith(QLatin1String("bluetooth")) ){ ret = i18n("Bluetooth"); } else if (uri.startsWith(QLatin1String("hpfax"))) { ret = i18n("Fax - HP Linux Imaging and Printing (HPLIP)"); } else if (uri.startsWith(QLatin1String("hp"))) { ret = i18n("HP Linux Imaging and Printing (HPLIP)"); } else if (uri.startsWith(QLatin1String("hal"))) { ret = i18n("Hardware Abstraction Layer (HAL)"); } else if (uri.startsWith(QLatin1String("socket"))) { ret = i18n("AppSocket/HP JetDirect"); } else if (uri.startsWith(QLatin1String("lpd"))) { // Check if the queue name is defined - QString queue = uri.section(QLatin1Char('/'), -1, -1); + const QString queue = uri.section(QLatin1Char('/'), -1, -1); if (queue.isEmpty()) { ret = i18n("LPD/LPR queue"); } else { ret = i18n("LPD/LPR queue %1", queue); } } else if (uri.startsWith(QLatin1String("smb"))) { ret = i18n("Windows Printer via SAMBA"); } else if (uri.startsWith(QLatin1String("ipp"))) { // Check if the queue name (fileName) is defined - QString queue = uri.section(QLatin1Char('/'), -1, -1); + const QString queue = uri.section(QLatin1Char('/'), -1, -1); if (queue.isEmpty()) { ret = i18n("IPP"); } else { ret = i18n("IPP %1", queue); } } else if (uri.startsWith(QLatin1String("https"))) { ret = i18n("HTTP"); } else if (uri.startsWith(QLatin1String("dnssd")) || uri.startsWith(QLatin1String("mdns"))) { // TODO this needs testing... QString text; if (uri.contains(QLatin1String("cups"))) { text = i18n("Remote CUPS printer via DNS-SD"); } else { if (uri.contains(QLatin1String("._ipp"))) { ret = i18n("IPP network printer via DNS-SD"); } else if (uri.contains(QLatin1String("._printer"))) { ret = i18n("LPD network printer via DNS-SD"); } else if (uri.contains(QLatin1String("._pdl-datastream"))) { ret = i18n("AppSocket/JetDirect network printer via DNS-SD"); } else { ret = i18n("Network printer via DNS-SD"); } } } else { ret = uri; } return ret; } diff --git a/add-printer/main.cpp b/add-printer/main.cpp index bb68228..c68d7c4 100644 --- a/add-printer/main.cpp +++ b/add-printer/main.cpp @@ -1,97 +1,100 @@ /*************************************************************************** * 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. * ***************************************************************************/ #include "AddPrinter.h" #include #include #include -#include + +#include #include #include +Q_LOGGING_CATEGORY(PM_ADD_PRINTER, "pm.add.printer") + int main(int argc, char **argv) { AddPrinter app(argc, argv); app.setOrganizationDomain(QLatin1String("org.kde")); KAboutData about(QLatin1String("kde-add-printer"), i18n("Add Printer"), QLatin1String(PM_VERSION), i18n("Tool for adding new printers"), KAboutLicense::GPL, i18n("(C) 2010-2018 Daniel Nicoletti")); about.addAuthor(QLatin1String("Daniel Nicoletti"), QString(), QLatin1String("dantti12@gmail.com")); about.addAuthor(QStringLiteral("Lukáš Tinkl"), i18n("Port to Qt 5 / Plasma 5"), QStringLiteral("ltinkl@redhat.com")); KAboutData::setApplicationData(about); QCommandLineParser parser; about.setupCommandLine(&parser); parser.addVersionOption(); parser.addHelpOption(); QCommandLineOption parentWindowOpt({QLatin1String("w"), QLatin1String("parent-window")}, i18n("Parent Window ID"), QLatin1String("wid")); parser.addOption(parentWindowOpt); QCommandLineOption addPrinterOpt(QLatin1String("add-printer"), i18n("Add a new printer")); parser.addOption(addPrinterOpt); QCommandLineOption addClassOpt(QLatin1String("add-class"), i18n("Add a new printer class")); parser.addOption(addClassOpt); QCommandLineOption changePpdOpt(QLatin1String("change-ppd"), i18n("Changes the PPD of a given printer"), QLatin1String("printer-name")); parser.addOption(changePpdOpt); QCommandLineOption newPrinterDevOpt(QLatin1String("new-printer-from-device"), i18n("Changes the PPD of a given printer/deviceid"), QLatin1String("printername/deviceid")); parser.addOption(newPrinterDevOpt); parser.process(app); about.processCommandLine(&parser); qulonglong wid = 0; if (parser.isSet(parentWindowOpt)) { wid = parser.value(parentWindowOpt).toULongLong(); } if (parser.isSet(addPrinterOpt)) { app.addPrinter(wid); } else if (parser.isSet(addClassOpt)) { app.addClass(wid); } else if (parser.isSet(changePpdOpt)) { app.changePPD(wid, parser.value(changePpdOpt)); } else if (parser.isSet(newPrinterDevOpt)) { const QString value = parser.value(newPrinterDevOpt); const QStringList values = value.split(QLatin1String("/")); if (values.size() == 2) { app.newPrinterFromDevice(wid, values.first(), values.last()); } else { qWarning() << "The expected input should be printer/deviceid"; exit(EXIT_FAILURE); } } else { parser.showHelp(EXIT_FAILURE); } return app.exec(); } diff --git a/configure-printer/ConfigurePrinterInterface.cpp b/configure-printer/ConfigurePrinterInterface.cpp index a4080de..b4ada94 100644 --- a/configure-printer/ConfigurePrinterInterface.cpp +++ b/configure-printer/ConfigurePrinterInterface.cpp @@ -1,125 +1,122 @@ /*************************************************************************** * Copyright (C) 2010-2018 Daniel Nicoletti * * * * 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; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ #include "ConfigurePrinterInterface.h" #include "configureprinteradaptor.h" #include "ConfigureDialog.h" #include "Debug.h" #include #include #include #include #include #include ConfigurePrinterInterface::ConfigurePrinterInterface(QObject *parent) : QObject(parent) { qCDebug(PM_CONFIGURE_PRINTER) << "Creating Helper"; (void) new ConfigurePrinterAdaptor(this); if (!QDBusConnection::sessionBus().registerService(QLatin1String("org.kde.ConfigurePrinter"))) { qCDebug(PM_CONFIGURE_PRINTER) << "another helper is already running"; return; } if (!QDBusConnection::sessionBus().registerObject(QLatin1String("/"), this)) { qCDebug(PM_CONFIGURE_PRINTER) << "unable to register service interface to dbus"; return; } // setup the timer that updates the UIs m_updateUi = new QTimer(this); m_updateUi->setInterval(1000); m_updateUi->start(); } ConfigurePrinterInterface::~ConfigurePrinterInterface() { } void ConfigurePrinterInterface::ConfigurePrinter(const QString &destName) { if (!m_uis.contains(destName)) { // Reserve this since the CUPS call might take a long time m_uis[destName] = 0; - QStringList att; - att << KCUPS_PRINTER_NAME; - att << KCUPS_PRINTER_TYPE; // Get destinations with these attributes QPointer request = new KCupsRequest; - request->getPrinters(att); + request->getPrinters({ KCUPS_PRINTER_NAME, KCUPS_PRINTER_TYPE }); request->waitTillFinished(); if (!request) { return; } bool found = false; KCupsPrinter printer; KCupsPrinters printers = request->printers(); for (int i = 0; i < printers.size(); i++) { if (printers.at(i).name() == destName) { printer = printers.at(i); found = true; break; } } request->deleteLater(); if (found) { auto ui = new ConfigureDialog(printer.name(), printer.isClass()); connect(m_updateUi, &QTimer::timeout, ui, static_cast(&ConfigureDialog::update)); connect(ui, &ConfigureDialog::finished, this, &ConfigurePrinterInterface::RemovePrinter); ui->show(); m_uis[printer.name()] = ui; } else { // Remove the reservation m_uis.remove(destName); // if no destination was found and we aren't showing // a queue quit the app if (m_uis.isEmpty()) { emit quit(); } return; } } // Check it it's not reserved if (m_uis.value(destName)) { KWindowSystem::forceActiveWindow(m_uis.value(destName)->winId()); } } void ConfigurePrinterInterface::RemovePrinter() { auto ui = qobject_cast(sender()); if (ui) { m_uis.remove(m_uis.key(ui)); } // if no destination was found and we aren't showing // a queue quit the app if (m_uis.isEmpty()) { emit quit(); } } diff --git a/configure-printer/ModifyPrinter.cpp b/configure-printer/ModifyPrinter.cpp index 9c00a11..3ef234e 100644 --- a/configure-printer/ModifyPrinter.cpp +++ b/configure-printer/ModifyPrinter.cpp @@ -1,295 +1,295 @@ /*************************************************************************** * 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 "ModifyPrinter.h" #include "ui_ModifyPrinter.h" #include "Debug.h" #include "SelectMakeModel.h" #include "SelectMakeModelDialog.h" #include #include #include #include #include ModifyPrinter::ModifyPrinter(const QString &destName, bool isClass, QWidget *parent) : PrinterPage(parent), ui(new Ui::ModifyPrinter), m_destName(destName), - m_isClass(isClass), - m_changes(0) + m_isClass(isClass) { ui->setupUi(this); ui->nameL->setText(destName); ui->connectionL->setVisible(!isClass); ui->connectionLE->setVisible(!isClass); ui->driverL->setVisible(!isClass); ui->makeCB->setVisible(!isClass); ui->membersL->setVisible(isClass); ui->membersLV->setVisible(isClass); if (isClass) { ui->membersLV->setPrinter(destName); } connect(ui->descriptionLE, &QLineEdit::textChanged, this, &ModifyPrinter::textChanged); connect(ui->locationLE, &QLineEdit::textChanged, this, &ModifyPrinter::textChanged); connect(ui->connectionLE, &QLineEdit::textChanged, this, &ModifyPrinter::textChanged); connect(ui->membersLV, static_cast(&ClassListWidget::changed), this, &ModifyPrinter::modelChanged); } ModifyPrinter::~ModifyPrinter() { delete ui; } void ModifyPrinter::on_makeCB_activated(int index) { bool isDifferent = true; if (ui->makeCB->itemData(index).toUInt() == PPDList) { auto dialog = new SelectMakeModelDialog(m_make, m_makeAndModel, this); connect(dialog, &SelectMakeModelDialog::accepted, this, &ModifyPrinter::ppdSelectionAccepted); connect(dialog, &SelectMakeModelDialog::rejected, this, &ModifyPrinter::ppdSelectionRejected); dialog->show(); return; } else if (ui->makeCB->itemData(index).toUInt() == PPDFile) { // set the QVariant type to bool makes it possible to know a file was selected m_changedValues[QLatin1String("ppd-name")] = true; } else if (ui->makeCB->itemData(index).toUInt() == PPDDefault) { isDifferent = false; m_changedValues.remove(QLatin1String("ppd-name")); } else if (ui->makeCB->itemData(index).toUInt() == PPDCustom) { m_changedValues[QLatin1String("ppd-name")] = ui->makeCB->itemData(index, PPDName).toString(); } else { qCWarning(PM_CONFIGURE_PRINTER) << "This should not happen"; return; } if (isDifferent != ui->makeCB->property("different").toBool()) { // it's different from the last time so add or remove changes isDifferent ? m_changes++ : m_changes--; ui->makeCB->setProperty("different", isDifferent); emit changed(m_changes); } ui->makeCB->setProperty("lastIndex", ui->makeCB->currentIndex()); } void ModifyPrinter::ppdSelectionAccepted() { auto dialog = qobject_cast(sender()); auto widget = qobject_cast(dialog->mainWidget()); if (widget->isFileSelected()) { QString fileName = widget->selectedPPDFileName(); ui->makeCB->insertItem(0, fileName, PPDFile); ui->makeCB->setCurrentIndex(0); on_makeCB_activated(0); } else if (!widget->selectedPPDName().isEmpty()) { QString makeAndModel = widget->selectedPPDMakeAndModel(); QString ppdName = widget->selectedPPDName(); ui->makeCB->insertItem(0, makeAndModel, PPDCustom); ui->makeCB->setItemData(0, ppdName, PPDName); ui->makeCB->setCurrentIndex(0); on_makeCB_activated(0); } else { ui->makeCB->setCurrentIndex(ui->makeCB->property("lastIndex").toInt()); } dialog->deleteLater(); } void ModifyPrinter::ppdSelectionRejected() { auto dialog = qobject_cast(sender()); ui->makeCB->setCurrentIndex(ui->makeCB->property("lastIndex").toInt()); dialog->deleteLater(); } void ModifyPrinter::setValues(const KCupsPrinter &printer) { // qCDebug(PM_CONFIGURE_PRINTER) << values; if (m_isClass) { ui->membersLV->setSelectedPrinters(printer.memberNames().join(QLatin1String("|"))); } else { ui->makeCB->clear(); ui->makeCB->setProperty("different", false); ui->makeCB->setProperty("lastIndex", 0); ui->makeCB->insertItem(0, i18n("Current - %1", printer.makeAndModel()), PPDDefault); ui->makeCB->insertSeparator(1); ui->makeCB->insertItem(2, i18n("Select a custom driver"), PPDList); } ui->membersLV->setProperty("different", false); ui->descriptionLE->setText(printer.info()); ui->descriptionLE->setProperty("orig_text", printer.info()); ui->descriptionLE->setProperty("different", false); ui->locationLE->setText(printer.location()); ui->locationLE->setProperty("orig_text", printer.location()); ui->locationLE->setProperty("different", false); ui->connectionLE->setText(printer.deviceUri()); ui->connectionLE->setProperty("orig_text", printer.deviceUri()); ui->connectionLE->setProperty("different", false); // clear old values m_changes = 0; m_changedValues.clear(); emit changed(0); } void ModifyPrinter::modelChanged() { bool isDifferent = ui->membersLV->hasChanges(); if (isDifferent != ui->membersLV->property("different").toBool()) { // it's different from the last time so add or remove changes isDifferent ? m_changes++ : m_changes--; ui->membersLV->setProperty("different", isDifferent); emit changed(m_changes); } // store the new values if (isDifferent) { m_changedValues[KCUPS_MEMBER_URIS] = ui->membersLV->currentSelected(true); } else { m_changedValues.remove(KCUPS_MEMBER_URIS); } } void ModifyPrinter::textChanged(const QString &text) { auto le = qobject_cast(sender()); bool isDifferent = le->property("orig_text") != text; if (isDifferent != le->property("different").toBool()) { // it's different from the last time so add or remove changes isDifferent ? m_changes++ : m_changes--; le->setProperty("different", isDifferent); emit changed(m_changes); } // store the new values QString attribute = le->property("AttributeName").toString(); if (isDifferent) { m_changedValues[attribute] = text; } else { m_changedValues.remove(attribute); } } void ModifyPrinter::save() { if (m_changes) { QVariantHash args = m_changedValues; QString fileName; qCDebug(PM_CONFIGURE_PRINTER) << args; if (args.contains(QLatin1String("ppd-name")) && args[QLatin1String("ppd-name")].type() == QVariant::Bool) { fileName = ui->makeCB->itemData(ui->makeCB->currentIndex(), PPDFile).toString(); args.remove(QLatin1String("ppd-name")); } qCDebug(PM_CONFIGURE_PRINTER) << fileName; QPointer request = new KCupsRequest; if (m_isClass) { request->addOrModifyClass(m_destName, args); } else { request->addOrModifyPrinter(m_destName, args, fileName); } request->waitTillFinished(); if (request) { if (!request->hasError()) { if (m_changedValues.contains(QLatin1String("ppd-name"))) { emit ppdChanged(); } request->getPrinterAttributes(m_destName, m_isClass, neededValues()); request->waitTillFinished(); if (!request->hasError() && !request->printers().isEmpty()) { KCupsPrinter printer = request->printers().first(); setValues(printer); } } else { KMessageBox::detailedSorry(this, m_isClass ? i18nc("@info", "Failed to configure class") : i18nc("@info", "Failed to configure printer"), request->errorMsg(), i18nc("@title:window", "Failed")); } request->deleteLater(); } } } QVariantHash ModifyPrinter::modifiedValues() const { return m_changedValues; } bool ModifyPrinter::hasChanges() { return m_changes; } void ModifyPrinter::setRemote(bool remote) { ui->descriptionLE->setReadOnly(remote); ui->locationLE->setReadOnly(remote); ui->connectionLE->setReadOnly(remote); ui->makeCB->setEnabled(!remote); } void ModifyPrinter::setCurrentMake(const QString &make) { m_make = make; } void ModifyPrinter::setCurrentMakeAndModel(const QString &makeAndModel) { m_makeAndModel = makeAndModel; } QStringList ModifyPrinter::neededValues() const { - QStringList ret; - ret << KCUPS_PRINTER_INFO; - ret << KCUPS_PRINTER_LOCATION; + QStringList ret({ + KCUPS_PRINTER_INFO, + KCUPS_PRINTER_LOCATION + }); if (m_isClass) { ret << KCUPS_MEMBER_NAMES; } else { ret << KCUPS_DEVICE_URI; ret << KCUPS_PRINTER_MAKE_AND_MODEL; } return ret; } diff --git a/configure-printer/ModifyPrinter.h b/configure-printer/ModifyPrinter.h index 189444c..59458b1 100644 --- a/configure-printer/ModifyPrinter.h +++ b/configure-printer/ModifyPrinter.h @@ -1,78 +1,78 @@ /*************************************************************************** * 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 MODIFY_PRINTER_H #define MODIFY_PRINTER_H #include "PrinterPage.h" #include "KCupsRequest.h" #include namespace Ui { class ModifyPrinter; } class ModifyPrinter : public PrinterPage { Q_OBJECT Q_ENUMS(Role) public: typedef enum { PPDDefault, PPDCustom, PPDFile, PPDList, PPDName = Qt::UserRole + 1 } Role; explicit ModifyPrinter(const QString &destName, bool isClass, QWidget *parent = 0); ~ModifyPrinter(); bool hasChanges() Q_DECL_OVERRIDE; QVariantHash modifiedValues() const Q_DECL_OVERRIDE; QStringList neededValues() const Q_DECL_OVERRIDE; void setRemote(bool remote) Q_DECL_OVERRIDE; void setValues(const KCupsPrinter &printer); void setCurrentMake(const QString &make); void setCurrentMakeAndModel(const QString &makeAndModel); void save() Q_DECL_OVERRIDE; signals: void ppdChanged(); private slots: void textChanged(const QString &text); void on_makeCB_activated(int index); void ppdSelectionAccepted(); void ppdSelectionRejected(); void modelChanged(); private: Ui::ModifyPrinter *ui; QString m_destName, m_make, m_makeAndModel; bool m_isClass; QVariantHash m_changedValues; - int m_changes; + int m_changes = 0; }; #endif diff --git a/configure-printer/PrinterBehavior.cpp b/configure-printer/PrinterBehavior.cpp index fd38d39..1ecb45b 100644 --- a/configure-printer/PrinterBehavior.cpp +++ b/configure-printer/PrinterBehavior.cpp @@ -1,327 +1,325 @@ /*************************************************************************** * 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 "PrinterBehavior.h" #include "ui_PrinterBehavior.h" #include "Debug.h" #include PrinterBehavior::PrinterBehavior(const QString &destName, bool isClass, QWidget *parent) : PrinterPage(parent), ui(new Ui::PrinterBehavior), m_destName(destName), - m_isClass(isClass), - m_changes(0) + m_isClass(isClass) { ui->setupUi(this); connect(ui->errorPolicyCB, static_cast(&QComboBox::currentIndexChanged), this, &PrinterBehavior::currentIndexChangedCB); connect(ui->operationPolicyCB, static_cast(&QComboBox::currentIndexChanged), this, &PrinterBehavior::currentIndexChangedCB); connect(ui->startingBannerCB, static_cast(&QComboBox::currentIndexChanged), this, &PrinterBehavior::currentIndexChangedCB); connect(ui->endingBannerCB, static_cast(&QComboBox::currentIndexChanged), this, &PrinterBehavior::currentIndexChangedCB); connect(ui->usersELB, &KEditListWidget::changed, this, &PrinterBehavior::userListChanged); connect(ui->allowRB, &QRadioButton::toggled, this, &PrinterBehavior::userListChanged); } PrinterBehavior::~PrinterBehavior() { delete ui; } void PrinterBehavior::setValues(const KCupsPrinter &printer) { int defaultChoice; ui->errorPolicyCB->clear(); const QStringList errorPolicySupported = printer.errorPolicySupported(); for (const QString &value : errorPolicySupported) { ui->errorPolicyCB->addItem(errorPolicyString(value), value); } QStringList errorPolicy = printer.errorPolicy(); if (!errorPolicy.isEmpty()) { defaultChoice = ui->errorPolicyCB->findData(errorPolicy.first()); ui->errorPolicyCB->setCurrentIndex(defaultChoice); ui->errorPolicyCB->setProperty("defaultChoice", defaultChoice); } ui->operationPolicyCB->clear(); const QStringList opPolicySupported = printer.opPolicySupported(); for (const QString &value : opPolicySupported) { ui->operationPolicyCB->addItem(operationPolicyString(value), value); } QStringList operationPolicy = printer.opPolicy(); if (!errorPolicy.isEmpty()) { defaultChoice = ui->operationPolicyCB->findData(operationPolicy.first()); ui->operationPolicyCB->setCurrentIndex(defaultChoice); ui->operationPolicyCB->setProperty("defaultChoice", defaultChoice); } ui->startingBannerCB->clear(); ui->endingBannerCB->clear(); const QStringList jobSheetsSupported = printer.jobSheetsSupported(); for (const QString &value : jobSheetsSupported) { ui->startingBannerCB->addItem(jobSheetsString(value), value); ui->endingBannerCB->addItem(jobSheetsString(value), value); } QStringList bannerPolicy = printer.jobSheetsDefault(); if (bannerPolicy.size() == 2) { defaultChoice = ui->startingBannerCB->findData(bannerPolicy.at(0)); ui->startingBannerCB->setCurrentIndex(defaultChoice); ui->startingBannerCB->setProperty("defaultChoice", defaultChoice); defaultChoice = ui->endingBannerCB->findData(bannerPolicy.at(1)); ui->endingBannerCB->setCurrentIndex(defaultChoice); ui->endingBannerCB->setProperty("defaultChoice", defaultChoice); } if (!printer.requestingUserNameAllowed().isEmpty()) { QStringList list = printer.requestingUserNameAllowed(); list.sort(); // sort the list here to be able to comapare it later ui->usersELB->setEnabled(true); if (list != ui->usersELB->items()) { ui->usersELB->clear(); ui->usersELB->insertStringList(list); } ui->usersELB->setProperty("defaultList", list); ui->allowRB->setProperty("defaultChoice", true); // Set checked AFTER the default choice was set // otherwise the signal will be emmited // which sets that we have a change ui->allowRB->setChecked(true); } else if (!printer.requestingUserNameDenied().isEmpty()) { QStringList list = printer.requestingUserNameDenied(); list.sort(); // sort the list here to be able to comapare it later ui->usersELB->setEnabled(true); if (list != ui->usersELB->items()) { ui->usersELB->clear(); ui->usersELB->insertStringList(list); } ui->usersELB->setProperty("defaultList", list); ui->allowRB->setProperty("defaultChoice", false); // Set checked AFTER the default choice was set // otherwise the signal will be emmited // which sets that we have a change ui->preventRB->setChecked(true); } // Clear previous changes m_changes = 0; emit changed(false); m_changedValues.clear(); ui->errorPolicyCB->setProperty("different", false); ui->operationPolicyCB->setProperty("different", false); ui->startingBannerCB->setProperty("different", false); ui->endingBannerCB->setProperty("different", false); ui->usersELB->setProperty("different", false); } void PrinterBehavior::userListChanged() { if (ui->usersELB->isEnabled() == false && (ui->allowRB->isChecked() || ui->preventRB->isChecked())) { // this only happen when the list was empty ui-> usersELB->setEnabled(true); } QStringList currentList, defaultList; currentList = ui->usersELB->items(); // sort the list so we can be sure it's different currentList.sort(); defaultList = ui->usersELB->property("defaultList").value(); bool isDifferent = currentList != defaultList; if (isDifferent == false && currentList.isEmpty() == false) { // if the lists are equal and not empty the user might have // changed the Radio Button... if (ui->allowRB->isChecked() != ui->allowRB->property("defaultChoice").toBool()) { isDifferent = true; } } if (isDifferent != ui->usersELB->property("different").toBool()) { // it's different from the last time so add or remove changes isDifferent ? m_changes++ : m_changes--; ui->usersELB->setProperty("different", isDifferent); emit changed(m_changes); } } void PrinterBehavior::currentIndexChangedCB(int index) { auto comboBox = qobject_cast(sender()); bool isDifferent = comboBox->property("defaultChoice").toInt() != index; if (isDifferent != comboBox->property("different").toBool()) { // it's different from the last time so add or remove changes isDifferent ? m_changes++ : m_changes--; comboBox->setProperty("different", isDifferent); emit changed(m_changes); } QString attribute = comboBox->property("AttributeName").toString(); QVariant value; // job-sheets-default has always two values if (attribute == QLatin1String("job-sheets-default")) { QStringList values; values << ui->startingBannerCB->itemData(ui->startingBannerCB->currentIndex()).toString(); values << ui->endingBannerCB->itemData(ui->endingBannerCB->currentIndex()).toString(); value = values; } else { value = comboBox->itemData(index).toString(); } // store the new values if (isDifferent) { m_changedValues[attribute] = value; } else { m_changedValues.remove(attribute); } } QString PrinterBehavior::errorPolicyString(const QString &policy) const { // TODO search for others policies of printer-error-policy-supported if (policy == QLatin1String("abort-job")) { return i18n("Abort job"); } else if (policy == QLatin1String("retry-current-job")) { return i18n("Retry current job"); } else if (policy == QLatin1String("retry-job")) { return i18n("Retry job"); } else if (policy == QLatin1String("stop-printer")) { return i18n("Stop printer"); } return policy; } QString PrinterBehavior::operationPolicyString(const QString &policy) const { // TODO search for others policies of printer-error-policy-supported if (policy == QLatin1String("authenticated")) { return i18n("Authenticated"); } else if (policy == QLatin1String("default")) { return i18n("Default"); } return policy; } QString PrinterBehavior::jobSheetsString(const QString &policy) const { // TODO search for others policies of printer-error-policy-supported if (policy == QLatin1String("none")) { return i18n("None"); } else if (policy == QLatin1String("classified")) { return i18n("Classified"); } else if (policy == QLatin1String("confidential")) { return i18n("Confidential"); } else if (policy == QLatin1String("secret")) { return i18n("Secret"); } else if (policy == QLatin1String("standard")) { return i18n("Standard"); } else if (policy == QLatin1String("topsecret")) { return i18n("Topsecret"); } else if (policy == QLatin1String("unclassified")) { return i18n("Unclassified"); } return policy; } void PrinterBehavior::save() { if (m_changes) { QVariantHash changedValues = m_changedValues; // since a QStringList might be big we get it here instead // of adding it at edit time. if (ui->usersELB->property("different").toBool()) { QStringList list = ui->usersELB->items(); if (list.isEmpty()) { list << QLatin1String("all"); changedValues[KCUPS_REQUESTING_USER_NAME_ALLOWED] = list; } else { if (ui->allowRB->isChecked()) { changedValues[KCUPS_REQUESTING_USER_NAME_ALLOWED] = list; } else { changedValues[KCUPS_REQUESTING_USER_NAME_DENIED] = list; } } } QPointer request = new KCupsRequest; if (m_isClass) { request->addOrModifyClass(m_destName, changedValues); } else { request->addOrModifyPrinter(m_destName, changedValues); } request->waitTillFinished(); if (request) { if (!request->hasError()) { request->getPrinterAttributes(m_destName, m_isClass, neededValues()); request->waitTillFinished(); if (request && !request->hasError() && !request->printers().isEmpty()){ KCupsPrinter printer = request->printers().first(); setValues(printer); } } request->deleteLater(); } } } void PrinterBehavior::setRemote(bool remote) { ui->errorPolicyCB->setEnabled(!remote); ui->operationPolicyCB->setEnabled(!remote); ui->startingBannerCB->setEnabled(!remote); ui->endingBannerCB->setEnabled(!remote); ui->allowRB->setEnabled(!remote); ui->preventRB->setEnabled(!remote); ui->usersELB->setEnabled(!remote); } bool PrinterBehavior::hasChanges() { return m_changes; } QStringList PrinterBehavior::neededValues() const { - QStringList ret; - ret << KCUPS_JOB_SHEETS_DEFAULT; - ret << KCUPS_JOB_SHEETS_SUPPORTED; + return QStringList({ + KCUPS_JOB_SHEETS_DEFAULT, + KCUPS_JOB_SHEETS_SUPPORTED, - ret << KCUPS_PRINTER_ERROR_POLICY; - ret << KCUPS_PRINTER_ERROR_POLICY_SUPPORTED; + KCUPS_PRINTER_ERROR_POLICY, + KCUPS_PRINTER_ERROR_POLICY_SUPPORTED, - ret << KCUPS_PRINTER_OP_POLICY; - ret << KCUPS_PRINTER_OP_POLICY_SUPPORTED; + KCUPS_PRINTER_OP_POLICY, + KCUPS_PRINTER_OP_POLICY_SUPPORTED, - ret << KCUPS_REQUESTING_USER_NAME_ALLOWED; - ret << KCUPS_REQUESTING_USER_NAME_DENIED; - - return ret; + KCUPS_REQUESTING_USER_NAME_ALLOWED, + KCUPS_REQUESTING_USER_NAME_DENIED + }); } diff --git a/configure-printer/PrinterBehavior.h b/configure-printer/PrinterBehavior.h index 7e2e89e..00bf201 100644 --- a/configure-printer/PrinterBehavior.h +++ b/configure-printer/PrinterBehavior.h @@ -1,63 +1,63 @@ /*************************************************************************** * 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 PRINTER_BEHAVIOR_H #define PRINTER_BEHAVIOR_H #include "PrinterPage.h" #include "KCupsRequest.h" #include namespace Ui { class PrinterBehavior; } class PrinterBehavior : public PrinterPage { Q_OBJECT public: explicit PrinterBehavior(const QString &destName, bool isClass, QWidget *parent = 0); ~PrinterBehavior(); void setValues(const KCupsPrinter &printer); void setRemote(bool remote) Q_DECL_OVERRIDE; bool hasChanges() Q_DECL_OVERRIDE; QStringList neededValues() const Q_DECL_OVERRIDE; void save() Q_DECL_OVERRIDE; private slots: void currentIndexChangedCB(int index); void userListChanged(); private: QString errorPolicyString(const QString &policy) const; QString operationPolicyString(const QString &policy) const; QString jobSheetsString(const QString &policy) const; Ui::PrinterBehavior *ui; QString m_destName; bool m_isClass; QVariantHash m_changedValues; - int m_changes; + int m_changes = 0; }; #endif diff --git a/configure-printer/PrinterOptions.cpp b/configure-printer/PrinterOptions.cpp index 9046d66..23c57d6 100644 --- a/configure-printer/PrinterOptions.cpp +++ b/configure-printer/PrinterOptions.cpp @@ -1,827 +1,825 @@ /*************************************************************************** * 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. * * * * The save PPD snipet is from CUPS * * Copyright 2007-2009 by Apple Inc. * * Copyright 1997-2007 by Easy Software Products. * * * * 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 is converted from LGPL 2 in accordance with section 3 * * See http://www.cups.org/documentation.php/license.html * ***************************************************************************/ #include "PrinterOptions.h" #include "ui_PrinterOptions.h" #include "Debug.h" #include #include #include #include #include #include #include #include #include #include #include #define DEFAULT_CHOICE "defaultChoice" PrinterOptions::PrinterOptions(const QString &destName, bool isClass, bool isRemote, QWidget *parent) : PrinterPage(parent), ui(new Ui::PrinterOptions), m_destName(destName), m_isClass(isClass), - m_isRemote(isRemote), - m_ppd(NULL), - m_changes(0) + m_isRemote(isRemote) { ui->setupUi(this); reloadPPD(); } void PrinterOptions::on_autoConfigurePB_clicked() { QPointer request = new KCupsRequest; request->printCommand(m_destName, QLatin1String("AutoConfigure"), i18n("Set Default Options")); request->waitTillFinished(); if (request) { request->deleteLater(); } } void PrinterOptions::reloadPPD() { // The caller "owns" the file that is created and must unlink the returned filename. if (!m_filename.isEmpty()) { unlink(qUtf8Printable(m_filename)); } // remove all the options while (ui->verticalLayout->count()) { qCDebug(PM_CONFIGURE_PRINTER) << "removing" << ui->verticalLayout->count(); QLayoutItem *item = ui->verticalLayout->itemAt(0); ui->verticalLayout->removeItem(item); if (item->widget()) { item->widget()->deleteLater(); delete item; } else if (item->layout()) { qCDebug(PM_CONFIGURE_PRINTER) << "removing layout" << ui->verticalLayout->count(); // item->layout()->deleteLater(); } else if (item->spacerItem()) { delete item->spacerItem(); } } m_changes = 0; m_customValues.clear(); emit changed(false); QPointer request = new KCupsRequest; request->getPrinterPPD(m_destName); request->waitTillFinished(); if (!request) { return; } m_filename = request->printerPPD(); m_ppd = ppdOpenFile(qUtf8Printable(m_filename)); request->deleteLater(); if (m_ppd == NULL) { qCWarning(PM_CONFIGURE_PRINTER) << "Could not open ppd file:" << m_filename << request->errorMsg(); m_filename.clear(); return; } ppdLocalize(m_ppd); // select the default options on the ppd file ppdMarkDefaults(m_ppd); // TODO try to use QTextCodec aliases const char *lang_encoding; lang_encoding = m_ppd->lang_encoding; if (lang_encoding && !strcasecmp (lang_encoding, "ISOLatin1")) { m_codec = QTextCodec::codecForName("ISO-8859-1"); } else if (lang_encoding && !strcasecmp (lang_encoding, "ISOLatin2")) { m_codec = QTextCodec::codecForName("ISO-8859-2"); } else if (lang_encoding && !strcasecmp (lang_encoding, "ISOLatin5")) { m_codec = QTextCodec::codecForName("ISO-8859-5"); } else if (lang_encoding && !strcasecmp (lang_encoding, "JIS83-RKSJ")) { m_codec = QTextCodec::codecForName("SHIFT-JIS"); } else if (lang_encoding && !strcasecmp (lang_encoding, "MacStandard")) { m_codec = QTextCodec::codecForName("MACINTOSH"); } else if (lang_encoding && !strcasecmp (lang_encoding, "WindowsANSI")) { m_codec = QTextCodec::codecForName("WINDOWS-1252"); } else { // Guess m_codec = QTextCodec::codecForName(lang_encoding); } if (m_codec == 0) { m_codec = QTextCodec::codecForName("UTF-8"); } if (m_ppd->manufacturer) { m_make = m_codec->toUnicode(m_ppd->manufacturer); } if (m_ppd->nickname) { m_makeAndModel = m_codec->toUnicode(m_ppd->nickname); } ui->autoConfigurePB->hide(); ppd_attr_t *ppdattr; if (m_ppd->num_filters == 0 || ((ppdattr = ppdFindAttr(m_ppd, "cupsCommands", NULL)) != NULL && ppdattr->value && strstr(ppdattr->value, "AutoConfigure"))) { ui->autoConfigurePB->show(); } else { for (int i = 0; i < m_ppd->num_filters; i ++) { if (!strncmp(m_ppd->filters[i], "application/vnd.cups-postscript", 31)) { ui->autoConfigurePB->show(); break; } } } createGroups(); } void PrinterOptions::createGroups() { int i; ppd_group_t *group; // Iterate over the groups for (i = 0, group = m_ppd->groups; i < m_ppd->num_groups; i++, group++) { // The name of the group QString name = m_codec->toUnicode(group->name); // The humman name of the group QString text = m_codec->toUnicode(group->text); // The group box were the options will be laid out auto groupBox = new QGroupBox(text, ui->scrollArea); // Create the form layout to put options in auto gFormLayout = new QFormLayout(groupBox); gFormLayout->setFormAlignment(Qt::AlignCenter); groupBox->setLayout(gFormLayout); ui->verticalLayout->addWidget(groupBox); int j; ppd_option_t *option; // Iterate over the options in the group for (j = 0, option = group->options; j < group->num_options; j++, option++) { QString oKeyword = m_codec->toUnicode(option->keyword); QString oText = m_codec->toUnicode(option->text); QString oDefChoice = m_codec->toUnicode(option->defchoice); // The python system-config-printer skips this one // which has the same data as "PageSize", let's hope // they did the right thing if (oKeyword == QLatin1String("PageRegion")) { continue; } QWidget *optionW = 0; switch (option->ui) { case PPD_UI_BOOLEAN: optionW = pickBoolean(option, oKeyword, ui->scrollAreaWidgetContents); break; case PPD_UI_PICKMANY: optionW = pickMany(option, oKeyword, ui->scrollAreaWidgetContents); break; case PPD_UI_PICKONE: optionW = pickOne(option, oKeyword, ui->scrollAreaWidgetContents); break; default: qCWarning(PM_CONFIGURE_PRINTER) << "Option type not recognized: " << option->ui; // let's use the most common optionW = pickOne(option, oKeyword, ui->scrollAreaWidgetContents); break; } if (optionW) { // insert the option widget gFormLayout->addRow(oText, optionW); } } } ui->verticalLayout->addStretch(); } QWidget* PrinterOptions::pickBoolean(ppd_option_t *option, const QString &keyword, QWidget *parent) const { Q_UNUSED(keyword) auto widget = new QWidget(parent); auto layout = new QHBoxLayout(widget); auto radioGroup = new QButtonGroup(widget); widget->setLayout(layout); int i; ppd_choice_t *choice; QString defChoice = m_codec->toUnicode(option->defchoice); // Iterate over the choices in the option for (i = 0, choice = option->choices; i < option->num_choices; ++i, ++choice) { QString choiceName = m_codec->toUnicode(choice->choice); QString cText = m_codec->toUnicode(choice->text); auto button = new QRadioButton(cText, widget); button->setChecked(defChoice == choiceName); button->setProperty("choice", choiceName); // if we are in looking at a remote printer we can't save it button->setEnabled(!m_isRemote); layout->addWidget(button); radioGroup->addButton(button); } // store the default choice radioGroup->setProperty(DEFAULT_CHOICE, defChoice); radioGroup->setProperty("Keyword", keyword); connect(radioGroup, static_cast(&QButtonGroup::buttonClicked), this, &PrinterOptions::radioBtClicked); return widget; } void PrinterOptions::radioBtClicked(QAbstractButton *button) { QObject *radioGroup = sender(); bool isDifferent = radioGroup->property(DEFAULT_CHOICE).toString() != button->property("choice"); if (isDifferent != radioGroup->property("different").toBool()) { // it's different from the last time so add or remove changes isDifferent ? m_changes++ : m_changes--; radioGroup->setProperty("different", isDifferent); emit changed(m_changes); } QString keyword = radioGroup->property("Keyword").toString(); QString choice = button->property("choice").toString(); radioGroup->setProperty("currentChoice", choice); // TODO warning about conflicts // ppdMarkOption(m_ppd, // m_codec->fromUnicode(keyword), // m_codec->fromUnicode(choice)); // store the new value if (isDifferent) { m_customValues[keyword] = radioGroup; } else { m_customValues.remove(keyword); } } QWidget* PrinterOptions::pickMany(ppd_option_t *option, const QString &keyword, QWidget *parent) const { Q_UNUSED(keyword) auto listView = new QListView(parent); auto model = new QStandardItemModel(listView); listView->setModel(model); listView->setItemDelegate(new NoSelectionRectDelegate(listView)); int i; ppd_choice_t *choice; QString oDefChoice = m_codec->toUnicode(option->defchoice); // Iterate over the choices in the option for (i = 0, choice = option->choices; i < option->num_choices; ++i, ++choice) { QString cName = m_codec->toUnicode(choice->choice); QString cText = m_codec->toUnicode(choice->text); auto item = new QStandardItem(cText); item->setData(cName); item->setCheckable(true); item->setEditable(false); // TODO there is only ONE default choice, what about the other // Items selected?! item->setCheckState(oDefChoice == cName ? Qt::Checked : Qt::Unchecked); model->appendRow(item); } // if we are in looking at a remote printer we can't save it listView->setEnabled(!m_isRemote); return qobject_cast(listView); } QWidget* PrinterOptions::pickOne(ppd_option_t *option, const QString &keyword, QWidget *parent) const { int i; ppd_choice_t *choice; QString defChoice = m_codec->toUnicode(option->defchoice); auto comboBox = new QComboBox(parent); // Iterate over the choices in the option for (i = 0, choice = option->choices; i < option->num_choices; ++i, ++choice) { QString cName = m_codec->toUnicode(choice->choice); QString cText = m_codec->toUnicode(choice->text); comboBox->addItem(cText, cName); } // store the default choice comboBox->setProperty(DEFAULT_CHOICE, defChoice); comboBox->setProperty("Keyword", keyword); comboBox->setCurrentIndex(comboBox->findData(defChoice)); // connect the signal AFTER setCurrentIndex is called connect(comboBox, static_cast(&QComboBox::currentIndexChanged), this, &PrinterOptions::currentIndexChangedCB); // if we are in looking at a remote printer we can't save it comboBox->setEnabled(!m_isRemote); return qobject_cast(comboBox); } void PrinterOptions::currentIndexChangedCB(int index) { auto comboBox = qobject_cast(sender()); bool isDifferent = comboBox->property(DEFAULT_CHOICE).toString() != comboBox->itemData(index); if (isDifferent != comboBox->property("different").toBool()) { // it's different from the last time so add or remove changes isDifferent ? m_changes++ : m_changes--; comboBox->setProperty("different", isDifferent); emit changed(m_changes); } QString keyword = comboBox->property("Keyword").toString(); QString value = comboBox->itemData(index).toString(); comboBox->setProperty("currentChoice", value); // TODO warning about conflicts // ppdMarkOption(m_ppd, // m_codec->fromUnicode(keyword), // m_codec->fromUnicode(value)); // store the new value if (isDifferent) { m_customValues[keyword] = qobject_cast(comboBox); } else { m_customValues.remove(keyword); } } PrinterOptions::~PrinterOptions() { if (m_ppd != NULL) { ppdClose(m_ppd); } if (!m_filename.isEmpty()) { unlink(qUtf8Printable(m_filename)); } delete ui; } const char * /* O - Value of variable */ PrinterOptions::getVariable(const char *name) const /* I - Name of variable */ { QString keyword = m_codec->toUnicode(name); if (m_customValues.contains(keyword)) { QString value = m_customValues[keyword]->property("currentChoice").toString(); return m_codec->fromUnicode(value).constData(); } else { return NULL; } } /* * 'get_points()' - Get a value in points. */ double /* O - Number in points */ PrinterOptions::get_points(double number, /* I - Original number */ const char *uval) /* I - Units */ { if (!strcmp(uval, "mm")) /* Millimeters */ return (number * 72.0 / 25.4); else if (!strcmp(uval, "cm")) /* Centimeters */ return (number * 72.0 / 2.54); else if (!strcmp(uval, "in")) /* Inches */ return (number * 72.0); else if (!strcmp(uval, "ft")) /* Feet */ return (number * 72.0 * 12.0); else if (!strcmp(uval, "m")) /* Meters */ return (number * 72.0 / 0.0254); else /* Points */ return (number); } /* * 'get_option_value()' - Return the value of an option. * * This function also handles generation of custom option values. */ char * /* O - Value string or NULL on error */ PrinterOptions::get_option_value( ppd_file_t *ppd, /* I - PPD file */ const char *name, /* I - Option name */ char *buffer, /* I - String buffer */ size_t bufsize) const /* I - Size of buffer */ { char *bufptr, /* Pointer into buffer */ *bufend; /* End of buffer */ ppd_coption_t *coption; /* Custom option */ ppd_cparam_t *cparam; /* Current custom parameter */ char keyword[256]; /* Parameter name */ const char *val, /* Parameter value */ *uval; /* Units value */ long integer; /* Integer value */ double number, /* Number value */ number_points; /* Number in points */ /* * See if we have a custom option choice... */ if ((val = getVariable(name)) == NULL) { /* * Option not found! */ return (NULL); } else if (strcasecmp(val, "Custom") || (coption = ppdFindCustomOption(ppd, name)) == NULL) { /* * Not a custom choice... */ qstrncpy(buffer, val, bufsize); return (buffer); } /* * OK, we have a custom option choice, format it... */ *buffer = '\0'; if (!strcmp(coption->keyword, "PageSize")) { const char *lval; /* Length string value */ double width, /* Width value */ width_points, /* Width in points */ length, /* Length value */ length_points; /* Length in points */ val = getVariable("PageSize.Width"); lval = getVariable("PageSize.Height"); uval = getVariable("PageSize.Units"); if (!val || !lval || !uval || (width = strtod(val, NULL)) == 0.0 || (length = strtod(lval, NULL)) == 0.0 || (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") && strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m"))) { return (NULL); } width_points = get_points(width, uval); length_points = get_points(length, uval); if (width_points < ppd->custom_min[0] || width_points > ppd->custom_max[0] || length_points < ppd->custom_min[1] || length_points > ppd->custom_max[1]) { return (NULL); } snprintf(buffer, bufsize, "Custom.%gx%g%s", width, length, uval); } else if (cupsArrayCount(coption->params) == 1) { cparam = ppdFirstCustomParam(coption); snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword, cparam->name); if ((val = getVariable(keyword)) == NULL) return (NULL); switch (cparam->type) { case PPD_CUSTOM_CURVE : case PPD_CUSTOM_INVCURVE : case PPD_CUSTOM_REAL : if ((number = strtod(val, NULL)) == 0.0 || number < cparam->minimum.custom_real || number > cparam->maximum.custom_real) return (NULL); snprintf(buffer, bufsize, "Custom.%g", number); break; case PPD_CUSTOM_INT : if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN || integer == LONG_MAX || integer < cparam->minimum.custom_int || integer > cparam->maximum.custom_int) return (NULL); snprintf(buffer, bufsize, "Custom.%ld", integer); break; case PPD_CUSTOM_POINTS : snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword); if ((number = strtod(val, NULL)) == 0.0 || (uval = getVariable(keyword)) == NULL || (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") && strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m"))) return (NULL); number_points = get_points(number, uval); if (number_points < cparam->minimum.custom_points || number_points > cparam->maximum.custom_points) return (NULL); snprintf(buffer, bufsize, "Custom.%g%s", number, uval); break; case PPD_CUSTOM_PASSCODE : for (uval = val; *uval; ++uval) { if (!isdigit(*uval & 255)) { return (NULL); } } case PPD_CUSTOM_PASSWORD : case PPD_CUSTOM_STRING : integer = (long)strlen(val); if (integer < cparam->minimum.custom_string || integer > cparam->maximum.custom_string) { return (NULL); } snprintf(buffer, bufsize, "Custom.%s", val); break; } } else { const char *prefix = "{"; /* Prefix string */ bufptr = buffer; bufend = buffer + bufsize; for (cparam = ppdFirstCustomParam(coption); cparam; cparam = ppdNextCustomParam(coption)) { snprintf(keyword, sizeof(keyword), "%s.%s", coption->keyword, cparam->name); if ((val = getVariable(keyword)) == NULL) { return (NULL); } snprintf(bufptr, bufend - bufptr, "%s%s=", prefix, cparam->name); bufptr += strlen(bufptr); prefix = " "; switch (cparam->type) { case PPD_CUSTOM_CURVE : case PPD_CUSTOM_INVCURVE : case PPD_CUSTOM_REAL : if ((number = strtod(val, NULL)) == 0.0 || number < cparam->minimum.custom_real || number > cparam->maximum.custom_real) return (NULL); snprintf(bufptr, bufend - bufptr, "%g", number); break; case PPD_CUSTOM_INT : if (!*val || (integer = strtol(val, NULL, 10)) == LONG_MIN || integer == LONG_MAX || integer < cparam->minimum.custom_int || integer > cparam->maximum.custom_int) { return (NULL); } snprintf(bufptr, bufend - bufptr, "%ld", integer); break; case PPD_CUSTOM_POINTS : snprintf(keyword, sizeof(keyword), "%s.Units", coption->keyword); if ((number = strtod(val, NULL)) == 0.0 || (uval = getVariable(keyword)) == NULL || (strcmp(uval, "pt") && strcmp(uval, "in") && strcmp(uval, "ft") && strcmp(uval, "cm") && strcmp(uval, "mm") && strcmp(uval, "m"))) { return (NULL); } number_points = get_points(number, uval); if (number_points < cparam->minimum.custom_points || number_points > cparam->maximum.custom_points) { return (NULL); } snprintf(bufptr, bufend - bufptr, "%g%s", number, uval); break; case PPD_CUSTOM_PASSCODE : for (uval = val; *uval; uval ++) { if (!isdigit(*uval & 255)) { return (NULL); } } case PPD_CUSTOM_PASSWORD : case PPD_CUSTOM_STRING : integer = (long)strlen(val); if (integer < cparam->minimum.custom_string || integer > cparam->maximum.custom_string) { return (NULL); } if ((bufptr + 2) > bufend) { return (NULL); } bufend --; *bufptr++ = '\"'; while (*val && bufptr < bufend) { if (*val == '\\' || *val == '\"') { if ((bufptr + 1) >= bufend) { return (NULL); } *bufptr++ = '\\'; } *bufptr++ = *val++; } if (bufptr >= bufend) { return (NULL); } *bufptr++ = '\"'; *bufptr = '\0'; bufend ++; break; } bufptr += strlen(bufptr); } if (bufptr == buffer || (bufend - bufptr) < 2) { return (NULL); } strcpy(bufptr, "}"); } return (buffer); } void PrinterOptions::save() { char tempfile[1024]; const char *var; cups_file_t *in, /* Input file */ *out; /* Output file */ char line[1024], /* Line from PPD file */ value[1024], /* Option value */ keyword[1024], /* Keyword from Default line */ *keyptr; /* Pointer into keyword... */ // copy cups-1.4.2/cgi-bin line 3779 if (!m_filename.isEmpty()) { out = cupsTempFile2(tempfile, sizeof(tempfile)); in = cupsFileOpen(qUtf8Printable(m_filename), "r"); if (!in || !out) { if (in) { cupsFileClose(in); } if (out) { cupsFileClose(out); unlink(tempfile); } // TODO add a KMessageBox::error return; } while (cupsFileGets(in, line, sizeof(line))) { if (!strncmp(line, "*cupsProtocol:", 14)) { continue; } else if (strncmp(line, "*Default", 8)) { cupsFilePrintf(out, "%s\n", line); } else { /* * Get default option name... */ qstrncpy(keyword, line + 8, sizeof(keyword)); for (keyptr = keyword; *keyptr; keyptr ++) { if (*keyptr == ':' || isspace(*keyptr & 255)) { break; } } *keyptr = '\0'; if (!strcmp(keyword, "PageRegion") || !strcmp(keyword, "PaperDimension") || !strcmp(keyword, "ImageableArea")) { var = get_option_value(m_ppd, "PageSize", value, sizeof(value)); } else { var = get_option_value(m_ppd, keyword, value, sizeof(value)); } if (!var) { cupsFilePrintf(out, "%s\n", line); } else { cupsFilePrintf(out, "*Default%s: %s\n", keyword, var); } } } cupsFileClose(in); cupsFileClose(out); } else { // TODO add a KMessageBox::error qCWarning(PM_CONFIGURE_PRINTER) << "No printer PPD file set, can't save options."; return; } QVariantHash values; // we need null values QPointer request = new KCupsRequest; if (m_isClass) { request->addOrModifyClass(m_destName, values); } else { request->addOrModifyPrinter(m_destName, values, QString::fromUtf8(tempfile)); } // Disable the widget till the request is processed // Otherwise the user might change something in the ui // which won't be saved but the apply but when the request // finishes we will set the current options as default setEnabled(false); request->waitTillFinished(); // unlink the file unlink(tempfile); if (request) { setEnabled(true); if (!request->hasError()) { // if we succefully save the new ppd we need now to // clear our changes - QHash::const_iterator i = m_customValues.constBegin(); + auto i = m_customValues.constBegin(); while (i != m_customValues.constEnd()) { - QString currentChoice; - currentChoice = i.value()->property("currentChoice").toString(); + QObject *obj = i.value(); + const QString currentChoice = obj->property("currentChoice").toString(); // Store the current choice as the default one - i.value()->setProperty(DEFAULT_CHOICE, currentChoice); - i.value()->setProperty("currentChoice", QVariant()); - i.value()->setProperty("different", false); + obj->setProperty(DEFAULT_CHOICE, currentChoice); + obj->setProperty("currentChoice", QVariant()); + obj->setProperty("different", false); ++i; } m_changes = 0; m_customValues.clear(); emit changed(false); } request->deleteLater(); } } bool PrinterOptions::hasChanges() { return m_changes; } QString PrinterOptions::currentMake() const { return m_make; } QString PrinterOptions::currentMakeAndModel() const { return m_makeAndModel; } diff --git a/configure-printer/PrinterOptions.h b/configure-printer/PrinterOptions.h index 1022fc5..ee47b36 100644 --- a/configure-printer/PrinterOptions.h +++ b/configure-printer/PrinterOptions.h @@ -1,77 +1,77 @@ /*************************************************************************** * 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 PRINTER_OPTIONS_H #define PRINTER_OPTIONS_H #include "PrinterPage.h" #include #include #include #include namespace Ui { class PrinterOptions; } class PrinterOptions : public PrinterPage { Q_OBJECT public: explicit PrinterOptions(const QString &destName, bool isClass, bool isRemote, QWidget *parent = 0); ~PrinterOptions(); bool hasChanges() Q_DECL_OVERRIDE; QString currentMake() const; QString currentMakeAndModel() const; void reloadPPD(); void save() Q_DECL_OVERRIDE; private slots: void on_autoConfigurePB_clicked(); void currentIndexChangedCB(int index); void radioBtClicked(QAbstractButton *button); private: QWidget* pickBoolean(ppd_option_t *option, const QString &keyword, QWidget *parent) const; QWidget* pickMany(ppd_option_t *option, const QString &keyword, QWidget *parent) const; QWidget* pickOne(ppd_option_t *option, const QString &keyword, QWidget *parent) const; const char* getVariable(const char *name) const; char * get_option_value(ppd_file_t *ppd, const char *name, char *buffer, size_t bufsize) const; static double get_points(double number, const char *uval); void createGroups(); Ui::PrinterOptions *ui; QString m_destName; bool m_isClass; bool m_isRemote; QString m_filename; - ppd_file_t *m_ppd; - int m_changes; + ppd_file_t *m_ppd = nullptr; + int m_changes = 0; QTextCodec *m_codec; QHash m_customValues; QString m_make, m_makeAndModel; }; #endif diff --git a/configure-printer/main.cpp b/configure-printer/main.cpp index e638b4e..8ad8a00 100644 --- a/configure-printer/main.cpp +++ b/configure-printer/main.cpp @@ -1,68 +1,68 @@ /*************************************************************************** * 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 "ConfigurePrinter.h" #include #include #include #include #include #include -#include +#include "Debug.h" int main(int argc, char **argv) { ConfigurePrinter app(argc, argv); app.setOrganizationDomain(QLatin1String("org.kde")); KAboutData aboutData(QLatin1String("ConfigurePrinter"), i18n("Configure Printer"), QLatin1String(PM_VERSION), i18n("ConfigurePrinter"), KAboutLicense::GPL, i18n("(C) 2010-2018 Daniel Nicoletti")); aboutData.addAuthor(QStringLiteral("Daniel Nicoletti"), QString(), QLatin1String("dantti12@gmail.com")); aboutData.addAuthor(QStringLiteral("Jan Grulich"), i18n("Port to Qt 5 / Plasma 5"), QStringLiteral("jgrulich@redhat.com")); KAboutData::setApplicationData(aboutData); KDBusService service(KDBusService::Unique); QCommandLineParser parser; aboutData.setupCommandLine(&parser); parser.addVersionOption(); parser.addHelpOption(); parser.addPositionalArgument(QLatin1String("printer"), i18n("Printer to be configured")); parser.process(app); aboutData.processCommandLine(&parser); const QStringList args = parser.positionalArguments(); if (args.count() == 1) { QString printerName = args.at(0); app.configurePrinter(printerName); } else { - qWarning() << "No printer was specified"; + qCWarning(PM_CONFIGURE_PRINTER) << "No printer was specified"; return 1; } return app.exec(); } diff --git a/libkcups/ClassListWidget.cpp b/libkcups/ClassListWidget.cpp index c9c90de..219b25a 100644 --- a/libkcups/ClassListWidget.cpp +++ b/libkcups/ClassListWidget.cpp @@ -1,185 +1,182 @@ /*************************************************************************** * Copyright (C) 2010-2018 by Daniel Nicoletti * * * * 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 "ClassListWidget.h" #include "SelectMakeModel.h" #include "KCupsRequest.h" #include "NoSelectionRectDelegate.h" #include #include #include #include #include -ClassListWidget::ClassListWidget(QWidget *parent) : - QListView(parent), - m_request(0), - m_showClasses(false) +ClassListWidget::ClassListWidget(QWidget *parent) : QListView(parent) { KConfigDialogManager::changedMap()->insert(QLatin1String("ClassListWidget"), SIGNAL(changed(QString))); m_model = new QStandardItemModel(this); setModel(m_model); setItemDelegate(new NoSelectionRectDelegate(this)); // Setup the busy cursor m_busySeq = new KPixmapSequenceOverlayPainter(this); m_busySeq->setSequence(KPixmapSequence(QLatin1String("process-working"), KIconLoader::SizeSmallMedium)); m_busySeq->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); m_busySeq->setWidget(viewport()); connect(m_model, &QStandardItemModel::dataChanged, this, &ClassListWidget::modelChanged); m_delayedInit.setInterval(0); m_delayedInit.setSingleShot(true); connect(&m_delayedInit, &QTimer::timeout, this, &ClassListWidget::init); m_delayedInit.start(); } ClassListWidget::~ClassListWidget() { } void ClassListWidget::init() { m_busySeq->start(); // Start spining m_model->clear(); QStringList att; att << KCUPS_PRINTER_NAME; att << KCUPS_PRINTER_URI_SUPPORTED; // Get destinations with these masks m_request = new KCupsRequest; connect(m_request, &KCupsRequest::finished, this, &ClassListWidget::loadFinished); if (m_showClasses) { m_request->getPrinters(att); } else { m_request->getPrinters(att, CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT); } } void ClassListWidget::loadFinished(KCupsRequest *request) { // If we have an old request running discard it's result and get a new one if (m_request != request) { request->deleteLater(); return; } m_busySeq->stop(); // Stop spining const KCupsPrinters printers = request->printers(); request->deleteLater(); m_request = 0; for (const KCupsPrinter &printer : printers) { QString destName = printer.name(); if (destName != m_printerName) { auto item = new QStandardItem; item->setText(destName); item->setCheckable(true); item->setEditable(false); item->setData(printer.uriSupported()); updateItemState(item); m_model->appendRow(item); } } modelChanged(); } void ClassListWidget::modelChanged() { QStringList currentMembers = currentSelected(false); m_changed = m_selectedPrinters != currentMembers; emit changed(selectedPrinters()); emit changed(m_changed); } QStringList ClassListWidget::currentSelected(bool uri) const { QStringList currentMembers; for (int i = 0; i < m_model->rowCount(); i++) { QStandardItem *item = m_model->item(i); if (item && item->checkState() == Qt::Checked) { if (uri) { currentMembers << item->data().toString(); } else { currentMembers << item->text(); } } } currentMembers.sort(); return currentMembers; } void ClassListWidget::updateItemState(QStandardItem *item) const { if (m_selectedPrinters.contains(item->text())) { item->setCheckState(Qt::Checked); } else { item->setCheckState(Qt::Unchecked); } } bool ClassListWidget::hasChanges() { return m_changed; } void ClassListWidget::setPrinter(const QString &printer) { if (m_printerName != printer) { m_printerName = printer; m_delayedInit.start(); } } QString ClassListWidget::selectedPrinters() const { return currentSelected(false).join(QLatin1String("|")); } void ClassListWidget::setSelectedPrinters(const QString &selected) { m_selectedPrinters = selected.split(QLatin1Char('|')); m_selectedPrinters.sort(); m_delayedInit.start(); } bool ClassListWidget::showClasses() const { return m_showClasses; } void ClassListWidget::setShowClasses(bool enable) { if (m_showClasses != enable) { m_showClasses = enable; m_delayedInit.start(); } } diff --git a/libkcups/ClassListWidget.h b/libkcups/ClassListWidget.h index 09aa78a..30349c3 100644 --- a/libkcups/ClassListWidget.h +++ b/libkcups/ClassListWidget.h @@ -1,70 +1,70 @@ /*************************************************************************** * 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 CLASS_LIST_WIDGET_H #define CLASS_LIST_WIDGET_H #include #include #include #include class KCupsRequest; class Q_DECL_EXPORT ClassListWidget : public QListView { Q_OBJECT Q_PROPERTY(QString selectedPrinters READ selectedPrinters WRITE setSelectedPrinters USER true) Q_PROPERTY(bool showClasses READ showClasses WRITE setShowClasses) public: explicit ClassListWidget(QWidget *parent = 0); ~ClassListWidget(); bool hasChanges(); void setPrinter(const QString &printer); QString selectedPrinters() const; void setSelectedPrinters(const QString &selected); bool showClasses() const; void setShowClasses(bool enable); QStringList currentSelected(bool uri) const; signals: void changed(bool changed); void changed(const QString &selected); private slots: void init(); void loadFinished(KCupsRequest *request); void modelChanged(); private: void updateItemState(QStandardItem *item) const; QString m_printerName; QStringList m_selectedPrinters; KPixmapSequenceOverlayPainter *m_busySeq; - KCupsRequest *m_request; + KCupsRequest *m_request = nullptr; bool m_changed; - bool m_showClasses; + bool m_showClasses = false; QStandardItemModel *m_model; QTimer m_delayedInit; }; #endif diff --git a/libkcups/JobModel.cpp b/libkcups/JobModel.cpp index 46fde97..5f9cd69 100644 --- a/libkcups/JobModel.cpp +++ b/libkcups/JobModel.cpp @@ -1,632 +1,628 @@ /*************************************************************************** * Copyright (C) 2010-2018 by Daniel Nicoletti * * * * 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 "JobModel.h" #include #include #include #include #include #include #include #include #include #include #include -#include - -JobModel::JobModel(QObject *parent) : - QStandardItemModel(parent), - m_jobRequest(0), - m_whichjobs(CUPS_WHICHJOBS_ACTIVE), - m_parentId(0) +JobModel::JobModel(QObject *parent) : QStandardItemModel(parent) { setHorizontalHeaderItem(ColStatus, new QStandardItem(i18n("Status"))); setHorizontalHeaderItem(ColName, new QStandardItem(i18n("Name"))); setHorizontalHeaderItem(ColUser, new QStandardItem(i18n("User"))); setHorizontalHeaderItem(ColCreated, new QStandardItem(i18n("Created"))); setHorizontalHeaderItem(ColCompleted, new QStandardItem(i18n("Completed"))); setHorizontalHeaderItem(ColPages, new QStandardItem(i18n("Pages"))); setHorizontalHeaderItem(ColProcessed, new QStandardItem(i18n("Processed"))); setHorizontalHeaderItem(ColSize, new QStandardItem(i18n("Size"))); setHorizontalHeaderItem(ColStatusMessage, new QStandardItem(i18n("Status Message"))); setHorizontalHeaderItem(ColPrinter, new QStandardItem(i18n("Printer"))); setHorizontalHeaderItem(ColFromHost, new QStandardItem(i18n("From Hostname"))); // Setup the attributes we want from jobs - m_jobAttributes << KCUPS_JOB_ID; - m_jobAttributes << KCUPS_JOB_NAME; - m_jobAttributes << KCUPS_JOB_K_OCTETS; - m_jobAttributes << KCUPS_JOB_K_OCTETS_PROCESSED; - m_jobAttributes << KCUPS_JOB_STATE; - m_jobAttributes << KCUPS_TIME_AT_COMPLETED; - m_jobAttributes << KCUPS_TIME_AT_CREATION; - m_jobAttributes << KCUPS_TIME_AT_PROCESSING; - m_jobAttributes << KCUPS_JOB_PRINTER_URI; - m_jobAttributes << KCUPS_JOB_ORIGINATING_USER_NAME; - m_jobAttributes << KCUPS_JOB_ORIGINATING_HOST_NAME; - m_jobAttributes << KCUPS_JOB_MEDIA_PROGRESS; - m_jobAttributes << KCUPS_JOB_MEDIA_SHEETS; - m_jobAttributes << KCUPS_JOB_MEDIA_SHEETS_COMPLETED; - m_jobAttributes << KCUPS_JOB_PRINTER_STATE_MESSAGE; - m_jobAttributes << KCUPS_JOB_PRESERVED; + m_jobAttributes = QStringList{ + KCUPS_JOB_ID, + KCUPS_JOB_NAME, + KCUPS_JOB_K_OCTETS, + KCUPS_JOB_K_OCTETS_PROCESSED, + KCUPS_JOB_STATE, + KCUPS_TIME_AT_COMPLETED, + KCUPS_TIME_AT_CREATION, + KCUPS_TIME_AT_PROCESSING, + KCUPS_JOB_PRINTER_URI, + KCUPS_JOB_ORIGINATING_USER_NAME, + KCUPS_JOB_ORIGINATING_HOST_NAME, + KCUPS_JOB_MEDIA_PROGRESS, + KCUPS_JOB_MEDIA_SHEETS, + KCUPS_JOB_MEDIA_SHEETS_COMPLETED, + KCUPS_JOB_PRINTER_STATE_MESSAGE, + KCUPS_JOB_PRESERVED + }; m_roles = QStandardItemModel::roleNames(); m_roles[RoleJobId] = "jobId"; m_roles[RoleJobState] = "jobState"; m_roles[RoleJobName] = "jobName"; m_roles[RoleJobPages] = "jobPages"; m_roles[RoleJobSize] = "jobSize"; m_roles[RoleJobOwner] = "jobOwner"; m_roles[RoleJobCreatedAt] = "jobCreatedAt"; m_roles[RoleJobIconName] = "jobIconName"; m_roles[RoleJobCancelEnabled] = "jobCancelEnabled"; m_roles[RoleJobHoldEnabled] = "jobHoldEnabled"; m_roles[RoleJobReleaseEnabled] = "jobReleaseEnabled"; m_roles[RoleJobRestartEnabled] = "jobRestartEnabled"; m_roles[RoleJobPrinter] = "jobPrinter"; m_roles[RoleJobOriginatingHostName] = "jobFrom"; // This is emitted when a job change it's state connect(KCupsConnection::global(), &KCupsConnection::jobState, this, &JobModel::insertUpdateJob); // This is emitted when a job is created connect(KCupsConnection::global(), &KCupsConnection::jobCreated, this, &JobModel::insertUpdateJob); // This is emitted when a job is stopped connect(KCupsConnection::global(), &KCupsConnection::jobStopped, this, &JobModel::insertUpdateJob); // This is emitted when a job has it's config changed connect(KCupsConnection::global(), &KCupsConnection::jobConfigChanged, this, &JobModel::insertUpdateJob); // This is emitted when a job change it's progress connect(KCupsConnection::global(), &KCupsConnection::jobProgress, this, &JobModel::insertUpdateJob); // This is emitted when a printer is removed connect(KCupsConnection::global(), &KCupsConnection::jobCompleted, this, &JobModel::jobCompleted); connect(KCupsConnection::global(), &KCupsConnection::serverAudit, this, &JobModel::getJobs); connect(KCupsConnection::global(), &KCupsConnection::serverStarted, this, &JobModel::getJobs); connect(KCupsConnection::global(), &KCupsConnection::serverStopped, this, &JobModel::getJobs); connect(KCupsConnection::global(), &KCupsConnection::serverRestarted, this, &JobModel::getJobs); } void JobModel::setParentWId(WId parentId) { m_parentId = parentId; } void JobModel::init(const QString &destName) { m_destName = destName; // Get all jobs getJobs(); } void JobModel::hold(const QString &printerName, int jobId) { QPointer request = new KCupsRequest; request->holdJob(printerName, jobId); request->waitTillFinished(); if (request) { request->deleteLater(); } } void JobModel::release(const QString &printerName, int jobId) { QPointer request = new KCupsRequest; request->releaseJob(printerName, jobId); request->waitTillFinished(); if (request) { request->deleteLater(); } } void JobModel::cancel(const QString &printerName, int jobId) { QPointer request = new KCupsRequest; request->cancelJob(printerName, jobId); request->waitTillFinished(); if (request) { request->deleteLater(); } } void JobModel::move(const QString &printerName, int jobId, const QString &toPrinterName) { QPointer request = new KCupsRequest; request->moveJob(printerName, jobId, toPrinterName); request->waitTillFinished(); if (request) { request->deleteLater(); } } void JobModel::getJobs() { if (m_jobRequest) { return; } m_jobRequest = new KCupsRequest; connect(m_jobRequest, &KCupsRequest::finished, this, &JobModel::getJobFinished); m_jobRequest->getJobs(m_destName, false, m_whichjobs, m_jobAttributes); m_processingJob.clear(); } void JobModel::getJobFinished(KCupsRequest *request) { if (request) { if (request->hasError()) { // clear the model after so that the proper widget can be shown clear(); } else { - KCupsJobs jobs = request->jobs(); + const KCupsJobs jobs = request->jobs(); qCDebug(LIBKCUPS) << jobs.size(); for (int i = 0; i < jobs.size(); ++i) { if (jobs.at(i).state() == IPP_JOB_PROCESSING) { m_processingJob = jobs.at(i).name(); } // try to find the job row int job_row = jobRow(jobs.at(i).id()); if (job_row == -1) { // not found, insert new one insertJob(i, jobs.at(i)); } else if (job_row == i) { // update the job updateJob(i, jobs.at(i)); } else { // found at wrong position // take it and insert on the right position QList row = takeRow(job_row); insertRow(i, row); updateJob(i, jobs.at(i)); } } // remove old printers // The above code starts from 0 and make sure // dest == modelIndex(x) and if it's not the // case it either inserts or moves it. // so any item > num_jobs can be safely deleted while (rowCount() > jobs.size()) { removeRow(rowCount() - 1); } } request->deleteLater(); } else { qCWarning(LIBKCUPS) << "Should not be called from a non KCupsRequest class" << sender(); } m_jobRequest = 0; } void JobModel::jobCompleted(const QString &text, const QString &printerUri, const QString &printerName, uint printerState, const QString &printerStateReasons, bool printerIsAcceptingJobs, uint jobId, uint jobState, const QString &jobStateReasons, const QString &jobName, uint jobImpressionsCompleted) { // REALLY? all these parameters just to say foo was deleted?? Q_UNUSED(text) Q_UNUSED(printerUri) Q_UNUSED(printerName) Q_UNUSED(printerState) Q_UNUSED(printerStateReasons) Q_UNUSED(printerIsAcceptingJobs) Q_UNUSED(jobId) Q_UNUSED(jobState) Q_UNUSED(jobStateReasons) Q_UNUSED(jobName) Q_UNUSED(jobImpressionsCompleted) // We grab all jobs again getJobs(); } void JobModel::insertUpdateJob(const QString &text, const QString &printerUri, const QString &printerName, uint printerState, const QString &printerStateReasons, bool printerIsAcceptingJobs, uint jobId, uint jobState, const QString &jobStateReasons, const QString &jobName, uint jobImpressionsCompleted) { // REALLY? all these parameters just to say foo was created?? Q_UNUSED(text) Q_UNUSED(printerUri) Q_UNUSED(printerName) Q_UNUSED(printerState) Q_UNUSED(printerStateReasons) Q_UNUSED(printerIsAcceptingJobs) Q_UNUSED(jobId) Q_UNUSED(jobState) Q_UNUSED(jobStateReasons) Q_UNUSED(jobName) Q_UNUSED(jobImpressionsCompleted) // We grab all jobs again getJobs(); } void JobModel::insertJob(int pos, const KCupsJob &job) { // insert the first column which has the job state and id QList row; ipp_jstate_e jobState = job.state(); auto statusItem = new QStandardItem(jobStatus(jobState)); statusItem->setData(jobState, RoleJobState); statusItem->setData(job.id(), RoleJobId); statusItem->setData(job.name(), RoleJobName); statusItem->setData(job.originatingUserName(), RoleJobOwner); statusItem->setData(job.originatingHostName(), RoleJobOriginatingHostName); QString size = KFormat().formatByteSize(job.size()); statusItem->setData(size, RoleJobSize); QString createdAt = QLocale().toString(job.createdAt()); statusItem->setData(createdAt, RoleJobCreatedAt); // TODO move the update code before the insert and reuse some code... statusItem->setData(KCupsJob::iconName(jobState), RoleJobIconName); statusItem->setData(KCupsJob::cancelEnabled(jobState), RoleJobCancelEnabled); statusItem->setData(KCupsJob::holdEnabled(jobState), RoleJobHoldEnabled); statusItem->setData(KCupsJob::releaseEnabled(jobState), RoleJobReleaseEnabled); statusItem->setData(job.reprintEnabled(), RoleJobRestartEnabled); QString pages = QString::number(job.pages()); if (job.processedPages()) { - pages = QString::number(job.processedPages()) % QLatin1Char('/') % QString::number(job.processedPages()); + pages = QString::number(job.processedPages()) + QLatin1Char('/') + QString::number(job.processedPages()); } if (statusItem->data(RoleJobPages) != pages) { statusItem->setData(pages, RoleJobPages); } row << statusItem; for (int i = ColName; i < LastColumn; i++) { // adds all Items to the model row << new QStandardItem; } // insert the whole row insertRow(pos, row); // update the items updateJob(pos, job); } void JobModel::updateJob(int pos, const KCupsJob &job) { // Job Status & internal dataipp_jstate_e ipp_jstate_e jobState = job.state(); if (item(pos, ColStatus)->data(RoleJobState).toInt() != jobState) { item(pos, ColStatus)->setText(jobStatus(jobState)); item(pos, ColStatus)->setData(static_cast(jobState), RoleJobState); item(pos, ColStatus)->setData(KCupsJob::iconName(jobState), RoleJobIconName); item(pos, ColStatus)->setData(KCupsJob::cancelEnabled(jobState), RoleJobCancelEnabled); item(pos, ColStatus)->setData(KCupsJob::holdEnabled(jobState), RoleJobHoldEnabled); item(pos, ColStatus)->setData(KCupsJob::releaseEnabled(jobState), RoleJobReleaseEnabled); item(pos, ColStatus)->setData(job.reprintEnabled(), RoleJobRestartEnabled); } QString pages = QString::number(job.pages()); if (job.processedPages()) { - pages = QString::number(job.processedPages()) % QLatin1Char('/') % QString::number(job.processedPages()); + pages = QString::number(job.processedPages()) + QLatin1Char('/') + QString::number(job.processedPages()); } if (item(pos, ColStatus)->data(RoleJobPages) != pages) { item(pos, ColStatus)->setData(pages, RoleJobPages); } // internal dest name & column QString destName = job.printer(); if (item(pos, ColStatus)->data(RoleJobPrinter).toString() != destName) { item(pos, ColStatus)->setData(destName, RoleJobPrinter); // Column job printer Name item(pos, ColPrinter)->setText(destName); } // job name QString jobName = job.name(); if (item(pos, ColName)->text() != jobName) { item(pos, ColStatus)->setData(jobName, RoleJobName); item(pos, ColName)->setText(jobName); } // owner of the job // try to get the full user name QString userString = job.originatingUserName(); KUser user(userString); if (user.isValid() && !user.property(KUser::FullName).toString().isEmpty()) { userString = user.property(KUser::FullName).toString(); } // user name if (item(pos, ColUser)->text() != userString) { item(pos, ColUser)->setText(userString); } // when it was created QDateTime timeAtCreation = job.createdAt(); if (item(pos, ColCreated)->data(Qt::DisplayRole).toDateTime() != timeAtCreation) { item(pos, ColCreated)->setData(timeAtCreation, Qt::DisplayRole); } // when it was completed QDateTime completedAt = job.completedAt(); if (item(pos, ColCompleted)->data(Qt::DisplayRole).toDateTime() != completedAt) { if (!completedAt.isNull()) { item(pos, ColCompleted)->setData(completedAt, Qt::DisplayRole); } else { // Clean the data might happen when the job is restarted item(pos, ColCompleted)->setText(QString()); } } // job pages int completedPages = job.processedPages(); if (item(pos, ColPages)->data(Qt::UserRole) != completedPages) { item(pos, ColPages)->setData(completedPages, Qt::UserRole); item(pos, ColPages)->setText(QString::number(completedPages)); } // when it was precessed QDateTime timeAtProcessing = job.processedAt(); if (item(pos, ColProcessed)->data(Qt::DisplayRole).toDateTime() != timeAtProcessing) { if (!timeAtProcessing.isNull()) { item(pos, ColProcessed)->setData(timeAtProcessing, Qt::DisplayRole); } else { // Clean the data might happen when the job is restarted item(pos, ColCompleted)->setText(QString()); } } int jobSize = job.size(); if (item(pos, ColSize)->data(Qt::UserRole) != jobSize) { item(pos, ColSize)->setData(jobSize, Qt::UserRole); item(pos, ColSize)->setText(KFormat().formatByteSize(jobSize)); } // job printer state message QString stateMessage = job.stateMsg(); if (item(pos, ColStatusMessage)->text() != stateMessage) { item(pos, ColStatusMessage)->setText(stateMessage); } // owner of the job // try to get the full user name QString originatingHostName = job.originatingHostName(); if (item(pos, ColFromHost)->text() != originatingHostName) { item(pos, ColFromHost)->setText(originatingHostName); } } QStringList JobModel::mimeTypes() const { return { QStringLiteral("application/x-cupsjobs") }; } Qt::DropActions JobModel::supportedDropActions() const { return Qt::MoveAction; } QMimeData* JobModel::mimeData(const QModelIndexList &indexes) const { auto mimeData = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); for (const QModelIndex &index : indexes) { if (index.isValid() && index.column() == 0) { // serialize the jobId and fromDestName stream << data(index, RoleJobId).toInt() << data(index, RoleJobPrinter).toString() << item(index.row(), ColName)->text(); } } mimeData->setData(QLatin1String("application/x-cupsjobs"), encodedData); return mimeData; } bool JobModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { Q_UNUSED(row) Q_UNUSED(column) Q_UNUSED(parent) if (action == Qt::IgnoreAction) { return true; } if (!data->hasFormat(QLatin1String("application/x-cupsjobs"))) { return false; } QByteArray encodedData = data->data(QLatin1String("application/x-cupsjobs")); QDataStream stream(&encodedData, QIODevice::ReadOnly); bool ret = false; while (!stream.atEnd()) { QString fromDestName, displayName; int jobId; // get the jobid and the from dest name stream >> jobId >> fromDestName >> displayName; if (fromDestName == m_destName) { continue; } QPointer request = new KCupsRequest; request->moveJob(fromDestName, jobId, m_destName); request->waitTillFinished(); if (request) { if (request->hasError()) { // failed to move one job // we return here to avoid more password tries KMessageBox::detailedSorryWId(m_parentId, i18n("Failed to move '%1' to '%2'", displayName, m_destName), request->errorMsg(), i18n("Failed")); } request->deleteLater(); ret = !request->hasError(); } } return ret; } QHash JobModel::roleNames() const { return m_roles; } KCupsRequest* JobModel::modifyJob(int row, JobAction action, const QString &newDestName, const QModelIndex &parent) { Q_UNUSED(parent) if (row < 0 || row >= rowCount()) { qCWarning(LIBKCUPS) << "Row number is invalid:" << row; return 0; } QStandardItem *job = item(row, ColStatus); int jobId = job->data(RoleJobId).toInt(); QString destName = job->data(RoleJobPrinter).toString(); // ignore some jobs ipp_jstate_t state = static_cast(job->data(RoleJobState).toInt()); if ((state == IPP_JOB_HELD && action == Hold) || (state == IPP_JOB_CANCELED && action == Cancel) || (state != IPP_JOB_HELD && action == Release)) { return 0; } auto request = new KCupsRequest; switch (action) { case Cancel: request->cancelJob(destName, jobId); break; case Hold: request->holdJob(destName, jobId); break; case Release: request->releaseJob(destName, jobId); break; case Reprint: request->restartJob(destName, jobId); break; case Move: request->moveJob(destName, jobId, newDestName); break; default: qCWarning(LIBKCUPS) << "Unknown ACTION called!!!" << action; return 0; } return request; } int JobModel::jobRow(int jobId) { // find the position of the jobId inside the model for (int i = 0; i < rowCount(); i++) { if (jobId == item(i)->data(RoleJobId).toInt()) { return i; } } // -1 if not found return -1; } QString JobModel::jobStatus(ipp_jstate_e job_state) { switch (job_state) { case IPP_JOB_PENDING : return i18n("Pending"); case IPP_JOB_HELD : return i18n("On hold"); case IPP_JOB_PROCESSING : return QLatin1String("-"); case IPP_JOB_STOPPED : return i18n("Stopped"); case IPP_JOB_CANCELED : return i18n("Canceled"); case IPP_JOB_ABORTED : return i18n("Aborted"); case IPP_JOB_COMPLETED : return i18n("Completed"); } return QLatin1String("-"); } void JobModel::clear() { removeRows(0, rowCount()); } void JobModel::setWhichJobs(WhichJobs whichjobs) { switch (whichjobs) { case WhichActive: m_whichjobs = CUPS_WHICHJOBS_ACTIVE; break; case WhichCompleted: m_whichjobs = CUPS_WHICHJOBS_COMPLETED; break; case WhichAll: m_whichjobs = CUPS_WHICHJOBS_ALL; break; } getJobs(); } Qt::ItemFlags JobModel::flags(const QModelIndex &index) const { if (index.isValid()) { ipp_jstate_t state = static_cast(item(index.row(), ColStatus)->data(RoleJobState).toInt()); if (state == IPP_JOB_PENDING || state == IPP_JOB_PROCESSING) { return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; } } return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDropEnabled; } QString JobModel::processingJob() const { return m_processingJob; } diff --git a/libkcups/JobModel.h b/libkcups/JobModel.h index 8bbe449..467ce79 100644 --- a/libkcups/JobModel.h +++ b/libkcups/JobModel.h @@ -1,151 +1,151 @@ /*************************************************************************** * 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 JOB_MODEL_H #define JOB_MODEL_H #include #include class KCupsJob; class KCupsRequest; class Q_DECL_EXPORT JobModel : public QStandardItemModel { Q_OBJECT Q_ENUMS(JobAction) Q_ENUMS(Role) Q_ENUMS(WhichJobs) public: enum Role { RoleJobId = Qt::UserRole + 2, RoleJobState, RoleJobName, RoleJobPages, RoleJobSize, RoleJobOwner, RoleJobCreatedAt, RoleJobIconName, RoleJobCancelEnabled, RoleJobHoldEnabled, RoleJobReleaseEnabled, RoleJobRestartEnabled, RoleJobPrinter, RoleJobOriginatingHostName }; enum JobAction { Cancel, Hold, Release, Move, Reprint }; enum WhichJobs { WhichAll, WhichActive, WhichCompleted }; enum Columns { ColStatus = 0, ColName, ColUser, ColCreated, ColCompleted, ColPages, ColProcessed, ColSize, ColStatusMessage, ColPrinter, ColFromHost, LastColumn }; explicit JobModel(QObject *parent = 0); void setParentWId(WId parentId); Q_INVOKABLE void init(const QString &destName = QString()); Q_INVOKABLE void hold(const QString &printerName, int jobId); Q_INVOKABLE void release(const QString &printerName, int jobId); Q_INVOKABLE void cancel(const QString &printerName, int jobId); Q_INVOKABLE void move(const QString &printerName, int jobId, const QString &toPrinterName); QString processingJob() const; Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; QStringList mimeTypes() const Q_DECL_OVERRIDE; Qt::DropActions supportedDropActions() const Q_DECL_OVERRIDE; QMimeData* mimeData(const QModelIndexList &indexes) const Q_DECL_OVERRIDE; bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) Q_DECL_OVERRIDE; virtual QHash roleNames() const override; Q_INVOKABLE void setWhichJobs(WhichJobs whichjobs); KCupsRequest* modifyJob(int row, JobAction action, const QString &newDestName = QString(), const QModelIndex &parent = QModelIndex()); private slots: void getJobs(); void getJobFinished(KCupsRequest *request); void jobCompleted(const QString &text, const QString &printerUri, const QString &printerName, uint printerState, const QString &printerStateReasons, bool printerIsAcceptingJobs, uint jobId, uint jobState, const QString &jobStateReasons, const QString &jobName, uint jobImpressionsCompleted); void insertUpdateJob(const QString &text, const QString &printerUri, const QString &printerName, uint printerState, const QString &printerStateReasons, bool printerIsAcceptingJobs, uint jobId, uint jobState, const QString &jobStateReasons, const QString &jobName, uint jobImpressionsCompleted); private: int jobRow(int jobId); void insertJob(int pos, const KCupsJob &job); void updateJob(int pos, const KCupsJob &job); QString jobStatus(ipp_jstate_e job_state); void clear(); - KCupsRequest *m_jobRequest; + KCupsRequest *m_jobRequest = nullptr; QString m_destName; QString m_processingJob; QHash m_roles; - int m_whichjobs; - WId m_parentId; + int m_whichjobs = CUPS_WHICHJOBS_ACTIVE; + WId m_parentId = 0; QStringList m_jobAttributes; }; #endif // JOB_MODEL_H diff --git a/libkcups/KCupsConnection.cpp b/libkcups/KCupsConnection.cpp index 9b84d84..c7c2914 100644 --- a/libkcups/KCupsConnection.cpp +++ b/libkcups/KCupsConnection.cpp @@ -1,898 +1,895 @@ /*************************************************************************** * Copyright (C) 2010-2018 by Daniel Nicoletti * * dantti12@gmail.com * * Copyright (C) 2012 Harald Sitter * * * * 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 "KCupsConnection.h" #include "Debug.h" #include "KCupsPasswordDialog.h" #include "KIppRequest.h" #include #include -#include #include #include #include #include #include #define RENEW_INTERVAL 3500 #define SUBSCRIPTION_DURATION 3600 #define DBUS_SERVER_RESTARTED "server-restarted" // ServerRestarted #define DBUS_SERVER_STARTED "server-started" // ServerStarted #define DBUS_SERVER_STOPPED "server-stopped" // ServerStopped #define DBUS_SERVER_AUDIT "server-audit" // ServerAudit #define DBUS_PRINTER_RESTARTED "printer-restarted" // PrinterRestarted #define DBUS_PRINTER_SHUTDOWN "printer-shutdown" // PrinterShutdown #define DBUS_PRINTER_STOPPED "printer-stopped" // PrinterStopped #define DBUS_PRINTER_STATE_CHANGED "printer-state-changed" // PrinterStateChanged #define DBUS_PRINTER_FINISHINGS_CHANGED "printer-finishings-changed" // PrinterFinishingsChanged #define DBUS_PRINTER_MEDIA_CHANGED "printer-media-changed" // PrinterMediaChanged #define DBUS_PRINTER_ADDED "printer-added" // PrinterAdded #define DBUS_PRINTER_DELETED "printer-deleted" // PrinterDeleted #define DBUS_PRINTER_MODIFIED "printer-modified" // PrinterModified #define DBUS_JOB_STATE_CHANGED "job-state-changed" // JobState #define DBUS_JOB_CREATED "job-created" // JobCreated #define DBUS_JOB_COMPLETED "job-completed" // JobCompleted #define DBUS_JOB_STOPPED "job-stopped" // JobStopped #define DBUS_JOB_CONFIG_CHANGED "job-config-changed" // JobConfigChanged #define DBUS_JOB_PROGRESS "job-progress" // JobProgress Q_DECLARE_METATYPE(QList) Q_DECLARE_METATYPE(QList) KCupsConnection* KCupsConnection::m_instance = 0; static int password_retries = 0; static int total_retries = 0; static int internalErrorCount = 0; const char * password_cb(const char *prompt, http_t *http, const char *method, const char *resource, void *user_data); KCupsConnection* KCupsConnection::global() { if (!m_instance) { m_instance = new KCupsConnection(qApp); } return m_instance; } KCupsConnection::KCupsConnection(QObject *parent) : QThread(parent) { init(); } KCupsConnection::KCupsConnection(const QUrl &server, QObject *parent) : QThread(parent), m_serverUrl(server) { qRegisterMetaType("KIppRequest"); init(); } KCupsConnection::~KCupsConnection() { if (m_instance == this) { m_instance = 0; } m_passwordDialog->deleteLater(); quit(); wait(); delete m_renewTimer; delete m_subscriptionTimer; } void KCupsConnection::setPasswordMainWindow(WId mainwindow) { m_passwordDialog->setMainWindow(mainwindow); } void KCupsConnection::init() { // Creating the dialog before start() will make it run on the gui thread m_passwordDialog = new KCupsPasswordDialog; - m_subscriptionId = -1; - m_inited = false; // setup the DBus subscriptions // Server related signals // ServerStarted notifierConnect(QLatin1String("ServerStarted"), this, SIGNAL(serverStarted(QString))); // ServerStopped notifierConnect(QLatin1String("ServerStopped"), this, SIGNAL(serverStopped(QString))); // ServerRestarted notifierConnect(QLatin1String("ServerRestarted"), this, SIGNAL(serverRestarted(QString))); // ServerAudit notifierConnect(QLatin1String("ServerAudit"), this, SIGNAL(serverAudit(QString))); // Printer related signals // PrinterAdded notifierConnect(QLatin1String("PrinterAdded"), this, SIGNAL(printerAdded(QString,QString,QString,uint,QString,bool))); // PrinterModified notifierConnect(QLatin1String("PrinterModified"), this, SIGNAL(printerModified(QString,QString,QString,uint,QString,bool))); // PrinterDeleted notifierConnect(QLatin1String("PrinterDeleted"), this, SIGNAL(printerDeleted(QString,QString,QString,uint,QString,bool))); // PrinterStateChanged notifierConnect(QLatin1String("PrinterStateChanged"), this, SIGNAL(printerStateChanged(QString,QString,QString,uint,QString,bool))); // PrinterStopped notifierConnect(QLatin1String("PrinterStopped"), this, SIGNAL(printerStopped(QString,QString,QString,uint,QString,bool))); // PrinterShutdown notifierConnect(QLatin1String("PrinterShutdown"), this, SIGNAL(printerShutdown(QString,QString,QString,uint,QString,bool))); // PrinterRestarted notifierConnect(QLatin1String("PrinterRestarted"), this, SIGNAL(printerRestarted(QString,QString,QString,uint,QString,bool))); // PrinterMediaChanged notifierConnect(QLatin1String("PrinterMediaChanged"), this, SIGNAL(printerMediaChanged(QString,QString,QString,uint,QString,bool))); // PrinterFinishingsChanged notifierConnect(QLatin1String("PrinterFinishingsChanged"), this, SIGNAL(PrinterFinishingsChanged(QString,QString,QString,uint,QString,bool))); // Job related signals // JobState notifierConnect(QLatin1String("JobState"), this, SIGNAL(jobState(QString,QString,QString,uint,QString,bool,uint,uint,QString,QString,uint))); // JobCreated notifierConnect(QLatin1String("JobCreated"), this, SIGNAL(jobCreated(QString,QString,QString,uint,QString,bool,uint,uint,QString,QString,uint))); // JobStopped notifierConnect(QLatin1String("JobStopped"), this, SIGNAL(jobStopped(QString,QString,QString,uint,QString,bool,uint,uint,QString,QString,uint))); // JobConfigChanged notifierConnect(QLatin1String("JobConfigChanged"), this, SIGNAL(jobConfigChanged(QString,QString,QString,uint,QString,bool,uint,uint,QString,QString,uint))); // JobProgress notifierConnect(QLatin1String("JobProgress"), this, SIGNAL(jobProgress(QString,QString,QString,uint,QString,bool,uint,uint,QString,QString,uint))); // JobCompleted notifierConnect(QLatin1String("JobCompleted"), this, SIGNAL(jobCompleted(QString,QString,QString,uint,QString,bool,uint,uint,QString,QString,uint))); // This signal is needed since the cups registration thing // doesn't emit printerAdded when we add a printer class // This is emitted when a printer/queue is changed QDBusConnection::systemBus().connect(QLatin1String(""), QLatin1String("/com/redhat/PrinterSpooler"), QLatin1String("com.redhat.PrinterSpooler"), QLatin1String("PrinterAdded"), this, SIGNAL(rhPrinterAdded(QString))); // This signal is needed since the cups registration thing // sometimes simple stops working... don't ask me why // This is emitted when a printer/queue is changed QDBusConnection::systemBus().connect(QLatin1String(""), QLatin1String("/com/redhat/PrinterSpooler"), QLatin1String("com.redhat.PrinterSpooler"), QLatin1String("QueueChanged"), this, SIGNAL(rhQueueChanged(QString))); // This signal is needed since the cups registration thing // doesn't emit printerRemoved when we add a printer class // This is emitted when a printer/queue is changed QDBusConnection::systemBus().connect(QLatin1String(""), QLatin1String("/com/redhat/PrinterSpooler"), QLatin1String("com.redhat.PrinterSpooler"), QLatin1String("PrinterRemoved"), this, SIGNAL(rhPrinterRemoved(QString))); QDBusConnection::systemBus().connect(QLatin1String(""), QLatin1String("/com/redhat/PrinterSpooler"), QLatin1String("com.redhat.PrinterSpooler"), QLatin1String("JobQueuedLocal"), this, SIGNAL(rhJobQueuedLocal(QString,uint,QString))); QDBusConnection::systemBus().connect(QLatin1String(""), QLatin1String("/com/redhat/PrinterSpooler"), QLatin1String("com.redhat.PrinterSpooler"), QLatin1String("JobStartedLocal"), this, SIGNAL(rhJobStartedLocal(QString,uint,QString))); // Creates the timer that will renew the DBus subscription m_renewTimer = new QTimer; m_renewTimer->setInterval(RENEW_INTERVAL*1000); m_renewTimer->moveToThread(this); connect(m_renewTimer, &QTimer::timeout, this, static_cast(&KCupsConnection::renewDBusSubscription), Qt::DirectConnection); // Creates the timer to merge updates on the DBus subscription m_subscriptionTimer = new QTimer; m_subscriptionTimer->setInterval(0); m_subscriptionTimer->setSingleShot(true); m_subscriptionTimer->moveToThread(this); connect(m_subscriptionTimer, &QTimer::timeout, this, &KCupsConnection::updateSubscription, Qt::DirectConnection); // Starts this thread start(); } void KCupsConnection::run() { // Check if we need an special connection if (!m_serverUrl.isEmpty()) { if (m_serverUrl.port() < 0) { // TODO find out if there's a better way of hardcoding // the CUPS port m_serverUrl.setPort(631); } cupsSetServer(qUtf8Printable(m_serverUrl.authority())); } // This is dead cool, cups will call the thread_password_cb() // function when a password set is needed, as we passed the // password dialog pointer the functions just need to call // it on a blocking mode. cupsSetPasswordCB2(password_cb, m_passwordDialog); m_inited = true; exec(); // Event loop quit so cancelDBusSubscription() if (m_subscriptionId != -1) { cancelDBusSubscription(); } } bool KCupsConnection::readyToStart() { if (QThread::currentThread() == this) { password_retries = 0; total_retries = 0; internalErrorCount = 0; return true; } return false; } ReturnArguments KCupsConnection::request(const KIppRequest &request, ipp_tag_t groupTag) const { ReturnArguments ret; ipp_t *response = NULL; do { ippDelete(response); response = NULL; response = request.sendIppRequest(); } while (retry(qUtf8Printable(request.resource()), request.operation())); if (response && groupTag != IPP_TAG_ZERO) { ret = parseIPPVars(response, groupTag); } ippDelete(response); return ret; } int KCupsConnection::renewDBusSubscription(int subscriptionId, int leaseDuration, const QStringList &events) { int ret = -1; ipp_op_t operation; // check if we have a valid subscription ID if (subscriptionId >= 0) { // Add the "notify-events" values to the request operation = IPP_RENEW_SUBSCRIPTION; } else { operation = IPP_CREATE_PRINTER_SUBSCRIPTION; } KIppRequest request(operation, QLatin1String("/")); request.addString(IPP_TAG_OPERATION, IPP_TAG_URI, KCUPS_PRINTER_URI, QLatin1String("/")); request.addInteger(IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, KCUPS_NOTIFY_LEASE_DURATION, leaseDuration); if (operation == IPP_CREATE_PRINTER_SUBSCRIPTION) { // Add the "notify-events" values to the request request.addStringList(IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD, KCUPS_NOTIFY_EVENTS, events); request.addString(IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD, KCUPS_NOTIFY_PULL_METHOD, QLatin1String("ippget")); request.addString(IPP_TAG_SUBSCRIPTION, IPP_TAG_URI, KCUPS_NOTIFY_RECIPIENT_URI, QLatin1String("dbus://")); } else { request.addInteger(IPP_TAG_OPERATION, IPP_TAG_INTEGER, KCUPS_NOTIFY_SUBSCRIPTION_ID, subscriptionId); } ipp_t *response = NULL; do { // Do the request response = request.sendIppRequest(); } while (retry("/", operation)); #if !(CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR < 6) if (response && ippGetStatusCode(response) == IPP_OK) { #else if (response && response->request.status.status_code == IPP_OK) { #endif // !(CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR < 6) ipp_attribute_t *attr; if (subscriptionId >= 0) { // Request was ok, just return the current subscription ret = subscriptionId; } else if ((attr = ippFindAttribute(response, "notify-subscription-id", IPP_TAG_INTEGER)) == NULL) { qCWarning(LIBKCUPS) << "No notify-subscription-id in response!"; ret = -1; } else { #if !(CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR < 6) ret = ippGetInteger(attr, 0); } } else if (subscriptionId >= 0 && response && ippGetStatusCode(response) == IPP_NOT_FOUND) { qCDebug(LIBKCUPS) << "Subscription not found"; // When the subscription is not found try to get a new one return renewDBusSubscription(-1, leaseDuration, events); #else ret = attr->values[0].integer; } } else if (subscriptionId >= 0 && response && response->request.status.status_code == IPP_NOT_FOUND) { qCDebug(LIBKCUPS) << "Subscription not found"; // When the subscription is not found try to get a new one return renewDBusSubscription(-1, leaseDuration, events); #endif // !(CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR < 6) } else { qCDebug(LIBKCUPS) << "Request failed" << cupsLastError() << httpGetStatus(CUPS_HTTP_DEFAULT); // When the server stops/restarts we will have some error so ignore it ret = subscriptionId; } ippDelete(response); return ret; } void KCupsConnection::notifierConnect(const QString &signal, QObject *receiver, const char *slot) { QDBusConnection systemBus = QDBusConnection::systemBus(); systemBus.connect(QString(), - QLatin1String("/org/cups/cupsd/Notifier"), - QLatin1String("org.cups.cupsd.Notifier"), + QStringLiteral("/org/cups/cupsd/Notifier"), + QStringLiteral("org.cups.cupsd.Notifier"), signal, receiver, slot); } void KCupsConnection::connectNotify(const QMetaMethod & signal) { QMutexLocker locker(&m_mutex); QString event = eventForSignal(signal); if (!event.isNull()) { m_connectedEvents << event; QMetaObject::invokeMethod(m_subscriptionTimer, "start", Qt::QueuedConnection); } } void KCupsConnection::disconnectNotify(const QMetaMethod & signal) { QMutexLocker locker(&m_mutex); QString event = eventForSignal(signal); if (!event.isNull()) { m_connectedEvents.removeOne(event); QMetaObject::invokeMethod(m_subscriptionTimer, "start", Qt::QueuedConnection); } } QString KCupsConnection::eventForSignal(const QMetaMethod & signal) const { // Server signals if (signal == QMetaMethod::fromSignal(&KCupsConnection::serverAudit)) { return QStringLiteral(DBUS_SERVER_AUDIT); } if (signal == QMetaMethod::fromSignal(&KCupsConnection::serverStarted)) { return QStringLiteral(DBUS_SERVER_STARTED); } if (signal == QMetaMethod::fromSignal(&KCupsConnection::serverStopped)) { return QStringLiteral(DBUS_SERVER_STOPPED); } if (signal == QMetaMethod::fromSignal(&KCupsConnection::serverRestarted)) { return QStringLiteral(DBUS_SERVER_RESTARTED); } // Printer signals if (signal == QMetaMethod::fromSignal(&KCupsConnection::printerAdded)) { return QStringLiteral(DBUS_PRINTER_ADDED); } if (signal == QMetaMethod::fromSignal(&KCupsConnection::printerDeleted)) { return QStringLiteral(DBUS_PRINTER_DELETED); } if (signal == QMetaMethod::fromSignal(&KCupsConnection::printerFinishingsChanged)) { return QStringLiteral(DBUS_PRINTER_FINISHINGS_CHANGED); } if (signal == QMetaMethod::fromSignal(&KCupsConnection::printerMediaChanged)) { return QStringLiteral(DBUS_PRINTER_MEDIA_CHANGED); } if (signal == QMetaMethod::fromSignal(&KCupsConnection::printerModified)) { return QStringLiteral(DBUS_PRINTER_MODIFIED); } if (signal == QMetaMethod::fromSignal(&KCupsConnection::printerRestarted)) { return QStringLiteral(DBUS_PRINTER_RESTARTED); } if (signal == QMetaMethod::fromSignal(&KCupsConnection::printerShutdown)) { return QStringLiteral(DBUS_PRINTER_SHUTDOWN); } if (signal == QMetaMethod::fromSignal(&KCupsConnection::printerStateChanged)) { return QStringLiteral(DBUS_PRINTER_STATE_CHANGED); } if (signal == QMetaMethod::fromSignal(&KCupsConnection::printerStopped)) { return QStringLiteral(DBUS_PRINTER_STOPPED); } // job signals if (signal == QMetaMethod::fromSignal(&KCupsConnection::jobCompleted)) { return QStringLiteral(DBUS_JOB_COMPLETED); } if (signal == QMetaMethod::fromSignal(&KCupsConnection::jobConfigChanged)) { return QStringLiteral(DBUS_JOB_CONFIG_CHANGED); } if (signal == QMetaMethod::fromSignal(&KCupsConnection::jobCreated)) { return QStringLiteral(DBUS_JOB_CREATED); } if (signal == QMetaMethod::fromSignal(&KCupsConnection::jobProgress)) { return QStringLiteral(DBUS_JOB_PROGRESS); } if (signal == QMetaMethod::fromSignal(&KCupsConnection::jobState)) { return QStringLiteral(DBUS_JOB_STATE_CHANGED); } if (signal == QMetaMethod::fromSignal(&KCupsConnection::jobStopped)) { return QStringLiteral(DBUS_JOB_STOPPED); } // No registered event signal matched return QString(); } void KCupsConnection::updateSubscription() { QMutexLocker locker(&m_mutex); // Build the current list QStringList currentEvents = m_connectedEvents; currentEvents.sort(); currentEvents.removeDuplicates(); // Check if the requested events are already being asked if (m_requestedDBusEvents != currentEvents) { m_requestedDBusEvents = currentEvents; // If we alread have a subscription lets cancel // and create a new one if (m_subscriptionId >= 0) { cancelDBusSubscription(); } // Canculates the new events renewDBusSubscription(); } } void KCupsConnection::renewDBusSubscription() { // check if we have a valid subscription ID if (m_subscriptionId >= 0) { m_subscriptionId = renewDBusSubscription(m_subscriptionId, SUBSCRIPTION_DURATION); } // The above request might fail if the subscription was cancelled if (m_subscriptionId < 0) { if (m_requestedDBusEvents.isEmpty()) { m_renewTimer->stop(); } else { m_subscriptionId = renewDBusSubscription(m_subscriptionId, SUBSCRIPTION_DURATION, m_requestedDBusEvents); m_renewTimer->start(); } } } void KCupsConnection::cancelDBusSubscription() { KIppRequest request(IPP_CANCEL_SUBSCRIPTION, QLatin1String("/")); request.addString(IPP_TAG_OPERATION, IPP_TAG_URI, KCUPS_PRINTER_URI, QLatin1String("/")); request.addInteger(IPP_TAG_OPERATION, IPP_TAG_INTEGER, KCUPS_NOTIFY_SUBSCRIPTION_ID, m_subscriptionId); do { // Do the request ippDelete(request.sendIppRequest()); } while (retry(qUtf8Printable(request.resource()), request.operation())); // Reset the subscription id m_subscriptionId = -1; } ReturnArguments KCupsConnection::parseIPPVars(ipp_t *response, ipp_tag_t group_tag) { ipp_attribute_t *attr; ReturnArguments ret; #if !(CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR < 6) QVariantHash destAttributes; for (attr = ippFirstAttribute(response); attr != NULL; attr = ippNextAttribute(response)) { // We hit an attribute sepparator if (ippGetName(attr) == NULL) { ret << destAttributes; destAttributes.clear(); continue; } // Skip leading attributes until we hit a a group which can be a printer, job... if (ippGetGroupTag(attr) != group_tag || (ippGetValueTag(attr) != IPP_TAG_INTEGER && ippGetValueTag(attr) != IPP_TAG_ENUM && ippGetValueTag(attr) != IPP_TAG_BOOLEAN && ippGetValueTag(attr) != IPP_TAG_TEXT && ippGetValueTag(attr) != IPP_TAG_TEXTLANG && ippGetValueTag(attr) != IPP_TAG_LANGUAGE && ippGetValueTag(attr) != IPP_TAG_NAME && ippGetValueTag(attr) != IPP_TAG_NAMELANG && ippGetValueTag(attr) != IPP_TAG_KEYWORD && ippGetValueTag(attr) != IPP_TAG_RANGE && ippGetValueTag(attr) != IPP_TAG_URI)) { continue; } // Add a printer description attribute... destAttributes[QString::fromUtf8(ippGetName(attr))] = ippAttrToVariant(attr); } if (!destAttributes.isEmpty()) { ret << destAttributes; } #else for (attr = response->attrs; attr != NULL; attr = attr->next) { /* * Skip leading attributes until we hit a a group which can be a printer, job... */ while (attr && attr->group_tag != group_tag) { attr = attr->next; } if (attr == NULL) { break; } /* * Pull the needed attributes from this printer... */ QVariantHash destAttributes; for (; attr && attr->group_tag == group_tag; attr = attr->next) { if (attr->value_tag != IPP_TAG_INTEGER && attr->value_tag != IPP_TAG_ENUM && attr->value_tag != IPP_TAG_BOOLEAN && attr->value_tag != IPP_TAG_TEXT && attr->value_tag != IPP_TAG_TEXTLANG && attr->value_tag != IPP_TAG_LANGUAGE && attr->value_tag != IPP_TAG_NAME && attr->value_tag != IPP_TAG_NAMELANG && attr->value_tag != IPP_TAG_KEYWORD && attr->value_tag != IPP_TAG_RANGE && attr->value_tag != IPP_TAG_URI) { continue; } /* * Add a printer description attribute... */ destAttributes[QString::fromUtf8(attr->name)] = ippAttrToVariant(attr); } ret << destAttributes; if (attr == NULL) { break; } } #endif // !(CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR < 6) return ret; } QVariant KCupsConnection::ippAttrToVariant(ipp_attribute_t *attr) { QVariant ret; #if !(CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR < 6) switch (ippGetValueTag(attr)) { case IPP_TAG_INTEGER: case IPP_TAG_ENUM: if (ippGetCount(attr) == 1) { ret = ippGetInteger(attr, 0); } else { QList values; for (int i = 0; i < ippGetCount(attr); ++i) { values << ippGetInteger(attr, i); } ret = qVariantFromValue(values); } break; case IPP_TAG_BOOLEAN: if (ippGetCount(attr)== 1) { ret = ippGetBoolean(attr, 0); } else { QList values; for (int i = 0; i < ippGetCount(attr); ++i) { values << ippGetBoolean(attr, i); } ret = qVariantFromValue(values); } break; case IPP_TAG_RANGE: { QVariantList values; for (int i = 0; i < ippGetCount(attr); ++i) { int rangeUpper; values << ippGetRange(attr, i, &rangeUpper); values << rangeUpper; } ret = values; } break; default: if (ippGetCount(attr)== 1) { ret = QString::fromUtf8(ippGetString(attr, 0, NULL)); } else { QStringList values; for (int i = 0; i < ippGetCount(attr); ++i) { values << QString::fromUtf8(ippGetString(attr, i, NULL)); } ret = values; } } #else switch (attr->value_tag) { case IPP_TAG_INTEGER: case IPP_TAG_ENUM: if (attr->num_values == 1) { ret = attr->values[0].integer; } else { QList values; for (int i = 0; i < attr->num_values; ++i) { values << attr->values[i].integer; } ret = qVariantFromValue(values); } break; case IPP_TAG_BOOLEAN: if (attr->num_values == 1) { ret = static_cast(attr->values[0].integer); } else { QList values; for (int i = 0; i < attr->num_values; ++i) { values << static_cast(attr->values[i].integer); } ret = qVariantFromValue(values); } break; case IPP_TAG_RANGE: { QVariantList values; for (int i = 0; i < attr->num_values; ++i) { values << attr->values[i].range.lower; values << attr->values[i].range.upper; } ret = values; } break; default: if (attr->num_values == 1) { ret = QString::fromUtf8(attr->values[0].string.text); } else { QStringList values; for (int i = 0; i < attr->num_values; ++i) { values << QString::fromUtf8(attr->values[i].string.text); } ret = values; } } #endif // !(CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR < 6) return ret; } bool KCupsConnection::retry(const char *resource, int operation) const { ipp_status_t status = cupsLastError(); if (operation != -1) { qCDebug(LIBKCUPS) << ippOpString(static_cast(operation)) << "last error:" << status << cupsLastErrorString(); } else { qCDebug(LIBKCUPS) << operation << "last error:" << status << cupsLastErrorString(); } // When CUPS process stops our connection // with it fails and has to be re-established if (status == IPP_INTERNAL_ERROR) { // Deleting this connection thread forces it // to create a new CUPS connection qCWarning(LIBKCUPS) << "IPP_INTERNAL_ERROR: clearing cookies and reconnecting"; // TODO maybe reconnect is enough // httpClearCookie(CUPS_HTTP_DEFAULT); // Reconnect to CUPS if (httpReconnect(CUPS_HTTP_DEFAULT)) { qCWarning(LIBKCUPS) << "Failed to reconnect" << cupsLastErrorString(); // Server might be restarting sleep for a few ms msleep(500); } // Try the request again return ++internalErrorCount < 3; } total_retries++; if (total_retries > (password_retries + 3)) { // Something is wrong. // This will happen if the password_cb function is not called, // which will for example be the case if the server has // an IP blacklist and thus always return 403. // In this case, there is nothing we can do. return false; } bool forceAuth = false; // If our user is forbidden to perform the // task we try again using the root user // ONLY if it was the first time if (status == IPP_FORBIDDEN && password_retries == 0) { // Pretend to be the root user // Sometimes setting this just works cupsSetUser("root"); // force authentication forceAuth = true; } if (status == IPP_NOT_AUTHORIZED || status == IPP_NOT_AUTHENTICATED) { if (password_retries > 3 || password_retries == -1) { // the authentication failed 3 times // OR the dialog was canceld (-1) // reset to 0 and quit the do-while loop password_retries = 0; total_retries = 0; return false; } // force authentication forceAuth = true; } if (forceAuth) { // force authentication qCDebug(LIBKCUPS) << "Calling cupsDoAuthentication() password_retries:" << password_retries; int ret = cupsDoAuthentication(CUPS_HTTP_DEFAULT, "POST", resource); qCDebug(LIBKCUPS) << "Called cupsDoAuthentication(), success:" << (ret == -1 ? true : false); // If the authentication was succefull // sometimes just trying to be root works return ret == -1 ? true : false; } // the action was not forbidden return false; } const char * password_cb(const char *prompt, http_t *http, const char *method, const char *resource, void *user_data) { Q_UNUSED(prompt) Q_UNUSED(http) Q_UNUSED(method) Q_UNUSED(resource) if (++password_retries > 3) { // cancel the authentication cupsSetUser(NULL); return NULL; } auto passwordDialog = static_cast(user_data); bool wrongPassword = password_retries > 1; // This will block this thread until exec is not finished qCDebug(LIBKCUPS) << password_retries; QMetaObject::invokeMethod(passwordDialog, "exec", Qt::BlockingQueuedConnection, Q_ARG(QString, QString::fromUtf8(cupsUser())), Q_ARG(bool, wrongPassword)); qCDebug(LIBKCUPS) << passwordDialog->accepted(); // The password dialog has just returned check the result // method that returns QDialog enums if (passwordDialog->accepted()) { cupsSetUser(qUtf8Printable(passwordDialog->username())); return qUtf8Printable(passwordDialog->password()); } else { // the dialog was canceled password_retries = -1; cupsSetUser(NULL); return NULL; } } diff --git a/libkcups/KCupsConnection.h b/libkcups/KCupsConnection.h index 9bc2e99..f2454b6 100644 --- a/libkcups/KCupsConnection.h +++ b/libkcups/KCupsConnection.h @@ -1,405 +1,405 @@ /*************************************************************************** * 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. * ***************************************************************************/ #ifndef KCUPSCONNECTION_H #define KCUPSCONNECTION_H #include #include #include #include #include #include #include #include #include #define KCUPS_DEVICE_CLASS QLatin1String("device-class") #define KCUPS_DEVICE_ID QLatin1String("device-id") #define KCUPS_DEVICE_INFO QLatin1String("device-info") #define KCUPS_DEVICE_MAKE_AND_MODEL QLatin1String("device-make-and-model") #define KCUPS_DEVICE_LOCATION QLatin1String("device-location") #define KCUPS_DEVICE_URI QLatin1String("device-uri") #define KCUPS_PRINTER_NAME QLatin1String("printer-name") #define KCUPS_PRINTER_LOCATION QLatin1String("printer-location") #define KCUPS_PRINTER_INFO QLatin1String("printer-info") #define KCUPS_PRINTER_URI QLatin1String("printer-uri") #define KCUPS_PRINTER_MAKE_AND_MODEL QLatin1String("printer-make-and-model") #define KCUPS_PRINTER_STATE QLatin1String("printer-state") #define KCUPS_PRINTER_STATE_MESSAGE QLatin1String("printer-state-message") #define KCUPS_PRINTER_IS_SHARED QLatin1String("printer-is-shared") #define KCUPS_PRINTER_IS_ACCEPTING_JOBS QLatin1String("printer-is-accepting-jobs") #define KCUPS_PRINTER_TYPE QLatin1String("printer-type") #define KCUPS_PRINTER_TYPE_MASK QLatin1String("printer-type-mask") #define KCUPS_PRINTER_COMMANDS QLatin1String("printer-commands") #define KCUPS_PRINTER_URI_SUPPORTED QLatin1String("printer-uri-supported") #define KCUPS_PRINTER_ERROR_POLICY QLatin1String("printer-error-policy") #define KCUPS_PRINTER_ERROR_POLICY_SUPPORTED QLatin1String("printer-error-policy-supported") #define KCUPS_PRINTER_OP_POLICY QLatin1String("printer-op-policy") #define KCUPS_PRINTER_OP_POLICY_SUPPORTED QLatin1String("printer-op-policy-supported") #define KCUPS_MEMBER_URIS QLatin1String("member-uris") #define KCUPS_MEMBER_NAMES QLatin1String("member-names") #define KCUPS_MARKER_CHANGE_TIME QLatin1String("marker-change-time") #define KCUPS_MARKER_COLORS QLatin1String("marker-colors") #define KCUPS_MARKER_LEVELS QLatin1String("marker-levels") #define KCUPS_MARKER_HIGH_LEVELS "marker-high-levels" #define KCUPS_MARKER_LOW_LEVELS "marker-low-levels" #define KCUPS_MARKER_NAMES QLatin1String("marker-names") #define KCUPS_MARKER_TYPES QLatin1String("marker-types") #define KCUPS_MARKER_MESSAGE "marker-message" #define KCUPS_JOB_ID QLatin1String("job-id") #define KCUPS_JOB_NAME QLatin1String("job-name") #define KCUPS_JOB_K_OCTETS QLatin1String("job-k-octets") #define KCUPS_JOB_K_OCTETS_PROCESSED QLatin1String("job-k-octets-processed") #define KCUPS_JOB_PRINTER_URI QLatin1String("job-printer-uri") #define KCUPS_JOB_PRINTER_STATE_MESSAGE QLatin1String("job-printer-state-message") #define KCUPS_JOB_ORIGINATING_USER_NAME QLatin1String("job-originating-user-name") #define KCUPS_JOB_ORIGINATING_HOST_NAME QLatin1String("job-originating-host-name") #define KCUPS_JOB_MEDIA_PROGRESS QLatin1String("job-media-progress") #define KCUPS_JOB_MEDIA_SHEETS QLatin1String("job-media-sheets") #define KCUPS_JOB_MEDIA_SHEETS_COMPLETED QLatin1String("job-media-sheets-completed") #define KCUPS_JOB_PRESERVED QLatin1String("job-preserved") #define KCUPS_JOB_STATE QLatin1String("job-state") #define KCUPS_JOB_SHEETS_DEFAULT QLatin1String("job-sheets-default") #define KCUPS_JOB_SHEETS_SUPPORTED QLatin1String("job-sheets-supported") #define KCUPS_JOB_SHEETS_DEFAULT QLatin1String("job-sheets-default") #define KCUPS_JOB_SHEETS_SUPPORTED QLatin1String("job-sheets-supported") #define KCUPS_MY_JOBS QLatin1String("my-jobs") #define KCUPS_WHICH_JOBS QLatin1String("which-jobs") #define KCUPS_TIME_AT_COMPLETED QLatin1String("time-at-completed") #define KCUPS_TIME_AT_CREATION QLatin1String("time-at-creation") #define KCUPS_TIME_AT_PROCESSING QLatin1String("time-at-processing") #define KCUPS_REQUESTED_ATTRIBUTES QLatin1String("requested-attributes") #define KCUPS_REQUESTING_USER_NAME QLatin1String("requesting-user-name") #define KCUPS_REQUESTING_USER_NAME_ALLOWED QLatin1String("requesting-user-name-allowed") #define KCUPS_REQUESTING_USER_NAME_DENIED QLatin1String("requesting-user-name-denied") #define KCUPS_PPD_MAKE_AND_MODEL QLatin1String("ppd-make-and-model") #define KCUPS_NOTIFY_EVENTS QLatin1String("notify-events") #define KCUPS_NOTIFY_PULL_METHOD QLatin1String("notify-pull-method") #define KCUPS_NOTIFY_RECIPIENT_URI QLatin1String("notify-recipient-uri") #define KCUPS_NOTIFY_LEASE_DURATION QLatin1String("notify-lease-duration") #define KCUPS_NOTIFY_SUBSCRIPTION_ID QLatin1String("notify-subscription-id") typedef QList ReturnArguments; class KIppRequest; class KCupsPasswordDialog; class Q_DECL_EXPORT KCupsConnection : public QThread { Q_OBJECT public: /** * This is the main Cups class @author Daniel Nicoletti * * By calling KCupsConnection::global() you have access to it. * Due to cups archtecture, this class has to live on a * separate thread so we avoid blocking the user interface when * the cups call blocks. * * It is IMPORTANT that we do not create several thread * for each cups request, doing so is a valid but breaks our * authentication. We could tho store the user information an * set the user/password every time it was needed. But I am not * sure this is safe. * * Extending this means either adding methods to the KCupsRequest * class which will move to this thread and then run. */ static KCupsConnection* global(); /** * @brief KCupsConnection * @param parent * * This is the default constructor that connects to the default server * If you don't have any special reason for creating a connection * on your own consider calling global() */ explicit KCupsConnection(QObject *parent = 0); explicit KCupsConnection(const QUrl &server, QObject *parent = 0); ~KCupsConnection(); void setPasswordMainWindow(WId mainwindow); Q_SIGNALS: /** * emitted when "server-started" is registered */ void serverStarted(const QString &text); /** * emitted when "server-stopped" is registered */ void serverStopped(const QString &text); /** * emitted when "server-restarted" is registered */ void serverRestarted(const QString &text); /** * emitted when "server-audit" is registered */ void serverAudit(const QString &text); /** * emitted when "printer-added" is registered */ void printerAdded(const QString &text, const QString &printerUri, const QString &printerName, uint printerState, const QString &printerStateReasons, bool printerIsAcceptingJobs); /** * emitted when "printer-modified" is registered */ void printerModified(const QString &text, const QString &printerUri, const QString &printerName, uint printerState, const QString &printerStateReasons, bool printerIsAcceptingJobs); /** * emitted when "printer-deleted" is registered */ void printerDeleted(const QString &text, const QString &printerUri, const QString &printerName, uint printerState, const QString &printerStateReasons, bool printerIsAcceptingJobs); /** * emitted when "printer-state-changed" is registered */ void printerStateChanged(const QString &text, const QString &printerUri, const QString &printerName, uint printerState, const QString &printerStateReasons, bool printerIsAcceptingJobs); /** * emitted when "printer-stopped" is registered */ void printerStopped(const QString &text, const QString &printerUri, const QString &printerName, uint printerState, const QString &printerStateReasons, bool printerIsAcceptingJobs); /** * emitted when "printer-restarted" is registered */ void printerRestarted(const QString &text, const QString &printerUri, const QString &printerName, uint printerState, const QString &printerStateReasons, bool printerIsAcceptingJobs); /** * emitted when "printer-shutdown" is registered */ void printerShutdown(const QString &text, const QString &printerUri, const QString &printerName, uint printerState, const QString &printerStateReasons, bool printerIsAcceptingJobs); /** * emitted when "printer-media-changed" is registered */ void printerMediaChanged(const QString &text, const QString &printerUri, const QString &printerName, uint printerState, const QString &printerStateReasons, bool printerIsAcceptingJobs); /** * emitted when "printer-finishings-changed" is registered */ void printerFinishingsChanged(const QString &text, const QString &printerUri, const QString &printerName, uint printerState, const QString &printerStateReasons, bool printerIsAcceptingJobs); /** * emitted when "job-state-changed" is registered */ void jobState(const QString &text, const QString &printerUri, const QString &printerName, uint printerState, const QString &printerStateReasons, bool printerIsAcceptingJobs, uint jobId, uint jobState, const QString &jobStateReasons, const QString &jobName, uint jobImpressionsCompleted); /** * emitted when "job-created" is registered */ void jobCreated(const QString &text, const QString &printerUri, const QString &printerName, uint printerState, const QString &printerStateReasons, bool printerIsAcceptingJobs, uint jobId, uint jobState, const QString &jobStateReasons, const QString &jobName, uint jobImpressionsCompleted); /** * emitted when "job-stopped" is registered */ void jobStopped(const QString &text, const QString &printerUri, const QString &printerName, uint printerState, const QString &printerStateReasons, bool printerIsAcceptingJobs, uint jobId, uint jobState, const QString &jobStateReasons, const QString &jobName, uint jobImpressionsCompleted); /** * emitted when "job-config-changed" is registered */ void jobConfigChanged(const QString &text, const QString &printerUri, const QString &printerName, uint printerState, const QString &printerStateReasons, bool printerIsAcceptingJobs, uint jobId, uint jobState, const QString &jobStateReasons, const QString &jobName, uint jobImpressionsCompleted); /** * emitted when "job-progress" is registered */ void jobProgress(const QString &text, const QString &printerUri, const QString &printerName, uint printerState, const QString &printerStateReasons, bool printerIsAcceptingJobs, uint jobId, uint jobState, const QString &jobStateReasons, const QString &jobName, uint jobImpressionsCompleted); /** * emitted when "job-completed" is registered */ void jobCompleted(const QString &text, const QString &printerUri, const QString &printerName, uint printerState, const QString &printerStateReasons, bool printerIsAcceptingJobs, uint jobId, uint jobState, const QString &jobStateReasons, const QString &jobName, uint jobImpressionsCompleted); void rhPrinterAdded(const QString &queueName); void rhPrinterRemoved(const QString &queueName); void rhQueueChanged(const QString &queueName); void rhJobQueuedLocal(const QString &queueName, uint jobId, const QString &jobOwner); void rhJobStartedLocal(const QString &queueName, uint jobId, const QString &jobOwner); protected: friend class KCupsRequest; virtual void run() Q_DECL_OVERRIDE; bool readyToStart(); bool retry(const char *resource, int operation) const; ReturnArguments request(const KIppRequest &request, ipp_tag_t groupTag = IPP_TAG_ZERO) const; private slots: void updateSubscription(); void renewDBusSubscription(); void cancelDBusSubscription(); protected: virtual void connectNotify(const QMetaMethod & signal) Q_DECL_OVERRIDE; virtual void disconnectNotify(const QMetaMethod & signal) Q_DECL_OVERRIDE; QString eventForSignal(const QMetaMethod & signal) const; private: void init(); int renewDBusSubscription(int subscriptionId, int leaseDuration, const QStringList &events = QStringList()); void notifierConnect(const QString &signal, QObject *receiver, const char *slot); static ReturnArguments parseIPPVars(ipp_t *response, ipp_tag_t group_tag); static QVariant ippAttrToVariant(ipp_attribute_t *attr); static KCupsConnection* m_instance; - bool m_inited; + bool m_inited = false; KCupsPasswordDialog *m_passwordDialog; QUrl m_serverUrl; QTimer *m_subscriptionTimer; QTimer *m_renewTimer; QStringList m_connectedEvents; //note this updated in another thread. Always guard with m_mutex QStringList m_requestedDBusEvents; - int m_subscriptionId; + int m_subscriptionId = -1; QMutex m_mutex; }; #endif // KCUPSCONNECTION_H diff --git a/libkcups/KCupsJob.cpp b/libkcups/KCupsJob.cpp index 4a7c83c..5d1fbbd 100644 --- a/libkcups/KCupsJob.cpp +++ b/libkcups/KCupsJob.cpp @@ -1,210 +1,210 @@ /*************************************************************************** - * Copyright (C) 2010-2012 by Daniel Nicoletti * + * 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 "KCupsJob.h" #include "Debug.h" KCupsJob::KCupsJob() : m_jobId(0) { } KCupsJob::KCupsJob(int jobId, const QString &printer) : m_jobId(jobId), m_printer(printer) { m_arguments[KCUPS_JOB_ID] = QString::number(jobId); } KCupsJob::KCupsJob(const QVariantHash &arguments) : m_arguments(arguments) { m_jobId = arguments[KCUPS_JOB_ID].toInt(); m_printer = arguments[KCUPS_JOB_PRINTER_URI].toString().section(QLatin1Char('/'), -1); } int KCupsJob::id() const { return m_jobId; } QString KCupsJob::idStr() const { return m_arguments[KCUPS_JOB_ID].toString(); } QString KCupsJob::name() const { return m_arguments[KCUPS_JOB_NAME].toString(); } QString KCupsJob::originatingUserName() const { return m_arguments[KCUPS_JOB_ORIGINATING_USER_NAME].toString(); } QString KCupsJob::originatingHostName() const { return m_arguments[KCUPS_JOB_ORIGINATING_HOST_NAME].toString(); } QString KCupsJob::printer() const { return m_printer; } QDateTime KCupsJob::createdAt() const { QDateTime ret; const auto it = m_arguments.constFind(KCUPS_TIME_AT_CREATION); if (it != m_arguments.constEnd()) { ret.setTime_t(it.value().toInt()); } return ret; } QDateTime KCupsJob::completedAt() const { QDateTime ret; const auto it = m_arguments.constFind(KCUPS_TIME_AT_COMPLETED); if (it != m_arguments.constEnd()) { ret.setTime_t(it.value().toInt()); } return ret; } QDateTime KCupsJob::processedAt() const { QDateTime ret; const auto it = m_arguments.constFind(KCUPS_TIME_AT_PROCESSING); if (it != m_arguments.constEnd()) { ret.setTime_t(it.value().toInt()); } return ret; } int KCupsJob::pages() const { return m_arguments[KCUPS_JOB_MEDIA_SHEETS].toInt(); } int KCupsJob::processedPages() const { return m_arguments[KCUPS_JOB_MEDIA_SHEETS_COMPLETED].toInt(); } int KCupsJob::size() const { int jobKOctets = m_arguments[KCUPS_JOB_K_OCTETS].toInt(); jobKOctets *= 1024; // transform it to bytes return jobKOctets; } bool KCupsJob::preserved() const { return m_arguments[KCUPS_JOB_PRESERVED].toInt(); } QString KCupsJob::iconName(ipp_jstate_t state) { QString ret; switch (state){ case IPP_JOB_PENDING: ret = QLatin1String("chronometer"); break; case IPP_JOB_HELD: ret = QLatin1String("media-playback-pause"); break; case IPP_JOB_PROCESSING: ret = QLatin1String("draw-arrow-forward"); break; case IPP_JOB_STOPPED: ret = QLatin1String("draw-rectangle"); break; case IPP_JOB_CANCELED: ret = QLatin1String("archive-remove"); break; case IPP_JOB_ABORTED: ret = QLatin1String("task-attempt"); break; case IPP_JOB_COMPLETED: ret = QLatin1String("task-complete"); break; default: ret = QLatin1String("unknown"); } return ret; } ipp_jstate_t KCupsJob::state() const { return static_cast(m_arguments[KCUPS_JOB_STATE].toUInt()); } QString KCupsJob::stateMsg() const { return m_arguments[KCUPS_JOB_PRINTER_STATE_MESSAGE].toString(); } bool KCupsJob::reprintEnabled() const { if (state() >= IPP_JOB_STOPPED && preserved()) { return true; } return false; } bool KCupsJob::cancelEnabled(ipp_jstate_t state) { switch (state) { case IPP_JOB_CANCELED: case IPP_JOB_COMPLETED: case IPP_JOB_ABORTED: return false; default: return true; } } bool KCupsJob::holdEnabled(ipp_jstate_t state) { switch (state) { case IPP_JOB_CANCELED: case IPP_JOB_COMPLETED: case IPP_JOB_ABORTED: case IPP_JOB_HELD: case IPP_JOB_STOPPED: return false; default: return true; } } bool KCupsJob::releaseEnabled(ipp_jstate_t state) { switch (state) { case IPP_JOB_HELD : case IPP_JOB_STOPPED : return true; default: return false; } } diff --git a/libkcups/KCupsRequest.cpp b/libkcups/KCupsRequest.cpp index ac9d1ed..c29a61d 100644 --- a/libkcups/KCupsRequest.cpp +++ b/libkcups/KCupsRequest.cpp @@ -1,670 +1,667 @@ /*************************************************************************** - * Copyright (C) 2010-2012 by Daniel Nicoletti * + * 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 "KCupsRequest.h" #include "Debug.h" #include "KIppRequest.h" #include "KCupsJob.h" #include "KCupsPrinter.h" #include -#include #include #include #define CUPS_DATADIR QLatin1String("/usr/share/cups") KCupsRequest::KCupsRequest(KCupsConnection *connection) : - m_connection(connection), - m_finished(true), - m_error(IPP_OK) + m_connection(connection) { // If no connection was specified use default one if (m_connection == 0) { m_connection = KCupsConnection::global(); } connect(this, &KCupsRequest::finished, &m_loop, &QEventLoop::quit); } QString KCupsRequest::serverError() const { switch (error()) { case IPP_SERVICE_UNAVAILABLE: return i18n("Print service is unavailable"); case IPP_NOT_FOUND : return i18n("Not found"); default : // In this case we don't want to map all enums qCWarning(LIBKCUPS) << "status unrecognised: " << error(); return QString::fromUtf8(ippErrorString(error())); } } void KCupsRequest::getPPDS(const QString &make) { if (m_connection->readyToStart()) { KIppRequest request(CUPS_GET_PPDS, QLatin1String("/")); if (!make.isEmpty()) { request.addString(IPP_TAG_PRINTER, IPP_TAG_TEXT, KCUPS_PPD_MAKE_AND_MODEL, make); } m_ppds = m_connection->request(request, IPP_TAG_PRINTER); setError(httpGetStatus(CUPS_HTTP_DEFAULT), cupsLastError(), QString::fromUtf8(cupsLastErrorString())); setFinished(); } else { invokeMethod("getPPDS", make); } } static void choose_device_cb(const char *device_class, /* I - Class */ const char *device_id, /* I - 1284 device ID */ const char *device_info, /* I - Description */ const char *device_make_and_model, /* I - Make and model */ const char *device_uri, /* I - Device URI */ const char *device_location, /* I - Location */ void *user_data) /* I - Result object */ { /* * Add the device to the array... */ auto request = static_cast(user_data); QMetaObject::invokeMethod(request, "device", Qt::QueuedConnection, Q_ARG(QString, QString::fromUtf8(device_class)), Q_ARG(QString, QString::fromUtf8(device_id)), Q_ARG(QString, QString::fromUtf8(device_info)), Q_ARG(QString, QString::fromUtf8(device_make_and_model)), Q_ARG(QString, QString::fromUtf8(device_uri)), Q_ARG(QString, QString::fromUtf8(device_location))); } void KCupsRequest::getDevices(int timeout) { getDevices(timeout, QStringList(), QStringList()); } void KCupsRequest::getDevices(int timeout, QStringList includeSchemes, QStringList excludeSchemes) { if (m_connection->readyToStart()) { do { const char *include; if (includeSchemes.isEmpty()) { include = CUPS_INCLUDE_ALL; } else { include = qUtf8Printable(includeSchemes.join(QLatin1String(","))); } const char *exclude; if (excludeSchemes.isEmpty()) { exclude = CUPS_EXCLUDE_NONE; } else { exclude = qUtf8Printable(excludeSchemes.join(QLatin1String(","))); } // Scan for devices for "timeout" seconds cupsGetDevices(CUPS_HTTP_DEFAULT, timeout, include, exclude, (cups_device_cb_t) choose_device_cb, this); } while (m_connection->retry("/admin/", CUPS_GET_DEVICES)); setError(httpGetStatus(CUPS_HTTP_DEFAULT), cupsLastError(), QString::fromUtf8(cupsLastErrorString())); setFinished(true); } else { invokeMethod("getDevices", timeout, includeSchemes, excludeSchemes); } } // THIS function can get the default server dest through the // "printer-is-default" attribute BUT it does not get user // defined default printer, see cupsGetDefault() on www.cups.org for details void KCupsRequest::getPrinters(QStringList attributes, int mask) { if (m_connection->readyToStart()) { KIppRequest request(CUPS_GET_PRINTERS, QLatin1String("/")); request.addInteger(IPP_TAG_OPERATION, IPP_TAG_ENUM, KCUPS_PRINTER_TYPE, CUPS_PRINTER_LOCAL); if (!attributes.isEmpty()) { request.addStringList(IPP_TAG_OPERATION, IPP_TAG_KEYWORD, KCUPS_REQUESTED_ATTRIBUTES, attributes); } if (mask != -1) { request.addInteger(IPP_TAG_OPERATION, IPP_TAG_ENUM, KCUPS_PRINTER_TYPE_MASK, mask); } const ReturnArguments ret = m_connection->request(request, IPP_TAG_PRINTER); for (const QVariantHash &arguments : ret) { m_printers << KCupsPrinter(arguments); } setError(httpGetStatus(CUPS_HTTP_DEFAULT), cupsLastError(), QString::fromUtf8(cupsLastErrorString())); setFinished(); } else { invokeMethod("getPrinters", qVariantFromValue(attributes), mask); } } void KCupsRequest::getPrinterAttributes(const QString &printerName, bool isClass, QStringList attributes) { if (m_connection->readyToStart()) { KIppRequest request(IPP_GET_PRINTER_ATTRIBUTES, QLatin1String("/")); request.addPrinterUri(printerName, isClass); request.addInteger(IPP_TAG_OPERATION, IPP_TAG_ENUM, QLatin1String(KCUPS_PRINTER_TYPE), CUPS_PRINTER_LOCAL); request.addStringList(IPP_TAG_OPERATION, IPP_TAG_KEYWORD, QLatin1String(KCUPS_REQUESTED_ATTRIBUTES), attributes); const ReturnArguments ret = m_connection->request(request, IPP_TAG_PRINTER); for (const QVariantHash &arguments : ret) { // Inject the printer name back to the arguments hash QVariantHash args = arguments; args[KCUPS_PRINTER_NAME] = printerName; m_printers << KCupsPrinter(args); } setError(httpGetStatus(CUPS_HTTP_DEFAULT), cupsLastError(), QString::fromUtf8(cupsLastErrorString())); setFinished(); } else { invokeMethod("getPrinterAttributes", printerName, isClass, qVariantFromValue(attributes)); } } void KCupsRequest::getJobs(const QString &printerName, bool myJobs, int whichJobs, QStringList attributes) { if (m_connection->readyToStart()) { KIppRequest request(IPP_GET_JOBS, QLatin1String("/")); // printer-uri makes the Name of the Job and owner came blank lol request.addPrinterUri(printerName, false); request.addInteger(IPP_TAG_OPERATION, IPP_TAG_ENUM, KCUPS_PRINTER_TYPE, CUPS_PRINTER_LOCAL); request.addStringList(IPP_TAG_OPERATION, IPP_TAG_KEYWORD, KCUPS_REQUESTED_ATTRIBUTES, attributes); request.addInteger(IPP_TAG_OPERATION, IPP_TAG_ENUM, KCUPS_MY_JOBS, myJobs); if (whichJobs == CUPS_WHICHJOBS_COMPLETED) { request.addString(IPP_TAG_OPERATION, IPP_TAG_KEYWORD, KCUPS_WHICH_JOBS, QLatin1String("completed")); } else if (whichJobs == CUPS_WHICHJOBS_ALL) { request.addString(IPP_TAG_OPERATION, IPP_TAG_KEYWORD, KCUPS_WHICH_JOBS, QLatin1String("all")); } const ReturnArguments ret = m_connection->request(request, IPP_TAG_JOB); for (const QVariantHash &arguments : ret) { m_jobs << KCupsJob(arguments); } setError(httpGetStatus(CUPS_HTTP_DEFAULT), cupsLastError(), QString::fromUtf8(cupsLastErrorString())); setFinished(); } else { invokeMethod("getJobs", printerName, myJobs, whichJobs, qVariantFromValue(attributes)); } } void KCupsRequest::getJobAttributes(int jobId, const QString &printerUri, QStringList attributes) { if (m_connection->readyToStart()) { KIppRequest request(IPP_GET_JOB_ATTRIBUTES, QLatin1String("/")); request.addString(IPP_TAG_OPERATION, IPP_TAG_URI, KCUPS_PRINTER_URI, printerUri); request.addInteger(IPP_TAG_OPERATION, IPP_TAG_ENUM, KCUPS_PRINTER_TYPE, CUPS_PRINTER_LOCAL); request.addStringList(IPP_TAG_OPERATION, IPP_TAG_KEYWORD, KCUPS_REQUESTED_ATTRIBUTES, attributes); request.addInteger(IPP_TAG_OPERATION, IPP_TAG_INTEGER, KCUPS_JOB_ID, jobId); const ReturnArguments ret = m_connection->request(request, IPP_TAG_PRINTER); for (const QVariantHash &arguments : ret) { m_jobs << KCupsJob(arguments); } setError(httpGetStatus(CUPS_HTTP_DEFAULT), cupsLastError(), QString::fromUtf8(cupsLastErrorString())); setFinished(); } else { invokeMethod("getJobAttributes", jobId, printerUri, qVariantFromValue(attributes)); } } void KCupsRequest::getServerSettings() { if (m_connection->readyToStart()) { do { int num_settings; cups_option_t *settings; QVariantHash arguments; int ret = cupsAdminGetServerSettings(CUPS_HTTP_DEFAULT, &num_settings, &settings); for (int i = 0; i < num_settings; ++i) { QString name = QString::fromUtf8(settings[i].name); QString value = QString::fromUtf8(settings[i].value); arguments[name] = value; } cupsFreeOptions(num_settings, settings); if (ret) { setError(HTTP_OK, IPP_OK, QString()); } else { setError(httpGetStatus(CUPS_HTTP_DEFAULT), cupsLastError(), QString::fromUtf8(cupsLastErrorString())); } m_server = KCupsServer(arguments); } while (m_connection->retry("/admin/", -1)); setFinished(); } else { invokeMethod("getServerSettings"); } } void KCupsRequest::getPrinterPPD(const QString &printerName) { if (m_connection->readyToStart()) { do { const char *filename; filename = cupsGetPPD2(CUPS_HTTP_DEFAULT, qUtf8Printable(printerName)); qCDebug(LIBKCUPS) << filename; m_ppdFile = QString::fromUtf8(filename); qCDebug(LIBKCUPS) << m_ppdFile; } while (m_connection->retry("/", CUPS_GET_PPD)); setError(httpGetStatus(CUPS_HTTP_DEFAULT), cupsLastError(), QString::fromUtf8(cupsLastErrorString())); setFinished(); } else { invokeMethod("getPrinterPPD", printerName); } } void KCupsRequest::setServerSettings(const KCupsServer &server) { if (m_connection->readyToStart()) { do { QVariantHash args = server.arguments(); int num_settings = 0; cups_option_t *settings; QVariantHash::const_iterator i = args.constBegin(); while (i != args.constEnd()) { num_settings = cupsAddOption(qUtf8Printable(i.key()), qUtf8Printable(i.value().toString()), num_settings, &settings); ++i; } cupsAdminSetServerSettings(CUPS_HTTP_DEFAULT, num_settings, settings); cupsFreeOptions(num_settings, settings); } while (m_connection->retry("/admin/", -1)); setError(httpGetStatus(CUPS_HTTP_DEFAULT), cupsLastError(), QString::fromUtf8(cupsLastErrorString())); setFinished(); } else { invokeMethod("setServerSettings", qVariantFromValue(server)); } } void KCupsRequest::addOrModifyPrinter(const QString &printerName, const QVariantHash &attributes, const QString &filename) { KIppRequest request(CUPS_ADD_MODIFY_PRINTER, QLatin1String("/admin/"), filename); request.addPrinterUri(printerName); request.addVariantValues(attributes); process(request); } void KCupsRequest::addOrModifyClass(const QString &printerName, const QVariantHash &attributes) { KIppRequest request(CUPS_ADD_MODIFY_CLASS, QLatin1String("/admin/")); request.addPrinterUri(printerName, true); request.addVariantValues(attributes); process(request); } void KCupsRequest::setShared(const QString &printerName, bool isClass, bool shared) { KIppRequest request(isClass ? CUPS_ADD_MODIFY_CLASS : CUPS_ADD_MODIFY_PRINTER, QLatin1String("/admin/")); request.addPrinterUri(printerName, isClass); request.addBoolean(IPP_TAG_OPERATION, KCUPS_PRINTER_IS_SHARED, shared); process(request); } void KCupsRequest::pausePrinter(const QString &printerName) { KIppRequest request(IPP_PAUSE_PRINTER, QLatin1String("/admin/")); request.addPrinterUri(printerName); process(request); } void KCupsRequest::resumePrinter(const QString &printerName) { KIppRequest request(IPP_RESUME_PRINTER, QLatin1String("/admin/")); request.addPrinterUri(printerName); process(request); } void KCupsRequest::rejectJobs(const QString &printerName) { KIppRequest request(CUPS_REJECT_JOBS, QLatin1String("/admin/")); request.addPrinterUri(printerName); process(request); } void KCupsRequest::acceptJobs(const QString &printerName) { KIppRequest request(CUPS_ACCEPT_JOBS, QLatin1String("/admin/")); request.addPrinterUri(printerName); process(request); } void KCupsRequest::setDefaultPrinter(const QString &printerName) { KIppRequest request(CUPS_SET_DEFAULT, QLatin1String("/admin/")); request.addPrinterUri(printerName); process(request); } void KCupsRequest::deletePrinter(const QString &printerName) { KIppRequest request(CUPS_DELETE_PRINTER, QLatin1String("/admin/")); request.addPrinterUri(printerName); process(request); } void KCupsRequest::printTestPage(const QString &printerName, bool isClass) { QString resource; /* POST resource path */ QString filename; /* Test page filename */ QString datadir; /* CUPS_DATADIR env var */ /* * Locate the test page file... */ datadir = QString::fromUtf8(qgetenv("CUPS_DATADIR")); if (datadir.isEmpty()) { datadir = CUPS_DATADIR; } filename = datadir % QLatin1String("/data/testprint"); /* * Point to the printer/class... */ if (isClass) { - resource = QLatin1String("/classes/") % printerName; + resource = QLatin1String("/classes/") + printerName; } else { - resource = QLatin1String("/printers/") % printerName; + resource = QLatin1String("/printers/") + printerName; } KIppRequest request(IPP_PRINT_JOB, resource, filename); request.addPrinterUri(printerName); request.addString(IPP_TAG_OPERATION, IPP_TAG_NAME, KCUPS_JOB_NAME, i18n("Test Page")); process(request); } void KCupsRequest::printCommand(const QString &printerName, const QString &command, const QString &title) { if (m_connection->readyToStart()) { do { int job_id; /* Command file job */ char command_file[1024]; /* Command "file" */ http_status_t status; /* Document status */ cups_option_t hold_option; /* job-hold-until option */ /* * Create the CUPS command file... */ snprintf(command_file, sizeof(command_file), "#CUPS-COMMAND\n%s\n", command.toUtf8().constData()); /* * Send the command file job... */ hold_option.name = const_cast("job-hold-until"); hold_option.value = const_cast("no-hold"); if ((job_id = cupsCreateJob(CUPS_HTTP_DEFAULT, qUtf8Printable(printerName), qUtf8Printable(title), 1, &hold_option)) < 1) { qWarning() << "Unable to send command to printer driver!"; setError(HTTP_OK, IPP_NOT_POSSIBLE, i18n("Unable to send command to printer driver!")); setFinished(); return; } status = cupsStartDocument(CUPS_HTTP_DEFAULT, qUtf8Printable(printerName), job_id, NULL, CUPS_FORMAT_COMMAND, 1); if (status == HTTP_CONTINUE) { status = cupsWriteRequestData(CUPS_HTTP_DEFAULT, command_file, strlen(command_file)); } if (status == HTTP_CONTINUE) { cupsFinishDocument(CUPS_HTTP_DEFAULT, qUtf8Printable(printerName)); } setError(httpGetStatus(CUPS_HTTP_DEFAULT), cupsLastError(), QString::fromUtf8(cupsLastErrorString())); if (httpGetStatus(CUPS_HTTP_DEFAULT), cupsLastError() >= IPP_REDIRECTION_OTHER_SITE) { qWarning() << "Unable to send command to printer driver!"; cupsCancelJob(qUtf8Printable(printerName), job_id); setFinished(); return; // Return to avoid a new try } } while (m_connection->retry("/", IPP_CREATE_JOB)); setError(httpGetStatus(CUPS_HTTP_DEFAULT), cupsLastError(), QString::fromUtf8(cupsLastErrorString())); setFinished(); } else { invokeMethod("printCommand", printerName, command, title); } } void KCupsRequest::cancelJob(const QString &printerName, int jobId) { KIppRequest request(IPP_CANCEL_JOB, QLatin1String("/jobs/")); request.addPrinterUri(printerName); request.addInteger(IPP_TAG_OPERATION, IPP_TAG_INTEGER, KCUPS_JOB_ID, jobId); process(request); } void KCupsRequest::holdJob(const QString &printerName, int jobId) { KIppRequest request(IPP_HOLD_JOB, QLatin1String("/jobs/")); request.addPrinterUri(printerName); request.addInteger(IPP_TAG_OPERATION, IPP_TAG_INTEGER, KCUPS_JOB_ID, jobId); process(request); } void KCupsRequest::releaseJob(const QString &printerName, int jobId) { KIppRequest request(IPP_RELEASE_JOB, QLatin1String("/jobs/")); request.addPrinterUri(printerName); request.addInteger(IPP_TAG_OPERATION, IPP_TAG_INTEGER, KCUPS_JOB_ID, jobId); process(request); } void KCupsRequest::restartJob(const QString &printerName, int jobId) { KIppRequest request(IPP_RESTART_JOB, QLatin1String("/jobs/")); request.addPrinterUri(printerName); request.addInteger(IPP_TAG_OPERATION, IPP_TAG_INTEGER, KCUPS_JOB_ID, jobId); process(request); } void KCupsRequest::moveJob(const QString &fromPrinterName, int jobId, const QString &toPrinterName) { if (jobId < -1 || fromPrinterName.isEmpty() || toPrinterName.isEmpty() || jobId == 0) { qWarning() << "Internal error, invalid input data" << jobId << fromPrinterName << toPrinterName; setFinished(); return; } KIppRequest request(CUPS_MOVE_JOB, QLatin1String("/jobs/")); request.addPrinterUri(fromPrinterName); request.addInteger(IPP_TAG_OPERATION, IPP_TAG_INTEGER, KCUPS_JOB_ID, jobId); QString toPrinterUri = KIppRequest::assembleUrif(toPrinterName, false); request.addString(IPP_TAG_OPERATION, IPP_TAG_URI, KCUPS_JOB_PRINTER_URI, toPrinterUri); process(request); } void KCupsRequest::invokeMethod(const char *method, const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, const QVariant &arg7, const QVariant &arg8) { m_error = IPP_OK; m_errorMsg.clear(); m_printers.clear(); m_jobs.clear(); m_ppds.clear(); m_ppdFile.clear(); // If this fails we get into a infinite loop // Do not use global()->thread() which point // to the KCupsConnection parent thread moveToThread(m_connection); m_finished = !QMetaObject::invokeMethod(this, method, Qt::QueuedConnection, QGenericArgument(arg1.typeName(), arg1.data()), QGenericArgument(arg2.typeName(), arg2.data()), QGenericArgument(arg3.typeName(), arg3.data()), QGenericArgument(arg4.typeName(), arg4.data()), QGenericArgument(arg5.typeName(), arg5.data()), QGenericArgument(arg6.typeName(), arg6.data()), QGenericArgument(arg7.typeName(), arg7.data()), QGenericArgument(arg8.typeName(), arg8.data())); if (m_finished) { setError(HTTP_ERROR, IPP_BAD_REQUEST, i18n("Failed to invoke method: %1", QLatin1String(method))); setFinished(); } } void KCupsRequest::process(const KIppRequest &request) { if (m_connection->readyToStart()) { m_connection->request(request); setError(httpGetStatus(CUPS_HTTP_DEFAULT), cupsLastError(), QString::fromUtf8(cupsLastErrorString())); setFinished(); } else { invokeMethod("process", qVariantFromValue(request)); } } ReturnArguments KCupsRequest::ppds() const { return m_ppds; } KCupsServer KCupsRequest::serverSettings() const { return m_server; } QString KCupsRequest::printerPPD() const { return m_ppdFile; } KCupsPrinters KCupsRequest::printers() const { return m_printers; } KCupsJobs KCupsRequest::jobs() const { return m_jobs; } void KCupsRequest::waitTillFinished() { if (m_finished) { return; } m_loop.exec(); } bool KCupsRequest::hasError() const { return m_error; } ipp_status_t KCupsRequest::error() const { return m_error; } http_status_t KCupsRequest::httpStatus() const { return m_httpStatus; } QString KCupsRequest::errorMsg() const { return m_errorMsg; } KCupsConnection *KCupsRequest::connection() const { return m_connection; } void KCupsRequest::setError(http_status_t httpStatus, ipp_status_t error, const QString &errorMsg) { m_httpStatus = httpStatus; m_error = error; m_errorMsg = errorMsg; } void KCupsRequest::setFinished(bool delayed) { m_finished = true; if (delayed) { QTimer::singleShot(0, this, [this] () { emit finished(this); }); } else { emit finished(this); } } diff --git a/libkcups/KCupsRequest.h b/libkcups/KCupsRequest.h index 0d9cc16..e1f8892 100644 --- a/libkcups/KCupsRequest.h +++ b/libkcups/KCupsRequest.h @@ -1,323 +1,323 @@ /*************************************************************************** * Copyright (C) 2010-2012 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 KCUPS_REQUEST_H #define KCUPS_REQUEST_H #include #include #include "KCupsConnection.h" #include "KCupsJob.h" #include "KCupsPrinter.h" #include "KCupsServer.h" #include "KIppRequest.h" class Q_DECL_EXPORT KCupsRequest : public QObject { Q_OBJECT public: /** * Default constructor, it takes no parent * because it will move to KCupsConnection thread * * Before calling any method connect to finished() signal or * use waitTillFinished(). * You must delete the object manually after finished * using deleteLater(). */ explicit KCupsRequest(KCupsConnection *connection = 0); /** * This method creates an event loop * and quits after the request is finished */ void waitTillFinished(); /** * This method returns true if there was an error with the request */ bool hasError() const; ipp_status_t error() const; http_status_t httpStatus() const; QString serverError() const; QString errorMsg() const; KCupsConnection* connection() const; /** * Non empty when getPrinters is called and finish is emitted */ KCupsPrinters printers() const; /** * Non empty when getPPDs is called and finish is emitted */ ReturnArguments ppds() const; /** * Non empty when getServerSettings() is called and finish is emitted */ KCupsServer serverSettings() const; /** * Non empty when \sa getPrinterPPD() is called and finish is emitted * \warning You must unlik the given file name */ QString printerPPD() const; /** * Non empty when getJobs is called and finish is emitted */ KCupsJobs jobs() const; /** * Get all available PPDs from the givem make * @param make the maker of the printer */ Q_INVOKABLE void getPPDS(const QString &make = QString()); /** * Get all devices that could be added as a printer * This method emits device() */ Q_INVOKABLE void getDevices(int timeout = CUPS_TIMEOUT_DEFAULT); /** * Get all devices that could be added as a printer * This method emits device() */ Q_INVOKABLE void getDevices(int timeout, QStringList includeSchemes, QStringList excludeSchemes); /** * Get all available printers * @param mask filter the kind of printer that will be emitted (-1 to no filter) * @param requestedAttr the attibutes to retrieve from cups * This method emits printer() * * THIS function can get the default server dest through the * "printer-is-default" attribute BUT it does not get user * defined default printer, see cupsGetDefault() on www.cups.org for details */ Q_INVOKABLE void getPrinters(QStringList attributes, int mask = -1); /** * Get attributes from a given printer * @param printer The printer to apply the change * @param isClass True it is a printer class * @param attributes The attributes you are requesting * * @return The return will be stored in \sa printers() */ Q_INVOKABLE void getPrinterAttributes(const QString &printerName, bool isClass, QStringList attributes); /** * Get all jobs * This method emits job() * TODO we need to see if we authenticate as root to do some taks * the myJobs will return the user's jobs or the root's jobs * @param printer which printer you are requiring jobs for (empty = all printers) * @param myJobs true if you only want your jobs * @param whichJobs which kind jobs should be sent */ Q_INVOKABLE void getJobs(const QString &printerName, bool myJobs, int whichJobs, QStringList attributes); /** * Get attributes from a given printer * @param printer The printer to apply the change * @param isClass True it is a printer class * @param attributes The attributes you are requesting * * @return The return will be stored in \sa printers() */ Q_INVOKABLE void getJobAttributes(int jobId, const QString &printerUri, QStringList attributes); /** * Get the CUPS server settings * This method emits server() */ Q_INVOKABLE void getServerSettings(); /** * Get the PPD associated with @arg printerName * the result is stored at \sa printerPPD() */ Q_INVOKABLE void getPrinterPPD(const QString &printerName); /** * Get the CUPS server settings * @param userValues the new server settings */ Q_INVOKABLE void setServerSettings(const KCupsServer &server); // ---- Printer Methods /** * Add or Modify a Printer * @param printerName The printer to apply the change * @param attributes The new attributes of the printer * @param filename The file name in case of changing the PPD */ void addOrModifyPrinter(const QString &printerName, const QVariantHash &attributes, const QString &filename = QString()); /** * Add or Modify a Class * @param className The class to apply the change * @param attributes The new attributes of the printer */ void addOrModifyClass(const QString &className, const QVariantHash &attributes); /** * Set if a given printer should be shared among other cups * @param printer The printer to apply the change * @param isClass True it is a printer class * @param shared True if it should be shared */ void setShared(const QString &printerName, bool isClass, bool shared); /** * Set if a given printer should be the default one among others * @param printer The printer to apply the change */ void setDefaultPrinter(const QString &printerName); /** * Pause the given printer from receiving jobs * @param printer The printer to apply the change */ void pausePrinter(const QString &printerName); /** * Resume the given printer from receiving jobs * @param printer The printer to apply the change */ void resumePrinter(const QString &printerName); /** * Allows the given printer from receiving jobs * @param printer The printer to apply the change */ void acceptJobs(const QString &printerName); /** * Prevents the given printer from receiving jobs * @param printer The printer to apply the change */ void rejectJobs(const QString &printerName); /** * Delete the given printer, if it's not local it's not * possible to delete it * @param printer The printer to apply the change */ void deletePrinter(const QString &printerName); /** * Print a test page * @param printerName The printer where the test should be done * @param isClass True it is a printer class */ void printTestPage(const QString &printerName, bool isClass); /** * Print a command test * @param printerName The printer where the test should be done * @param command The command to print * @param title The title of the command */ Q_INVOKABLE void printCommand(const QString &printerName, const QString &command, const QString &title); // Jobs methods /** * Cancels tries to cancel a given job * @param printerName the destination name (printer) * @param jobId the job identification */ void cancelJob(const QString &printerName, int jobId); /** * Holds the printing of a given job * @param printerName the destination name (printer) * @param jobId the job identification */ void holdJob(const QString &printerName, int jobId); /** * Holds the printing of a given job * @param printerName the destination name (printer) * @param jobId the job identification */ void releaseJob(const QString &printerName, int jobId); /** * Restart the printing of a given job * @param printerName the destination name (printer) * @param jobId the job identification */ void restartJob(const QString &printerName, int jobId); /** * Holds the printing of a given job * @param fromDestName the destination name which holds the job * @param jobId the job identification * @param toDestName the destination to hold the job */ void moveJob(const QString &fromPrinterName, int jobId, const QString &toPrinterName); signals: void device(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(KCupsRequest *); private: void invokeMethod(const char *method, const QVariant &arg1 = QVariant(), const QVariant &arg2 = QVariant(), const QVariant &arg3 = QVariant(), const QVariant &arg4 = QVariant(), const QVariant &arg5 = QVariant(), const QVariant &arg6 = QVariant(), const QVariant &arg7 = QVariant(), const QVariant &arg8 = QVariant()); Q_INVOKABLE void process(const KIppRequest &request); void setError(http_status_t httpStatus, ipp_status_t error, const QString &errorMsg); void setFinished(bool delayed = false); KCupsConnection *m_connection; QEventLoop m_loop; - bool m_finished; - ipp_status_t m_error; + bool m_finished = true; + ipp_status_t m_error = IPP_OK; http_status_t m_httpStatus; QString m_errorMsg; ReturnArguments m_ppds; KCupsServer m_server; QString m_ppdFile; KCupsPrinters m_printers; KCupsJobs m_jobs; }; #endif // KCUPS_REQUEST_H diff --git a/libkcups/KIppRequest.cpp b/libkcups/KIppRequest.cpp index 5d1fd97..42adc2c 100644 --- a/libkcups/KIppRequest.cpp +++ b/libkcups/KIppRequest.cpp @@ -1,276 +1,273 @@ /*************************************************************************** - * Copyright (C) 2010-2013 by Daniel Nicoletti * + * 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 "KIppRequest.h" #include "KIppRequest_p.h" #include "Debug.h" -#include - KIppRequest::KIppRequest() : d_ptr(new KIppRequestPrivate) { } KIppRequest::KIppRequest(const KIppRequest &other) : d_ptr(new KIppRequestPrivate) { *this = other; } KIppRequest::KIppRequest(ipp_op_t operation, const QString &resource, const QString &filename) : d_ptr(new KIppRequestPrivate) { Q_D(KIppRequest); d->operation = operation; d->resource = resource; d->filename = filename; // send our user name on the request too addString(IPP_TAG_OPERATION, IPP_TAG_NAME, QLatin1String(KCUPS_REQUESTING_USER_NAME), QString::fromUtf8(cupsUser())); } KIppRequest::~KIppRequest() { - Q_D(KIppRequest); - delete d; + delete d_ptr; } ipp_op_t KIppRequest::operation() const { Q_D(const KIppRequest); return d->operation; } QString KIppRequest::resource() const { Q_D(const KIppRequest); return d->resource; } QString KIppRequest::filename() const { Q_D(const KIppRequest); return d->filename; } ipp_t *KIppRequest::sendIppRequest() const { Q_D(const KIppRequest); ipp_t *request = ippNewRequest(d->operation); d->addRawRequestsToIpp(request); if (d->filename.isNull()) { return cupsDoRequest(CUPS_HTTP_DEFAULT, request, qUtf8Printable(d->resource)); } else { return cupsDoFileRequest(CUPS_HTTP_DEFAULT, request, qUtf8Printable(d->resource), qUtf8Printable(d->filename)); } } void KIppRequest::addString(ipp_tag_t group, ipp_tag_t valueTag, const QString &name, const QString &value) { Q_D(KIppRequest); d->addRequest(group, valueTag, name, value); } void KIppRequest::addStringList(ipp_tag_t group, ipp_tag_t valueTag, const QString &name, const QStringList &value) { Q_D(KIppRequest); d->addRequest(group, valueTag, name, value); } void KIppRequest::addInteger(ipp_tag_t group, ipp_tag_t valueTag, const QString &name, int value) { Q_D(KIppRequest); d->addRequest(group, valueTag, name, value); } void KIppRequest::addBoolean(ipp_tag_t group, const QString &name, bool value) { Q_D(KIppRequest); d->addRequest(group, IPP_TAG_ZERO, name, value); } void KIppRequest::addVariantValues(const QVariantHash &values) { - QVariantHash::ConstIterator i = values.constBegin(); + auto i = values.constBegin(); while (i != values.constEnd()) { - QString key = i.key(); - QVariant value = i.value(); + const QString &key = i.key(); + const QVariant &value = i.value(); switch (value.type()) { case QVariant::Bool: // Still in use at add-printer/PageAddPrinter.cpp if (key == QLatin1String(KCUPS_PRINTER_IS_ACCEPTING_JOBS)) { addBoolean(IPP_TAG_PRINTER, key, value.toBool()); } else { addBoolean(IPP_TAG_OPERATION, key, value.toBool()); } break; case QVariant::Int: // Still in use at add-printer/PageAddPrinter.cpp if (key == QLatin1String(KCUPS_PRINTER_STATE)) { addInteger(IPP_TAG_PRINTER, IPP_TAG_ENUM, key, value.toInt()); } else { addInteger(IPP_TAG_OPERATION, IPP_TAG_ENUM, key, value.toInt()); } break; case QVariant::String: // Still in use at add-printer/* if (key == QLatin1String(KCUPS_DEVICE_URI)) { // device uri has a different TAG addString(IPP_TAG_PRINTER, IPP_TAG_URI, key, value.toString()); } else if (key == QLatin1String(KCUPS_PRINTER_OP_POLICY) || key == QLatin1String(KCUPS_PRINTER_ERROR_POLICY) || key == QLatin1String("ppd-name")) { // printer-op-policy has a different TAG addString(IPP_TAG_PRINTER, IPP_TAG_NAME, key, value.toString()); } else if (key == QLatin1String(KCUPS_JOB_NAME)) { addString(IPP_TAG_OPERATION, IPP_TAG_NAME, key, value.toString()); } else if (key == QLatin1String(KCUPS_WHICH_JOBS)) { addString(IPP_TAG_OPERATION, IPP_TAG_KEYWORD, key, value.toString()); } else { addString(IPP_TAG_PRINTER, IPP_TAG_TEXT, key, value.toString()); } break; case QVariant::StringList: if (key == QLatin1String(KCUPS_MEMBER_URIS)) { addStringList(IPP_TAG_PRINTER, IPP_TAG_URI, key, value.toStringList()); } else { addStringList(IPP_TAG_PRINTER, IPP_TAG_NAME, key, value.toStringList()); } break; case QVariant::UInt: addInteger(IPP_TAG_OPERATION, IPP_TAG_ENUM, key, value.toInt()); break; default: qCWarning(LIBKCUPS) << "type NOT recognized! This will be ignored:" << key << "values" << i.value(); } ++i; } } void KIppRequest::addPrinterUri(const QString &printerName, bool isClass) { QString uri = assembleUrif(printerName, isClass); addString(IPP_TAG_OPERATION, IPP_TAG_URI, QLatin1String(KCUPS_PRINTER_URI), uri); } QString KIppRequest::assembleUrif(const QString &name, bool isClass) { char uri[HTTP_MAX_URI]; // printer URI QString destination; if (isClass) { - destination = QLatin1String("/classes/") % name; + destination = QLatin1String("/classes/") + name; } else { - destination = QLatin1String("/printers/") % name; + destination = QLatin1String("/printers/") + name; } httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", cupsUser(), "localhost", ippPort(), destination.toUtf8().constData()); return QString::fromLatin1(uri); } KIppRequest &KIppRequest::operator =(const KIppRequest &other) { Q_D(KIppRequest); if (this == &other) return *this; *d = *other.d_ptr; return *this; } void KIppRequestPrivate::addRequest(ipp_tag_t group, ipp_tag_t valueTag, const QString &name, const QVariant &value) { KCupsRawRequest request; request.group = group; request.valueTag = valueTag; request.name = name; request.value = value; rawRequests << request; } void KIppRequestPrivate::addRawRequestsToIpp(ipp_t *ipp) const { // sort the values as CUPS requires it std::sort(rawRequests.begin(), rawRequests.end(), [] (const KCupsRawRequest &a, const KCupsRawRequest &b) { return a.group < b.group; }); const QList &requests = rawRequests; for (const KCupsRawRequest &request :requests) { switch (request.value.type()) { case QVariant::Bool: ippAddBoolean(ipp, request.group, request.name.toUtf8().constData(), request.value.toBool()); break; case QVariant::Int: case QVariant::UInt: ippAddInteger(ipp, request.group, request.valueTag, request.name.toUtf8().constData(), request.value.toInt()); break; case QVariant::String: ippAddString(ipp, request.group, request.valueTag, request.name.toUtf8().constData(), "utf-8", request.value.toString().toUtf8().constData()); break; case QVariant::StringList: { QStringList list = request.value.toStringList(); QList valuesQByteArrayList; const char **values = qStringListToCharPtrPtr(list, valuesQByteArrayList); ippAddStrings(ipp, request.group, request.valueTag, request.name.toUtf8().constData(), list.size(), "utf-8", values); // ippAddStrings deep copies everything so we can throw away the values. // the QBAList and content is auto discarded when going out of scope. delete [] values; break; } default: qCWarning(LIBKCUPS) << "type NOT recognized! This will be ignored:" << request.name << "values" << request.value; } } } diff --git a/libkcups/PPDModel.cpp b/libkcups/PPDModel.cpp index 0f4d1ab..eced5b6 100644 --- a/libkcups/PPDModel.cpp +++ b/libkcups/PPDModel.cpp @@ -1,128 +1,126 @@ /*************************************************************************** * Copyright (C) 2010-2018 by Daniel Nicoletti * * * * 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 "PPDModel.h" #include "Debug.h" -#include - #include PPDModel::PPDModel(QObject *parent) : QStandardItemModel(parent) { } void PPDModel::setPPDs(const QList &ppds, const DriverMatchList &driverMatch) { clear(); QStandardItem *recommended = 0; for (const DriverMatch &driver : driverMatch) { // Find the matched PPD on the PPDs list for (const QVariantHash &ppd : ppds) { if (ppd[QLatin1String("ppd-name")].toString() == driver.ppd) { // Create the PPD QStandardItem *ppdItem = createPPDItem(ppd, true); if (recommended == 0) { recommended = new QStandardItem; recommended->setText(i18n("Recommended Drivers")); appendRow(recommended); } recommended->appendRow(ppdItem); break; } } } for (const QVariantHash &ppd : ppds) { // Find or create the PPD parent (printer Make) QStandardItem *makeItem = findCreateMake(ppd[QLatin1String("ppd-make")].toString()); // Create the PPD QStandardItem *ppdItem = createPPDItem(ppd, false); makeItem->appendRow(ppdItem); } } QStandardItem* PPDModel::findCreateMake(const QString &make) { for (int i = 0; i < rowCount(); ++i) { QStandardItem *makeItem = item(i); if (makeItem->text() == make) { return makeItem; } } auto makeItem = new QStandardItem(make); appendRow(makeItem); return makeItem; } Qt::ItemFlags PPDModel::flags(const QModelIndex &index) const { Q_UNUSED(index) return Qt::ItemIsSelectable | Qt::ItemIsEnabled; } void PPDModel::clear() { // Remove all rows from the model removeRows(0, rowCount()); } QStandardItem *PPDModel::createPPDItem(const QVariantHash &ppd, bool recommended) { auto ret = new QStandardItem; QString make = ppd[QLatin1String("ppd-make")].toString(); QString makeAndModel = ppd[QLatin1String("ppd-make-and-model")].toString(); QString naturalLanguage = ppd[QLatin1String("ppd-natural-language")].toString(); QString ppdName = ppd[QLatin1String("ppd-name")].toString(); // Set this data before we change the makeAndModel ret->setData(ppdName, PPDName); ret->setData(make, PPDMake); ret->setData(makeAndModel, PPDMakeAndModel); QString text; if (recommended) { text = makeAndModel % QLatin1String(" (") % naturalLanguage % QLatin1Char(')'); } else { // Removes the Make part of the string if (makeAndModel.startsWith(make)) { makeAndModel.remove(0, make.size() + 1); } // Create the PPD text = makeAndModel.trimmed() % QLatin1String(" (") % naturalLanguage % QLatin1Char(')'); } ret->setText(text); return ret; } diff --git a/libkcups/PrinterModel.cpp b/libkcups/PrinterModel.cpp index 394cbc3..2d77483 100644 --- a/libkcups/PrinterModel.cpp +++ b/libkcups/PrinterModel.cpp @@ -1,522 +1,525 @@ /*************************************************************************** * 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 "PrinterModel.h" #include "Debug.h" #include #include #include #include #include #include #include #include #include #include PrinterModel::PrinterModel(QObject *parent) : QStandardItemModel(parent), m_unavailable(true) { - m_attributes << KCUPS_PRINTER_NAME; - m_attributes << KCUPS_PRINTER_STATE; - m_attributes << KCUPS_PRINTER_STATE_MESSAGE; - m_attributes << KCUPS_PRINTER_IS_SHARED; - m_attributes << KCUPS_PRINTER_IS_ACCEPTING_JOBS; - m_attributes << KCUPS_PRINTER_TYPE; - m_attributes << KCUPS_PRINTER_LOCATION; - m_attributes << KCUPS_PRINTER_INFO; - m_attributes << KCUPS_PRINTER_MAKE_AND_MODEL; - m_attributes << KCUPS_PRINTER_COMMANDS; - m_attributes << KCUPS_MARKER_CHANGE_TIME; - m_attributes << KCUPS_MARKER_COLORS; - m_attributes << KCUPS_MARKER_LEVELS; - m_attributes << KCUPS_MARKER_NAMES; - m_attributes << KCUPS_MARKER_TYPES; + m_attributes = QStringList{ + KCUPS_PRINTER_NAME, + KCUPS_PRINTER_STATE, + KCUPS_PRINTER_STATE_MESSAGE, + KCUPS_PRINTER_IS_SHARED, + KCUPS_PRINTER_IS_ACCEPTING_JOBS, + KCUPS_PRINTER_TYPE, + KCUPS_PRINTER_LOCATION, + KCUPS_PRINTER_INFO, + KCUPS_PRINTER_MAKE_AND_MODEL, + KCUPS_PRINTER_COMMANDS, + KCUPS_MARKER_CHANGE_TIME, + KCUPS_MARKER_COLORS, + KCUPS_MARKER_LEVELS, + KCUPS_MARKER_NAMES, + KCUPS_MARKER_TYPES + }; m_roles = QStandardItemModel::roleNames(); m_roles[DestStatus] = "stateMessage"; m_roles[DestName] = "printerName"; m_roles[DestState] = "printerState"; m_roles[DestIsDefault] = "isDefault"; m_roles[DestIsShared] = "isShared"; m_roles[DestIsAcceptingJobs] = "isAcceptingJobs"; m_roles[DestIsPaused] = "isPaused"; m_roles[DestIsClass] = "isClass"; m_roles[DestLocation] = "location"; m_roles[DestDescription] = "info"; m_roles[DestKind] = "kind"; m_roles[DestType] = "type"; m_roles[DestCommands] = "commands"; m_roles[DestMarkerChangeTime] = "markerChangeTime"; m_roles[DestMarkers] = "markers"; m_roles[DestIconName] = "iconName"; m_roles[DestRemote] = "remote"; // This is emitted when a printer is added connect(KCupsConnection::global(), &KCupsConnection::printerAdded, this, &PrinterModel::insertUpdatePrinter); // This is emitted when a printer is modified connect(KCupsConnection::global(), &KCupsConnection::printerModified, this, &PrinterModel::insertUpdatePrinter); // This is emitted when a printer has it's state changed connect(KCupsConnection::global(), &KCupsConnection::printerStateChanged, this, &PrinterModel::insertUpdatePrinter); // This is emitted when a printer is stopped connect(KCupsConnection::global(), &KCupsConnection::printerStopped, this, &PrinterModel::insertUpdatePrinter); // This is emitted when a printer is restarted connect(KCupsConnection::global(), &KCupsConnection::printerRestarted, this, &PrinterModel::insertUpdatePrinter); // This is emitted when a printer is shutdown connect(KCupsConnection::global(), &KCupsConnection::printerShutdown, this, &PrinterModel::insertUpdatePrinter); // This is emitted when a printer is removed connect(KCupsConnection::global(), &KCupsConnection::printerDeleted, this, &PrinterModel::printerRemoved); connect(KCupsConnection::global(), &KCupsConnection::serverAudit, this, &PrinterModel::serverChanged); connect(KCupsConnection::global(), &KCupsConnection::serverStarted, this, &PrinterModel::serverChanged); connect(KCupsConnection::global(), &KCupsConnection::serverStopped, this, &PrinterModel::serverChanged); connect(KCupsConnection::global(), &KCupsConnection::serverRestarted, this, &PrinterModel::serverChanged); // Deprecated stuff that works better than the above connect(KCupsConnection::global(), &KCupsConnection::rhPrinterAdded, this, &PrinterModel::insertUpdatePrinterName); connect(KCupsConnection::global(), &KCupsConnection::rhPrinterRemoved, this, &PrinterModel::printerRemovedName); connect(KCupsConnection::global(), &KCupsConnection::rhQueueChanged, this, &PrinterModel::insertUpdatePrinterName); connect(this, &PrinterModel::rowsInserted, this, &PrinterModel::slotCountChanged); connect(this, &PrinterModel::rowsRemoved, this, &PrinterModel::slotCountChanged); connect(this, &PrinterModel::modelReset, this, &PrinterModel::slotCountChanged); update(); } void PrinterModel::getDestsFinished(KCupsRequest *request) { // When there is no printer IPP_NOT_FOUND is returned if (request->hasError() && request->error() != IPP_NOT_FOUND) { // clear the model after so that the proper widget can be shown clear(); emit error(request->error(), request->serverError(), request->errorMsg()); if (request->error() == IPP_SERVICE_UNAVAILABLE && !m_unavailable) { m_unavailable = true; emit serverUnavailableChanged(m_unavailable); } } else { if (m_unavailable) { m_unavailable = false; emit serverUnavailableChanged(m_unavailable); } - KCupsPrinters printers = request->printers(); + const KCupsPrinters printers = request->printers(); for (int i = 0; i < printers.size(); ++i) { // If there is a printer and it's not the current one add it // as a new destination int dest_row = destRow(printers.at(i).name()); if (dest_row == -1) { // not found, insert new one insertDest(i, printers.at(i)); } else if (dest_row == i) { // update the printer updateDest(item(i), printers.at(i)); } else { // found at wrong position // take it and insert on the right position QList row = takeRow(dest_row); insertRow(i, row); updateDest(item(i), printers.at(i)); } } // remove old printers // The above code starts from 0 and make sure // dest == modelIndex(x) and if it's not the // case it either inserts or moves it. // so any item > num_jobs can be safely deleted while (rowCount() > printers.size()) { removeRow(rowCount() - 1); } emit error(IPP_OK, QString(), QString()); } request->deleteLater(); } void PrinterModel::slotCountChanged() { emit countChanged(rowCount()); } QVariant PrinterModel::headerData(int section, Qt::Orientation orientation, int role) const { if (section == 0 && orientation == Qt::Horizontal && role == Qt::DisplayRole) { return i18n("Printers"); } return QVariant(); } int PrinterModel::count() const { return rowCount(); } bool PrinterModel::serverUnavailable() const { return m_unavailable; } QHash PrinterModel::roleNames() const { return m_roles; } void PrinterModel::pausePrinter(const QString &printerName) { QPointer request = new KCupsRequest; request->pausePrinter(printerName); request->waitTillFinished(); if (request) { request->deleteLater(); } } void PrinterModel::resumePrinter(const QString &printerName) { QPointer request = new KCupsRequest; request->resumePrinter(printerName); request->waitTillFinished(); if (request) { request->deleteLater(); } } void PrinterModel::rejectJobs(const QString &printerName) { QPointer request = new KCupsRequest; request->rejectJobs(printerName); request->waitTillFinished(); if (request) { request->deleteLater(); } } void PrinterModel::acceptJobs(const QString &printerName) { QPointer request = new KCupsRequest; request->acceptJobs(printerName); request->waitTillFinished(); if (request) { request->deleteLater(); } } void PrinterModel::update() { // kcmshell(6331) PrinterModel::update: (QHash(("printer-type", QVariant(int, 75534348) ) ( "marker-names" , QVariant(QStringList, ("Cyan", "Yellow", "Magenta", "Black") ) ) ( "printer-name" , QVariant(QString, "EPSON_Stylus_TX105") ) ( "marker-colors" , QVariant(QStringList, ("#00ffff", "#ffff00", "#ff00ff", "#000000") ) ) ( "printer-location" , QVariant(QString, "Luiz Vitor’s MacBook Pro") ) ( "marker-levels" , QVariant(QList, ) ) ( "marker-types" , QVariant(QStringList, ("inkCartridge", "inkCartridge", "inkCartridge", "inkCartridge") ) ) ( "printer-is-shared" , QVariant(bool, true) ) ( "printer-state-message" , QVariant(QString, "") ) ( "printer-commands" , QVariant(QStringList, ("Clean", "PrintSelfTestPage", "ReportLevels") ) ) ( "marker-change-time" , QVariant(int, 1267903160) ) ( "printer-state" , QVariant(int, 3) ) ( "printer-info" , QVariant(QString, "EPSON Stylus TX105") ) ( "printer-make-and-model" , QVariant(QString, "EPSON TX105 Series") ) ) ) // Get destinations with these attributes auto request = new KCupsRequest; connect(request, &KCupsRequest::finished, this, &PrinterModel::getDestsFinished); request->getPrinters(m_attributes); } void PrinterModel::insertDest(int pos, const KCupsPrinter &printer) { // Create the printer item auto stdItem = new QStandardItem(printer.name()); stdItem->setData(printer.name(), DestName); stdItem->setIcon(printer.icon()); // update the item updateDest(stdItem, printer); // insert the printer Item insertRow(pos, stdItem); } void PrinterModel::updateDest(QStandardItem *destItem, const KCupsPrinter &printer) { // store if the printer is the network default bool isDefault = printer.isDefault(); if (isDefault != destItem->data(DestIsDefault).toBool()) { destItem->setData(isDefault, DestIsDefault); } // store the printer state KCupsPrinter::Status state = printer.state(); if (state != destItem->data(DestState)) { destItem->setData(state, DestState); } qCDebug(LIBKCUPS) << state << printer.name(); // store if the printer is accepting jobs bool accepting = printer.isAcceptingJobs(); if (accepting != destItem->data(DestIsAcceptingJobs)) { destItem->setData(accepting, DestIsAcceptingJobs); } // store the printer status message QString status = destStatus(state, printer.stateMsg(), accepting); if (status != destItem->data(DestStatus)) { destItem->setData(status, DestStatus); } bool paused = (state == KCupsPrinter::Stopped || !accepting); if (paused != destItem->data(DestIsPaused)) { destItem->setData(paused, DestIsPaused); } // store if the printer is shared bool shared = printer.isShared(); if (shared != destItem->data(DestIsShared)) { destItem->setData(shared, DestIsShared); } // store if the printer is a class // the printer-type param is a flag bool isClass = printer.isClass(); if (isClass != destItem->data(DestIsClass)) { destItem->setData(isClass, DestIsClass); } // store if the printer type // the printer-type param is a flag uint printerType = printer.type(); if (printerType != destItem->data(DestType)) { destItem->setData(printerType, DestType); destItem->setData(printerType & CUPS_PRINTER_REMOTE, DestRemote); } // store the printer location QString location = printer.location(); if (location != destItem->data(DestLocation).toString()) { destItem->setData(location, DestLocation); } // store the printer icon name QString iconName = printer.iconName(); if (iconName != destItem->data(DestIconName).toString()) { destItem->setData(iconName, DestIconName); } if (destItem->data(DestName).toString() != destItem->text()){ if (destItem->text() != destItem->data(DestName).toString()){ destItem->setText(destItem->data(DestName).toString()); } } // store the printer description QString description = printer.info(); if (description != destItem->data(DestDescription).toString()){ destItem->setData(description, DestDescription); } // store the printer kind QString kind = printer.makeAndModel(); if (kind != destItem->data(DestKind)) { destItem->setData(kind, DestKind); } // store the printer commands QStringList commands = printer.commands(); if (commands != destItem->data(DestCommands)) { destItem->setData(commands, DestCommands); } int markerChangeTime = printer.markerChangeTime(); if (markerChangeTime != destItem->data(DestMarkerChangeTime)) { destItem->setData(printer.markerChangeTime(), DestMarkerChangeTime); - QVariantHash markers; - markers[KCUPS_MARKER_CHANGE_TIME] = printer.markerChangeTime(); - markers[KCUPS_MARKER_COLORS] = printer.argument(KCUPS_MARKER_COLORS); - markers[KCUPS_MARKER_LEVELS] = printer.argument(KCUPS_MARKER_LEVELS); - markers[KCUPS_MARKER_NAMES] = printer.argument(KCUPS_MARKER_NAMES); - markers[KCUPS_MARKER_TYPES] = printer.argument(KCUPS_MARKER_TYPES); + const QVariantHash markers{ + {KCUPS_MARKER_CHANGE_TIME, printer.markerChangeTime()}, + {KCUPS_MARKER_COLORS, printer.argument(KCUPS_MARKER_COLORS)}, + {KCUPS_MARKER_LEVELS, printer.argument(KCUPS_MARKER_LEVELS)}, + {KCUPS_MARKER_NAMES, printer.argument(KCUPS_MARKER_NAMES)}, + {KCUPS_MARKER_TYPES, printer.argument(KCUPS_MARKER_TYPES)} + }; destItem->setData(markers, DestMarkers); } } int PrinterModel::destRow(const QString &destName) { // find the position of the jobId inside the model for (int i = 0; i < rowCount(); i++) { if (destName == item(i)->data(DestName).toString()) { return i; } } // -1 if not found return -1; } QString PrinterModel::destStatus(KCupsPrinter::Status state, const QString &message, bool isAcceptingJobs) const { switch (state) { case KCupsPrinter::Idle: if (message.isEmpty()){ return isAcceptingJobs ? i18n("Idle") : i18n("Idle, rejecting jobs"); } else { return isAcceptingJobs ? i18n("Idle - '%1'", message) : i18n("Idle, rejecting jobs - '%1'", message); } case KCupsPrinter::Printing: if (message.isEmpty()){ return i18n("In use"); } else { return i18n("In use - '%1'", message); } case KCupsPrinter::Stopped: if (message.isEmpty()){ return isAcceptingJobs ? i18n("Paused") : i18n("Paused, rejecting jobs"); } else { return isAcceptingJobs ? i18n("Paused - '%1'", message) : i18n("Paused, rejecting jobs - '%1'", message); } default : if (message.isEmpty()){ return i18n("Unknown"); } else { return i18n("Unknown - '%1'", message); } } } void PrinterModel::clear() { removeRows(0, rowCount()); } Qt::ItemFlags PrinterModel::flags(const QModelIndex &index) const { Q_UNUSED(index) return Qt::ItemIsSelectable | Qt::ItemIsEnabled; } void PrinterModel::insertUpdatePrinterName(const QString &printerName) { auto request = new KCupsRequest; connect(request, &KCupsRequest::finished, this, &PrinterModel::insertUpdatePrinterFinished); // TODO how do we know if it's a class if this DBus signal // does not tell us request->getPrinterAttributes(printerName, false, m_attributes); } void PrinterModel::insertUpdatePrinter(const QString &text, const QString &printerUri, const QString &printerName, uint printerState, const QString &printerStateReasons, bool printerIsAcceptingJobs) { Q_UNUSED(text) Q_UNUSED(printerUri) Q_UNUSED(printerState) Q_UNUSED(printerStateReasons) Q_UNUSED(printerIsAcceptingJobs) qCDebug(LIBKCUPS) << text << printerUri << printerName << printerState << printerStateReasons << printerIsAcceptingJobs; insertUpdatePrinterName(printerName); } void PrinterModel::insertUpdatePrinterFinished(KCupsRequest *request) { if (!request->hasError()) { const KCupsPrinters printers = request->printers(); for (const KCupsPrinter &printer : printers) { // If there is a printer and it's not the current one add it // as a new destination int dest_row = destRow(printer.name()); if (dest_row == -1) { // not found, insert new one insertDest(0, printer); } else { // update the printer updateDest(item(dest_row), printer); } } } request->deleteLater(); } void PrinterModel::printerRemovedName(const QString &printerName) { qCDebug(LIBKCUPS) << printerName; // Look for the removed printer int dest_row = destRow(printerName); if (dest_row != -1) { removeRows(dest_row, 1); } } void PrinterModel::printerRemoved(const QString &text, const QString &printerUri, const QString &printerName, uint printerState, const QString &printerStateReasons, bool printerIsAcceptingJobs) { // REALLY? all these parameters just to say foo was deleted?? Q_UNUSED(text) Q_UNUSED(printerUri) Q_UNUSED(printerState) Q_UNUSED(printerStateReasons) Q_UNUSED(printerIsAcceptingJobs) qCDebug(LIBKCUPS) << text << printerUri << printerName << printerState << printerStateReasons << printerIsAcceptingJobs; // Look for the removed printer int dest_row = destRow(printerName); if (dest_row != -1) { removeRows(dest_row, 1); } } void PrinterModel::printerStateChanged(const QString &text, const QString &printerUri, const QString &printerName, uint printerState, const QString &printerStateReasons, bool printerIsAcceptingJobs) { qCDebug(LIBKCUPS) << text << printerUri << printerName << printerState << printerStateReasons << printerIsAcceptingJobs; } void PrinterModel::printerStopped(const QString &text, const QString &printerUri, const QString &printerName, uint printerState, const QString &printerStateReasons, bool printerIsAcceptingJobs) { qCDebug(LIBKCUPS) << text << printerUri << printerName << printerState << printerStateReasons << printerIsAcceptingJobs; } void PrinterModel::printerRestarted(const QString &text, const QString &printerUri, const QString &printerName, uint printerState, const QString &printerStateReasons, bool printerIsAcceptingJobs) { qCDebug(LIBKCUPS) << text << printerUri << printerName << printerState << printerStateReasons << printerIsAcceptingJobs; } void PrinterModel::printerShutdown(const QString &text, const QString &printerUri, const QString &printerName, uint printerState, const QString &printerStateReasons, bool printerIsAcceptingJobs) { qCDebug(LIBKCUPS) << text << printerUri << printerName << printerState << printerStateReasons << printerIsAcceptingJobs; } void PrinterModel::printerModified(const QString &text, const QString &printerUri, const QString &printerName, uint printerState, const QString &printerStateReasons, bool printerIsAcceptingJobs) { qCDebug(LIBKCUPS) << text << printerUri << printerName << printerState << printerStateReasons << printerIsAcceptingJobs; } void PrinterModel::serverChanged(const QString &text) { qCDebug(LIBKCUPS) << text; update(); } diff --git a/libkcups/SelectMakeModel.cpp b/libkcups/SelectMakeModel.cpp index ef42c37..01e4b31 100644 --- a/libkcups/SelectMakeModel.cpp +++ b/libkcups/SelectMakeModel.cpp @@ -1,316 +1,312 @@ /*************************************************************************** * 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 "SelectMakeModel.h" #include "ui_SelectMakeModel.h" #include "PPDModel.h" #include "Debug.h" #include "KCupsRequest.h" #include "NoSelectionRectDelegate.h" #include #include #include -#include #include #include #include #include // Marshall the MyStructure data into a D-Bus argument QDBusArgument &operator<<(QDBusArgument &argument, const DriverMatch &driverMatch) { argument.beginStructure(); argument << driverMatch.ppd << driverMatch.match; argument.endStructure(); return argument; } // Retrieve the MyStructure data from the D-Bus argument const QDBusArgument &operator>>(const QDBusArgument &argument, DriverMatch &driverMatch) { argument.beginStructure(); argument >> driverMatch.ppd >> driverMatch.match; argument.endStructure(); return argument; } SelectMakeModel::SelectMakeModel(QWidget *parent) : QWidget(parent), - ui(new Ui::SelectMakeModel), - m_ppdRequest(0), - m_gotBestDrivers(false), - m_hasRecommended(false) + ui(new Ui::SelectMakeModel) { ui->setupUi(this); // Configure the erro message widget ui->messageWidget->setMessageType(KMessageWidget::Error); ui->messageWidget->hide(); m_sourceModel = new PPDModel(this); ui->makeView->setModel(m_sourceModel); ui->makeView->setItemDelegate(new NoSelectionRectDelegate(this)); // Updates the PPD view to the selected Make connect(ui->makeView->selectionModel(), &QItemSelectionModel::currentChanged, ui->ppdsLV, &QListView::setRootIndex); ui->ppdsLV->setModel(m_sourceModel); ui->ppdsLV->setItemDelegate(new NoSelectionRectDelegate(this)); connect(m_sourceModel, &PPDModel::dataChanged, this, &SelectMakeModel::checkChanged); // Clear the PPD view selection, so the Next/Finish button gets disabled connect(ui->makeView->selectionModel(), &QItemSelectionModel::currentChanged, ui->ppdsLV->selectionModel(), &QItemSelectionModel::clearSelection); // Make sure we update the Next/Finish button if a PPD is selected connect(ui->ppdsLV->selectionModel(), &QItemSelectionModel::selectionChanged, this, &SelectMakeModel::checkChanged); // When the radio button changes the signal must be emitted connect(ui->ppdFileRB, &QRadioButton::toggled, this, &SelectMakeModel::checkChanged); connect(ui->ppdFilePathUrl, &KUrlRequester::textChanged, this, &SelectMakeModel::checkChanged); qDBusRegisterMetaType(); qDBusRegisterMetaType(); } SelectMakeModel::~SelectMakeModel() { delete ui; } void SelectMakeModel::setDeviceInfo(const QString &deviceId, const QString &make, const QString &makeAndModel, const QString &deviceUri) { qCDebug(LIBKCUPS) << "===================================" << deviceId << makeAndModel << deviceUri; m_gotBestDrivers = false; m_hasRecommended = false; m_make = make; m_makeAndModel = makeAndModel; // Get the best drivers QDBusMessage message; message = QDBusMessage::createMethodCall(QLatin1String("org.fedoraproject.Config.Printing"), QLatin1String("/org/fedoraproject/Config/Printing"), QLatin1String("org.fedoraproject.Config.Printing"), QLatin1String("GetBestDrivers")); message << deviceId; message << makeAndModel; message << deviceUri; QDBusConnection::sessionBus().callWithCallback(message, this, SLOT(getBestDriversFinished(QDBusMessage)), SLOT(getBestDriversFailed(QDBusError,QDBusMessage))); if (!m_ppdRequest) { m_ppdRequest = new KCupsRequest; connect(m_ppdRequest, &KCupsRequest::finished, this, &SelectMakeModel::ppdsLoaded); m_ppdRequest->getPPDS(); } } void SelectMakeModel::setMakeModel(const QString &make, const QString &makeAndModel) { if (!m_ppdRequest) { // We won't try to get the best driver // we should be we need more info and testing // TODO m_gotBestDrivers = true; m_hasRecommended = false; m_make = make; m_makeAndModel = makeAndModel; m_ppdRequest = new KCupsRequest; connect(m_ppdRequest, &KCupsRequest::finished, this, &SelectMakeModel::ppdsLoaded); m_ppdRequest->getPPDS(); } else { // TODO test this setModelData(); } } void SelectMakeModel::ppdsLoaded(KCupsRequest *request) { if (request->hasError()) { qCWarning(LIBKCUPS) << "Failed to get PPDs" << request->errorMsg(); ui->messageWidget->setText(i18n("Failed to get a list of drivers: '%1'", request->errorMsg())); ui->messageWidget->animatedShow(); // Force the changed signal to be sent checkChanged(); } else { m_ppds = request->ppds(); // Try to show the PPDs setModelData(); } m_ppdRequest = nullptr; request->deleteLater(); } void SelectMakeModel::checkChanged() { qCDebug(LIBKCUPS); if (isFileSelected()) { emit changed(!selectedPPDFileName().isNull()); } else { // enable or disable the job action buttons if something is selected emit changed(!selectedPPDName().isNull()); selectFirstMake(); } } QString SelectMakeModel::selectedPPDName() const { QItemSelection ppdSelection = ui->ppdsLV->selectionModel()->selection(); if (!isFileSelected() && !ppdSelection.indexes().isEmpty()) { QModelIndex index = ppdSelection.indexes().first(); return index.data(PPDModel::PPDName).toString(); } return QString(); } QString SelectMakeModel::selectedPPDMakeAndModel() const { QItemSelection ppdSelection = ui->ppdsLV->selectionModel()->selection(); if (!isFileSelected() && !ppdSelection.indexes().isEmpty()) { QModelIndex index = ppdSelection.indexes().first(); return index.data(PPDModel::PPDMakeAndModel).toString(); } return QString(); } QString SelectMakeModel::selectedPPDFileName() const { if (isFileSelected()) { QFileInfo file = ui->ppdFilePathUrl->url().toLocalFile(); qCDebug(LIBKCUPS) << ui->ppdFilePathUrl->url().toLocalFile() << file.isFile() << file.filePath(); if (file.isFile()) { return file.filePath(); } } return QString(); } bool SelectMakeModel::isFileSelected() const { qCDebug(LIBKCUPS) << ui->ppdFileRB->isChecked(); return ui->ppdFileRB->isChecked(); } void SelectMakeModel::getBestDriversFinished(const QDBusMessage &message) { if (message.type() == QDBusMessage::ReplyMessage && message.arguments().size() == 1) { QDBusArgument argument = message.arguments().first().value(); const DriverMatchList driverMatchList = qdbus_cast(argument); m_driverMatchList = driverMatchList; m_hasRecommended = !m_driverMatchList.isEmpty(); for (const DriverMatch &driverMatch : driverMatchList) { qCDebug(LIBKCUPS) << driverMatch.ppd << driverMatch.match; } } else { qCWarning(LIBKCUPS) << "Unexpected message" << message; } m_gotBestDrivers = true; setModelData(); } void SelectMakeModel::getBestDriversFailed(const QDBusError &error, const QDBusMessage &message) { qCWarning(LIBKCUPS) << "Failed to get best drivers" << error << message; // Show the PPDs anyway m_gotBestDrivers = true; ui->messageWidget->setText(i18n("Failed to search for a recommended driver: '%1'", error.message())); ui->messageWidget->animatedShow(); setModelData(); } void SelectMakeModel::setModelData() { if (!m_ppds.isEmpty() && m_gotBestDrivers) { m_sourceModel->setPPDs(m_ppds, m_driverMatchList); // Pre-select the first Recommended PPD if (m_hasRecommended) { selectRecommendedPPD(); } else if (!m_ppds.isEmpty() && !m_make.isEmpty()) { selectMakeModelPPD(); } // Force changed signal to be emitted checkChanged(); } } void SelectMakeModel::selectFirstMake() { QItemSelection selection; selection = ui->makeView->selectionModel()->selection(); // Make sure the first make is selected if (selection.indexes().isEmpty() && m_sourceModel->rowCount() > 0) { ui->makeView->selectionModel()->setCurrentIndex(m_sourceModel->index(0, 0), QItemSelectionModel::SelectCurrent); } } void SelectMakeModel::selectMakeModelPPD() { const QList makes = m_sourceModel->findItems(m_make); for (QStandardItem *make : makes) { // Check if the item is in this make for (int i = 0; i < make->rowCount(); i++) { if (make->child(i)->data(PPDModel::PPDMakeAndModel).toString() == m_makeAndModel) { ui->makeView->selectionModel()->setCurrentIndex(make->index(), QItemSelectionModel::SelectCurrent); ui->ppdsLV->selectionModel()->setCurrentIndex(make->child(i)->index(), QItemSelectionModel::SelectCurrent); return; } } } // the exact PPD wasn't found try to select just the make if (!makes.isEmpty()) { ui->makeView->selectionModel()->setCurrentIndex(makes.first()->index(), QItemSelectionModel::SelectCurrent); } } void SelectMakeModel::selectRecommendedPPD() { // Force the first make to be selected selectFirstMake(); QItemSelection ppdSelection = ui->ppdsLV->selectionModel()->selection(); if (ppdSelection.indexes().isEmpty()) { QItemSelection makeSelection = ui->makeView->selectionModel()->selection(); QModelIndex parent = makeSelection.indexes().first(); if (parent.isValid()) { ui->ppdsLV->selectionModel()->setCurrentIndex(m_sourceModel->index(0, 0, parent), QItemSelectionModel::SelectCurrent); } } } diff --git a/libkcups/SelectMakeModel.h b/libkcups/SelectMakeModel.h index 458a369..9becf25 100644 --- a/libkcups/SelectMakeModel.h +++ b/libkcups/SelectMakeModel.h @@ -1,77 +1,77 @@ /*************************************************************************** * 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 SELECT_MAKE_MODEL_H #define SELECT_MAKE_MODEL_H #include #include #include "KCupsConnection.h" #include "PPDModel.h" namespace Ui { class SelectMakeModel; } class KCupsRequest; class Q_DECL_EXPORT SelectMakeModel : public QWidget { Q_OBJECT public: explicit SelectMakeModel(QWidget *parent = 0); ~SelectMakeModel(); void setDeviceInfo(const QString &deviceId, const QString &make, const QString &makeAndModel, const QString &deviceUri); void setMakeModel(const QString &make, const QString &makeAndModel); QString selectedPPDName() const; QString selectedPPDMakeAndModel() const; QString selectedPPDFileName() const; bool isFileSelected() const; public slots: void checkChanged(); void ppdsLoaded(KCupsRequest *request); signals: void changed(bool); private slots: void getBestDriversFinished(const QDBusMessage &message); void getBestDriversFailed(const QDBusError &error, const QDBusMessage &message); private: void setModelData(); void selectFirstMake(); void selectMakeModelPPD(); void selectRecommendedPPD(); - Ui::SelectMakeModel *ui; - PPDModel *m_sourceModel; - KCupsRequest *m_ppdRequest; ReturnArguments m_ppds; DriverMatchList m_driverMatchList; - bool m_gotBestDrivers; - bool m_hasRecommended; QString m_make; QString m_makeAndModel; + Ui::SelectMakeModel *ui; + PPDModel *m_sourceModel; + KCupsRequest *m_ppdRequest = nullptr; + bool m_gotBestDrivers = false; + bool m_hasRecommended = false; }; #endif diff --git a/print-manager-kded/PrintManagerKded.cpp b/print-manager-kded/PrintManagerKded.cpp index 8f1908d..2dada14 100644 --- a/print-manager-kded/PrintManagerKded.cpp +++ b/print-manager-kded/PrintManagerKded.cpp @@ -1,52 +1,51 @@ /*************************************************************************** * 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 "PrintManagerKded.h" #include "NewPrinterNotification.h" #include #include K_PLUGIN_FACTORY(PrintDFactory, registerPlugin();) PrintManagerKded::PrintManagerKded(QObject *parent, const QVariantList &args) : - KDEDModule(parent), - m_newPrinterNotification(0) + KDEDModule(parent) { Q_UNUSED(args) QTimer::singleShot(0, this, &PrintManagerKded::loadThread); } PrintManagerKded::~PrintManagerKded() { if (m_newPrinterNotification) { m_newPrinterNotification->deleteLater(); } } void PrintManagerKded::loadThread() { m_newPrinterNotification = new NewPrinterNotification; } #include "PrintManagerKded.moc" diff --git a/print-manager-kded/PrintManagerKded.h b/print-manager-kded/PrintManagerKded.h index fa238cc..2255a87 100644 --- a/print-manager-kded/PrintManagerKded.h +++ b/print-manager-kded/PrintManagerKded.h @@ -1,43 +1,43 @@ /*************************************************************************** * Copyright (C) 2010-2012 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 PRINTMANAGERKDED_H #define PRINTMANAGERKDED_H #include #include class NewPrinterNotification; class PrintManagerKded : public KDEDModule { Q_OBJECT public: PrintManagerKded(QObject *parent, const QVariantList &args); ~PrintManagerKded(); private slots: void loadThread(); private: - NewPrinterNotification *m_newPrinterNotification; + NewPrinterNotification *m_newPrinterNotification = nullptr; }; #endif // PRINTMANAGERKDED_H diff --git a/printer-manager-kcm/PrintKCM.cpp b/printer-manager-kcm/PrintKCM.cpp index 3218376..1e58070 100644 --- a/printer-manager-kcm/PrintKCM.cpp +++ b/printer-manager-kcm/PrintKCM.cpp @@ -1,386 +1,383 @@ /*************************************************************************** * 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 "PrintKCM.h" #include "ui_PrintKCM.h" #include #include #include #include "PrinterDelegate.h" #include "PrinterDescription.h" #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY(PrintKCMFactory, registerPlugin();) PrintKCM::PrintKCM(QWidget *parent, const QVariantList &args) : KCModule(parent, args), - ui(new Ui::PrintKCM), - m_lastError(-1), // Force the error to run on the first time - m_serverRequest(0) + ui(new Ui::PrintKCM) { - KAboutData *aboutData; - aboutData = new KAboutData(QLatin1String("kcm_print"), - i18n("Print settings"), - QLatin1String(PM_VERSION), - i18n("Print settings"), - KAboutLicense::GPL, - i18n("(C) 2010-2018 Daniel Nicoletti")); + auto aboutData = new KAboutData(QLatin1String("kcm_print"), + i18n("Print settings"), + QLatin1String(PM_VERSION), + i18n("Print settings"), + KAboutLicense::GPL, + i18n("(C) 2010-2018 Daniel Nicoletti")); aboutData->addAuthor(QStringLiteral("Daniel Nicoletti"), QString(), QLatin1String("dantti12@gmail.com")); aboutData->addAuthor(QStringLiteral("Jan Grulich"), i18n("Port to Qt 5 / Plasma 5"), QStringLiteral("jgrulich@redhat.com")); setAboutData(aboutData); setButtons(NoAdditionalButton); ui->setupUi(this); connect(ui->printerDesc, &PrinterDescription::updateNeeded, this, &PrintKCM::update); // The printer list needs to increase in width according to the icon sizes // default dialog icon size is 32, this times 6 is 192 which is roughly the original width ui->printersTV->setMinimumWidth(IconSize(KIconLoader::Dialog) * 6); auto addMenu = new QMenu(this); addMenu->addAction(i18nc("@action:intoolbar","Add a Printer Class"), this, &PrintKCM::addClass); ui->addTB->setIcon(QIcon::fromTheme(QLatin1String("list-add"))); ui->addTB->setToolTip(i18n("Add a new printer or a printer class")); ui->addTB->setMenu(addMenu); ui->removeTB->setIcon(QIcon::fromTheme(QLatin1String("list-remove"))); ui->removeTB->setToolTip(i18n("Remove Printer")); auto systemMenu = new QMenu(this); connect(systemMenu, &QMenu::aboutToShow, this, &PrintKCM::getServerSettings); connect(systemMenu, &QMenu::triggered, this, &PrintKCM::systemPreferencesTriggered); #if CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR < 6 m_showSharedPrinters = systemMenu->addAction(i18nc("@action:intoolbar","Show printers shared by other systems")); m_showSharedPrinters->setCheckable(true); systemMenu->addSeparator(); #endif // CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR < 6 m_shareConnectedPrinters = systemMenu->addAction(i18nc("@action:intoolbar","Share printers connected to this system")); m_shareConnectedPrinters->setCheckable(true); m_allowPrintringFromInternet = systemMenu->addAction(i18nc("@action:intoolbar","Allow printing from the Internet")); m_allowPrintringFromInternet->setCheckable(true); m_allowPrintringFromInternet->setEnabled(false); connect(m_shareConnectedPrinters, &QAction::toggled, m_allowPrintringFromInternet, &QAction::setEnabled); connect(m_shareConnectedPrinters, &QAction::toggled, ui->printerDesc, &PrinterDescription::enableShareCheckBox); systemMenu->addSeparator(); m_allowRemoteAdmin = systemMenu->addAction(i18nc("@action:intoolbar","Allow remote administration")); m_allowRemoteAdmin->setCheckable(true); m_allowUsersCancelAnyJob = systemMenu->addAction(i18nc("@action:intoolbar","Allow users to cancel any job (not just their own)")); m_allowUsersCancelAnyJob->setCheckable(true); ui->systemPreferencesTB->setIcon(QIcon::fromTheme(QLatin1String("configure"))); ui->systemPreferencesTB->setToolTip(i18n("Configure the global preferences")); ui->systemPreferencesTB->setMenu(systemMenu); m_model = new PrinterModel(this); auto sortModel = new PrinterSortFilterModel(this); sortModel->setSourceModel(m_model); ui->printersTV->setModel(sortModel); ui->printersTV->setItemDelegate(new NoSelectionRectDelegate(this)); ui->printersTV->setItemDelegate(new PrinterDelegate(this)); connect(ui->printersTV->selectionModel(), &QItemSelectionModel::selectionChanged, this, &PrintKCM::update); connect(sortModel, &PrinterSortFilterModel::rowsInserted, this, &PrintKCM::update); connect(sortModel, &PrinterSortFilterModel::rowsRemoved, this, &PrintKCM::update); connect(m_model, &PrinterModel::dataChanged, this, &PrintKCM::update); connect(m_model, &PrinterModel::error, this, &PrintKCM::error); ui->addPrinterBtn->setIcon(QIcon::fromTheme(QLatin1String("list-add"))); connect(ui->addPrinterBtn, &QPushButton::clicked, this, &PrintKCM::on_addTB_clicked); // Force the model update AFTER we setup the error signal m_model->update(); // Make sure we update our server settings if the user change it on // another interface connect(KCupsConnection::global(), &KCupsConnection::serverAudit, this, &PrintKCM::getServerSettings); connect(KCupsConnection::global(), &KCupsConnection::serverStarted, this, &PrintKCM::getServerSettings); connect(KCupsConnection::global(), &KCupsConnection::serverStopped, this, &PrintKCM::getServerSettings); connect(KCupsConnection::global(), &KCupsConnection::serverRestarted, this, &PrintKCM::getServerSettings); // We need to know the server settings so we disable the // share printer checkbox if sharing is disabled on the server getServerSettings(); } PrintKCM::~PrintKCM() { delete ui; } void PrintKCM::error(int lastError, const QString &errorTitle, const QString &errorMsg) { if (lastError) { // The user has no printer // allow him to add a new one if (lastError == IPP_NOT_FOUND) { showInfo(QIcon::fromTheme(QLatin1String("dialog-information")), i18n("No printers have been configured or discovered"), QString(), true, true); } else { showInfo(QIcon::fromTheme(QLatin1String("printer")), QStringLiteral("%1").arg(errorTitle), errorMsg, false, false); } } if (m_lastError != lastError) { // if no printer was found the server // is still working if (lastError == IPP_NOT_FOUND) { ui->addTB->setEnabled(true); ui->systemPreferencesTB->setEnabled(true); } else { ui->addTB->setEnabled(!lastError); ui->systemPreferencesTB->setEnabled(!lastError); } m_lastError = lastError; // Force an update update(); } } void PrintKCM::showInfo(const QIcon &icon, const QString &title, const QString &comment, bool showAddPrinter, bool showToolButtons) { ui->hugeIcon->setPixmap(icon.pixmap(128, 128)); ui->errorText->setText(title); ui->errorComment->setVisible(!comment.isEmpty()); ui->errorComment->setText(comment); ui->addPrinterBtn->setVisible(showAddPrinter); // Well, when there is no printer, there is nothing to add to a printer class // so we can actually hide the Add button nontheless? ui->addTB->setVisible(!showAddPrinter && showToolButtons); ui->removeTB->setVisible(!showAddPrinter && showToolButtons); ui->lineTB->setVisible(!showAddPrinter && showToolButtons); ui->printersTV->setVisible(!showAddPrinter && showToolButtons); // Make sure we are visible ui->stackedWidget->setCurrentIndex(1); } void PrintKCM::update() { if (m_model->rowCount()) { m_lastError = -1; // if the model has printers reset the error code if (ui->stackedWidget->currentIndex() != 0) { ui->stackedWidget->setCurrentIndex(0); } QItemSelection selection; // we need to map the selection to source to get the real indexes selection = ui->printersTV->selectionModel()->selection(); // select the first printer if there are printers if (selection.indexes().isEmpty()) { ui->printersTV->selectionModel()->select(m_model->index(0, 0), QItemSelectionModel::Select); return; } QModelIndex index = selection.indexes().first(); QString destName = index.data(PrinterModel::DestName).toString(); if (ui->printerDesc->destName() != destName) { ui->printerDesc->setPrinterIcon(index.data(Qt::DecorationRole).value()); int type = index.data(PrinterModel::DestType).toUInt(); // If we remove discovered printers, they will come // back to hunt us a bit later ui->removeTB->setEnabled(!(type & CUPS_PRINTER_DISCOVERED)); } ui->printerDesc->setDestName(index.data(PrinterModel::DestName).toString(), index.data(PrinterModel::DestDescription).toString(), index.data(PrinterModel::DestIsClass).toBool(), m_model->rowCount() == 1); ui->printerDesc->setDestStatus(index.data(PrinterModel::DestStatus).toString()); ui->printerDesc->setLocation(index.data(PrinterModel::DestLocation).toString()); ui->printerDesc->setKind(index.data(PrinterModel::DestKind).toString()); ui->printerDesc->setIsShared(index.data(PrinterModel::DestIsShared).toBool()); ui->printerDesc->setAcceptingJobs(index.data(PrinterModel::DestIsAcceptingJobs).toBool()); ui->printerDesc->setIsDefault(index.data(PrinterModel::DestIsDefault).toBool()); ui->printerDesc->setCommands(index.data(PrinterModel::DestCommands).toStringList()); ui->printerDesc->setMarkers(index.data(PrinterModel::DestMarkers).value()); ui->addTB->show(); ui->removeTB->show(); ui->lineTB->show(); // Show the printer list only if there are more than 1 printer ui->printersTV->setVisible(m_model->rowCount() > 1); } else { // disable the printer action buttons if there is nothing to selected ui->removeTB->setEnabled(false); if (m_lastError == IPP_OK) { // the model is empty and no problem happened showInfo(QIcon::fromTheme(QLatin1String("dialog-information")), i18n("No printers have been configured or discovered"), QString(), true, true); } } } void PrintKCM::on_addTB_clicked() { KToolInvocation::kdeinitExec(QLatin1String("kde-add-printer"), { QLatin1String("--add-printer") }); } void PrintKCM::addClass() { KToolInvocation::kdeinitExec(QLatin1String("kde-add-printer"), { QLatin1String("--add-class") }); } void PrintKCM::on_removeTB_clicked() { QItemSelection selection; // we need to map the selection to source to get the real indexes selection = ui->printersTV->selectionModel()->selection(); // enable or disable the job action buttons if something is selected if (!selection.indexes().isEmpty()) { QModelIndex index = selection.indexes().first(); int resp; QString msg, title; if (index.data(PrinterModel::DestIsClass).toBool()) { title = i18n("Remove class"); msg = i18n("Are you sure you want to remove the class '%1'?", index.data(Qt::DisplayRole).toString()); } else { title = i18n("Remove printer"); msg = i18n("Are you sure you want to remove the printer '%1'?", index.data(Qt::DisplayRole).toString()); } resp = KMessageBox::warningYesNo(this, msg, title); if (resp == KMessageBox::Yes) { QPointer request = new KCupsRequest; request->deletePrinter(index.data(PrinterModel::DestName).toString()); request->waitTillFinished(); if (request) { request->deleteLater(); } } } } void PrintKCM::getServerSettings() { if (!m_serverRequest) { auto systemMenu = qobject_cast(sender()); m_serverRequest = new KCupsRequest; m_serverRequest->setProperty("interactive", static_cast(systemMenu)); connect(m_serverRequest, &KCupsRequest::finished, this, &PrintKCM::getServerSettingsFinished); m_serverRequest->getServerSettings(); } } void PrintKCM::getServerSettingsFinished(KCupsRequest *request) { // When we don't have any destinations error is set to IPP_NOT_FOUND // we can safely ignore the error since it DOES bring the server settings bool error = request->hasError() && request->error() != IPP_NOT_FOUND; #if CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR < 6 m_showSharedPrinters->setEnabled(!error); #endif // CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR < 6 m_shareConnectedPrinters->setEnabled(!error); m_allowRemoteAdmin->setEnabled(!error); m_allowUsersCancelAnyJob->setEnabled(!error); if (error) { if (request->property("interactive").toBool()) { KMessageBox::detailedSorry(this, i18nc("@info", "Failed to get server settings"), request->errorMsg(), i18nc("@title:window", "Failed")); } } else { KCupsServer server = request->serverSettings(); #if CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR < 6 m_showSharedPrinters->setChecked(server.showSharedPrinters()); #endif // CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR < 6 m_shareConnectedPrinters->setChecked(server.sharePrinters()); m_allowPrintringFromInternet->setChecked(server.allowPrintingFromInternet()); m_allowRemoteAdmin->setChecked(server.allowRemoteAdmin()); m_allowUsersCancelAnyJob->setChecked(server.allowUserCancelAnyJobs()); } request->deleteLater(); m_serverRequest = 0; } void PrintKCM::updateServerFinished(KCupsRequest *request) { if (request->hasError()) { if (request->error() == IPP_SERVICE_UNAVAILABLE || request->error() == IPP_INTERNAL_ERROR || request->error() == IPP_AUTHENTICATION_CANCELED) { // Server is restarting, or auth was canceled, update the settings in one second QTimer::singleShot(1000, this, &PrintKCM::update); } else { KMessageBox::detailedSorry(this, i18nc("@info", "Failed to configure server settings"), request->errorMsg(), request->serverError()); // Force the settings to be retrieved again update(); } } request->deleteLater(); } void PrintKCM::systemPreferencesTriggered() { KCupsServer server; #if CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR < 6 server.setShowSharedPrinters(m_showSharedPrinters->isChecked()); #endif // CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR < 6 server.setSharePrinters(m_shareConnectedPrinters->isChecked()); server.setAllowPrintingFromInternet(m_allowPrintringFromInternet->isChecked()); server.setAllowRemoteAdmin(m_allowRemoteAdmin->isChecked()); server.setAllowUserCancelAnyJobs(m_allowUsersCancelAnyJob->isChecked()); auto request = new KCupsRequest; connect(request, &KCupsRequest::finished, this, &PrintKCM::updateServerFinished); request->setServerSettings(server); } #include "PrintKCM.moc" diff --git a/printer-manager-kcm/PrintKCM.h b/printer-manager-kcm/PrintKCM.h index 1934a77..28bb41c 100644 --- a/printer-manager-kcm/PrintKCM.h +++ b/printer-manager-kcm/PrintKCM.h @@ -1,70 +1,70 @@ /*************************************************************************** * 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 PRINT_KCM_H #define PRINT_KCM_H #include #include #include #include namespace Ui { class PrintKCM; } class KCupsRequest; class PrinterModel; class PrintKCM : public KCModule { Q_OBJECT public: PrintKCM(QWidget *parent, const QVariantList &args); ~PrintKCM(); private slots: void update(); void on_addTB_clicked(); void addClass(); void on_removeTB_clicked(); void error(int lastError, const QString &errorTitle, const QString &errorMsg); void showInfo(const QIcon &icon, const QString &title, const QString &comment, bool showAddPrinter, bool showToolButtons); void getServerSettings(); void getServerSettingsFinished(KCupsRequest *request); void updateServerFinished(KCupsRequest *request); void systemPreferencesTriggered(); private: Ui::PrintKCM *ui; PrinterModel *m_model; - int m_lastError; + int m_lastError = -1; // Force the error to run on the first time - KCupsRequest *m_serverRequest; + KCupsRequest *m_serverRequest = nullptr; QAction *m_showSharedPrinters; QAction *m_shareConnectedPrinters; QAction *m_allowPrintringFromInternet; QAction *m_allowRemoteAdmin; QAction *m_allowUsersCancelAnyJob; }; #endif diff --git a/printer-manager-kcm/PrinterDescription.cpp b/printer-manager-kcm/PrinterDescription.cpp index 00f68d7..7e39f5b 100644 --- a/printer-manager-kcm/PrinterDescription.cpp +++ b/printer-manager-kcm/PrinterDescription.cpp @@ -1,284 +1,279 @@ /*************************************************************************** * 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 "PrinterDescription.h" #include "ui_PrinterDescription.h" #include #include #include #include #include #include #include #include #include #define PRINTER_ICON_SIZE 128 Q_DECLARE_METATYPE(QList) PrinterDescription::PrinterDescription(QWidget *parent) : QWidget(parent), - ui(new Ui::PrinterDescription), - m_isClass(false), - m_globalShared(false), - m_markerChangeTime(0) + ui(new Ui::PrinterDescription) { ui->setupUi(this); m_layoutEnd = ui->formLayout->count(); // loads the standard key icon m_printerIcon = KIconLoader::global()->loadIcon(QLatin1String("printer"), KIconLoader::NoGroup, PRINTER_ICON_SIZE, // a not so huge icon KIconLoader::DefaultState); ui->iconL->setPixmap(m_printerIcon); m_pauseIcon = KIconLoader::global()->loadIcon(QLatin1String("media-playback-pause"), KIconLoader::NoGroup, KIconLoader::SizeMedium, KIconLoader::DefaultState, QStringList(), 0, true); auto menu = new QMenu(ui->maintenancePB); menu->addAction(ui->actionPrintTestPage); menu->addAction(ui->actionPrintSelfTestPage); menu->addAction(ui->actionCleanPrintHeads); ui->actionCleanPrintHeads->setVisible(false); ui->actionPrintSelfTestPage->setVisible(false); ui->maintenancePB->setMenu(menu); ui->errorMessage->setMessageType(KMessageWidget::Error); ui->errorMessage->hide(); } PrinterDescription::~PrinterDescription() { delete ui; } void PrinterDescription::on_openQueuePB_clicked() { - QStringList args; - args << m_destName; - KToolInvocation::kdeinitExec(QLatin1String("kde-print-queue"), args); + KToolInvocation::kdeinitExec(QLatin1String("kde-print-queue"), { m_destName }); } void PrinterDescription::on_defaultCB_clicked() { ui->defaultCB->setDisabled(true); auto request = new KCupsRequest; connect(request, &KCupsRequest::finished, this, &PrinterDescription::requestFinished); request->setDefaultPrinter(m_destName); } void PrinterDescription::on_sharedCB_clicked() { ui->sharedCB->setDisabled(true); auto request = new KCupsRequest; connect(request, &KCupsRequest::finished, this, &PrinterDescription::requestFinished); request->setShared(m_destName, m_isClass, ui->sharedCB->isChecked()); } void PrinterDescription::on_rejectPrintJobsCB_clicked() { ui->rejectPrintJobsCB->setDisabled(true); auto request = new KCupsRequest; connect(request, &KCupsRequest::finished, this, &PrinterDescription::requestFinished); if (ui->rejectPrintJobsCB->isChecked()) { request->rejectJobs(m_destName); } else { request->acceptJobs(m_destName); } } void PrinterDescription::setPrinterIcon(const QIcon &icon) { ui->iconL->setPixmap(icon.pixmap(PRINTER_ICON_SIZE, PRINTER_ICON_SIZE)); } void PrinterDescription::setDestName(const QString &name, const QString &description, bool isClass, bool singlePrinter) { m_destName = name; m_markerData.clear(); if (m_isClass != isClass) { m_isClass = isClass; ui->sharedCB->setText(m_isClass ? i18n("Share this class") : i18n("Share this printer")); } ui->nameMsgL->setText(name); if (!description.isEmpty() && description != ui->printerNameL->text()) { ui->printerNameL->setText(description); } else if (description.isEmpty() && name != ui->printerNameL->text()) { ui->printerNameL->setText(name); } ui->statusL->setVisible(singlePrinter); ui->nameL->setVisible(singlePrinter); ui->nameMsgL->setVisible(singlePrinter); } void PrinterDescription::setDestStatus(const QString &status) { ui->statusL->setText(status); } void PrinterDescription::setLocation(const QString &location) { ui->locationMsgL->setText(location); } void PrinterDescription::setKind(const QString &kind) { ui->kindMsgL->setText(kind); } void PrinterDescription::setIsDefault(bool isDefault) { ui->defaultCB->setEnabled(!isDefault); ui->defaultCB->setChecked(isDefault); } void PrinterDescription::setIsShared(bool isShared) { m_isShared = isShared; if (m_globalShared) { ui->sharedCB->setChecked(isShared); } else { ui->sharedCB->setChecked(false); } ui->sharedCB->setEnabled(m_globalShared); } void PrinterDescription::setAcceptingJobs(bool accepting) { ui->rejectPrintJobsCB->setEnabled(true); ui->rejectPrintJobsCB->setChecked(!accepting); } void PrinterDescription::setCommands(const QStringList &commands) { // On the first time this method runs the list // can be empty, so keep all objects initialized on the // constructor if (m_commands != commands) { m_commands = commands; ui->actionCleanPrintHeads->setVisible(commands.contains(QLatin1String("Clean"))); ui->actionPrintSelfTestPage->setVisible(commands.contains(QLatin1String("PrintSelfTestPage"))); // TODO if the printer supports ReportLevels // we should probably probe for them // commands.contains("ReportLevels") } } void PrinterDescription::setMarkers(const QVariantHash &data) { // Remove old progress bars while (ui->formLayout->count() > m_layoutEnd) { ui->formLayout->takeAt(ui->formLayout->count() - 1)->widget()->deleteLater(); } int size = data[KCUPS_MARKER_NAMES].toStringList().size(); if (size != data[KCUPS_MARKER_LEVELS].value >().size() || size != data[KCUPS_MARKER_COLORS].toStringList().size() || size != data[KCUPS_MARKER_TYPES].toStringList().size()) { return; } // Create a colored progress bar for each marker for (int i = 0; i < size; i++) { if (data[KCUPS_MARKER_TYPES].toStringList().at(i) == QLatin1String("unknown")) { continue; } auto pogressBar = new QProgressBar; pogressBar->setValue(data[KCUPS_MARKER_LEVELS].value >().at(i)); pogressBar->setTextVisible(false); pogressBar->setMaximumHeight(15); QPalette palette = pogressBar->palette(); palette.setColor(QPalette::Active, QPalette::Highlight, QColor(data[KCUPS_MARKER_COLORS].toStringList().at(i))); palette.setColor(QPalette::Inactive, QPalette::Highlight, QColor(data[KCUPS_MARKER_COLORS].toStringList().at(i)).lighter()); pogressBar->setPalette(palette); auto label = new QLabel(data[KCUPS_MARKER_NAMES].toStringList().at(i), this); ui->formLayout->addRow(label, pogressBar); } } void PrinterDescription::on_actionPrintTestPage_triggered(bool checked) { Q_UNUSED(checked) auto request = new KCupsRequest; connect(request, &KCupsRequest::finished, this, &PrinterDescription::requestFinished); request->printTestPage(m_destName, m_isClass); } void PrinterDescription::on_actionCleanPrintHeads_triggered(bool checked) { Q_UNUSED(checked) auto request = new KCupsRequest; connect(request, &KCupsRequest::finished, this, &PrinterDescription::requestFinished); request->printCommand(m_destName, QLatin1String("Clean all"), i18n("Clean Print Heads")); } void PrinterDescription::on_actionPrintSelfTestPage_triggered(bool checked) { Q_UNUSED(checked) auto request = new KCupsRequest; connect(request, &KCupsRequest::finished, this, &PrinterDescription::requestFinished); request->printCommand(m_destName, QLatin1String("PrintSelfTestPage"), i18n("Print Self-Test Page")); } void PrinterDescription::requestFinished(KCupsRequest *request) { if (request && request->hasError()) { ui->errorMessage->setText(i18n("Failed to perform request: %1", request->errorMsg())); ui->errorMessage->animatedShow(); emit updateNeeded(); } } QString PrinterDescription::destName() const { return m_destName; } void PrinterDescription::enableShareCheckBox(bool enable) { m_globalShared = enable; setIsShared(m_isShared); } void PrinterDescription::on_configurePB_clicked() { QProcess::startDetached(QLatin1String("configure-printer"), {m_destName}); } diff --git a/printer-manager-kcm/PrinterDescription.h b/printer-manager-kcm/PrinterDescription.h index 110f9c5..e7dd50d 100644 --- a/printer-manager-kcm/PrinterDescription.h +++ b/printer-manager-kcm/PrinterDescription.h @@ -1,91 +1,91 @@ /*************************************************************************** * 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 PRINTER_DESCRIPTION_H #define PRINTER_DESCRIPTION_H #include #include class QToolButton; class QSortFilterProxyModel; namespace Ui { class PrinterDescription; } class PrintQueueModel; class PrinterDescription : public QWidget { Q_OBJECT public: explicit PrinterDescription(QWidget *parent = 0); ~PrinterDescription(); void setPrinterIcon(const QIcon &icon); void setDestName(const QString &name, const QString &description, bool isClass, bool singlePrinter); void setDestStatus(const QString &status); void setLocation(const QString &location); void setKind(const QString &kind); void setIsDefault(bool isDefault); void setIsShared(bool isShared); void setAcceptingJobs(bool accepting); void setCommands(const QStringList &commands); void setMarkers(const QVariantHash &data); QString destName() const; public slots: void enableShareCheckBox(bool enable); signals: void updateNeeded(); private slots: void on_configurePB_clicked(); void on_openQueuePB_clicked(); void on_defaultCB_clicked(); void on_sharedCB_clicked(); void on_rejectPrintJobsCB_clicked(); void on_actionPrintTestPage_triggered(bool checked); void on_actionCleanPrintHeads_triggered(bool checked); void on_actionPrintSelfTestPage_triggered(bool checked); void requestFinished(KCupsRequest *request); private: Ui::PrinterDescription *ui; QString m_destName; - bool m_isClass; + bool m_isClass = false; bool m_isShared; - bool m_globalShared; + bool m_globalShared = false; QStringList m_commands; QPixmap m_printerIcon; QPixmap m_pauseIcon; QPixmap m_startIcon; QPixmap m_warningIcon; - int m_markerChangeTime; + int m_markerChangeTime = 0; QVariantHash m_markerData; int m_layoutEnd; }; #endif diff --git a/printqueue/PrintQueue.cpp b/printqueue/PrintQueue.cpp index e8cd948..1ea8cc7 100644 --- a/printqueue/PrintQueue.cpp +++ b/printqueue/PrintQueue.cpp @@ -1,122 +1,119 @@ /*************************************************************************** * 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 "PrintQueue.h" #include "PrintQueueUi.h" #include #include #include #include #include PrintQueue::PrintQueue(int &argc, char **argv) : QApplication(argc, argv) { } PrintQueue::~PrintQueue() { } void PrintQueue::showQueues(const QStringList &queues, const QString &cwd) { Q_UNUSED(cwd) if (!queues.isEmpty()) { for (const QString &queue : queues) { showQueue(queue); } } else { qDebug() << "called with no args"; // If DBus called the ui list won't be empty QTimer::singleShot(500, this, &PrintQueue::removeQueue); } } void PrintQueue::showQueue(const QString &destName) { qDebug() << Q_FUNC_INFO << destName; if (!m_uis.contains(destName)) { // Reserve this since the CUPS call might take a long time m_uis[destName] = 0; - QStringList attr; - attr << KCUPS_PRINTER_NAME; - attr << KCUPS_PRINTER_TYPE; // Get destinations with these attributes QPointer request = new KCupsRequest; - request->getPrinters(attr); + request->getPrinters({ KCUPS_PRINTER_NAME, KCUPS_PRINTER_TYPE }); request->waitTillFinished(); if (!request) { return; } bool found = false; KCupsPrinter printer; - KCupsPrinters printers = request->printers(); - for (int i = 0; i < printers.size(); i++) { - if (printers.at(i).name() == destName) { - printer = printers.at(i); + const KCupsPrinters printers = request->printers(); + for (const KCupsPrinter &printerItem : printers) { + if (printerItem.name() == destName) { + printer = printerItem; found = true; break; } } request->deleteLater(); if (found) { auto ui = new PrintQueueUi(printer); connect(ui, &PrintQueueUi::finished, this, &PrintQueue::removeQueue); ui->show(); m_uis[printer.name()] = ui; } else { // Remove the reservation m_uis.remove(destName); // if no destination was found and we aren't showing // a queue quit the app if (m_uis.isEmpty()) { emit quit(); } return; } } // Check it it's not reserved if (m_uis.value(destName)) { KWindowSystem::forceActiveWindow(m_uis.value(destName)->winId()); } } void PrintQueue::removeQueue() { auto ui = qobject_cast(sender()); if (ui) { m_uis.remove(m_uis.key(ui)); } // if no destination was found and we aren't showing // a queue quit the app if (m_uis.isEmpty()) { quit(); } } diff --git a/printqueue/PrintQueueUi.cpp b/printqueue/PrintQueueUi.cpp index dd266d0..6ca0c05 100644 --- a/printqueue/PrintQueueUi.cpp +++ b/printqueue/PrintQueueUi.cpp @@ -1,614 +1,606 @@ /*************************************************************************** * 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 "PrintQueueUi.h" #include "ui_PrintQueueUi.h" #include #include #include #include #include #include #include #include #include -#include #include #include #include #include #include #include #include #include #define PRINTER_ICON_SIZE 92 PrintQueueUi::PrintQueueUi(const KCupsPrinter &printer, QWidget *parent) : QDialog(parent), ui(new Ui::PrintQueueUi), - m_destName(printer.name()), - m_preparingMenu(false), - m_printerPaused(false), - m_lastState(0) + m_destName(printer.name()) { ui->setupUi(this); // since setupUi needs to setup on the mainWidget() // we need to manually connect the buttons connect(ui->cancelJobPB, &QPushButton::clicked, this, &PrintQueueUi::cancelJob); connect(ui->holdJobPB, &QPushButton::clicked, this, &PrintQueueUi::holdJob); connect(ui->resumeJobPB, &QPushButton::clicked, this, &PrintQueueUi::resumeJob); connect(ui->reprintPB, &QPushButton::clicked, this, &PrintQueueUi::reprintJob); connect(ui->pausePrinterPB, &QPushButton::clicked, this, &PrintQueueUi::pausePrinter); connect(ui->configurePrinterPB, &QPushButton::clicked, this, &PrintQueueUi::configurePrinter); connect(ui->whichJobsCB, static_cast(&QComboBox::currentIndexChanged), this, &PrintQueueUi::whichJobsIndexChanged); // Needed so we have our dialog size saved setAttribute(Qt::WA_DeleteOnClose); setWindowIcon(printer.icon()); if (printer.info().isEmpty()) { m_title = printer.name(); } else { m_title = printer.name() % QLatin1String(" - ") % printer.info(); } setWindowTitle(m_title); setSizeGripEnabled(true); (void) minimumSizeHint(); //Force the dialog to be laid out now layout()->setContentsMargins(0,0,0,0); m_isClass = printer.isClass(); // setup default options ui->jobsView->setCornerWidget(new QWidget); setupButtons(); // loads the standard key icon m_printerIcon = printer.icon().pixmap(PRINTER_ICON_SIZE, PRINTER_ICON_SIZE); ui->iconL->setPixmap(m_printerIcon); m_pauseIcon = KIconLoader::global()->loadIcon(QLatin1String("media-playback-pause"), KIconLoader::NoGroup, KIconLoader::SizeMedium, KIconLoader::DefaultState, QStringList(), 0, true); ui->printerStatusMsgL->setText(QString()); // setup the jobs model m_model = new JobModel(this); m_model->setParentWId(winId()); m_model->init(printer.name()); connect(m_model, &JobModel::dataChanged, this, &PrintQueueUi::updateButtons); connect(m_model, &JobModel::dataChanged, this, &PrintQueueUi::update); m_proxyModel = new JobSortFilterModel(this); m_proxyModel->setSourceModel(m_model); m_proxyModel->setDynamicSortFilter(true); ui->jobsView->setModel(m_proxyModel); ui->jobsView->setItemDelegate(new NoSelectionRectDelegate(this)); // sort by status column means the jobs will be sorted by the queue order ui->jobsView->sortByColumn(JobModel::ColStatus, Qt::AscendingOrder); connect(ui->jobsView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &PrintQueueUi::updateButtons); connect(ui->jobsView, &QTreeView::customContextMenuRequested, this, &PrintQueueUi::showContextMenu); ui->jobsView->header()->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui->jobsView->header(), &QHeaderView::customContextMenuRequested, this, &PrintQueueUi::showHeaderContextMenu); QHeaderView *header = ui->jobsView->header(); header->setSectionResizeMode(QHeaderView::Interactive); header->setStretchLastSection(false); header->setSectionResizeMode(JobModel::ColStatus, QHeaderView::ResizeToContents); header->setSectionResizeMode(JobModel::ColName, QHeaderView::Stretch); header->setSectionResizeMode(JobModel::ColUser, QHeaderView::ResizeToContents); header->setSectionResizeMode(JobModel::ColCreated, QHeaderView::ResizeToContents); header->setSectionResizeMode(JobModel::ColCompleted, QHeaderView::ResizeToContents); header->setSectionResizeMode(JobModel::ColPages, QHeaderView::ResizeToContents); header->setSectionResizeMode(JobModel::ColProcessed, QHeaderView::ResizeToContents); header->setSectionResizeMode(JobModel::ColSize, QHeaderView::ResizeToContents); header->setSectionResizeMode(JobModel::ColStatusMessage, QHeaderView::ResizeToContents); header->setSectionResizeMode(JobModel::ColPrinter, QHeaderView::ResizeToContents); KConfigGroup printQueue(KSharedConfig::openConfig(QLatin1String("print-manager")), "PrintQueue"); if (printQueue.hasKey("ColumnState")) { // restore the header state order header->restoreState(printQueue.readEntry("ColumnState", QByteArray())); } else { // Hide some columns ColPrinter header->hideSection(JobModel::ColPrinter); header->hideSection(JobModel::ColUser); header->hideSection(JobModel::ColCompleted); header->hideSection(JobModel::ColSize); header->hideSection(JobModel::ColFromHost); } // This is emitted when a printer is modified connect(KCupsConnection::global(), &KCupsConnection::printerModified, this, &PrintQueueUi::updatePrinter); // This is emitted when a printer has it's state changed connect(KCupsConnection::global(), &KCupsConnection::printerStateChanged, this, &PrintQueueUi::updatePrinter); // This is emitted when a printer is stopped connect(KCupsConnection::global(), &KCupsConnection::printerStopped, this, &PrintQueueUi::updatePrinter); // This is emitted when a printer is restarted connect(KCupsConnection::global(), &KCupsConnection::printerRestarted, this, &PrintQueueUi::updatePrinter); // This is emitted when a printer is shutdown connect(KCupsConnection::global(), &KCupsConnection::printerShutdown, this, &PrintQueueUi::updatePrinter); // This is emitted when a printer is removed connect(KCupsConnection::global(), &KCupsConnection::printerDeleted, this, &PrintQueueUi::updatePrinter); // This is emitted when a printer/queue is changed // Deprecated stuff that works better than the above connect(KCupsConnection::global(), &KCupsConnection::rhPrinterAdded, this, &PrintQueueUi::updatePrinterByName); connect(KCupsConnection::global(), &KCupsConnection::rhPrinterRemoved, this, &PrintQueueUi::updatePrinterByName); connect(KCupsConnection::global(), &KCupsConnection::rhQueueChanged, this, &PrintQueueUi::updatePrinterByName); updatePrinterByName(m_destName); // Restore the dialog size KConfigGroup configGroup(KSharedConfig::openConfig(QLatin1String("print-manager")), "PrintQueue"); KWindowConfig::restoreWindowSize(windowHandle(), configGroup); } PrintQueueUi::~PrintQueueUi() { KConfigGroup configGroup(KSharedConfig::openConfig(QLatin1String("print-manager")), "PrintQueue"); // save the header state order configGroup.writeEntry("ColumnState", ui->jobsView->header()->saveState()); // Save the dialog size KWindowConfig::saveWindowSize(windowHandle(), configGroup); delete ui; } int PrintQueueUi::columnCount(const QModelIndex &parent) const { if (!parent.isValid()) { return JobModel::LastColumn; } return 0; } void PrintQueueUi::setState(int state, const QString &message) { qDebug() << state << message; if (state != m_lastState || ui->printerStatusMsgL->text() != message) { // save the last state so the ui doesn't need to keep updating if (ui->printerStatusMsgL->text() != message) { ui->printerStatusMsgL->setText(message); } m_lastState = state; QPixmap icon(m_printerIcon); m_printerPaused = false; switch (state) { case KCupsPrinter::Idle: ui->statusL->setText(i18n("Printer ready")); ui->pausePrinterPB->setText(i18n("Pause Printer")); ui->pausePrinterPB->setIcon(QIcon::fromTheme(QLatin1String("media-playback-pause"))); break; case KCupsPrinter::Printing: if (!m_title.isNull()) { QString jobTitle = m_model->processingJob(); if (jobTitle.isEmpty()) { ui->statusL->setText(i18n("Printing...")); } else { ui->statusL->setText(i18n("Printing '%1'", jobTitle)); } ui->pausePrinterPB->setText(i18n("Pause Printer")); ui->pausePrinterPB->setIcon(QIcon::fromTheme(QLatin1String("media-playback-pause"))); } break; case KCupsPrinter::Stopped: m_printerPaused = true; ui->statusL->setText(i18n("Printer paused")); ui->pausePrinterPB->setText(i18n("Resume Printer")); ui->pausePrinterPB->setIcon(QIcon::fromTheme(QLatin1String("media-playback-start"))); // create a paiter to paint the action icon over the key icon { QPainter painter(&icon); // the emblem icon to size 32 int overlaySize = KIconLoader::SizeMedium; QPoint startPoint; // bottom right corner startPoint = QPoint(PRINTER_ICON_SIZE - overlaySize - 2, PRINTER_ICON_SIZE - overlaySize - 2); painter.drawPixmap(startPoint, m_pauseIcon); } break; default : ui->statusL->setText(i18n("Printer state unknown")); break; } // set the printer icon setWindowIcon(icon); } } void PrintQueueUi::showContextMenu(const QPoint &point) { // check if the click was actually over a job if (!ui->jobsView->indexAt(point).isValid() || m_preparingMenu) { return; } m_preparingMenu = true; bool moveTo = false; QItemSelection selection; // we need to map the selection to source to get the real indexes selection = m_proxyModel->mapSelectionToSource(ui->jobsView->selectionModel()->selection()); // if the selection is empty the user clicked on an empty space if (!selection.indexes().isEmpty()) { const QModelIndexList indexes = selection.indexes(); for (const QModelIndex &index : indexes) { if (index.column() == 0 && index.flags() & Qt::ItemIsDragEnabled) { // Found a move to item moveTo = true; break; } } // if we can move a job create the menu if (moveTo) { // context menu auto menu = new QMenu(this); // move to menu auto moveToMenu = new QMenu(i18n("Move to"), this); // get printers we can move to QPointer request = new KCupsRequest; - QStringList attr; - attr << KCUPS_PRINTER_NAME; - attr << KCUPS_PRINTER_INFO; - request->getPrinters(attr); + request->getPrinters({ KCUPS_PRINTER_NAME, KCUPS_PRINTER_INFO }); request->waitTillFinished(); if (!request) { return; } const KCupsPrinters printers = request->printers(); request->deleteLater(); for (const KCupsPrinter &printer : printers) { // If there is a printer and it's not the current one add it // as a new destination if (printer.name() != m_destName) { QAction *action = moveToMenu->addAction(printer.info()); action->setData(printer.name()); } } if (!moveToMenu->isEmpty()) { menu->addMenu(moveToMenu); // show the menu on the right point QAction *action = menu->exec(ui->jobsView->mapToGlobal(point)); if (action) { // move the job modifyJob(JobModel::Move, action->data().toString()); } } } } m_preparingMenu = false; } void PrintQueueUi::showHeaderContextMenu(const QPoint &point) { // Displays a menu containing the header name, and // a check box to indicate if it's being shown auto menu = new QMenu(this); for (int i = 0; i < m_proxyModel->columnCount(); i++) { - QAction *action; - QString name; - name = m_proxyModel->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString(); - action = menu->addAction(name); + auto name = m_proxyModel->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString(); + QAction *action = menu->addAction(name); action->setCheckable(true); action->setChecked(!ui->jobsView->header()->isSectionHidden(i)); action->setData(i); } QAction *action = menu->exec(ui->jobsView->header()->mapToGlobal(point)); if (action) { int section = action->data().toInt(); if (action->isChecked()) { ui->jobsView->header()->showSection(section); } else { ui->jobsView->header()->hideSection(section); } } } void PrintQueueUi::updatePrinterByName(const QString &printer) { qDebug() << printer << m_destName; if (printer != m_destName) { // It was another printer that changed return; } - QStringList attr; - attr << KCUPS_PRINTER_INFO; - attr << KCUPS_PRINTER_TYPE; - attr << KCUPS_PRINTER_STATE; - attr << KCUPS_PRINTER_STATE_MESSAGE; + const QStringList attr({ + KCUPS_PRINTER_INFO, + KCUPS_PRINTER_TYPE, + KCUPS_PRINTER_STATE, + KCUPS_PRINTER_STATE_MESSAGE, + }); auto request = new KCupsRequest; connect(request, &KCupsRequest::finished, this, &PrintQueueUi::getAttributesFinished); request->getPrinterAttributes(printer, m_isClass, attr); } void PrintQueueUi::updatePrinter(const QString &text, const QString &printerUri, const QString &printerName, uint printerState, const QString &printerStateReasons, bool printerIsAcceptingJobs) { // REALLY? all these parameters just to say foo was added?? Q_UNUSED(text) Q_UNUSED(printerUri) Q_UNUSED(printerState) Q_UNUSED(printerStateReasons) Q_UNUSED(printerIsAcceptingJobs) qDebug() << printerName << printerStateReasons; updatePrinterByName(printerName); } void PrintQueueUi::getAttributesFinished(KCupsRequest *request) { qDebug() << request->hasError() << request->printers().isEmpty(); if (request->hasError() || request->printers().isEmpty()) { // if cups stops we disable our queue setEnabled(false); request->deleteLater(); // DO not delete before using as the request is in another thread return; } else if (isEnabled() == false) { // if cups starts again we enable our queue setEnabled(true); } KCupsPrinter printer = request->printers().first(); // get printer-info if (printer.info().isEmpty()) { m_title = printer.name(); } else { - m_title = printer.name() % QLatin1String(" - ") % printer.info(); + m_title = printer.name() + QLatin1String(" - ") + printer.info(); } // get printer-state setState(printer.state(), printer.stateMsg()); // store if the printer is a class m_isClass = printer.isClass(); request->deleteLater(); update(); } void PrintQueueUi::update() { // Set window title if (m_model->rowCount()) { if (m_destName.isNull()) { setWindowTitle(i18np("All Printers (%1 Job)", "All Printers (%1 Jobs)", m_model->rowCount())); } else { setWindowTitle(i18np("%2 (%1 Job)", "%2 (%1 Jobs)", m_model->rowCount(), m_title)); } } else { setWindowTitle(m_destName.isNull() ? i18n("All Printers") : m_title); } } void PrintQueueUi::updateButtons() { bool cancel, hold, release, reprint; // Set all options to false cancel = hold = release = reprint = false; QItemSelection selection; // we need to map the selection to source to get the real indexes selection = m_proxyModel->mapSelectionToSource(ui->jobsView->selectionModel()->selection()); // enable or disable the job action buttons if something is selected if (!selection.indexes().isEmpty()) { const QModelIndexList indexes = selection.indexes(); for (const QModelIndex &index : indexes) { if (index.column() == 0) { switch (static_cast(index.data(JobModel::RoleJobState).toInt())) { case IPP_JOB_CANCELED : case IPP_JOB_COMPLETED : case IPP_JOB_ABORTED : break; case IPP_JOB_HELD : case IPP_JOB_STOPPED : release = true; cancel = true; break; default: cancel = hold = true; break; } if (index.data(JobModel::RoleJobRestartEnabled).toBool()) { reprint = true; } } } } ui->cancelJobPB->setEnabled(cancel); ui->holdJobPB->setEnabled(hold); ui->resumeJobPB->setEnabled(release); ui->reprintPB->setEnabled(reprint); } void PrintQueueUi::modifyJob(int action, const QString &destName) { // get all selected indexes QItemSelection selection; // we need to map the selection to source to get the real indexes selection = m_proxyModel->mapSelectionToSource(ui->jobsView->selectionModel()->selection()); const QModelIndexList indexes = selection.indexes(); for (const QModelIndex &index : indexes) { if (index.column() == 0) { KCupsRequest *request; request = m_model->modifyJob(index.row(), static_cast(action), destName); if (!request) { // probably the job already has this state // or this is an unknown action continue; } request->waitTillFinished(); if (request->hasError()) { QString msg, jobName; jobName = m_model->item(index.row(), static_cast(JobModel::ColName))->text(); switch (action) { case JobModel::Cancel: msg = i18n("Failed to cancel '%1'", jobName); break; case JobModel::Hold: msg = i18n("Failed to hold '%1'", jobName); break; case JobModel::Release: msg = i18n("Failed to release '%1'", jobName); break; case JobModel::Reprint: msg = i18n("Failed to reprint '%1'", jobName); break; case JobModel::Move: msg = i18n("Failed to move '%1' to '%2'", jobName, destName); break; } KMessageBox::detailedSorry(this, msg, request->errorMsg(), i18n("Failed")); } request->deleteLater(); } } } void PrintQueueUi::pausePrinter() { // STOP and RESUME printer QPointer request = new KCupsRequest; if (m_printerPaused) { qDebug() << m_destName << "m_printerPaused"; request->resumePrinter(m_destName); } else { qDebug() << m_destName << "NOT m_printerPaused"; request->pausePrinter(m_destName); } request->waitTillFinished(); if (request) { request->deleteLater(); } } void PrintQueueUi::configurePrinter() { QProcess::startDetached(QLatin1String("configure-printer"), {m_destName}); } void PrintQueueUi::cancelJob() { // CANCEL a job modifyJob(JobModel::Cancel); } void PrintQueueUi::holdJob() { // HOLD a job modifyJob(JobModel::Hold); } void PrintQueueUi::resumeJob() { // RESUME a job modifyJob(JobModel::Release); } void PrintQueueUi::reprintJob() { modifyJob(JobModel::Reprint); } void PrintQueueUi::whichJobsIndexChanged(int index) { switch (index) { case 1: m_model->setWhichJobs(JobModel::WhichCompleted); break; case 2: m_model->setWhichJobs(JobModel::WhichAll); break; default: m_model->setWhichJobs(JobModel::WhichActive); break; } } void PrintQueueUi::setupButtons() { // setup jobs buttons // cancel action ui->cancelJobPB->setIcon(QIcon::fromTheme(QLatin1String("dialog-cancel"))); // hold job action ui->holdJobPB->setIcon(QIcon::fromTheme(QLatin1String("document-open-recent"))); // resume job action // TODO we need a new icon ui->resumeJobPB->setIcon(QIcon::fromTheme(QLatin1String("media-playback-start"))); ui->reprintPB->setIcon(QIcon::fromTheme(QLatin1String("view-refresh"))); const QIcon viewFilterIcon = QIcon::fromTheme(QLatin1String("view-filter")); ui->whichJobsCB->setItemIcon(0, viewFilterIcon); ui->whichJobsCB->setItemIcon(1, viewFilterIcon); ui->whichJobsCB->setItemIcon(2, viewFilterIcon); // stop start printer ui->pausePrinterPB->setIcon(QIcon::fromTheme(QLatin1String("media-playback-pause"))); // configure printer ui->configurePrinterPB->setIcon(QIcon::fromTheme(QLatin1String("configure"))); } void PrintQueueUi::closeEvent(QCloseEvent *event) { // emits finished signal to be removed the cache emit finished(); QWidget::closeEvent(event); } diff --git a/printqueue/PrintQueueUi.h b/printqueue/PrintQueueUi.h index 1caf52e..9b1f7de 100644 --- a/printqueue/PrintQueueUi.h +++ b/printqueue/PrintQueueUi.h @@ -1,94 +1,94 @@ /*************************************************************************** * 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. * ***************************************************************************/ #ifndef PRINT_QUEUE_UI_H #define PRINT_QUEUE_UI_H #include #include #include namespace Ui { class PrintQueueUi; } class KCupsRequest; class KCupsPrinter; class JobSortFilterModel; class JobModel; class PrintQueueUi : public QDialog { Q_OBJECT public: explicit PrintQueueUi(const KCupsPrinter &printer, QWidget *parent = 0); ~PrintQueueUi(); signals: void finished(); public slots: void update(); private slots: void updatePrinterByName(const QString &printer); void updatePrinter(const QString &text, const QString &printerUri, const QString &printerName, uint printerState, const QString &printerStateReasons, bool printerIsAcceptingJobs); void whichJobsIndexChanged(int index); void pausePrinter(); void configurePrinter(); void cancelJob(); void holdJob(); void resumeJob(); void reprintJob(); int columnCount(const QModelIndex &parent = QModelIndex()) const; void updateButtons(); void showContextMenu(const QPoint &point); void showHeaderContextMenu(const QPoint &point); void getAttributesFinished(KCupsRequest *request); private: void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE; void setupButtons(); void setState(int state, const QString &message); void modifyJob(int action, const QString &destName = QString()); Ui::PrintQueueUi *ui; QToolButton *m_filterJobs; JobSortFilterModel *m_proxyModel; JobModel *m_model; QString m_destName; QString m_title; - bool m_isClass; - bool m_preparingMenu; QPixmap m_printerIcon; QPixmap m_pauseIcon; QPixmap m_startIcon; QPixmap m_warningIcon; - bool m_printerPaused; - char m_lastState; + char m_lastState = 0; + bool m_isClass; + bool m_preparingMenu = false; + bool m_printerPaused = false; }; #endif