File indexing completed on 2024-05-12 16:36:44
0001 /* This file is part of the KDE project 0002 * Copyright (C) 2007-2009 Thorsten Zachmann <zachmann@kde.org> 0003 * Copyright (C) 2010 Benjamin Port <port.benjamin@gmail.com> 0004 * This library is free software; you can redistribute it and/or 0005 * modify it under the terms of the GNU Library General Public 0006 * License as published by the Free Software Foundation; either 0007 * version 2 of the License, or ( at your option ) any later version. 0008 * 0009 * This library is distributed in the hope that it will be useful, 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 * Library General Public License for more details. 0013 * 0014 * You should have received a copy of the GNU Library General Public License 0015 * along with this library; see the file COPYING.LIB. If not, write to 0016 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 * Boston, MA 02110-1301, USA. 0018 */ 0019 0020 #include "KPrPage.h" 0021 0022 #include <QString> 0023 0024 #include <KoXmlNS.h> 0025 #include <KoXmlWriter.h> 0026 #include <KoOdfLoadingContext.h> 0027 #include <KoOdfStylesReader.h> 0028 #include <KoStyleStack.h> 0029 #include <KoGenStyle.h> 0030 #include <KoShapeLayer.h> 0031 #include <KoPALoadingContext.h> 0032 #include <KoPASavingContext.h> 0033 0034 #include "StageDebug.h" 0035 #include "KPrDocument.h" 0036 #include "KPrDeclarations.h" 0037 #include "KPresenter.h" 0038 #include "KPrPageApplicationData.h" 0039 #include "KPrMasterPage.h" 0040 #include "KPrNotes.h" 0041 #include "KPrPlaceholderShape.h" 0042 #include "KPrShapeManagerDisplayMasterStrategy.h" 0043 #include "KPrPageSelectStrategyFixed.h" 0044 #include "pagelayout/KPrPageLayout.h" 0045 #include "pagelayout/KPrPageLayouts.h" 0046 #include "pagelayout/KPrPageLayoutSharedSavingData.h" 0047 #include "pagelayout/KPrPlaceholder.h" 0048 #include "pageeffects/KPrPageEffectRegistry.h" 0049 #include "pageeffects/KPrPageEffect.h" 0050 #include "animations/KPrAnimationLoader.h" 0051 0052 class Q_DECL_HIDDEN KPrPage::Private 0053 { 0054 public: 0055 Private( KPrPage * page, KPrDocument * document ) 0056 : pageNotes( new KPrNotes( page, document ) ) 0057 , declarations( document->declarations() ) 0058 {} 0059 0060 ~Private() 0061 { 0062 delete pageNotes; 0063 } 0064 KPrNotes * pageNotes; 0065 QHash<KPrDeclarations::Type, QString> usedDeclaration; 0066 KPrDeclarations *declarations; 0067 0068 }; 0069 0070 KPrPage::KPrPage( KoPAMasterPage * masterPage, KPrDocument * document ) 0071 : KoPAPage( masterPage ) 0072 , KPrPageData(document) 0073 , d( new Private( this, document ) ) 0074 { 0075 setApplicationData( new KPrPageApplicationData() ); 0076 placeholders().init( 0, shapes() ); 0077 } 0078 0079 KPrPage::~KPrPage() 0080 { 0081 delete d; 0082 } 0083 0084 KPrPageApplicationData * KPrPage::pageData( KoPAPageBase * page ) 0085 { 0086 KPrPageApplicationData * data = dynamic_cast<KPrPageApplicationData *>( page->applicationData() ); 0087 Q_ASSERT( data ); 0088 return data; 0089 } 0090 0091 KPrNotes *KPrPage::pageNotes() 0092 { 0093 return d->pageNotes; 0094 } 0095 0096 void KPrPage::shapeAdded( KoShape * shape ) 0097 { 0098 Q_ASSERT( shape ); 0099 placeholders().shapeAdded( shape ); 0100 } 0101 0102 void KPrPage::shapeRemoved( KoShape * shape ) 0103 { 0104 Q_ASSERT( shape ); 0105 placeholders().shapeRemoved( shape ); 0106 } 0107 0108 void KPrPage::setLayout( KPrPageLayout * layout, KoPADocument * document ) 0109 { 0110 QSizeF pageSize( pageLayout().width, pageLayout().height ); 0111 KPrMasterPage * master = dynamic_cast<KPrMasterPage *>( masterPage() ); 0112 Q_ASSERT( master ); 0113 placeholders().setLayout( layout, document, shapes(), pageSize, master ? master->placeholders().styles() : QMap<QString, KoTextShapeData*>() ); 0114 debugStage << "master placeholders"; 0115 master->placeholders().debug(); 0116 } 0117 0118 KPrPageLayout * KPrPage::layout() const 0119 { 0120 return placeholders().layout(); 0121 } 0122 0123 bool KPrPage::loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context) 0124 { 0125 if (!KoPAPageBase::loadOdf(element, context)) { 0126 return false; 0127 } 0128 KPrPageApplicationData * data = dynamic_cast<KPrPageApplicationData *>( applicationData() ); 0129 Q_ASSERT( data ); 0130 0131 KoXmlElement animation = KoXml::namedItemNS(element, KoXmlNS::anim, "par"); 0132 0133 bool loadOldTransition = true; 0134 if (!animation.isNull()) { 0135 KoXmlElement animationElement; 0136 forEachElement(animationElement, animation) { 0137 if (animationElement.namespaceURI() == KoXmlNS::anim) { 0138 if (animationElement.tagName() == "par") { 0139 QString begin(animationElement.attributeNS(KoXmlNS::smil, "begin")); 0140 if (begin.endsWith(QLatin1String("begin"))) { 0141 KoXmlElement transitionElement(KoXml::namedItemNS(animationElement, KoXmlNS::anim, "transitionFilter" )); 0142 data->setPageEffect( KPrPageEffectRegistry::instance()->createPageEffect( transitionElement ) ); 0143 debugStage << "XXXXXXX found page transition"; 0144 loadOldTransition = false; 0145 } 0146 // check that the id is the correct one. 0147 0148 } 0149 if (animationElement.tagName() == "seq") { 0150 QString nodeType(animationElement.attributeNS(KoXmlNS::presentation, "node-type")); 0151 if (nodeType == "main-sequence") { 0152 KPrAnimationLoader al; 0153 al.loadOdf(animationElement, context); 0154 animations().init(al.animations()); 0155 } 0156 else { 0157 // not yet supported 0158 } 0159 } 0160 } 0161 } 0162 } 0163 0164 if (loadOldTransition) { 0165 KoOdfStylesReader& stylesReader = context.odfLoadingContext().stylesReader(); 0166 const KoXmlElement * styleElement = stylesReader.findContentAutoStyle( element.attributeNS( KoXmlNS::draw, "style-name" ), "drawing-page" ); 0167 if ( styleElement ) { 0168 #ifndef KOXML_USE_QDOM 0169 KoXmlNode node = styleElement->namedItemNS( KoXmlNS::style, "drawing-page-properties" ); 0170 #else 0171 KoXmlNode node; // XXX!!! 0172 #endif 0173 if ( node.isElement() ) { 0174 0175 data->setPageEffect( KPrPageEffectRegistry::instance()->createPageEffect( node.toElement() ) ); 0176 } 0177 } 0178 } 0179 // load page transition 0180 data->pageTransition().loadOdfAttributes(element, context); 0181 return true; 0182 } 0183 0184 void KPrPage::saveOdfPageContent( KoPASavingContext & paContext ) const 0185 { 0186 KoXmlWriter &writer(paContext.xmlWriter()); 0187 if ( layout() ) { 0188 KPrPageLayoutSharedSavingData * layouts = dynamic_cast<KPrPageLayoutSharedSavingData *>( paContext.sharedData( KPR_PAGE_LAYOUT_SHARED_SAVING_ID ) ); 0189 Q_ASSERT( layouts ); 0190 if ( layouts ) { 0191 QString layoutStyle = layouts->pageLayoutStyle( layout() ); 0192 if ( ! layoutStyle.isEmpty() ) { 0193 writer.addAttribute( "presentation:presentation-page-layout-name", layoutStyle ); 0194 } 0195 } 0196 } 0197 QHash<KPrDeclarations::Type, QString>::const_iterator it(d->usedDeclaration.constBegin()); 0198 for (; it != d->usedDeclaration.constEnd(); ++it) { 0199 switch (it.key()) { 0200 case KPrDeclarations::Footer: 0201 writer.addAttribute("presentation:use-footer-name", it.value()); 0202 break; 0203 case KPrDeclarations::Header: 0204 writer.addAttribute("presentation:use-header-name", it.value()); 0205 break; 0206 case KPrDeclarations::DateTime: 0207 writer.addAttribute("presentation:use-date-time-name", it.value()); 0208 break; 0209 } 0210 } 0211 KoPAPageBase::saveOdfPageContent( paContext ); 0212 } 0213 0214 void KPrPage::saveOdfPageStyleData( KoGenStyle &style, KoPASavingContext &paContext ) const 0215 { 0216 KoPAPage::saveOdfPageStyleData( style, paContext ); 0217 style.addProperty( "presentation:background-visible", ( m_pageProperties & DisplayMasterBackground ) == DisplayMasterBackground ); 0218 style.addProperty( "presentation:background-objects-visible", ( m_pageProperties & DisplayMasterShapes ) == DisplayMasterShapes ); 0219 style.addProperty( "presentation:display-date-time", ( m_pageProperties & DisplayDateTime ) == DisplayDateTime ); 0220 style.addProperty( "presentation:display-footer", ( m_pageProperties & DisplayFooter ) == DisplayFooter ); 0221 style.addProperty( "presentation:display-header", ( m_pageProperties & DisplayHeader ) == DisplayHeader ); 0222 style.addProperty( "presentation:display-page-number", ( m_pageProperties & DisplayPageNumber ) == DisplayPageNumber ); 0223 0224 KPrPageApplicationData * data = dynamic_cast<KPrPageApplicationData *>( applicationData() ); 0225 Q_ASSERT( data ); 0226 KPrPageEffect * pageEffect = data->pageEffect(); 0227 0228 if ( pageEffect ) { 0229 pageEffect->saveOdfSmilAttributes( style ); 0230 } 0231 data->pageTransition().saveOdfAttributes(style); 0232 } 0233 0234 void KPrPage::loadOdfPageTag( const KoXmlElement &element, KoPALoadingContext &loadingContext ) 0235 { 0236 KoPAPage::loadOdfPageTag( element, loadingContext ); 0237 0238 KoStyleStack& styleStack = loadingContext.odfLoadingContext().styleStack(); 0239 0240 int pageProperties = m_pageProperties & UseMasterBackground; 0241 if ( styleStack.property( KoXmlNS::presentation, "background-objects-visible" ) == "true" ) { 0242 pageProperties |= DisplayMasterShapes; 0243 } 0244 if ( styleStack.property( KoXmlNS::presentation, "background-visible" ) == "true" ) { 0245 pageProperties |= DisplayMasterBackground; 0246 } 0247 if ( styleStack.property( KoXmlNS::presentation, "display-header" ) == "true" ) { 0248 pageProperties |= DisplayHeader; 0249 } 0250 if ( styleStack.property( KoXmlNS::presentation, "display-footer" ) == "true" ) { 0251 pageProperties |= DisplayFooter; 0252 } 0253 if ( styleStack.property( KoXmlNS::presentation, "display-page-number" ) == "true" ) { 0254 pageProperties |= DisplayPageNumber; 0255 } 0256 if ( styleStack.property( KoXmlNS::presentation, "display-date-time" ) == "true" ) { 0257 pageProperties |= DisplayDateTime; 0258 } 0259 m_pageProperties = pageProperties; 0260 0261 #ifndef KOXML_USE_QDOM 0262 KoXmlNode node = element.namedItemNS(KoXmlNS::presentation, "notes"); 0263 #else 0264 KoXmlNode node; //XXX!!! 0265 #endif 0266 if ( node.isElement() ) { 0267 d->pageNotes->loadOdf(node.toElement(), loadingContext); 0268 } 0269 } 0270 0271 void KPrPage::loadOdfPageExtra( const KoXmlElement &element, KoPALoadingContext & loadingContext ) 0272 { 0273 // the layout needs to be loaded after the shapes are already loaded so the initialization of the data works 0274 KPrPageLayout * layout = 0; 0275 if ( element.hasAttributeNS( KoXmlNS::presentation, "presentation-page-layout-name" ) ) { 0276 KPrPageLayouts *layouts = loadingContext.documentResourceManager()->resource(KPresenter::PageLayouts).value<KPrPageLayouts*>(); 0277 0278 Q_ASSERT( layouts ); 0279 if ( layouts ) { 0280 QString layoutName = element.attributeNS( KoXmlNS::presentation, "presentation-page-layout-name" ); 0281 QRectF pageRect( 0, 0, pageLayout().width, pageLayout().height ); 0282 layout = layouts->pageLayout( layoutName, loadingContext, pageRect ); 0283 debugStage << "page layout" << layoutName << layout; 0284 } 0285 } 0286 placeholders().init( layout, shapes() ); 0287 0288 if (element.hasAttributeNS(KoXmlNS::presentation, "use-footer-name")) { 0289 QString name = element.attributeNS (KoXmlNS::presentation, "use-footer-name"); 0290 d->usedDeclaration.insert(KPrDeclarations::Footer, name); 0291 } 0292 if (element.hasAttributeNS( KoXmlNS::presentation, "use-header-name")) { 0293 QString name = element.attributeNS (KoXmlNS::presentation, "use-header-name"); 0294 d->usedDeclaration.insert(KPrDeclarations::Header, name); 0295 } 0296 if (element.hasAttributeNS( KoXmlNS::presentation, "use-date-time-name")) { 0297 QString name = element.attributeNS (KoXmlNS::presentation, "use-date-time-name"); 0298 d->usedDeclaration.insert(KPrDeclarations::DateTime, name); 0299 } 0300 } 0301 0302 bool KPrPage::saveOdfAnimations(KoPASavingContext & paContext) const 0303 { 0304 KPrPageApplicationData *data = dynamic_cast<KPrPageApplicationData *>(applicationData()); 0305 Q_ASSERT(data); 0306 KPrPageEffect *pageEffect = data->pageEffect(); 0307 QList<KPrAnimationStep*> steps = animationSteps(); 0308 if (pageEffect || steps.size() > 1) { 0309 KoXmlWriter &writer = paContext.xmlWriter(); 0310 writer.startElement("anim:par"); 0311 writer.addAttribute("presentation:node-type", "timing-root"); 0312 0313 if (pageEffect) { 0314 writer.startElement("anim:par"); 0315 writer.addAttribute("smil:begin", "page" + QString::number(paContext.page()) + ".begin"); 0316 writer.startElement("anim:transitionFilter"); 0317 pageEffect->saveOdfSmilAttributes(writer); 0318 writer.endElement(); // anim:transitionFilter 0319 writer.endElement(); // anim:par 0320 } 0321 0322 if (steps.size() > 1) { 0323 writer.startElement("anim:seq"); 0324 writer.addAttribute("presentation:node-type", "main-sequence"); 0325 for (int i = 1; i < steps.size(); i++) { 0326 KPrAnimationStep *step = steps.at(i); 0327 step->saveOdf(paContext); 0328 } 0329 writer.endElement(); 0330 } 0331 writer.endElement(); // anim:par 0332 } 0333 return true; 0334 } 0335 0336 bool KPrPage::saveOdfPresentationNotes(KoPASavingContext &paContext) const 0337 { 0338 d->pageNotes->saveOdf(paContext); 0339 return true; 0340 } 0341 0342 KoPageApp::PageType KPrPage::pageType() const 0343 { 0344 return KoPageApp::Slide; 0345 } 0346 0347 QString KPrPage::declaration(KPrDeclarations::Type type) const 0348 { 0349 return d->declarations->declaration(type, d->usedDeclaration.value(type)); 0350 } 0351 0352 bool KPrPage::displayShape(KoShape *shape) const 0353 { 0354 bool display = true; 0355 QString presentationClass = shape->additionalAttribute("presentation:class"); 0356 if (!presentationClass.isEmpty()) { 0357 if (presentationClass == "date-time") { 0358 display = m_pageProperties & DisplayDateTime; 0359 } 0360 else if (presentationClass == "footer") { 0361 display = m_pageProperties & DisplayFooter; 0362 } 0363 else if (presentationClass == "header") { 0364 display = m_pageProperties & DisplayHeader; 0365 } 0366 else if (presentationClass == "page-number") { 0367 display = m_pageProperties & DisplayPageNumber; 0368 } 0369 } 0370 return display; 0371 } 0372 0373 KoShapeManagerPaintingStrategy * KPrPage::getPaintingStrategy() const 0374 { 0375 return new KPrShapeManagerDisplayMasterStrategy(0, new KPrPageSelectStrategyFixed(this) ); 0376 }