asynchronous word-count.
diff --git a/sw/inc/IDocumentStatistics.hxx b/sw/inc/IDocumentStatistics.hxx
index 4ec926a1..2c5a0501 100644
--- a/sw/inc/IDocumentStatistics.hxx
+++ b/sw/inc/IDocumentStatistics.hxx
@@ -35,13 +35,26 @@

    /** Document - Statistics
    */
    /// Returns a reference to the existing document statistics
    virtual const SwDocStat &GetDocStat() const = 0;

    virtual const SwDocStat &GetUpdatedDocStat() = 0;
    /**
      * Updates the document statistics if the document has been
      * modified and returns a reference to the result.
      * \param bCompleteAsync if true will return a partial result,
      * and potentially trigger a timeout to complete the work.
      */
    virtual const SwDocStat &GetUpdatedDocStat(bool bCompleteAsync) = 0;

    /// Set the document statistics
    virtual void SetDocStat(const SwDocStat& rStat) = 0;

    virtual void UpdateDocStat() = 0;
    /**
      * Updates the internal document's statistics
      * \param bCompleteAsync if true it may do part of the
      * work and trigger a timeout to complete it.
      */
    virtual void UpdateDocStat(bool bCompleteAsync) = 0;

protected:
    virtual ~IDocumentStatistics() {};
diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx
index c67f79f..ccebf5c 100644
--- a/sw/inc/doc.hxx
+++ b/sw/inc/doc.hxx
@@ -282,6 +282,7 @@ class SW_DLLPUBLIC SwDoc :
    */
    Timer       aIdleTimer;             ///< Own IdleTimer
    Timer       aOLEModifiedTimer;      ///< Timer for update modified OLE-Objecs
    Timer       aStatsUpdateTimer;      ///< Timer for asynchronous stats calculation
    SwDBData    aDBData;                ///< database descriptor
    ::com::sun::star::uno::Sequence <sal_Int8 > aRedlinePasswd;
    String      sTOIAutoMarkURL;        ///< ::com::sun::star::util::URL of table of index AutoMark file
@@ -909,9 +910,9 @@ public:
    */
    virtual void DocInfoChgd();
    virtual const SwDocStat &GetDocStat() const;
    virtual const SwDocStat &GetUpdatedDocStat();
    virtual const SwDocStat &GetUpdatedDocStat(bool bCompleteAsync = false);
    virtual void SetDocStat(const SwDocStat& rStat);
    virtual void UpdateDocStat();
    virtual void UpdateDocStat(bool bCompleteAsync = false);

    /** IDocumentState
    */
@@ -2071,6 +2072,17 @@ private:
    void CopyMasterHeader(const SwPageDesc &rChged, const SwFmtHeader &rHead, SwPageDesc *pDesc, bool bLeft);
    /// Copies master footer to left / first one, if necessary - used by ChgPageDesc().
    void CopyMasterFooter(const SwPageDesc &rChged, const SwFmtFooter &rFoot, SwPageDesc *pDesc, bool bLeft);

    /** continue computing a chunk of document statistics
      * \param nTextNodes number of paragraphs to calculate before
      * exiting
      *
      * returns false when there is no more to calculate
      */
    bool IncrementalDocStatCalculate(long nTextNodes = 250);

    /// Our own 'StatsUpdateTimer' calls the following method
    DECL_LINK( DoIdleStatsUpdate, Timer * );
};

// This method is called in Dtor of SwDoc and deletes cache of ContourObjects.
diff --git a/sw/inc/ndtxt.hxx b/sw/inc/ndtxt.hxx
index 18c2b02..5a47fb2 100644
--- a/sw/inc/ndtxt.hxx
+++ b/sw/inc/ndtxt.hxx
@@ -745,8 +745,8 @@ public:
                            xub_StrLen nStart, xub_StrLen nEnd,
                            SwUndoTransliterate* pUndo = 0 );

    /// count words in given range
    void CountWords( SwDocStat& rStat, xub_StrLen nStart, xub_StrLen nEnd ) const;
    /// count words in given range - returns true if we refreshed out count
    bool CountWords( SwDocStat& rStat, xub_StrLen nStart, xub_StrLen nEnd ) const;

    /** Checks some global conditions like loading or destruction of document
       to economize notifications */
