Warning, file /office/calligra/libs/kross/KoScriptingOdf.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /***************************************************************************
0002  * KoScriptingOdf.h
0003  * This file is part of the KDE project
0004  * copyright (C) 2007 Sebastian Sauer <mail@dipe.org>
0005  *
0006  * This program is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Library General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2 of the License, or (at your option) any later version.
0010  *
0011  * This program is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Library General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Library General Public License
0017  * along with this program; see the file COPYING.  If not, write to
0018  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020  ***************************************************************************/
0021 
0022 #ifndef KOSCRIPTINGODF_H
0023 #define KOSCRIPTINGODF_H
0024 
0025 #include <QPair>
0026 #include <KoXmlReader.h>
0027 #include <KoDocument.h>
0028 
0029 class KoScriptingOdfStore;
0030 class KoPartAdaptor;
0031 
0032 /**
0033 * The KoScriptingOdfReader provides functionality to read content
0034 * from a KoStore.
0035 *
0036 * The following python samples does open the content.xml file and
0037 * reads all text:p elements from it;
0038 * \code
0039 * import Kross, Words
0040 * Words.document().openUrl("/home/kde4/testDoc.odt")
0041 * reader = Words.store().open("META-INF/manifest.xml")
0042 * reader = store.open("content.xml")
0043 * def onElement():
0044 *     if reader.name() != "text:p":
0045 *         raise "This should never happen cause of the filter"
0046 *     print "%s %s" % (reader.level(),reader.attributeNames())
0047 * reader.connect("onElement()", onElement)
0048 * reader.setNameFilter("text:p")
0049 * reader.start()
0050 * \endcode
0051 */
0052 class KoScriptingOdfReader : public QObject
0053 {
0054     Q_OBJECT
0055 public:
0056     /** Constructor. */
0057     explicit KoScriptingOdfReader(KoScriptingOdfStore *store, const KoXmlDocument &doc);
0058     /** Destructor. */
0059     ~KoScriptingOdfReader() override;
0060     /** Return the KoScriptingOdfStore instance this reader belongs to. */
0061     KoScriptingOdfStore *store() const;
0062     /** Return the KoXmlDocument instance this reader operates on. */
0063     KoXmlDocument doc() const;
0064     /** Return the current element. */
0065     KoXmlElement currentElement() const;
0066 
0067 public Q_SLOTS:
0068 
0069     /**
0070     * Return the element tag-name filter that will be applied on reading.
0071     */
0072     QString nameFilter() const;
0073 
0074     /**
0075     * Set the element tag-name filter that will be applied on reading.
0076     *
0077     * This python sample demonstrates usage of the setNameFilter()-method;
0078     * \code
0079     * # Only handle text:p elements.
0080     * reader.setNameFilter("text:p")
0081     *
0082     * # Use a regular expression for the tag-name.
0083     * reader.setNameFilter(".*:p", True)
0084     * \endcode
0085     */
0086     void setNameFilter(const QString &name = QString(), bool regularExpression = false);
0087 
0088     //QString levelFilter() const;
0089     //void setLevelFilter(const QString &name = QString()) const;
0090 
0091     /**
0092     * Start the reading.
0093     *
0094     * This will fire up the whole reading process. We walk through
0095     * all elements and emit the onElement() signal or other signals
0096     * for each element we are interested in.
0097     */
0098     void start();
0099 
0100     /**
0101     * Return the tag-name of the current element. This could be
0102     * e.g. "office:text", "style:style" or "text:p".
0103     */
0104     QString name() const;
0105 
0106     /**
0107     * The namespace of the element. For example "office:document-content".
0108     */
0109     QString namespaceURI() const;
0110 
0111     //QString prefix() const { return m_currentElement.prefix(); }
0112     //QString localName() const { return m_currentElement.localName(); }
0113 
0114     /**
0115     * The level the element is on. Elements may nested and the level is
0116     * a number that defines how much elements are around this element.
0117     * The root-element has a level of 0, direct children of the
0118     * root-element have a level of 1, there children of 2, etc.
0119     */
0120     int level() const;
0121 #ifndef KOXML_USE_QDOM
0122     /**
0123     * Return a list of attribute-names the element has. This could be
0124     * for example "text:style-name".
0125     */
0126     QStringList attributeNames();
0127 #endif
0128 
0129     /**
0130     * Return the value of the attribute with the name \p name .
0131     */
0132     QString attribute(const QString &name, const QString &defaultValue = QString()) const;
0133 
0134     /**
0135     * Return the value of the attribute with the name \p name that is within
0136     * the namespace \p namespaceURI .
0137     */
0138     QString attributeNS(const QString &namespaceURI, const QString &localName, const QString &defaultValue = QString()) const;
0139 
0140     /**
0141     * Returns true if the current element has an attribute with name \p name.
0142     */
0143     bool hasAttribute(const QString &name) const;
0144 
0145     /**
0146     * Returns true if the current element has an attribute with name \p name that
0147     * is within the namespace \p namespaceURI .
0148     */
0149     bool hasAttributeNS(const QString &namespaceURI, const QString &localName) const;
0150 
0151     /**
0152     * Returns true if the current element is invalid.
0153     */
0154     bool isNull() const;
0155 
0156     /**
0157     * Return true if the current element is an element.
0158     */
0159     bool isElement() const;
0160 
0161     //bool isText() const;
0162     //bool isCDATASection() const { return m_currentElement.isCDATASection(); }
0163     //bool isDocument() const { return m_currentElement.isDocument(); }
0164     //QString toText() const { return m_currentElement.toText().data(); }
0165     //KoXmlCDATASection toCDATASection() const;
0166 
0167     /**
0168     * Return true if the current element has child nodes. Please note, that
0169     * text-nodes are not counted as children by this method. Fetch any text
0170     * by using the text() method which will return an empty string if there
0171     * is actually no text.
0172     */
0173     bool hasChildren() const;
0174 
0175     /**
0176     * Return the content of the element as string.
0177     */
0178     QString text() const;
0179 
0180 Q_SIGNALS:
0181 
0182     /**
0183     * This signal got emitted after start() was called for each
0184     * element we read.
0185     */
0186     void onElement();
0187 
0188 protected:
0189     /** Emit the onElement signal above. */
0190     void emitOnElement();
0191     /** Set the current element. */
0192     void setCurrentElement(const KoXmlElement &elem);
0193     /** Set the level. */
0194     void setLevel(int level);
0195     /** Element-handler. */
0196     virtual void handleElement(KoXmlElement &elem, int level = 0);
0197 
0198 private:
0199     KoScriptingOdfStore *m_store;
0200     KoXmlDocument m_doc;
0201     KoXmlElement m_currentElement;
0202     int m_level;
0203     QString m_filter;
0204     QRegExp m_filterRegExp;
0205 };
0206 
0207 /**
0208 * The KoScriptingOdfManifestReader class handles reading ODF META-INF/manifest.xml files.
0209 *
0210 * The following python sample script does use the Words scripting module to load a
0211 * ISO OpenDocument Text file and print the content of the manifest-file to stdout;
0212 * \code
0213 * import Kross, Words
0214 * Words.document().openUrl("/home/kde4/testDoc.odt")
0215 * reader = Words.store().open("META-INF/manifest.xml")
0216 * if not reader:
0217 *     raise "Failed to read the mainfest"
0218 * for i in range( reader.count() ):
0219 *     print "%s %s" % (reader.type(i),reader.path(i))
0220 * \endcode
0221 */
0222 class KoScriptingOdfManifestReader : public KoScriptingOdfReader
0223 {
0224     Q_OBJECT
0225 public:
0226     /** Constructor. */
0227     KoScriptingOdfManifestReader(KoScriptingOdfStore *store, const KoXmlDocument &doc);
0228     /** Destructor. */
0229     ~KoScriptingOdfManifestReader() override {}
0230 
0231 public Q_SLOTS:
0232     /** Returns the number of file-entries the manifest has. */
0233     int count() const {
0234         return m_entries.count();
0235     }
0236     /** Returns the type of the file-entry. This could be for example
0237     something like "text/xml" or "application/vnd.oasis.opendocument.text" */
0238     QString type(int index) {
0239         return m_entries.value(index).first;
0240     }
0241     /** Return the path of the file-entry. This could be for example
0242     something like "/", "content.xml" or "styles.xml". */
0243     QString path(int index) {
0244         return m_entries.value(index).second;
0245     }
0246     /**
0247     * Return a list of paths for the defined type. If not type is defined
0248     * just all paths are returned.
0249     *
0250     * Python sample that does use the paths-method;
0251     * \code
0252     * # Following may print ['/','content.xml','styles.xml']
0253     * print reader.paths()
0254     *
0255     * # Following may print ['content.xml','styles.xml']
0256     * print reader.paths("text/xml")
0257     * \endcode
0258     */
0259     QStringList paths(const QString &type = QString()) const;
0260 private:
0261     QList<QPair<QString,QString> > m_entries;
0262 };
0263 
0264 /**
0265 * The KoScriptingOdfManifestReader class handles reading ODF styles.xml files.
0266 */
0267 class KoScriptingOdfStylesReader : public KoScriptingOdfReader
0268 {
0269     Q_OBJECT
0270 public:
0271     /** Constructor. */
0272     KoScriptingOdfStylesReader(KoScriptingOdfStore *store, const KoXmlDocument &doc);
0273     /** Destructor. */
0274     ~KoScriptingOdfStylesReader() override {}
0275 public Q_SLOTS:
0276     //QString style(const QString &styleName);
0277 };
0278 
0279 /**
0280 * The KoScriptingOdfManifestReader class handles reading ODF content.xml files.
0281 */
0282 class KoScriptingOdfContentReader : public KoScriptingOdfReader
0283 {
0284     Q_OBJECT
0285 public:
0286     /** Constructor. */
0287     KoScriptingOdfContentReader(KoScriptingOdfStore *store, const KoXmlDocument &doc);
0288     /** Destructor. */
0289     ~KoScriptingOdfContentReader() override {}
0290 public Q_SLOTS:
0291     //QStringList headers(const QString &filter);
0292     //QStringList lists(const QString &filter);
0293     //QStringList images(const QString &filter);
0294     //QStringList tables(const QString &filter);
0295 };
0296 
0297 /**
0298 * The KoScriptingOdfStore class provides access to the KoStore functionality.
0299 *
0300 * The following python sample does use Words do read a ODT document and then
0301 * flushes the DOM tree to stdout.
0302 * \code
0303 * import Kross
0304 * Words = Kross.module("words")
0305 *
0306 * # Get the Words KoApplicationAdaptor instance.
0307 * docAdaptor = Words.document()
0308 * # Open an ISO OpenDocument Text File.
0309 * docAdaptor.openUrl("/home/kde4/testDoc.odt")
0310 *
0311 * # Get a KoStore instance.
0312 * store = Words.store()
0313 * # Open the content.xml file within the KoStore.
0314 * reader = store.open("content.xml")
0315 * if not reader:
0316 *     raise "Failed to read file from the store"
0317 *
0318 * # This function got called for each element
0319 * def onElement(name, level):
0320 *     print "ELEMENT name=%s level=%s" % (name, level)
0321 * # Connect our callback function with the reader.
0322 * reader.connect("onElement(QString,int)", onElement)
0323 *
0324 * # Start the reading.
0325 * reader.start()
0326 * \endcode
0327 */
0328 class KoScriptingOdfStore : public QObject
0329 {
0330     Q_OBJECT
0331 public:
0332     /** Constructor. */
0333     explicit KoScriptingOdfStore(QObject *parent, KoDocument *doc);
0334     /** Destructor. */
0335     ~KoScriptingOdfStore() override;
0336 
0337     //KoStore* readStore() const;
0338     //QIODevice* readDevice() const;
0339 
0340 public Q_SLOTS:
0341 
0342     /**
0343     * Returns true if there exists a file with the defined name
0344     * \p fileName in the store else false is returned.
0345     *
0346     * The following python sample does use the hasFile-method;
0347     * \code
0348     * if not store.hasFile("content.xml"):
0349     *     raise "No content.xml file within the store."
0350     * if not store.hasFile("tar:/META-INF/manifest.xml"):
0351     *     raise "No manifest.xml file within the store."
0352     * \endcode
0353     */
0354     bool hasFile(const QString &fileName);
0355 
0356     /**
0357     * Returns true if the store is already opened else false
0358     * got returned. The store does allow to open and deal
0359     * with maximal one file the same time.
0360     */
0361     bool isOpen() const;
0362 
0363     /**
0364     * Open the file with the defined name \p fileName and
0365     * return a \a KoScriptingOdfReader object if the file
0366     * was open successful else NULL (aka no object) got
0367     * returned.
0368     *
0369     * If the store is already opened, it got closed before
0370     * we try to open the new file. This means, that all
0371     * previous \a KoScriptingOdfReader instances are
0372     * invalid and that only the last one returned by using
0373     * the open-method is valid till closed.
0374     *
0375     * The following python sample does use the open-method;
0376     * \code
0377     * # Fetch a reader for the styles.xml file.
0378     * stylesReader = store.open("styles.xml")
0379     * if not stylesReader:
0380     *     raise "Failed to read styles"
0381     *
0382     * # Now fetch a reader for the manifest. Please note,
0383     * # that stylesReader.close() is implicit done here.
0384     * manifestReader = store.open("META-INF/manifest.xml")
0385     * if not manifestReader:
0386     *     raise "Failed to read mainfest"
0387     * \endcode
0388     */
0389     QObject* open(const QString &fileName);
0390 
0391     /**
0392     * Closes the store if it's opened. If the store was not opened
0393     * or got closed successful true is returned.
0394     */
0395     bool close();
0396 
0397     /**
0398     * Extract the content of the file named \p fileName and return
0399     * it as an array of bytes.
0400     */
0401     QByteArray extract(const QString &fileName);
0402 
0403     /**
0404     * Extract the content of the file named \p fileName to the defined
0405     * target-file \p toFileName and return true on success.
0406     */
0407     bool extractToFile(const QString &fileName, const QString &toFileName);
0408 
0409     //QStringList directories();
0410     //bool hasDirectory(const QString &directoryName);
0411     //QString currentDirectory();
0412     //bool changeDirectory(const QString &directoryName);
0413 
0414     /**
0415     * Returns the document the store is the backend for.
0416     */
0417     QObject *document() const;
0418 
0419     /**
0420     * Set the document the store is the backend for. This could
0421     * be a \a KoPartAdaptor or a \a KoDocument object.
0422     */
0423     bool setDocument(QObject *document);
0424 
0425     //void setFilter(const QString &filter) {}
0426     //void start() {}
0427 
0428 Q_SIGNALS:
0429 
0430     //void onElement();
0431     //void onHeader();
0432     //void onParagraph();
0433 
0434 private:
0435     KoStore *getReadStore();
0436     QByteArray getByteArray();
0437     QByteArray getMimeType() const;
0438 
0439     QPointer<KoDocument> m_document;
0440     QPointer<KoPartAdaptor> m_documentAdaptor;
0441 
0442     KoStore *m_readStore;
0443     QIODevice *m_readDevice;
0444     KoScriptingOdfReader *m_reader;
0445     QByteArray m_byteArray;
0446 };
0447 
0448 
0449 
0450 #endif