1 /*
2 * This file is part of Office 2007 Filters for Calligra
3 * Copyright (C) 2002 Laurent Montel <lmontel@mandrakesoft.com>
4 * Copyright (c) 2003 Lukas Tinkl <lukas@kde.org>
5 * Copyright (C) 2003 David Faure <faure@kde.org>
6 * Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
7 *
8 * Contact: Suresh Chande suresh.chande@nokia.com
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public License
12 * version 2.1 as published by the Free Software Foundation.
13 *
14 * This library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 * 02110-1301 USA
23 *
24 */
25
26 #ifndef MSOOXML_UTILS_H
27 #define MSOOXML_UTILS_H
28
29 #include "komsooxml_export.h"
30
31 #include <QSize>
32 #include <QColor>
33 #include <QBuffer>
34 #include <KoFilterChain.h>
35 #include <KoXmlReader.h>
36 #include "MsooXmlDebug.h"
37 #include <KoGenStyle.h>
38
39 class KZip;
40 struct KoOdfWriters;
41 class KoCharacterStyle;
42 class KoXmlWriter;
43 class KoGenStyles;
44
45 //! Returns from the current block if the result of @a call is not equal to KoFilter::OK
46 #define RETURN_IF_ERROR( call ) \
47 { \
48 const KoFilter::ConversionStatus result = call; \
49 if (result != KoFilter::OK) \
50 return result; \
51 }
52
53 //! Common utilities for handling MSOOXML formats
54 namespace MSOOXML
55 {
56
57 class MsooXmlReader;
58 class MsooXmlReaderContext;
59
60 namespace Utils {
61
62 enum autoFitStatus {
63 autoFitUnUsed, autoFitOn, autoFitOff
64 };
65
66 enum MSOOXMLFilter {
67 DocxFilter, PptxFilter, XlsxFilter
68 };
69
70 class KOMSOOXML_EXPORT ParagraphBulletProperties
71 {
72 public:
73
74 ParagraphBulletProperties();
75
76 void clear();
77
78 QString convertToListProperties(KoGenStyles& mainStyles, MSOOXMLFilter filter = XlsxFilter);
79
80 bool isEmpty() const;
81
82 void setBulletChar(const QString& bulletChar);
83
84 void setPrefix(const QString& prefixChar);
85
86 void setSuffix(const QString& suffixChar);
87
88 void setAlign(const QString& align);
89
90 void setNumFormat(const QString& numFormat);
91
92 void setMargin(const qreal margin);
93
94 void setIndent(const qreal indent);
95
96 void setPicturePath(const QString& picturePath);
97
98 void setBulletFont(const QString& font);
99
100 void setBulletColor(const QString& bulletColor);
101
102 void setStartValue(const QString& value);
103
104 void setBulletRelativeSize(const int size);
105
106 void setBulletSizePt(const qreal size);
107
108 void setFollowingChar(const QString& value);
109
110 void setTextStyle(const KoGenStyle& textStyle);
111
112 void setStartOverride(const bool startOverride);
113
114 QString startValue() const;
115
116 QString bulletRelativeSize() const;
117
118 QString bulletSizePt() const;
119
120 QString bulletColor() const;
121
122 QString bulletChar() const;
123
124 QString bulletFont() const;
125
126 QString indent() const;
127
128 QString margin() const;
129
130 QString followingChar() const;
131
132 KoGenStyle textStyle() const;
133
134 bool startOverride() const;
135
136 void addInheritedValues(const ParagraphBulletProperties& properties);
137
138 int m_level;
139
140 enum ParagraphBulletType {BulletType, NumberType, PictureType, DefaultType};
141 ParagraphBulletType m_type;
142
143 private:
144
145 QString m_startValue;
146 QString m_bulletFont;
147 QString m_bulletChar;
148 QString m_numFormat;
149 QString m_prefix;
150 QString m_suffix;
151 QString m_align;
152 QString m_indent;
153 QString m_margin;
154 QString m_picturePath;
155 QString m_bulletColor;
156 QString m_followingChar;
157 QString m_bulletRelativeSize;
158 QString m_bulletSize;
159
160 KoGenStyle m_textStyle;
161
162 // MSWord specific: Restart the numbering when this list style is
163 // used for the 1st time. Otherwise don't restart in case any of the
164 // styles inheriting from the same abstract numbering definition was
165 // already used. Let's ignore presence of this attribute in
166 // addInheritedValues.
167 bool m_startOverride;
168 };
169
170 //! Container autodeleter. Works for QList, QHash and QMap.
171 //! @todo move to more generic place
172 template <typename T>
173 class ContainerDeleter
174 {
175 public:
ContainerDeleter(T & container)176 ContainerDeleter(T& container) : m_container(&container) {}
~ContainerDeleter()177 ~ContainerDeleter() {
178 qDeleteAll(*m_container); m_container->clear();
179 }
180 private:
181 T* const m_container;
182 };
183
184 //! Helper that sets given variable to specified value on destruction
185 //! Object of type Setter are supposed to be created on the stack.
186 //! @todo Copied from calligra/kexi/kexiutils/utils.h; replace with a shared code
187 template <typename T>
188 class Setter
189 {
190 public:
191 //! Creates a new setter object for variable @a var,
192 //! which will be set to value @a val on setter's destruction.
Setter(T * var,const T & val)193 Setter(T* var, const T& val)
194 : m_var(var), m_value(val) {
195 }
~Setter()196 ~Setter() {
197 if (m_var)
198 *m_var = m_value;
199 }
200 //! Clears the assignment, so the setter
201 //! will not alter the variable on destruction
clear()202 void clear() {
203 m_var = 0;
204 }
205 private:
206 T* m_var;
207 const T m_value;
208 };
209
210 //! Helper that works like the @ref Setter class but also has behaviour of std::auto_ptr.
211 //! When std::auto_ptr is used, the pointer of type T* is not set back to 0 on destruction.
212 //! @todo replace with a shared code
213 template <typename T>
214 class AutoPtrSetter
215 {
216 public:
217 //! Creates a new auto-ptr setter object for variable pointer of type T* @a ptr,
218 //! which will be set to 0 setter's destruction, unless release() was called.
AutoPtrSetter(T * ptr)219 explicit AutoPtrSetter(T* ptr)
220 : m_pptr(&ptr) {
221 }
~AutoPtrSetter()222 ~AutoPtrSetter() {
223 if (m_pptr && *m_pptr) {
224 delete *m_pptr;
225 *m_pptr = 0;
226 }
227 }
228 //! Bypasses the smart pointer, and returns it, so on destruction
229 //! of the AutoPtrSetter object the pointed object will not be deleted
230 //! (so it is the behaviour like std::auto__ptr::release())
231 //! but also the pointer of type T* will not be cleared.
release()232 T* release() {
233 T* p = m_pptr ? *m_pptr : 0;
234 m_pptr = 0;
235 return p;
236 }
237 private:
238 T** m_pptr;
239 };
240
241 //! Decodes boolean attribute @a value. If unspecified returns @a defaultValue.
242 //! @return true unless @a value is equal to "false", "off" or "0".
243 KOMSOOXML_EXPORT bool convertBooleanAttr(const QString& value, bool defaultValue = false);
244
245 //! Loads content types from "[Content_Types].xml"
246 /*! Based on information from ECMA-376, Part 1: "11.2 Package Structure".
247 @return status: KoFilter::OK on success or KoFilter::WrongFormat when any unexpected and critical incompatibility occurs.
248 */
249 //! @todo create whole class keeping the data
250 KOMSOOXML_EXPORT KoFilter::ConversionStatus loadContentTypes(const KoXmlDocument& contentTypesXML,
251 QMultiHash<QByteArray, QByteArray>& contentTypes);
252
253 //! Loads content types from "docProps/app.xml"
254 KOMSOOXML_EXPORT KoFilter::ConversionStatus loadDocumentProperties(const KoXmlDocument& appXML, QMap<QString, QVariant>& properties);
255
256 //! @return device for file @a fileName of @a zip archive. Status @a status is written on error.
257 //! The device is already opened for reading and should be deleted after use.
258 KOMSOOXML_EXPORT QIODevice* openDeviceForFile(const KZip* zip,
259 QString& errorMessage,
260 const QString& fileName,
261 KoFilter::ConversionStatus& status);
262
263 //! QXmlStreamReader-based generic loading/parsing into @a doc KoXmlDocument
264 KOMSOOXML_EXPORT KoFilter::ConversionStatus loadAndParse(QIODevice* io, KoXmlDocument& doc,
265 QString& errorMessage, const QString & fileName);
266
267 //! @see KoOdfReadStore::loadAndParse(QIODevice* fileDevice, KoXmlDocument& doc, QString& errorMessage, const QString& fileName)
268 KOMSOOXML_EXPORT KoFilter::ConversionStatus loadAndParse(KoXmlDocument& doc,
269 const KZip* zip,
270 QString& errorMessage,
271 const QString& fileName);
272
273 //! QXmlStreamReader-based loading/parsing for document.xml
274 KOMSOOXML_EXPORT KoFilter::ConversionStatus loadAndParseDocument(MsooXmlReader* reader,
275 const KZip* zip,
276 KoOdfWriters* writers,
277 QString& errorMessage,
278 const QString& fileName,
279 MsooXmlReaderContext* context = 0);
280
281 /*! Copies file @a sourceName from zip archive @a zip to @a outputStore store
282 under @a destinationName name. If @a size is not 0, *size is set to size of the image
283 @return KoFilter::OK on success.
284 On failure @a errorMessage is set. */
285 KoFilter::ConversionStatus copyFile(const KZip* zip, QString& errorMessage,
286 const QString& sourceName, KoStore *outputStore,
287 const QString& destinationName, bool oleType=false);
288
289 /*! Creates a file */
290 KoFilter::ConversionStatus createImage(QString& errorMessage,
291 const QImage& source, KoStore *outputStore,
292 const QString& destinationName);
293
294 /*! @return size of image file @a sourceName read from zip archive @a zip.
295 Size of the image is returned in @a size.
296 @return KoFilter::OK on success.
297 On failure @a errorMessage is set. */
298 KoFilter::ConversionStatus imageSize(const KZip* zip, QString& errorMessage,
299 const QString& sourceName, QSize* size);
300
301 //! Loads a thumbnail.
302 /*! @return conversion status
303 @todo Thumbnails are apparently used only by PowerPoint or templates for now.
304 Implement it, for now this feature is not needed for docx. */
305 KOMSOOXML_EXPORT KoFilter::ConversionStatus loadThumbnail(QImage& thumbnail, KZip* zip);
306
307 // -- conversions ---
308
309 //! Handles ST_Lang value @a value (Language Reference) (SharedML, 22.9.2.6)
310 /*! The value specifies that its contents contains a language identifier as defined by RFC 4646/BCP 47.
311 Sets up @a language and @a country based on @a value that is of format {langugage}-{country}
312 @return true on success. */
313 KOMSOOXML_EXPORT bool ST_Lang_to_languageAndCountry(const QString& value, QString& language, QString& country);
314
315 //! @return QColor value for ST_HexColorRGB (Hexadecimal Color Value) (SharedML, 22.9.2.5)
316 //! or invalid QColor if @a color is not in the expected format.
317 //! @par val color value in RRGGBB hexadecimal format
ST_HexColorRGB_to_QColor(const QString & color)318 inline QColor ST_HexColorRGB_to_QColor(const QString& color)
319 {
320 if (color.length() != 6)
321 return QColor();
322 bool ok;
323 const uint rgb = color.toUInt(&ok, 16);
324 return ok ? QColor(QRgb(rgb)) : QColor(); // alpha ignored
325 // return QColor(QRgb(0xff000000 | color.toInt(0, 16)));
326 }
327
328 //! @return QBrush value for ST_HighlightColor
329 //! The brush is built out of solid color.
330 //! If colorName is not supported by the standard, QBrush() is returned.
331 //! @par colorName named text highlight color like "black", "blue" (17.18.40)
332 KOMSOOXML_EXPORT QBrush ST_HighlightColor_to_QColor(const QString& colorName);
333
334 //! Converts value for 22.9.2.9 ST_Percentage (Percentage Value with Sign) from string
335 //! Sets @arg ok to true on success.
336 KOMSOOXML_EXPORT qreal ST_Percentage_to_double(const QString& val, bool& ok);
337
338 //! Converts value for 22.9.2.9 ST_Percentage (Percentage Value with Sign) from string
339 //! If "%" suffix is not present (MSOOXML violation of OOXML), the format is expected to be int({ST_Percentage}*1000).
340 //! Sets @arg ok to true on success.
341 KOMSOOXML_EXPORT qreal ST_Percentage_withMsooxmlFix_to_double(const QString& val, bool& ok);
342
343 struct KOMSOOXML_EXPORT DoubleModifier {
DoubleModifierDoubleModifier344 DoubleModifier(qreal v) : value(v), valid(true) {}
DoubleModifierDoubleModifier345 DoubleModifier() : value(0.0), valid(false) {}
346 qreal value;
347 bool valid;
348 };
349
350 KOMSOOXML_EXPORT QColor colorForLuminance(const QColor& color,
351 const DoubleModifier& modulation, const DoubleModifier& offset);
352
353 KOMSOOXML_EXPORT void modifyColor(QColor& color, qreal tint, qreal shade, qreal satMod);
354
355 //! Converts shape types from ECMA-376 to ODF.
356 /*! @return "Common Presentation Shape Attribute" value (ODF 1.1., 9.6.1)
357 for presentation shape converted from ECMA-376 19.7.10
358 ST_PlaceholderType (Placeholder ID) value, p. 2987.
359 @param ecmaType ECMA-376 shape type
360 The conversion is useful e.g. for presentation:class attribute of draw:frame
361 out of ECMA-376's ph\@type attribute.
362 By default (and for empty argument), "outline" is returned.
363 */
364 //! @todo or "object"? ST_PlaceholderType docs day the default is "obj".
365 //! CASE \#P500
366 KOMSOOXML_EXPORT QString ST_PlaceholderType_to_ODF(const QString& ecmaType);
367
368 //! Sets up @p textStyleProperties with underline style matching MSOOXML name @p msooxmlName.
369 //! Based on 17.18.99 ST_Underline (Underline Patterns), WML ECMA-376 p.1681
370 //! and on 20.1.10.82 ST_TextUnderlineType (Text Underline Types), DrawingML ECMA-376 p.3450 (merged)
371 KOMSOOXML_EXPORT void setupUnderLineStyle(const QString& msooxmlName, KoCharacterStyle* textStyleProperties);
372
373 //! @return the symbolic name of column @p column (counted from 0)
374 //! This is similar to the notation of spreadsheet's column, e.g. 0th column is "A", 1st is "B", 26th is "AA".
375 KOMSOOXML_EXPORT QString columnName(uint column);
376
377 //! Splits @a pathAndFile into path and file parts. Path does not end with '/'.
378 KOMSOOXML_EXPORT void splitPathAndFile(const QString& pathAndFile, QString* path, QString* file);
379
380 //! Returns calculated angle and xDiff, yDiff, caller has to apply these to style
381 KOMSOOXML_EXPORT void rotateString(const qreal rotation, const qreal width, const qreal height, qreal& angle, qreal& xDiff, qreal& yDiff);
382
383 //! Marker related utils
384 KOMSOOXML_EXPORT QString defineMarkerStyle(KoGenStyles& mainStyles, const QString& markerType);
385
386 KOMSOOXML_EXPORT qreal defineMarkerWidth(const QString &markerWidth, const qreal lineWidth);
387
388 //! A helper allowing to buffer xml streams and writing them back later
389 /*! This class is useful when information that has to be written in advance is
390 based on XML elements parsed later. In such case the information cannot be
391 saved in one pass. Example of this is paragraphs style name: is should be
392 written to style:name attribute but relevant XML elements (that we use for
393 building the style) are appearing later. So we first output created XML to
394 a buffer, then save the parent element with the style name and use
395 KoXmlWriter::addCompleteElement() to redirect the buffer contents as a
396 subelement.
397
398 Example use:
399 @code
400 KoXmlWriter *body = ...;
401 XmlWriteBuffer buf;
402 body = buf.setWriter(body);
403 // ...
404 // buf.originalWriter() can be used here ...
405 // ...
406 // Use the new buffered body writer here, e.g.:
407 body->startElement("text:span", false);
408 body->addAttribute("text:style-name", currentTextStyleName);
409 body->addTextSpan(text);
410 body->endElement();
411
412 // We are done with the buffered body writer, now release it and restore
413 // the original body writer. This inserts all the XML buffered by buf
414 // into the original body writer (using KoXmlWriter::addCompleteElement()).
415
416 body = buf.releaseWriter();
417 @endcode */
418 class KOMSOOXML_EXPORT XmlWriteBuffer
419 {
420 public:
421 //! Constructor; no writer is set initially.
422 XmlWriteBuffer();
423
424 //! Destructor, releases writer if there is any set.
425 ~XmlWriteBuffer();
426
427 //! Assigns writer @a writer to this buffer.
428 /*! From now any output directed to @a writer is written to a buffer instead.
429 Use releaseWriter() to write the changes back through the original writer.
430 @return the newly created writer, which usually should be assigned
431 to the variable passed as @a writer. */
432 KoXmlWriter* setWriter(KoXmlWriter* writer);
433
434 //! Releases the original writer set before using setWriter(KoXmlWriter*&).
435 /*! This inserts all the XML buffered by buffer into the original body writer passed in setWriter()
436 (internally using KoXmlWriter::addCompleteElement()).
437 @return the original writer set in setWriter();
438 this writer usually should be assigned back to the variable
439 altered by the recent use of setWriter(). */
440 KoXmlWriter* releaseWriter();
441
442 //! Releases the original writer set before using setWriter(KoXmlWriter*&).
443 /*! This inserts all the XML buffered by buffer into @a bkpXmlSnippet
444 @return the original writer set in setWriter();
445 this writer usually should be assigned back to the variable
446 altered by the recent use of setWriter(). */
447 KoXmlWriter* releaseWriter(QString& bkpXmlSnippet);
448
449 //! @return the original writer set in setWriter(). Does not change the state of the buffer.
450 /*! Use this method when you need to access the remembered writer without releasing it. */
originalWriter()451 KoXmlWriter* originalWriter() const {
452 return m_origWriter;
453 }
454
455 //! Clears this buffer without performing any output to the writer.
456 void clear();
457
458 //! Returns true if the buffer is empty; otherwise returns false.
isEmpty()459 bool isEmpty() const {
460 return m_buffer.buffer().isEmpty();
461 }
462
463 private:
464 //! Internal, used in releaseWriter() and the destructor; Does not assert when there's nothing to release.
465 KoXmlWriter* releaseWriterInternal();
466
467 QBuffer m_buffer;
468 KoXmlWriter* m_origWriter;
469 KoXmlWriter* m_newWriter;
470 };
471
472 //! The purpose of this class is to make sure the this->body variable is proper
473 //! set back to what it was before even if one of the TRY_READ calls lead to
474 //! us skipping out of this method. In that case we need to make sure to restore
475 //! the body variable else things may later crash.
476 //!
477 //! FIXME refactor the XmlWriteBuffer and merge this hack in so we don't
478 //! need to work-around at any place where it's used.
479 template <typename T>
480 class AutoRestore
481 {
482 public:
AutoRestore(T ** originalPtr)483 explicit AutoRestore(T** originalPtr)
484 : m_originalPtr(originalPtr), m_prevValue(*originalPtr) {
485 }
~AutoRestore()486 ~AutoRestore() {
487 if (m_originalPtr) {
488 *m_originalPtr = m_prevValue;
489 }
490 }
491 private:
492 T** m_originalPtr;
493 T* m_prevValue;
494 };
495
496 } // Utils namespace
497
498 } // MSOOXML namespace
499
500 #endif /* MSOOXML_UTILS_H */
501