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 }