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; 54 SwTxtNode* getMyTxtNode() { return (SwTxtNode*)GetRegisteredIn(); } 55 DECL_LINK( TimerRepaint, Timer * ); 56 57 public: 58 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 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 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 */ 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 */ 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 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 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 188 IGrammarContact* createGrammarContact() 189 { 190 return new SwGrammarContact(); 191 } 192 193 void finishGrammarCheck( SwTxtNode& rTxtNode ) 194 { 195 IGrammarContact* pGrammarContact = getGrammarContact( rTxtNode ); 196 if( pGrammarContact ) 197 pGrammarContact->finishGrammarCheck( rTxtNode ); 198 } 199 200