1 /*
2     This file is part of the Okteta Kasten module, made within the KDE community.
3 
4     SPDX-FileCopyrightText: 2007-2008 Friedrich W. H. Kossebau <kossebau@kde.org>
5 
6     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
7 */
8 
9 #include "printtool.hpp"
10 
11 // controller
12 #include "printjob.hpp"
13 #include "printdialog.hpp"
14 #include "framestopaperprinter.hpp"
15 #include "headerfooterframerenderer.hpp"
16 #include "bytearrayframerenderer.hpp"
17 // Okteta Kasten gui
18 #include <Kasten/Okteta/ByteArrayView>
19 // Okteta Kasten core
20 #include <Kasten/Okteta/ByteArrayDocument>
21 // Okteta core
22 #include <Okteta/AbstractByteArrayModel>
23 // Kasten core
24 #include <Kasten/AbstractModelSynchronizer>
25 // KF
26 #include <KLocalizedString>
27 #include <KMessageBox>
28 // Qt
29 #include <QApplication>
30 #include <QPrinter>
31 #include <QPageLayout>
32 #include <QFont>
33 #include <QFontMetrics>
34 
35 namespace Kasten {
36 
37 PrintTool::PrintTool() = default;
38 
39 PrintTool::~PrintTool() = default;
40 
setTargetModel(AbstractModel * model)41 void PrintTool::setTargetModel(AbstractModel* model)
42 {
43 //     if( mByteArrayView ) mByteArrayView->disconnect( this );
44 
45     mByteArrayView = model ? model->findBaseModel<ByteArrayView*>() : nullptr;
46 
47     mDocument = mByteArrayView ? qobject_cast<ByteArrayDocument*>(mByteArrayView->baseModel()) : nullptr;
48     mByteArrayModel = mDocument ? mDocument->content() : nullptr;
49 
50     const bool hasView = (mByteArrayView && mByteArrayModel);
51     emit viewChanged(hasView);
52 }
53 
print()54 void PrintTool::print()
55 {
56     auto* printer = new QPrinter;
57 
58 //     LayoutDialogPage* layoutPage = new LayoutDialogPage();
59 //     QList<QWidget*> customDialogPages;
60 //     customDialogPages << layoutPage;
61     auto* printDialog = new PrintDialog(printer, QApplication::activeWindow());
62     // Disable PrintPageRange, this tells Qt we can't do client-side page selection,
63     // so it will try do server-side page selection if supported
64     printDialog->setOption(QPrintDialog::PrintPageRange, false);
65 //    printDialog->setOptionTabs(customDialogPages);
66 
67     printDialog->setWindowTitle(i18nc("@title:window", "Print Byte Array %1", mDocument->title()));
68     connect(printDialog, QOverload<QPrinter*>::of(&QPrintDialog::accepted), this, &PrintTool::triggerPrint);
69     printDialog->open();
70 }
71 
triggerPrint(QPrinter * printer)72 void PrintTool::triggerPrint(QPrinter* printer)
73 {
74     const QString creator = QStringLiteral("Print Plugin for Okteta " OKTETA_VERSION);   // no i18n(), keep space at end as separator
75     printer->setCreator(creator);
76 
77     FramesToPaperPrinter framesPrinter;
78 #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
79     const QPageLayout pageLayout = printer->pageLayout();
80     const int printerResolution = printer->resolution();
81     framesPrinter.setPaperRect(pageLayout.fullRectPixels(printerResolution));
82     framesPrinter.setPageRect(pageLayout.paintRectPixels(printerResolution));
83 #else
84     framesPrinter.setPaperRect(printer->paperRect());
85     framesPrinter.setPageRect(printer->pageRect());
86 #endif
87     printer->setFullPage(true);
88 
89     PrintInfo info;
90     const QRect pageRect = framesPrinter.pageRect();
91     const int left = pageRect.left();
92     const int width = pageRect.width();
93 
94     auto* headerFrameRenderer = new HeaderFooterFrameRenderer(&info);
95     headerFrameRenderer->setTexts(QStringLiteral("%d"),
96                                     QStringLiteral("%f"),
97                                     i18nc("in the header of the printed page, e.g. Page 2 of 20", "Page %p of %P"));
98     headerFrameRenderer->setWidth(width);
99     headerFrameRenderer->setPos(pageRect.topLeft());
100 
101     auto* footerFrameRenderer = new HeaderFooterFrameRenderer(&info);
102     footerFrameRenderer->setTexts(i18nc("in the footer of the printed page, e.g. Printed by: Joe User",
103                                         "Printed by: %U"),
104                                     QString(),
105                                     QStringLiteral("%F"));
106     footerFrameRenderer->setWidth(width);
107     const int footerTop = pageRect.bottom() - footerFrameRenderer->height();
108     footerFrameRenderer->setPos(left, footerTop);
109 
110     const int contentHeight = pageRect.height() - footerFrameRenderer->height() - headerFrameRenderer->height();
111     const int contentTop = pageRect.top() + headerFrameRenderer->height();
112     auto* byteArrayFrameRenderer = new ByteArrayFrameRenderer;
113     byteArrayFrameRenderer->setPos(left, contentTop);
114     byteArrayFrameRenderer->setWidth(width);
115     byteArrayFrameRenderer->setHeight(contentHeight);
116 
117     Okteta::AddressRange range = mByteArrayView->selection();
118     if (!range.isValid()) {
119         range.setByWidth(0, mByteArrayModel->size());
120     }
121     byteArrayFrameRenderer->setByteArrayModel(mByteArrayModel, range.start(), range.width());
122 
123     // TODO: use noOfBytesPerLine of view, scale resolution down if it does not fit the page
124     const int noOfBytesPerLine = mByteArrayView->noOfBytesPerLine();
125 //         byteArrayFrameRenderer->setNoOfBytesPerLine( mByteArrayView->noOfBytesPerLine() );
126 
127     const Okteta::Address startOffset = mByteArrayView->startOffset() + range.start();
128     const int line = startOffset / noOfBytesPerLine;
129     const Okteta::Address firstLineOffset = mByteArrayView->firstLineOffset() + line * noOfBytesPerLine;
130     byteArrayFrameRenderer->setFirstLineOffset(firstLineOffset);
131     byteArrayFrameRenderer->setStartOffset(startOffset);
132 
133     byteArrayFrameRenderer->setCharCoding(mByteArrayView->charCodingName());
134     byteArrayFrameRenderer->setBufferSpacing(mByteArrayView->byteSpacingWidth(),
135                                                 mByteArrayView->noOfGroupedBytes(),
136                                                 mByteArrayView->groupSpacingWidth());
137     byteArrayFrameRenderer->setBinaryGapWidth(mByteArrayView->binaryGapWidth());
138 
139     byteArrayFrameRenderer->setValueCoding((Okteta::ValueCoding)mByteArrayView->valueCoding());
140     byteArrayFrameRenderer->setShowsNonprinting(mByteArrayView->showsNonprinting());
141     byteArrayFrameRenderer->setSubstituteChar(mByteArrayView->substituteChar());
142     byteArrayFrameRenderer->setUndefinedChar(mByteArrayView->undefinedChar());
143     byteArrayFrameRenderer->showByteArrayColumns(mByteArrayView->visibleByteArrayCodings());
144 
145 //     if( !confirmPrintPageNumber( byteArrayFrameRenderer->framesCount()) )
146 //         return;
147 
148     framesPrinter.addFrameRenderer(headerFrameRenderer);
149     framesPrinter.addFrameRenderer(byteArrayFrameRenderer);
150     framesPrinter.addFrameRenderer(footerFrameRenderer);
151 
152     info.setNoOfPages(byteArrayFrameRenderer->framesCount());
153     AbstractModelSynchronizer* synchronizer = mDocument->synchronizer();
154     if (synchronizer) {
155         info.setUrl(synchronizer->url());
156     }
157 
158     QApplication::setOverrideCursor(Qt::WaitCursor);
159 
160     auto* printJob = new PrintJob(&framesPrinter, 0, byteArrayFrameRenderer->framesCount() - 1, printer);
161     const bool success = printJob->exec();
162 
163     delete printer;
164 
165     QApplication::restoreOverrideCursor();
166 
167     if (!success) {
168         const QString message = i18nc("@info", "Could not print.");
169 
170         KMessageBox::sorry(QApplication::activeWindow(), message, i18nc("@title:window", "Print Byte Array %1", mDocument->title()));
171     }
172 }
173 
174 }
175