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 }