summaryrefslogtreecommitdiffstats
path: root/sw/source/core/doc/DocumentStatisticsManager.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/core/doc/DocumentStatisticsManager.cxx')
-rw-r--r--sw/source/core/doc/DocumentStatisticsManager.cxx218
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: */