File indexing completed on 2024-05-12 16:34:43

0001 /* This file is part of the KDE project
0002  * Copyright (C) 2008 Peter Simonsson <peter.simonsson@gmail.com>
0003  * Copyright (C) 2010-2014 Yue Liu <yue.liu@mail.com>
0004  *
0005  * This library is free software; you can redistribute it and/or
0006  * modify it under the terms of the GNU Library General Public
0007  * License as published by the Free Software Foundation; either
0008  * version 2 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  * Library General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU Library General Public License
0016  * along with this library; see the file COPYING.LIB.  If not, write to
0017  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018  * Boston, MA 02110-1301, USA.
0019  */
0020 
0021 #include "StencilShapeFactory.h"
0022 
0023 #include "StencilBoxDebug.h"
0024 
0025 #include <KoShape.h>
0026 #include <KoDrag.h>
0027 #include <KoShapeOdfSaveHelper.h>
0028 #include <KoOdf.h>
0029 #include <KoShapeLoadingContext.h>
0030 #include <KoShapeBasedDocumentBase.h>
0031 #include <KoOdfLoadingContext.h>
0032 #include <KoStore.h>
0033 #include <KoOdfReadStore.h>
0034 #include <KoXmlNS.h>
0035 #include <KoShapeRegistry.h>
0036 #include <SvgParser.h>
0037 #include <KoProperties.h>
0038 #include <KoShapeGroup.h>
0039 #include <KoShapeGroupCommand.h>
0040 
0041 #include <QMimeData>
0042 #include <QIODevice>
0043 #include <KArchive/kcompressiondevice.h>
0044 
0045 StencilShapeFactory::
0046 StencilShapeFactory(const QString& id,
0047                     const QString& name,
0048                     const KoProperties* props)
0049     : KoShapeFactoryBase(id, name)
0050     , m_properties(props)
0051 {
0052     // ensures ShapeCollectionDocker ignores the stencil shapes for now,
0053     // exclusively available by StencilBox
0054     setFamily("stencil");
0055 }
0056 
0057 StencilShapeFactory::
0058 ~StencilShapeFactory()
0059 {
0060     delete m_properties;
0061 }
0062 
0063 KoShape* StencilShapeFactory::
0064 createFromOdf(KoStore* store, KoDocumentResourceManager* documentRes) const
0065 {
0066     KoOdfReadStore odfStore(store);
0067     QString errorMessage;
0068     if (! odfStore.loadAndParse(errorMessage)) {
0069         errorStencilBox << "loading and parsing failed:" << errorMessage << endl;
0070         return 0;
0071     }
0072 
0073     KoXmlElement content = odfStore.contentDoc().documentElement();
0074     KoXmlElement realBody(KoXml::namedItemNS(content, KoXmlNS::office, "body"));
0075     if (realBody.isNull()) {
0076         errorStencilBox << "No body tag found!" << endl;
0077         return 0;
0078     }
0079 
0080     KoXmlElement body = KoXml::namedItemNS(realBody, KoXmlNS::office, "drawing");
0081     if (body.isNull()) {
0082         errorStencilBox << "No office:drawing tag found!" << endl;
0083         return 0;
0084     }
0085 
0086     KoXmlElement page = KoXml::namedItemNS(body, KoXmlNS::draw, "page");
0087     if (page.isNull()) {
0088         errorStencilBox << "No page found!" << endl;
0089         return 0;
0090     }
0091 
0092     KoXmlElement shapeElement = KoXml::namedItemNS(page, KoXmlNS::draw, "g");
0093     if (shapeElement.isNull()) {
0094         shapeElement = KoXml::namedItemNS(page, KoXmlNS::draw, "custom-shape");
0095         if (shapeElement.isNull()) {
0096             errorStencilBox << "draw:g or draw:custom-shape element not found!" << endl;
0097             return 0;
0098         }
0099     }
0100 
0101     KoOdfLoadingContext loadingContext(odfStore.styles(), odfStore.store());
0102     KoShapeLoadingContext context(loadingContext, documentRes);
0103 
0104     KoShapeRegistry* registry = KoShapeRegistry::instance();
0105     foreach (const QString & id, registry->keys()) {
0106         KoShapeFactoryBase* shapeFactory = registry->value(id);
0107         shapeFactory->newDocumentResourceManager(documentRes);
0108     }
0109 
0110     return KoShapeRegistry::instance()->createShapeFromOdf(shapeElement, context);
0111 }
0112 
0113 KoShape* StencilShapeFactory::
0114 createFromSvg(QIODevice* in, KoDocumentResourceManager* documentRes) const
0115 {
0116     if (!in->open(QIODevice::ReadOnly)) {
0117         debugStencilBox << "svg file open error";
0118         return 0;
0119     }
0120 
0121     int line, col;
0122     QString errormessage;
0123     KoXmlDocument inputDoc;
0124     const bool parsed = inputDoc.setContent(in, &errormessage, &line, &col);
0125     in->close();
0126 
0127     if (!parsed) {
0128         debugStencilBox << "Error while parsing file: "
0129         << "at line " << line << " column: " << col
0130         << " message: " << errormessage << endl;
0131         return 0;
0132     }
0133 
0134     SvgParser parser(documentRes);
0135     parser.setXmlBaseDir(id());
0136     QList<KoShape*> shapes = parser.parseSvg(inputDoc.documentElement());
0137     if (shapes.isEmpty())
0138         return 0;
0139     if (shapes.count() == 1)
0140         return shapes.first();
0141 
0142     KoShapeGroup *svgGroup = new KoShapeGroup;
0143     KoShapeGroupCommand cmd(svgGroup, shapes);
0144     cmd.redo();
0145 
0146     return svgGroup;
0147 }
0148 
0149 KoShape* StencilShapeFactory::
0150 createDefaultShape(KoDocumentResourceManager* documentResources) const
0151 {
0152     KoShape* shape = 0;
0153     KoStore* store = 0;
0154     QIODevice* in = 0;
0155     QString ext = id().mid(id().lastIndexOf('.')).toLower();
0156     if (ext == ".odg") {
0157         store = KoStore::createStore(id(), KoStore::Read);
0158         if (!store->bad()) {
0159             shape = createFromOdf(store, documentResources);
0160         }
0161         delete store;
0162     } else if (ext == ".svg") {
0163         in = new KCompressionDevice(id(), KCompressionDevice::None);
0164         shape = createFromSvg(in, documentResources);
0165         delete in;
0166     } else if (ext == ".svgz") {
0167         in = new KCompressionDevice(id(), KCompressionDevice::GZip);
0168         shape = createFromSvg(in, documentResources);
0169         delete in;
0170     } else {
0171         debugStencilBox << "stencil format" << ext << "unsupported";
0172     }
0173 
0174     if (shape) {
0175         if (m_properties->intProperty("keepAspectRatio") == 1)
0176             shape->setKeepAspectRatio(true);
0177     }
0178 
0179     return shape;
0180 }
0181 
0182 // StencilShapeFactory shouldn't participate element support detection
0183 bool StencilShapeFactory::
0184 supports(const KoXmlElement& e, KoShapeLoadingContext& context) const
0185 {
0186     Q_UNUSED(e);
0187     Q_UNUSED(context);
0188     return false;
0189 }