10#include "printpainter.h"
12#include "katebuffer.h"
13#include "katedocument.h"
14#include "katehighlight.h"
15#include "katepartdebug.h"
16#include "katerenderer.h"
17#include "katetextfolding.h"
18#include "katetextlayout.h"
21#include <KLocalizedString>
27using namespace KatePrinter;
29class KatePrinter::PageLayout
47 bool selectionOnly =
false;
53 uint headerHeight = 0;
55 uint footerHeight = 0;
65 , m_printLineNumbers(false)
68 , m_useBackground(false)
70 , m_useHeaderBackground(false)
71 , m_useFooterBackground(false)
84 m_renderer->setPrinterFriendly(
true);
89PrintPainter::~PrintPainter()
94void PrintPainter::setTextFont(
const QFont &font)
96 m_renderer->config()->setFont(font);
99void PrintPainter::setUseBox(
const bool on)
102 setBoxWidth(m_boxWidth);
105void PrintPainter::setBoxWidth(
const int width)
117void PrintPainter::setBoxColor(
const QColor &color)
124void PrintPainter::setHeaderBackground(
const QColor &color)
127 m_headerBackground = color;
131void PrintPainter::setHeaderForeground(
const QColor &color)
134 m_headerForeground = color;
138void PrintPainter::setFooterBackground(
const QColor &color)
141 m_footerBackground = color;
144void PrintPainter::setFooterForeground(
const QColor &color)
147 m_footerForeground = color;
151void PrintPainter::setColorScheme(
const QString &scheme)
154 m_renderer->config()->setSchema(scheme);
160void PrintPainter::updateCache()
162 m_fontHeight = m_renderer->fontHeight();
171void PrintPainter::paint(
QPrinter *printer)
const
176 configure(printer, pl);
178 uint lineCount = pl.firstline;
181 bool pageStarted =
true;
184 auto &f = m_renderer->
folding();
187 while (lineCount <= pl.lastline) {
188 if (y + m_fontHeight > pl.maxHeight) {
189 if ((
int)currentPage == printer->
toPage()) {
193 painter.resetTransform();
200 qCDebug(LOG_KTE) <<
"Starting new page," << lineCount <<
"lines up to now.";
201 paintNewPage(painter, currentPage, y, pl);
203 painter.translate(pl.xstart, y);
206 const bool skipLine = m_dontPrintFoldedCode && !f.isLineVisible(lineCount);
208 if (!skipLine && m_printLineNumbers ) {
209 paintLineNumber(painter, lineCount, pl);
213 paintLine(painter, lineCount, y, remainder, pl);
226 pl.pageHeight = printer->
height();
227 pl.pageWidth = printer->
width();
228 pl.headerWidth = printer->
width();
229 pl.innerMargin = m_useBox ? m_boxMargin : 6;
230 pl.maxWidth = printer->
width();
231 pl.maxHeight = (m_useBox ? printer->
height() - pl.innerMargin : printer->
height());
235 if (m_view && pl.selectionOnly) {
237 pl.selectionRange = m_view->selectionRange();
238 pl.firstline = pl.selectionRange.start().line();
239 pl.lastline = pl.selectionRange.end().line();
242 if (m_printLineNumbers) {
246 pl.maxWidth -= m_lineNumberWidth + _adj;
247 pl.xstart += m_lineNumberWidth + _adj;
250 if (m_useHeader || m_useFooter) {
256 std::map<QString, QString> tags;
259 tags[QStringLiteral(
"u")] = u.loginName();
266 tags[QStringLiteral(
"f")] = m_doc->
url().
fileName();
267 tags[QStringLiteral(
"U")] = m_doc->
url().
toString();
268 if (pl.selectionOnly) {
270 tags[QStringLiteral(
"f")].prepend(s);
271 tags[QStringLiteral(
"U")].prepend(s);
278 if (m_useBox || m_useHeaderBackground) {
279 pl.headerHeight += pl.innerMargin * 2;
284 pl.headerTagList = m_headerFormat;
285 QMutableStringListIterator it(pl.headerTagList);
286 while (it.hasNext()) {
289 int pos = tag.
indexOf(reTags, 0, &match);
292 rep = tags[
match.captured(1)];
293 tag.
replace((uint)pos, 2, rep);
295 pos = tag.
indexOf(reTags, pos, &match);
303 if (m_useBox || m_useFooterBackground) {
304 pl.footerHeight += 2 * pl.innerMargin;
306 pl.footerHeight += 1;
309 pl.footerTagList = m_footerFormat;
310 QMutableStringListIterator it(pl.footerTagList);
311 while (it.hasNext()) {
314 int pos = tag.
indexOf(reTags, 0, &match);
317 rep = tags[
match.captured(1)];
318 tag.
replace((uint)pos, 2, rep);
320 pos = tag.
indexOf(reTags, pos, &match);
325 pl.maxHeight -= pl.footerHeight;
329 if (m_useBackground) {
331 pl.xstart += pl.innerMargin;
332 pl.maxWidth -= pl.innerMargin * 2;
338 pl.maxWidth -= (m_boxWidth + pl.innerMargin) * 2;
339 pl.xstart += m_boxWidth + pl.innerMargin;
341 pl.maxHeight -= m_boxWidth;
344 int pageHeight = pl.maxHeight;
346 pageHeight -= pl.headerHeight + pl.innerMargin;
349 pageHeight -= pl.footerHeight + pl.innerMargin;
352 const int linesPerPage = pageHeight / m_fontHeight;
355 pl.firstline = (printer->
fromPage() - 1) * linesPerPage;
361 if (!pl.headerTagList.filter(QStringLiteral(
"%P")).isEmpty() || !pl.footerTagList.filter(QStringLiteral(
"%P")).isEmpty()) {
362 qCDebug(LOG_KTE) <<
"'%P' found! calculating number of pages...";
367 for (
unsigned int i = pl.firstline; i <= pl.lastline; ++i) {
368 KateLineLayout rangeptr(*m_renderer);
370 m_renderer->
layoutLine(&rangeptr, (
int)pl.maxWidth,
false);
371 totalLines += rangeptr.viewLineCount();
374 const int totalPages = (totalLines / linesPerPage) + ((totalLines % linesPerPage) > 0 ? 1 : 0);
381 QString re(QStringLiteral(
"%P"));
384 for (it = pl.headerTagList.begin(); it != pl.headerTagList.end(); ++it) {
388 for (it = pl.footerTagList.begin(); it != pl.footerTagList.end(); ++it) {
394void PrintPainter::paintNewPage(
QPainter &painter,
const uint currentPage, uint &y,
const PageLayout &pl)
const
397 paintHeader(painter, currentPage, y, pl);
401 paintFooter(painter, currentPage, pl);
404 if (m_useBackground) {
405 paintBackground(painter, y, pl);
409 paintBox(painter, y, pl);
412 if (m_printGuide && currentPage == 1) {
413 paintGuide(painter, y, pl);
417void PrintPainter::paintHeader(
QPainter &painter,
const uint currentPage, uint &y,
const PageLayout &pl)
const
420 painter.
setPen(
QPen(m_headerForeground, 0.5));
423 if (m_useHeaderBackground) {
424 painter.
fillRect(0, 0, pl.headerWidth, pl.headerHeight, m_headerBackground);
427 if (pl.headerTagList.count() == 3) {
430 int marg = (m_useBox || m_useHeaderBackground) ? pl.innerMargin : 0;
436 for (
int i = 0; i < 3; i++) {
437 s = pl.headerTagList[i];
442 painter.
drawText(marg, 0, pl.headerWidth - (marg * 2), pl.headerHeight, align, s);
447 if (!(m_useHeaderBackground || m_useBox || m_useBackground)) {
448 painter.
drawLine(0, pl.headerHeight - 1, pl.headerWidth, pl.headerHeight - 1);
454 y += pl.headerHeight + pl.innerMargin;
457void PrintPainter::paintFooter(
QPainter &painter,
const uint currentPage,
const PageLayout &pl)
const
460 painter.
setPen(
QPen(m_footerForeground, 0.5));
463 if (!(m_useFooterBackground || m_useBox || m_useBackground)) {
464 painter.
drawLine(0, pl.pageHeight - pl.footerHeight - 1, pl.headerWidth, pl.pageHeight - pl.footerHeight - 1);
466 if (m_useFooterBackground) {
467 painter.
fillRect(0, pl.pageHeight - pl.footerHeight, pl.headerWidth, pl.footerHeight, m_footerBackground);
470 if (pl.footerTagList.count() == 3) {
472 int marg = (m_useBox || m_useFooterBackground) ? pl.innerMargin : 0;
478 for (
int i = 0; i < 3; i++) {
479 s = pl.footerTagList[i];
483 painter.
drawText(marg, pl.pageHeight - pl.footerHeight, pl.headerWidth - (marg * 2), pl.footerHeight, align, s);
495 QString _hlName = m_doc->highlight()->name();
498 const auto _attributes = m_doc->highlight()->attributesForDefinition(m_renderer->config()->schema());
499 const QColor _defaultPen = _attributes.at(0)->foreground().color();
502 painter.
setPen(_defaultPen);
506 _marg += (2 * m_boxWidth) + (2 * pl.innerMargin);
508 if (m_useBackground) {
509 _marg += 2 * pl.innerMargin;
512 y += 1 + pl.innerMargin;
520 painter.
drawText(
QRect(_marg, y, pl.pageWidth - (2 * _marg), pl.maxHeight - y),
522 i18n(
"Typographical Conventions for %1", _hlName),
524 const int _w = pl.pageWidth - (_marg * 2) - (pl.innerMargin * 2);
525 const int _x = _marg + pl.innerMargin;
526 y += _r.
height() + pl.innerMargin;
527 painter.
drawLine(_x, y, _x + _w, y);
528 y += 1 + pl.innerMargin;
536 const int _guideCols = _w / (_widest + pl.innerMargin);
539 const int _cw = _w / _guideCols;
547 if (_hl != _hlName && _hl != _currentHlName) {
548 _currentHlName = _hl;
549 if (_i % _guideCols) {
554 painter.
setPen(_defaultPen);
560 painter.
setPen(attribute->foreground().color());
561 painter.
setFont(attribute->font());
565 _rect.
moveTo(_x + ((_i % _guideCols) * _cw), y);
566 painter.
fillRect(_rect, attribute->background());
572 if (_i && !(_i % _guideCols)) {
577 if (_i % _guideCols) {
581 painter.
setPen(_defaultPen);
584 painter.
fillRect(0, y + pl.innerMargin, pl.headerWidth, m_boxWidth, m_boxColor);
587 painter.
drawRect(_marg, _ystart, pl.pageWidth - (2 * _marg), y - _ystart + pl.innerMargin);
592 y += (m_useBox ? m_boxWidth : 1) + (pl.innerMargin * 2);
599 painter.
drawRect(0, 0, pl.pageWidth, pl.pageHeight);
602 painter.
drawLine(0, pl.headerHeight, pl.headerWidth, pl.headerHeight);
608 painter.
fillRect(0, pl.maxHeight + pl.innerMargin, pl.headerWidth, m_boxWidth, m_boxColor);
614void PrintPainter::paintBackground(
QPainter &painter,
const uint y,
const PageLayout &pl)
const
619 int _h = pl.maxHeight - y;
621 _y -= pl.innerMargin;
622 _h += 2 * pl.innerMargin;
624 if (m_useHeaderBackground) {
625 _y -= pl.innerMargin;
626 _h += pl.innerMargin;
628 if (m_useFooterBackground) {
629 _h += pl.innerMargin;
632 painter.
fillRect(0, _y, pl.pageWidth, _h, m_renderer->config()->backgroundColor());
635void PrintPainter::paintLine(
QPainter &painter,
const uint line, uint &y, uint &remainder,
const PageLayout &pl)
const
638 KateLineLayout rangeptr(*m_renderer);
639 rangeptr.setLine(line);
640 m_renderer->
layoutLine(&rangeptr, (
int)pl.maxWidth,
false);
644 if (pl.selectionOnly) {
645 if (m_view && m_view->blockSelection()) {
646 int _x = m_renderer->
cursorToX(rangeptr.viewLine(0), pl.selectionRange.start());
647 int _x1 = m_renderer->
cursorToX(rangeptr.viewLine(rangeptr.viewLineCount() - 1), pl.selectionRange.end());
652 }
else if (line == pl.firstline || line == pl.lastline) {
653 QRegion region(0, 0, pl.maxWidth, rangeptr.viewLineCount() * m_fontHeight);
655 if (line == pl.firstline) {
656 int l = rangeptr.viewLineForColumn(pl.selectionRange.start().column());
658 for (
int vl = 0; vl < l; ++vl) {
659 region = region.subtracted(
QRegion(0, vl * m_fontHeight, pl.maxWidth, m_fontHeight));
661 region = region.subtracted(
QRegion(0, 0, m_renderer->
cursorToX(rangeptr.viewLine(l), pl.selectionRange.start()), m_fontHeight));
664 if (line == pl.lastline) {
665 int vl = rangeptr.viewLineForColumn(pl.selectionRange.end().column());
666 int x = m_renderer->
cursorToX(rangeptr.viewLine(vl), pl.selectionRange.end());
668 region = region.subtracted(
QRegion(x, (vl)*m_fontHeight, pl.maxWidth - x, m_fontHeight));
671 for (; vl < rangeptr.viewLineCount(); ++vl) {
672 region = region.subtracted(
QRegion(0, vl * m_fontHeight, pl.maxWidth, m_fontHeight));
682 int _lines = rangeptr.viewLineCount();
684 int proceedLines = _lines;
686 proceedLines = qMin((pl.maxHeight - y) / m_fontHeight, remainder);
688 painter.
translate(0, -(_lines -
int(remainder)) * m_fontHeight + 1);
690 (_lines -
int(remainder)) * m_fontHeight + 1,
692 proceedLines * m_fontHeight);
693 remainder -= proceedLines;
694 }
else if (y + m_fontHeight * _lines > pl.maxHeight) {
695 remainder = _lines - ((pl.maxHeight - y) / m_fontHeight);
696 painter.
setClipRect(0, 0, pl.maxWidth, (_lines -
int(remainder)) * m_fontHeight + 1);
697 }
else if (!pl.selectionOnly) {
703 if (!m_dontPrintFoldedCode) {
707 m_renderer->
paintTextLine(painter, &rangeptr, 0, (
int)pl.maxWidth,
QRectF{},
nullptr, flags);
710 painter.
translate(_xadjust, (m_fontHeight * (_lines - remainder)));
712 y += m_fontHeight * proceedLines;
715void PrintPainter::paintLineNumber(
QPainter &painter,
const uint number,
const PageLayout &pl)
const
717 const int left = ((m_useBox || m_useBackground) ? pl.innerMargin : 0) - pl.xstart;
721 painter.
setPen(m_renderer->config()->lineNumberColor());
Backend of KTextEditor::Document related public KTextEditor interfaces.
int lastLine() const
gets the last line number (lines() - 1)
int lines() const override
Get the count of lines of the document.
An object representing a section of text, from one Cursor to another.
Handles all of the work of rendering the text (used for the views and printing)
Kate::TextFolding & folding() const
Returns the folding info to which this renderer is bound.
const QFont & currentFont() const
Access currently used font.
int cursorToX(const KateTextLayout &range, int col, bool returnPastLine=false) const
Returns the x position of cursor col on the line range.
@ SkipDrawFirstInvisibleLineUnderlined
Skip drawing the dashed underline at the start of a folded block of text?
const QFontMetricsF & currentFontMetrics() const
Access currently used font metrics.
void layoutLine(KateLineLayout *line, int maxwidth=-1, bool cacheLayout=false) const
Text width & height calculation functions...
void paintTextLine(QPainter &paint, KateLineLayout *range, int xStart, int xEnd, const QRectF &textClipRect=QRectF(), const KTextEditor::Cursor *cursor=nullptr, PaintTextLineFlags flags=PaintTextLineFlags())
This is the ultimate function to perform painting of a text line.
QString i18n(const char *text, const TYPE &arg...)
KCOREADDONS_EXPORT Result match(QStringView pattern, QStringView str)
bool isValid() const const
QDateTime currentDateTime()
QFlags< T > & setFlag(Enum flag, bool on)
void setBold(bool enable)
void setUnderline(bool enable)
QRect boundingRect(QChar ch) const const
int leading() const const
QRectF boundingRect(QChar ch) const const
qreal horizontalAdvance(QChar ch) const const
QString toString(QDate date, FormatType format) const const
void drawLine(const QLine &line)
void drawRect(const QRect &rectangle)
void drawText(const QPoint &position, const QString &text)
void fillRect(const QRect &rectangle, QGradient::Preset preset)
void setClipRect(const QRect &rectangle, Qt::ClipOperation operation)
void setClipRegion(const QRegion ®ion, Qt::ClipOperation operation)
void setClipping(bool enable)
void setFont(const QFont &font)
void setPen(Qt::PenStyle style)
void translate(const QPoint &offset)
int fromPage() const const
virtual bool newPage() override
PrintRange printRange() const const
void moveTo(const QPoint &position)
qreal width() const const
QString arg(Args &&... args) const const
QString & fill(QChar ch, qsizetype size)
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
qsizetype length() const const
QString number(double n, char format, int precision)
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
QString section(QChar sep, qsizetype start, qsizetype end, SectionFlags flags) const const
QTextStream & left(QTextStream &stream)
QString fileName(ComponentFormattingOptions options) const const
QString toString(FormattingOptions options) const const