File indexing completed on 2024-06-16 04:47:17

0001 /***************************************************************************
0002  * SPDX-FileCopyrightText: 2022 S. MANKOWSKI stephane@mankowski.fr
0003  * SPDX-FileCopyrightText: 2022 G. DE BURE support@mankowski.fr
0004  * SPDX-License-Identifier: GPL-3.0-or-later
0005  ***************************************************************************/
0006 /** @file
0007  * A plugin to print pages
0008  *
0009  * @author Stephane MANKOWSKI
0010  */
0011 #include "skgprintplugin.h"
0012 
0013 #include <kaboutdata.h>
0014 #include <kactioncollection.h>
0015 #include <kpluginfactory.h>
0016 #include <kstandardaction.h>
0017 
0018 #include <qbuffer.h>
0019 #include <qdesktopservices.h>
0020 #include <qdir.h>
0021 #include <qpainter.h>
0022 #include <qpicture.h>
0023 #include <qprintdialog.h>
0024 #include <qprintpreviewdialog.h>
0025 #include <qsavefile.h>
0026 #include <qtextbrowser.h>
0027 
0028 #include "skgmainpanel.h"
0029 #include "skgprint_settings.h"
0030 #include "skgtraces.h"
0031 #include "skgtreeview.h"
0032 
0033 /**
0034  * This plugin factory.
0035  */
0036 K_PLUGIN_CLASS_WITH_JSON(SKGPrintPlugin, "metadata.json")
0037 
0038 SKGPrintPlugin::SKGPrintPlugin(QWidget* iWidget, QObject* iParent, const QVariantList& /*iArg*/) :
0039     SKGInterfacePlugin(iParent), m_currentDocument(nullptr)
0040 {
0041     SKGTRACEINFUNC(10)
0042     Q_UNUSED(iWidget)
0043     m_printer.setResolution(QPrinter::HighResolution);
0044 }
0045 
0046 SKGPrintPlugin::~SKGPrintPlugin()
0047 {
0048     SKGTRACEINFUNC(10)
0049     m_currentDocument = nullptr;
0050 }
0051 
0052 bool SKGPrintPlugin::setupActions(SKGDocument* iDocument)
0053 {
0054     SKGTRACEINFUNC(10)
0055 
0056     m_currentDocument = iDocument;
0057 
0058     setComponentName(QStringLiteral("skg_print"), title());
0059     setXMLFile(QStringLiteral("skg_print.rc"));
0060 
0061     registerGlobalAction(QStringLiteral("file_print"), KStandardAction::print(this, SLOT(onPrint()), actionCollection()), QStringList(), -1);
0062     registerGlobalAction(QStringLiteral("file_print_preview"), KStandardAction::printPreview(this, SLOT(onPrintPreview()), actionCollection()), QStringList(), -1);
0063 
0064     auto actPrintHtmlAction = new QAction(SKGServices::fromTheme(QStringLiteral("preview")), i18nc("Verb, print in an html file",  "Print into a html file"), this);
0065     connect(actPrintHtmlAction, &QAction::triggered, this, &SKGPrintPlugin::onPrintHtml);
0066     registerGlobalAction(QStringLiteral("file_print_html"), actPrintHtmlAction, QStringList(), -1);
0067 
0068     return true;
0069 }
0070 
0071 KConfigSkeleton* SKGPrintPlugin::getPreferenceSkeleton()
0072 {
0073     return skgprint_settings::self();
0074 }
0075 
0076 QString SKGPrintPlugin::title() const
0077 {
0078     return i18nc("Verb, action to use a printer", "print");
0079 }
0080 
0081 int SKGPrintPlugin::getOrder() const
0082 {
0083     return 2;
0084 }
0085 
0086 QStringList SKGPrintPlugin::tips() const
0087 {
0088     QStringList output;
0089     output.push_back(i18nc("Description of a tips", "<p>… you can <a href=\"skg://file_print\">print</a> all opened pages.</p>"));
0090     return output;
0091 }
0092 
0093 void SKGPrintPlugin::onPrint()
0094 {
0095     SKGError err;
0096     SKGTRACEINFUNCRC(10, err)
0097 
0098     if (SKGMainPanel::getMainPanel() != nullptr) {
0099         QPointer<QPrintDialog> dialog = new QPrintDialog(&m_printer, SKGMainPanel::getMainPanel());
0100         dialog->setOption(QAbstractPrintDialog::PrintCurrentPage, true);
0101         dialog->setMinMax(1, SKGMainPanel::getMainPanel()->getTabWidget()->count());
0102         if (dialog->exec() == QDialog::Accepted) {
0103             QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
0104             print(&m_printer);
0105             QApplication::restoreOverrideCursor();
0106         }
0107     }
0108 }
0109 
0110 void SKGPrintPlugin::onPrintPreview()
0111 {
0112     SKGError err;
0113     SKGTRACEINFUNCRC(10, err)
0114     // TODO(SMI): QWebEngine does not work
0115     QPointer<QPrintPreviewDialog> dialog = new QPrintPreviewDialog(SKGMainPanel::getMainPanel());
0116     connect(dialog.data(), &QPrintPreviewDialog::paintRequested, this, &SKGPrintPlugin::print);
0117     dialog->exec();
0118 }
0119 
0120 void SKGPrintPlugin::onPrintHtml()
0121 {
0122     QString html;
0123     getHtml(&m_printer, html);
0124 
0125     QString fileName = QDir::tempPath() % "/skrooge.html";
0126     QSaveFile file(fileName);
0127     if (file.open(QIODevice::WriteOnly)) {
0128         QTextStream out(&file);
0129         out << html;
0130 
0131         // Close file
0132         file.commit();
0133     }
0134     QDesktopServices::openUrl(QUrl::fromLocalFile(fileName));
0135 }
0136 
0137 SKGError SKGPrintPlugin::getHtml(QPrinter* iPrinter, QString& oHtml) const
0138 {
0139     SKGError err;
0140     _SKGTRACEINFUNCRC(10, err)
0141     if ((SKGMainPanel::getMainPanel() != nullptr) && (iPrinter != nullptr)) {
0142         QString html;
0143 
0144         // Get printer options
0145         int docCopies;
0146         int pageCopies;
0147         if (iPrinter->collateCopies()) {
0148             docCopies = 1;
0149             pageCopies = iPrinter->copyCount();
0150         } else {
0151             docCopies = iPrinter->copyCount();
0152             pageCopies = 1;
0153         }
0154         int fromPage = qMin(iPrinter->fromPage(), iPrinter->toPage());
0155         int toPage = qMax(iPrinter->fromPage(), iPrinter->toPage());
0156 
0157         // Compute the number of pages
0158         SKGTabWidget* tabs = SKGMainPanel::getMainPanel()->getTabWidget();
0159         int nbpages = tabs->count();
0160 
0161         if (fromPage == 0 && toPage == 0) {
0162             fromPage = 1;
0163             toPage = nbpages;
0164         }
0165         if (iPrinter->printRange() == QPrinter::CurrentPage) {
0166             fromPage = SKGMainPanel::getMainPanel()->currentPageIndex() + 1;
0167             toPage = fromPage;
0168         }
0169 
0170         SKGTRACEL(10) << "Nb copy document=" << docCopies << SKGENDL;
0171         SKGTRACEL(10) << "Nb copy page=" << docCopies << SKGENDL;
0172         SKGTRACEL(10) << "From=" << fromPage << SKGENDL;
0173         SKGTRACEL(10) << "To=" << toPage << SKGENDL;
0174 
0175         // Copy document
0176         for (int c = 1; !err && c <= docCopies; ++c) {
0177             for (int i = 1; !err && i <= nbpages; ++i) {
0178                 // Compute page
0179                 int pageToTreat = (iPrinter->pageOrder() == QPrinter::LastPageFirst ? nbpages + 1 - i : i);
0180 
0181                 // Do we have to print it
0182                 if (pageToTreat >= fromPage && pageToTreat <= toPage) {
0183                     // Yes, get the widget
0184                     // Copy pages
0185                     for (int p = 1; !err && p <= pageCopies; ++p) {
0186                         auto* page = qobject_cast<SKGTabPage*>(tabs->widget(pageToTreat - 1));
0187                         if (page != nullptr) {
0188                             // Add page break if needed
0189                             if (!html.isEmpty()) {
0190                                 html = html % "<div style=\"page-break-after:always\"></div>";
0191                             }
0192 
0193                             // Add widgets
0194                             QList<QWidget*> widgets = page->printableWidgets();
0195                             int nbw = widgets.count();
0196                             for (int j = 0; !err && j < nbw; ++j) {
0197                                 QWidget* w = widgets.at(j);
0198                                 if (w != nullptr) {
0199                                     // Add widget
0200                                     /*SKGTreeView* tw = qobject_cast< SKGTreeView* >(w);
0201                                     if (tw) {
0202                                         QTextBrowser* tb = tw->getTextBrowser();
0203                                         if (tb) {
0204                                             html = html % tb->toHtml();
0205                                             delete tb;
0206                                         }
0207                                     } else {*/
0208 #ifdef SKG_WEBENGINE
0209                                     auto q = qobject_cast< QWebEngineView* >(w);
0210 #endif
0211 #ifdef SKG_WEBKIT
0212                                     auto q = qobject_cast< QWebView* >(w);
0213 #endif
0214 #if !defined(SKG_WEBENGINE) && !defined(SKG_WEBKIT)
0215                                     auto q = qobject_cast< QTextBrowser* >(w);
0216 #endif
0217                                     if (q != nullptr) {
0218 #ifdef SKG_WEBENGINE
0219                                         q->page()->toHtml([&](const QString & result) {
0220                                             html = html % result;
0221                                         });
0222                                         qApp->processEvents(QEventLoop::AllEvents, 5000);
0223 #endif
0224 #ifdef SKG_WEBKIT
0225                                         html = html % q->page()->currentFrame()->toHtml();
0226 #endif
0227 #if !defined(SKG_WEBENGINE) && !defined(SKG_WEBKIT)
0228                                         html = html % q->toHtml();
0229 #endif
0230                                     } else {
0231                                         // Save palette
0232                                         QPalette previousPalette = w->palette();
0233 
0234                                         // Draw in a picture with white background
0235                                         QPalette palette;
0236                                         palette.setColor(QPalette::Background, Qt::white);
0237                                         w->setPalette(palette);
0238                                         QImage image = w->grab().toImage();
0239 
0240                                         // Restore palette
0241                                         w->setPalette(previousPalette);
0242 
0243                                         QByteArray byteArray;
0244                                         QBuffer buffer(&byteArray);
0245                                         image.save(&buffer, "PNG");
0246 
0247                                         QString imgBase64 = QString::fromLatin1(byteArray.toBase64().data());
0248                                         html = html % "<img src=\"data:image/png;base64," % imgBase64 % "\" />";
0249                                     }
0250                                     // }
0251                                 }
0252                             }
0253                         }
0254                     }
0255                 }
0256             }
0257         }
0258 
0259         oHtml = "<body style=\"background-color:white;\">" + html + "</body>";
0260     }
0261     return err;
0262 }
0263 
0264 void SKGPrintPlugin::print(QPrinter* iPrinter)
0265 {
0266     SKGTRACEINFUNC(10)
0267     if ((SKGMainPanel::getMainPanel() != nullptr) && (iPrinter != nullptr)) {
0268         QString html;
0269         SKGError err = getHtml(iPrinter, html);
0270 
0271         // Print
0272         m_toPrint.setFixedSize(QSize(iPrinter->width(), iPrinter->height()));
0273 #ifdef SKG_WEBENGINE
0274         // TODO(SMI): QWebEngine - doesn't work - bad quality printing
0275         disconnect(&m_toPrint);
0276         connect(&m_toPrint, &QWebEngineView::loadFinished, &m_toPrint, [ = ]() {
0277             m_toPrint.page()->print(iPrinter, [](bool) {});
0278         });
0279         m_toPrint.setHtml(html, QUrl("file://"));
0280 #endif
0281 #ifdef SKG_WEBKIT
0282         m_toPrint.setHtml(html);
0283         m_toPrint.print(iPrinter);
0284 #endif
0285 #if !defined(SKG_WEBENGINE) && !defined(SKG_WEBKIT)
0286         m_toPrint.setHtml(html);
0287         m_toPrint.print(iPrinter);
0288 #endif
0289 
0290         // status bar
0291         IFOKDO(err, SKGError(0, i18nc("Successful message after an user action", "Print successfully done.")))
0292         else {
0293             err.addError(ERR_FAIL, i18nc("Error message", "Print failed"));
0294         }
0295 
0296         // Display error
0297         SKGMainPanel::displayErrorMessage(err);
0298     }
0299 }
0300 
0301 #include <skgprintplugin.moc>