File indexing completed on 2025-01-19 13:27:35

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