1 /* This file is part of the KDE project
2 * Copyright (C) 2001-2007 by OpenMFG, LLC (info@openmfg.com)
3 * Copyright (C) 2007-2008 by Adam Pigg (adam@piggz.co.uk)
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "KReportHTMLCSSRenderer_p.h"
20 #include "KReportRenderObjects.h"
21 #include "kreport_debug.h"
22
23 #include <QTemporaryFile>
24 #include <QDir>
25 #include <QPainter>
26 #include <QString>
27
28 namespace KReportPrivate {
29
HTMLCSSRenderer()30 HTMLCSSRenderer::HTMLCSSRenderer()
31 {
32
33 }
34
~HTMLCSSRenderer()35 HTMLCSSRenderer::~HTMLCSSRenderer()
36 {
37
38 }
39
render(const KReportRendererContext & context,ORODocument * document,int page)40 bool HTMLCSSRenderer::render(const KReportRendererContext& context, ORODocument *document, int page)
41 {
42 Q_UNUSED(page);
43 QTemporaryFile tempHtmlFile; // auto removed by default on destruction
44 if (!tempHtmlFile.open()) {
45 kreportWarning() << "Couldn't create temporary file to write into";
46 return false;
47 }
48
49 QTextStream out(&tempHtmlFile);
50
51 QString dirSuffix = QLatin1String(".files");
52 QDir tempDir;
53 QFileInfo fi(tempHtmlFile);
54
55 QString tempFileName = fi.absoluteFilePath();
56 m_tempDirName = tempFileName + dirSuffix;
57 m_actualDirName = context.url().fileName() + dirSuffix;
58
59 if (!tempDir.mkpath(m_tempDirName))
60 return false;
61
62 out << renderCSS(document);
63
64 out.flush();
65 tempHtmlFile.close();
66
67 bool status = true; //!< @todo KIO
68 // if (KIO::NetAccess::upload(tempFileName, context.destinationUrl, 0) && KIO::NetAccess::dircopy(QUrl(m_tempDirName), QUrl(context.destinationUrl.url() + dirSuffix), 0)) {
69 // status = true;
70 // }
71
72 // cleanup the temporary directory
73 tempDir.setPath(m_tempDirName);
74 QStringList fileList = tempDir.entryList();
75 foreach(const QString& fileName, fileList) {
76 tempDir.remove(fileName);
77 }
78 tempDir.rmdir(m_tempDirName);
79
80 return status;
81 }
82
83 //! @todo use QTextStream for efficiency
renderCSS(ORODocument * document)84 QString HTMLCSSRenderer::renderCSS(ORODocument *document)
85 {
86 QString html;
87 QString body;
88 QString style;
89 QStringList styles;
90 int styleindex;
91 bool renderedPageHead = false;
92 bool renderedPageFoot = false;
93
94 QDir d(m_tempDirName);
95 // Render Each Section
96 for (int s = 0; s < document->sectionCount(); s++) {
97 OROSection *section = document->section(s);
98
99 if (section->type() == KReportSectionData::Type::GroupHeader
100 || section->type() == KReportSectionData::Type::GroupFooter
101 || section->type() == KReportSectionData::Type::Detail
102 || section->type() == KReportSectionData::Type::ReportHeader
103 || section->type() == KReportSectionData::Type::ReportFooter
104 || (section->type() == KReportSectionData::Type::PageHeaderAny && !renderedPageHead)
105 || (section->type() == KReportSectionData::Type::PageFooterAny && !renderedPageFoot
106 && s > document->sectionCount() - 2))
107 { // render the page foot right at the end, it
108 // will either be the last or second last
109 // section if there is a report footer
110 if (section->type() == KReportSectionData::Type::PageHeaderAny)
111 renderedPageHead = true;
112
113 if (section->type() == KReportSectionData::Type::PageFooterAny)
114 renderedPageFoot = true;
115
116 style = QLatin1String("position: relative; top: 0pt; left: 0pt; background-color: ") + section->backgroundColor().name() + QLatin1String("; height: ") + QString::number(section->height()) + QLatin1String("pt;");
117
118 if (!styles.contains(style)) {
119 styles << style;
120 }
121 styleindex = styles.indexOf(style);
122
123 body += QLatin1String("<div class=\"style") + QString::number(styleindex) + QLatin1String("\">\n");
124 //Render the objects in each section
125 for (int i = 0; i < section->primitiveCount(); i++) {
126 OROPrimitive * prim = section->primitive(i);
127 //kreportDebug() << "Got object type" << prim->type();
128 if (OROTextBox *tb = dynamic_cast<OROTextBox*>(prim)) {
129 QColor bg = tb->textStyle().backgroundColor;
130 style = QLatin1String("position: absolute; ") +
131 QLatin1String("background-color: ") + QString::fromLatin1("rgba(%1,%2,%3,%4)")
132 .arg(bg.red())
133 .arg(bg.green())
134 .arg(bg.blue())
135 .arg(0.01 * tb->textStyle().backgroundOpacity) +QLatin1String( "; ") +
136 QLatin1String("top: ") + QString::number(tb->position().y()) + QLatin1String("pt; ") +
137 QLatin1String("left: ") + QString::number(tb->position().x()) + QLatin1String("pt; ") +
138 QLatin1String("font-size: ") + QString::number(tb->textStyle().font.pointSize()) + QLatin1String("pt; ") +
139 QLatin1String("color: ") + tb->textStyle().foregroundColor.name() + QLatin1String("; ") +
140 QLatin1String("width: ") + QString::number(tb->size().width()) + QLatin1String("px;") +
141 QLatin1String("height: ") + QString::number(tb->size().height()) + QLatin1String("px;") ;
142 //! @todo opaque text + translucent background
143 //it looks a pain to implement
144 //http://developer.mozilla.org/en/docs/Useful_CSS_tips:Color_and_Background
145 //style += "filter:alpha(opacity=" + QString::number((tb->textStyle().bgOpacity / 255) * 100) + ");"; //ie opacity
146 //style += "opacity: " + QString::number(tb->textStyle().bgOpacity / 255.0) + ";";
147
148 if (!styles.contains(style)) {
149 styles << style;
150 }
151 styleindex = styles.indexOf(style);
152
153 body += QLatin1String("<div class=\"style") + QString::number(styleindex) + QLatin1String("\">") +
154 tb->text() +
155 QLatin1String("</div>\n");
156 } else if (OROImage *im = dynamic_cast<OROImage*>(prim)) {
157 style = QLatin1String("position: absolute; ") +
158 QLatin1String("top: ") + QString::number(im->position().y()) + QLatin1String("pt; ") +
159 QLatin1String("left: ") + QString::number(im->position().x()) + QLatin1String("pt; ");
160 if (!styles.contains(style)) {
161 styles << style;
162 }
163 styleindex = styles.indexOf(style);
164
165 body += QLatin1String("<div class=\"style") + QString::number(styleindex) + QLatin1String("\">") +
166 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>") +
167 QLatin1String("</div>\n");
168
169
170 im->image().save(m_tempDirName + QLatin1String("/object") + QString::number(s) + QString::number(i) + QLatin1String(".png"));
171 } else if (OROPicture *im = dynamic_cast<OROPicture*>(prim)) {
172 style = QLatin1String("position: absolute; ") +
173 QLatin1String("top: ") + QString::number(im->position().y()) + QLatin1String("pt; ") +
174 QLatin1String("left: ") + QString::number(im->position().x()) + QLatin1String("pt; ");
175 if (!styles.contains(style)) {
176 styles << style;
177 }
178 styleindex = styles.indexOf(style);
179
180 body += QLatin1String("<div class=\"style") + QString::number(styleindex) + QLatin1String("\">") +
181 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>") +
182 QLatin1String("</div>\n");
183
184 QImage image(im->size().toSize(), QImage::Format_RGB32);
185 QPainter painter(&image);
186 im->picture()->play(&painter);
187 image.save(m_tempDirName + QLatin1String("/object") + QString::number(s) + QString::number(i) + QLatin1String(".png"));
188 } else {
189 kreportWarning() << "unrecognized primitive type";
190 }
191 }
192 body += QLatin1String("</div>\n");
193 }
194 }
195
196 //! @todo add option for creating separate css file
197 html = QLatin1String("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n"
198 "<html>\n"
199 "<head>\n"
200 "<style type=\"text/css\">\n");
201
202 for (int i = 0; i < styles.count(); ++i) {
203 html += QLatin1String(".style") + QString::number(i) + QLatin1String("{") + styles[i] + QLatin1String("}\n");
204 }
205
206 html += QLatin1String("</style>\n") +
207 QLatin1String("<title>") + document->title() + QLatin1String("</title>\n") +
208 QLatin1String("<meta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\">\n") +
209 QLatin1String("<meta name=\"generator\" content=\"Kexi\">\n") +
210 QLatin1String("</head>\n") +
211 QLatin1String("<body>\n") +
212 body +
213 QLatin1String("\n</body>\n") +
214 QLatin1String("</html>\n");
215
216 return html;
217 }
218
219 }
220