File indexing completed on 2024-05-12 04:43:22

0001 /* This file is part of the KDE project
0002    Copyright (C) 2012 by Dag Andersen (danders@get2net.dk)
0003 
0004    This library is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU Library General Public
0006    License as published by the Free Software Foundation; either
0007    version 2.1 of the License, or (at your option) any later version.
0008 
0009    This library is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012    Library General Public License for more details.
0013 
0014    You should have received a copy of the GNU Library General Public License
0015    along with this library; see the file COPYING.LIB.  If not, write to
0016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017    Boston, MA 02110-1301, USA.
0018 */
0019 
0020 #include "KoOdtFrameReportDocument.h"
0021 #include "KoOdtFrameReportPrimitive.h"
0022 #include "KReportRenderObjects.h"
0023 
0024 #include <KoOdfWriteStore.h>
0025 #include <KoXmlWriter.h>
0026 #include <KoStore.h>
0027 #include <KoOdfGraphicStyles.h>
0028 #include <KoGenStyles.h>
0029 #include <KoGenStyle.h>
0030 #include <KReportDpi.h>
0031 
0032 #include <QVarLengthArray>
0033 #include "kreport_debug.h"
0034 
0035 KoOdtFrameReportDocument::KoOdtFrameReportDocument()
0036     : manifestWriter(0)
0037 {
0038 }
0039 
0040 KoOdtFrameReportDocument::~KoOdtFrameReportDocument()
0041 {
0042     foreach (const QList<KoOdtFrameReportPrimitive*> &lst, m_pagemap) {
0043         foreach(KoOdtFrameReportPrimitive *p, lst) {
0044             delete p;
0045         }
0046     }
0047 }
0048 
0049 void KoOdtFrameReportDocument::setPageOptions(const ReportPageOptions &pageOptions)
0050 {
0051     m_pageOptions = pageOptions;
0052 }
0053 
0054 void KoOdtFrameReportDocument::startTable(OROSection* section)
0055 {
0056     Q_UNUSED(section);
0057 }
0058 
0059 void KoOdtFrameReportDocument::addPrimitive(KoOdtFrameReportPrimitive *data)
0060 {
0061     m_pagemap[data->pageNumber()].append( data);
0062 }
0063 
0064 QFile::FileError KoOdtFrameReportDocument::saveDocument(const QString& path)
0065 {
0066     // create output store
0067     KoStore *store = KoStore::createStore(path, KoStore::Write,
0068                                     "application/vnd.oasis.opendocument.text", KoStore::Zip);
0069     if (!store) {
0070         kreportWarning() << "Couldn't open the requested file.";
0071         return QFile::OpenError;
0072     }
0073 
0074     KoOdfWriteStore oasisStore(store);
0075     manifestWriter = oasisStore.manifestWriter("application/vnd.oasis.opendocument.text");
0076     if (!manifestWriter) {
0077         return QFile::NoError;
0078     }
0079     // save extra data like images...
0080     foreach (const QList<KoOdtFrameReportPrimitive*> &lst, m_pagemap) {
0081         foreach(KoOdtFrameReportPrimitive *p, lst) {
0082             p->saveData(store, manifestWriter);
0083         }
0084     }
0085     //kreportDebug()<<"data saved";
0086     KoGenStyles coll;
0087     createStyles(&coll); // create basic styles
0088     bool ok = createContent(&oasisStore, coll);
0089     if (ok) {
0090         // save styles to styles.xml
0091         ok = coll.saveOdfStylesDotXml(store, manifestWriter);
0092     }
0093     ok = oasisStore.closeManifestWriter() && ok;
0094     delete oasisStore.store();
0095     return ok ? QFile::NoError : QFile::WriteError;
0096 
0097 }
0098 
0099 void KoOdtFrameReportDocument::createStyles(KoGenStyles *coll)
0100 {
0101     // convert to inches
0102     qreal pw = m_pageOptions.widthPx() / KReportPrivate::dpiX();
0103     qreal ph = m_pageOptions.heightPx() / KReportPrivate::dpiY();
0104     qreal topMargin = m_pageOptions.getMarginTop() / KReportPrivate::dpiY();
0105     qreal bottomMargin = m_pageOptions.getMarginBottom() / KReportPrivate::dpiY();
0106     qreal leftMargin = m_pageOptions.getMarginLeft() / KReportPrivate::dpiX();
0107     qreal rightMargin = m_pageOptions.getMarginRight() / KReportPrivate::dpiX();
0108     QString orientation = m_pageOptions.isPortrait() ? "portrait" : "landscape";
0109 
0110     //kreportDebug()<<"Page:"<<pw<<ph<<orientation;
0111     //kreportDebug()<<"Margin:"<<topMargin<<bottomMargin<<leftMargin<<rightMargin;
0112     KoGenStyle page(KoGenStyle::PageLayoutStyle, "page-layout");
0113     page.addProperty("style:num-format", "1");
0114     page.addProperty("style:print-orientation", orientation);
0115     page.addProperty("style:writing-mode", "lr-tb");
0116     page.addProperty("style:footnote-max-height", "0cm");
0117 
0118     page.addProperty("fo:page-width", QString("%1in").arg(pw));
0119     page.addProperty("fo:page-height", QString("%1in").arg(ph));
0120     page.addProperty("fo:margin-top", QString("%1in").arg(topMargin));
0121     page.addProperty("fo:margin-bottom", QString("%1in").arg(bottomMargin));
0122     page.addProperty("fo:margin-left", QString("%1in").arg(leftMargin));
0123     page.addProperty("fo:margin-right", QString("%1in").arg(rightMargin));
0124     page.setAutoStyleInStylesDotXml(true);
0125     QString pagename = coll->insert(page, "pm");
0126 
0127     KoGenStyle master(KoGenStyle::MasterPageStyle, "master-page");
0128     master.addAttribute("style:page-layout-name", pagename);
0129     coll->insert(master, "Standard", KoGenStyles::DontAddNumberToName);
0130 
0131     KoGenStyle fs(KoGenStyle::GraphicStyle, "graphic");
0132     fs.addProperty("vertical-pos", "from-top");
0133     fs.addProperty("vertical-rel", "page");
0134     fs.addProperty("horizontal-pos", "from-left");
0135     fs.addProperty("horizontal-rel", "page");
0136     coll->insert(fs, "Frame", KoGenStyles::DontAddNumberToName);
0137 
0138     KoGenStyle ps(KoGenStyle::ParagraphStyle, "paragraph");
0139     ps.addAttribute("style:parent-style-name", "Standard");
0140     coll->insert(ps, "P1", KoGenStyles::DontAddNumberToName);
0141 }
0142 
0143 bool KoOdtFrameReportDocument::createContent(KoOdfWriteStore* store, KoGenStyles *coll)
0144 {
0145     KoXmlWriter* bodyWriter = store->bodyWriter();
0146     KoXmlWriter* contentWriter = store->contentWriter();
0147 
0148     if (!bodyWriter || !contentWriter || !manifestWriter) {
0149         kreportWarning()<<"Failed to created odt writer";
0150         return false;
0151     }
0152 
0153     // OpenDocument spec requires the manifest to include a list of the files in this package
0154     manifestWriter->addManifestEntry("content.xml",  "text/xml");
0155 //     manifestWriter->addManifestEntry("styles.xml",  "text/xml");
0156 
0157     contentWriter->startElement("office:automatic-styles");
0158 
0159     //new page
0160     contentWriter->startElement("style:style");
0161     contentWriter->addAttribute("style:name", "NewPage");
0162     contentWriter->addAttribute("style:master-page-name", "Standard");
0163     contentWriter->addAttribute("style:family", "paragraph");
0164     contentWriter->startElement("style:paragraph-properties");
0165     contentWriter->addAttribute("fo:font-family", "Arial");
0166     contentWriter->addAttribute("fo:break-before", "page"); // needed by LibreOffice
0167     contentWriter->endElement(); // style:paragraph-properties
0168     contentWriter->endElement(); // style:style
0169 
0170     contentWriter->startElement("text:sequence-decls");
0171     contentWriter->startElement("text:sequence-decl");
0172     contentWriter->addAttribute("text:display-outline-level", "0");
0173     contentWriter->addAttribute("text:name", "Illustration");
0174     contentWriter->endElement(); //text:sequence-decl
0175     contentWriter->startElement("text:sequence-decl");
0176     contentWriter->addAttribute("text:display-outline-level", "0");
0177     contentWriter->addAttribute("text:name", "Table");
0178     contentWriter->endElement(); //text:sequence-decl
0179     contentWriter->startElement("text:sequence-decl");
0180     contentWriter->addAttribute("text:display-outline-level", "0");
0181     contentWriter->addAttribute("text:name", "Text");
0182     contentWriter->endElement(); //text:sequence-decl
0183     contentWriter->startElement("text:sequence-decl");
0184     contentWriter->addAttribute("text:display-outline-level", "0");
0185     contentWriter->addAttribute("text:name", "Drawing");
0186     contentWriter->endElement(); //text:sequence-decl
0187     contentWriter->endElement(); //text:sequence-decls
0188     contentWriter->endElement(); // office:automatic-styles
0189 
0190     // office:body
0191     bodyWriter->startElement("office:body");
0192     bodyWriter->startElement("office:text");
0193 
0194     createPages(bodyWriter, coll);
0195 
0196     bodyWriter->endElement();  // office:text
0197     bodyWriter->endElement();  // office:body
0198 
0199     return store->closeContentWriter();
0200 }
0201 
0202 void KoOdtFrameReportDocument::createPages(KoXmlWriter* bodyWriter, KoGenStyles *coll)
0203 {
0204     QMap<int, QList<KoOdtFrameReportPrimitive*> >::const_iterator it;
0205     for (it = m_pagemap.constBegin(); it != m_pagemap.constEnd(); ++it) {
0206         bodyWriter->startElement("text:p");
0207         bodyWriter->addAttribute("text:style-name", "NewPage");
0208         // all frames need to be *inside* or else LibreWriter shows nothing
0209         foreach (KoOdtFrameReportPrimitive *data, it.value()) {
0210             data->createStyle(coll);
0211             data->createBody(bodyWriter);
0212         }
0213         bodyWriter->endElement(); // text:p
0214     }
0215     if (m_pagemap.isEmpty()) {
0216         // words crashes if there is no text element
0217         bodyWriter->startElement("text:p");
0218         bodyWriter->addAttribute("text:style-name", "P1");
0219         bodyWriter->endElement(); // text:p
0220     }
0221 }