File indexing completed on 2024-04-28 09:41:04
0001 /* 0002 -------------------------------------------------------------------- 0003 KDE\QT printing implementation. 0004 -------------------------------------------------------------------- 0005 SPDX-FileCopyrightText: 1999 Robert Berry <rjmber@ntlworld.com> 0006 -------------------------------------------------------------------- 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include "crontabPrinter.h" 0011 0012 #include <QPainter> 0013 #include <QPrintDialog> 0014 #include <QPrinter> 0015 #include <numeric> 0016 0017 #include <KLocalizedString> 0018 0019 #include "crontabWidget.h" 0020 0021 #include "ctcron.h" 0022 #include "cttask.h" 0023 #include "ctvariable.h" 0024 0025 #include "kcm_cron_debug.h" 0026 0027 CrontabPrinter::CrontabPrinter(CrontabWidget *crontabWidget) 0028 : mCrontabWidget(crontabWidget) 0029 { 0030 } 0031 0032 CrontabPrinter::~CrontabPrinter() 0033 { 0034 delete mCrontabPrinterWidget; 0035 0036 delete mPainter; 0037 delete mPrinter; 0038 delete mPrintView; 0039 } 0040 0041 bool CrontabPrinter::start() 0042 { 0043 qCDebug(KCM_CRON_LOG) << "Printing selection..."; 0044 0045 if (!mPrinter) { 0046 mPrinter = new QPrinter(); 0047 } 0048 0049 // do some printer initialization 0050 mPrinter->setFullPage(true); 0051 0052 /* 0053 CrontabPrinterWidget* dialogPage = new CrontabPrinterWidget(crontabWidge); 0054 printer->addDialogPage(dialogPage); 0055 */ 0056 0057 // initialize the printer using the print dialog 0058 auto printDialog = new QPrintDialog(mPrinter, nullptr); 0059 printDialog->setOptions(QAbstractPrintDialog::PrintToFile); 0060 if (printDialog->exec() == QDialog::Rejected) { 0061 qCDebug(KCM_CRON_LOG) << "Printing canceled"; 0062 delete printDialog; 0063 return false; 0064 } 0065 0066 delete printDialog; 0067 0068 // create a painter to paint on the printer object 0069 mPainter = new QPainter(); 0070 0071 // start painting 0072 mPainter->begin(mPrinter); 0073 0074 const int margin = computeMargin(); 0075 mPrintView = new QRect(margin, margin, mPainter->device()->width() - 2 * margin, mPainter->device()->height() - 2 * margin); 0076 0077 mPage = 1; 0078 mCurrentRowPosition = 0; 0079 0080 drawMainTitle(); 0081 0082 return true; 0083 } 0084 0085 void CrontabPrinter::printTasks() 0086 { 0087 CTCron *cron = mCrontabWidget->currentCron(); 0088 0089 drawTitle(i18n("Scheduled Tasks")); 0090 0091 QList<QStringList> tasksContent; 0092 tasksContent.reserve(cron->tasks().count()); 0093 const auto tasks = cron->tasks(); 0094 for (CTTask *task : tasks) { 0095 QStringList values; 0096 values << task->schedulingCronFormat(); 0097 values << task->command; 0098 values << task->comment; 0099 0100 tasksContent.append(values); 0101 } 0102 0103 const QList<int> tasksColumnWidths = findColumnWidths(tasksContent, 3); 0104 0105 QStringList taskHeaders; 0106 taskHeaders << i18n("Scheduling") << i18n("Command") << i18n("Description"); 0107 drawHeader(tasksColumnWidths, taskHeaders); 0108 0109 for (const QStringList &contents : std::as_const(tasksContent)) { 0110 drawContentRow(tasksColumnWidths, contents); 0111 0112 needNewPage(); 0113 } 0114 0115 drawTable(tasksColumnWidths); 0116 } 0117 0118 void CrontabPrinter::printVariables() 0119 { 0120 CTCron *cron = mCrontabWidget->currentCron(); 0121 0122 mPainter->translate(0, 20); 0123 mCurrentRowPosition = 0; 0124 0125 // Environment Variables 0126 0127 drawTitle(i18n("Environment Variables")); 0128 0129 // QList<QStringList> variablesContent; 0130 const auto variables = cron->variables(); 0131 for (CTVariable *variable : variables) { 0132 mPainter->drawText(*(mPrintView), Qt::AlignLeft | Qt::TextWordWrap, variable->variable + QLatin1String(" = ") + variable->value); 0133 0134 const int moveBy = computeStringHeight(variable->variable); 0135 mPainter->translate(0, moveBy); 0136 } 0137 } 0138 0139 void CrontabPrinter::drawMainTitle() 0140 { 0141 CTCron *cron = mCrontabWidget->currentCron(); 0142 0143 QFont originalFont = mPainter->font(); 0144 QFont titleFont(originalFont); 0145 titleFont.setPixelSize(20); 0146 titleFont.setBold(true); 0147 0148 mPainter->setFont(titleFont); 0149 0150 QString mainTitle; 0151 if (cron->isSystemCron()) { 0152 mainTitle = i18n("System Crontab"); 0153 } else if (cron->isMultiUserCron()) { 0154 mainTitle = i18n("All Users Crontabs"); 0155 } else { 0156 mainTitle = i18nc("Crontab of user login", "Crontab of user %1", cron->userLogin()); 0157 } 0158 0159 mPainter->drawText(*(mPrintView), Qt::AlignHCenter | Qt::TextWordWrap, mainTitle); 0160 0161 mPainter->translate(0, computeStringHeight(mainTitle)); 0162 0163 mPainter->setFont(originalFont); 0164 } 0165 0166 void CrontabPrinter::drawTitle(const QString &title) 0167 { 0168 QFont originalFont = mPainter->font(); 0169 QFont titleFont(originalFont); 0170 titleFont.setPixelSize(16); 0171 titleFont.setBold(true); 0172 0173 mPainter->setFont(titleFont); 0174 0175 mPainter->drawText(*(mPrintView), Qt::AlignLeft | Qt::TextWordWrap, title); 0176 0177 mPainter->translate(0, computeStringHeight(title)); 0178 0179 mPainter->setFont(originalFont); 0180 } 0181 0182 void CrontabPrinter::drawHeader(const QList<int> &columnWidths, const QStringList &headers) 0183 { 0184 QFont originalFont = mPainter->font(); 0185 QFont titleFont(originalFont); 0186 titleFont.setBold(true); 0187 0188 mPainter->setFont(titleFont); 0189 0190 drawContentRow(columnWidths, headers); 0191 0192 mPainter->setFont(originalFont); 0193 } 0194 0195 void CrontabPrinter::drawContentRow(const QList<int> &columnWidths, const QStringList &contents) 0196 { 0197 QString firstColumn; 0198 0199 int totalWidths = 0; 0200 int index = 0; 0201 for (const QString &content : contents) { 0202 if (index == 0) { 0203 firstColumn = content; 0204 } 0205 0206 mPainter->drawText(*(mPrintView), Qt::AlignLeft | Qt::TextWordWrap, QLatin1String(" ") + content); 0207 0208 mPainter->translate(columnWidths[index], 0); 0209 0210 totalWidths += columnWidths[index]; 0211 0212 index++; 0213 } 0214 0215 int moveBy = computeStringHeight(firstColumn); 0216 0217 changeRow(-totalWidths, moveBy); 0218 } 0219 0220 void CrontabPrinter::finish() 0221 { 0222 // stop painting, this will automatically send the print data to the printer 0223 mPainter->end(); 0224 } 0225 0226 void CrontabPrinter::printPageNumber() 0227 { 0228 qCDebug(KCM_CRON_LOG) << "Printing page number..."; 0229 0230 mPainter->translate(0, -mCurrentRowPosition); 0231 mPrintView->moveTo(QPoint(0, mPrintView->height())); 0232 mPainter->translate(0, -mPrintView->height()); 0233 mPainter->drawText(mPrintView->right() - mPainter->fontMetrics().boundingRect(QString::number(mPage)).width(), 0234 mPrintView->bottom() + mPainter->fontMetrics().ascent() + 5, 0235 QString::number(mPage)); 0236 } 0237 0238 void CrontabPrinter::changeRow(int x, int y) 0239 { 0240 mPainter->translate(x, y); 0241 mCurrentRowPosition = mCurrentRowPosition + y; 0242 } 0243 0244 int CrontabPrinter::computeMargin() const 0245 { 0246 const int dpiy = mPainter->device()->logicalDpiY(); 0247 const int margin = (int)((2 / 2.54) * dpiy); // 2 cm margins 0248 0249 return margin; 0250 } 0251 0252 int CrontabPrinter::computeStringHeight(const QString &text) const 0253 { 0254 const int fontHeight = mPainter->fontMetrics().height(); 0255 const int lines = mPainter->fontMetrics().boundingRect(text).width() / mPrintView->width() + 1; 0256 const int moveBy = (fontHeight + 2) * lines; 0257 0258 return moveBy; 0259 } 0260 0261 /** 0262 * Whether crontab should be printed 0263 */ 0264 bool CrontabPrinter::isPrintCrontab() const 0265 { 0266 return mCrontabPrinterWidget->printCrontab(); 0267 } 0268 0269 /** 0270 * Whether all users should be printed (root only) 0271 */ 0272 bool CrontabPrinter::isAllUsers() const 0273 { 0274 return mCrontabPrinterWidget->printAllUsers(); 0275 } 0276 0277 void CrontabPrinter::drawTable(const QList<int> &columnWidths) 0278 { 0279 mPainter->translate(0, -mCurrentRowPosition + computeMargin()); 0280 0281 int columnWidthsTotal = std::accumulate(columnWidths.begin(), columnWidths.end(), 0); 0282 0283 const int margin = computeMargin(); 0284 int linePositionX = margin; 0285 0286 QPen originalPen = mPainter->pen(); 0287 QPen pen(originalPen); 0288 0289 pen.setWidth(1); 0290 0291 mPainter->setPen(pen); 0292 0293 // First horizontal line 0294 mPainter->drawLine(QPoint(margin, 0), QPoint(margin + columnWidthsTotal, 0)); 0295 0296 // Second horizontal line 0297 mPainter->drawLine(QPoint(margin, 0 + computeStringHeight(QStringLiteral(" "))), 0298 QPoint(margin + columnWidthsTotal, 0 + computeStringHeight(QStringLiteral(" ")))); 0299 0300 // First vertical line 0301 mPainter->drawLine(QPoint(linePositionX, 0), QPoint(linePositionX, mCurrentRowPosition)); 0302 0303 for (int columnWidth : columnWidths) { 0304 linePositionX += columnWidth; 0305 mPainter->drawLine(QPoint(linePositionX, 0), QPoint(linePositionX, mCurrentRowPosition)); 0306 } 0307 0308 // Last horizontal line 0309 mPainter->drawLine(QPoint(margin, mCurrentRowPosition), QPoint(margin + columnWidthsTotal, mCurrentRowPosition)); 0310 0311 mPainter->setPen(originalPen); 0312 0313 mPainter->translate(0, mCurrentRowPosition - computeMargin()); 0314 } 0315 0316 QList<int> CrontabPrinter::findMaxWidths(const QList<QStringList> &contents, int columnCount) 0317 { 0318 QList<int> columnWidths; 0319 columnWidths.reserve(columnCount); 0320 for (int i = 0; i < columnCount; ++i) { 0321 columnWidths.append(0); 0322 } 0323 0324 for (const QStringList &content : contents) { 0325 int columnIndex = 0; 0326 while (columnIndex < columnWidths.count()) { 0327 const int valueWidth = mPainter->fontMetrics().boundingRect(content.at(columnIndex)).width(); 0328 if (columnWidths[columnIndex] < valueWidth) { 0329 columnWidths[columnIndex] = valueWidth; 0330 } 0331 0332 columnIndex++; 0333 } 0334 } 0335 0336 return columnWidths; 0337 } 0338 0339 QList<int> CrontabPrinter::findColumnWidths(const QList<QStringList> &contents, int columnCount) 0340 { 0341 QList<int> columnWidths = findMaxWidths(contents, columnCount); 0342 0343 int margin = computeMargin(); 0344 int pageWidth = mPainter->device()->width() - 2 * margin; 0345 0346 int columnWidthSum = 0; 0347 for (int width : std::as_const(columnWidths)) { 0348 qCDebug(KCM_CRON_LOG) << "Column : " << width; 0349 columnWidthSum += width; 0350 } 0351 0352 if (columnWidthSum >= pageWidth) { 0353 qCDebug(KCM_CRON_LOG) << "The printing could be out of the page"; 0354 return columnWidths; 0355 } 0356 0357 int additionalSpace = (pageWidth - columnWidthSum) / columnWidths.count(); 0358 0359 int columnIndex = 0; 0360 while (columnIndex < columnWidths.count()) { 0361 columnWidths[columnIndex] = columnWidths[columnIndex] + additionalSpace; 0362 0363 columnIndex++; 0364 } 0365 0366 return columnWidths; 0367 } 0368 0369 void CrontabPrinter::needNewPage() 0370 { 0371 const int margin = computeMargin(); 0372 if (mCurrentRowPosition + margin >= mPrintView->height()) { 0373 printPageNumber(); 0374 mPrinter->newPage(); 0375 mPage++; 0376 mCurrentRowPosition = 0; 0377 } 0378 }