diff --git a/sw/source/core/doc/doc.cxx b/sw/source/core/doc/doc.cxx
index cd71cf5..0470ef3 100644
--- a/sw/source/core/doc/doc.cxx
+++ b/sw/source/core/doc/doc.cxx
@@ -55,6 +55,7 @@
#include <editeng/rsiditem.hxx>
#include <unotools/charclass.hxx>
#include <unotools/localedatawrapper.hxx>
#include <vcl/timer.hxx>

#include <swatrset.hxx>
#include <swmodule.hxx>
@@ -112,6 +113,7 @@
#include <shellres.hxx>
#include <txtfrm.hxx>
#include <attrhint.hxx>
#include <view.hxx>

#include <wdocsh.hxx>           // SwWebDocShell
#include <prtopt.hxx>           // SwPrintOptions
@@ -1146,10 +1148,6 @@ bool SwDoc::UpdateParRsid( SwTxtNode *pTxtNode, sal_uInt32 nVal )
    return pTxtNode->SetAttr( aRsid );
}


/*************************************************************************
 *             void SetDocStat( const SwDocStat& rStat );
 *************************************************************************/
void SwDoc::SetDocStat( const SwDocStat& rStat )
{
    *pDocStat = rStat;
@@ -1160,11 +1158,11 @@ const SwDocStat& SwDoc::GetDocStat() const
    return *pDocStat;
}

const SwDocStat& SwDoc::GetUpdatedDocStat()
const SwDocStat& SwDoc::GetUpdatedDocStat( bool bCompleteAsync )
{
    if (pDocStat->bModified)
    if( pDocStat->bModified )
    {
        UpdateDocStat();
        UpdateDocStat( bCompleteAsync );
    }
    return *pDocStat;
}
@@ -1686,92 +1684,117 @@ void SwDoc::CalculatePagePairsForProspectPrinting(
    // thus we are done here.
}

/*************************************************************************
 *            void UpdateDocStat();
 *************************************************************************/
void SwDoc::UpdateDocStat()
// returns true while there is more to do
bool SwDoc::IncrementalDocStatCalculate( long nTextNodes )
{
    pDocStat->Reset();
    pDocStat->nPara = 0; // default is 1!
    SwNode* pNd;

    // This is the inner loop - at least while the paras are dirty.
    for( sal_uLong i = GetNodes().Count(); i > 0 && nTextNodes > 0; )
    {
        switch( ( pNd = GetNodes()[ --i ])->GetNodeType() )
        {
        case ND_TEXTNODE:
        {
            SwTxtNode *pTxt = static_cast< SwTxtNode * >( pNd );
            if( pTxt->CountWords( *pDocStat, 0, pTxt->GetTxt().Len() ) )
                nTextNodes--;
            break;
        }
        case ND_TABLENODE:      ++pDocStat->nTbl;   break;
        case ND_GRFNODE:        ++pDocStat->nGrf;   break;
        case ND_OLENODE:        ++pDocStat->nOLE;   break;
        case ND_SECTIONNODE:    break;
        }
    }

    // #i93174#: notes contain paragraphs that are not nodes
    {
        SwFieldType * const pPostits( GetSysFldType(RES_POSTITFLD) );
        SwIterator<SwFmtFld,SwFieldType> aIter( *pPostits );
        for( SwFmtFld* pFmtFld = aIter.First(); pFmtFld;  pFmtFld = aIter.Next() )
        {
            if (pFmtFld->IsFldInDoc())
            {
                SwPostItField const * const pField(
                    static_cast<SwPostItField const*>(pFmtFld->GetFld()));
                pDocStat->nAllPara += pField->GetNumberOfParagraphs();
            }
        }
    }

    pDocStat->nPage     = GetCurrentLayout() ? GetCurrentLayout()->GetPageNum() : 0;
    pDocStat->bModified = sal_False;

    com::sun::star::uno::Sequence < com::sun::star::beans::NamedValue > aStat( pDocStat->nPage ? 8 : 7);
    sal_Int32 n=0;
    aStat[n].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("TableCount"));
    aStat[n++].Value <<= (sal_Int32)pDocStat->nTbl;
    aStat[n].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ImageCount"));
    aStat[n++].Value <<= (sal_Int32)pDocStat->nGrf;
    aStat[n].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ObjectCount"));
    aStat[n++].Value <<= (sal_Int32)pDocStat->nOLE;
    if ( pDocStat->nPage )
    {
        aStat[n].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("PageCount"));
        aStat[n++].Value <<= (sal_Int32)pDocStat->nPage;
    }
    aStat[n].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ParagraphCount"));
    aStat[n++].Value <<= (sal_Int32)pDocStat->nPara;
    aStat[n].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("WordCount"));
    aStat[n++].Value <<= (sal_Int32)pDocStat->nWord;
    aStat[n].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharacterCount"));
    aStat[n++].Value <<= (sal_Int32)pDocStat->nChar;
    aStat[n].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("NonWhitespaceCharacterCount"));
    aStat[n++].Value <<= (sal_Int32)pDocStat->nCharExcludingSpaces;

    // For e.g. autotext documents there is no pSwgInfo (#i79945)
    SfxObjectShell * const pObjShell( 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( IsModified() );
        const ModifyBlocker_Impl b(pObjShell);
        xDocProps->setDocumentStatistics(aStat);
        if (!bDocWasModified)
        {
            ResetModified();
        }
    }

    // optionally update stat. fields
    SwFieldType *pType = GetSysFldType(RES_DOCSTATFLD);
    pType->UpdateFlds();

    return nTextNodes <= 0;
}

