Make the icon an attribute on the printer object

This allows retrying based on actual size and using cURL for getting
the icon to avoid old Qt network code.
This commit is contained in:
Anton Thomasson 2022-02-19 17:33:59 +01:00
parent d8267db9fe
commit 0efd96c072
12 changed files with 154 additions and 75 deletions

View file

@ -36,6 +36,7 @@ DEFINES += SEAPRINT_VERSION='\\"$$VERSION\\"'
SOURCES += src/harbour-seaprint.cpp \ SOURCES += src/harbour-seaprint.cpp \
src/convertchecker.cpp \ src/convertchecker.cpp \
src/curlrequester.cpp \ src/curlrequester.cpp \
src/imageitem.cpp \
src/ippdiscovery.cpp \ src/ippdiscovery.cpp \
src/ippmsg.cpp \ src/ippmsg.cpp \
src/ippprinter.cpp \ src/ippprinter.cpp \
@ -82,6 +83,7 @@ TRANSLATIONS += translations/harbour-seaprint-de.ts \
HEADERS += \ HEADERS += \
src/convertchecker.h \ src/convertchecker.h \
src/curlrequester.h \ src/curlrequester.h \
src/imageitem.h \
src/ippdiscovery.h \ src/ippdiscovery.h \
src/ippmsg.h \ src/ippmsg.h \
src/ippprinter.h \ src/ippprinter.h \

View file

