File indexing completed on 2024-05-19 16:09:58
0001 /* This file is part of the KDE project 0002 * Copyright (C) 2006, 2008, 2010 Thomas Zander <zander@kde.org> 0003 * Copyright (C) 2008 Pierre Ducroquet <pinaraf@pinaraf.info> 0004 * Copyright (C) 2008 Sebastian Sauer <mail@dipe.org> 0005 * 0006 * This library is free software; you can redistribute it and/or 0007 * modify it under the terms of the GNU Library General Public 0008 * License as published by the Free Software Foundation; either 0009 * version 2 of the License, or (at your option) any later version. 0010 * 0011 * This library is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0014 * Library General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU Library General Public License 0017 * along with this library; see the file COPYING.LIB. If not, write to 0018 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0019 * Boston, MA 02110-1301, USA. 0020 */ 0021 0022 #include "KWPageStyle.h" 0023 #include "KWPageStyle_p.h" 0024 0025 #include <KoXmlWriter.h> 0026 #include <KoXmlNS.h> 0027 #include <KoUnit.h> 0028 #include <KoColorBackground.h> 0029 #include <KoPatternBackground.h> 0030 #include <KoImageCollection.h> 0031 #include <KoOdfLoadingContext.h> 0032 0033 #include <QBuffer> 0034 #include <QColor> 0035 0036 KWPageStylePrivate::~KWPageStylePrivate() 0037 { 0038 } 0039 0040 void KWPageStylePrivate::clear() 0041 { 0042 displayName.clear(); 0043 headerDistance = 10; // ~3mm 0044 footerDistance = 10; 0045 headerMinimumHeight = 10; // includes spacing 0046 footerMinimumHeight = 10; // includes spacing 0047 headers = Words::HFTypeNone; 0048 footers = Words::HFTypeNone; 0049 pageUsage = KWPageStyle::AllPages; 0050 columns.reset(); 0051 direction = KoText::AutoDirection; 0052 headerDynamicSpacing = false; 0053 footerDynamicSpacing = false; 0054 fullPageBackground.clear(); 0055 nextStyleName.clear(); 0056 } 0057 0058 /////////// 0059 0060 KWPageStyle::KWPageStyle(const QString &name, const QString &displayname) 0061 : d (new KWPageStylePrivate()) 0062 { 0063 d->name = name; 0064 if (!displayname.isEmpty() && displayname != name) 0065 d->displayName = displayname; 0066 } 0067 0068 KWPageStyle::KWPageStyle(const KWPageStyle &ps) 0069 : d(ps.d) 0070 { 0071 } 0072 0073 KWPageStyle::KWPageStyle() 0074 { 0075 } 0076 0077 bool KWPageStyle::isValid() const 0078 { 0079 return d && !d->name.isEmpty(); 0080 } 0081 0082 0083 KWPageStyle &KWPageStyle::operator=(const KWPageStyle &ps) 0084 { 0085 d = ps.d; 0086 return *this; 0087 } 0088 0089 KWPageStyle::~KWPageStyle() 0090 { 0091 } 0092 0093 KWPageStyle::PageUsageType KWPageStyle::pageUsage() const 0094 { 0095 return d ? d->pageUsage : KWPageStyle::AllPages; 0096 } 0097 0098 void KWPageStyle::setPageUsage(KWPageStyle::PageUsageType pageusage) const 0099 { 0100 d->pageUsage = pageusage; 0101 } 0102 0103 void KWPageStyle::setFooterPolicy(Words::HeaderFooterType p) 0104 { 0105 d->footers = p; 0106 } 0107 0108 void KWPageStyle::setHeaderPolicy(Words::HeaderFooterType p) 0109 { 0110 d->headers = p; 0111 } 0112 0113 KoPageLayout KWPageStyle::pageLayout() const 0114 { 0115 return d->pageLayout; 0116 } 0117 0118 void KWPageStyle::setPageLayout(const KoPageLayout &pageLayout) 0119 { 0120 d->pageLayout = pageLayout; 0121 } 0122 0123 KoColumns KWPageStyle::columns() const 0124 { 0125 return d->columns; 0126 } 0127 0128 void KWPageStyle::setColumns(const KoColumns &columns) 0129 { 0130 d->columns = columns; 0131 } 0132 0133 Words::HeaderFooterType KWPageStyle::headerPolicy() const 0134 { 0135 return d->headers; 0136 } 0137 0138 Words::HeaderFooterType KWPageStyle::footerPolicy() const 0139 { 0140 return d->footers; 0141 } 0142 0143 qreal KWPageStyle::headerDistance() const 0144 { 0145 return d->headerDistance; 0146 } 0147 0148 void KWPageStyle::setHeaderDistance(qreal distance) 0149 { 0150 d->headerDistance = distance; 0151 } 0152 0153 bool KWPageStyle::headerDynamicSpacing() const 0154 { 0155 return d->headerDynamicSpacing; 0156 } 0157 0158 void KWPageStyle::setHeaderDynamicSpacing(bool dynamic) 0159 { 0160 d->headerDynamicSpacing = dynamic; 0161 } 0162 0163 qreal KWPageStyle::headerMinimumHeight() const 0164 { 0165 return d->headerMinimumHeight; 0166 } 0167 0168 void KWPageStyle::setHeaderMinimumHeight(qreal height) 0169 { 0170 d->headerMinimumHeight = height; 0171 } 0172 0173 qreal KWPageStyle::footerMinimumHeight() const 0174 { 0175 return d->footerMinimumHeight; 0176 } 0177 0178 void KWPageStyle::setFooterMinimumHeight(qreal height) 0179 { 0180 d->footerMinimumHeight = height; 0181 } 0182 0183 qreal KWPageStyle::footerDistance() const 0184 { 0185 return d->footerDistance; 0186 } 0187 0188 void KWPageStyle::setFooterDistance(qreal distance) 0189 { 0190 d->footerDistance = distance; 0191 } 0192 0193 bool KWPageStyle::footerDynamicSpacing() const 0194 { 0195 return d->footerDynamicSpacing; 0196 } 0197 0198 void KWPageStyle::setFooterDynamicSpacing(bool dynamic) 0199 { 0200 d->footerDynamicSpacing = dynamic; 0201 } 0202 0203 void KWPageStyle::clear() 0204 { 0205 d->clear(); 0206 } 0207 0208 QString KWPageStyle::name() const 0209 { 0210 return d->name; 0211 } 0212 0213 QString KWPageStyle::displayName() const 0214 { 0215 return d->displayName; 0216 } 0217 0218 QSharedPointer<KoShapeBackground> KWPageStyle::background() const 0219 { 0220 return d->fullPageBackground; 0221 } 0222 0223 void KWPageStyle::setBackground(QSharedPointer<KoShapeBackground> background) 0224 { 0225 d->fullPageBackground = background; 0226 } 0227 0228 KoGenStyle KWPageStyle::saveOdf() const 0229 { 0230 KoGenStyle pageLayout = d->pageLayout.saveOdf(); 0231 pageLayout.setAutoStyleInStylesDotXml(true); 0232 0233 switch (d->pageUsage) { 0234 case LeftPages: 0235 pageLayout.addAttribute("style:page-usage", "left"); 0236 break; 0237 case MirroredPages: 0238 pageLayout.addAttribute("style:page-usage", "mirrored"); 0239 break; 0240 case RightPages: 0241 pageLayout.addAttribute("style:page-usage", "right"); 0242 break; 0243 default: 0244 pageLayout.addAttribute("style:page-usage", "all"); 0245 break; 0246 } 0247 0248 // Save background color if it is set 0249 if (d->fullPageBackground) 0250 { 0251 KoColorBackground *colorBackground = dynamic_cast<KoColorBackground*>(d->fullPageBackground.data()); 0252 if (colorBackground) 0253 pageLayout.addProperty("fo:background-color", colorBackground->color().name()); 0254 } 0255 0256 // save column data 0257 d->columns.saveOdf(pageLayout); 0258 0259 //<style:footnote-sep style:adjustment="left" style:width="0.5pt" style:rel-width="20%" style:line-style="solid"/> 0260 //writer.startElement("style:footnote-sep"); 0261 // TODO 0262 //writer.addAttribute("style:adjustment",) 0263 //writer.addAttribute("style:width",) 0264 //writer.addAttribute("style:rel-width",) 0265 //writer.addAttribute("style:line-style",) 0266 //writer.endElement(); 0267 0268 0269 0270 if (headerPolicy() != Words::HFTypeNone) { 0271 QBuffer buffer; 0272 buffer.open(QIODevice::WriteOnly); 0273 KoXmlWriter writer(&buffer); 0274 0275 writer.startElement("style:header-style"); 0276 writer.startElement("style:header-footer-properties"); 0277 writer.addAttributePt("fo:min-height", headerMinimumHeight()); 0278 writer.addAttributePt("fo:margin-bottom", headerDistance()); 0279 writer.addAttribute("style:dynamic-spacing", headerDynamicSpacing()); 0280 // TODO there are quite some more properties we want to at least preserve between load and save 0281 writer.endElement(); 0282 writer.endElement(); 0283 0284 QString contentElement = QString::fromUtf8(buffer.buffer(), buffer.buffer().size()); 0285 // the 1_ 2_ is needed to get the correct order 0286 pageLayout.addStyleChildElement("1_headerStyle", contentElement); 0287 } 0288 if (footerPolicy() != Words::HFTypeNone) { 0289 QBuffer buffer; 0290 buffer.open(QIODevice::WriteOnly); 0291 KoXmlWriter writer(&buffer); 0292 0293 writer.startElement("style:footer-style"); 0294 writer.startElement("style:header-footer-properties"); 0295 writer.addAttributePt("fo:min-height", footerMinimumHeight()); 0296 writer.addAttributePt("fo:margin-top", footerDistance()); 0297 writer.addAttribute("style:dynamic-spacing", footerDynamicSpacing()); 0298 // TODO there are quite some more properties we want to at least preserve between load and save 0299 writer.endElement(); 0300 writer.endElement(); 0301 0302 QString contentElement = QString::fromUtf8(buffer.buffer(), buffer.buffer().size()); 0303 pageLayout.addStyleChildElement("2_footerStyle", contentElement); 0304 } 0305 0306 // TODO see how we should save margins if we use the 'closest to binding' stuff. 0307 0308 return pageLayout; 0309 } 0310 0311 void KWPageStyle::loadOdf(KoOdfLoadingContext &context, const KoXmlElement &masterNode, const KoXmlElement &style, KoDocumentResourceManager *documentResources) 0312 { 0313 d->pageLayout.loadOdf(style); 0314 KoXmlElement props = KoXml::namedItemNS(style, KoXmlNS::style, "page-layout-properties"); 0315 if (props.isNull()) 0316 return; 0317 QString direction = props.attributeNS(KoXmlNS::style, "writing-mode", "lr-tb"); 0318 d->direction = KoText::directionFromString(direction); 0319 0320 QString pageUsage = style.attributeNS(KoXmlNS::style, "page-usage", "all"); 0321 if (pageUsage == "left") { 0322 d->pageUsage = LeftPages; 0323 } else if (pageUsage == "mirrored") { 0324 d->pageUsage = MirroredPages; 0325 } else if (pageUsage == "right") { 0326 d->pageUsage = RightPages; 0327 } else { // "all" 0328 d->pageUsage = AllPages; 0329 } 0330 0331 d->columns.loadOdf(props); 0332 0333 KoXmlElement header = KoXml::namedItemNS(style, KoXmlNS::style, "header-style"); 0334 if (! header.isNull()) { 0335 KoXmlElement hfprops = KoXml::namedItemNS(header, KoXmlNS::style, "header-footer-properties"); 0336 if (! hfprops.isNull()) { 0337 d->headerDistance = KoUnit::parseValue(hfprops.attributeNS(KoXmlNS::fo, "margin-bottom")); 0338 d->headerMinimumHeight = KoUnit::parseValue(hfprops.attributeNS(KoXmlNS::fo, "min-height")); 0339 const QString dynamicSpacing(hfprops.attributeNS(KoXmlNS::style, "dynamic-spacing")); 0340 d->headerDynamicSpacing = dynamicSpacing == "true"; 0341 } 0342 // TODO there are quite some more properties we want to at least preserve between load and save 0343 } 0344 0345 KoXmlElement footer = KoXml::namedItemNS(style, KoXmlNS::style, "footer-style"); 0346 if (! footer.isNull()) { 0347 KoXmlElement hfprops = KoXml::namedItemNS(footer, KoXmlNS::style, "header-footer-properties"); 0348 if (! hfprops.isNull()) { 0349 d->footerDistance = KoUnit::parseValue(hfprops.attributeNS(KoXmlNS::fo, "margin-top")); 0350 d->footerMinimumHeight = KoUnit::parseValue(hfprops.attributeNS(KoXmlNS::fo, "min-height")); 0351 const QString dynamicSpacing(hfprops.attributeNS(KoXmlNS::style, "dynamic-spacing")); 0352 d->footerDynamicSpacing = dynamicSpacing == "true"; 0353 } 0354 // TODO there are quite some more properties we want to at least preserve between load and save 0355 } 0356 0357 // Load background picture 0358 KoXmlElement propBackgroundImage = KoXml::namedItemNS(props, KoXmlNS::style, "background-image"); 0359 if (!propBackgroundImage.isNull()) { 0360 const QString href = propBackgroundImage.attributeNS(KoXmlNS::xlink, "href", QString()); 0361 if (!href.isEmpty()) { 0362 QSharedPointer<KoPatternBackground> background = QSharedPointer<KoPatternBackground>(new KoPatternBackground(documentResources->imageCollection())); 0363 d->fullPageBackground = background; 0364 0365 KoImageCollection *imageCollection = documentResources->imageCollection(); 0366 if (imageCollection != 0) { 0367 KoImageData *imageData = imageCollection->createImageData(href,context.store()); 0368 background->setPattern(imageData); 0369 } 0370 } 0371 // TODO load another possible attributes 0372 } 0373 0374 // Load background color 0375 QString backgroundColor = props.attributeNS(KoXmlNS::fo, "background-color", QString()); 0376 if (!backgroundColor.isNull() && d->fullPageBackground == 0) { 0377 0378 if (backgroundColor == "transparent") { 0379 d->fullPageBackground.clear(); 0380 } 0381 else { 0382 d->fullPageBackground = QSharedPointer<KoShapeBackground>(new KoColorBackground(QColor(backgroundColor))); 0383 } 0384 } 0385 0386 // Load next master-page style name 0387 d->nextStyleName = masterNode.attributeNS(KoXmlNS::style, "next-style-name", QString()); 0388 } 0389 0390 QString KWPageStyle::nextStyleName() const 0391 { 0392 return d->nextStyleName; 0393 } 0394 0395 void KWPageStyle::setNextStyleName(const QString &nextStyleName) 0396 { 0397 d->nextStyleName = nextStyleName; 0398 } 0399 0400 KoText::Direction KWPageStyle::direction() const 0401 { 0402 return d->direction; 0403 } 0404 0405 void KWPageStyle::setDirection(KoText::Direction direction) 0406 { 0407 d->direction = direction; 0408 } 0409 0410 bool KWPageStyle::operator==(const KWPageStyle &other) const 0411 { 0412 bool equals = d == other.d; 0413 return equals; 0414 } 0415 0416 KWPageStylePrivate *KWPageStyle::priv() 0417 { 0418 return d.data(); 0419 } 0420 0421 const KWPageStylePrivate *KWPageStyle::priv() const 0422 { 0423 return d.data(); 0424 } 0425 0426 uint KWPageStyle::hash() const 0427 { 0428 return ((uint) d) + 1; 0429 } 0430 0431 bool KWPageStyle::isPageSpread() const 0432 { 0433 return d->pageLayout.leftMargin < 0; 0434 } 0435 0436 uint qHash(const KWPageStyle &style) 0437 { 0438 return style.hash(); 0439 } 0440 0441 void KWPageStyle::detach(const QString &newName, const QString &displayName) 0442 { 0443 d->fullPageBackground.clear(); 0444 d.detach(); 0445 d->name = newName; 0446 d->displayName = displayName; 0447 }