IMPL_LINK( SwDoc, DoIdleStatsUpdate, Timer *, pTimer )
{
    (void)pTimer;
    if( IncrementalDocStatCalculate( 1000 ) )
        aStatsUpdateTimer.Start();

    SwView* pView = GetDocShell() ? GetDocShell()->GetView() : NULL;
    if( pView )
        pView->UpdateDocStats();
    return 0;
}

void SwDoc::UpdateDocStat( bool bCompleteAsync )
{
    if( pDocStat->bModified )
    {
        pDocStat->Reset();
        pDocStat->nPara = 0;        // default is 1!
        SwNode* pNd;

        for( sal_uLong i = GetNodes().Count(); i; )
        {
            switch( ( pNd = GetNodes()[ --i ])->GetNodeType() )
            {
            case ND_TEXTNODE:
                ((SwTxtNode*)pNd)->CountWords( *pDocStat, 0, ((SwTxtNode*)pNd)->GetTxt().Len() );
                break;
            case ND_TABLENODE:      ++pDocStat->nTbl;   break;
            case ND_GRFNODE:        ++pDocStat->nGrf;   break;
            case ND_OLENODE:        ++pDocStat->nOLE;   break;
            case ND_SECTIONNODE:    break;
            }
        }

        // #i93174#: notes contain paragraphs that are not nodes
        {
            SwFieldType * const pPostits( GetSysFldType(RES_POSTITFLD) );
            SwIterator<SwFmtFld,SwFieldType> aIter( *pPostits );
            for( SwFmtFld* pFmtFld = aIter.First(); pFmtFld;  pFmtFld = aIter.Next() )
            {
                if (pFmtFld->IsFldInDoc())
                {
                    SwPostItField const * const pField(
                        static_cast<SwPostItField const*>(pFmtFld->GetFld()));
                    pDocStat->nAllPara += pField->GetNumberOfParagraphs();
                }
            }
        }

        pDocStat->nPage     = GetCurrentLayout() ? GetCurrentLayout()->GetPageNum() : 0;    //swmod 080218
        pDocStat->bModified = sal_False;

        com::sun::star::uno::Sequence < com::sun::star::beans::NamedValue > aStat( pDocStat->nPage ? 8 : 7);
        sal_Int32 n=0;
        aStat[n].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("TableCount"));
        aStat[n++].Value <<= (sal_Int32)pDocStat->nTbl;
        aStat[n].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ImageCount"));
        aStat[n++].Value <<= (sal_Int32)pDocStat->nGrf;
        aStat[n].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ObjectCount"));
        aStat[n++].Value <<= (sal_Int32)pDocStat->nOLE;
        if ( pDocStat->nPage )
        {
            aStat[n].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("PageCount"));
            aStat[n++].Value <<= (sal_Int32)pDocStat->nPage;
        }
        aStat[n].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ParagraphCount"));
        aStat[n++].Value <<= (sal_Int32)pDocStat->nPara;
        aStat[n].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("WordCount"));
        aStat[n++].Value <<= (sal_Int32)pDocStat->nWord;
        aStat[n].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CharacterCount"));
        aStat[n++].Value <<= (sal_Int32)pDocStat->nChar;
        aStat[n].Name = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("NonWhitespaceCharacterCount"));
        aStat[n++].Value <<= (sal_Int32)pDocStat->nCharExcludingSpaces;

        // For e.g. autotext documents there is no pSwgInfo (#i79945)
        SfxObjectShell * const pObjShell( 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( IsModified() );
            const ModifyBlocker_Impl b(pObjShell);
            xDocProps->setDocumentStatistics(aStat);
            if (!bDocWasModified)
            {
                ResetModified();
            }
        }

        // optionally update stat. fields
        SwFieldType *pType = GetSysFldType(RES_DOCSTATFLD);
        pType->UpdateFlds();
        if (!bCompleteAsync)
            while (IncrementalDocStatCalculate()) {}
        else if (IncrementalDocStatCalculate())
            aStatsUpdateTimer.Start();
    }
}