@ -4,6 +4,7 @@ import Sailfish.Pickers 1.0
import seaprint.ippdiscovery 1.0 import seaprint.ippdiscovery 1.0
import seaprint.convertchecker 1.0 import seaprint.convertchecker 1.0
import seaprint.ippprinter 1.0 import seaprint.ippprinter 1.0
import seaprint.imageitem 1.0
import seaprint.mimer 1.0 import seaprint.mimer 1.0
import "utils.js" as Utils import "utils.js" as Utils
@ -212,7 +213,7 @@ Page {
} }
} }
Image { ImageItem {
id: icon id: icon
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
@ -221,13 +222,17 @@ Page {
height: Theme.itemSizeLarge height: Theme.itemSizeLarge
width: Theme.itemSizeLarge width: Theme.itemSizeLarge
sourceSize.height: height image: printer.icon
sourceSize.width: width
source: printer.attrs["printer-icons"] ? "image://ippdiscovery/"+Utils.selectIcon(printer.attrs["printer-icons"].value)
: "image://svg/qml/pages/icon-seaprint-nobg.svg"
// Some printers serve their icons over https with invalid certs...
onStatusChanged: if (status == Image.Error) source = "image://svg/qml/pages/icon-seaprint-nobg.svg"
Image {
id: placeholder
anchors.fill: parent
sourceSize.height: height
sourceSize.width: width
visible: !parent.valid
source: "image://svg/qml/pages/icon-seaprint-nobg.svg"
}
} }
Image { Image {

View file

@ -461,26 +461,6 @@ function fixupChoices(name, choices, mimeType)
} }
} }
function selectIcon(icons)
{
for(var i=0; i < icons.length; i++)
{
if(endsWith("M.png", icons[i]) || endsWith("128.png", icons[i]) || endsWith("128.PNG", icons[i]))
{
return icons[i];
}
}
// Icons must be 48, 128 or 256px and sorted by size, so if all 3 are provided we want the middle one
if(icons.length == 3)
{
return icons[1];
}
else
{
return icons[0];
}
}
function isWaringState(printer) function isWaringState(printer)
{ {
if(printer.attrs["printer-state"].value > 4) if(printer.attrs["printer-state"].value > 4)

View file

@ -3,6 +3,7 @@
#include <sailfishapp.h> #include <sailfishapp.h>
#include <src/ippdiscovery.h> #include <src/ippdiscovery.h>
#include <src/ippprinter.h> #include <src/ippprinter.h>
#include <src/imageitem.h>
#include <src/mimer.h> #include <src/mimer.h>
#include <src/convertchecker.h> #include <src/convertchecker.h>
#include <src/svgprovider.h> #include <src/svgprovider.h>
@ -41,12 +42,12 @@ int main(int argc, char *argv[])
qmlRegisterSingletonType<ConvertChecker>("seaprint.convertchecker", 1, 0, "ConvertChecker", singletontype_provider<ConvertChecker>); qmlRegisterSingletonType<ConvertChecker>("seaprint.convertchecker", 1, 0, "ConvertChecker", singletontype_provider<ConvertChecker>);
qmlRegisterSingletonType<ConvertChecker>("seaprint.settings", 1, 0, "SeaPrintSettings", singletontype_provider<Settings>); qmlRegisterSingletonType<ConvertChecker>("seaprint.settings", 1, 0, "SeaPrintSettings", singletontype_provider<Settings>);
qmlRegisterType<IppPrinter>("seaprint.ippprinter", 1, 0, "IppPrinter"); qmlRegisterType<IppPrinter>("seaprint.ippprinter", 1, 0, "IppPrinter");
qmlRegisterType<ImageItem>("seaprint.imageitem", 1, 0, "ImageItem");
qmlRegisterUncreatableType<IppMsg>("seaprint.ippmsg", 1, 0, "IppMsg", "Only used to supply an enum type"); qmlRegisterUncreatableType<IppMsg>("seaprint.ippmsg", 1, 0, "IppMsg", "Only used to supply an enum type");
QQuickView* view = SailfishApp::createView(); QQuickView* view = SailfishApp::createView();
view->engine()->addImportPath(SailfishApp::pathTo("qml/pages").toString()); view->engine()->addImportPath(SailfishApp::pathTo("qml/pages").toString());
view->engine()->addImageProvider(QLatin1String("ippdiscovery"), IppDiscovery::instance());
view->engine()->addImageProvider(QLatin1String("svg"), SvgProvider::instance()); view->engine()->addImageProvider(QLatin1String("svg"), SvgProvider::instance());
view->setSource(SailfishApp::pathToMainQml()); view->setSource(SailfishApp::pathToMainQml());

32
src/imageitem.cpp Normal file
View file

@ -0,0 +1,32 @@
#include "imageitem.h"
#include "svgprovider.h"
ImageItem::ImageItem()
{
}
void ImageItem::paint(QPainter *painter)
{
QImage scaled = _image.scaledToHeight(boundingRect().height(), Qt::SmoothTransformation);
painter->drawImage(QPoint {0, 0}, scaled);
}
QImage ImageItem::getImage() const
{
return _image;
}
void ImageItem::setImage(const QImage &image)
{
_image = image;
emit imageChanged();
update();
}
bool ImageItem::isValid() const
{
return !_image.isNull();
}

31
src/imageitem.h Normal file
View file

@ -0,0 +1,31 @@
#ifndef IMAGEITEM_H
#define IMAGEITEM_H
#include <QQuickPaintedItem>
#include <QPainter>
#include <QImage>
class ImageItem : public QQuickPaintedItem
{
Q_OBJECT
Q_PROPERTY(QImage image READ getImage WRITE setImage NOTIFY imageChanged)
Q_PROPERTY(bool valid READ isValid NOTIFY imageChanged)
public:
ImageItem();
void paint(QPainter *painter);
signals:
void imageChanged();
private:
QImage getImage() const;
void setImage(const QImage &image);
bool isValid() const;
QImage _image;
};
#endif // IMAGEITEM_H

View file

@ -37,7 +37,7 @@ QStringList get_addr(Bytestream& bts)
return addr; return addr;
} }
IppDiscovery::IppDiscovery() : QStringListModel(), QQuickImageProvider(QQuickImageProvider::Image, ForceAsynchronousImageLoading) IppDiscovery::IppDiscovery() : QStringListModel()
{ {
socket = new QUdpSocket(this); socket = new QUdpSocket(this);
connect(socket, &QUdpSocket::readyRead, this, &IppDiscovery::readPendingDatagrams); connect(socket, &QUdpSocket::readyRead, this, &IppDiscovery::readPendingDatagrams);
@ -419,37 +419,3 @@ void IppDiscovery::resolve(QUrl& url)
url.setHost(_AAs.value(host)); url.setHost(_AAs.value(host));
} }
} }
QImage IppDiscovery::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{ //TODO: consider caching images (doesn't appear to be needed currently)
Q_UNUSED(requestedSize);
qDebug() << "requesting image" << id;
QImage img;
QNetworkAccessManager* nam = new QNetworkAccessManager();
QUrl url(id);
resolve(url);
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::UserAgentHeader, "SeaPrint " SEAPRINT_VERSION);
connect(nam, &QNetworkAccessManager::sslErrors, &IppPrinter::ignoreSslErrors);
QNetworkReply* reply = nam->get(request);
QEventLoop loop;
connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
if (reply->error() == QNetworkReply::NoError)
{
QImageReader imageReader(reply);
img = imageReader.read();
}
*size = img.size();
delete nam;
return img;
}

View file

