1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
19 #include <DocumentStatisticsManager.hxx>
23 #include <IDocumentFieldsAccess.hxx>
24 #include <IDocumentState.hxx>
25 #include <IDocumentLayoutAccess.hxx>
29 #include <rootfrm.hxx>
30 #include <docufld.hxx>
31 #include <docstat.hxx>
32 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
33 #include <com/sun/star/frame/XModel.hpp>
35 using namespace ::com::sun::star
;
40 DocumentStatisticsManager::DocumentStatisticsManager( SwDoc
& i_rSwdoc
)
42 mpDocStat( new SwDocStat
),
43 mbInitialized( false ),
44 maStatsUpdateIdle( i_rSwdoc
, "sw::DocumentStatisticsManager maStatsUpdateIdle" )
46 maStatsUpdateIdle
.SetPriority( TaskPriority::LOWEST
);
47 maStatsUpdateIdle
.SetInvokeHandler( LINK( this, DocumentStatisticsManager
, DoIdleStatsUpdate
) );
50 void DocumentStatisticsManager::DocInfoChgd(bool const isEnableSetModified
)
52 m_rDoc
.getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::DocInfo
)->UpdateFields();
53 m_rDoc
.getIDocumentFieldsAccess().GetSysFieldType( SwFieldIds::TemplateName
)->UpdateFields();
54 if (isEnableSetModified
)
56 m_rDoc
.getIDocumentState().SetModified();
60 const SwDocStat
& DocumentStatisticsManager::GetDocStat() const
65 void DocumentStatisticsManager::SetDocStatModified(bool bSet
)
67 mpDocStat
->bModified
= bSet
;
70 const SwDocStat
& DocumentStatisticsManager::GetUpdatedDocStat( bool bCompleteAsync
, bool bFields
)
72 if( mpDocStat
->bModified
|| !mbInitialized
)
74 UpdateDocStat( bCompleteAsync
, bFields
);
79 void DocumentStatisticsManager::SetDocStat( const SwDocStat
& rStat
)
85 void DocumentStatisticsManager::UpdateDocStat( bool bCompleteAsync
, bool bFields
)
87 if( !mpDocStat
->bModified
&& mbInitialized
)
92 maStatsUpdateIdle
.Stop();
93 while (IncrementalDocStatCalculate(
94 std::numeric_limits
<tools::Long
>::max(), bFields
)) {}
96 else if (IncrementalDocStatCalculate(5000, bFields
))
97 maStatsUpdateIdle
.Start();
99 maStatsUpdateIdle
.Stop();
102 // returns true while there is more to do
103 bool DocumentStatisticsManager::IncrementalDocStatCalculate(tools::Long nChars
, bool bFields
)
105 mbInitialized
= true;
107 mpDocStat
->nPara
= 0; // default is 1!
109 // This is the inner loop - at least while the paras are dirty.
110 for( SwNodeOffset i
= m_rDoc
.GetNodes().Count(); i
> SwNodeOffset(0) && nChars
> 0; )
112 SwNode
* pNd
= m_rDoc
.GetNodes()[ --i
];
113 switch( pNd
->GetNodeType() )
115 case SwNodeType::Text
:
117 tools::Long
const nOldChars(mpDocStat
->nChar
);
118 SwTextNode
*pText
= static_cast< SwTextNode
* >( pNd
);
119 if (pText
->CountWords(*mpDocStat
, 0, pText
->GetText().getLength()))
121 nChars
-= (mpDocStat
->nChar
- nOldChars
);
125 case SwNodeType::Table
: ++mpDocStat
->nTable
; break;
126 case SwNodeType::Grf
: ++mpDocStat
->nGrf
; break;
127 case SwNodeType::Ole
: ++mpDocStat
->nOLE
; break;
128 case SwNodeType::Section
: break;
133 // #i93174#: notes contain paragraphs that are not nodes
135 SwFieldType
* const pPostits( m_rDoc
.getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::Postit
) );
136 std::vector
<SwFormatField
*> vFields
;
137 pPostits
->GatherFields(vFields
);
138 for(auto pFormatField
: vFields
)
140 const auto pField
= static_cast<SwPostItField
const*>(pFormatField
->GetField());
141 mpDocStat
->nAllPara
+= pField
->GetNumberOfParagraphs();
145 mpDocStat
->nPage
= m_rDoc
.getIDocumentLayoutAccess().GetCurrentLayout() ? m_rDoc
.getIDocumentLayoutAccess().GetCurrentLayout()->GetPageNum() : 0;
146 SetDocStatModified( false );
148 css::uno::Sequence
< css::beans::NamedValue
> aStat( mpDocStat
->nPage
? 8 : 7);
149 auto pStat
= aStat
.getArray();
151 pStat
[n
].Name
= "TableCount";
152 pStat
[n
++].Value
<<= static_cast<sal_Int32
>(mpDocStat
->nTable
);
153 pStat
[n
].Name
= "ImageCount";
154 pStat
[n
++].Value
<<= static_cast<sal_Int32
>(mpDocStat
->nGrf
);
155 pStat
[n
].Name
= "ObjectCount";
156 pStat
[n
++].Value
<<= static_cast<sal_Int32
>(mpDocStat
->nOLE
);
157 if ( mpDocStat
->nPage
)
159 pStat
[n
].Name
= "PageCount";
160 pStat
[n
++].Value
<<= static_cast<sal_Int32
>(mpDocStat
->nPage
);
162 pStat
[n
].Name
= "ParagraphCount";
163 pStat
[n
++].Value
<<= static_cast<sal_Int32
>(mpDocStat
->nPara
);
164 pStat
[n
].Name
= "WordCount";
165 pStat
[n
++].Value
<<= static_cast<sal_Int32
>(mpDocStat
->nWord
);
166 pStat
[n
].Name
= "CharacterCount";
167 pStat
[n
++].Value
<<= static_cast<sal_Int32
>(mpDocStat
->nChar
);
168 pStat
[n
].Name
= "NonWhitespaceCharacterCount";
169 pStat
[n
++].Value
<<= static_cast<sal_Int32
>(mpDocStat
->nCharExcludingSpaces
);
171 // For e.g. autotext documents there is no pSwgInfo (#i79945)
172 SwDocShell
* pObjShell(m_rDoc
.GetDocShell());
175 const uno::Reference
<document::XDocumentPropertiesSupplier
> xDPS(
176 pObjShell
->GetModel(), uno::UNO_QUERY_THROW
);
177 const uno::Reference
<document::XDocumentProperties
> xDocProps(
178 xDPS
->getDocumentProperties());
179 // #i96786#: do not set modified flag when updating statistics
180 const bool bDocWasModified( m_rDoc
.getIDocumentState().IsModified() );
181 const ModifyBlocker_Impl
b(pObjShell
);
182 // rhbz#1081176: don't jump to cursor pos because of (temporary)
183 // activation of modified flag triggering move to input position
184 auto aViewGuard(pObjShell
->LockAllViews());
185 xDocProps
->setDocumentStatistics(aStat
);
186 if (!bDocWasModified
)
188 m_rDoc
.getIDocumentState().ResetModified();
192 // optionally update stat. fields
195 SwFieldType
*pType
= m_rDoc
.getIDocumentFieldsAccess().GetSysFieldType(SwFieldIds::DocStat
);
196 pType
->UpdateFields();
202 IMPL_LINK( DocumentStatisticsManager
, DoIdleStatsUpdate
, Timer
*, pIdle
, void )
204 if (IncrementalDocStatCalculate(32000))
206 SwView
* pView
= m_rDoc
.GetDocShell() ? m_rDoc
.GetDocShell()->GetView() : nullptr;
208 pView
->UpdateDocStats();
211 DocumentStatisticsManager::~DocumentStatisticsManager()
213 maStatsUpdateIdle
.Stop();
217 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */