File indexing completed on 2024-05-05 04:43:21

0001 /* This file is part of the KDE project
0002  * Copyright (C) 2001-2007 by OpenMFG, LLC (info@openmfg.com)
0003  * Copyright (C) 2007-2008 by Adam Pigg (adam@piggz.co.uk)
0004  *
0005  * This library is free software; you can redistribute it and/or
0006  * modify it under the terms of the GNU Lesser General Public
0007  * License as published by the Free Software Foundation; either
0008  * version 2.1 of the License, or (at your option) any later version.
0009  *
0010  * This library is distributed in the hope that it will be useful,
0011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0013  * Lesser General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU Lesser General Public
0016  * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
0017  */
0018 
0019 #include "KReportHTMLCSSRenderer_p.h"
0020 #include "KReportRenderObjects.h"
0021 #include "kreport_debug.h"
0022 
0023 #include <QTemporaryFile>
0024 #include <QDir>
0025 #include <QPainter>
0026 #include <QString>
0027 
0028 namespace KReportPrivate {
0029   
0030 HTMLCSSRenderer::HTMLCSSRenderer()
0031 {
0032 
0033 }
0034 
0035 HTMLCSSRenderer::~HTMLCSSRenderer()
0036 {
0037 
0038 }
0039 
0040 bool HTMLCSSRenderer::render(const KReportRendererContext& context, ORODocument *document, int page)
0041 {
0042     Q_UNUSED(page);
0043     QTemporaryFile tempHtmlFile; // auto removed by default on destruction
0044     if (!tempHtmlFile.open()) {
0045         kreportWarning() << "Couldn't create temporary file to write into";
0046         return false;
0047     }
0048 
0049     QTextStream out(&tempHtmlFile);
0050 
0051     QString dirSuffix = QLatin1String(".files");
0052     QDir tempDir;
0053     QFileInfo fi(tempHtmlFile);
0054 
0055     QString tempFileName = fi.absoluteFilePath();
0056     m_tempDirName = tempFileName + dirSuffix;
0057     m_actualDirName = context.url().fileName() + dirSuffix;
0058 
0059     if (!tempDir.mkpath(m_tempDirName))
0060         return false;
0061 
0062     out << renderCSS(document);
0063 
0064     out.flush();
0065     tempHtmlFile.close();
0066 
0067     bool status = true; //!< @todo KIO
0068 //    if (KIO::NetAccess::upload(tempFileName, context.destinationUrl, 0) && KIO::NetAccess::dircopy(QUrl(m_tempDirName),  QUrl(context.destinationUrl.url() + dirSuffix), 0)) {
0069 //        status = true;
0070 //    }
0071 
0072     // cleanup the temporary directory
0073     tempDir.setPath(m_tempDirName);
0074     QStringList fileList = tempDir.entryList();
0075     foreach(const QString& fileName, fileList) {
0076         tempDir.remove(fileName);
0077     }
0078     tempDir.rmdir(m_tempDirName);
0079 
0080     return status;
0081 }
0082 
0083 //! @todo use QTextStream for efficiency
0084 QString HTMLCSSRenderer::renderCSS(ORODocument *document)
0085 {
0086     QString html;
0087     QString body;
0088     QString style;
0089     QStringList styles;
0090     int styleindex;
0091     bool renderedPageHead = false;
0092     bool renderedPageFoot = false;
0093 
0094     QDir d(m_tempDirName);
0095     // Render Each Section
0096     for (int s = 0; s < document->sectionCount(); s++) {
0097         OROSection *section = document->section(s);
0098 
0099         if (section->type() == KReportSectionData::Type::GroupHeader
0100             || section->type() == KReportSectionData::Type::GroupFooter
0101             || section->type() == KReportSectionData::Type::Detail
0102             || section->type() == KReportSectionData::Type::ReportHeader
0103             || section->type() == KReportSectionData::Type::ReportFooter
0104             || (section->type() == KReportSectionData::Type::PageHeaderAny && !renderedPageHead)
0105             || (section->type() == KReportSectionData::Type::PageFooterAny && !renderedPageFoot
0106                 && s > document->sectionCount() - 2))
0107         { // render the page foot right at the end, it
0108           // will either be the last or second last
0109           // section if there is a report footer
0110             if (section->type() == KReportSectionData::Type::PageHeaderAny)
0111                 renderedPageHead = true;
0112 
0113             if (section->type() == KReportSectionData::Type::PageFooterAny)
0114                 renderedPageFoot = true;
0115 
0116             style = QLatin1String("position: relative; top: 0pt; left: 0pt; background-color: ") + section->backgroundColor().name() + QLatin1String("; height: ") + QString::number(section->height()) + QLatin1String("pt;");
0117 
0118             if (!styles.contains(style)) {
0119                 styles << style;
0120             }
0121             styleindex = styles.indexOf(style);
0122 
0123             body += QLatin1String("<div class=\"style") + QString::number(styleindex) + QLatin1String("\">\n");
0124             //Render the objects in each section
0125             for (int i = 0; i < section->primitiveCount(); i++) {
0126                 OROPrimitive * prim = section->primitive(i);
0127                 //kreportDebug() << "Got object type" << prim->type();
0128                 if (OROTextBox *tb = dynamic_cast<OROTextBox*>(prim)) {
0129                     QColor bg = tb->textStyle().backgroundColor;
0130                     style = QLatin1String("position: absolute; ") +
0131                             QLatin1String("background-color: ") + QString::fromLatin1("rgba(%1,%2,%3,%4)")
0132                                                             .arg(bg.red())
0133                                                             .arg(bg.green())
0134                                                             .arg(bg.blue())
0135                                                             .arg(0.01 * tb->textStyle().backgroundOpacity) +QLatin1String( "; ") +
0136                             QLatin1String("top: ") + QString::number(tb->position().y()) + QLatin1String("pt; ") +
0137                             QLatin1String("left: ") + QString::number(tb->position().x()) + QLatin1String("pt; ") +
0138                             QLatin1String("font-size: ") + QString::number(tb->textStyle().font.pointSize()) + QLatin1String("pt; ") +
0139                             QLatin1String("color: ") + tb->textStyle().foregroundColor.name() + QLatin1String("; ") +
0140                             QLatin1String("width: ") + QString::number(tb->size().width()) + QLatin1String("px;") +
0141                             QLatin1String("height: ") + QString::number(tb->size().height()) + QLatin1String("px;") ;
0142                     //! @todo opaque text + translucent background
0143                     //it looks a pain to implement
0144                     //http://developer.mozilla.org/en/docs/Useful_CSS_tips:Color_and_Background
0145                     //style += "filter:alpha(opacity=" + QString::number((tb->textStyle().bgOpacity / 255) * 100) + ");"; //ie opacity
0146                     //style += "opacity: " + QString::number(tb->textStyle().bgOpacity / 255.0) + ";";
0147 
0148                     if (!styles.contains(style)) {
0149                         styles << style;
0150                     }
0151                     styleindex = styles.indexOf(style);
0152 
0153                     body += QLatin1String("<div class=\"style") + QString::number(styleindex) + QLatin1String("\">") +
0154                             tb->text() +
0155                             QLatin1String("</div>\n");
0156                 } else if (OROImage *im = dynamic_cast<OROImage*>(prim)) {
0157                     style = QLatin1String("position: absolute; ") +
0158                             QLatin1String("top: ") + QString::number(im->position().y()) + QLatin1String("pt; ") +
0159                             QLatin1String("left: ") + QString::number(im->position().x()) + QLatin1String("pt; ");
0160                     if (!styles.contains(style)) {
0161                         styles << style;
0162                     }
0163                     styleindex = styles.indexOf(style);
0164 
0165                     body += QLatin1String("<div class=\"style") + QString::number(styleindex) + QLatin1String("\">") +
0166                             QLatin1String("<img width=\"") + QString::number(im->size().width()) + QLatin1String("px") + QLatin1String("\" height=\"") + QString::number(im->size().height()) + QLatin1String("px") + QLatin1String("\" src=\"./") + m_actualDirName + QLatin1String("/object") + QString::number(s) + QString::number(i) + QLatin1String(".png\"></img>") +
0167                             QLatin1String("</div>\n");
0168 
0169 
0170                     im->image().save(m_tempDirName + QLatin1String("/object") + QString::number(s) + QString::number(i) + QLatin1String(".png"));
0171                 } else if (OROPicture *im = dynamic_cast<OROPicture*>(prim)) {
0172                     style = QLatin1String("position: absolute; ") +
0173                             QLatin1String("top: ") + QString::number(im->position().y()) + QLatin1String("pt; ") +
0174                             QLatin1String("left: ") + QString::number(im->position().x()) + QLatin1String("pt; ");
0175                     if (!styles.contains(style)) {
0176                         styles << style;
0177                     }
0178                     styleindex = styles.indexOf(style);
0179 
0180                     body += QLatin1String("<div class=\"style") + QString::number(styleindex) + QLatin1String("\">") +
0181                             QLatin1String("<img width=\"") + QString::number(im->size().width()) + QLatin1String("px") + QLatin1String("\" height=\"") + QString::number(im->size().height()) + QLatin1String("px") + QLatin1String("\" src=\"./") + m_actualDirName + QLatin1String("/object") + QString::number(s) + QString::number(i) + QLatin1String(".png\"></img>") +
0182                             QLatin1String("</div>\n");
0183 
0184                     QImage image(im->size().toSize(), QImage::Format_RGB32);
0185                     QPainter painter(&image);
0186                     im->picture()->play(&painter);
0187                     image.save(m_tempDirName + QLatin1String("/object") + QString::number(s) + QString::number(i) + QLatin1String(".png"));
0188                 } else {
0189                     kreportWarning() << "unrecognized primitive type";
0190                 }
0191             }
0192             body += QLatin1String("</div>\n");
0193         }
0194     }
0195 
0196     //! @todo add option for creating separate css file
0197     html = QLatin1String("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n"
0198         "<html>\n"
0199         "<head>\n"
0200         "<style type=\"text/css\">\n");
0201 
0202     for (int i = 0; i < styles.count(); ++i) {
0203         html += QLatin1String(".style") + QString::number(i) + QLatin1String("{") + styles[i] + QLatin1String("}\n");
0204     }
0205 
0206     html += QLatin1String("</style>\n") +
0207         QLatin1String("<title>") + document->title() + QLatin1String("</title>\n") +
0208         QLatin1String("<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\">\n") +
0209         QLatin1String("<meta name=\"generator\" content=\"Kexi\">\n") +
0210         QLatin1String("</head>\n") +
0211         QLatin1String("<body>\n") +
0212         body +
0213         QLatin1String("\n</body>\n") +
0214         QLatin1String("</html>\n");
0215 
0216     return html;
0217 }
0218 
0219 }