diff --git a/sw/source/core/doc/docnew.cxx b/sw/source/core/doc/docnew.cxx
index 949cab1..7b1faa6 100644
--- a/sw/source/core/doc/docnew.cxx
+++ b/sw/source/core/doc/docnew.cxx
@@ -403,6 +403,9 @@ SwDoc::SwDoc()
    aOLEModifiedTimer.SetTimeout( 1000 );
    aOLEModifiedTimer.SetTimeoutHdl( LINK( this, SwDoc, DoUpdateModifiedOLE ));

    aStatsUpdateTimer.SetTimeout( 100 );
    aStatsUpdateTimer.SetTimeoutHdl( LINK( this, SwDoc, DoIdleStatsUpdate ) );

    // Create DBMgr
    pNewDBMgr = new SwNewDBMgr;

@@ -508,6 +511,7 @@ SwDoc::~SwDoc()
    SetDefault(aCharFmt);

    StopIdling();   // stop idle timer
    aStatsUpdateTimer.Stop();

    delete pUnoCallBack, pUnoCallBack = 0;
    delete pURLStateChgd;
diff --git a/sw/source/core/txtnode/txtedt.cxx b/sw/source/core/txtnode/txtedt.cxx
index d91bf7d..3c8503b 100644
--- a/sw/source/core/txtnode/txtedt.cxx
+++ b/sw/source/core/txtnode/txtedt.cxx
@@ -1854,22 +1854,24 @@ void SwTxtNode::ReplaceTextOnly( xub_StrLen nPos, xub_StrLen nLen,
    NotifyClients( 0, &aHint );
}

