Warning, file /office/calligra/libs/flake/KoOdfWorkaround.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* This file is part of the KDE project 0002 Copyright (C) 2009 Thorsten Zachmann <zachmann@kde.org> 0003 Copyright (C) 2009 Johannes Simon <johannes.simon@gmail.com> 0004 Copyright (C) 2010,2011 Jan Hambrecht <jaham@gmx.net> 0005 Copyright 2012 Friedrich W. H. Kossebau <kossebau@kde.org> 0006 0007 This library is free software; you can redistribute it and/or 0008 modify it under the terms of the GNU Library General Public 0009 License as published by the Free Software Foundation; either 0010 version 2 of the License, or (at your option) any later version. 0011 0012 This library is distributed in the hope that it will be useful, 0013 but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0015 Library General Public License for more details. 0016 0017 You should have received a copy of the GNU Library General Public License 0018 along with this library; see the file COPYING.LIB. If not, write to 0019 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0020 * Boston, MA 02110-1301, USA. 0021 */ 0022 0023 #include "KoOdfWorkaround.h" 0024 0025 #include "KoShapeLoadingContext.h" 0026 #include "KoShape.h" 0027 #include "KoPathShape.h" 0028 #include "KoColorBackground.h" 0029 #include <KoOdfLoadingContext.h> 0030 #include <KoXmlReader.h> 0031 #include <KoXmlNS.h> 0032 #include <KoStyleStack.h> 0033 #include <KoUnit.h> 0034 0035 #include <QPen> 0036 #include <QColor> 0037 0038 #include <FlakeDebug.h> 0039 0040 static bool s_workaroundPresentationPlaceholderBug = false; 0041 0042 void KoOdfWorkaround::fixSkew(QStringList ¶ms, KoShapeLoadingContext &context) 0043 { 0044 if (context.odfLoadingContext().generatorType() == KoOdfLoadingContext::OpenOffice) { 0045 debugFlake << "Work around OO bug: skewa clockwize and radians as default unit"; 0046 QString angle = params[0].trimmed(); 0047 if (angle.startsWith('-')) { 0048 angle = angle.remove(0, 1); 0049 } else { 0050 angle = angle.prepend('-'); 0051 } 0052 const QChar c = angle.at(angle.length() -1); 0053 if (c.isDigit()) { 0054 angle.append("rad"); 0055 } 0056 params[0] = angle; 0057 } 0058 } 0059 0060 void KoOdfWorkaround::fixRotate(QStringList ¶ms, KoShapeLoadingContext &context) 0061 { 0062 if (context.odfLoadingContext().generatorType() == KoOdfLoadingContext::OpenOffice) { 0063 debugFlake << "Work around OO bug: rotates clockwize and radians as default unit"; 0064 QString angle = params[0].trimmed(); 0065 if (angle.startsWith('-')) { 0066 angle = angle.remove(0, 1); 0067 } else { 0068 angle = angle.prepend('-'); 0069 } 0070 const QChar c = angle.at(angle.length() -1); 0071 if (c.isDigit()) { 0072 angle.append("rad"); 0073 } 0074 params[0] = angle; 0075 } 0076 } 0077 0078 void KoOdfWorkaround::fixPenWidth(QPen & pen, KoShapeLoadingContext &context) 0079 { 0080 if (context.odfLoadingContext().generatorType() == KoOdfLoadingContext::OpenOffice && pen.widthF() == 0.0) { 0081 pen.setWidthF(0.5); 0082 debugFlake << "Work around OO bug with pen width 0"; 0083 } 0084 } 0085 0086 void KoOdfWorkaround::fixEnhancedPath(QString & path, const KoXmlElement &element, KoShapeLoadingContext &context) 0087 { 0088 if (context.odfLoadingContext().generatorType() == KoOdfLoadingContext::OpenOffice) { 0089 if (path.isEmpty() && element.attributeNS(KoXmlNS::draw, "type", "") == "ellipse") { 0090 path = "U 10800 10800 10800 10800 0 360 Z N"; 0091 } 0092 } 0093 } 0094 0095 void KoOdfWorkaround::fixEnhancedPathPolarHandlePosition(QString &position, const KoXmlElement &element, KoShapeLoadingContext &context) 0096 { 0097 if (context.odfLoadingContext().generatorType() == KoOdfLoadingContext::OpenOffice) { 0098 if (element.hasAttributeNS(KoXmlNS::draw, "handle-polar")) { 0099 QStringList tokens = position.simplified().split(' '); 0100 if (tokens.count() == 2) { 0101 position = tokens[1] + ' ' + tokens[0]; 0102 } 0103 } 0104 } 0105 } 0106 0107 QColor KoOdfWorkaround::fixMissingFillColor(const KoXmlElement &element, KoShapeLoadingContext &context) 0108 { 0109 // Default to an invalid color 0110 QColor color; 0111 0112 if (element.prefix() == "chart") { 0113 KoStyleStack &styleStack = context.odfLoadingContext().styleStack(); 0114 styleStack.save(); 0115 0116 bool hasStyle = element.hasAttributeNS(KoXmlNS::chart, "style-name"); 0117 if (hasStyle) { 0118 context.odfLoadingContext().fillStyleStack(element, KoXmlNS::chart, "style-name", "chart"); 0119 styleStack.setTypeProperties("graphic"); 0120 } 0121 0122 if (context.odfLoadingContext().generatorType() == KoOdfLoadingContext::OpenOffice) { 0123 if (hasStyle && !styleStack.hasProperty(KoXmlNS::draw, "fill") && 0124 styleStack.hasProperty(KoXmlNS::draw, "fill-color")) { 0125 color = QColor(styleStack.property(KoXmlNS::draw, "fill-color")); 0126 } else if (!hasStyle || (!styleStack.hasProperty(KoXmlNS::draw, "fill") 0127 && !styleStack.hasProperty(KoXmlNS::draw, "fill-color"))) { 0128 KoXmlElement plotAreaElement = element.parentNode().toElement(); 0129 KoXmlElement chartElement = plotAreaElement.parentNode().toElement(); 0130 0131 if (element.tagName() == "wall") { 0132 if (chartElement.hasAttributeNS(KoXmlNS::chart, "class")) { 0133 QString chartType = chartElement.attributeNS(KoXmlNS::chart, "class"); 0134 // TODO: Check what default backgrounds for surface, stock and gantt charts are 0135 if (chartType == "chart:line" || 0136 chartType == "chart:area" || 0137 chartType == "chart:bar" || 0138 chartType == "chart:scatter") 0139 color = QColor(0xe0e0e0); 0140 } 0141 } else if (element.tagName() == "series") { 0142 if (chartElement.hasAttributeNS(KoXmlNS::chart, "class")) { 0143 QString chartType = chartElement.attributeNS(KoXmlNS::chart, "class"); 0144 // TODO: Check what default backgrounds for surface, stock and gantt charts are 0145 if (chartType == "chart:area" || 0146 chartType == "chart:bar") 0147 color = QColor(0x99ccff); 0148 } 0149 } 0150 else if (element.tagName() == "chart") 0151 color = QColor(0xffffff); 0152 } 0153 } 0154 0155 styleStack.restore(); 0156 } 0157 0158 return color; 0159 } 0160 0161 bool KoOdfWorkaround::fixMissingStroke(QPen &pen, const KoXmlElement &element, KoShapeLoadingContext &context, const KoShape *shape) 0162 { 0163 bool fixed = false; 0164 0165 if (context.odfLoadingContext().generatorType() == KoOdfLoadingContext::OpenOffice) { 0166 KoStyleStack &styleStack = context.odfLoadingContext().styleStack(); 0167 if (element.prefix() == "chart") { 0168 styleStack.save(); 0169 0170 bool hasStyle = element.hasAttributeNS(KoXmlNS::chart, "style-name"); 0171 if (hasStyle) { 0172 context.odfLoadingContext().fillStyleStack(element, KoXmlNS::chart, "style-name", "chart"); 0173 styleStack.setTypeProperties("graphic"); 0174 } 0175 0176 if (hasStyle && styleStack.hasProperty(KoXmlNS::draw, "stroke") && 0177 !styleStack.hasProperty(KoXmlNS::svg, "stroke-color")) { 0178 fixed = true; 0179 pen.setColor(Qt::black); 0180 } else if (!hasStyle) { 0181 KoXmlElement plotAreaElement = element.parentNode().toElement(); 0182 KoXmlElement chartElement = plotAreaElement.parentNode().toElement(); 0183 0184 if (element.tagName() == "series") { 0185 QString chartType = chartElement.attributeNS(KoXmlNS::chart, "class"); 0186 if (!chartType.isEmpty()) { 0187 // TODO: Check what default backgrounds for surface, stock and gantt charts are 0188 if (chartType == "chart:line" || 0189 chartType == "chart:scatter") { 0190 fixed = true; 0191 pen = QPen(0x99ccff); 0192 } 0193 } 0194 } else if (element.tagName() == "legend") { 0195 fixed = true; 0196 pen = QPen(Qt::black); 0197 } 0198 } 0199 styleStack.restore(); 0200 } 0201 else { 0202 const KoPathShape *pathShape = dynamic_cast<const KoPathShape*>(shape); 0203 if (pathShape) { 0204 const QString strokeColor(styleStack.property(KoXmlNS::svg, "stroke-color")); 0205 if (strokeColor.isEmpty()) { 0206 pen.setColor(Qt::black); 0207 } else { 0208 pen.setColor(strokeColor); 0209 } 0210 fixed = true; 0211 } 0212 } 0213 } 0214 0215 return fixed; 0216 } 0217 0218 bool KoOdfWorkaround::fixMissingStyle_DisplayLabel(const KoXmlElement &element, KoShapeLoadingContext &context) 0219 { 0220 Q_UNUSED(element); 0221 // If no axis style is specified, OpenOffice.org hides the axis' data labels 0222 if (context.odfLoadingContext().generatorType() == KoOdfLoadingContext::OpenOffice) 0223 return false; 0224 0225 // In all other cases, they're visible 0226 return true; 0227 } 0228 0229 void KoOdfWorkaround::setFixPresentationPlaceholder(bool fix, KoShapeLoadingContext &context) 0230 { 0231 KoOdfLoadingContext::GeneratorType type(context.odfLoadingContext().generatorType()); 0232 if (type == KoOdfLoadingContext::OpenOffice || type == KoOdfLoadingContext::MicrosoftOffice) { 0233 s_workaroundPresentationPlaceholderBug = fix; 0234 } 0235 } 0236 0237 bool KoOdfWorkaround::fixPresentationPlaceholder() 0238 { 0239 return s_workaroundPresentationPlaceholderBug; 0240 } 0241 0242 void KoOdfWorkaround::fixPresentationPlaceholder(KoShape *shape) 0243 { 0244 if (s_workaroundPresentationPlaceholderBug && !shape->hasAdditionalAttribute("presentation:placeholder")) { 0245 shape->setAdditionalAttribute("presentation:placeholder", "true"); 0246 } 0247 } 0248 0249 QSharedPointer<KoColorBackground> KoOdfWorkaround::fixBackgroundColor(const KoShape *shape, KoShapeLoadingContext &context) 0250 { 0251 QSharedPointer<KoColorBackground> colorBackground; 0252 KoOdfLoadingContext &odfContext = context.odfLoadingContext(); 0253 if (odfContext.generatorType() == KoOdfLoadingContext::OpenOffice) { 0254 const KoPathShape *pathShape = dynamic_cast<const KoPathShape*>(shape); 0255 //check shape type 0256 if (pathShape) { 0257 KoStyleStack &styleStack = odfContext.styleStack(); 0258 const QString color(styleStack.property(KoXmlNS::draw, "fill-color")); 0259 if (color.isEmpty()) { 0260 colorBackground = QSharedPointer<KoColorBackground>(new KoColorBackground(QColor(153, 204, 255))); 0261 } else { 0262 colorBackground = QSharedPointer<KoColorBackground>(new KoColorBackground(color)); 0263 } 0264 } 0265 } 0266 return colorBackground; 0267 } 0268 0269 void KoOdfWorkaround::fixGluePointPosition(QString &positionString, KoShapeLoadingContext &context) 0270 { 0271 KoOdfLoadingContext::GeneratorType type(context.odfLoadingContext().generatorType()); 0272 if (type == KoOdfLoadingContext::OpenOffice && !positionString.endsWith('%')) { 0273 const qreal pos = KoUnit::parseValue(positionString); 0274 positionString = QString("%1%%").arg(KoUnit::toMillimeter(pos)); 0275 } 0276 } 0277 0278 void KoOdfWorkaround::fixMissingFillRule(Qt::FillRule& fillRule, KoShapeLoadingContext& context) 0279 { 0280 if ((context.odfLoadingContext().generatorType() == KoOdfLoadingContext::OpenOffice)) { 0281 fillRule = Qt::OddEvenFill; 0282 } 0283 } 0284 0285 bool KoOdfWorkaround::fixAutoGrow(KoTextShapeDataBase::ResizeMethod method, KoShapeLoadingContext &context) 0286 { 0287 bool fix = false; 0288 if (context.odfLoadingContext().generatorType() == KoOdfLoadingContext::OpenOffice) { 0289 if (method == KoTextShapeDataBase::AutoGrowWidth || method == KoTextShapeDataBase::AutoGrowHeight || method == KoTextShapeDataBase::AutoGrowWidthAndHeight) { 0290 fix = true; 0291 } 0292 } 0293 return fix; 0294 } 0295 0296 bool KoOdfWorkaround::fixEllipse(const QString &kind, KoShapeLoadingContext &context) 0297 { 0298 bool radiusGiven = false; 0299 if (context.odfLoadingContext().generatorType() == KoOdfLoadingContext::OpenOffice) { 0300 if (kind == "section" || kind == "arc") { 0301 radiusGiven = true; 0302 } 0303 } 0304 return radiusGiven; 0305 } 0306 0307 void KoOdfWorkaround::fixBadFormulaHiddenForStyleCellProtect(QString& value) 0308 { 0309 if (value.endsWith(QLatin1String("Formula.hidden"))) { 0310 const int length = value.length(); 0311 value[length-14] = QLatin1Char('f'); 0312 value[length-7] = QLatin1Char('-'); 0313 } 0314 } 0315 0316 void KoOdfWorkaround::fixBadDateForTextTime(QString &value) 0317 { 0318 if (value.startsWith(QLatin1String("0-00-00T"))) { 0319 value.remove(0, 8); 0320 } 0321 } 0322 0323 void KoOdfWorkaround::fixClipRectOffsetValuesString(QString &offsetValuesString) 0324 { 0325 if (! offsetValuesString.contains(QLatin1Char(','))) { 0326 // assumes no spaces existing between values and units 0327 offsetValuesString = offsetValuesString.simplified().replace(QLatin1Char(' '), QLatin1Char(',')); 0328 } 0329 } 0330 0331 QString KoOdfWorkaround::fixTableTemplateName(const KoXmlElement &e) 0332 { 0333 return e.attributeNS(KoXmlNS::text, "style-name", QString()); 0334 } 0335 0336 QString KoOdfWorkaround::fixTableTemplateCellStyleName(const KoXmlElement &e) 0337 { 0338 return e.attributeNS(KoXmlNS::text, "style-name", QString()); 0339 } 0340 0341 static const struct { 0342 const char* oldPath; 0343 const char* newPath; 0344 } markerPathMapping[] = { 0345 // Arrow 0346 {"m10 0-10 30h20z", 0347 "M10 0l-10 30h20z"}, 0348 // Square 0349 {"m0 0h10v10h-10", 0350 "M0 0h10v10h-10z"}, 0351 // Small Arrow 0352 {"m1321 3493h-1321l702-3493z", 0353 "M1321 3493h-1321l702-3493z"}, 0354 // Dimension Lines 0355 {"M0 0h278 278 280v36 36 38h-278-278-280v-36-36z", 0356 "m0 0h278 278 280v36 36 38h-278-278-280v-36-36z"}, 0357 // Double Arrow 0358 {"m737 1131h394l-564-1131-567 1131h398l-398 787h1131z", 0359 "M737 1131h394l-564-1131-567 1131h398l-398 787h1131z"}, 0360 // Rounded short Arrow 0361 {"m1009 1050-449-1008-22-30-29-12-34 12-21 26-449 1012-5 13v8l5 21 12 21 17 13 21 4h903l21-4 21-13 9-21 4-21v-8z", 0362 "M1009 1050l-449-1008-22-30-29-12-34 12-21 26-449 1012-5 13v8l5 21 12 21 17 13 21 4h903l21-4 21-13 9-21 4-21v-8z"}, 0363 // Symmetric Arrow 0364 {"m564 0-564 902h1131z", 0365 "M564 0l-564 902h1131z"}, 0366 // Line Arrow 0367 {"m0 2108v17 17l12 42 30 34 38 21 43 4 29-8 30-21 25-26 13-34 343-1532 339 1520 13 42 29 34 39 21 42 4 42-12 34-30 21-42v-39-12l-4 4-440-1998-9-42-25-39-38-25-43-8-42 8-38 25-26 39-8 42z", 0368 "M0 2108v17 17l12 42 30 34 38 21 43 4 29-8 30-21 25-26 13-34 343-1532 339 1520 13 42 29 34 39 21 42 4 42-12 34-30 21-42v-39-12l-4 4-440-1998-9-42-25-39-38-25-43-8-42 8-38 25-26 39-8 42z"}, 0369 // Rounded large Arrow 0370 {"m1127 2120-449-2006-9-42-25-39-38-25-38-8-43 8-38 25-25 39-9 42-449 2006v13l-4 9 9 42 25 38 38 25 42 9h903l42-9 38-25 26-38 8-42v-9z", 0371 "M1127 2120l-449-2006-9-42-25-39-38-25-38-8-43 8-38 25-25 39-9 42-449 2006v13l-4 9 9 42 25 38 38 25 42 9h903l42-9 38-25 26-38 8-42v-9z"}, 0372 // Circle 0373 {"m462 1118-102-29-102-51-93-72-72-93-51-102-29-102-13-105 13-102 29-106 51-102 72-89 93-72 102-50 102-34 106-9 101 9 106 34 98 50 93 72 72 89 51 102 29 106 13 102-13 105-29 102-51 102-72 93-93 72-98 51-106 29-101 13z", 0374 "M462 1118l-102-29-102-51-93-72-72-93-51-102-29-102-13-105 13-102 29-106 51-102 72-89 93-72 102-50 102-34 106-9 101 9 106 34 98 50 93 72 72 89 51 102 29 106 13 102-13 105-29 102-51 102-72 93-93 72-98 51-106 29-101 13z"}, 0375 // Square 45 0376 {"m0 564 564 567 567-567-567-564z", 0377 "M0 564l564 567 567-567-567-564z"}, 0378 // Arrow concave 0379 {"m1013 1491 118 89-567-1580-564 1580 114-85 136-68 148-46 161-17 161 13 153 46z", 0380 "M1013 1491l118 89-567-1580-564 1580 114-85 136-68 148-46 161-17 161 13 153 46z"}, 0381 // Short line Arrow 0382 {"m1500 0 1500 2789v211h-114l-1286-2392v2392h-200v-2392l-1286 2392h-114v-211z", 0383 "M1500 0l1500 2789v211h-114l-1286-2392v2392h-200v-2392l-1286 2392h-114v-211z"}, 0384 // Triangle unfilled 0385 {"m1500 0 1500 3000h-3000zm1500-2553-1176 2353h2353z", 0386 "M1500 0l1500 3000h-3000zM1500 447l-1176 2353h2353z"}, 0387 // Diamond unfilled 0388 {"m1500 0 1500 3000-1500 3000-1500-3000zm1500-2553-1276 2553 1276 2553 1276-2553z", 0389 "M1500 0l1500 3000-1500 3000-1500-3000zM1500 447l-1276 2553 1276 2553 1276-2553z"}, 0390 // Diamond 0391 {"m1500 0 1500 3000-1500 3000-1500-3000z", 0392 "M1500 0l1500 3000-1500 3000-1500-3000z"}, 0393 // Circle unfilled 0394 {"m1500 3000c-276 0-511-63-750-201s-411-310-549-549-201-474-201-750 63-511 201-750 310-411 549-549 474-201 750-201 511 63 750 201 411 310 549 549 201 474 201 750-63 511-201 750-310 411-549 549-474 201-750 201zm0-200c-239 0-443-55-650-174s-356-269-476-476-174-411-174-650 55-443 174-650 269-356 476-476c207-119 411-174 650-174s443 55 650 174c207 120 356 269 476 476s174 411 174 650-55 443-174 650-269 356-476 476c-207 119-411 174-650 174z", 0395 "M1500 3000c-276 0-511-63-750-201s-411-310-549-549-201-474-201-750 63-511 201-750 310-411 549-549 474-201 750-201 511 63 750 201 411 310 549 549 201 474 201 750-63 511-201 750-310 411-549 549-474 201-750 201zM1500 2800c-239 0-443-55-650-174s-356-269-476-476-174-411-174-650 55-443 174-650 269-356 476-476c207-119 411-174 650-174s443 55 650 174c207 120 356 269 476 476s174 411 174 650-55 443-174 650-269 356-476 476c-207 119-411 174-650 174z"}, 0396 // Square 45 unfilled 0397 {"m1500 3000-1500-1500 1500-1500 1500 1500zm-1500 1215-1215-1215 1215-1215 1215 1215z", 0398 "M1500 3000l-1500-1500 1500-1500 1500 1500zM1500 2715l-1215-1215 1215-1215 1215 1215z"}, 0399 // Square unfilled 0400 {"m0 0h300v300h-300zm20-280h260v260h-260z", 0401 "M0 0h300v300h-300zM20 20h260v260h-260z"}, 0402 // Half Circle unfilled 0403 {"m14971 0c21 229 29 423 29 653 0 690-79 1328-244 1943-165 614-416 1206-761 1804-345 597-733 1110-1183 1560-451 450-964 837-1562 1182-598 345-1190 596-1806 760-600 161-1223 240-1894 244v600h-100v-600c-671-4-1294-83-1894-244-616-164-1208-415-1806-760-598-345-1111-732-1562-1182-450-450-838-963-1183-1560-345-598-596-1190-761-1804-165-615-244-1253-244-1943 0-230 8-424 29-653l298 26 299 26c-18 211-26 390-26 601 0 635 72 1222 224 1787 151 566 383 1110 700 1659 318 550 674 1022 1088 1437 415 414 888 769 1438 1087 550 317 1095 548 1661 700 566 151 1154 223 1789 223s1223-72 1789-223c566-152 1111-383 1661-700 550-318 1023-673 1438-1087 414-415 770-887 1088-1437 317-549 549-1093 700-1659 152-565 224-1152 224-1787 0-211-8-390-26-601l299-26z", 0404 "M14971 0c21 229 29 423 29 653 0 690-79 1328-244 1943-165 614-416 1206-761 1804-345 597-733 1110-1183 1560-451 450-964 837-1562 1182s-1190 596-1806 760c-600 161-1223 240-1894 244v600h-100v-600c-671-4-1294-83-1894-244-616-164-1208-415-1806-760s-1111-732-1562-1182c-450-450-838-963-1183-1560-345-598-596-1190-761-1804-165-615-244-1253-244-1943 0-230 8-424 29-653l298 26 299 26c-18 211-26 390-26 601 0 635 72 1222 224 1787 151 566 383 1110 700 1659 318 550 674 1022 1088 1437 415 414 888 769 1438 1087 550 317 1095 548 1661 700 566 151 1154 223 1789 223s1223-72 1789-223c566-152 1111-383 1661-700 550-318 1023-673 1438-1087 414-415 770-887 1088-1437 317-549 549-1093 700-1659 152-565 224-1152 224-1787 0-211-8-390-26-601l299-26z"} 0405 }; 0406 static const int markerPathMappingSize = sizeof(markerPathMapping)/sizeof(markerPathMapping[0]); 0407 0408 void KoOdfWorkaround::fixMarkerPath(QString& path) 0409 { 0410 for (int i = 0; i < markerPathMappingSize; ++i) { 0411 if (path == QLatin1String(markerPathMapping[i].oldPath)) { 0412 path = QLatin1String(markerPathMapping[i].newPath); 0413 break; 0414 } 0415 } 0416 }