Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 : #include <DocumentStatisticsManager.hxx>
20 : #include <doc.hxx>
21 : #include <editsh.hxx>
22 : #include <fldbas.hxx>
23 : #include <docsh.hxx>
24 : #include <IDocumentFieldsAccess.hxx>
25 : #include <IDocumentState.hxx>
26 : #include <IDocumentLayoutAccess.hxx>
27 : #include <view.hxx>
28 : #include <ndtxt.hxx>
29 : #include <calbck.hxx>
30 : #include <fmtfld.hxx>
31 : #include <rootfrm.hxx>
32 : #include <docufld.hxx>
33 : #include <docstat.hxx>
34 : #include <vector>
35 : #include <viewsh.hxx>
36 : #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
37 :
38 : using namespace ::com::sun::star;
39 :
40 : namespace
41 : {
42 : class LockAllViews
43 : {
44 : std::vector<SwViewShell*> m_aViewWasUnLocked;
45 : SwViewShell* m_pViewShell;
46 : public:
47 1103 : explicit LockAllViews(SwViewShell *pViewShell)
48 1103 : : m_pViewShell(pViewShell)
49 : {
50 1103 : if (!m_pViewShell)
51 1112 : return;
52 2188 : for(SwViewShell& rShell : m_pViewShell->GetRingContainer())
53 : {
54 1094 : if(rShell.IsViewLocked())
55 : {
56 66 : m_aViewWasUnLocked.push_back(&rShell);
57 66 : rShell.LockView(true);
58 : }
59 : }
60 : }
61 1103 : ~LockAllViews()
62 1103 : {
63 1169 : for(SwViewShell* pShell : m_aViewWasUnLocked)
64 66 : pShell->LockView(false);
65 1103 : }
66 : };
67 : }
68 :
69 : namespace sw
70 : {
71 :
72 2958 : DocumentStatisticsManager::DocumentStatisticsManager( SwDoc& i_rSwdoc ) : m_rDoc( i_rSwdoc ),
73 2958 : mpDocStat( new SwDocStat )
74 : {
75 2958 : maStatsUpdateTimer.SetTimeout( 1 );
76 2958 : maStatsUpdateTimer.SetPriority( SchedulerPriority::LOWEST );
77 2958 : maStatsUpdateTimer.SetTimeoutHdl( LINK( this, DocumentStatisticsManager, DoIdleStatsUpdate ) );
78 2958 : }
79 :
80 4216 : void DocumentStatisticsManager::DocInfoChgd( )
81 : {
82 4216 : m_rDoc.getIDocumentFieldsAccess().GetSysFieldType( RES_DOCINFOFLD )->UpdateFields();
83 4216 : m_rDoc.getIDocumentFieldsAccess().GetSysFieldType( RES_TEMPLNAMEFLD )->UpdateFields();
84 4216 : m_rDoc.getIDocumentState().SetModified();
85 4216 : }
86 :
87 53556309 : const SwDocStat& DocumentStatisticsManager::GetDocStat() const
88 : {
89 53556309 : return *mpDocStat;
90 : }
91 :
92 1001754 : SwDocStat& DocumentStatisticsManager::GetDocStat()
93 : {
94 1001754 : return *mpDocStat;
95 : }
96 :
97 959 : const SwDocStat& DocumentStatisticsManager::GetUpdatedDocStat( bool bCompleteAsync, bool bFields )
98 : {
99 959 : if( mpDocStat->bModified )
100 : {
101 925 : UpdateDocStat( bCompleteAsync, bFields );
102 : }
103 959 : return *mpDocStat;
104 : }
105 :
106 283 : void DocumentStatisticsManager::SetDocStat( const SwDocStat& rStat )
107 : {
108 283 : *mpDocStat = rStat;
109 283 : }
110 :
111 1085 : void DocumentStatisticsManager::UpdateDocStat( bool bCompleteAsync, bool bFields )
112 : {
113 1085 : if( mpDocStat->bModified )
114 : {
115 1085 : if (!bCompleteAsync)
116 : {
117 396 : while (IncrementalDocStatCalculate(
118 198 : ::std::numeric_limits<long>::max(), bFields)) {}
119 198 : maStatsUpdateTimer.Stop();
120 : }
121 887 : else if (IncrementalDocStatCalculate(5000, bFields))
122 18 : maStatsUpdateTimer.Start();
123 : else
124 869 : maStatsUpdateTimer.Stop();
125 : }
126 1085 : }
127 :
128 : // returns true while there is more to do
129 1103 : bool DocumentStatisticsManager::IncrementalDocStatCalculate(long nChars, bool bFields)
130 : {
131 1103 : mpDocStat->Reset();
132 1103 : mpDocStat->nPara = 0; // default is 1!
133 :
134 : // This is the inner loop - at least while the paras are dirty.
135 21951 : for( sal_uLong i = m_rDoc.GetNodes().Count(); i > 0 && nChars > 0; )
136 : {
137 : SwNode* pNd;
138 19745 : switch( ( pNd = m_rDoc.GetNodes()[ --i ])->GetNodeType() )
139 : {
140 : case ND_TEXTNODE:
141 : {
142 5936 : long const nOldChars(mpDocStat->nChar);
143 5936 : SwTextNode *pText = static_cast< SwTextNode * >( pNd );
144 5936 : if (pText->CountWords(*mpDocStat, 0, pText->GetText().getLength()))
145 : {
146 779 : nChars -= (mpDocStat->nChar - nOldChars);
147 : }
148 5936 : break;
149 : }
150 71 : case ND_TABLENODE: ++mpDocStat->nTable; break;
151 22 : case ND_GRFNODE: ++mpDocStat->nGrf; break;
152 11 : case ND_OLENODE: ++mpDocStat->nOLE; break;
153 83 : case ND_SECTIONNODE: break;
154 : }
155 : }
156 :
157 : // #i93174#: notes contain paragraphs that are not nodes
158 : {
159 1103 : SwFieldType * const pPostits( m_rDoc.getIDocumentFieldsAccess().GetSysFieldType(RES_POSTITFLD) );
160 1103 : SwIterator<SwFormatField,SwFieldType> aIter( *pPostits );
161 1147 : for( SwFormatField* pFormatField = aIter.First(); pFormatField; pFormatField = aIter.Next() )
162 : {
163 44 : if (pFormatField->IsFieldInDoc())
164 : {
165 : SwPostItField const * const pField(
166 44 : static_cast<SwPostItField const*>(pFormatField->GetField()));
167 44 : mpDocStat->nAllPara += pField->GetNumberOfParagraphs();
168 : }
169 1103 : }
170 : }
171 :
172 1103 : mpDocStat->nPage = m_rDoc.getIDocumentLayoutAccess().GetCurrentLayout() ? m_rDoc.getIDocumentLayoutAccess().GetCurrentLayout()->GetPageNum() : 0;
173 1103 : mpDocStat->bModified = false;
174 :
175 1103 : com::sun::star::uno::Sequence < com::sun::star::beans::NamedValue > aStat( mpDocStat->nPage ? 8 : 7);
176 1103 : sal_Int32 n=0;
177 1103 : aStat[n].Name = "TableCount";
178 1103 : aStat[n++].Value <<= (sal_Int32)mpDocStat->nTable;
179 1103 : aStat[n].Name = "ImageCount";
180 1103 : aStat[n++].Value <<= (sal_Int32)mpDocStat->nGrf;
181 1103 : aStat[n].Name = "ObjectCount";
182 1103 : aStat[n++].Value <<= (sal_Int32)mpDocStat->nOLE;
183 1103 : if ( mpDocStat->nPage )
184 : {
185 1094 : aStat[n].Name = "PageCount";
186 1094 : aStat[n++].Value <<= (sal_Int32)mpDocStat->nPage;
187 : }
188 1103 : aStat[n].Name = "ParagraphCount";
189 1103 : aStat[n++].Value <<= (sal_Int32)mpDocStat->nPara;
190 1103 : aStat[n].Name = "WordCount";
191 1103 : aStat[n++].Value <<= (sal_Int32)mpDocStat->nWord;
192 1103 : aStat[n].Name = "CharacterCount";
193 1103 : aStat[n++].Value <<= (sal_Int32)mpDocStat->nChar;
194 1103 : aStat[n].Name = "NonWhitespaceCharacterCount";
195 1103 : aStat[n++].Value <<= (sal_Int32)mpDocStat->nCharExcludingSpaces;
196 :
197 : // For e.g. autotext documents there is no pSwgInfo (#i79945)
198 1103 : SwDocShell* pObjShell(m_rDoc.GetDocShell());
199 1103 : if (pObjShell)
200 : {
201 : const uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
202 1103 : pObjShell->GetModel(), uno::UNO_QUERY_THROW);
203 : const uno::Reference<document::XDocumentProperties> xDocProps(
204 2206 : xDPS->getDocumentProperties());
205 : // #i96786#: do not set modified flag when updating statistics
206 1103 : const bool bDocWasModified( m_rDoc.getIDocumentState().IsModified() );
207 2206 : const ModifyBlocker_Impl b(pObjShell);
208 : // rhbz#1081176: don't jump to cursor pos because of (temporary)
209 : // activation of modified flag triggering move to input position
210 2206 : LockAllViews aViewGuard(pObjShell->GetEditShell());
211 1103 : xDocProps->setDocumentStatistics(aStat);
212 1103 : if (!bDocWasModified)
213 : {
214 402 : m_rDoc.getIDocumentState().ResetModified();
215 1103 : }
216 : }
217 :
218 : // optionally update stat. fields
219 1103 : if (bFields)
220 : {
221 216 : SwFieldType *pType = m_rDoc.getIDocumentFieldsAccess().GetSysFieldType(RES_DOCSTATFLD);
222 216 : pType->UpdateFields();
223 : }
224 :
225 1103 : return nChars < 0;
226 : }
227 :
228 36 : IMPL_LINK_TYPED( DocumentStatisticsManager, DoIdleStatsUpdate, Timer *, pTimer, void )
229 : {
230 : (void)pTimer;
231 18 : if (IncrementalDocStatCalculate(32000))
232 0 : maStatsUpdateTimer.Start();
233 :
234 18 : SwView* pView = m_rDoc.GetDocShell() ? m_rDoc.GetDocShell()->GetView() : NULL;
235 18 : if( pView )
236 18 : pView->UpdateDocStats();
237 18 : }
238 :
239 8847 : DocumentStatisticsManager::~DocumentStatisticsManager()
240 : {
241 2949 : maStatsUpdateTimer.Stop();
242 2949 : delete mpDocStat;
243 5898 : }
244 :
245 177 : }
246 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|