File indexing completed on 2024-04-28 05:08:25

0001 /***************************************************************************
0002     Copyright (C) 2020 Robby Stephenson <robby@periapsis.org>
0003  ***************************************************************************/
0004 
0005 /***************************************************************************
0006  *                                                                         *
0007  *   This program is free software; you can redistribute it and/or         *
0008  *   modify it under the terms of the GNU General Public License as        *
0009  *   published by the Free Software Foundation; either version 2 of        *
0010  *   the License or (at your option) version 3 or any later version        *
0011  *   accepted by the membership of KDE e.V. (or its successor approved     *
0012  *   by the membership of KDE e.V.), which shall act as a proxy            *
0013  *   defined in Section 14 of version 3 of the license.                    *
0014  *                                                                         *
0015  *   This program is distributed in the hope that it will be useful,       *
0016  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0017  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0018  *   GNU General Public License for more details.                          *
0019  *                                                                         *
0020  *   You should have received a copy of the GNU General Public License     *
0021  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
0022  *                                                                         *
0023  ***************************************************************************/
0024 
0025 #include "printhandler.h"
0026 #include "document.h"
0027 #include "controller.h"
0028 #include "translators/htmlexporter.h"
0029 #include "utils/cursorsaver.h"
0030 #include "config/tellico_config.h"
0031 #include "../tellico_debug.h"
0032 
0033 #ifdef USE_KHTML
0034 #include <KHTMLPart>
0035 #include <KHTMLView>
0036 #include <KAboutData>
0037 #else
0038 #include <QWebEngineView>
0039 #include <QWebEnginePage>
0040 #include <QWebEngineSettings>
0041 #include <QPrinter>
0042 #include <QPrinterInfo>
0043 #include <QPrintDialog>
0044 #include <QPrintPreviewDialog>
0045 #include <QPrintPreviewWidget>
0046 #include <QEventLoop>
0047 #endif
0048 
0049 using Tellico::PrintHandler;
0050 
0051 #ifndef USE_KHTML
0052 class WebPagePrintable : public QWebEnginePage {
0053 Q_OBJECT
0054 
0055 public:
0056   WebPagePrintable(QObject* parent) : QWebEnginePage(parent) {
0057     QWebEngineSettings* settings = this->settings();
0058     settings->setAttribute(QWebEngineSettings::JavascriptEnabled, false);
0059     settings->setAttribute(QWebEngineSettings::PluginsEnabled, false);
0060     settings->setAttribute(QWebEngineSettings::LocalContentCanAccessRemoteUrls, true);
0061     settings->setAttribute(QWebEngineSettings::LocalContentCanAccessFileUrls, true);
0062   }
0063 
0064 public Q_SLOTS:
0065   void printDocument(QPrinter* printer) {
0066     Tellico::GUI::CursorSaver cs(Qt::WaitCursor);
0067     QEventLoop loop;
0068     print(printer, [&](bool) { loop.quit(); });
0069     loop.exec();
0070   }
0071 };
0072 #endif
0073 
0074 PrintHandler::PrintHandler(QObject* parent_) : QObject(parent_)
0075     , m_inPrintPreview(false) {
0076 }
0077 
0078 PrintHandler::~PrintHandler() {
0079 }
0080 
0081 void PrintHandler::setEntries(const Tellico::Data::EntryList& entries_) {
0082   m_entries = entries_;
0083   m_html.clear();
0084 }
0085 
0086 void PrintHandler::setColumns(const QStringList& columns_) {
0087   m_columns = columns_;
0088   m_html.clear();
0089 }
0090 
0091 void PrintHandler::print() {
0092   GUI::CursorSaver cs(Qt::WaitCursor);
0093 
0094   if(m_html.isEmpty()) {
0095     m_html = generateHtml();
0096     if(m_html.isEmpty()) {
0097       myDebug() << "PrintHandler - empty html output";
0098       return;
0099     }
0100   }
0101 
0102 #ifdef USE_KHTML
0103   KHTMLPart w;
0104 
0105   // KHTMLPart printing was broken in KDE until KHTML 5.16
0106   // see https://git.reviewboard.kde.org/r/125681/
0107   const QString version =  w.componentData().version();
0108   const uint major = version.section(QLatin1Char('.'), 0, 0).toUInt();
0109   const uint minor = version.section(QLatin1Char('.'), 1, 1).toUInt();
0110   if(major == 5 && minor < 16) {
0111     myWarning() << "Printing is broken for KDE Frameworks < 5.16. Please upgrade";
0112     return;
0113   }
0114 
0115   w.setJScriptEnabled(false);
0116   w.setJavaEnabled(false);
0117   w.setMetaRefreshEnabled(false);
0118   w.setPluginsEnabled(false);
0119   w.begin(Data::Document::self()->URL());
0120   w.write(m_html);
0121   w.end();
0122   w.view()->print();
0123 #else
0124   QScopedPointer<QWebEngineView> view(new QWebEngineView);
0125   WebPagePrintable* page = new WebPagePrintable(view.data());
0126   view->setPage(page);
0127   view->setHtml(m_html, Data::Document::self()->URL());
0128 
0129   // don't have busy cursor when showing the print dialog
0130   cs.restore();
0131 
0132   auto info = QPrinterInfo::defaultPrinter();
0133   QScopedPointer<QPrinter> printer;
0134   if(info.isNull()) {
0135     printer.reset(new QPrinter);
0136   } else {
0137     printer.reset(new QPrinter(info));
0138   }
0139   printer->setResolution(300);
0140   QPointer<QPrintDialog> dialog = new QPrintDialog(printer.data(), view.data());
0141   if(dialog->exec() != QDialog::Accepted) {
0142     return;
0143   }
0144   page->printDocument(printer.data());
0145 #endif
0146 }
0147 
0148 void PrintHandler::printPreview() {
0149 // print preview only works with WebEngine
0150 #ifndef USE_KHTML
0151   if(m_inPrintPreview) {
0152     return;
0153   }
0154   GUI::CursorSaver cs(Qt::WaitCursor);
0155 
0156   if(m_html.isEmpty()) {
0157     m_html = generateHtml();
0158     if(m_html.isEmpty()) {
0159       myDebug() << "PrintHandler - empty html output in preview";
0160       return;
0161     }
0162   }
0163 
0164   QScopedPointer<QWebEngineView> view(new QWebEngineView);
0165   WebPagePrintable* page = new WebPagePrintable(view.data());
0166   view->setPage(page);
0167   view->setHtml(m_html, Data::Document::self()->URL());
0168 
0169   // don't have busy cursor when showing the print dialog
0170   cs.restore();
0171 
0172   m_inPrintPreview = true;
0173   auto info = QPrinterInfo::defaultPrinter();
0174   QScopedPointer<QPrinter> printer;
0175   if(info.isNull()) {
0176     printer.reset(new QPrinter);
0177   } else {
0178     printer.reset(new QPrinter(info));
0179   }
0180   printer->setResolution(300);
0181   QPrintPreviewDialog preview(printer.data(), view.data());
0182   connect(&preview, &QPrintPreviewDialog::paintRequested,
0183           page, &WebPagePrintable::printDocument);
0184   {
0185     // this is a workaround for ensuring the initial dailog open shows the preview already
0186     // with Qt 5.15.2, it didn't seem to get previewed initially
0187     QList<QPrintPreviewWidget*> list = preview.findChildren<QPrintPreviewWidget*>();
0188     QPrintPreviewWidget* w = list.first();
0189     if(w) w->updatePreview();
0190   }
0191   preview.exec();
0192   m_inPrintPreview = false;
0193 #endif
0194 }
0195 
0196 QString PrintHandler::generateHtml() const {
0197   Export::HTMLExporter exporter(Data::Document::self()->collection());
0198   // only print visible entries
0199   exporter.setEntries(m_entries);
0200   exporter.setXSLTFile(QStringLiteral("tellico-printing.xsl"));
0201   exporter.setPrintHeaders(Config::printFieldHeaders());
0202   exporter.setPrintGrouped(Config::printGrouped());
0203   exporter.setGroupBy(Controller::self()->expandedGroupBy());
0204   if(!Config::printGrouped()) { // the sort titles are only used if the entries are not grouped
0205     exporter.setSortTitles(Controller::self()->sortTitles());
0206   }
0207   exporter.setColumns(m_columns);
0208   exporter.setMaxImageSize(Config::maxImageWidth(), Config::maxImageHeight());
0209   if(Config::printFormatted()) {
0210     exporter.setOptions(Export::ExportUTF8 | Export::ExportFormatted);
0211   } else {
0212     exporter.setOptions(Export::ExportUTF8);
0213   }
0214 
0215   return exporter.text();
0216 }
0217 
0218 #ifndef USE_KHTML
0219 #include "printhandler.moc"
0220 #endif