diff options
Diffstat (limited to 'sw/source/core/doc/DocumentStatisticsManager.cxx')
-rw-r--r-- | sw/source/core/doc/DocumentStatisticsManager.cxx | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/sw/source/core/doc/DocumentStatisticsManager.cxx b/sw/source/core/doc/DocumentStatisticsManager.cxx new file mode 100644 index 000000000..9508e6d72 --- /dev/null +++ b/sw/source/core/doc/DocumentStatisticsManager.cxx @@ -0,0 +1,218 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#include <DocumentStatisticsManager.hxx> +#include <doc.hxx> +#include <fldbas.hxx> +#include <docsh.hxx> +#include <IDocumentFieldsAccess.hxx> +#include <IDocumentState.hxx> +#include <IDocumentLayoutAccess.hxx> +#include <view.hxx> +#include <ndtxt.hxx> +#include <calbck.hxx> +#include <fmtfld.hxx> +#include <rootfrm.hxx> +#include <docufld.hxx> +#include <docstat.hxx> +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> +#include <com/sun/star/frame/XModel.hpp> + +using namespace ::com::sun::star; + +namespace sw +{ + +DocumentStatisticsManager::DocumentStatisticsManager( SwDoc& i_rSwdoc ) : m_rDoc( i_rSwdoc ), + mpDocStat( new SwDocStat ), + mbInitialized( false ), + maStatsUpdateIdle( i_rSwdoc ) + +{ + maStatsUpdateIdle.SetPriority( TaskPriority::LOWEST ); + maStatsUpdateIdle.SetInvokeHandler( LINK( this, DocumentStatisticsManager, DoIdleStatsUpdate ) ); + maStatsUpdateIdle.SetDebugName( "sw::DocumentStatisticsManager maStatsUpdateIdle" ); +} + +void DocumentStatisticsManager::DocInfoChgd(bool const isEnableSetModified) +{ + m_rDoc.getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::DocInfo )->UpdateFields(); + m_rDoc.getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::TemplateName )->UpdateFields(); + if (isEnableSetModified) + { + m_rDoc.getIDocumentState().SetModified(); + } +} + +const SwDocStat& DocumentStatisticsManager::GetDocStat() const +{ + return *mpDocStat; +} + +void DocumentStatisticsManager::SetDocStatModified(bool bSet) +{ + mpDocStat->bModified = bSet; +} + +const SwDocStat& DocumentStatisticsManager::GetUpdatedDocStat( bool bCompleteAsync, bool bFields ) +{ + if( mpDocStat->bModified || !mbInitialized) + { + UpdateDocStat( bCompleteAsync, bFields ); + } + return *mpDocStat; +} + +void DocumentStatisticsManager::SetDocStat( const SwDocStat& rStat ) +{ + *mpDocStat = rStat; + mbInitialized = true; +} + +void DocumentStatisticsManager::UpdateDocStat( bool bCompleteAsync, bool bFields ) +{ + if( mpDocStat->bModified || !mbInitialized) + { + if (!bCompleteAsync) + { + maStatsUpdateIdle.Stop(); + while (IncrementalDocStatCalculate( + std::numeric_limits<long>::max(), bFields)) {} + } + else if (IncrementalDocStatCalculate(5000, bFields)) + maStatsUpdateIdle.Start(); + else + maStatsUpdateIdle.Stop(); + } +} + +// returns true while there is more to do +bool DocumentStatisticsManager::IncrementalDocStatCalculate(long nChars, bool bFields) +{ + mbInitialized = true; + mpDocStat->Reset(); + mpDocStat->nPara = 0; // default is 1! + + // This is the inner loop - at least while the paras are dirty. + for( sal_uLong i = m_rDoc.GetNodes().Count(); i > 0 && nChars > 0; ) + { + SwNode* pNd = m_rDoc.GetNodes()[ --i ]; + switch( pNd->GetNodeType() ) + { + case SwNodeType::Text: + { + long const nOldChars(mpDocStat->nChar); + SwTextNode *pText = static_cast< SwTextNode * >( pNd ); + if (pText->CountWords(*mpDocStat, 0, pText->GetText().getLength())) + { + nChars -= (mpDocStat->nChar - nOldChars); + } + break; + } + case SwNodeType::Table: ++mpDocStat->nTable; break; + case SwNodeType::Grf: ++mpDocStat->nGrf; break; + case SwNodeType::Ole: ++mpDocStat->nOLE; break; + case SwNodeType::Section: break; + default: break; + } + } + + // #i93174#: notes contain paragraphs that are not nodes + { + SwFieldType * const pPostits( m_rDoc.getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::Postit) ); + std::vector<SwFormatField*> vFields; + pPostits->GatherFields(vFields); + for(auto pFormatField : vFields) + { + const auto pField = static_cast<SwPostItField const*>(pFormatField->GetField()); + mpDocStat->nAllPara += pField->GetNumberOfParagraphs(); + } + } + + mpDocStat->nPage = m_rDoc.getIDocumentLayoutAccess().GetCurrentLayout() ? m_rDoc.getIDocumentLayoutAccess().GetCurrentLayout()->GetPageNum() : 0; + SetDocStatModified( false ); + + css::uno::Sequence < css::beans::NamedValue > aStat( mpDocStat->nPage ? 8 : 7); + sal_Int32 n=0; + aStat[n].Name = "TableCount"; + aStat[n++].Value <<= static_cast<sal_Int32>(mpDocStat->nTable); + aStat[n].Name = "ImageCount"; + aStat[n++].Value <<= static_cast<sal_Int32>(mpDocStat->nGrf); + aStat[n].Name = "ObjectCount"; + aStat[n++].Value <<= static_cast<sal_Int32>(mpDocStat->nOLE); + if ( mpDocStat->nPage ) + { + aStat[n].Name = "PageCount"; + aStat[n++].Value <<= static_cast<sal_Int32>(mpDocStat->nPage); + } + aStat[n].Name = "ParagraphCount"; + aStat[n++].Value <<= static_cast<sal_Int32>(mpDocStat->nPara); + aStat[n].Name = "WordCount"; + aStat[n++].Value <<= static_cast<sal_Int32>(mpDocStat->nWord); + aStat[n].Name = "CharacterCount"; + aStat[n++].Value <<= static_cast<sal_Int32>(mpDocStat->nChar); + aStat[n].Name = "NonWhitespaceCharacterCount"; + aStat[n++].Value <<= static_cast<sal_Int32>(mpDocStat->nCharExcludingSpaces); + + // For e.g. autotext documents there is no pSwgInfo (#i79945) + SwDocShell* pObjShell(m_rDoc.GetDocShell()); + if (pObjShell) + { + const uno::Reference<document::XDocumentPropertiesSupplier> xDPS( + pObjShell->GetModel(), uno::UNO_QUERY_THROW); + const uno::Reference<document::XDocumentProperties> xDocProps( + xDPS->getDocumentProperties()); + // #i96786#: do not set modified flag when updating statistics + const bool bDocWasModified( m_rDoc.getIDocumentState().IsModified() ); + const ModifyBlocker_Impl b(pObjShell); + // rhbz#1081176: don't jump to cursor pos because of (temporary) + // activation of modified flag triggering move to input position + auto aViewGuard(pObjShell->LockAllViews()); + xDocProps->setDocumentStatistics(aStat); + if (!bDocWasModified) + { + m_rDoc.getIDocumentState().ResetModified(); + } + } + + // optionally update stat. fields + if (bFields) + { + SwFieldType *pType = m_rDoc.getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::DocStat); + pType->UpdateFields(); + } + + return nChars < 0; +} + +IMPL_LINK( DocumentStatisticsManager, DoIdleStatsUpdate, Timer *, pIdle, void ) +{ + if (IncrementalDocStatCalculate(32000)) + pIdle->Start(); + SwView* pView = m_rDoc.GetDocShell() ? m_rDoc.GetDocShell()->GetView() : nullptr; + if( pView ) + pView->UpdateDocStats(); +} + +DocumentStatisticsManager::~DocumentStatisticsManager() +{ + maStatsUpdateIdle.Stop(); +} + +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |