File indexing completed on 2024-05-12 16:29:13

0001 /*
0002  * This file is part of Office 2007 Filters for Calligra
0003  * Copyright (C) 2002 Laurent Montel <lmontel@mandrakesoft.com>
0004  * Copyright (c) 2003 Lukas Tinkl <lukas@kde.org>
0005  * Copyright (C) 2003 David Faure <faure@kde.org>
0006  * Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
0007  *
0008  * Contact: Suresh Chande suresh.chande@nokia.com
0009  *
0010  * This library is free software; you can redistribute it and/or
0011  * modify it under the terms of the GNU Lesser General Public License
0012  * version 2.1 as published by the Free Software Foundation.
0013  *
0014  * This library is distributed in the hope that it will be useful, but
0015  * WITHOUT ANY WARRANTY; without even the implied warranty of
0016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0017  * Lesser General Public License for more details.
0018  *
0019  * You should have received a copy of the GNU Lesser General Public
0020  * License along with this library; if not, write to the Free Software
0021  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0022  * 02110-1301 USA
0023  *
0024  */
0025 
0026 #ifndef MSOOXML_UTILS_H
0027 #define MSOOXML_UTILS_H
0028 
0029 #include "komsooxml_export.h"
0030 
0031 #include <QSize>
0032 #include <QColor>
0033 #include <QBuffer>
0034 #include <KoFilterChain.h>
0035 #include <KoXmlReader.h>
0036 #include "MsooXmlDebug.h"
0037 #include <KoGenStyle.h>
0038 
0039 class KZip;
0040 struct KoOdfWriters;
0041 class KoCharacterStyle;
0042 class KoXmlWriter;
0043 class KoGenStyles;
0044 
0045 //! Returns from the current block if the result of @a call is not equal to KoFilter::OK
0046 #define RETURN_IF_ERROR( call ) \
0047     { \
0048         const KoFilter::ConversionStatus result = call; \
0049         if (result != KoFilter::OK) \
0050             return result; \
0051     }
0052 
0053 //! Common utilities for handling MSOOXML formats
0054 namespace MSOOXML
0055 {
0056 
0057 class MsooXmlReader;
0058 class MsooXmlReaderContext;
0059 
0060 namespace Utils {
0061 
0062 enum autoFitStatus {
0063     autoFitUnUsed, autoFitOn, autoFitOff
0064 };
0065 
0066 enum MSOOXMLFilter {
0067     DocxFilter, PptxFilter, XlsxFilter
0068 };
0069 
0070 class KOMSOOXML_EXPORT ParagraphBulletProperties
0071 {
0072 public:
0073 
0074     ParagraphBulletProperties();
0075 
0076     void clear();
0077 
0078     QString convertToListProperties(KoGenStyles& mainStyles, MSOOXMLFilter filter = XlsxFilter);
0079 
0080     bool isEmpty() const;
0081 
0082     void setBulletChar(const QString& bulletChar);
0083 
0084     void setPrefix(const QString& prefixChar);
0085 
0086     void setSuffix(const QString& suffixChar);
0087 
0088     void setAlign(const QString& align);
0089 
0090     void setNumFormat(const QString& numFormat);
0091 
0092     void setMargin(const qreal margin);
0093 
0094     void setIndent(const qreal indent);
0095 
0096     void setPicturePath(const QString& picturePath);
0097 
0098     void setBulletFont(const QString& font);
0099 
0100     void setBulletColor(const QString& bulletColor);
0101 
0102     void setStartValue(const QString& value);
0103 
0104     void setBulletRelativeSize(const int size);
0105 
0106     void setBulletSizePt(const qreal size);
0107 
0108     void setFollowingChar(const QString& value);
0109 
0110     void setTextStyle(const KoGenStyle& textStyle);
0111 
0112     void setStartOverride(const bool startOverride);
0113 
0114     QString startValue() const;
0115 
0116     QString bulletRelativeSize() const;
0117 
0118     QString bulletSizePt() const;
0119 
0120     QString bulletColor() const;
0121 
0122     QString bulletChar() const;
0123 
0124     QString bulletFont() const;
0125 
0126     QString indent() const;
0127 
0128     QString margin() const;
0129 
0130     QString followingChar() const;
0131 
0132     KoGenStyle textStyle() const;
0133 
0134     bool startOverride() const;
0135 
0136     void addInheritedValues(const ParagraphBulletProperties& properties);
0137 
0138     int m_level;
0139 
0140     enum ParagraphBulletType {BulletType, NumberType, PictureType, DefaultType};
0141     ParagraphBulletType m_type;
0142 
0143 private:
0144 
0145     QString m_startValue;
0146     QString m_bulletFont;
0147     QString m_bulletChar;
0148     QString m_numFormat;
0149     QString m_prefix;
0150     QString m_suffix;
0151     QString m_align;
0152     QString m_indent;
0153     QString m_margin;
0154     QString m_picturePath;
0155     QString m_bulletColor;
0156     QString m_followingChar;
0157     QString m_bulletRelativeSize;
0158     QString m_bulletSize;
0159 
0160     KoGenStyle m_textStyle;
0161 
0162     // MSWord specific: Restart the numbering when this list style is
0163     // used for the 1st time.  Otherwise don't restart in case any of the
0164     // styles inheriting from the same abstract numbering definition was
0165     // already used.  Let's ignore presence of this attribute in
0166     // addInheritedValues.
0167     bool m_startOverride;
0168 };
0169 
0170 //! Container autodeleter. Works for QList, QHash and QMap.
0171 //! @todo move to more generic place
0172 template <typename T>
0173 class ContainerDeleter
0174 {
0175 public:
0176     ContainerDeleter(T& container) : m_container(&container) {}
0177     ~ContainerDeleter() {
0178         qDeleteAll(*m_container); m_container->clear();
0179     }
0180 private:
0181     T* const m_container;
0182 };
0183 
0184 //! Helper that sets given variable to specified value on destruction
0185 //! Object of type Setter are supposed to be created on the stack.
0186 //! @todo Copied from calligra/kexi/kexiutils/utils.h; replace with a shared code
0187 template <typename T>
0188 class Setter
0189 {
0190 public:
0191     //! Creates a new setter object for variable @a var,
0192     //! which will be set to value @a val on setter's destruction.
0193     Setter(T* var, const T& val)
0194             : m_var(var), m_value(val) {
0195     }
0196     ~Setter() {
0197         if (m_var)
0198             *m_var = m_value;
0199     }
0200     //! Clears the assignment, so the setter
0201     //! will not alter the variable on destruction
0202     void clear() {
0203         m_var = 0;
0204     }
0205 private:
0206     T* m_var;
0207     const T m_value;
0208 };
0209 
0210 //! Helper that works like the @ref Setter class but also has behaviour of std::auto_ptr.
0211 //! When std::auto_ptr is used, the pointer of type T* is not set back to 0 on destruction.
0212 //! @todo replace with a shared code
0213 template <typename T>
0214 class AutoPtrSetter
0215 {
0216 public:
0217     //! Creates a new auto-ptr setter object for variable pointer of type T* @a ptr,
0218     //! which will be set to 0 setter's destruction, unless release() was called.
0219     explicit AutoPtrSetter(T* ptr)
0220             : m_pptr(&ptr) {
0221     }
0222     ~AutoPtrSetter() {
0223         if (m_pptr && *m_pptr) {
0224             delete *m_pptr;
0225             *m_pptr = 0;
0226         }
0227     }
0228     //! Bypasses the smart pointer, and returns it, so on destruction
0229     //! of the AutoPtrSetter object the pointed object will not be deleted
0230     //! (so it is the behaviour like std::auto__ptr::release())
0231     //! but also the pointer of type T* will not be cleared.
0232     T* release() {
0233         T* p = m_pptr ? *m_pptr : 0;
0234         m_pptr = 0;
0235         return p;
0236     }
0237 private:
0238     T** m_pptr;
0239 };
0240 
0241 //! Decodes boolean attribute @a value. If unspecified returns @a defaultValue.
0242 //! @return true unless @a value is equal to "false", "off" or "0".
0243 KOMSOOXML_EXPORT bool convertBooleanAttr(const QString& value, bool defaultValue = false);
0244 
0245 //! Loads content types from "[Content_Types].xml"
0246 /*! Based on information from ECMA-376, Part 1: "11.2 Package Structure".
0247  @return status: KoFilter::OK on success or KoFilter::WrongFormat when any unexpected and critical incompatibility occurs.
0248 */
0249 //! @todo create whole class keeping the data
0250 KOMSOOXML_EXPORT KoFilter::ConversionStatus loadContentTypes(const KoXmlDocument& contentTypesXML,
0251         QMultiHash<QByteArray, QByteArray>& contentTypes);
0252 
0253 //! Loads content types from "docProps/app.xml"
0254 KOMSOOXML_EXPORT KoFilter::ConversionStatus loadDocumentProperties(const KoXmlDocument& appXML, QMap<QString, QVariant>& properties);
0255 
0256 //! @return device for file @a fileName of @a zip archive. Status @a status is written on error.
0257 //! The device is already opened for reading and should be deleted after use.
0258 KOMSOOXML_EXPORT QIODevice* openDeviceForFile(const KZip* zip,
0259         QString& errorMessage,
0260         const QString& fileName,
0261         KoFilter::ConversionStatus& status);
0262 
0263 //! QXmlStreamReader-based generic loading/parsing into @a doc KoXmlDocument
0264 KOMSOOXML_EXPORT KoFilter::ConversionStatus loadAndParse(QIODevice* io, KoXmlDocument& doc,
0265         QString& errorMessage, const QString & fileName);
0266 
0267 //! @see KoOdfReadStore::loadAndParse(QIODevice* fileDevice, KoXmlDocument& doc, QString& errorMessage, const QString& fileName)
0268 KOMSOOXML_EXPORT KoFilter::ConversionStatus loadAndParse(KoXmlDocument& doc,
0269         const KZip* zip,
0270         QString& errorMessage,
0271         const QString& fileName);
0272 
0273 //! QXmlStreamReader-based loading/parsing for document.xml
0274 KOMSOOXML_EXPORT KoFilter::ConversionStatus loadAndParseDocument(MsooXmlReader* reader,
0275         const KZip* zip,
0276         KoOdfWriters* writers,
0277         QString& errorMessage,
0278         const QString& fileName,
0279         MsooXmlReaderContext* context = 0);
0280 
0281 /*! Copies file @a sourceName from zip archive @a zip to @a outputStore store
0282  under @a destinationName name. If @a size is not 0, *size is set to size of the image
0283  @return KoFilter::OK on success.
0284  On failure @a errorMessage is set. */
0285 KoFilter::ConversionStatus copyFile(const KZip* zip, QString& errorMessage,
0286                                     const QString& sourceName, KoStore *outputStore,
0287                                     const QString& destinationName, bool oleType=false);
0288 
0289 /*! Creates a file */
0290 KoFilter::ConversionStatus createImage(QString& errorMessage,
0291                                        const QImage& source, KoStore *outputStore,
0292                                        const QString& destinationName);
0293 
0294 /*! @return size of image file @a sourceName read from zip archive @a zip.
0295  Size of the image is returned in @a size.
0296  @return KoFilter::OK on success.
0297  On failure @a errorMessage is set. */
0298 KoFilter::ConversionStatus imageSize(const KZip* zip, QString& errorMessage,
0299                                      const QString& sourceName, QSize* size);
0300 
0301 //! Loads a thumbnail.
0302 /*! @return conversion status
0303     @todo Thumbnails are apparently used only by PowerPoint or templates for now.
0304           Implement it, for now this feature is not needed for docx. */
0305 KOMSOOXML_EXPORT KoFilter::ConversionStatus loadThumbnail(QImage& thumbnail, KZip* zip);
0306 
0307 // -- conversions ---
0308 
0309 //! Handles ST_Lang value @a value (Language Reference) (SharedML, 22.9.2.6)
0310 /*! The value specifies that its contents contains a language identifier as defined by RFC 4646/BCP 47.
0311     Sets up @a language and @a country based on @a value that is of format {langugage}-{country}
0312     @return true on success. */
0313 KOMSOOXML_EXPORT bool ST_Lang_to_languageAndCountry(const QString& value, QString& language, QString& country);
0314 
0315 //! @return QColor value for ST_HexColorRGB (Hexadecimal Color Value) (SharedML, 22.9.2.5)
0316 //!         or invalid QColor if @a color is not in the expected format.
0317 //! @par val color value in RRGGBB hexadecimal format
0318 inline QColor ST_HexColorRGB_to_QColor(const QString& color)
0319 {
0320     if (color.length() != 6)
0321         return QColor();
0322     bool ok;
0323     const uint rgb = color.toUInt(&ok, 16);
0324     return ok ? QColor(QRgb(rgb)) : QColor(); // alpha ignored
0325 //    return QColor(QRgb(0xff000000 | color.toInt(0, 16)));
0326 }
0327 
0328 //! @return QBrush value for ST_HighlightColor
0329 //! The brush is built out of solid color.
0330 //! If colorName is not supported by the standard, QBrush() is returned.
0331 //! @par colorName named text highlight color like "black", "blue" (17.18.40)
0332 KOMSOOXML_EXPORT QBrush ST_HighlightColor_to_QColor(const QString& colorName);
0333 
0334 //! Converts value for 22.9.2.9 ST_Percentage (Percentage Value with Sign) from string
0335 //! Sets @arg ok to true on success.
0336 KOMSOOXML_EXPORT qreal ST_Percentage_to_double(const QString& val, bool& ok);
0337 
0338 //! Converts value for 22.9.2.9 ST_Percentage (Percentage Value with Sign) from string
0339 //! If "%" suffix is not present (MSOOXML violation of OOXML), the format is expected to be int({ST_Percentage}*1000).
0340 //! Sets @arg ok to true on success.
0341 KOMSOOXML_EXPORT qreal ST_Percentage_withMsooxmlFix_to_double(const QString& val, bool& ok);
0342 
0343 struct KOMSOOXML_EXPORT DoubleModifier {
0344     DoubleModifier(qreal v) : value(v), valid(true) {}
0345     DoubleModifier() : value(0.0), valid(false) {}
0346     qreal value;
0347     bool valid;
0348 };
0349 
0350 KOMSOOXML_EXPORT QColor colorForLuminance(const QColor& color,
0351     const DoubleModifier& modulation, const DoubleModifier& offset);
0352 
0353 KOMSOOXML_EXPORT void modifyColor(QColor& color, qreal tint, qreal shade, qreal satMod);
0354 
0355 //! Converts shape types from ECMA-376 to ODF.
0356 /*! @return "Common Presentation Shape Attribute" value (ODF 1.1., 9.6.1)
0357             for presentation shape converted from ECMA-376 19.7.10
0358             ST_PlaceholderType (Placeholder ID) value, p. 2987.
0359     @param ecmaType ECMA-376 shape type
0360     The conversion is useful e.g. for presentation:class attribute of draw:frame
0361     out of ECMA-376's ph\@type attribute.
0362     By default (and for empty argument), "outline" is returned.
0363 */
0364 //! @todo or "object"?  ST_PlaceholderType docs day the default is "obj".
0365 //! CASE \#P500
0366 KOMSOOXML_EXPORT QString ST_PlaceholderType_to_ODF(const QString& ecmaType);
0367 
0368 //! Sets up @p textStyleProperties with underline style matching MSOOXML name @p msooxmlName.
0369 //! Based on 17.18.99 ST_Underline (Underline Patterns), WML ECMA-376 p.1681
0370 //! and on 20.1.10.82 ST_TextUnderlineType (Text Underline Types), DrawingML ECMA-376 p.3450 (merged)
0371 KOMSOOXML_EXPORT void setupUnderLineStyle(const QString& msooxmlName, KoCharacterStyle* textStyleProperties);
0372 
0373 //! @return the symbolic name of column @p column (counted from 0)
0374 //! This is similar to the notation of spreadsheet's column, e.g. 0th column is "A", 1st is "B", 26th is "AA".
0375 KOMSOOXML_EXPORT QString columnName(uint column);
0376 
0377 //! Splits @a pathAndFile into path and file parts. Path does not end with '/'.
0378 KOMSOOXML_EXPORT void splitPathAndFile(const QString& pathAndFile, QString* path, QString* file);
0379 
0380 //! Returns calculated angle and xDiff, yDiff, caller has to apply these to style
0381 KOMSOOXML_EXPORT void rotateString(const qreal rotation, const qreal width, const qreal height, qreal& angle, qreal& xDiff, qreal& yDiff);
0382 
0383 //! Marker related utils
0384 KOMSOOXML_EXPORT QString defineMarkerStyle(KoGenStyles& mainStyles, const QString& markerType);
0385 
0386 KOMSOOXML_EXPORT qreal defineMarkerWidth(const QString &markerWidth, const qreal lineWidth);
0387 
0388 //! A helper allowing to buffer xml streams and writing them back later
0389 /*! This class is useful when information that has to be written in advance is
0390     based on XML elements parsed later.  In such case the information cannot be
0391     saved in one pass.  Example of this is paragraphs style name: is should be
0392     written to style:name attribute but relevant XML elements (that we use for
0393     building the style) are appearing later.  So we first output created XML to
0394     a buffer, then save the parent element with the style name and use
0395     KoXmlWriter::addCompleteElement() to redirect the buffer contents as a
0396     subelement.
0397 
0398      Example use:
0399      @code
0400      KoXmlWriter *body = ...;
0401      XmlWriteBuffer buf;
0402      body = buf.setWriter(body);
0403      // ...
0404      // buf.originalWriter() can be used here ...
0405      // ...
0406      // Use the new buffered body writer here, e.g.:
0407      body->startElement("text:span", false);
0408      body->addAttribute("text:style-name", currentTextStyleName);
0409      body->addTextSpan(text);
0410      body->endElement();
0411 
0412      // We are done with the buffered body writer, now release it and restore
0413      // the original body writer.  This inserts all the XML buffered by buf
0414      // into the original body writer (using KoXmlWriter::addCompleteElement()).
0415 
0416      body = buf.releaseWriter();
0417      @endcode */
0418 class KOMSOOXML_EXPORT XmlWriteBuffer
0419 {
0420 public:
0421     //! Constructor; no writer is set initially.
0422     XmlWriteBuffer();
0423 
0424     //! Destructor, releases writer if there is any set.
0425     ~XmlWriteBuffer();
0426 
0427     //! Assigns writer @a writer to this buffer.
0428     /*! From now any output directed to @a writer is written to a buffer instead.
0429      Use releaseWriter() to write the changes back through the original writer.
0430      @return the newly created writer, which usually should be assigned
0431              to the variable passed as @a writer. */
0432     KoXmlWriter* setWriter(KoXmlWriter* writer);
0433 
0434     //! Releases the original writer set before using setWriter(KoXmlWriter*&).
0435     /*! This inserts all the XML buffered by buffer into the original body writer passed in setWriter()
0436      (internally using KoXmlWriter::addCompleteElement()).
0437      @return the original writer set in setWriter();
0438              this writer usually should be assigned back to the variable
0439              altered by the recent use of setWriter(). */
0440     KoXmlWriter* releaseWriter();
0441 
0442     //! Releases the original writer set before using setWriter(KoXmlWriter*&).
0443     /*! This inserts all the XML buffered by buffer into @a bkpXmlSnippet
0444      @return the original writer set in setWriter();
0445              this writer usually should be assigned back to the variable
0446              altered by the recent use of setWriter(). */
0447     KoXmlWriter* releaseWriter(QString& bkpXmlSnippet);
0448 
0449     //! @return the original writer set in setWriter(). Does not change the state of the buffer.
0450     /*! Use this method when you need to access the remembered writer without releasing it. */
0451     KoXmlWriter* originalWriter() const {
0452         return m_origWriter;
0453     }
0454 
0455     //! Clears this buffer without performing any output to the writer.
0456     void clear();
0457 
0458     //! Returns true if the buffer is empty; otherwise returns false.
0459     bool isEmpty() const {
0460         return m_buffer.buffer().isEmpty();
0461     }
0462 
0463 private:
0464     //! Internal, used in releaseWriter() and the destructor; Does not assert when there's nothing to release.
0465     KoXmlWriter* releaseWriterInternal();
0466 
0467     QBuffer m_buffer;
0468     KoXmlWriter* m_origWriter;
0469     KoXmlWriter* m_newWriter;
0470 };
0471 
0472 //! The purpose of this class is to make sure the this->body variable is proper
0473 //! set back to what it was before even if one of the TRY_READ calls lead to
0474 //! us skipping out of this method. In that case we need to make sure to restore
0475 //! the body variable else things may later crash.
0476 //!
0477 //! FIXME refactor the XmlWriteBuffer and merge this hack in so we don't
0478 //! need to work-around at any place where it's used.
0479 template <typename T>
0480 class AutoRestore
0481 {
0482 public:
0483     explicit AutoRestore(T** originalPtr)
0484             : m_originalPtr(originalPtr), m_prevValue(*originalPtr) {
0485     }
0486     ~AutoRestore() {
0487         if (m_originalPtr) {
0488             *m_originalPtr = m_prevValue;
0489         }
0490     }
0491 private:
0492     T** m_originalPtr;
0493     T* m_prevValue;
0494 };
0495 
0496 } // Utils namespace
0497 
0498 } // MSOOXML namespace
0499 
0500 #endif /* MSOOXML_UTILS_H */