@ -1,16 +1,11 @@
#ifndef IPPDISCOVERY_H #ifndef IPPDISCOVERY_H
#define IPPDISCOVERY_H #define IPPDISCOVERY_H
#include <QStringListModel> #include <QStringListModel>
#include <QQuickImageProvider>
#include <QUdpSocket> #include <QUdpSocket>
#include <QMutex> #include <QMutex>
#include <QImageReader>
#include <QtNetwork>
#include <QNetworkAccessManager>
#include <QEventLoop>
#include "bytestream.h" #include "bytestream.h"
class IppDiscovery : public QStringListModel, public QQuickImageProvider class IppDiscovery : public QStringListModel
{ {
Q_OBJECT Q_OBJECT
public: public:
@ -49,9 +44,6 @@ private:
void updateAndQueryPtrs(QStringList& ptrs, QStringList new_ptrs); void updateAndQueryPtrs(QStringList& ptrs, QStringList new_ptrs);
QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override;
QStringList _ipp; QStringList _ipp;
QStringList _ipps; QStringList _ipps;
QMap<QString,QString> _rps; QMap<QString,QString> _rps;

View file

@ -25,6 +25,7 @@ IppPrinter::IppPrinter() : _worker(this)
connect(this, &IppPrinter::doConvertPlaintext, &_worker, &PrinterWorker::convertPlaintext); connect(this, &IppPrinter::doConvertPlaintext, &_worker, &PrinterWorker::convertPlaintext);
connect(this, &IppPrinter::doGetStrings, &_worker, &PrinterWorker::getStrings); connect(this, &IppPrinter::doGetStrings, &_worker, &PrinterWorker::getStrings);
connect(this, &IppPrinter::doGetImage, &_worker, &PrinterWorker::getImage);
connect(&_worker, &PrinterWorker::progress, this, &IppPrinter::setProgress); connect(&_worker, &PrinterWorker::progress, this, &IppPrinter::setProgress);
connect(&_worker, &PrinterWorker::busyMessage, this, &IppPrinter::setBusyMessage); connect(&_worker, &PrinterWorker::busyMessage, this, &IppPrinter::setBusyMessage);
@ -106,7 +107,7 @@ void IppPrinter::refresh() {
} }
emit attrsChanged(); emit attrsChanged();
MaybeGetStrings(); // MaybeGetStrings(); - for testing fake file-prinetrs with a strings file hosted elsewhere
UpdateAdditionalDocumentFormats(); UpdateAdditionalDocumentFormats();
} }
else else
@ -128,6 +129,41 @@ void IppPrinter::MaybeGetStrings()
} }
} }
void IppPrinter::MaybeGetIcon(bool retry)
{
if(_attrs.contains("printer-icons") && (_icon.isNull() || retry))
{
QUrl url;
QJsonArray icons = _attrs["printer-icons"].toObject()["value"].toArray();
if(retry)
{ // If there were more than one icon, try the last one on the retry
if(icons.size() > 1)
{
url = icons.last().toString();
}
}
else
{
if(icons.size() == 3)
{ // If there are 3 icons, the first will be the 48px one, ignore it
url = icons.at(1).toString();
}
else
{
url = icons.at(0).toString();
}
}
if(!url.isEmpty())
{
IppDiscovery::instance()->resolve(url);
emit doGetImage(url);
}
}
}
void IppPrinter::UpdateAdditionalDocumentFormats() void IppPrinter::UpdateAdditionalDocumentFormats()
{ {
_additionalDocumentFormats = QStringList(); _additionalDocumentFormats = QStringList();
@ -180,6 +216,7 @@ void IppPrinter::getPrinterAttributesFinished(CURLcode res, Bytestream data)
emit attrsChanged(); emit attrsChanged();
MaybeGetStrings(); MaybeGetStrings();
MaybeGetIcon();
UpdateAdditionalDocumentFormats(); UpdateAdditionalDocumentFormats();
} }
@ -272,6 +309,26 @@ void IppPrinter::getStringsFinished(CURLcode res, Bytestream data)
} }
} }
void IppPrinter::getImageFinished(CURLcode res, Bytestream data)
{
qDebug() << res << data.size();
if(res == CURLE_OK)
{
QImage tmp;
if(tmp.loadFromData(data.raw(), data.size(), "PNG"))
{
_icon = tmp;
qDebug() << "image loaded" << _icon;
emit iconChanged();
if(tmp.size().width() < 128)
{
MaybeGetIcon(true);
}
}
}
}
void IppPrinter::ignoreSslErrors(QNetworkReply *reply, const QList<QSslError> &errors) void IppPrinter::ignoreSslErrors(QNetworkReply *reply, const QList<QSslError> &errors)
{ {
bool ignore = Settings::instance()->ignoreSslErrors(); bool ignore = Settings::instance()->ignoreSslErrors();

View file

@ -1,8 +1,7 @@
#ifndef IPPPRINTER_H #ifndef IPPPRINTER_H
#define IPPPRINTER_H #define IPPPRINTER_H
#include <QtNetwork> #include <QImage>
#include <QNetworkAccessManager>
#include "ippmsg.h" #include "ippmsg.h"
#include "printerworker.h" #include "printerworker.h"
#include "curlrequester.h" #include "curlrequester.h"
@ -19,6 +18,7 @@ class IppPrinter : public QObject
Q_PROPERTY(QJsonObject jobAttrs MEMBER _jobAttrs NOTIFY jobAttrsChanged) Q_PROPERTY(QJsonObject jobAttrs MEMBER _jobAttrs NOTIFY jobAttrsChanged)
Q_PROPERTY(QJsonArray jobs MEMBER _jobs NOTIFY jobsChanged) Q_PROPERTY(QJsonArray jobs MEMBER _jobs NOTIFY jobsChanged)
Q_PROPERTY(QJsonObject strings MEMBER _strings NOTIFY stringsChanged) Q_PROPERTY(QJsonObject strings MEMBER _strings NOTIFY stringsChanged)
Q_PROPERTY(QImage icon MEMBER _icon NOTIFY iconChanged)
Q_PROPERTY(QStringList additionalDocumentFormats MEMBER _additionalDocumentFormats NOTIFY additionalDocumentFormatsChanged) Q_PROPERTY(QStringList additionalDocumentFormats MEMBER _additionalDocumentFormats NOTIFY additionalDocumentFormatsChanged)
Q_PROPERTY(QString busyMessage MEMBER _busyMessage NOTIFY busyMessageChanged) Q_PROPERTY(QString busyMessage MEMBER _busyMessage NOTIFY busyMessageChanged)
Q_PROPERTY(QString progress MEMBER _progress NOTIFY progressChanged) Q_PROPERTY(QString progress MEMBER _progress NOTIFY progressChanged)
@ -49,6 +49,7 @@ signals:
void jobsChanged(); void jobsChanged();
void stringsChanged(); void stringsChanged();
void iconChanged();
void jobFinished(bool status); void jobFinished(bool status);
void cancelStatus(bool status); void cancelStatus(bool status);
@ -78,6 +79,7 @@ signals:
quint32 HwResX, quint32 HwResY, bool TwoSided, bool Tumble, bool BackHFlip, bool BackVFlip); quint32 HwResX, quint32 HwResY, bool TwoSided, bool Tumble, bool BackHFlip, bool BackVFlip);
void doGetStrings(QUrl url); void doGetStrings(QUrl url);
void doGetImage(QUrl url);
void additionalDocumentFormatsChanged(); void additionalDocumentFormatsChanged();
void busyMessageChanged(); void busyMessageChanged();
@ -89,6 +91,7 @@ public slots:
void onUrlChanged(); void onUrlChanged();
void MaybeGetStrings(); void MaybeGetStrings();
void MaybeGetIcon(bool retry=false);
void UpdateAdditionalDocumentFormats(); void UpdateAdditionalDocumentFormats();
void getPrinterAttributesFinished(CURLcode res, Bytestream data); void getPrinterAttributesFinished(CURLcode res, Bytestream data);
void printRequestFinished(CURLcode res, Bytestream data); void printRequestFinished(CURLcode res, Bytestream data);
@ -96,6 +99,7 @@ public slots:
void cancelJobFinished(CURLcode res, Bytestream data); void cancelJobFinished(CURLcode res, Bytestream data);
void getStringsFinished(CURLcode res, Bytestream data); void getStringsFinished(CURLcode res, Bytestream data);
void getImageFinished(CURLcode res, Bytestream data);
static void ignoreSslErrors(QNetworkReply *reply, const QList<QSslError> &errors); static void ignoreSslErrors(QNetworkReply *reply, const QList<QSslError> &errors);
@ -122,6 +126,7 @@ private:
QJsonArray _jobs; QJsonArray _jobs;
QJsonObject _strings; QJsonObject _strings;
QImage _icon;
QStringList _additionalDocumentFormats; QStringList _additionalDocumentFormats;

View file

@ -26,6 +26,13 @@ void PrinterWorker::getStrings(QUrl url)
connect(&cr, &CurlRequester::done, _printer, &IppPrinter::getStringsFinished); connect(&cr, &CurlRequester::done, _printer, &IppPrinter::getStringsFinished);
} }
void PrinterWorker::getImage(QUrl url)
{
CurlRequester cr(url, CurlRequester::HttpGetRequest);
connect(&cr, &CurlRequester::done, _printer, &IppPrinter::getImageFinished);
}
void PrinterWorker::getPrinterAttributes(Bytestream msg) void PrinterWorker::getPrinterAttributes(Bytestream msg)
{ {
CurlRequester cr(_printer->httpUrl()); CurlRequester cr(_printer->httpUrl());

View file

@ -32,6 +32,7 @@ private:
public slots: public slots:
void getStrings(QUrl url); void getStrings(QUrl url);
void getImage(QUrl url);
void getPrinterAttributes(Bytestream msg); void getPrinterAttributes(Bytestream msg);
void getJobs(Bytestream msg); void getJobs(Bytestream msg);
void cancelJob(Bytestream msg); void cancelJob(Bytestream msg);