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