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>