Warning, file /office/calligra/libs/pageapp/KoPADocument.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) 2006-2011 Thorsten Zachmann <zachmann@kde.org>
0003    Copyright (C) 2007 Thomas Zander <zander@kde.org>
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 "KoPADocument.h"
0022 
0023 #include "KoPAView.h"
0024 #include "KoPAPage.h"
0025 #include "KoPAMasterPage.h"
0026 #include "KoPASavingContext.h"
0027 #include "KoPALoadingContext.h"
0028 #include "KoPAPageProvider.h"
0029 #include "commands/KoPAPageDeleteCommand.h"
0030 
0031 #include <KoStore.h>
0032 #include <KoXmlWriter.h>
0033 #include <KoOdfReadStore.h>
0034 #include <KoOdfWriteStore.h>
0035 #include <KoOdfLoadingContext.h>
0036 #include <KoOasisSettings.h>
0037 #include <KoStoreDevice.h>
0038 #include <KoGenStyles.h>
0039 #include <KoShapeController.h>
0040 #include <KoDocumentResourceManager.h>
0041 #include <KoGridData.h>
0042 #include <KoGuidesData.h>
0043 #include <KoText.h>
0044 #include <KoTextSharedLoadingData.h>
0045 #include <KoInlineTextObjectManager.h>
0046 #include <KoStyleManager.h>
0047 #include <KoXmlNS.h>
0048 #include <KoProgressUpdater.h>
0049 #include <KoUpdater.h>
0050 #include <KoDocumentInfo.h>
0051 #include <KoVariableManager.h>
0052 #include <KoPart.h>
0053 #include <KoUnit.h>
0054 
0055 #include <PageAppDebug.h>
0056 #include <kconfig.h>
0057 #include <kconfiggroup.h>
0058 #include <KSharedConfig>
0059 
0060 #include <QPainter>
0061 
0062 class Q_DECL_HIDDEN KoPADocument::Private
0063 {
0064 public:
0065     QList<KoPAPageBase*> pages;
0066     QList<KoPAPageBase*> masterPages;
0067     KoInlineTextObjectManager *inlineTextObjectManager;
0068     bool rulersVisible;
0069     KoPAPageProvider *pageProvider;
0070     QPointer<KoUpdater> odfProgressUpdater;
0071     QPointer<KoUpdater> odfMasterPageProgressUpdater;
0072     QPointer<KoUpdater> odfPageProgressUpdater;
0073     QString defaultStylesResourcePath;
0074     bool showPageMargins;
0075 };
0076 
0077 KoPADocument::KoPADocument(KoPart *part)
0078     : KoDocument(part),
0079     d(new Private())
0080 {
0081     d->inlineTextObjectManager = resourceManager()->resource(KoText::InlineTextObjectManager).value<KoInlineTextObjectManager*>();
0082     // Do not assert, it should be possible to run wo InlineTextObjectManager
0083     // This is used by unit tests, so these will fail
0084     // Q_ASSERT(d->inlineTextObjectManager);
0085     if (d->inlineTextObjectManager) {
0086         connect(documentInfo(), SIGNAL(infoUpdated(QString,QString)),
0087                 d->inlineTextObjectManager, SLOT(documentInformationUpdated(QString,QString)));
0088     } else {
0089         warnPageApp<<"Could not find resource 'KoText::InlineTextObjectManager'";
0090     }
0091     d->rulersVisible = false;
0092     resourceManager()->setUndoStack(undoStack());
0093     resourceManager()->setOdfDocument(this);
0094     // this is needed so the text shape have a shape controller set when loaded, it is needed for copy and paste
0095     new KoShapeController(0, this);
0096     QVariant variant;
0097     d->pageProvider = new KoPAPageProvider();
0098     variant.setValue<void*>(d->pageProvider);
0099     resourceManager()->setResource(KoText::PageProvider, variant);
0100     loadConfig();
0101 }
0102 
0103 KoPADocument::~KoPADocument()
0104 {
0105     saveConfig();
0106     qDeleteAll( d->pages );
0107     qDeleteAll( d->masterPages );
0108     delete d->pageProvider;
0109     delete d;
0110 }
0111 
0112 QPixmap KoPADocument::generatePreview(const QSize& size)
0113 {
0114     // use first page as preview for all pages
0115     KoPAPageBase *page = pageByIndex(0, false);
0116     Q_ASSERT( page );
0117     return pageThumbnail(page, size);
0118 }
0119 
0120 void KoPADocument::paintContent( QPainter &painter, const QRect &rect)
0121 {
0122     KoPAPageBase * page = pageByIndex( 0, false );
0123     Q_ASSERT( page );
0124     QPixmap thumbnail( pageThumbnail( page, rect.size() ) );
0125     painter.drawPixmap( rect, thumbnail );
0126 }
0127 
0128 bool KoPADocument::loadXML( const KoXmlDocument & doc, KoStore * )
0129 {
0130     Q_UNUSED( doc );
0131 
0132     //Perhaps not necessary if we use filter import/export for old file format
0133     //only needed as it is in the base class will be removed.
0134     return true;
0135 }
0136 
0137 void KoPADocument::setupOpenFileSubProgress()
0138 {
0139     if (progressUpdater()) {
0140         d->odfProgressUpdater = progressUpdater()->startSubtask(1, "KoPADocument::loadOdf");
0141         d->odfMasterPageProgressUpdater = progressUpdater()->startSubtask(1, "KoPADocument::loadOdfMasterPages");
0142         d->odfPageProgressUpdater = progressUpdater()->startSubtask(5, "KoPADocument::loadOdfPages");
0143     }
0144 }
0145 
0146 bool KoPADocument::loadOdf( KoOdfReadStore & odfStore)
0147 {
0148     updateDocumentURL();
0149 
0150     if (d->odfProgressUpdater) {
0151         d->odfProgressUpdater->setProgress(0);
0152     }
0153     KoOdfLoadingContext loadingContext( odfStore.styles(), odfStore.store(), defaultStylesResourcePath());
0154     KoPALoadingContext paContext(loadingContext, resourceManager());
0155 
0156     KoXmlElement content = odfStore.contentDoc().documentElement();
0157     KoXmlElement realBody ( KoXml::namedItemNS( content, KoXmlNS::office, "body" ) );
0158 
0159     if ( realBody.isNull() ) {
0160         errorPageApp << "No body tag found!" << endl;
0161         return false;
0162     }
0163 
0164     KoXmlElement body = KoXml::namedItemNS(realBody, KoXmlNS::office, odfTagName( false ));
0165 
0166     if ( body.isNull() ) {
0167         errorPageApp << "No office:" << odfTagName( false ) << " tag found!" << endl;
0168         return false;
0169     }
0170 
0171     // Load text styles before the corresponding text shapes try to use them!
0172     KoTextSharedLoadingData * sharedData = new KoTextSharedLoadingData();
0173     paContext.addSharedData( KOTEXT_SHARED_LOADING_ID, sharedData );
0174     KoStyleManager *styleManager = resourceManager()->resource(KoText::StyleManager).value<KoStyleManager*>();
0175 
0176     sharedData->loadOdfStyles(paContext, styleManager);
0177     if (d->odfProgressUpdater) {
0178         d->odfProgressUpdater->setProgress(20);
0179     }
0180 
0181     d->masterPages = loadOdfMasterPages( odfStore.styles().masterPages(), paContext );
0182     if ( !loadOdfProlog( body, paContext ) ) {
0183         return false;
0184     }
0185     d->pages = loadOdfPages( body, paContext );
0186 
0187     // create pages if there are none
0188     if (d->masterPages.empty()) {
0189         d->masterPages.append(newMasterPage());
0190     }
0191     if (d->pages.empty()) {
0192         d->pages.append(newPage(static_cast<KoPAMasterPage*>(d->masterPages.first())));
0193     }
0194 
0195     if ( !loadOdfEpilogue( body, paContext ) ) {
0196         return false;
0197     }
0198 
0199     loadOdfDocumentStyles( paContext );
0200 
0201     if ( d->pages.size() > 1 ) {
0202         emit actionsPossible(KoPAView::ActionDeletePage, false);
0203     }
0204 
0205     updatePageCount();
0206 
0207     loadOdfSettings(odfStore.settingsDoc());
0208 
0209     if (d->odfProgressUpdater) {
0210         d->odfProgressUpdater->setProgress(100);
0211     }
0212     return true;
0213 }
0214 
0215 bool KoPADocument::saveOdf( SavingContext & documentContext )
0216 {
0217     KoXmlWriter* contentWriter = documentContext.odfStore.contentWriter();
0218     if ( !contentWriter )
0219         return false;
0220 
0221     KoGenStyles mainStyles;
0222     KoXmlWriter * bodyWriter = documentContext.odfStore.bodyWriter();
0223 
0224     KoPASavingContext paContext(*bodyWriter, mainStyles, documentContext.embeddedSaver, 1);
0225 
0226     saveOdfDocumentStyles( paContext );
0227 
0228     bodyWriter->startElement( "office:body" );
0229     bodyWriter->startElement( odfTagName( true ) );
0230 
0231     if ( !saveOdfProlog( paContext ) ) {
0232         return false;
0233     }
0234 
0235     if ( !saveOdfPages( paContext, d->pages, d->masterPages ) ) {
0236         return false;
0237     }
0238 
0239     if ( ! saveOdfEpilogue( paContext ) ) {
0240         return false;
0241     }
0242 
0243     bodyWriter->endElement(); // office:odfTagName()
0244     bodyWriter->endElement(); // office:body
0245 
0246     mainStyles.saveOdfStyles( KoGenStyles::DocumentAutomaticStyles, contentWriter );
0247 
0248     documentContext.odfStore.closeContentWriter();
0249 
0250     //add manifest line for content.xml
0251     documentContext.odfStore.manifestWriter()->addManifestEntry( "content.xml", "text/xml" );
0252 
0253     if ( ! mainStyles.saveOdfStylesDotXml( documentContext.odfStore.store(), documentContext.odfStore.manifestWriter() ) ) {
0254         return false;
0255     }
0256 
0257     KoStore * store = documentContext.odfStore.store();
0258     if ( ! store->open( "settings.xml" ) ) {
0259         return false;
0260     }
0261 
0262     saveOdfSettings( store );
0263 
0264     if ( ! store->close() ) {
0265         return false;
0266     }
0267 
0268     documentContext.odfStore.manifestWriter()->addManifestEntry( "settings.xml", "text/xml" );
0269 
0270     //setModified( false );
0271 
0272     bool retval = paContext.saveDataCenter( documentContext.odfStore.store(), documentContext.odfStore.manifestWriter() );
0273 
0274     if (retval) {
0275         updateDocumentURL();
0276     }
0277 
0278     return retval;
0279 }
0280 
0281 QList<KoPAPageBase *> KoPADocument::loadOdfMasterPages( const QHash<QString, KoXmlElement*> masterStyles, KoPALoadingContext & context )
0282 {
0283     context.odfLoadingContext().setUseStylesAutoStyles( true );
0284     QList<KoPAPageBase *> masterPages;
0285 
0286     if (d->odfMasterPageProgressUpdater) {
0287         d->odfMasterPageProgressUpdater->setProgress(0);
0288     }
0289 
0290     QHash<QString, KoXmlElement*>::const_iterator it( masterStyles.constBegin() );
0291     int count = 0;
0292     for ( ; it != masterStyles.constEnd(); ++it )
0293     {
0294         KoPAMasterPage * masterPage = newMasterPage();
0295         masterPage->loadOdf( *( it.value() ), context );
0296         masterPages.append( masterPage );
0297         context.addMasterPage( it.key(), masterPage );
0298         if (d->odfMasterPageProgressUpdater) {
0299             int progress = 100 * ++count / masterStyles.size();
0300             d->odfMasterPageProgressUpdater->setProgress(progress);
0301         }
0302     }
0303     context.odfLoadingContext().setUseStylesAutoStyles( false );
0304     if (d->odfMasterPageProgressUpdater) {
0305         d->odfMasterPageProgressUpdater->setProgress(100);
0306     }
0307     return masterPages;
0308 }
0309 
0310 QList<KoPAPageBase *> KoPADocument::loadOdfPages( const KoXmlElement & body, KoPALoadingContext & context )
0311 {
0312     if (d->masterPages.isEmpty()) { // we require at least one master page. Auto create one if the doc was faulty.
0313         d->masterPages << newMasterPage();
0314     }
0315 
0316     int childNodesCount = 0;
0317     int childCount = 0;
0318     if (d->odfPageProgressUpdater) {
0319         d->odfPageProgressUpdater->setProgress(0);
0320         childNodesCount = body.childNodesCount();
0321     }
0322 
0323     QList<KoPAPageBase *> pages;
0324     KoXmlElement element;
0325     forEachElement( element, body )
0326     {
0327         if ( element.tagName() == "page" && element.namespaceURI() == KoXmlNS::draw ) {
0328             KoPAPage *page = newPage(static_cast<KoPAMasterPage*>(d->masterPages.first()));
0329             page->loadOdf( element, context );
0330             pages.append( page );
0331             // in case the page name is pageX where X is the page number remove the name as this is
0332             // remove the page name and show the default page name like Slide X or Page X. 
0333             if (page->name() == QString("page%1").arg(pages.size())) {
0334                 page->setName("");
0335             }
0336         }
0337 
0338         if (d->odfPageProgressUpdater) {
0339             int progress = 100 * ++childCount / childNodesCount;
0340             d->odfPageProgressUpdater->setProgress(progress);
0341         }
0342     }
0343     if (d->odfPageProgressUpdater) {
0344         d->odfPageProgressUpdater->setProgress(100);
0345     }
0346     return pages;
0347 }
0348 
0349 bool KoPADocument::loadOdfEpilogue( const KoXmlElement & body, KoPALoadingContext & context )
0350 {
0351     Q_UNUSED( body );
0352     Q_UNUSED( context );
0353     return true;
0354 }
0355 
0356 bool KoPADocument::loadOdfProlog( const KoXmlElement & body, KoPALoadingContext & context )
0357 {
0358     Q_UNUSED( body );
0359     Q_UNUSED( context );
0360 
0361     // Load user defined variable declarations
0362     if (KoVariableManager *variableManager = inlineTextObjectManager()->variableManager()) {
0363         variableManager->loadOdf(body);
0364     }
0365 
0366     return true;
0367 }
0368 
0369 bool KoPADocument::saveOdfPages( KoPASavingContext &paContext, QList<KoPAPageBase *> &pages, QList<KoPAPageBase *> &masterPages )
0370 {
0371     paContext.addOption( KoPASavingContext::DrawId );
0372     paContext.addOption( KoPASavingContext::AutoStyleInStyleXml );
0373 
0374     // save master pages
0375     foreach( KoPAPageBase *page, masterPages ) {
0376         if ( paContext.isSetClearDrawIds() ) {
0377             paContext.clearXmlIds("shape");
0378         }
0379         page->saveOdf( paContext );
0380     }
0381 
0382     paContext.removeOption( KoPASavingContext::AutoStyleInStyleXml );
0383 
0384     // save pages
0385     foreach ( KoPAPageBase *page, pages ) {
0386         page->saveOdf( paContext );
0387         paContext.incrementPage();
0388     }
0389 
0390     return true;
0391 }
0392 
0393 bool KoPADocument::saveOdfProlog( KoPASavingContext & paContext )
0394 {
0395     Q_UNUSED( paContext );
0396 
0397     // Save user defined variable declarations
0398     if (KoVariableManager *variableManager = inlineTextObjectManager()->variableManager()) {
0399         variableManager->saveOdf(&paContext.xmlWriter());
0400     }
0401 
0402     return true;
0403 }
0404 
0405 bool KoPADocument::saveOdfEpilogue( KoPASavingContext & paContext )
0406 {
0407     Q_UNUSED( paContext );
0408     return true;
0409 }
0410 
0411 bool KoPADocument::saveOdfSettings( KoStore * store )
0412 {
0413     KoStoreDevice settingsDev( store );
0414     KoXmlWriter * settingsWriter = KoOdfWriteStore::createOasisXmlWriter( &settingsDev, "office:document-settings" );
0415 
0416     settingsWriter->startElement("office:settings");
0417     settingsWriter->startElement("config:config-item-set");
0418     settingsWriter->addAttribute("config:name", "view-settings");
0419 
0420     saveUnitOdf(settingsWriter);
0421 
0422     settingsWriter->endElement(); // config:config-item-set
0423 
0424     settingsWriter->startElement("config:config-item-set");
0425     settingsWriter->addAttribute("config:name", "ooo:view-settings");
0426     settingsWriter->startElement("config:config-item-map-indexed" );
0427     settingsWriter->addAttribute("config:name", "Views" );
0428     settingsWriter->startElement("config:config-item-map-entry" );
0429 
0430     guidesData().saveOdfSettings( *settingsWriter );
0431     gridData().saveOdfSettings( *settingsWriter );
0432 
0433     settingsWriter->endElement(); // config:config-item-map-entry
0434     settingsWriter->endElement(); // config:config-item-map-indexed
0435     settingsWriter->endElement(); // config:config-item-set
0436 
0437     settingsWriter->endElement(); // office:settings
0438     settingsWriter->endElement(); // office:document-settings
0439 
0440     settingsWriter->endDocument();
0441 
0442     delete settingsWriter;
0443 
0444     return true;
0445 }
0446 
0447 void KoPADocument::loadOdfSettings(  const KoXmlDocument & settingsDoc )
0448 {
0449     if ( settingsDoc.isNull() ) {
0450         return ; // not an error if some file doesn't have settings.xml
0451     }
0452 
0453     KoOasisSettings settings( settingsDoc );
0454     KoOasisSettings::Items viewSettings = settings.itemSet( "view-settings" );
0455     if ( !viewSettings.isNull() ) {
0456         setUnit(KoUnit::fromSymbol(viewSettings.parseConfigItemString("unit")));
0457         // FIXME: add other config here.
0458     }
0459 
0460     guidesData().loadOdfSettings( settingsDoc );
0461     gridData().loadOdfSettings( settingsDoc );
0462 }
0463 
0464 void KoPADocument::saveOdfDocumentStyles( KoPASavingContext & context )
0465 {
0466     KoStyleManager *styleManager = resourceManager()->resource(KoText::StyleManager).value<KoStyleManager*>();
0467     Q_ASSERT( styleManager );
0468     styleManager->saveOdf(context);
0469 }
0470 
0471 bool KoPADocument::loadOdfDocumentStyles( KoPALoadingContext & context )
0472 {
0473     Q_UNUSED( context );
0474     return true;
0475 }
0476 
0477 KoPAPageBase* KoPADocument::pageByIndex( int index, bool masterPage ) const
0478 {
0479     if ( masterPage )
0480     {
0481         return d->masterPages.at( index );
0482     }
0483     else
0484     {
0485         return d->pages.at( index );
0486     }
0487 }
0488 
0489 int KoPADocument::pageIndex( KoPAPageBase * page ) const
0490 {
0491     const QList<KoPAPageBase*>& pages = dynamic_cast<KoPAMasterPage *>( page ) ? d->masterPages : d->pages;
0492     return pages.indexOf( page );
0493 }
0494 
0495 KoPAPageBase* KoPADocument::pageByNavigation( KoPAPageBase * currentPage, KoPageApp::PageNavigation pageNavigation ) const
0496 {
0497     const QList<KoPAPageBase*>& pages = dynamic_cast<KoPAMasterPage *>( currentPage ) ? d->masterPages : d->pages;
0498 
0499     Q_ASSERT( ! pages.isEmpty() );
0500 
0501     KoPAPageBase * newPage = currentPage;
0502 
0503     switch ( pageNavigation )
0504     {
0505         case KoPageApp::PageFirst:
0506             newPage = pages.first();
0507             break;
0508         case KoPageApp::PageLast:
0509             newPage = pages.last();
0510             break;
0511         case KoPageApp::PagePrevious:
0512         {
0513             int index = pages.indexOf( currentPage ) - 1;
0514             if ( index >= 0 )
0515             {
0516                 newPage = pages.at( index );
0517             }
0518         }   break;
0519         case KoPageApp::PageNext:
0520             // fall through
0521         default:
0522         {
0523             int index = pages.indexOf( currentPage ) + 1;
0524             if ( index < pages.size() )
0525             {
0526                 newPage = pages.at( index );
0527             }
0528             break;
0529         }
0530     }
0531 
0532     return newPage;
0533 }
0534 
0535 void KoPADocument::addShape( KoShape * shape )
0536 {
0537     if(!shape)
0538         return;
0539 
0540     // the KoShapeController sets the active layer as parent
0541     KoPAPageBase *page(pageByShape(shape));
0542 
0543     emit shapeAdded(shape);
0544 
0545     // it can happen in Stage notes view that there is no page
0546     if ( page ) {
0547         page->shapeAdded( shape );
0548         postAddShape( page, shape );
0549     }
0550 }
0551 
0552 void KoPADocument::postAddShape( KoPAPageBase * page, KoShape * shape )
0553 {
0554     Q_UNUSED( page );
0555     Q_UNUSED( shape );
0556 }
0557 
0558 void KoPADocument::removeShape(KoShape *shape)
0559 {
0560     if (!shape)
0561         return;
0562 
0563     KoPAPageBase *page(pageByShape(shape));
0564 
0565     emit shapeRemoved(shape);
0566 
0567     page->shapeRemoved(shape);
0568     postRemoveShape(page, shape);
0569 }
0570 
0571 void KoPADocument::postRemoveShape( KoPAPageBase * page, KoShape * shape )
0572 {
0573     Q_UNUSED( page );
0574     Q_UNUSED( shape );
0575 }
0576 
0577 void KoPADocument::removePage( KoPAPageBase * page )
0578 {
0579     KoPAPageDeleteCommand * command = new KoPAPageDeleteCommand( this, page );
0580     pageRemoved( page, command );
0581     addCommand( command );
0582 }
0583 
0584 
0585 void KoPADocument::removePages(QList<KoPAPageBase *> &pages)
0586 {
0587     KoPAPageDeleteCommand *command = new KoPAPageDeleteCommand(this, pages);
0588     addCommand(command);
0589 }
0590 
0591 void KoPADocument::pageRemoved( KoPAPageBase * page, KUndo2Command * parent )
0592 {
0593     Q_UNUSED( page );
0594     Q_UNUSED( parent );
0595 }
0596 
0597 KoPAPageBase * KoPADocument::pageByShape( KoShape * shape ) const
0598 {
0599     KoShape * parent = shape;
0600     KoPAPageBase * page = 0;
0601     while ( !page && ( parent = parent->parent() ) )
0602     {
0603         page = dynamic_cast<KoPAPageBase*>( parent );
0604     }
0605     return page;
0606 }
0607 
0608 //F)XME
0609 /*
0610 void KoPADocument::updateViews(KoPAPageBase *page)
0611 {
0612     if (!page) return;
0613 
0614     foreach (KoView *view, views()) {
0615         KoPAView *paView = static_cast<KoPAView *>(view);
0616         if ( paView->activePage() == page ) {
0617             paView->viewMode()->updateActivePage( page );
0618         }
0619         else if ( dynamic_cast<KoPAMasterPage *>( page ) ) {
0620             // if the page changed is a master page, we need to check whether it is the current page's master page
0621             KoPAPage *activePage = dynamic_cast<KoPAPage *>( paView->activePage() );
0622             if ( activePage && activePage->masterPage() == page ) {
0623                 paView->viewMode()->updateActivePage( activePage );
0624             }
0625         }
0626     }
0627 }
0628 */
0629 KoPageApp::PageType KoPADocument::pageType() const
0630 {
0631     return KoPageApp::Page;
0632 }
0633 
0634 QPixmap KoPADocument::pageThumbnail(KoPAPageBase* page, const QSize& size)
0635 {
0636     int pageNumber = pageIndex(page) + 1;
0637     d->pageProvider->setPageData(pageNumber, page);
0638     return page->thumbnail(size);
0639 }
0640 
0641 QImage KoPADocument::pageThumbImage(KoPAPageBase* page, const QSize& size)
0642 {
0643     int pageNumber = pageIndex(page) + 1;
0644     d->pageProvider->setPageData(pageNumber, page);
0645     return page->thumbImage(size);
0646 }
0647 
0648 void KoPADocument::initEmpty()
0649 {
0650     d->masterPages.clear();
0651     d->pages.clear();
0652     KoPAMasterPage * masterPage = newMasterPage();
0653     d->masterPages.append( masterPage );
0654     KoPAPage * page = newPage( masterPage );
0655     d->pages.append( page );
0656     KoDocument::initEmpty();
0657 }
0658 
0659 void KoPADocument::insertPage( KoPAPageBase* page, int index )
0660 {
0661     if ( !page )
0662         return;
0663 
0664     QList<KoPAPageBase*>& pages = dynamic_cast<KoPAMasterPage *>( page ) ? d->masterPages : d->pages;
0665 
0666     if ( index > pages.size() || index < 0 )
0667     {
0668         index = pages.size();
0669     }
0670 
0671     pages.insert( index, page );
0672     updatePageCount();
0673 
0674     emit actionsPossible(KoPAView::ActionDeletePage, pages.size() > 1);
0675 
0676     emit pageAdded(page);
0677 }
0678 
0679 void KoPADocument::insertPage( KoPAPageBase* page, KoPAPageBase* after )
0680 {
0681     if ( !page )
0682         return;
0683 
0684     QList<KoPAPageBase*>& pages = dynamic_cast<KoPAMasterPage *>( page ) ? d->masterPages : d->pages;
0685 
0686     int index = 0;
0687 
0688     if ( after != 0 )
0689     {
0690         index = pages.indexOf( after ) + 1;
0691 
0692         // Append the page if after wasn't found in pages
0693         if ( index == 0 )
0694             index = pages.count();
0695     }
0696 
0697     pages.insert( index, page );
0698     updatePageCount();
0699 
0700     emit actionsPossible(KoPAView::ActionDeletePage, pages.size() > 1);
0701 
0702     emit pageAdded( page );
0703 }
0704 
0705 int KoPADocument::takePage( KoPAPageBase *page )
0706 {
0707     Q_ASSERT( page );
0708 
0709     QList<KoPAPageBase *>& pages = dynamic_cast<KoPAMasterPage *>( page ) ? d->masterPages : d->pages;
0710 
0711     int index = pages.indexOf( page );
0712 
0713     // it should not be possible to delete the last page
0714     Q_ASSERT( pages.size() > 1 );
0715 
0716     if ( index != -1 ) {
0717         pages.removeAt( index );
0718 
0719         // change to previous page when the page is the active one if the first one is delete go to the next one
0720         int newIndex = index == 0 ? 0 : index - 1;
0721         KoPAPageBase * newActivePage = pages.at( newIndex );
0722 
0723         updatePageCount();
0724 
0725         emit replaceActivePage(page, newActivePage);
0726         emit pageRemoved(page, index);
0727     }
0728 
0729     if ( pages.size() == 1 ) {
0730         emit actionsPossible(KoPAView::ActionDeletePage, false);
0731     }
0732 
0733 
0734     return index;
0735 }
0736 
0737 QList<KoPAPageBase*> KoPADocument::pages( bool masterPages ) const
0738 {
0739     return masterPages ? d->masterPages : d->pages;
0740 }
0741 
0742 KoPAPage * KoPADocument::newPage( KoPAMasterPage * masterPage )
0743 {
0744     return new KoPAPage( masterPage );
0745 }
0746 
0747 KoPAMasterPage * KoPADocument::newMasterPage()
0748 {
0749     return new KoPAMasterPage();
0750 }
0751 
0752 /// return the inlineTextObjectManager for this document.
0753 KoInlineTextObjectManager *KoPADocument::inlineTextObjectManager() const
0754 {
0755     return d->inlineTextObjectManager;
0756 }
0757 
0758 void KoPADocument::loadConfig()
0759 {
0760     KSharedConfigPtr config = KSharedConfig::openConfig();
0761 
0762     if( config->hasGroup( "Grid" ) )
0763     {
0764         KoGridData defGrid;
0765         KConfigGroup configGroup = config->group( "Grid" );
0766         bool showGrid = configGroup.readEntry<bool>( "ShowGrid", defGrid.showGrid() );
0767         gridData().setShowGrid(showGrid);
0768         bool paintGridInBackground = configGroup.readEntry("PaintGridInBackground", defGrid.paintGridInBackground());
0769         gridData().setPaintGridInBackground(paintGridInBackground);
0770         bool snapToGrid = configGroup.readEntry<bool>( "SnapToGrid", defGrid.snapToGrid() );
0771         gridData().setSnapToGrid(snapToGrid);
0772         qreal spacingX = configGroup.readEntry<qreal>( "SpacingX", defGrid.gridX() );
0773         qreal spacingY = configGroup.readEntry<qreal>( "SpacingY", defGrid.gridY() );
0774         gridData().setGrid( spacingX, spacingY );
0775         QColor color = configGroup.readEntry( "Color", defGrid.gridColor() );
0776         gridData().setGridColor( color );
0777     }
0778 
0779     d->showPageMargins = true;
0780     if( config->hasGroup( "Interface" ) )
0781     {
0782         KConfigGroup configGroup = config->group( "Interface" );
0783         bool showRulers = configGroup.readEntry<bool>( "ShowRulers", true);
0784         setRulersVisible(showRulers);
0785 
0786         bool showPageMargins = configGroup.readEntry<bool>( "ShowPageMargins", true);
0787         setShowPageMargins(showPageMargins);
0788     }
0789 }
0790 
0791 void KoPADocument::saveConfig()
0792 {
0793     KSharedConfigPtr config = KSharedConfig::openConfig();
0794     KConfigGroup configGroup = config->group( "Grid" );
0795     KoGridData defGrid;
0796 
0797     bool showGrid = gridData().showGrid();
0798     if ((showGrid == defGrid.showGrid()) && !configGroup.hasDefault("ShowGrid"))
0799         configGroup.revertToDefault("ShowGrid");
0800     else
0801         configGroup.writeEntry("ShowGrid", showGrid);
0802 
0803     bool snapToGrid = gridData().snapToGrid();
0804     if ((snapToGrid == defGrid.snapToGrid()) && !configGroup.hasDefault("SnapToGrid"))
0805         configGroup.revertToDefault("SnapToGrid");
0806     else
0807         configGroup.writeEntry("SnapToGrid", snapToGrid);
0808 
0809     qreal spacingX = gridData().gridX();
0810     if ((spacingX == defGrid.gridX()) && !configGroup.hasDefault("SpacingX"))
0811         configGroup.revertToDefault("SpacingX");
0812     else
0813         configGroup.writeEntry("SpacingX", spacingX);
0814 
0815     qreal spacingY = gridData().gridY();
0816     if ((spacingY == defGrid.gridY()) && !configGroup.hasDefault("SpacingY"))
0817         configGroup.revertToDefault("SpacingY");
0818     else
0819         configGroup.writeEntry("SpacingY", spacingY);
0820 
0821     QColor color = gridData().gridColor();
0822     if ((color == defGrid.gridColor()) && !configGroup.hasDefault("Color"))
0823         configGroup.revertToDefault("Color");
0824     else
0825         configGroup.writeEntry("Color", color);
0826 
0827     configGroup = config->group( "Interface" );
0828 
0829     bool showRulers = rulersVisible();
0830     if ((showRulers == true) && !configGroup.hasDefault("ShowRulers"))
0831         configGroup.revertToDefault("ShowRulers");
0832     else
0833         configGroup.writeEntry("ShowRulers", showRulers);
0834 
0835     bool showMargins = showPageMargins();
0836     if ((showMargins == true) && !configGroup.hasDefault("ShowPageMargins")) {
0837         configGroup.revertToDefault("ShowPageMargins");
0838     } else {
0839         configGroup.writeEntry("ShowPageMargins", showMargins);
0840     }
0841 }
0842 
0843 void KoPADocument::setRulersVisible(bool visible)
0844 {
0845     d->rulersVisible = visible;
0846 }
0847 
0848 bool KoPADocument::rulersVisible() const
0849 {
0850     return d->rulersVisible;
0851 }
0852 
0853 // TODO: the property "defaultStylesResourcePath" for each and every document
0854 // is not nice to have. Instead the info about that path (and similar data like?)
0855 // should be noted at some central component that all document objects etc. know
0856 // about and where the app which uses these classes can configure the path to
0857 // its needs
0858 void KoPADocument::setDefaultStylesResourcePath(const QString& defaultStylesResourcePath)
0859 {
0860     d->defaultStylesResourcePath = defaultStylesResourcePath;
0861 }
0862 
0863 QString KoPADocument::defaultStylesResourcePath() const
0864 {
0865     return d->defaultStylesResourcePath;
0866 }
0867 
0868 int KoPADocument::pageCount() const
0869 {
0870     return d->pages.count();
0871 }
0872 
0873 void KoPADocument::updatePageCount()
0874 {
0875     if (resourceManager()->hasResource(KoText::InlineTextObjectManager)) {
0876         QVariant var = resourceManager()->resource(KoText::InlineTextObjectManager);
0877         KoInlineTextObjectManager *om = var.value<KoInlineTextObjectManager*>();
0878         om->setProperty( KoInlineObject::PageCount, pageCount() );
0879     }
0880 }
0881 
0882 void KoPADocument::updateDocumentURL()
0883 {
0884     if (resourceManager()->hasResource(KoText::InlineTextObjectManager)) {
0885         QVariant var = resourceManager()->resource(KoText::InlineTextObjectManager);
0886         KoInlineTextObjectManager *om = var.value<KoInlineTextObjectManager*>();
0887         om->setProperty(KoInlineObject::DocumentURL, url().url(QUrl::PreferLocalFile));
0888     }
0889 }
0890 
0891 void KoPADocument::setShowPageMargins(bool state)
0892 {
0893     d->showPageMargins = state;
0894 }
0895 
0896 bool KoPADocument::showPageMargins() const
0897 {
0898     return d->showPageMargins;
0899 }