File indexing completed on 2024-05-12 16:37:10

0001 /* This file is part of the KDE project
0002  * Copyright (C) 2002-2006 David Faure <faure@kde.org>
0003  * Copyright (C) 2005-2010 Thomas Zander <zander@kde.org>
0004  * Copyright (C) 2007 Thorsten Zachmann <zachmann@kde.org>
0005  * Copyright (C) 2008 Pierre Ducroquet <pinaraf@pinaraf.info>
0006  * Copyright (C) 2008 Sebastian Sauer <mail@dipe.org>
0007  * Copyright (C) 2010 Boudewijn Rempt <boud@kogmbh.com>
0008  * Copyright (C) 2010 C. Boemann <cbo@kogmbh.com>
0009  *
0010  * This library is free software; you can redistribute it and/or
0011  * modify it under the terms of the GNU Library General Public
0012  * License as published by the Free Software Foundation; either
0013  * version 2 of the License, or (at your option) any later version.
0014  *
0015  * This library is distributed in the hope that it will be useful,
0016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0018  * Library General Public License for more details.
0019  *
0020  * You should have received a copy of the GNU Library General Public License
0021  * along with this library; see the file COPYING.LIB.  If not, write to
0022  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0023  * Boston, MA 02110-1301, USA.
0024  */
0025 
0026 #include "KWDocument.h"
0027 
0028 #include "KWFactory.h"
0029 #include "KWView.h"
0030 #include "KWCanvas.h"
0031 #include "KWCanvasItem.h"
0032 #include "KWPageManager.h"
0033 #include "KWPage.h"
0034 #include "KWPageStyle.h"
0035 #include "KWOdfLoader.h"
0036 #include "KWOdfWriter.h"
0037 #include "frames/KWFrameSet.h"
0038 #include "frames/KWTextFrameSet.h"
0039 #include "frames/KWFrame.h"
0040 #include "frames/KWFrameLayout.h"
0041 #include "dialogs/KWFrameDialog.h"
0042 #include "KWRootAreaProvider.h"
0043 #include "WordsDebug.h"
0044 
0045 // calligra libs includes
0046 #include <changetracker/KoChangeTracker.h>
0047 #include <KoShapeManager.h>
0048 #include <KoTextDocument.h>
0049 #include <KoAnnotation.h>
0050 #include <KoGridData.h>
0051 #include <KoShapeAnchor.h>
0052 #include <KoShapeContainer.h>
0053 #include <KoToolManager.h>
0054 #include <KoShapeController.h>
0055 #include <KoShapeRegistry.h>
0056 #include <KoShapeFactoryBase.h>
0057 #include <KoStyleManager.h>
0058 #include <KoDocumentResourceManager.h>
0059 #include <KoCanvasResourceManager.h>
0060 #include <KoTextRangeManager.h>
0061 #include <KoInlineTextObjectManager.h>
0062 #include <KoDocumentInfo.h>
0063 #include <KoCharacterStyle.h>
0064 #include <KoParagraphStyle.h>
0065 #include <KoListStyle.h>
0066 #include <KoListLevelProperties.h>
0067 #include <KoSelection.h>
0068 #include <KoTextDocumentLayout.h>
0069 #include <KoTextLayoutRootArea.h>
0070 #include <KoTextEditor.h>
0071 #include <KoPart.h>
0072 #include <KoDocumentInfoDlg.h>
0073 #include <KoDocumentRdfBase.h>
0074 #include <KoAnnotationLayoutManager.h>
0075 #include <KoPageWidgetItem.h>
0076 #include <KoUnit.h>
0077 
0078 #ifdef SHOULD_BUILD_RDF
0079 #include <KoDocumentRdf.h>
0080 #include <KoDocumentRdfEditWidget.h>
0081 #endif
0082 
0083 #include <KoProgressUpdater.h>
0084 #include <KoUpdater.h>
0085 
0086 // KF5
0087 #include <klocalizedstring.h>
0088 #include <kconfiggroup.h>
0089 #include <KSharedConfig>
0090 
0091 // Qt
0092 #include <QIODevice>
0093 #include <QTimer>
0094 #include <QThread>
0095 #include <QCoreApplication>
0096 #include <QTextBlock>
0097 #include <QTime>
0098 
0099 KWDocument::KWDocument(KoPart *part)
0100         : KoDocument(part)
0101         , m_isMasterDocument(false)
0102         , m_frameLayout(&m_pageManager, m_frameSets)
0103         , m_mainFramesetEverFinished(false)
0104         , m_annotationManager(0)
0105 {
0106     Q_ASSERT(part);
0107     m_frameLayout.setDocument(this);
0108     resourceManager()->setOdfDocument(this);
0109 
0110     connect(&m_frameLayout, SIGNAL(newFrameSet(KWFrameSet*)), this, SLOT(addFrameSet(KWFrameSet*)));
0111     connect(&m_frameLayout, SIGNAL(removedFrameSet(KWFrameSet*)), this, SLOT(removeFrameSet(KWFrameSet*)));
0112 
0113     // Init shape Factories with our frame based configuration panels.
0114     m_panelFactories = KWFrameDialog::panels(this);
0115     foreach (const QString &id, KoShapeRegistry::instance()->keys()) {
0116         KoShapeFactoryBase *shapeFactory = KoShapeRegistry::instance()->value(id);
0117         if (shapeFactory) {
0118             shapeFactory->setOptionPanels(m_panelFactories);
0119         }
0120     }
0121 
0122     resourceManager()->setUndoStack(undoStack());
0123     if (documentRdf()) {
0124         documentRdf()->linkToResourceManager(resourceManager());
0125     }
0126 
0127 #ifdef SHOULD_BUILD_RDF
0128     {
0129         KoDocumentRdf *rdf = new KoDocumentRdf(this);
0130         setDocumentRdf(rdf);
0131     }
0132 
0133 #endif
0134 
0135 
0136 
0137 /* TODO reenable after release
0138     QVariant variant;
0139     variant.setValue(new KoChangeTracker(resourceManager()));
0140     resourceManager()->setResource(KoText::ChangeTracker, variant);
0141 */
0142     m_shapeController = new KoShapeController(0, this);
0143 
0144     if (inlineTextObjectManager()) {
0145         connect(documentInfo(), SIGNAL(infoUpdated(QString,QString)),
0146                 inlineTextObjectManager(), SLOT(documentInformationUpdated(QString,QString)));
0147     }
0148 
0149     m_annotationManager = new KoAnnotationLayoutManager(this);
0150 
0151     clear();
0152 }
0153 
0154 KWDocument::~KWDocument()
0155 {
0156     qDeleteAll(m_panelFactories);
0157     m_config.setUnit(unit());
0158     saveConfig();
0159     qDeleteAll(m_frameSets);
0160 }
0161 
0162 bool KWDocument::isMasterDocument() const
0163 {
0164     return m_isMasterDocument;
0165 }
0166 
0167 void KWDocument::setIsMasterDocument(bool isMasterDocument)
0168 {
0169     m_isMasterDocument = isMasterDocument;
0170 }
0171 
0172 
0173 
0174 // Words adds a couple of dialogs (like KWFrameDialog) which will not call addShape(), but
0175 // will call addFrameSet.  Which will itself call addSequencedShape()
0176 // any call coming in here is due to the undo/redo framework, pasting or for nested frames
0177 void KWDocument::addShape(KoShape *shape)
0178 {
0179     KWFrame *frame = dynamic_cast<KWFrame*>(shape->applicationData());
0180     debugWords << "shape=" << shape << "frame=" << frame;
0181     if (frame == 0) {
0182         if (shape->shapeId() == TextShape_SHAPEID) {
0183             KWTextFrameSet *tfs = new KWTextFrameSet(this);
0184             tfs->setName("Text");
0185             frame = new KWFrame(shape, tfs);
0186         } else {
0187             KWFrameSet *fs = new KWFrameSet();
0188             fs->setName(shape->shapeId());
0189             frame = new KWFrame(shape, fs);
0190         }
0191     }
0192     Q_ASSERT(KWFrameSet::from(shape));
0193     if (!m_frameSets.contains(KWFrameSet::from(shape))) {
0194         addFrameSet(KWFrameSet::from(shape));
0195     }
0196 
0197     if (!(shape->shapeId() == "AnnotationTextShapeID")) {
0198         emit shapeAdded(shape, KoShapeManager::PaintShapeOnAdd);
0199     }
0200 
0201     shape->update();
0202 }
0203 
0204 void KWDocument::removeShape(KoShape *shape)
0205 {
0206     debugWords << "shape=" << shape;
0207     KWFrameSet *fs = KWFrameSet::from(shape);
0208     if (fs) { // not all shapes have to have to be in a frameset
0209         if (fs->shapeCount() == 1) // last shape on FrameSet
0210             removeFrameSet(fs); // shape and frameset will be deleted when the shape is deleted
0211         else
0212             fs->removeShape(shape);
0213     } else { // not in a frameset, but we still have to remove it from views.
0214         emit shapeRemoved(shape);
0215     }
0216     if (shape->shapeId() == "AnnotationTextShapeID") {
0217         annotationLayoutManager()->removeAnnotationShape(shape);
0218     }
0219 }
0220 
0221 void KWDocument::shapesRemoved(const QList<KoShape*> &shapes, KUndo2Command *command)
0222 {
0223     QMap<KoTextEditor *, QList<KoShapeAnchor *> > anchors;
0224     QMap<KoTextEditor *, QList<KoAnnotation *> > annotations;
0225     const KoAnnotationManager *annotationManager = textRangeManager()->annotationManager();
0226     foreach (KoShape *shape, shapes) {
0227         KoShapeAnchor *anchor = shape->anchor();
0228         if (anchor && anchor->textLocation()) {
0229             const QTextDocument *document = anchor->textLocation()->document();
0230             if (document) {
0231                 KoTextEditor *editor = KoTextDocument(document).textEditor();
0232                 anchors[editor].append(anchor);
0233             }
0234             break;
0235         }
0236         foreach (const QString &name, annotationManager->annotationNameList()) {
0237             KoAnnotation *annotation = annotationManager->annotation(name);
0238             if (annotation->annotationShape() == shape) {
0239                 // Remove From annotation layout manager.
0240                 KoTextEditor *editor = KoTextDocument(annotation->document()).textEditor();
0241                 annotations[editor].append(annotation);
0242                 break;
0243             }
0244         }
0245     }
0246 
0247     QMap<KoTextEditor *, QList<KoShapeAnchor *> >::const_iterator anchorIter(anchors.constBegin());
0248     for (; anchorIter != anchors.constEnd(); ++anchorIter) {
0249         anchorIter.key()->removeAnchors(anchorIter.value(), command);
0250     }
0251 
0252     QMap<KoTextEditor *, QList<KoAnnotation *> >::const_iterator annotationIter(annotations.constBegin());
0253     for (; annotationIter != annotations.constEnd(); ++annotationIter) {
0254         annotationIter.key()->removeAnnotations(annotationIter.value(), command);
0255     }
0256 }
0257 
0258 QPixmap KWDocument::generatePreview(const QSize &size)
0259 {
0260     // use first page as preview for all pages
0261     KWPage firstPage = pageManager()->begin();
0262     if (! firstPage.isValid()) {
0263         // TODO: what to return for no page?
0264         return QPixmap();
0265     }
0266 
0267     // use shape manager from canvasItem even for QWidget environments
0268     // if using the shape manager from one of the views there is no guarantee
0269     // that the view, its canvas and the shapemanager is not destroyed in between
0270     KoShapeManager* shapeManager = static_cast<KWCanvasItem*>(documentPart()->canvasItem(this))->shapeManager();
0271 
0272     return QPixmap::fromImage(firstPage.thumbnail(size, shapeManager, true));
0273 }
0274 
0275 void KWDocument::paintContent(QPainter &, const QRect &)
0276 {
0277 }
0278 
0279 KWPage KWDocument::insertPage(int afterPageNum, const QString &masterPageName)
0280 {
0281     debugWords << "afterPageNum=" << afterPageNum << "masterPageName=" << masterPageName;
0282 
0283     //KWPage prevPage = m_document->pageManager().page(m_afterPageNum);
0284     KWPageStyle pageStyle = pageManager()->pageStyle(masterPageName);
0285     KWPage page = pageManager()->insertPage(afterPageNum + 1, pageStyle);
0286     Q_ASSERT(page.isValid());
0287     Q_ASSERT(page.pageNumber() >= 1 && page.pageNumber() <= pageManager()->pageCount());
0288 
0289     // Set the y-offset of the new page.
0290     KWPage prevPage = page.previous();
0291     if (prevPage.isValid()) {
0292         KoInsets padding = pageManager()->padding();    //TODO Shouldn't this be style dependent ?
0293         page.setOffsetInDocument(prevPage.offsetInDocument() + prevPage.height() + padding.top + padding.bottom);
0294     } else {
0295         page.setOffsetInDocument(0.0);
0296     }
0297 
0298     debugWords << "pageNumber=" << page.pageNumber();
0299 
0300     // Create the KWTextFrame's for the new KWPage
0301     KWFrameLayout *framelayout = frameLayout();
0302     framelayout->createNewFramesForPage(page.pageNumber());
0303 
0304     // make sure we have updated the view before we do anything else
0305     firePageSetupChanged();
0306 
0307     return page;
0308 }
0309 
0310 KWPage KWDocument::appendPage(const QString &masterPageName)
0311 {
0312     int number = 0;
0313     KWPage last = m_pageManager.last();
0314     if (last.isValid())
0315         number = last.pageNumber();
0316     return insertPage(number, masterPageName);
0317 }
0318 
0319 void KWDocument::firePageSetupChanged()
0320 {
0321     debugWords;
0322     if (inlineTextObjectManager())
0323         inlineTextObjectManager()->setProperty(KoInlineObject::PageCount, pageCount());
0324     emit pageSetupChanged();
0325 }
0326 
0327 void KWDocument::removeFrameSet(KWFrameSet *fs)
0328 {
0329     debugWords << "frameSet=" << fs;
0330     m_frameSets.removeAt(m_frameSets.indexOf(fs));
0331     setModified(true);
0332     foreach (KoShape *shape, fs->shapes())
0333         removeSequencedShape(shape);
0334 
0335     disconnect(fs, SIGNAL(shapeAdded(KoShape*)), this, SLOT(addSequencedShape(KoShape*)));
0336     disconnect(fs, SIGNAL(shapeRemoved(KoShape*)), this, SLOT(removeSequencedShape(KoShape*)));
0337 }
0338 
0339 void KWDocument::relayout(QList<KWFrameSet*> framesets)
0340 {
0341     if (framesets.isEmpty())
0342         framesets = m_frameSets;
0343 
0344     debugWords << "frameSets=" << framesets;
0345 
0346 
0347     // we switch to the interaction tool to avoid crashes if the tool was editing a frame.
0348     //KoToolManager::instance()->switchToolRequested(KoInteractionTool_ID);
0349 
0350     // remove header/footer frames that are not visible.
0351     //m_frameLayout.cleanupHeadersFooters();
0352 
0353     // create new frames and lay them out on the pages
0354     foreach (const KWPage &page, m_pageManager.pages()) {
0355         m_frameLayout.createNewFramesForPage(page.pageNumber());
0356     }
0357 
0358     // re-layout the content displayed within the pages
0359     foreach (KWFrameSet *fs, framesets) {
0360         KWTextFrameSet *tfs = dynamic_cast<KWTextFrameSet*>(fs);
0361         if (!tfs)
0362             continue;
0363         KoTextDocumentLayout *lay = dynamic_cast<KoTextDocumentLayout*>(tfs->document()->documentLayout());
0364         Q_ASSERT(lay);
0365 
0366         if (tfs->textFrameSetType() == Words::MainTextFrameSet && m_layoutProgressUpdater) {
0367             connect(lay, SIGNAL(layoutProgressChanged(int)), this, SLOT(layoutProgressChanged(int)));
0368             connect(lay, SIGNAL(finishedLayout()), this, SLOT(layoutFinished()));
0369         }
0370 
0371         // schedule all calls so multiple layout calls are compressed
0372         lay->scheduleLayout();
0373     }
0374 
0375     firePageSetupChanged();
0376 }
0377 
0378 void KWDocument::layoutProgressChanged(int percent)
0379 {
0380     Q_ASSERT(m_layoutProgressUpdater);
0381     m_layoutProgressUpdater->setProgress(percent);
0382 }
0383 
0384 void KWDocument::layoutFinished()
0385 {
0386     Q_ASSERT(m_layoutProgressUpdater);
0387     disconnect(QObject::sender(), SIGNAL(layoutProgressChanged(int)), this, SLOT(layoutProgressChanged(int)));
0388     disconnect(QObject::sender(), SIGNAL(finishedLayout()), this, SLOT(layoutFinished()));
0389     m_layoutProgressUpdater->setProgress(100);
0390     m_layoutProgressUpdater = 0; // free the instance
0391 }
0392 
0393 void KWDocument::addFrameSet(KWFrameSet *fs)
0394 {
0395     debugWords << "frameSet=" << fs;
0396 
0397     Q_ASSERT(!m_frameSets.contains(fs));
0398     setModified(true);
0399 
0400     // Be sure we add headers and footers to the beginning of the m_frameSets QList and every other KWFrameTextType
0401     // after them so future operations iterating over that QList always handle headers and footers first.
0402     int insertAt = m_frameSets.count();
0403     KWTextFrameSet *tfs = dynamic_cast<KWTextFrameSet*>(fs);
0404     if (tfs && Words::isHeaderFooter(tfs)) {
0405         insertAt = 0;
0406         for(int i = 0; i < m_frameSets.count(); ++i) {
0407             KWTextFrameSet *_tfs = dynamic_cast<KWTextFrameSet*>(m_frameSets[i]);
0408             if (_tfs && !Words::isHeaderFooter(_tfs)) {
0409                 insertAt = i;
0410                 break;
0411             }
0412         }
0413     }
0414     m_frameSets.insert(insertAt, fs);
0415 
0416     foreach (KoShape *shape, fs->shapes())
0417         addSequencedShape(shape);
0418 
0419     if (KWTextFrameSet *tfs = dynamic_cast<KWTextFrameSet*>(fs)) {
0420         Q_ASSERT(tfs->pageManager() == pageManager());
0421         if (tfs->textFrameSetType() == Words::MainTextFrameSet) {
0422             KoTextDocumentLayout *lay = dynamic_cast<KoTextDocumentLayout*>(tfs->document()->documentLayout());
0423             Q_ASSERT(lay);
0424             connect(lay, SIGNAL(finishedLayout()), this, SLOT(mainTextFrameSetLayoutDone()));
0425         }
0426     }
0427 
0428     connect(fs, SIGNAL(shapeAdded(KoShape*)), this, SLOT(addSequencedShape(KoShape*)));
0429     connect(fs, SIGNAL(shapeRemoved(KoShape*)), this, SLOT(removeSequencedShape(KoShape*)));
0430 }
0431 
0432 void KWDocument::addSequencedShape(KoShape *shape)
0433 {
0434     debugWords << "shape=" << shape << "frameSet=" << KWFrameSet::from(shape);
0435     //firePageSetupChanged();
0436     emit shapeAdded(shape, KoShapeManager::AddWithoutRepaint);
0437 }
0438 
0439 void KWDocument::removeSequencedShape(KoShape *shape)
0440 {
0441     debugWords << "shape=" << shape << "frameSet=" << KWFrameSet::from(shape);
0442 
0443     emit shapeRemoved(shape);
0444     KWPage page = pageManager()->page(shape);
0445     if (!page.isValid()) return;
0446     if (!page.isAutoGenerated()) return;
0447     if (page != pageManager()->last() || page == pageManager()->begin())
0448         return; // can only delete last page.
0449     foreach (KWFrameSet *fs, m_frameSets) {
0450         foreach (KoShape *s, fs->shapes()) {
0451             if (page == pageManager()->page(s))
0452                 return;
0453         }
0454     }
0455     //KWPageRemoveCommand *cmd = new KWPageRemoveCommand(this, page);
0456     //cmd->redo();
0457     //delete cmd;
0458 }
0459 
0460 void KWDocument::mainTextFrameSetLayoutDone()
0461 {
0462     m_mainFramesetEverFinished = true;
0463 }
0464 
0465 KWFrameSet *KWDocument::frameSetByName(const QString &name)
0466 {
0467     foreach (KWFrameSet *fs, m_frameSets) {
0468         if (fs->name() == name)
0469             return fs;
0470     }
0471     return 0;
0472 }
0473 
0474 KWTextFrameSet *KWDocument::mainFrameSet() const
0475 {
0476     return m_frameLayout.mainFrameSet();
0477 }
0478 
0479 KoInlineTextObjectManager *KWDocument::inlineTextObjectManager() const
0480 {
0481     QVariant var = resourceManager()->resource(KoText::InlineTextObjectManager);
0482     return var.value<KoInlineTextObjectManager*>();
0483 }
0484 
0485 KoTextRangeManager *KWDocument::textRangeManager() const
0486 {
0487     QVariant var = resourceManager()->resource(KoText::TextRangeManager);
0488     return var.value<KoTextRangeManager*>();
0489 }
0490 
0491 QString KWDocument::uniqueFrameSetName(const QString &suggestion)
0492 {
0493     // make up a new name for the frameset, use "[base] [digits]" as template.
0494     // Fully translatable naturally :)
0495     return renameFrameSet("", suggestion);
0496 }
0497 
0498 QString KWDocument::suggestFrameSetNameForCopy(const QString &base)
0499 {
0500     // make up a new name for the frameset, use Copy[digits]-[base] as template.
0501     // Fully translatable naturally :)
0502     return renameFrameSet(i18n("Copy"), base);
0503 }
0504 
0505 QString KWDocument::renameFrameSet(const QString &prefix, const QString &base)
0506 {
0507     if (! frameSetByName(base))
0508         return base;
0509     QString before, after;
0510     QRegExp findDigits("\\d+");
0511     int pos = findDigits.indexIn(base);
0512     if (pos >= 0) {
0513         before = base.left(pos);
0514         after = base.mid(pos + findDigits.matchedLength());
0515     } else if (prefix.isEmpty())
0516         before = base + ' ';
0517     else {
0518         before = prefix;
0519         after = ' ' + base;
0520     }
0521 
0522     if (! before.startsWith(prefix)) {
0523         before = prefix + before;
0524     }
0525 
0526     int count = 0;
0527     while (true) {
0528         QString name = QString(before + (count == 0 ? QString() : QString::number(count)) + after).trimmed();
0529         if (! frameSetByName(name))
0530             return name;
0531         count++;
0532     }
0533 }
0534 
0535 // *** LOADING
0536 
0537 void KWDocument::initEmpty()
0538 {
0539     clear();
0540 
0541     appendPage("Standard");
0542 
0543     Q_ASSERT(resourceManager()->hasResource(KoText::StyleManager));
0544     KoStyleManager *styleManager = resourceManager()->resource(KoText::StyleManager).value<KoStyleManager*>();
0545     Q_ASSERT(styleManager);
0546     KoParagraphStyle *parag = new KoParagraphStyle();
0547     parag->setName(i18n("Standard"));
0548     parag->setFontPointSize(12);
0549     parag->setFontWeight(QFont::Normal);
0550     styleManager->add(parag);
0551 
0552     parag = new KoParagraphStyle();
0553     parag->setName(i18n("Document Title"));
0554     parag->setFontPointSize(24);
0555     parag->setFontWeight(QFont::Bold);
0556     parag->setAlignment(Qt::AlignCenter);
0557     styleManager->add(parag);
0558 
0559     parag = new KoParagraphStyle();
0560     parag->setName(i18n("Head 1"));
0561     parag->setFontPointSize(20);
0562     parag->setFontWeight(QFont::Bold);
0563     styleManager->add(parag);
0564 
0565     parag = new KoParagraphStyle();
0566     parag->setName(i18n("Head 2"));
0567     parag->setFontPointSize(16);
0568     parag->setFontWeight(QFont::Bold);
0569     styleManager->add(parag);
0570 
0571     parag = new KoParagraphStyle();
0572     parag->setName(i18n("Head 3"));
0573     parag->setFontPointSize(12);
0574     parag->setFontWeight(QFont::Bold);
0575     styleManager->add(parag);
0576 
0577     parag = new KoParagraphStyle();
0578     parag->setName(i18n("Bullet List"));
0579     KoListStyle *list = new KoListStyle(parag);
0580     KoListLevelProperties llp = list->levelProperties(0);
0581     llp.setLabelType(KoListStyle::BulletCharLabelType);
0582     llp.setBulletCharacter(QChar(0x2022)); // Bullet
0583     list->setLevelProperties(llp);
0584     parag->setListStyle(list);
0585     styleManager->add(parag);
0586 
0587     setMimeTypeAfterLoading("application/vnd.oasis.opendocument.text");
0588     KoDocument::initEmpty();
0589     clearUndoHistory();
0590 }
0591 
0592 void KWDocument::clear()
0593 {
0594     // document defaults
0595     foreach (const KWPage &page, m_pageManager.pages())
0596         m_pageManager.removePage(page);
0597     m_pageManager.clearPageStyles();
0598 
0599     m_config.load(this); // re-load values
0600     foreach (KWFrameSet *fs, m_frameSets) {
0601         removeFrameSet(fs);
0602         delete fs;
0603     }
0604 
0605     // industry standard for bleed
0606     KoInsets padding;
0607     padding.top = MM_TO_POINT(3);
0608     padding.bottom = MM_TO_POINT(3);
0609     padding.left = MM_TO_POINT(3);
0610     padding.right = MM_TO_POINT(3);
0611     m_pageManager.setPadding(padding);
0612 
0613     if (inlineTextObjectManager())
0614         inlineTextObjectManager()->setProperty(KoInlineObject::PageCount, pageCount());
0615 }
0616 
0617 void KWDocument::setupOpenFileSubProgress()
0618 {
0619     if (progressUpdater()) {
0620         m_layoutProgressUpdater = progressUpdater()->startSubtask(1, "Layouting");
0621     }
0622 }
0623 
0624 bool KWDocument::loadOdf(KoOdfReadStore &odfStore)
0625 {
0626     clear();
0627     KWOdfLoader loader(this);
0628     bool rc = loader.load(odfStore);
0629     if (rc)
0630         endOfLoading();
0631     return rc;
0632 }
0633 
0634 bool KWDocument::loadXML(const KoXmlDocument &doc, KoStore *store)
0635 {
0636     Q_UNUSED(doc);
0637     Q_UNUSED(store);
0638     return false;
0639 }
0640 
0641 void KWDocument::endOfLoading() // called by both oasis and oldxml
0642 {
0643     debugWords;
0644 
0645     // Get the master page name of the first page.
0646     QString firstPageMasterName;
0647     if (mainFrameSet()) {
0648         QTextBlock block = mainFrameSet()->document()->firstBlock();
0649         firstPageMasterName = block.blockFormat().stringProperty(KoParagraphStyle::MasterPageName);
0650     }
0651 
0652     appendPage(firstPageMasterName);
0653 
0654     relayout();
0655 
0656     debugWords << "KWDocument::endOfLoading done";
0657 #if 0
0658     // Note that more stuff will happen in completeLoading
0659     firePageSetupChanged();
0660 #endif
0661     setModified(false);
0662 }
0663 
0664 bool KWDocument::saveOdf(SavingContext &documentContext)
0665 {
0666     KWOdfWriter writer(this);
0667     return writer.save(documentContext.odfStore, documentContext.embeddedSaver);
0668 }
0669 
0670 void KWDocument::updatePagesForStyle(const KWPageStyle &style)
0671 {
0672     debugWords << "pageStyleName=" << style.name();
0673     QList<KWFrameSet*> framesets;
0674     foreach(KWFrameSet *fs, frameLayout()->getFrameSets(style)) {
0675         KWTextFrameSet* tfs = dynamic_cast<KWTextFrameSet*>(fs);
0676         if (tfs)
0677             framesets.append(tfs);
0678     }
0679     int pageNumber = -1;
0680     foreach (const KWPage &page, pageManager()->pages()) {
0681         if (page.pageStyle() == style) {
0682             pageNumber = page.pageNumber();
0683             break;
0684         }
0685     }
0686     //Q_ASSERT(pageNumber >= 1);
0687     if (pageNumber < 1)
0688         return;
0689     foreach(KWFrameSet *fs, framesets) {
0690         static_cast<KWTextFrameSet*>(fs)->rootAreaProvider()->clearPages(pageNumber);
0691     }
0692     relayout(framesets);
0693 }
0694 
0695 void KWDocument::saveConfig()
0696 {
0697 //   KConfigGroup group(KoGlobal::calligraConfig(), "Spelling");
0698 //   group.writeEntry("PersonalDict", m_spellCheckPersonalDict);
0699 
0700     m_config.save();
0701     KSharedConfigPtr config = KSharedConfig::openConfig();
0702     KConfigGroup interface = config->group("Interface");
0703     interface.writeEntry("ResolutionX", gridData().gridX());
0704     interface.writeEntry("ResolutionY", gridData().gridY());
0705 }
0706 
0707 KoShape *KWDocument::findTargetTextShape(KoShape *shape) const
0708 {
0709     KoShape *result = 0;
0710     int      area   = 0;
0711     QRectF   br     = shape->boundingRect();
0712 
0713     // now find the frame that is closest to the frame we want to inline.
0714     foreach (KoShape *shape, mainFrameSet()->shapes()) {
0715         QRectF intersection  = br.intersected(shape->boundingRect());
0716         int    intersectArea = qRound(intersection.width() * intersection.height());
0717 
0718         if (intersectArea > area) {
0719             result = shape;
0720             area   = intersectArea;
0721         } else if (result == 0) {
0722             // TODO check distance between frames or something.
0723         }
0724     }
0725 
0726     return result;
0727 }
0728 
0729 KoShapeAnchor* KWDocument::anchorOfShape(KoShape *shape) const
0730 {
0731     Q_ASSERT(mainFrameSet());
0732     Q_ASSERT(shape);
0733 
0734     KoShapeAnchor *anchor = shape->anchor();
0735 
0736     if (!anchor) {
0737         anchor = new KoShapeAnchor(shape);
0738         anchor->setAnchorType(KoShapeAnchor::AnchorPage);
0739         anchor->setHorizontalPos(KoShapeAnchor::HFromLeft);
0740         anchor->setVerticalPos(KoShapeAnchor::VFromTop);
0741         shape->setAnchor(anchor);
0742     }
0743 
0744     return anchor;
0745 }
0746 
0747 
0748 KWFrame *KWDocument::frameOfShape(KoShape* shape) const
0749 {
0750     while (shape) {
0751         KWFrame *answer = dynamic_cast<KWFrame*>(shape->applicationData());
0752         if (answer)
0753             return answer;
0754         if (shape->parent() == 0)
0755             break;
0756         shape = shape->parent();
0757     }
0758 
0759     KWFrame *answer = dynamic_cast<KWFrame*>(shape->applicationData());
0760     if (answer == 0) { // this may be a clipping shape containing the frame-shape
0761         KoShapeContainer *container = dynamic_cast<KoShapeContainer*>(shape);
0762         if (container && container->shapeCount() == 1) {
0763             answer = dynamic_cast<KWFrame*>(container->shapes()[0]->applicationData());
0764         }
0765     }
0766 
0767     return answer;
0768 }
0769 
0770 KoDocumentInfoDlg *KWDocument::createDocumentInfoDialog(QWidget *parent, KoDocumentInfo *docInfo) const
0771 {
0772 
0773     KoDocumentInfoDlg *dlg = new KoDocumentInfoDlg(parent, docInfo);
0774     KoMainWindow *mainwin = dynamic_cast<KoMainWindow*>(parent);
0775     if (mainwin) {
0776         connect(dlg, SIGNAL(saveRequested()), mainwin, SLOT(slotFileSave()));
0777     }
0778 
0779 #ifdef SHOULD_BUILD_RDF
0780     KoPageWidgetItem *rdfEditWidget = new KoDocumentRdfEditWidget(static_cast<KoDocumentRdf*>(documentRdf()));
0781     dlg->addPageItem(rdfEditWidget);
0782 #endif
0783     return dlg;
0784 }