File indexing completed on 2025-01-12 05:01:59
0001 /* 0002 SPDX-FileCopyrightText: 2003-2007 Craig Drummond <craig@kde.org> 0003 SPDX-License-Identifier: GPL-2.0-or-later 0004 */ 0005 0006 #include "Printer.h" 0007 #include "ActionLabel.h" 0008 #include "Fc.h" 0009 #include "FcEngine.h" 0010 #include "KfiConstants.h" 0011 #include "config-fontinst.h" 0012 #include <KAboutData> 0013 #include <QApplication> 0014 #include <QCloseEvent> 0015 #include <QCommandLineOption> 0016 #include <QCommandLineParser> 0017 #include <QFile> 0018 #include <QFontDatabase> 0019 #include <QFontMetrics> 0020 #include <QFrame> 0021 #include <QGridLayout> 0022 #include <QPainter> 0023 #include <QPrintDialog> 0024 #include <QPrinter> 0025 #include <QProgressBar> 0026 #include <QTextStream> 0027 #include <QWidget> 0028 0029 #include "config-workspace.h" 0030 0031 #ifdef HAVE_LOCALE_H 0032 #include <QDialogButtonBox> 0033 #include <QPushButton> 0034 #include <QVBoxLayout> 0035 #include <locale.h> 0036 #endif 0037 #include "CreateParent.h" 0038 0039 // Enable the following to allow printing of non-installed fonts. Does not seem to work :-( 0040 // #define KFI_PRINT_APP_FONTS 0041 0042 using namespace KFI; 0043 0044 static const int constMarginLineBefore = 1; 0045 static const int constMarginLineAfter = 2; 0046 static const int constMarginFont = 4; 0047 0048 inline bool sufficientSpace(int y, int pageHeight, const QFontMetrics &fm) 0049 { 0050 return (y + constMarginFont + fm.height()) < pageHeight; 0051 } 0052 0053 static bool sufficientSpace(int y, QPainter *painter, QFont font, const int *sizes, int pageHeight, int size) 0054 { 0055 int titleFontHeight = painter->fontMetrics().height(), required = titleFontHeight + constMarginLineBefore + constMarginLineAfter; 0056 0057 for (unsigned int s = 0; sizes[s]; ++s) { 0058 font.setPointSize(sizes[s]); 0059 required += QFontMetrics(font, painter->device()).height(); 0060 if (sizes[s + 1]) { 0061 required += constMarginFont; 0062 } 0063 } 0064 0065 if (0 == size) { 0066 font.setPointSize(CFcEngine::constDefaultAlphaSize); 0067 int fontHeight = QFontMetrics(font, painter->device()).height(); 0068 0069 required += (3 * (constMarginFont + fontHeight)) + constMarginLineBefore + constMarginLineAfter; 0070 } 0071 return (y + required) < pageHeight; 0072 } 0073 0074 static QString usableStr(QFont &font, const QString &str) 0075 { 0076 Q_UNUSED(font) 0077 return str; 0078 } 0079 0080 static bool hasStr(QFont &font, const QString &str) 0081 { 0082 Q_UNUSED(font) 0083 Q_UNUSED(str) 0084 return true; 0085 } 0086 0087 static QString previewString(QFont &font, const QString &text, bool onlyDrawChars) 0088 { 0089 Q_UNUSED(font) 0090 Q_UNUSED(onlyDrawChars) 0091 return text; 0092 } 0093 0094 CPrintThread::CPrintThread(QPrinter *printer, const QList<Misc::TFont> &items, int size, QObject *parent) 0095 : QThread(parent) 0096 , m_printer(printer) 0097 , m_items(items) 0098 , m_size(size) 0099 , m_cancelled(false) 0100 { 0101 } 0102 0103 CPrintThread::~CPrintThread() 0104 { 0105 } 0106 0107 void CPrintThread::cancel() 0108 { 0109 m_cancelled = true; 0110 } 0111 0112 void CPrintThread::run() 0113 { 0114 QPainter painter; 0115 QFont sans("sans", 12, QFont::Bold); 0116 bool changedFontEmbeddingSetting(false); 0117 QString str(CFcEngine(false).getPreviewString()); 0118 0119 if (!m_printer->fontEmbeddingEnabled()) { 0120 m_printer->setFontEmbeddingEnabled(true); 0121 changedFontEmbeddingSetting = true; 0122 } 0123 0124 m_printer->setResolution(72); 0125 painter.begin(m_printer); 0126 0127 int pageWidth = painter.device()->width(), pageHeight = painter.device()->height(), y = 0, oneSize[2] = {m_size, 0}; 0128 const int *sizes = oneSize; 0129 bool firstFont(true); 0130 0131 if (0 == m_size) { 0132 sizes = CFcEngine::constScalableSizes; 0133 } 0134 0135 painter.setClipping(true); 0136 painter.setClipRect(0, 0, pageWidth, pageHeight); 0137 0138 QList<Misc::TFont>::ConstIterator it(m_items.constBegin()), end(m_items.constEnd()); 0139 0140 for (int i = 0; it != end && !m_cancelled; ++it, ++i) { 0141 QString name(FC::createName((*it).family, (*it).styleInfo)); 0142 Q_EMIT progress(i, name); 0143 0144 unsigned int s = 0; 0145 QFont font; 0146 0147 #ifdef KFI_PRINT_APP_FONTS 0148 QString family; 0149 0150 if (-1 != appFont[(*it).family]) { 0151 family = QFontDatabase::applicationFontFamilies(appFont[(*it).family]).first(); 0152 font = QFont(family); 0153 } 0154 #else 0155 font = CFcEngine::getQFont((*it).family, (*it).styleInfo, CFcEngine::constDefaultAlphaSize); 0156 #endif 0157 painter.setFont(sans); 0158 0159 if (!firstFont && !sufficientSpace(y, &painter, font, sizes, pageHeight, m_size)) { 0160 m_printer->newPage(); 0161 y = 0; 0162 } 0163 painter.setFont(sans); 0164 y += painter.fontMetrics().height(); 0165 painter.drawText(0, y, name); 0166 0167 y += constMarginLineBefore; 0168 painter.drawLine(0, y, pageWidth, y); 0169 y += constMarginLineAfter; 0170 0171 bool onlyDrawChars = false; 0172 Qt::TextElideMode em = Qt::LeftToRight == QApplication::layoutDirection() ? Qt::ElideRight : Qt::ElideLeft; 0173 0174 if (0 == m_size) { 0175 font.setPointSize(CFcEngine::constDefaultAlphaSize); 0176 painter.setFont(font); 0177 0178 QFontMetrics fm(font, painter.device()); 0179 bool lc = hasStr(font, CFcEngine::getLowercaseLetters()), uc = hasStr(font, CFcEngine::getUppercaseLetters()); 0180 0181 onlyDrawChars = !lc && !uc; 0182 0183 if (lc || uc) { 0184 y += CFcEngine::constDefaultAlphaSize; 0185 } 0186 0187 if (lc) { 0188 painter.drawText(0, y, fm.elidedText(CFcEngine::getLowercaseLetters(), em, pageWidth)); 0189 y += constMarginFont + CFcEngine::constDefaultAlphaSize; 0190 } 0191 0192 if (uc) { 0193 painter.drawText(0, y, fm.elidedText(CFcEngine::getUppercaseLetters(), em, pageWidth)); 0194 y += constMarginFont + CFcEngine::constDefaultAlphaSize; 0195 } 0196 0197 if (lc || uc) { 0198 QString validPunc(usableStr(font, CFcEngine::getPunctuation())); 0199 if (validPunc.length() >= (CFcEngine::getPunctuation().length() / 2)) { 0200 painter.drawText(0, y, fm.elidedText(CFcEngine::getPunctuation(), em, pageWidth)); 0201 y += constMarginFont + constMarginLineBefore; 0202 } 0203 painter.drawLine(0, y, pageWidth, y); 0204 y += constMarginLineAfter; 0205 } 0206 } 0207 0208 for (; sizes[s]; ++s) { 0209 y += sizes[s]; 0210 font.setPointSize(sizes[s]); 0211 painter.setFont(font); 0212 0213 QFontMetrics fm(font, painter.device()); 0214 0215 if (sufficientSpace(y, pageHeight, fm)) { 0216 painter.drawText(0, y, fm.elidedText(previewString(font, str, onlyDrawChars), em, pageWidth)); 0217 if (sizes[s + 1]) { 0218 y += constMarginFont; 0219 } 0220 } else { 0221 break; 0222 } 0223 } 0224 y += (s < 1 || sizes[s - 1] < 25 ? 14 : 28); 0225 firstFont = false; 0226 } 0227 Q_EMIT progress(m_items.count(), QString()); 0228 painter.end(); 0229 0230 // 0231 // Did we change the users font settings? If so, reset to their previous values... 0232 if (changedFontEmbeddingSetting) { 0233 m_printer->setFontEmbeddingEnabled(false); 0234 } 0235 } 0236 0237 CPrinter::CPrinter(QWidget *parent) 0238 : QDialog(parent) 0239 { 0240 setWindowTitle(i18n("Print")); 0241 0242 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel); 0243 connect(buttonBox, &QDialogButtonBox::rejected, this, &CPrinter::slotCancelClicked); 0244 0245 QVBoxLayout *mainLayout = new QVBoxLayout; 0246 setLayout(mainLayout); 0247 0248 QFrame *page = new QFrame(this); 0249 QGridLayout *layout = new QGridLayout(page); 0250 m_statusLabel = new QLabel(page); 0251 m_progress = new QProgressBar(page); 0252 layout->addWidget(m_actionLabel = new CActionLabel(this), 0, 0, 2, 1); 0253 layout->addWidget(m_statusLabel, 0, 1); 0254 layout->addWidget(m_progress, 1, 1); 0255 m_progress->setRange(0, 100); 0256 layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding), 2, 0); 0257 0258 mainLayout->addWidget(page); 0259 mainLayout->addWidget(buttonBox); 0260 setMinimumSize(420, 80); 0261 } 0262 0263 CPrinter::~CPrinter() 0264 { 0265 } 0266 0267 void CPrinter::print(const QList<Misc::TFont> &items, int size) 0268 { 0269 #ifdef HAVE_LOCALE_H 0270 char *oldLocale = setlocale(LC_NUMERIC, "C"); 0271 #endif 0272 0273 QPrinter printer; 0274 QPrintDialog *dialog = new QPrintDialog(&printer, parentWidget()); 0275 0276 if (dialog->exec()) { 0277 CPrintThread *thread = new CPrintThread(&printer, items, size, this); 0278 0279 m_progress->setRange(0, items.count()); 0280 m_progress->setValue(0); 0281 progress(0, QString()); 0282 connect(thread, &CPrintThread::progress, this, &CPrinter::progress); 0283 connect(thread, &QThread::finished, this, &QDialog::accept); 0284 connect(this, &CPrinter::cancelled, thread, &CPrintThread::cancel); 0285 m_actionLabel->startAnimation(); 0286 thread->start(); 0287 exec(); 0288 delete thread; 0289 } 0290 0291 delete dialog; 0292 0293 #ifdef HAVE_LOCALE_H 0294 if (oldLocale) { 0295 setlocale(LC_NUMERIC, oldLocale); 0296 } 0297 #endif 0298 } 0299 0300 void CPrinter::progress(int p, const QString &label) 0301 { 0302 if (!label.isEmpty()) { 0303 m_statusLabel->setText(label); 0304 } 0305 m_progress->setValue(p); 0306 } 0307 0308 void CPrinter::slotCancelClicked() 0309 { 0310 m_statusLabel->setText(i18n("Canceling…")); 0311 Q_EMIT cancelled(); 0312 } 0313 0314 void CPrinter::closeEvent(QCloseEvent *e) 0315 { 0316 Q_UNUSED(e) 0317 e->ignore(); 0318 slotCancelClicked(); 0319 } 0320 0321 int main(int argc, char **argv) 0322 { 0323 QApplication app(argc, argv); 0324 0325 KLocalizedString::setApplicationDomain(KFI_CATALOGUE); 0326 KAboutData aboutData("kfontprint", 0327 i18n("Font Printer"), 0328 WORKSPACE_VERSION_STRING, 0329 i18n("Simple font printer"), 0330 KAboutLicense::GPL, 0331 i18n("(C) Craig Drummond, 2007")); 0332 KAboutData::setApplicationData(aboutData); 0333 0334 QGuiApplication::setWindowIcon(QIcon::fromTheme("kfontprint")); 0335 0336 QCommandLineParser parser; 0337 const QCommandLineOption embedOption(QLatin1String("embed"), i18n("Makes the dialog transient for an X app specified by winid"), QLatin1String("winid")); 0338 parser.addOption(embedOption); 0339 const QCommandLineOption sizeOption(QLatin1String("size"), i18n("Size index to print fonts"), QLatin1String("index")); 0340 parser.addOption(sizeOption); 0341 const QCommandLineOption pfontOption( 0342 QLatin1String("pfont"), 0343 i18n("Font to print, specified as \"Family,Style\" where Style is a 24-bit decimal number composed as: <weight><width><slant>"), 0344 QLatin1String("font")); 0345 parser.addOption(pfontOption); 0346 const QCommandLineOption listfileOption(QLatin1String("listfile"), i18n("File containing list of fonts to print"), QLatin1String("file")); 0347 parser.addOption(listfileOption); 0348 const QCommandLineOption deletefileOption(QLatin1String("deletefile"), i18n("Remove file containing list of fonts to print")); 0349 parser.addOption(deletefileOption); 0350 0351 aboutData.setupCommandLine(&parser); 0352 parser.process(app); 0353 aboutData.processCommandLine(&parser); 0354 0355 QList<Misc::TFont> fonts; 0356 int size(parser.value(sizeOption).toInt()); 0357 0358 if (size > -1 && size < 256) { 0359 QString listFile(parser.value(listfileOption)); 0360 0361 if (!listFile.isEmpty()) { 0362 QFile f(listFile); 0363 0364 if (f.open(QIODevice::ReadOnly)) { 0365 QTextStream str(&f); 0366 0367 while (!str.atEnd()) { 0368 QString family(str.readLine()), style(str.readLine()); 0369 0370 if (!family.isEmpty() && !style.isEmpty()) { 0371 fonts.append(Misc::TFont(family, style.toUInt())); 0372 } else { 0373 break; 0374 } 0375 } 0376 f.close(); 0377 } 0378 0379 if (parser.isSet(deletefileOption)) { 0380 ::unlink(listFile.toLocal8Bit().constData()); 0381 } 0382 } else { 0383 QStringList fl(parser.values(pfontOption)); 0384 QStringList::ConstIterator it(fl.begin()), end(fl.end()); 0385 0386 for (; it != end; ++it) { 0387 QString f(*it); 0388 0389 int commaPos = f.lastIndexOf(','); 0390 0391 if (-1 != commaPos) { 0392 fonts.append(Misc::TFont(f.left(commaPos), f.mid(commaPos + 1).toUInt())); 0393 } 0394 } 0395 } 0396 0397 if (!fonts.isEmpty()) { 0398 CPrinter(createParent(parser.value(embedOption).toInt(nullptr, 16))).print(fonts, size); 0399 0400 return 0; 0401 } 0402 } 0403 0404 return -1; 0405 }