1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 #include <vcl/timer.hxx>
32 #include <hints.hxx>
33 #include <IGrammarContact.hxx>
34 #include <pam.hxx>
35 #include <ndtxt.hxx>
36 #include <SwGrammarMarkUp.hxx>
37 #include <txtfrm.hxx>
38 #include <rootfrm.hxx>
39 #include <viewsh.hxx>
40 
41 /* SwGrammarContact
42     This class is responsible for the delayed display of grammar checks when a paragraph is edited
43     It's a client of the paragraph the cursor points to.
44     If the cursor position changes, updateCursorPosition has to be called
45     If the grammar checker wants to set a grammar marker at a paragraph, he has to request
46     the grammar list from this class. If the requested paragraph is not edited, it returns
47     the normal grammar list. But if the paragraph is the active one, a proxy list will be returned and
48     all changes are set in this proxy list. If the cursor leaves the paragraph the proxy list
49     will replace the old list. If the grammar checker has completed the paragraph ('setChecked')
50     then a timer is setup which replaces the old list as well.
51 */
52 
53 class SwGrammarContact : public IGrammarContact, public SwClient
54 {
55     Timer aTimer;
56     SwGrammarMarkUp *mpProxyList;
57     bool mbFinished;
58     SwTxtNode* getMyTxtNode() { return (SwTxtNode*)GetRegisteredIn(); }
59   	DECL_LINK( TimerRepaint, Timer * );
60 
61 public:
62     SwGrammarContact();
63     ~SwGrammarContact() { aTimer.Stop(); delete mpProxyList; }
64 
65     // (pure) virtual functions of IGrammarContact
66     virtual void updateCursorPosition( const SwPosition& rNewPos );
67     virtual SwGrammarMarkUp* getGrammarCheck( SwTxtNode& rTxtNode, bool bCreate );
68     virtual void finishGrammarCheck( SwTxtNode& rTxtNode );
69 protected:
70     // virtual function of SwClient
71 	virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew);
72 };
73 
74 SwGrammarContact::SwGrammarContact() : mpProxyList(0), mbFinished( false )
75 {
76 	aTimer.SetTimeout( 2000 );  // Repaint of grammar check after 'setChecked'
77 	aTimer.SetTimeoutHdl( LINK(this, SwGrammarContact, TimerRepaint) );
78 }
79 
80 IMPL_LINK( SwGrammarContact, TimerRepaint, Timer *, pTimer )
81 {
82     if( pTimer )
83     {
84         pTimer->Stop();
85         if( GetRegisteredIn() )
86         {   //Replace the old wrong list by the proxy list and repaint all frames
87             getMyTxtNode()->SetGrammarCheck( mpProxyList, true );
88             mpProxyList = 0;
89             SwTxtFrm::repaintTextFrames( *getMyTxtNode() );
90         }
91     }
92     return 0;
93 }
94 
95 /* I'm always a client of the current paragraph */
96 void SwGrammarContact::updateCursorPosition( const SwPosition& rNewPos )
97 {
98     SwTxtNode* pTxtNode = rNewPos.nNode.GetNode().GetTxtNode();
99     if( pTxtNode != GetRegisteredIn() ) // paragraph has been changed
100     {
101         aTimer.Stop();
102         if( GetRegisteredIn() ) // My last paragraph has been left
103         {
104             if( mpProxyList )
105             {   // replace old list by the proxy list and repaint
106                 getMyTxtNode()->SetGrammarCheck( mpProxyList, true );
107                 SwTxtFrm::repaintTextFrames( *getMyTxtNode() );
108             }
109             GetRegisteredInNonConst()->Remove( this ); // good bye old paragraph
110             mpProxyList = 0;
111         }
112         if( pTxtNode )
113             pTxtNode->Add( this ); // welcome new paragraph
114     }
115 }
116 
117 /* deliver a grammar check list for the given text node */
118 SwGrammarMarkUp* SwGrammarContact::getGrammarCheck( SwTxtNode& rTxtNode, bool bCreate )
119 {
120     SwGrammarMarkUp *pRet = 0;
121     if( GetRegisteredIn() == &rTxtNode ) // hey, that's my current paragraph!
122     {   // so you will get a proxy list...
123         if( bCreate )
124         {
125             if( mbFinished )
126             {
127                 delete mpProxyList;
128                 mpProxyList = 0;
129             }
130             if( !mpProxyList )
131             {
132                 if( rTxtNode.GetGrammarCheck() )
133                     mpProxyList = (SwGrammarMarkUp*)rTxtNode.GetGrammarCheck()->Clone();
134                 else
135                 {
136                     mpProxyList = new SwGrammarMarkUp();
137                     mpProxyList->SetInvalid( 0, STRING_LEN );
138                 }
139             }
140            mbFinished = false;
141         }
142         pRet = mpProxyList;
143     }
144     else
145     {
146         pRet = rTxtNode.GetGrammarCheck(); // do you have already a list?
147         if( bCreate && !pRet ) // do you want to create a list?
148         {
149             pRet = new SwGrammarMarkUp();
150             pRet->SetInvalid( 0, STRING_LEN );
151             rTxtNode.SetGrammarCheck( pRet );
152             rTxtNode.SetGrammarCheckDirty( true );
153         }
154     }
155     return pRet;
156 }
157 
158 void SwGrammarContact::Modify( const SfxPoolItem* pOld, const SfxPoolItem * )
159 {
160 	if( !pOld || pOld->Which() != RES_OBJECTDYING )
161 		return;
162 
163 	SwPtrMsgPoolItem *pDead = (SwPtrMsgPoolItem *)pOld;
164 	if( pDead->pObject == GetRegisteredIn() )
165 	{    // if my current paragraph dies, I throw the proxy list away
166         aTimer.Stop();
167 		GetRegisteredInNonConst()->Remove( this );
168         delete mpProxyList;
169         mpProxyList = 0;
170 	}
171 }
172 
173 void SwGrammarContact::finishGrammarCheck( SwTxtNode& rTxtNode )
174 {
175     if( &rTxtNode != GetRegisteredIn() ) // not my paragraph
176         SwTxtFrm::repaintTextFrames( rTxtNode ); // can be repainted directly
177     else
178     {
179         if( mpProxyList )
180         {
181             mbFinished = true;
182             aTimer.Start(); // will replace old list and repaint with delay
183         }
184         else if( getMyTxtNode()->GetGrammarCheck() )
185         {   // all grammar problems seems to be gone, no delay needed
186             getMyTxtNode()->SetGrammarCheck( 0, true );
187             SwTxtFrm::repaintTextFrames( *getMyTxtNode() );
188         }
189     }
190 }
191 
192 IGrammarContact* createGrammarContact()
193 {
194     return new SwGrammarContact();
195 }
196 
197 void finishGrammarCheck( SwTxtNode& rTxtNode )
198 {
199     IGrammarContact* pGrammarContact = getGrammarContact( rTxtNode );
200     if( pGrammarContact )
201         pGrammarContact->finishGrammarCheck( rTxtNode );
202 }
203 
204