File indexing completed on 2024-05-19 16:09:32

0001 /* This file is part of the KDE project
0002    Copyright (C) 2006-2010 Thorsten Zachmann <zachmann@kde.org>
0003   Copyright (C) 2010 Benjamin Port <port.benjamin@gmail.com>
0004 
0005    This library is free software; you can redistribute it and/or
0006    modify it under the terms of the GNU Library General Public
0007    License as published by the Free Software Foundation; either
0008    version 2 of the License, or (at your option) any later version.
0009 
0010    This library is distributed in the hope that it will be useful,
0011    but WITHOUT ANY WARRANTY; without even the implied warranty of
0012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013    Library General Public License for more details.
0014 
0015    You should have received a copy of the GNU Library General Public License
0016    along with this library; see the file COPYING.LIB.  If not, write to
0017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018  * Boston, MA 02110-1301, USA.
0019 */
0020 
0021 #include "KPrDocument.h"
0022 
0023 
0024 #include "KPrView.h"
0025 #include "KPresenter.h"
0026 #include "KPrPage.h"
0027 #include "KPrMasterPage.h"
0028 #include "KPrShapeApplicationData.h"
0029 #include "KPrFactory.h"
0030 #include "KPrViewModeNotes.h"
0031 #include "KPrPlaceholderShapeFactory.h"
0032 #include "KPrSoundCollection.h"
0033 #include "KPrDeclarations.h"
0034 #include "pagelayout/KPrPageLayouts.h"
0035 #include "tools/KPrPlaceholderToolFactory.h"
0036 #include "commands/KPrDeleteSlidesCommand.h"
0037 #include <KoPASavingContext.h>
0038 #include <KoPALoadingContext.h>
0039 #include <KoShapeLoadingContext.h>
0040 #include <KoShapeRegistry.h>
0041 #include <KoToolRegistry.h>
0042 #include <KoXmlNS.h>
0043 #include <KoXmlWriter.h>
0044 
0045 #include <kconfig.h>
0046 #include <kconfiggroup.h>
0047 #include <KSharedConfig>
0048 
0049 #include <QTimer>
0050 #include <QCoreApplication>
0051 #include <QGlobalStatic>
0052 #include <QStandardPaths>
0053 
0054 class InitOnce
0055 {
0056 public:
0057     InitOnce()
0058     {
0059         KoToolRegistry * toolRegistry = KoToolRegistry::instance();
0060         toolRegistry->add( new KPrPlaceholderToolFactory() );
0061         KoShapeRegistry * registry = KoShapeRegistry::instance();
0062         registry->addFactory( new KPrPlaceholderShapeFactory() );
0063     }
0064 };
0065 
0066 Q_GLOBAL_STATIC( InitOnce, s_initOnce );
0067 
0068 KPrDocument::KPrDocument(KoPart *part)
0069 : KoPADocument(part)
0070 , m_customSlideShows(new KPrCustomSlideShows())
0071 , m_presentationMonitor( 0 )
0072 , m_presenterViewEnabled( false )
0073 , m_declarations( new KPrDeclarations() )
0074 {
0075     // TODO: revisit if this is the place where that initialization should happen
0076     InitOnce * initOnce = s_initOnce;
0077     // have this is as otherwise we get a warning from the compiler
0078     // the variable is used and the way it is done is to only call it once
0079     Q_UNUSED( initOnce );
0080 
0081     KoShapeLoadingContext::addAdditionalAttributeData( KoShapeLoadingContext::AdditionalAttributeData(
0082                                                        KoXmlNS::presentation, "placeholder",
0083                                                        "presentation:placeholder" ) );
0084 
0085     KoShapeLoadingContext::addAdditionalAttributeData( KoShapeLoadingContext::AdditionalAttributeData(
0086                                                        KoXmlNS::presentation, "class",
0087                                                        "presentation:class" ) );
0088 
0089     QVariant variant;
0090     variant.setValue(new KPrSoundCollection(this));
0091     resourceManager()->setResource(KPresenter::SoundCollection, variant);
0092 
0093     variant.setValue(new KPrPageLayouts(this));
0094     resourceManager()->setResource(KPresenter::PageLayouts, variant);
0095 
0096     loadKPrConfig();
0097 }
0098 
0099 KPrDocument::~KPrDocument()
0100 {
0101     saveKPrConfig();
0102     delete m_customSlideShows;
0103     delete m_declarations;
0104 }
0105 
0106 const char * KPrDocument::odfTagName( bool withNamespace )
0107 {
0108     return withNamespace ? "office:presentation": "presentation";
0109 }
0110 
0111 bool KPrDocument::saveOdfProlog( KoPASavingContext & context )
0112 {
0113     if ( !KoPADocument::saveOdfProlog( context ) )
0114         return false;
0115     m_declarations->saveOdf( context );
0116     return true;
0117 }
0118 
0119 bool KPrDocument::saveOdfEpilogue( KoPASavingContext & context )
0120 {
0121     context.xmlWriter().startElement( "presentation:settings" );
0122     if ( !m_activeCustomSlideShow.isEmpty() && m_customSlideShows->names().contains(  m_activeCustomSlideShow ) ) {
0123         context.xmlWriter().addAttribute( "presentation:show", m_activeCustomSlideShow );
0124     }
0125     m_customSlideShows->saveOdf( context );
0126     context.xmlWriter().endElement();//presentation:settings
0127     return true;
0128 }
0129 
0130 void KPrDocument::saveOdfDocumentStyles( KoPASavingContext & context )
0131 {
0132     KoPADocument::saveOdfDocumentStyles( context );
0133     KPrPageLayouts *layouts = resourceManager()->resource(KPresenter::PageLayouts).value<KPrPageLayouts*>();
0134 
0135     Q_ASSERT( layouts );
0136     if ( layouts ) {
0137         layouts->saveOdf( context );
0138     }
0139 }
0140 
0141 bool KPrDocument::loadOdfEpilogue( const KoXmlElement & body, KoPALoadingContext & context )
0142 {
0143     const KoXmlElement & presentationSettings( KoXml::namedItemNS( body, KoXmlNS::presentation, "settings" ) );
0144     if ( !presentationSettings.isNull() ) {
0145         m_customSlideShows->loadOdf( presentationSettings, context );
0146     }
0147 
0148     m_activeCustomSlideShow = QString( "" );
0149     if ( presentationSettings.hasAttributeNS( KoXmlNS::presentation, "show" ) ) {
0150         QString show = presentationSettings.attributeNS( KoXmlNS::presentation, "show" );
0151         if ( m_customSlideShows->names().contains( show ) ) {
0152             m_activeCustomSlideShow = show;
0153         }
0154     }
0155 
0156     return true;
0157 }
0158 
0159 bool KPrDocument::loadOdfDocumentStyles( KoPALoadingContext & context )
0160 {
0161     KPrPageLayouts *layouts = resourceManager()->resource(KPresenter::PageLayouts).value<KPrPageLayouts*>();
0162     if ( layouts ) {
0163         layouts->loadOdf( context );
0164     }
0165     return true;
0166 }
0167 
0168 KoPAPage * KPrDocument::newPage( KoPAMasterPage * masterPage )
0169 {
0170     Q_ASSERT(masterPage);
0171     return new KPrPage( masterPage, this );
0172 }
0173 
0174 KoPAMasterPage * KPrDocument::newMasterPage()
0175 {
0176     return new KPrMasterPage(this);
0177 }
0178 
0179 KoOdf::DocumentType KPrDocument::documentType() const
0180 {
0181     return KoOdf::Presentation;
0182 }
0183 
0184 void KPrDocument::addAnimation( KPrShapeAnimation * animation )
0185 {
0186     KoShape * shape = animation->shape();
0187 
0188     KPrShapeAnimations & animations( animationsByPage( pageByShape( shape ) ) );
0189 
0190     // add animation to the list of animations
0191     animations.add( animation );
0192 
0193     // add animation to the shape animation data so that it can be regenerated on delete shape and undo
0194     KPrShapeApplicationData * applicationData = dynamic_cast<KPrShapeApplicationData*>( shape->applicationData() );
0195     if ( applicationData == 0 ) {
0196         applicationData = new KPrShapeApplicationData();
0197         shape->setApplicationData( applicationData );
0198     }
0199     applicationData->animations().insert( animation );
0200     applicationData->setDeleteAnimations(false);
0201 }
0202 
0203 void KPrDocument::removeAnimation( KPrShapeAnimation * animation, bool removeFromApplicationData )
0204 {
0205     KoShape * shape = animation->shape();
0206 
0207     KPrShapeAnimations & animations( animationsByPage( pageByShape( shape ) ) );
0208 
0209     // remove animation from the list of animations
0210     animations.remove( animation );
0211 
0212     KPrShapeApplicationData *applicationData = dynamic_cast<KPrShapeApplicationData*>(shape->applicationData());
0213     Q_ASSERT(applicationData);
0214     if (removeFromApplicationData) {
0215         // remove animation from the shape animation data
0216         applicationData->animations().remove(animation);
0217     } else {
0218         applicationData->setDeleteAnimations(true);
0219     }
0220 }
0221 
0222 void KPrDocument::replaceAnimation(KPrShapeAnimation *oldAnimation, KPrShapeAnimation *newAnimation)
0223 {
0224     KoShape *shape = oldAnimation->shape();
0225     KPrShapeAnimations &animations(animationsByPage(pageByShape(shape)));
0226 
0227     // remove animation from the list of animations
0228     animations.replaceAnimation(oldAnimation, newAnimation);
0229 }
0230 
0231 void KPrDocument::postAddShape( KoPAPageBase * page, KoShape * shape )
0232 {
0233     Q_UNUSED( page );
0234     KPrShapeApplicationData * applicationData = dynamic_cast<KPrShapeApplicationData*>( shape->applicationData() );
0235     if ( applicationData ) {
0236         // reinsert animations. this is needed on undo of a delete shape that had a animations
0237         QSet<KPrShapeAnimation *> animations = applicationData->animations();
0238         for ( QSet<KPrShapeAnimation *>::const_iterator it( animations.begin() ); it != animations.end(); ++it ) {
0239             addAnimation( *it );
0240         }
0241     }
0242 }
0243 
0244 void KPrDocument::postRemoveShape( KoPAPageBase * page, KoShape * shape )
0245 {
0246     Q_UNUSED( page );
0247     KPrShapeApplicationData * applicationData = dynamic_cast<KPrShapeApplicationData*>( shape->applicationData() );
0248     if ( applicationData ) {
0249         QSet<KPrShapeAnimation *> animations = applicationData->animations();
0250         for ( QSet<KPrShapeAnimation *>::const_iterator it( animations.begin() ); it != animations.end(); ++it ) {
0251             // remove animations, don't remove from shape application data so that it can be reinserted on undo.
0252             removeAnimation( *it, false );
0253         }
0254     }
0255 }
0256 
0257 void KPrDocument::removePages(QList<KoPAPageBase *> &pages)
0258 {
0259     KPrDeleteSlidesCommand *command = new KPrDeleteSlidesCommand(this, pages);
0260     addCommand(command);
0261 }
0262 
0263 void KPrDocument::loadKPrConfig()
0264 {
0265     KSharedConfigPtr config = KSharedConfig::openConfig();
0266 
0267     if ( config->hasGroup( "SlideShow" ) ) {
0268         KConfigGroup configGroup = config->group( "SlideShow" );
0269         m_presentationMonitor = configGroup.readEntry<int>( "PresentationMonitor", 0 );
0270         m_presenterViewEnabled = configGroup.readEntry<bool>( "PresenterViewEnabled", false );
0271     }
0272 }
0273 
0274 void KPrDocument::saveKPrConfig()
0275 {
0276     KSharedConfigPtr config = KSharedConfig::openConfig();
0277     KConfigGroup configGroup = config->group( "SlideShow" );
0278 
0279     configGroup.writeEntry( "PresentationMonitor", m_presentationMonitor );
0280     configGroup.writeEntry( "PresenterViewEnabled", m_presenterViewEnabled );
0281 }
0282 
0283 KoPageApp::PageType KPrDocument::pageType() const
0284 {
0285     return KoPageApp::Slide;
0286 }
0287 
0288 void KPrDocument::initEmpty()
0289 {
0290     QString fileName(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("calligrastage/templates/Screen/.source/emptyLandscape.otp")));
0291     setModified( true );
0292     bool ok = loadNativeFormat( fileName );
0293     if ( !ok ) {
0294         // use initEmpty from  kopageapp
0295         showLoadingErrorDialog();
0296         KoPADocument::initEmpty();
0297     }
0298     resetURL();
0299 }
0300 
0301 KPrShapeAnimations & KPrDocument::animationsByPage( KoPAPageBase * page )
0302 {
0303     KPrPageData * pageData = dynamic_cast<KPrPageData *>( page );
0304     Q_ASSERT( pageData );
0305     return pageData->animations();
0306 }
0307 
0308 KPrCustomSlideShows* KPrDocument::customSlideShows()
0309 {
0310     return m_customSlideShows;
0311 }
0312 
0313 void KPrDocument::setCustomSlideShows( KPrCustomSlideShows* replacement )
0314 {
0315     m_customSlideShows = replacement;
0316     emit customSlideShowsModified();
0317 }
0318 
0319 int KPrDocument::presentationMonitor()
0320 {
0321     return m_presentationMonitor;
0322 }
0323 
0324 void KPrDocument::setPresentationMonitor( int monitor )
0325 {
0326     m_presentationMonitor = monitor;
0327 }
0328 
0329 bool KPrDocument::isPresenterViewEnabled()
0330 {
0331     return m_presenterViewEnabled;
0332 }
0333 
0334 void KPrDocument::setPresenterViewEnabled( bool enabled )
0335 {
0336     m_presenterViewEnabled = enabled;
0337 }
0338 
0339 QList<KoPAPageBase*> KPrDocument::slideShow() const
0340 {
0341     if ( !m_activeCustomSlideShow.isEmpty() &&
0342             m_customSlideShows->names().contains( m_activeCustomSlideShow ) ) {
0343         return m_customSlideShows->getByName( m_activeCustomSlideShow );
0344     }
0345 
0346     return pages();
0347 }
0348 
0349 QString KPrDocument::activeCustomSlideShow() const
0350 {
0351     return m_activeCustomSlideShow;
0352 }
0353 
0354 void KPrDocument::setActiveCustomSlideShow( const QString &customSlideShow )
0355 {
0356     if ( customSlideShow != m_activeCustomSlideShow ) {
0357         m_activeCustomSlideShow = customSlideShow;
0358         emit activeCustomSlideShowChanged( customSlideShow );
0359     }
0360 }
0361 
0362 bool KPrDocument::loadOdfProlog( const KoXmlElement & body, KoPALoadingContext & context )
0363 {
0364     if ( !KoPADocument::loadOdfProlog( body, context ) )
0365         return false;
0366     return m_declarations->loadOdf( body, context );
0367 }
0368 
0369 KPrDeclarations * KPrDocument::declarations() const
0370 {
0371     return m_declarations;
0372 }