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