void SwTxtNode::CountWords( SwDocStat& rStat,
// the return values allows us to see if we did the heavy-
// lifting required to actually break and count the words.
bool SwTxtNode::CountWords( SwDocStat& rStat,
                            xub_StrLen nStt, xub_StrLen nEnd ) const
{
    if( nStt > nEnd )
    {   // bad call
        return;
        return false;
    }
    if (IsInRedlines())
    {   //not counting txtnodes used to hold deleted redline content
        return;
        return false;
    }
    bool bCountAll = ( (0 == nStt) && (GetTxt().Len() == nEnd) );
    ++rStat.nAllPara; // #i93174#: count _all_ paragraphs
    if ( IsHidden() )
    {   // not counting hidden paras
        return;
        return false;
    }
    // count words in numbering string if started at beginning of para:
    bool bCountNumbering = nStt == 0;
@@ -1886,7 +1888,7 @@ void SwTxtNode::CountWords( SwDocStat& rStat,

    if( nStt == nEnd && !bCountNumbering)
    {   // unnumbered empty node or empty selection
        return;
        return false;
    }

    // count of non-empty paras
@@ -1900,7 +1902,7 @@ void SwTxtNode::CountWords( SwDocStat& rStat,
        rStat.nAsianWord += GetParaNumberOfAsianWords();
        rStat.nChar += GetParaNumberOfChars();
        rStat.nCharExcludingSpaces += GetParaNumberOfCharsExcludingSpaces();
        return;
        return false;
    }

    // ConversionMap to expand fields, remove invisible and redline deleted text for scanner
@@ -1914,7 +1916,7 @@ void SwTxtNode::CountWords( SwDocStat& rStat,
    if (aExpandText.isEmpty() && !bCountNumbering)
    {
        OSL_ENSURE(aExpandText.getLength() >= 0, "Node text expansion error: length < 0." );
        return;
        return false;
    }

    //do the count
@@ -2002,6 +2004,8 @@ void SwTxtNode::CountWords( SwDocStat& rStat,
    rStat.nAsianWord += nTmpAsianWords;
    rStat.nChar += nTmpChars;
    rStat.nCharExcludingSpaces += nTmpCharsExcludingSpaces;

    return true;
}

//
diff --git a/sw/source/ui/dialog/wordcountdialog.cxx b/sw/source/ui/dialog/wordcountdialog.cxx
index ff777ac..6d8d738 100644
--- a/sw/source/ui/dialog/wordcountdialog.cxx
+++ b/sw/source/ui/dialog/wordcountdialog.cxx
@@ -32,7 +32,7 @@
#include <vcl/msgbox.hxx>

IMPL_LINK_NOARG(SwWordCountFloatDlg, CloseHdl)
{   
{
    SfxViewFrame* pVFrame = ::GetActiveView()->GetViewFrame();
    if (pVFrame != NULL)
    {
diff --git a/sw/source/ui/inc/view.hxx b/sw/source/ui/inc/view.hxx
index 2cfcf389..d0a542b 100644
--- a/sw/source/ui/inc/view.hxx
+++ b/sw/source/ui/inc/view.hxx
@@ -358,7 +358,9 @@ class SW_DLLPUBLIC SwView: public SfxViewShell

    SW_DLLPRIVATE virtual void  Move();

    SW_DLLPRIVATE sal_Bool          InsertGraphicDlg( SfxRequest& );
    SW_DLLPRIVATE sal_Bool      InsertGraphicDlg( SfxRequest& );

    SW_DLLPRIVATE void          DocumentStatsChanged();

protected:

@@ -656,6 +658,8 @@ public:

    // exhibition hack (MA,MBA)
    void SelectShellForDrop();

    void UpdateDocStats();
};

// ----------------- inline Methoden ----------------------
diff --git a/sw/source/ui/uiview/view.cxx b/sw/source/ui/uiview/view.cxx
index 1ad946c..26a135d 100644
--- a/sw/source/ui/uiview/view.cxx
+++ b/sw/source/ui/uiview/view.cxx
@@ -1055,6 +1055,7 @@ SwView::~SwView()
    bInDtor = sal_True;
    pEditWin->Hide(); // damit kein Paint Aerger machen kann!
    // An der SwDocShell den Pointer auf die View ruecksetzen

    SwDocShell* pDocSh = GetDocShell();
    if( pDocSh && pDocSh->GetView() == this )
        pDocSh->SetView( 0 );
diff --git a/sw/source/ui/uiview/view2.cxx b/sw/source/ui/uiview/view2.cxx
index f5aff2a..0414f68 100644
--- a/sw/source/ui/uiview/view2.cxx
+++ b/sw/source/ui/uiview/view2.cxx
@@ -1203,6 +1203,13 @@ void SwView::UpdatePageNums(sal_uInt16 nPhyNum, sal_uInt16 nVirtNum, const Strin
    rBnd.Update( FN_STAT_PAGE );
}

void SwView::UpdateDocStats()
{
    SfxBindings &rBnd = GetViewFrame()->GetBindings();
    rBnd.Invalidate( FN_STAT_WORDCOUNT );
    rBnd.Update( FN_STAT_WORDCOUNT );
}

/*--------------------------------------------------------------------
    Beschreibung:   Status der Stauszeile
 --------------------------------------------------------------------*/
@@ -1241,7 +1248,7 @@ void SwView::StateStatusLine(SfxItemSet &rSet)
                SwDocStat documentStats;
                {
                    rShell.CountWords(selectionStats);
                    documentStats = rShell.GetDoc()->GetUpdatedDocStat();
                    documentStats = rShell.GetDoc()->GetUpdatedDocStat( true /* complete-async */ );
                }

                const sal_uInt32 stringId = selectionStats.nWord? STR_STATUSBAR_WORDCOUNT : STR_STATUSBAR_WORDCOUNT_NO_SELECTION;