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