File indexing completed on 2024-12-29 04:47:03

0001 /*
0002   This file is part of KAddressBook.
0003   SPDX-FileCopyrightText: 1996-2002 Mirko Boehm <mirko@kde.org>
0004   SPDX-FileCopyrightText: 2009 Tobias Koenig <tokoe@kde.org>
0005 
0006   SPDX-License-Identifier: GPL-2.0-or-later WITH Qt-Commercial-exception-1.0
0007 */
0008 
0009 #include "detailledstyle.h"
0010 
0011 #include "printingwizard.h"
0012 #include "printprogress.h"
0013 #include "printstyle.h"
0014 #include "ui_ds_appearance.h"
0015 
0016 #include <KConfig>
0017 #include <KConfigGroup>
0018 #include <KLocalizedString>
0019 #include <KSharedConfig>
0020 #include <QCheckBox>
0021 #include <QLocale>
0022 #include <QPrinter>
0023 #include <QTextDocument>
0024 
0025 using namespace KABPrinting;
0026 
0027 static const char ConfigSectionName[] = "DetailedPrintStyle";
0028 static const char ContactHeaderForeColor[] = "ContactHeaderForeColor";
0029 static const char ContactHeaderBGColor[] = "ContactHeaderBGColor";
0030 
0031 struct ContactBlock {
0032     using List = QList<ContactBlock>;
0033 
0034     QString header;
0035     QStringList entries;
0036 };
0037 
0038 struct ColorSettings {
0039     QString headerTextColor;
0040     QString headerBackgroundColor;
0041 };
0042 
0043 QString contactsToHtml(const KContacts::Addressee::List &contacts, const ColorSettings &settings)
0044 {
0045     QString content = QStringLiteral("<html>\n");
0046     content += QLatin1StringView(" <head>\n");
0047     content += QLatin1StringView("  <style type=\"text/css\">\n");
0048     content += QLatin1StringView("    td.indented {\n");
0049     content += QLatin1StringView("      padding-left: 20px;\n");
0050     content += QLatin1StringView("      font-family: Fixed, monospace;\n");
0051     content += QLatin1StringView("    }\n");
0052     content += QLatin1StringView("  </style>\n");
0053     content += QLatin1StringView(" </head>\n");
0054     content += QLatin1StringView(" <body>\n");
0055     ContactBlock::List blocks;
0056     for (const KContacts::Addressee &contact : contacts) {
0057         blocks.clear();
0058         QString name = contact.realName();
0059         if (!contact.title().isEmpty() || !contact.role().isEmpty()) {
0060             QStringList contentAddress;
0061             if (!contact.title().isEmpty()) {
0062                 contentAddress << contact.title();
0063             }
0064             if (!contact.role().isEmpty()) {
0065                 contentAddress << contact.role();
0066             }
0067             name += QStringLiteral(" (%1)").arg(contentAddress.join(QStringLiteral(", ")));
0068         }
0069 
0070         const QString birthday = QLocale().toString(contact.birthday().date(), QLocale::ShortFormat);
0071 
0072         if (!contact.organization().isEmpty()) {
0073             ContactBlock block;
0074             block.header = i18n("Organization:");
0075             block.entries.append(contact.organization());
0076 
0077             blocks.append(block);
0078         }
0079 
0080         if (!contact.emails().isEmpty()) {
0081             ContactBlock block;
0082             block.header = (contact.emails().count() == 1 ? i18n("Email address:") : i18n("Email addresses:"));
0083             block.entries = contact.emails();
0084 
0085             blocks.append(block);
0086         }
0087 
0088         if (!contact.phoneNumbers().isEmpty()) {
0089             const KContacts::PhoneNumber::List numbers = contact.phoneNumbers();
0090 
0091             ContactBlock block;
0092             block.header = (numbers.count() == 1 ? i18n("Telephone:") : i18n("Telephones:"));
0093 
0094             for (const KContacts::PhoneNumber &number : numbers) {
0095                 const QString line = number.typeLabel() + QLatin1StringView(": ") + number.number();
0096                 block.entries.append(line);
0097             }
0098 
0099             blocks.append(block);
0100         }
0101 
0102         if (contact.url().isValid()) {
0103             ContactBlock block;
0104             block.header = i18n("Web page:");
0105             block.entries.append(contact.url().url().toDisplayString());
0106 
0107             blocks.append(block);
0108         }
0109 
0110         if (!contact.addresses().isEmpty()) {
0111             const KContacts::Address::List addresses = contact.addresses();
0112 
0113             for (const KContacts::Address &address : addresses) {
0114                 ContactBlock block;
0115 
0116                 switch (address.type()) {
0117                 case KContacts::Address::Dom:
0118                     block.header = i18n("Domestic Address");
0119                     break;
0120                 case KContacts::Address::Intl:
0121                     block.header = i18n("International Address");
0122                     break;
0123                 case KContacts::Address::Postal:
0124                     block.header = i18n("Postal Address");
0125                     break;
0126                 case KContacts::Address::Parcel:
0127                     block.header = i18n("Parcel Address");
0128                     break;
0129                 case KContacts::Address::Home:
0130                     block.header = i18n("Home Address");
0131                     break;
0132                 case KContacts::Address::Work:
0133                     block.header = i18n("Work Address");
0134                     break;
0135                 case KContacts::Address::Pref:
0136                 default:
0137                     block.header = i18n("Preferred Address");
0138                 }
0139                 block.header += QLatin1Char(':');
0140 
0141                 block.entries = address.formatted(KContacts::AddressFormatStyle::Postal).split(QLatin1Char('\n'), Qt::KeepEmptyParts);
0142                 blocks.append(block);
0143             }
0144         }
0145 
0146         if (!contact.note().isEmpty()) {
0147             ContactBlock block;
0148             block.header = i18n("Notes:");
0149             block.entries = contact.note().split(QLatin1Char('\n'), Qt::KeepEmptyParts);
0150 
0151             blocks.append(block);
0152         }
0153 
0154         // add header
0155         content += QLatin1StringView(
0156             "  <table style=\"border-width: 0px; border-spacing: 0px; "
0157             "page-break-inside: avoid\" cellspacing=\"0\" cellpadding=\"0\" width=\"100%\">\n");
0158         content += QLatin1StringView("   <tr>\n");
0159         content += QLatin1StringView("    <td style=\"color: ") + settings.headerTextColor + QLatin1StringView(";\" bgcolor=\"")
0160             + settings.headerBackgroundColor + QLatin1StringView(R"(" style="padding-left: 20px">)") + name + QLatin1StringView("</td>\n");
0161         content += QLatin1StringView("    <td style=\"color: ") + settings.headerTextColor + QLatin1StringView(R"(;" align="right" bgcolor=")")
0162             + settings.headerBackgroundColor + QLatin1StringView(R"(" style="padding-right: 20px">)") + birthday + QLatin1StringView("</td>\n");
0163         content += QLatin1StringView("   </tr>\n");
0164 
0165         for (int i = 0; i < blocks.count(); i += 2) {
0166             // add empty line for spacing
0167             content += QLatin1StringView("   <tr>\n");
0168             content += QLatin1StringView("    <td>&nbsp;</td>\n");
0169             content += QLatin1StringView("    <td>&nbsp;</td>\n");
0170             content += QLatin1StringView("   </tr>\n");
0171 
0172             // add real block data
0173             const ContactBlock leftBlock = blocks.at(i);
0174             const ContactBlock rightBlock = ((i + 1 < blocks.count()) ? blocks.at(i + 1) : ContactBlock());
0175 
0176             content += QLatin1StringView("   <tr>\n");
0177             content += QLatin1StringView("    <td>") + leftBlock.header + QLatin1StringView("</td>\n");
0178             content += QLatin1StringView("    <td>") + rightBlock.header + QLatin1StringView("</td>\n");
0179             content += QLatin1StringView("   </tr>\n");
0180 
0181             const int maxLines = qMax(leftBlock.entries.count(), rightBlock.entries.count());
0182             for (int j = 0; j < maxLines; ++j) {
0183                 QString leftLine;
0184                 QString rightLine;
0185 
0186                 if (j < leftBlock.entries.count()) {
0187                     leftLine = leftBlock.entries.at(j);
0188                 }
0189 
0190                 if (j < rightBlock.entries.count()) {
0191                     rightLine = rightBlock.entries.at(j);
0192                 }
0193 
0194                 content += QLatin1StringView("   <tr>\n");
0195                 content += QLatin1StringView("    <td class=\"indented\">") + leftLine + QLatin1StringView("</td>\n");
0196                 content += QLatin1StringView("    <td class=\"indented\">") + rightLine + QLatin1StringView("</td>\n");
0197                 content += QLatin1StringView("   </tr>\n");
0198             }
0199         }
0200 
0201         // add empty line for spacing
0202         content += QLatin1StringView("   <tr>\n");
0203         content += QLatin1StringView("    <td>&nbsp;</td>\n");
0204         content += QLatin1StringView("    <td>&nbsp;</td>\n");
0205         content += QLatin1StringView("   </tr>\n");
0206         content += QLatin1StringView("  </table>\n");
0207     }
0208     content += QLatin1StringView(" </body>\n");
0209     content += QLatin1StringView("</html>\n");
0210 
0211     return content;
0212 }
0213 
0214 class KABPrinting::AppearancePage : public QWidget, public Ui::AppearancePage_Base
0215 {
0216 public:
0217     explicit AppearancePage(QWidget *parent)
0218         : QWidget(parent)
0219     {
0220         setupUi(this);
0221         setObjectName(QLatin1StringView("AppearancePage"));
0222     }
0223 };
0224 
0225 DetailledPrintStyle::DetailledPrintStyle(PrintingWizard *parent)
0226     : PrintStyle(parent)
0227     , mPageAppearance(new AppearancePage(parent))
0228 {
0229     setPreview(QStringLiteral("detailed-style.png"));
0230     setPreferredSortOptions(KAddressBookImportExport::ContactFields::FormattedName, Qt::AscendingOrder);
0231 
0232     addPage(mPageAppearance, i18n("Detailed Print Style - Appearance"));
0233 
0234     KConfigGroup config(KSharedConfig::openConfig(), QLatin1StringView(ConfigSectionName));
0235 
0236     mPageAppearance->kcbHeaderBGColor->setColor(config.readEntry(ContactHeaderBGColor, QColor(Qt::black)));
0237 
0238     mPageAppearance->kcbHeaderTextColor->setColor(config.readEntry(ContactHeaderForeColor, QColor(Qt::white)));
0239 }
0240 
0241 DetailledPrintStyle::~DetailledPrintStyle() = default;
0242 
0243 void DetailledPrintStyle::print(const KContacts::Addressee::List &contacts, PrintProgress *progress)
0244 {
0245     progress->addMessage(i18n("Setting up colors"));
0246     progress->setProgress(0);
0247 
0248     const QColor headerBackgroundColor = mPageAppearance->kcbHeaderBGColor->color();
0249     const QColor headerForegroundColor = mPageAppearance->kcbHeaderTextColor->color();
0250 
0251     KConfigGroup config(KSharedConfig::openConfig(), QLatin1StringView(ConfigSectionName));
0252     config.writeEntry(ContactHeaderForeColor, headerForegroundColor);
0253     config.writeEntry(ContactHeaderBGColor, headerBackgroundColor);
0254     config.sync();
0255 
0256     ColorSettings settings;
0257     settings.headerBackgroundColor = headerBackgroundColor.name();
0258     settings.headerTextColor = headerForegroundColor.name();
0259 
0260     QPrinter *printer = wizard()->printer();
0261 
0262     progress->addMessage(i18n("Setting up document"));
0263 
0264     const QString html = contactsToHtml(contacts, settings);
0265 
0266     QTextDocument document;
0267     document.setHtml(html);
0268 
0269     progress->addMessage(i18n("Printing"));
0270 
0271     document.print(printer);
0272 
0273     progress->addMessage(i18nc("Finished printing", "Done"));
0274 }
0275 
0276 DetailledPrintStyleFactory::DetailledPrintStyleFactory(PrintingWizard *parent)
0277     : PrintStyleFactory(parent)
0278 {
0279 }
0280 
0281 PrintStyle *DetailledPrintStyleFactory::create() const
0282 {
0283     return new DetailledPrintStyle(mParent);
0284 }
0285 
0286 QString DetailledPrintStyleFactory::description() const
0287 {
0288     return i18n("Detailed Style");
0289 }
0290 
0291 #include "moc_detailledstyle.cpp"