Warning, file /office/calligra/filters/sheets/xlsx/XlsxXmlCommonReader.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002  * This file is part of Office 2007 Filters for Calligra
0003  *
0004  * SPDX-FileCopyrightText: 2009 Nokia Corporation and /or its subsidiary(-ies).
0005  *
0006  * Contact: Suresh Chande suresh.chande@nokia.com
0007  *
0008  * SPDX-License-Identifier: LGPL-2.1-only
0009  *
0010  */
0011 
0012 #include "XlsxUtils.h"
0013 #include "XlsxXmlCommonReader.h"
0014 
0015 #include <math.h>
0016 
0017 #include <MsooXmlSchemas.h>
0018 #include <MsooXmlUtils.h>
0019 #include <KoXmlWriter.h>
0020 #include <KoCharacterStyle.h>
0021 
0022 #undef MSOOXML_CURRENT_NS
0023 #define MSOOXML_CURRENT_CLASS XlsxXmlCommonReader
0024 #define BIND_READ_CLASS MSOOXML_CURRENT_CLASS
0025 
0026 #include <MsooXmlReader_p.h>
0027 
0028 class XlsxXmlCommonReader::Private
0029 {
0030 public:
0031     Private() {
0032     }
0033     ~Private() {
0034     }
0035 private:
0036 };
0037 
0038 XlsxXmlCommonReader::XlsxXmlCommonReader(KoOdfWriters *writers)
0039         : MSOOXML::MsooXmlReader(writers)
0040         , d(new Private)
0041 {
0042     init();
0043 }
0044 
0045 XlsxXmlCommonReader::~XlsxXmlCommonReader()
0046 {
0047     delete d;
0048 }
0049 
0050 void XlsxXmlCommonReader::init()
0051 {
0052     m_currentTextStyleProperties = 0;
0053 }
0054 
0055 QColor XlsxXmlCommonReader::tintedColor(const QColor& color, qreal tint)
0056 {
0057     const int HLSMAX = 255; // Used for computing tint
0058     if (tint == 0.0 || !color.isValid()) {
0059         return color;
0060     }
0061     int h, l, s;
0062     color.getHsl(&h, &l, &s);
0063     if (tint < 0.0) {
0064         l = floor( l * (1.0 + tint) );
0065     }
0066     else {
0067         l = floor( l * (1.0 - tint) + (HLSMAX - HLSMAX * (1.0 - tint)) );
0068     }
0069     int r, g, b;
0070     color.getRgb(&r, &g, &b);
0071     return QColor(r, g, b, color.alpha());
0072 }
0073 
0074 #undef CURRENT_EL
0075 #define CURRENT_EL t
0076 //! t handler (Text)
0077 /*! ECMA-376, 18.4.12, p. 1914.
0078  This element represents the text content shown as part of a string.
0079 
0080  No child elements.
0081  Parent elements:
0082  - is (§18.3.1.53)
0083  - [done] r (§18.4.4)
0084  - rPh (§18.4.6)
0085  - [done] si (§18.4.8)
0086  - text (§18.7.7)
0087 
0088  @todo support all child elements
0089 */
0090 KoFilter::ConversionStatus XlsxXmlCommonReader::read_t()
0091 {
0092     READ_PROLOGUE
0093     while (!atEnd()) {
0094         readNext();
0095         qCDebug(lcXlsxImport) << *this;
0096         if (isCharacters()) {
0097             body->addTextSpan(text().toString());
0098         }
0099         BREAK_IF_END_OF(CURRENT_EL)
0100     }
0101     READ_EPILOGUE
0102 }
0103 
0104 #undef CURRENT_EL
0105 #define CURRENT_EL r
0106 //! r handler (Rich Text Run)
0107 /*! ECMA-376, 18.4.12, p. 1909.
0108  This element represents a run of rich text. A rich text run is a region of text that share a common set of
0109  properties, such as formatting properties. The properties are defined in the rPr element, and the text displayed
0110  to the user is defined in the Text (t) element.
0111 
0112  Parent elements:
0113  - is (§18.3.1.53)
0114  - [done] si (§18.4.8)
0115  - text (§18.7.7)
0116 
0117  Child elements:
0118  - [done] rPr (§18.4.7)
0119  - [done] t (§18.4.12)
0120 
0121  @todo support all elements
0122 */
0123 KoFilter::ConversionStatus XlsxXmlCommonReader::read_r()
0124 {
0125     READ_PROLOGUE
0126 
0127     m_currentTextStyle = KoGenStyle(KoGenStyle::TextAutoStyle, "text");
0128 
0129     MSOOXML::Utils::XmlWriteBuffer rBuf;
0130     body = rBuf.setWriter(body);
0131 
0132     while (!atEnd()) {
0133         readNext();
0134         BREAK_IF_END_OF(CURRENT_EL)
0135         if (isStartElement()) {
0136             TRY_READ_IF(rPr)
0137             ELSE_TRY_READ_IF(t)
0138             ELSE_WRONG_FORMAT
0139         }
0140     }
0141 
0142     body = rBuf.originalWriter();
0143 
0144     body->startElement("text:span", false);
0145     if (!m_currentTextStyle.isEmpty() || !m_currentTextStyle.parentName().isEmpty()) {
0146         const QString currentTextStyleName(mainStyles->insert(m_currentTextStyle));
0147         body->addAttribute("text:style-name", currentTextStyleName);
0148     }
0149 
0150     (void)rBuf.releaseWriter();
0151 
0152     body->endElement(); //text:span
0153 
0154     READ_EPILOGUE
0155 }
0156 
0157 #undef CURRENT_EL
0158 #define CURRENT_EL rPr
0159 //! rPr handler (Run Properties)
0160 /*! ECMA-376, 18.4.7, p. 1911.
0161  This element represents a set of properties to apply to the contents of this rich text run.
0162 
0163  Parent elements:
0164  - [done] r (§18.4.4)
0165 
0166  Child elements:
0167  - [done] b §18.8.2
0168  - charset §18.4.1
0169  - [done] color §18.3.1.15
0170  - condense §18.8.12
0171  - extend §18.8.17
0172  - family §18.8.18
0173  - [done] i §18.8.26
0174  - [done] outline §18.4.2
0175  - [done] rFont §18.4.5
0176  - [done] scheme §18.8.35
0177  - shadow §18.8.36
0178  - [done] strike §18.4.10
0179  - [done] sz §18.4.11
0180  - [done] u §18.4.13
0181  - [done] vertAlign §18.4.14
0182 
0183  @todo support all child elements
0184 */
0185 KoFilter::ConversionStatus XlsxXmlCommonReader::read_rPr()
0186 {
0187     READ_PROLOGUE
0188     m_currentTextStyleProperties = new KoCharacterStyle;
0189 
0190     m_currentColor = QColor();
0191 
0192     while (!atEnd()) {
0193         readNext();
0194         BREAK_IF_END_OF(CURRENT_EL)
0195         if (isStartElement()) {
0196             TRY_READ_IF(vertAlign)
0197             ELSE_TRY_READ_IF(sz)
0198             ELSE_TRY_READ_IF(rFont)
0199             ELSE_TRY_READ_IF(color)
0200             ELSE_TRY_READ_IF(u)
0201             ELSE_TRY_READ_IF(i)
0202             ELSE_TRY_READ_IF(b)
0203             ELSE_TRY_READ_IF(strike)
0204             ELSE_TRY_READ_IF(outline)
0205             SKIP_UNKNOWN
0206 //! @todo add ELSE_WRONG_FORMAT
0207         }
0208     }
0209 
0210     if (m_currentColor.isValid()) {
0211         m_currentTextStyleProperties->setForeground(QBrush(m_currentColor));
0212     }
0213 
0214     m_currentTextStyleProperties->saveOdf(m_currentTextStyle);
0215     delete m_currentTextStyleProperties;
0216     m_currentTextStyleProperties = 0;
0217     READ_EPILOGUE
0218 }
0219 
0220 #undef CURRENT_EL
0221 #define CURRENT_EL vertAlign
0222 //! vertAlign handler (Vertical Alignment)
0223 /*! ECMA-376, 18.4.7, p. 1914.
0224  This element adjusts the vertical position of the text relative to the text's default appearance for this run.
0225  It is used to get 'superscript' or 'subscript' texts, and shall reduce the font size
0226  (if a smaller size is available) accordingly.
0227 
0228  Parent elements:
0229  - [done] font (§18.8.22)
0230  - [done] rPr (§18.4.7)
0231 
0232  No child elements.
0233 
0234  @todo support all elements
0235 */
0236 KoFilter::ConversionStatus XlsxXmlCommonReader::read_vertAlign()
0237 {
0238     READ_PROLOGUE
0239     const QXmlStreamAttributes attrs(attributes());
0240     TRY_READ_ATTR_WITHOUT_NS(val)
0241     if (val == "subscript") {
0242         m_currentTextStyleProperties->setVerticalAlignment(QTextCharFormat::AlignSubScript);
0243     }
0244     else if (val == "superscript") {
0245         m_currentTextStyleProperties->setVerticalAlignment(QTextCharFormat::AlignSuperScript);
0246     }
0247 
0248     readNext();
0249     READ_EPILOGUE
0250 }
0251 
0252 #undef CURRENT_EL
0253 #define CURRENT_EL sz
0254 //! fontSize
0255 /*
0256  Parent elements:
0257  - [done] font (§18.8.22);
0258  - [done] rPr (§18.4.7)
0259 
0260  Child elements:
0261  - none
0262 */
0263 KoFilter::ConversionStatus XlsxXmlCommonReader::read_sz()
0264 {
0265     READ_PROLOGUE
0266     const QXmlStreamAttributes attrs(attributes());
0267     TRY_READ_ATTR_WITHOUT_NS(val)
0268 
0269     if (!val.isEmpty()) {
0270         m_currentTextStyleProperties->setFontPointSize(val.toDouble());
0271     }
0272 
0273     readNext();
0274     READ_EPILOGUE
0275 }
0276 
0277 #undef CURRENT_EL
0278 #define CURRENT_EL rFont
0279 //! font
0280 /*
0281  Parent elements:
0282  - [done] rPr (§18.4.7)
0283 
0284  Child elements:
0285  - none
0286 */
0287 KoFilter::ConversionStatus XlsxXmlCommonReader::read_rFont()
0288 {
0289     READ_PROLOGUE
0290     const QXmlStreamAttributes attrs(attributes());
0291     TRY_READ_ATTR_WITHOUT_NS(val)
0292 
0293     if (!val.isEmpty()) {
0294         m_currentTextStyle.addProperty("fo:font-family", val);
0295     }
0296 
0297     readNext();
0298     READ_EPILOGUE
0299 }
0300 
0301 #undef CURRENT_EL
0302 #define CURRENT_EL i
0303 //! i handler (Italic)
0304 /*! ECMA-376, 18.8.26, p. 1969.
0305  Displays characters in italic font style.
0306 
0307  Parent elements:
0308  - [done] font (§18.8.22)
0309  - [done] rPr (§18.4.7)
0310 
0311  Child elements:
0312  - none
0313 */
0314 KoFilter::ConversionStatus XlsxXmlCommonReader::read_i()
0315 {
0316     READ_PROLOGUE
0317     const QXmlStreamAttributes attrs(attributes());
0318     TRY_READ_ATTR_WITHOUT_NS(val)
0319     const bool italic = MSOOXML::Utils::convertBooleanAttr(val, true);
0320     m_currentTextStyleProperties->setFontItalic(italic);
0321 
0322     readNext();
0323     READ_EPILOGUE
0324 }
0325 
0326 #undef CURRENT_EL
0327 #define CURRENT_EL scheme
0328 //! scheme handler (Scheme)
0329 /*!
0330 
0331  Parent elements:
0332  - [done] font (§18.8.22)
0333  - [done] rPr (§18.4.7)
0334 
0335  Child elements:
0336  - none
0337 */
0338 KoFilter::ConversionStatus XlsxXmlCommonReader::read_scheme()
0339 {
0340     READ_PROLOGUE
0341 
0342     const QXmlStreamAttributes attrs(attributes());
0343     TRY_READ_ATTR_WITHOUT_NS(val)
0344     QString font;
0345 
0346     if (val == "major") {
0347         font = m_themes->fontScheme.majorFonts.latinTypeface;
0348         m_currentTextStyle.addProperty("fo:font-family", font);
0349     } else if (val == "minor") {
0350         font = m_themes->fontScheme.minorFonts.latinTypeface;
0351         m_currentTextStyle.addProperty("fo:font-family", font);
0352     }
0353 
0354     readNext();
0355     READ_EPILOGUE
0356 }
0357 
0358 #undef CURRENT_EL
0359 #define CURRENT_EL b
0360 //! b handler (Bold)
0361 /*! ECMA-376, 18.8.2, p. 1947.
0362  Displays characters in bold face font style.
0363 
0364  Parent elements:
0365  - [done] font (§18.8.22)
0366  - [done] rPr (§18.4.7)
0367 
0368  Child elements:
0369  - none
0370 */
0371 KoFilter::ConversionStatus XlsxXmlCommonReader::read_b()
0372 {
0373     READ_PROLOGUE
0374 
0375     const QXmlStreamAttributes attrs(attributes());
0376     TRY_READ_ATTR_WITHOUT_NS(val)
0377     const bool bold = MSOOXML::Utils::convertBooleanAttr(val, true);
0378     m_currentTextStyleProperties->setFontWeight(bold ? QFont::Bold : QFont::Normal);
0379 
0380     readNext();
0381     READ_EPILOGUE
0382 }
0383 
0384 #undef CURRENT_EL
0385 #define CURRENT_EL outline
0386 //! outline handler (Outline)
0387 /*!
0388 
0389  Parent elements:
0390  - [done] font (§18.8.22)
0391  - [done] rPr (§18.4.7)
0392 
0393  Child elements:
0394  - none
0395 */
0396 KoFilter::ConversionStatus XlsxXmlCommonReader::read_outline()
0397 {
0398     READ_PROLOGUE
0399 
0400     const QXmlStreamAttributes attrs(attributes());
0401     TRY_READ_ATTR_WITHOUT_NS(val)
0402     if (val == "1") {
0403         m_currentTextStyleProperties->setTextOutline(QPen(Qt::SolidLine));
0404     }
0405 
0406     readNext();
0407     READ_EPILOGUE
0408 }
0409 
0410 #undef CURRENT_EL
0411 #define CURRENT_EL strike
0412 //! strike handler (Strike Through)
0413 /*! ECMA-376, 18.4.10, p. 1913.
0414  This element draws a strikethrough line through the horizontal middle of the text.
0415 
0416  Parent elements:
0417  - [done] font (§18.8.22)
0418  - [done] rPr (§18.4.7)
0419 
0420  Child elements:
0421  - none
0422 */
0423 KoFilter::ConversionStatus XlsxXmlCommonReader::read_strike()
0424 {
0425     READ_PROLOGUE
0426 
0427     m_currentTextStyleProperties->setStrikeOutStyle(KoCharacterStyle::SolidLine);
0428     m_currentTextStyleProperties->setStrikeOutType(KoCharacterStyle::SingleLine);
0429 
0430     readNext();
0431     READ_EPILOGUE
0432 }
0433 
0434 #undef CURRENT_EL
0435 #define CURRENT_EL u
0436 //! u handler (Underline)
0437 /*! ECMA-376, 18.4.13, p. 1914.
0438  This element represents the underline formatting style.
0439 
0440  Parent elements:
0441  - [done] font (§18.8.22)
0442  - [done] rPr (§18.4.7)
0443 
0444  Child elements:
0445  - none
0446 */
0447 KoFilter::ConversionStatus XlsxXmlCommonReader::read_u()
0448 {
0449     READ_PROLOGUE
0450     const QXmlStreamAttributes attrs(attributes());
0451 
0452     TRY_READ_ATTR_WITHOUT_NS(val)
0453     if (!val.isEmpty()) {
0454         MSOOXML::Utils::setupUnderLineStyle(val, m_currentTextStyleProperties);
0455     }
0456 
0457     readNext();
0458     READ_EPILOGUE
0459 }
0460 
0461 #undef CURRENT_EL
0462 #define CURRENT_EL color
0463 //! color
0464 /*
0465  Parent elements:
0466  - [done] font (§18.8.22);
0467  - [done] rPr (§18.4.7)
0468 
0469  Child elements:
0470  - none
0471 */
0472 KoFilter::ConversionStatus XlsxXmlCommonReader::read_color()
0473 {
0474     READ_PROLOGUE
0475     const QXmlStreamAttributes attrs(attributes());
0476 
0477     TRY_READ_ATTR_WITHOUT_NS(indexed)
0478     TRY_READ_ATTR_WITHOUT_NS(rgb)
0479     TRY_READ_ATTR_WITHOUT_NS(theme)
0480     TRY_READ_ATTR_WITHOUT_NS(tint)
0481 
0482     if (!indexed.isEmpty()) {
0483         int index = indexed.toInt();
0484         if (index >= 0 && index < 64) {
0485             m_currentColor = QString("#%1").arg(m_colorIndices.at(index));
0486         }
0487     }
0488     if (!rgb.isEmpty()) {
0489         m_currentColor = QString("#" + rgb.right(rgb.length()-2));
0490     }
0491     if (!theme.isEmpty()) {
0492         // Xlsx seems to switch these indices
0493         if (theme == "0" ) {
0494             theme = "1";
0495         }
0496         else if (theme == "1" ) {
0497             theme = "0";
0498         }
0499         else if (theme == "2") {
0500             theme = "3";
0501         }
0502         else if (theme == "3") {
0503             theme = "2";
0504         }
0505         MSOOXML::DrawingMLColorSchemeItemBase *colorItemBase = m_themes->colorScheme.value(theme);
0506         if (colorItemBase) {
0507             m_currentColor = colorItemBase->value();
0508         }
0509     }
0510     if (!tint.isEmpty()) {
0511         m_currentColor = tintedColor(m_currentColor, tint.toDouble());
0512     }
0513 
0514     readNext();
0515     READ_EPILOGUE
0516 }