mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-24 10:52:53 +00:00
553 lines
21 KiB
C++
553 lines
21 KiB
C++
/***************************************************************************
|
||
* 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 "PrinterModel.h"
|
||
|
||
#include <QDateTime>
|
||
#include <QMimeData>
|
||
#include <QDBusConnection>
|
||
#include <QtDBus/QDBusInterface>
|
||
#include <QPointer>
|
||
|
||
#include <KUser>
|
||
#include <KDebug>
|
||
#include <KLocale>
|
||
#include <KMessageBox>
|
||
|
||
#include <KCupsRequest.h>
|
||
|
||
#include <cups/cups.h>
|
||
|
||
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;
|
||
|
||
QHash<int, QByteArray> roles = roleNames();
|
||
roles[DestStatus] = "stateMessage";
|
||
roles[DestName] = "printerName";
|
||
roles[DestState] = "printerState";
|
||
roles[DestIsDefault] = "isDefault";
|
||
roles[DestIsShared] = "isShared";
|
||
roles[DestIsAcceptingJobs] = "isAcceptingJobs";
|
||
roles[DestIsPaused] = "isPaused";
|
||
roles[DestIsClass] = "isClass";
|
||
roles[DestLocation] = "location";
|
||
roles[DestDescription] = "info";
|
||
roles[DestKind] = "kind";
|
||
roles[DestType] = "type";
|
||
roles[DestCommands] = "commands";
|
||
roles[DestMarkerChangeTime] = "markerChangeTime";
|
||
roles[DestMarkers] = "markers";
|
||
roles[DestIconName] = "iconName";
|
||
roles[DestRemote] = "remote";
|
||
setRoleNames(roles);
|
||
|
||
// This is emitted when a printer is added
|
||
connect(KCupsConnection::global(),
|
||
SIGNAL(printerAdded(QString,QString,QString,uint,QString,bool)),
|
||
this,
|
||
SLOT(insertUpdatePrinter(QString,QString,QString,uint,QString,bool)));
|
||
|
||
// This is emitted when a printer is modified
|
||
connect(KCupsConnection::global(),
|
||
SIGNAL(printerModified(QString,QString,QString,uint,QString,bool)),
|
||
this,
|
||
SLOT(insertUpdatePrinter(QString,QString,QString,uint,QString,bool)));
|
||
|
||
// This is emitted when a printer has it's state changed
|
||
connect(KCupsConnection::global(),
|
||
SIGNAL(printerStateChanged(QString,QString,QString,uint,QString,bool)),
|
||
this,
|
||
SLOT(insertUpdatePrinter(QString,QString,QString,uint,QString,bool)));
|
||
|
||
// This is emitted when a printer is stopped
|
||
connect(KCupsConnection::global(),
|
||
SIGNAL(printerStopped(QString,QString,QString,uint,QString,bool)),
|
||
this,
|
||
SLOT(insertUpdatePrinter(QString,QString,QString,uint,QString,bool)));
|
||
|
||
// This is emitted when a printer is restarted
|
||
connect(KCupsConnection::global(),
|
||
SIGNAL(printerRestarted(QString,QString,QString,uint,QString,bool)),
|
||
this,
|
||
SLOT(insertUpdatePrinter(QString,QString,QString,uint,QString,bool)));
|
||
|
||
// This is emitted when a printer is shutdown
|
||
connect(KCupsConnection::global(),
|
||
SIGNAL(printerShutdown(QString,QString,QString,uint,QString,bool)),
|
||
this,
|
||
SLOT(insertUpdatePrinter(QString,QString,QString,uint,QString,bool)));
|
||
|
||
// This is emitted when a printer is removed
|
||
connect(KCupsConnection::global(),
|
||
SIGNAL(printerDeleted(QString,QString,QString,uint,QString,bool)),
|
||
this,
|
||
SLOT(printerRemoved(QString,QString,QString,uint,QString,bool)));
|
||
|
||
connect(KCupsConnection::global(), SIGNAL(serverAudit(QString)),
|
||
SLOT(serverChanged(QString)));
|
||
connect(KCupsConnection::global(), SIGNAL(serverStarted(QString)),
|
||
SLOT(serverChanged(QString)));
|
||
connect(KCupsConnection::global(), SIGNAL(serverStopped(QString)),
|
||
SLOT(serverChanged(QString)));
|
||
connect(KCupsConnection::global(), SIGNAL(serverRestarted(QString)),
|
||
SLOT(serverChanged(QString)));
|
||
|
||
// Deprecated stuff that works better than the above
|
||
connect(KCupsConnection::global(), SIGNAL(rhPrinterAdded(QString)),
|
||
this, SLOT(insertUpdatePrinter(QString)));
|
||
|
||
connect(KCupsConnection::global(), SIGNAL(rhPrinterRemoved(QString)),
|
||
this, SLOT(printerRemoved(QString)));
|
||
|
||
connect(KCupsConnection::global(), SIGNAL(rhQueueChanged(QString)),
|
||
this, SLOT(insertUpdatePrinter(QString)));
|
||
|
||
connect(this, SIGNAL(rowsInserted(QModelIndex,int,int)),
|
||
this, SLOT(slotCountChanged()));
|
||
connect(this, SIGNAL(rowsRemoved(QModelIndex,int,int)),
|
||
this, SLOT(slotCountChanged()));
|
||
connect(this, SIGNAL(modelReset()),
|
||
this, SLOT(slotCountChanged()));
|
||
|
||
update();
|
||
}
|
||
|
||
void PrinterModel::getDestsFinished()
|
||
{
|
||
KCupsRequest *request = qobject_cast<KCupsRequest *>(sender());
|
||
// 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();
|
||
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<QStandardItem *> 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;
|
||
}
|
||
|
||
void PrinterModel::pausePrinter(const QString &printerName)
|
||
{
|
||
QPointer<KCupsRequest> request = new KCupsRequest;
|
||
request->pausePrinter(printerName);
|
||
request->waitTillFinished();
|
||
if (request) {
|
||
request->deleteLater();
|
||
}
|
||
}
|
||
|
||
void PrinterModel::resumePrinter(const QString &printerName)
|
||
{
|
||
QPointer<KCupsRequest> request = new KCupsRequest;
|
||
request->resumePrinter(printerName);
|
||
request->waitTillFinished();
|
||
if (request) {
|
||
request->deleteLater();
|
||
}
|
||
}
|
||
|
||
void PrinterModel::rejectJobs(const QString &printerName)
|
||
{
|
||
QPointer<KCupsRequest> request = new KCupsRequest;
|
||
request->rejectJobs(printerName);
|
||
request->waitTillFinished();
|
||
if (request) {
|
||
request->deleteLater();
|
||
}
|
||
}
|
||
|
||
void PrinterModel::acceptJobs(const QString &printerName)
|
||
{
|
||
QPointer<KCupsRequest> 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<int>, ) ) ( "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
|
||
KCupsRequest *request = new KCupsRequest;
|
||
connect(request, SIGNAL(finished()), this, SLOT(getDestsFinished()));
|
||
request->getPrinters(m_attributes);
|
||
}
|
||
|
||
void PrinterModel::insertDest(int pos, const KCupsPrinter &printer)
|
||
{
|
||
// Create the printer item
|
||
QStandardItem *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);
|
||
}
|
||
kDebug() << 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["marker-change-time"] = printer.markerChangeTime();
|
||
markers["marker-colors"] = printer.argument("marker-colors");
|
||
markers["marker-levels"] = printer.argument("marker-levels");
|
||
markers["marker-names"] = printer.argument("marker-names");
|
||
markers["marker-types"] = printer.argument("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::insertUpdatePrinter(const QString &printerName)
|
||
{
|
||
KCupsRequest *request = new KCupsRequest;
|
||
connect(request, SIGNAL(finished()), this, SLOT(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)
|
||
|
||
kDebug() << text << printerUri << printerName << printerState << printerStateReasons << printerIsAcceptingJobs;
|
||
insertUpdatePrinter(printerName);
|
||
}
|
||
|
||
void PrinterModel::insertUpdatePrinterFinished()
|
||
{
|
||
KCupsRequest *request = qobject_cast<KCupsRequest *>(sender());
|
||
if (!request->hasError()) {
|
||
foreach (const KCupsPrinter &printer, request->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::printerRemoved(const QString &printerName)
|
||
{
|
||
kDebug() << 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)
|
||
kDebug() << 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)
|
||
{
|
||
kDebug() << 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)
|
||
{
|
||
kDebug() << 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)
|
||
{
|
||
kDebug() << 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)
|
||
{
|
||
kDebug() << 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)
|
||
{
|
||
kDebug() << text << printerUri << printerName << printerState << printerStateReasons << printerIsAcceptingJobs;
|
||
}
|
||
|
||
void PrinterModel::serverChanged(const QString &text)
|
||
{
|
||
kDebug() << text;
|
||
update();
|
||
}
|
||
|
||
#include "PrinterModel.moc"
|