Files
qt5-legatus-legacy/Lts/Common/LtsPrinting/printing_base.cpp
2026-08-13 18:33:10 +02:00

1363 lines
40 KiB
C++
Executable File

/**
* @RDE_HEADER@
* Small QPrinter abstraction class
* $Id$
* $HeadURL$
* $Author$
*/
//----------------------------------------------------------------------------
// have a look at the source TextPrinter 0.3 :
// http://qt-apps.org/content/show.php/Base?content=62383
#include "printing_base.h"
#include <ngltools/ngltools_filesystem.h>
#include <QDateTime>
#include <QFile>
#include <QUrl>
#include <QPair>
#include <QPrinter>
#include <QPrintDialog>
#include <QPrinterInfo>
#include <QPainter>
#include <QListView>
#include <QTextFrame>
#include <QTextFrameFormat>
#include <QTextDocument>
#include <QAbstractTextDocumentLayout>
#include <QTextBlock>
#include <QTableView>
#include <QTreeView>
#include <QTemporaryFile>
#include <nglsettings/nglsettings_settings.h>
#include <ngltools/ngltools_dtg.h>
#include <NGLLogger/NGLLoggerBootstrap.h>
#include <KDReports/KDReports.h>
//#include <QDebug>
namespace LtsPrinting
{
static inline double mmToInches(double mm) { return mm * 0.039370147; }
static inline double inchesToMM(double inches) { return inches * 25.4; }
bool LtsPrinting::Base::m_printToFile = false;
static int TitleDataHeight = 50; // cab hack
static int DescriptionDataHeight = 50;
static void spanSizes(const QAbstractItemView *view,
const QModelIndex &ms,
int &rowSpanSize,
int &columnSpanSize,
QVector<QPair<int, int> > &spannedL);
//----------------------------------------------------------------------------
Base::Base(QTextDocument &doc,
QWidget *dialogParent,
const QString &dialogTitle,
const QString &_fn,
QPrinter::PaperSize _ps,
QPrinter::Orientation _or,
QPrinter::ColorMode _cm)
: m_printer(new QPrinter),
m_painter(new QPainter),
m_iconFilenameNr(0),
m_tempdoc(nullptr),
leftmargin_(15.0), rightmargin_(15.0), topmargin_(15.0),
bottommargin_(15.0), spacing_(5.0),
headersize_(10), headerrule_(0.5), headertext_(HeaderText),
footersize_(10), footerrule_(0.5), footertext_(FooterText),
itemFontSize_(2),
m_settings(new NGL::Settings(NGL::findProjectConfigFile())),
m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("NGLPrinting")),
m_currentPage(1)
{
QString fn = _fn;
fn = fn.remove(QLatin1Char(' '));
fn = fn.remove(QLatin1String(".."));
fn = fn.remove(QLatin1Char('/')); // und welche Zeichen noch?
fn = m_settings->printPath() + fn;
if (!fn.endsWith(QLatin1String(".pdf"), Qt::CaseInsensitive))
fn += QLatin1String(".pdf");
#ifndef WIN32
m_printer->setOutputFileName(fn);
#endif
m_printer->setOutputFormat(QPrinter::NativeFormat);
/*
const QList<QPrinterInfo> availablePrinters = QPrinterInfo::availablePrinters();
QString printerTemplate = NGL::TempSettings::printerNameTemplate();
if (printerTemplate.isEmpty())
{
// A3, A4: preselect a phys. printer (heuristic):
Q_FOREACH (const QPrinterInfo &pinfo, availablePrinters)
{
bool A3Found = false;
bool A4Found = false;
DEBUG_LOG(m_logger) << "printer: "
<< qPrintable(pinfo.printerName()) ;
Q_FOREACH (const QPageSize &pageSize, pinfo.supportedPageSizes())
{
QPageSize::PageSizeId ps = pageSize.id();
const QPageSize::PageSizeId ps_A3 = QPageSize::A3;
const QPageSize::PageSizeId ps_A4 = QPageSize::A4;
DEBUG_LOG(m_logger) << "printer: " << qPrintable(pinfo.printerName())
<< " papersize = " << ps ;
if (ps == ps_A3)
A3Found = true;
if (ps == ps_A4)
A4Found = true;
}
if ((A3Found && (_ps == QPrinter::A3)) ||
(!A3Found && A4Found && (_ps == QPrinter::A4)))
{
m_printer->setPrinterName(pinfo.printerName());
break;
}
}
}
else
{
const QString papeSize = (_ps == QPrinter::A3) ? QLatin1String("A3") : QLatin1String("A4");
QStringList printerNames;
printerNames += QString(printerTemplate + QLatin1Char('_') + papeSize).toLower();
printerNames += QString(papeSize + QLatin1Char('_') + printerTemplate).toLower();
Q_FOREACH (const QPrinterInfo &pinfo, availablePrinters)
{
DEBUG_LOG(m_logger) << "printer: "
<< qPrintable(pinfo.printerName()) ;
const QString curPrinterLower = pinfo.printerName().toLower();
if (printerNames.contains(curPrinterLower))
{
DEBUG_LOG(m_logger) << "found valid printer " << pinfo.printerName() ;
m_printer->setPrinterName(pinfo.printerName());
break;
}
}
}
*/
m_printer->setPaperSize(_ps);
m_printer->setOrientation(_or);
m_printer->setColorMode(_cm);
m_printer->setFullPage(true);
// QTextDocument :
// default properties for all TextBlocks (and Tree/Table-List blocks) :
QTextOption tOption = doc.defaultTextOption();
tOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
// tOption.setWrapMode(QTextOption::WordWrap);
doc.setDefaultTextOption(tOption);
// other global QTextDocument settings :
// set the doc.setPageSize(..) for multiple pages,
// implies doc.setTextWidth(printerPageSize().width()) :
doc.setPageSize(QSizeF(printerPageSize()));
doc.setDefaultStyleSheet(styleSheet());
//
if (m_printToFile)
return;
QPrintDialog *dialog = new QPrintDialog(m_printer, dialogParent);
// what is allowed ? :
QAbstractPrintDialog::PrintDialogOptions op =
QAbstractPrintDialog::PrintToFile |
QAbstractPrintDialog::PrintSelection |
QAbstractPrintDialog::PrintPageRange |
QAbstractPrintDialog::PrintShowPageSize |
QAbstractPrintDialog::PrintCollateCopies;
dialog->setOptions(op);
QString title = dialogTitle;
if (_ps == QPrinter::A2) title += QLatin1String(" (A2)");
if (_ps == QPrinter::A3) title += QLatin1String(" (A3)");
if (_ps == QPrinter::A4) title += QLatin1String(" (A4)");
if (_ps == QPrinter::A5) title += QLatin1String(" (A5)");
dialog->setWindowTitle(title);
if (dialog->exec() != QDialog::Accepted)
{
// no printing at all, is indicated by :
// qCritical() << "m_printer = NULL";
delete m_printer;
m_printer = nullptr;
return;
}
m_painter->begin(m_printer);
}
//----------------------------------------------------------------------------
Base::~Base()
{
delete m_printer;
delete m_painter;
delete m_tempdoc;
// delete imiplicit defined files :
for (int nr = 0; nr < m_iconFilenameNr; ++nr)
QFile::remove(iconFilename(nr));
delete m_settings;
}
//----------------------------------------------------------------------------
void Base::setPrintToFile(bool printToFile)
{
m_printToFile = printToFile;
}
//----------------------------------------------------------------------------
QPrinter *Base::printer()
{
DEBUG_LOG(m_logger) << "Base::printer" ;
return m_printer;
}
//----------------------------------------------------------------------------
QString Base::styleSheet()
{
QString ret;
// TODO ret += ""; // TODO
return ret;
}
//----------------------------------------------------------------------------
QSize Base::printerPageSize() const
{
return QSize(m_printer->pageRect().width() - 2 * DOC_MARGIN,
m_printer->pageRect().height() - 2 * DOC_MARGIN);
}
bool Base::newPage()
{
return m_printer->newPage();
}
//----------------------------------------------------------------------------
QSize Base::contentPageSize() const
{
QSize ps(printerPageSize());
// subtract headerRect(device) and footerRect(device)
ps.setHeight(ps.height() - 50 - 50); // cab hack
return ps;
}
//----------------------------------------------------------------------------
void Base::printTitleData(QString &htmlStr, const QString &title, const QString &heading)
{
if (!title.isEmpty())
{
htmlStr += QLatin1String("<table width=\"100%\"><tr><td align=\"center\">") +
QLatin1Char('<') + heading + QLatin1Char('>') + title + QLatin1String("</") + heading + QLatin1Char('>') +
QLatin1String("</td></tr></table>");
}
}
//----------------------------------------------------------------------------
bool Base::printListData(QString &str,
const QAbstractItemView *view,
const QString &title,
bool asIcons,
int iconExtent)
{
if (!view)
return false;
printTitleData(str, title);
QAbstractItemModel *vm = view->model();
if (!vm)
return false;
QItemSelectionModel *sm = view->selectionModel();
QModelIndexList mil;
if (m_printer->printRange() == QPrinter::Selection)
mil = sm->selectedRows();
else
{
int row = 0;
while (1)
{
QModelIndex mi = vm->index(row, 0, QModelIndex());
if (mi.isValid())
{
mil.append(mi);
row++;
continue;
}
break;
}
}
if (mil.count() == 0)
return false;
if (asIcons)
{
// icons as a table:
int elemWidth = iconExtent + 40; // todo: width: elemMargin + icon + text
int tableWidth = contentPageSize().width();
int nColums = tableWidth / elemWidth;
str += QLatin1String("<table border=\"0\" cellspacing=\"2\">") +
QLatin1String("<colgroup width=\"") + QString::number(elemWidth) + QLatin1String("\" ") +
QLatin1String("span=\"") + QString::number(nColums) + QLatin1String("\">") +
QLatin1String("</colgroup>") +
QLatin1String("<tbody>") +
QLatin1String("<tr>");
// rows :
int columIdx = 0;
for (const QModelIndex &mi :qAsConst(mil))
{
// check for new row:
if (columIdx >= nColums)
{
// new row:
columIdx = 0;
str += QLatin1String("</tr><tr>");
}
// one table cell :
str += QLatin1String("<td>");
printDecorationData(str, vm, mi, iconExtent / 2);
// display text under the icon :
QVariant vdata = vm->data(mi, Qt::DisplayRole);
str += QLatin1String("<br />");
QString displayText;
if (vdata.isValid())
displayText = vdata.toString();
else
displayText = QLatin1Char(' ');
str += QLatin1String("<font size=-1>") + displayText + QLatin1String("</font>") +
QLatin1String("</td>");
++columIdx;
// : one table cell
}
str += QLatin1String("</tr></tbody></table>");
}
else
{
// list:
for (const QModelIndex &mi :qAsConst(mil))
{
if (printItemData(str, vm, mi, iconExtent))
str += QLatin1String("<br />");
}
}
return true;
}
static QModelIndexList getItemChildren(const QAbstractItemModel *model,
const QTreeView *tv,
const QModelIndex &root)
{
QModelIndexList ret;
const int rc = model->rowCount(root);
ret.reserve(rc);
for (int row = 0; row < rc; ++row)
{
const QModelIndex mi = model->index(row, 0, root);
ret += mi;
if (tv->isExpanded(mi))
ret += getItemChildren(model, tv, mi);
}
return ret;
}
//----------------------------------------------------------------------------
bool Base::printTableData(QString &str,
const QAbstractItemView *view,
const QString &title_,
const QSet<int> &suppressCols,
int iconExtent)
{
if (!view)
return false;
QString title = title_;
printTitleData(str, title.remove(QLatin1String("[*]")));
const QAbstractItemModel *imodel = view->model();
QModelIndexList mil;
if (m_printer->printRange() == QPrinter::Selection)
{
const QItemSelectionModel *sm = view->selectionModel();
mil += sm->selectedRows();
}
else
{
const QTreeView *tv = qobject_cast<const QTreeView *>(view);
if (tv)
{
const int rc = imodel->rowCount();
mil.reserve(rc);
for (int row = 0; row < rc; ++row)
{
QModelIndex mi = imodel->index(row, 0);
mil += mi;
if (tv->isExpanded(mi))
mil += getItemChildren(imodel, tv, mi);
}
}
else
{
const int rc = imodel->rowCount();
mil.reserve(rc);
for (int row = 0; row < rc; ++row)
mil.append(imodel->index(row, 0));
}
}
int colCount = imodel->columnCount();
QStringList tableHeader;
for (int i = 0; i < colCount; i++)
{
if (suppressCols.contains(i))
continue;
QVariant v = imodel->headerData(i, Qt::Horizontal);
if (v.isValid())
tableHeader.append(v.toString());
}
str += QLatin1String("<table border=\"1\" cellspacing=\"0\" cellpadding=\"3\" style=\"border-collapse:collapse\">") +
QLatin1String("<thead>") +
QLatin1String("<tr>");
for (const QString &s : qAsConst(tableHeader))
str += QLatin1String("<th scope=\"col\">") + s + QLatin1String("</th>");
str += QLatin1String("</tr></thead><tbody>");
// cells could be glued together (cells span)
// example: let four colums be spanned: tableView->setSpan(0,1,1,4);
// then we get foreach col = 1, ..., 4): view->columnSpan(0, col) == 4
QVector<QPair<int, int> > spannedL;
for (const QModelIndex &mi :qAsConst(mil))
{
str += QLatin1String("<tr>");
for (int ii = 0; ii < colCount; ii++)
{
if (suppressCols.contains(ii))
continue;
const QModelIndex ms = mi.sibling(mi.row(), ii);
if (spannedL.contains(qMakePair(ms.row(), ms.column())))
continue;
int rowSpanSize;
int columnSpanSize;
spanSizes(view, ms, rowSpanSize, columnSpanSize, spannedL);
printTableItemData(str, imodel, ms, rowSpanSize, columnSpanSize,
iconExtent);
}
str += QLatin1String("</tr>");
}
str += QLatin1String("</tbody></table>");
DEBUG_LOG(m_logger) << qPrintable(str) ;
return true;
}
//----------------------------------------------------------------------------
void spanSizes(const QAbstractItemView *view,
const QModelIndex &ms,
int &rowSpanSize,
int &columnSpanSize,
QVector<QPair<int, int> > &spannedL)
{
rowSpanSize = 1;
columnSpanSize = 1;
const QTableView *tview = qobject_cast<const QTableView *>(view);
if (tview)
{
rowSpanSize = tview->rowSpan(ms.row(), ms.column());
columnSpanSize = tview->columnSpan(ms.row(), ms.column());
for (int row = ms.row(); row < ms.row() + rowSpanSize; ++row)
spannedL << qMakePair(row, ms.column());
for (int column = ms.column(); column < ms.column() + columnSpanSize; ++column)
spannedL << qMakePair(ms.row(), column);
}
}
//----------------------------------------------------------------------------
bool Base::printTableItemData(QString &str,
const QAbstractItemModel *model,
const QModelIndex &mi,
int rowSpanSize,
int columnSpanSize,
int iconExtent)
{
QVariant vdata;
QString htmlString;
// Qt::BackgroundRole :
vdata = model->data(mi, Qt::BackgroundRole);
if (vdata.isValid())
{
QString bgColorString = vdata.value<QBrush>().color().name();
htmlString += QLatin1String("<td bgcolor=\"") + bgColorString + QLatin1Char('\"');
}
else
htmlString += QLatin1String("<td");
// cells could be glued together (cells span) :
if (rowSpanSize > 1)
htmlString += QLatin1String(" rowspan=\"") + QString::number(rowSpanSize) + QLatin1Char('\"');
if (columnSpanSize > 1)
htmlString += QLatin1String(" colspan=\"") + QString::number(columnSpanSize) + QLatin1Char('\"');
//
htmlString += QLatin1Char('>');
printItemData(htmlString, model, mi, iconExtent);
htmlString += QLatin1String("</td>");
str += htmlString;
return true;
}
//----------------------------------------------------------------------------
/**
* we expect children only at column 0
**/
bool Base::printTreeData(QString &str,
const QAbstractItemView *view,
const QString &title,
const QSet<int> &suppressCols,
int iconExtent,
const QList<QString> &tabtexts)
{
if (!view)
return false;
printTitleData(str, title);
QAbstractItemModel *vm = view->model();
if (!vm)
return false;
QItemSelectionModel *sm = view->selectionModel();
QModelIndexList milColumn0;
if (m_printer->printRange() == QPrinter::Selection)
milColumn0 = sm->selectedRows();
else
{
int row = 0;
while (1)
{
QModelIndex mi = vm->index(row, 0);
if (mi.isValid())
{
milColumn0.append(mi);
row++;
continue;
}
break;
}
}
if (milColumn0.count() == 0)
return false;
// borderless table for tree :
str += QLatin1String("<table border=\"0\" cellspacing=\"2\" cellpadding=\"1\">") +
QLatin1String("<tbody><tr>");
QStringList tableHeader;
if (tabtexts.size() > 0)
tableHeader = tabtexts;
else // headerData :
{
for (int i = 0; i < vm->columnCount(); i++)
{
if (suppressCols.contains(i))
continue;
QVariant v = vm->headerData(i, Qt::Horizontal);
if (v.isValid())
tableHeader.append(v.toString());
else
tableHeader.append(QString());
}
}
for (const QString &s : qAsConst(tableHeader))
str += QLatin1String("<th align=\"left\"><h4>") + s + QLatin1String("</h4></th>");
str += QLatin1String("</tr>");
for (const QModelIndex &miColumn0 : qAsConst(milColumn0))
printListPoint(str, view, vm, miColumn0, suppressCols, iconExtent);
str += QLatin1String("</tbody></table><br /><br />");
// QFile f("/tmp/out.html");
// f.open(QIODevice::WriteOnly);
// f.write(str.toUtf8());
// f.close();
return true;
}
//----------------------------------------------------------------------------
void Base::printListPoint(QString &str,
const QAbstractItemView *view,
const QAbstractItemModel *vm,
const QModelIndex &miColumn0,
const QSet<int> &suppressCols,
int iconExtent)
{
if (!miColumn0.isValid())
return;
// one row :
str += QLatin1String("<tr>");
for (int column = 0; column < vm->columnCount(); column++)
{
if (suppressCols.contains(column))
continue;
QModelIndex ms = miColumn0.sibling(miColumn0.row(), column);
if (!ms.isValid())
continue;
str += QLatin1String("<td><dl>");
if (column == 0)
{
// set tabs :
int hierCount = hierarchyCount(ms);
for (int genIdx = 0; genIdx < hierCount; ++genIdx)
str += QLatin1String("<dd><dl>");
str += QLatin1String("<dt>");
printItemData(str, vm, ms, iconExtent);
str += QLatin1String("</dt>");
for (int genIdx = 0; genIdx < hierCount; ++genIdx)
str += QLatin1String("</dl></dd>");
}
else
{
str += QLatin1String("<dt>");
printItemData(str, vm, ms, iconExtent);
str += QLatin1String("</dt>");
}
str += QLatin1String("</dl></td>");
}
str += QLatin1String("</tr>");
// the childs of row 0 :
const QTreeView *tv = qobject_cast<const QTreeView *>(view);
const bool expanded = tv ? tv->isExpanded(miColumn0) : true;
if (expanded)
{
const int rc = vm->rowCount(miColumn0);
for (int row = 0; row < rc; row++)
{
QModelIndex cmi = vm->index(row, 0, miColumn0);
if (cmi.isValid())
printListPoint(str, view, vm, cmi, suppressCols, iconExtent);
}
}
}
//----------------------------------------------------------------------------
int Base::hierarchyCount(const QModelIndex &child)
{
int count = 0;
const auto parent = child.parent();
if (parent.isValid())
count = hierarchyCount(parent) + 1;
return count;
}
//----------------------------------------------------------------------------
bool Base::printItemData(QString &str,
const QAbstractItemModel *model,
const QModelIndex &mi,
int iconExtent)
{
QVariant vdata;
QString displayString;
QString htmlString;
// Qt::CheckStateRole :
vdata = model->data(mi, Qt::CheckStateRole);
if (vdata.isValid())
{
displayString += QLatin1String("<code>"); // monocrome font
if (static_cast<Qt::CheckState>(vdata.toInt()))
displayString += QLatin1String("&otimes; "); // char checked
else
displayString += QLatin1String("&omicron; "); // char unchecked
displayString += QLatin1String("</code>");
}
// Qt::DecorationRole :
printDecorationData(displayString, model, mi, iconExtent / 2);
// Qt::DisplayRole (display text) :
displayString += QLatin1Char(' ');
vdata = model->data(mi, Qt::DisplayRole);
if (vdata.isValid())
displayString += vdata.toString();
// Qt::TextColorRole (obsolete) :
QString fgColorString;
vdata = model->data(mi, Qt::TextColorRole);
if (vdata.isValid())
fgColorString = vdata.value<QColor>().name();
// Qt::ForegroundRole :
vdata = model->data(mi, Qt::ForegroundRole);
if (vdata.isValid())
fgColorString = vdata.value<QBrush>().color().name();
// htmlString :
htmlString += QLatin1String("<font size=\"") + QString::number(itemFontSize_) + QLatin1Char('\"');
if (!fgColorString.isNull())
htmlString += QLatin1String(" color=\"") + fgColorString + QLatin1Char('\"');
htmlString += QLatin1Char('>') + displayString + QLatin1String("</font>");
str += htmlString;
return true;
}
//----------------------------------------------------------------------------
void Base::printDecorationData(QString &str,
const QAbstractItemModel *model,
const QModelIndex &mi,
int iconExtent)
{
QVariant vdata = model->data(mi, Qt::DecorationRole);
if (vdata.isNull() || !vdata.isValid())
return;
QIcon icon = vdata.value<QIcon>();
if (icon.isNull())
return;
// write icon to file :
QString fn = iconFilename(m_iconFilenameNr++);
QPixmap pm = icon.pixmap(1000); // , QIcon::Selected, QIcon::On);
pm.save(fn);
//
str += QLatin1String("<img src=\"") + fn + QLatin1Char('\"') +
QLatin1String(" width=\"") + QString::number(iconExtent) + QLatin1Char('\"') +
QLatin1String(" height=\"") + QString::number(iconExtent) + QLatin1Char('\"') +
QLatin1String(" alt=\"icon\" />"); // text if icon is broken
}
//----------------------------------------------------------------------------
QString Base::iconFilename(int nr) const
{
return m_settings->printPath() + QLatin1String("icon_") + QString::number(nr) + QLatin1String(".png");
}
//----------------------------------------------------------------------------
bool Base::printDocTextBlock(QTextDocument &doc,
const QString &text,
const QString &title)
{
QTextCursor cursor(&doc);
cursor.movePosition(QTextCursor::End);
if (!title.isEmpty())
{
QString htmlStr;
printTitleData(htmlStr, title);
cursor.insertHtml(htmlStr);
}
cursor.insertBlock();
QTextBlockFormat bf = cursor.blockFormat();
bf.setNonBreakableLines(false);
cursor.setBlockFormat(bf);
QTextCharFormat cf = cursor.blockCharFormat();
cf.setFontWeight(QFont::Normal);
cursor.setBlockCharFormat(cf);
cursor.insertText(text);
return true;
}
//----------------------------------------------------------------------------
bool Base::printDocImage(QTextDocument &doc, const QImage &image,
const QString &title, const QString &description, const qreal alreadyUsedHeight) const
{
if (image.isNull())
return false;
QTextCursor cursor(&doc);
static int iImageCounter = 0;
QString name = QStringLiteral("printing://image_%1.png").arg(iImageCounter++);
doc.addResource(QTextDocument::ImageResource,
QUrl(name),
QVariant(image));
QString htmlStr;
if (!title.isEmpty())
printTitleData(htmlStr, title);
if (!description.isEmpty())
printTitleData(htmlStr, description, QLatin1String("h4"));
double rel = (double)image.height() / (double)image.width();
double dwMax = contentPageSize().width();
double dhMax = contentPageSize().height() - alreadyUsedHeight;
if (!title.isEmpty())
dhMax -= TitleDataHeight;
if (!description.isEmpty())
dhMax -= DescriptionDataHeight;
double dh = dhMax;
double dw = dwMax;
if (rel >= 1)
{
// Bild ist hoeher als breit
// dh bleibt, dw muss sich anpassen
double new_dw = dhMax / rel;
if (new_dw > dwMax)
{
// errechnete Breite ist groesser als max -> an dw anpassen
dh = dwMax * rel;
}
else
dw = new_dw;
}
else
{
// Bild ist breiter als hoch
// dw bleibt, dh muss sich anpassen
double new_dh = dw * rel;
if (new_dh > dhMax)
{
// errechnete Hoehe ist groesser als max -> an dh anpassen
dw = dhMax / rel;
}
else
dh = new_dh;
}
QTextImageFormat tif;
tif.setName(name);
tif.setHeight(dh);
tif.setWidth(dw);
//cursor.movePosition(QTextCursor::End);
cursor.insertHtml(htmlStr);
cursor.insertImage(tif);
return true;
}
//----------------------------------------------------------------------------
bool Base::printReportData(QTextDocument &doc, KDReports::Report &report )
{
QTextCursor cursor(&doc);
cursor.movePosition(QTextCursor::End);
QTemporaryFile tempFile;
if (!tempFile.open())
return false;
if (!report.exportToHtml(tempFile.fileName()))
return false;
cursor.insertHtml(QString::fromUtf8(tempFile.readAll()));
return true;
}
//----------------------------------------------------------------------------
QPrinter::PageSize Base::pageSize() const
{
return m_printer->pageSize();
}
//----------------------------------------------------------------------------
void Base::setPageSize(QPrinter::PageSize size)
{
m_printer->setPageSize(size);
}
//----------------------------------------------------------------------------
QPrinter::Orientation Base::orientation() const
{
return m_printer->orientation();
}
//----------------------------------------------------------------------------
void Base::setOrientation(QPrinter::Orientation orientation)
{
m_printer->setOrientation(orientation);
}
//----------------------------------------------------------------------------
double Base::leftMargin() const
{
return leftmargin_; // in millimeters
}
//----------------------------------------------------------------------------
void Base::setLeftMargin(double margin)
{
if ((margin > 0) && (margin < m_printer->paperRect().width() / 2))
leftmargin_ = margin;
else
leftmargin_ = 0;
}
//----------------------------------------------------------------------------
double Base::rightMargin() const
{
return rightmargin_; // in millimeters.
}
//----------------------------------------------------------------------------
void Base::setRightMargin(double margin)
{
if ((margin > 0) && (margin < m_printer->paperRect().width() / 2))
rightmargin_ = margin;
else
rightmargin_ = 0;
}
//----------------------------------------------------------------------------
double Base::topMargin() const
{
return topmargin_; // in millimeters
}
//----------------------------------------------------------------------------
void Base::setTopMargin(double margin)
{
if ((margin > 0) && (margin < m_printer->paperRect().height() / 4))
topmargin_ = margin;
else
topmargin_ = 0;
}
//----------------------------------------------------------------------------
double Base::bottomMargin() const
{
return bottommargin_; // in millimeters.
}
//----------------------------------------------------------------------------
void Base::setBottomMargin(double margin)
{
if ((margin > 0) && (margin < m_printer->paperRect().height() / 4))
bottommargin_ = margin;
else
bottommargin_ = 0;
}
//----------------------------------------------------------------------------
void Base::setMargins(double margin)
{
if ((margin > 0)
&& (margin < m_printer->paperRect().height() / 2)
&& (margin < m_printer->paperRect().width() / 2))
leftmargin_ = rightmargin_ = topmargin_ = bottommargin_ = margin;
else
leftmargin_ = rightmargin_ = topmargin_ = bottommargin_ = 0;
}
//----------------------------------------------------------------------------
double Base::spacing() const
{
return spacing_;
}
//----------------------------------------------------------------------------
void Base::setSpacing(double spacing)
{
if ((spacing > 0) && (spacing <= m_printer->paperRect().height() / 8))
spacing_ = spacing;
else
spacing_ = 0;
}
//----------------------------------------------------------------------------
double Base::headerSize() const
{
return headersize_;
}
//----------------------------------------------------------------------------
void Base::setHeaderSize(double size)
{
if ((size > 0) && (size <= m_printer->paperRect().height() / 8))
headersize_ = size;
else
headersize_ = 0;
}
//----------------------------------------------------------------------------
double Base::headerRule() const
{
return headerrule_;
}
//----------------------------------------------------------------------------
void Base::setHeaderRule(double pointsize)
{
headerrule_ = qMax(0.0, pointsize);
}
//----------------------------------------------------------------------------
const QString &Base::headerText() const
{
return headertext_;
}
//----------------------------------------------------------------------------
/// Set the text for the header. Rich text is supported. HTML tags may be used
/// to format the text and align elements. The following page variables may be
/// included in the text ( using the format set with setPageFormat() )
/// - \&exercise; - Insert current exercise name
/// - \&title; - Insert document title
/// - \&logo; - Insert current logo png
/// - \&logoHeight; - will be replaced by (headerSize * 2) ?
///
void Base::setHeaderText(const QString &text)
{
headertext_ = text;
}
//----------------------------------------------------------------------------
double Base::footerSize() const
{
return footersize_; // in millimeters
}
//----------------------------------------------------------------------------
void Base::setFooterSize(double size)
{
if ((size > 0) && (size <= m_printer->paperRect().height() / 8))
footersize_ = size;
else
footersize_ = 0;
}
//----------------------------------------------------------------------------
double Base::footerRule() const
{
return footerrule_;
}
//----------------------------------------------------------------------------
void Base::setFooterRule(double pointsize)
{
footerrule_ = qMax(0.0, pointsize);
}
//----------------------------------------------------------------------------
const QString &Base::footerText() const
{
return footertext_;
}
//----------------------------------------------------------------------------
/// Set the text for the footer. Rich text is supported. HTML tags may be used
/// to format the text and align elements. The following page variables may be
/// included in the text ( using the format set with setPageFormat() )
/// - \&date; - Insert current date
/// - \&user; - Insert current user
/// - \&page; - Insert current page number
///
void Base::setFooterText(const QString &text)
{
footertext_ = text;
}
//----------------------------------------------------------------------------
void Base:: setItemFontSize(int itemFontSize)
{
itemFontSize_ = itemFontSize;
}
//----------------------------------------------------------------------------
QRectF Base::paperRect(QPaintDevice *device)
{
// calculate size of paper
QRectF rect = m_printer->paperRect();
// adjust for DPI
rect.setWidth(rect.width() *
device->logicalDpiX() / m_printer->logicalDpiX());
rect.setHeight(rect.height() *
device->logicalDpiY() / m_printer->logicalDpiY());
return rect;
}
//----------------------------------------------------------------------------
QRectF Base::contentRect(QPaintDevice *device)
{
// calculate size of content (paper - margins)
QRectF rect = paperRect(device);
rect.adjust(mmToInches(leftmargin_) * device->logicalDpiX(),
mmToInches(topmargin_) * device->logicalDpiY(),
-mmToInches(rightmargin_) * device->logicalDpiX(),
-mmToInches(bottommargin_) * device->logicalDpiY());
// header
if (headersize_ > 0)
{
rect.adjust(0, mmToInches(headersize_) * device->logicalDpiY(), 0, 0);
rect.adjust(0, mmToInches(spacing_) * device->logicalDpiY(), 0, 0);
}
// footer
if (footersize_ > 0)
{
rect.adjust(0, 0, 0, -mmToInches(footersize_) * device->logicalDpiY());
rect.adjust(0, 0, 0, -mmToInches(spacing_) * device->logicalDpiY());
}
return rect;
}
//----------------------------------------------------------------------------
QRectF Base::headerRect(QPaintDevice *device)
{
QRectF rect = paperRect(device);
rect.adjust(mmToInches(leftmargin_) * device->logicalDpiX(),
mmToInches(topmargin_) * device->logicalDpiY(),
-mmToInches(rightmargin_) * device->logicalDpiX(), 0);
rect.setBottom(rect.top() +
mmToInches(headersize_) * device->logicalDpiY());
return rect;
}
//----------------------------------------------------------------------------
QRectF Base::footerRect(QPaintDevice *device)
{
QRectF rect = paperRect(device);
rect.adjust(mmToInches(leftmargin_) * device->logicalDpiX(), 0,
-mmToInches(rightmargin_) * device->logicalDpiX(),
-mmToInches(bottommargin_) * device->logicalDpiY());
rect.setTop(rect.bottom() -
mmToInches(footersize_) * device->logicalDpiY());
return rect;
}
//----------------------------------------------------------------------------
void Base::print(QTextDocument *doc)
{
m_tempdoc = doc->clone();
print();
delete m_tempdoc;
m_tempdoc = nullptr;
}
//----------------------------------------------------------------------------
void Base::printSinglePage(QTextDocument *doc)
{
m_tempdoc = doc->clone();
printSinglePage();
delete m_tempdoc;
m_tempdoc = nullptr;
}
//----------------------------------------------------------------------------
void Base::printSinglePage()
{
if (!m_printer || !m_tempdoc) return;
m_tempdoc->setUseDesignMetrics(true);
m_tempdoc->documentLayout()->setPaintDevice(m_printer);
m_tempdoc->setPageSize(contentRect(m_printer).size());
// dump existing margin (if any)
QTextFrameFormat fmt = m_tempdoc->rootFrame()->frameFormat();
fmt.setMargin(0);
m_tempdoc->rootFrame()->setFrameFormat(fmt);
// to iterate through pages we have to worry about
// copies, collation, page range, and print order
// get num copies
int doccopies;
int pagecopies;
if (m_printer->collateCopies())
{
doccopies = 1;
pagecopies = m_printer->numCopies();
}
else
{
doccopies = m_printer->numCopies();
pagecopies = 1;
}
// get page range
int firstpage = m_printer->fromPage();
int lastpage = m_printer->toPage();
if (firstpage == 0 && lastpage == 0) // all pages
{
firstpage = 1;
lastpage = m_tempdoc->pageCount();
}
// print order
bool ascending = true;
if (m_printer->pageOrder() == QPrinter::LastPageFirst)
{
int tmp = firstpage;
firstpage = lastpage;
lastpage = tmp;
ascending = false;
}
// loop through and print pages
m_painter->setRenderHints(QPainter::Antialiasing |
QPainter::TextAntialiasing |
QPainter::SmoothPixmapTransform, true);
for (int dc = 0; dc < doccopies; dc++)
{
int pagenum = firstpage;
while (true)
{
for (int pc = 0; pc < pagecopies; pc++)
{
if (m_printer->printerState() == QPrinter::Aborted ||
m_printer->printerState() == QPrinter::Error)
return;
// print page
paintPage( m_tempdoc, pagenum);
if (pc < pagecopies - 1)
m_printer->newPage();
}
if (pagenum == lastpage)
break;
if (ascending)
pagenum++;
else
pagenum--;
{
m_printer->newPage();
}
}
if (dc < doccopies - 1)
{
m_printer->newPage();
}
}
}
void Base::printDone()
{
m_painter->end();
m_currentPage = 1;
}
void Base::print()
{
m_currentPage = 1;
printSinglePage();
m_painter->end();
m_currentPage = 1;
}
//----------------------------------------------------------------------------
void Base::paintPage(QTextDocument *document,
int pagenum)
{
QRectF rect;
double onepoint = m_painter->device()->logicalDpiY() / 72.0;
// header
if (headersize_ > 0)
{
rect = headerRect(m_painter->device());
if (headerrule_ > 0.0)
{
m_painter->save();
// allow space between rule and header
m_painter->translate(0, onepoint + (headerrule_ * onepoint / 2.0));
m_painter->setPen(QPen(Qt::black, headerrule_ * onepoint));
m_painter->drawLine(rect.bottomLeft(), rect.bottomRight());
m_painter->restore();
}
// replace header variables
QString header = headertext_;
QString title = document->metaInformation(QTextDocument::DocumentTitle).remove(QLatin1String("[*]"));
header.replace(QLatin1String("&exercise;"), currentExerciseName());
header.replace(QLatin1String("&title;"), title);
header.replace(QLatin1String("&logo;"), m_settings->logoProject());
header.replace(QLatin1String("&logoHeight;"), QString::number(ProjectIconHeight));
//
m_painter->save();
m_painter->translate(rect.left(), rect.top());
QRectF clip(0, 0, rect.width(), rect.height());
QTextDocument doc;
doc.setUseDesignMetrics(true);
doc.setHtml(header);
doc.documentLayout()->setPaintDevice(m_painter->device());
doc.setPageSize(rect.size());
// align text to bottom
double newtop = clip.bottom() - doc.size().height();
clip.setHeight(doc.size().height());
m_painter->translate(0, newtop);
doc.drawContents(m_painter, clip);
m_painter->restore();
}
// footer
if (footersize_ > 0)
{
rect = footerRect(m_painter->device());
if (footerrule_ > 0.0)
{
m_painter->save();
// allow space between rule and footer
m_painter->translate(0, -onepoint + (-footerrule_ * onepoint / 2.0));
m_painter->setPen(QPen(Qt::black, footerrule_ * onepoint));
m_painter->drawLine(rect.topLeft(), rect.topRight());
m_painter->restore();
}
// replace footer variables
QString footer = footertext_;
footer.replace(QLatin1String("&date;"), QObject::tr("Printed on: ") + DTG::toString(QDateTime::currentDateTime()) );
footer.replace(QLatin1String("&user;"), operatorName());
footer.replace(QLatin1String("&footertitle;"), footertitle_);
footer.replace(QLatin1String("&page;"), QString::number(m_currentPage++));
//
m_painter->save();
m_painter->translate(rect.left(), rect.top());
QRectF clip(0, 0, rect.width(), rect.height());
QTextDocument doc;
doc.setUseDesignMetrics(true);
doc.setHtml(footer);
doc.documentLayout()->setPaintDevice(m_painter->device());
doc.setPageSize(rect.size());
doc.drawContents(m_painter, clip);
m_painter->restore();
}
// content
m_painter->save();
rect = contentRect(m_painter->device());
m_painter->translate(rect.left(), rect.top() - (pagenum - 1) * rect.height());
QRectF clip(0, (pagenum - 1) * rect.height(), rect.width(), rect.height());
document->drawContents(m_painter, clip);
m_painter->restore();
}
//----------------------------------------------------------------------------
void Base::setCurrentExerciseName( const QString& exerciseName )
{
m_exerciseName = exerciseName;
}
//----------------------------------------------------------------------------
QString Base::currentExerciseName() const
{
return m_exerciseName;
}
//----------------------------------------------------------------------------
void Base::setOperatorName( const QString& operatorName )
{
m_operatorName = operatorName;
}
//----------------------------------------------------------------------------
QString Base::operatorName() const
{
return m_operatorName;
}
//----------------------------------------------------------------------------
QSize Base::pageSizeInMM()
{
QRectF rect = contentRect(m_printer);
return rect.size().toSize();
}
} // namespace LtsPrinting