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 }