Warning, file /office/calligra/libs/textlayout/IndexGeneratorManager.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) 2011 Ko GmbH <cbo@kogmbh.com>
0003  *
0004  * This library is free software; you can redistribute it and/or
0005  * modify it under the terms of the GNU Library General Public
0006  * License as published by the Free Software Foundation; either
0007  * version 2 of the License, or (at your option) any later version.
0008  *
0009  * This library is distributed in the hope that it will be useful,
0010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012  * Library General Public License for more details.
0013  *
0014  * You should have received a copy of the GNU Library General Public License
0015  * along with this library; see the file COPYING.LIB.  If not, write to
0016  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017  * Boston, MA 02110-1301, USA.
0018  */
0019 
0020 #include "IndexGeneratorManager.h"
0021 
0022 #include "KoTextDocumentLayout.h"
0023 #include "ToCGenerator.h"
0024 
0025 #include <KoTextDocument.h>
0026 #include <KoParagraphStyle.h>
0027 #include <KoTableOfContentsGeneratorInfo.h>
0028 
0029 #include <QTextDocument>
0030 #include <TextLayoutDebug.h>
0031 
0032 IndexGeneratorManager::IndexGeneratorManager(QTextDocument *document)
0033     : QObject(document)
0034     , m_document(document)
0035     , m_state(FirstRunNeeded)
0036 {
0037     m_documentLayout = static_cast<KoTextDocumentLayout *>(document->documentLayout());
0038 
0039     // connect to layoutIsDirty
0040     connect(m_documentLayout, SIGNAL(layoutIsDirty()), this, SLOT(requestGeneration()));
0041 
0042     // connect to FinishedLayout
0043     connect(m_documentLayout, SIGNAL(finishedLayout()), this, SLOT(startDoneTimer()));
0044 
0045     connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(timeout()));
0046     m_updateTimer.setInterval(5000); // after 5 seconds of pause we update
0047     m_updateTimer.setSingleShot(true);
0048 
0049     connect(&m_doneTimer, SIGNAL(timeout()), this, SLOT(layoutDone()));
0050     m_doneTimer.setInterval(1000); // after 1 seconds of silence we assume layout is done
0051     m_doneTimer.setSingleShot(true);
0052 }
0053 
0054 IndexGeneratorManager::~IndexGeneratorManager()
0055 {
0056 }
0057 
0058 IndexGeneratorManager *IndexGeneratorManager::instance(QTextDocument *document)
0059 {
0060     QVariant resource = document->resource(KoTextDocument::IndexGeneratorManager, KoTextDocument::IndexGeneratorManagerUrl);
0061 
0062     IndexGeneratorManager *igm = resource.value<IndexGeneratorManager *>();
0063 
0064     if (!igm) {
0065         igm = new IndexGeneratorManager(document);
0066 
0067         resource.setValue(igm);
0068 
0069         document->addResource(KoTextDocument::IndexGeneratorManager, KoTextDocument::IndexGeneratorManagerUrl, resource);
0070     }
0071 
0072     return igm;
0073 }
0074 
0075 void IndexGeneratorManager::requestGeneration()
0076 {
0077     if (m_state == FirstRun || m_state == SecondRun) {
0078         return;
0079     }
0080     if (m_document->characterCount() < 2) {
0081         return;
0082     }
0083     m_updateTimer.stop();
0084     m_updateTimer.start();
0085 }
0086 
0087 void IndexGeneratorManager::startDoneTimer()
0088 {
0089     //we delay acting on the finishedLayout signal by 1 second. This way we
0090     // don't act on it until every header has had a chance to be layouted
0091     // in words (we assume that a new finishedLayout signal will arrive within that
0092     // 1 second)
0093     m_doneTimer.start();
0094 }
0095 
0096 void IndexGeneratorManager::timeout()
0097 {
0098     m_updateTimer.stop();
0099     m_state = FirstRunNeeded;
0100     m_documentLayout->scheduleLayout();
0101 }
0102 
0103 bool IndexGeneratorManager::generate()
0104 {
0105     if (m_state == Resting || m_state == FirstRunLayouting || m_state == SecondRunLayouting) {
0106         return false;
0107     }
0108 
0109     if (m_state == FirstRun || m_state == SecondRun) {
0110         return true;
0111     }
0112 
0113     if (m_document->characterCount() < 2) {
0114         return false;
0115     }
0116 
0117     if (m_state == FirstRunNeeded) {
0118         m_state = FirstRun;
0119     }
0120 
0121     if (m_state == SecondRunNeeded) {
0122         m_state = SecondRun;
0123     }
0124 
0125     QTextBlock block = m_document->firstBlock();
0126 
0127     bool success = true;
0128     while (block.isValid()) {
0129         QTextBlockFormat format = block.blockFormat();
0130 
0131         if (format.hasProperty(KoParagraphStyle::TableOfContentsData)) {
0132             QVariant data = format.property(KoParagraphStyle::TableOfContentsData);
0133             KoTableOfContentsGeneratorInfo *tocInfo = data.value<KoTableOfContentsGeneratorInfo *>();
0134 
0135             data = format.property(KoParagraphStyle::GeneratedDocument);
0136             QTextDocument *tocDocument = data.value<QTextDocument *>();
0137 
0138             ToCGenerator *generator = m_generators[tocInfo];
0139             if (!generator) {
0140                 generator = new ToCGenerator(tocDocument, tocInfo);
0141                 m_generators[tocInfo] = generator;
0142             }
0143 
0144             generator->setBlock(block);
0145             success &= generator->generate();
0146         }
0147         block = block.next();
0148     }
0149 
0150 
0151     if (m_state == FirstRun) {
0152         m_state = FirstRunLayouting;
0153     }
0154 
0155     if (m_state == SecondRun) {
0156         if (success) {
0157             m_state = SecondRunLayouting;
0158         } else {
0159             m_state = FirstRunLayouting;
0160         }
0161     }
0162 
0163     return false;
0164 }
0165 
0166 void IndexGeneratorManager::layoutDone()
0167 {
0168     switch (m_state) {
0169         case FirstRunLayouting:
0170             m_state = SecondRunNeeded;
0171             m_documentLayout->scheduleLayout();
0172             break;
0173         case SecondRunLayouting:
0174             m_state = Resting;
0175             break;
0176         default:
0177             break;
0178     }
0179 }