1*3b8558fdSAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 3*3b8558fdSAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4*3b8558fdSAndrew Rist * or more contributor license agreements. See the NOTICE file 5*3b8558fdSAndrew Rist * distributed with this work for additional information 6*3b8558fdSAndrew Rist * regarding copyright ownership. The ASF licenses this file 7*3b8558fdSAndrew Rist * to you under the Apache License, Version 2.0 (the 8*3b8558fdSAndrew Rist * "License"); you may not use this file except in compliance 9*3b8558fdSAndrew Rist * with the License. You may obtain a copy of the License at 10cdf0e10cSrcweir * 11*3b8558fdSAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12cdf0e10cSrcweir * 13*3b8558fdSAndrew Rist * Unless required by applicable law or agreed to in writing, 14*3b8558fdSAndrew Rist * software distributed under the License is distributed on an 15*3b8558fdSAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*3b8558fdSAndrew Rist * KIND, either express or implied. See the License for the 17*3b8558fdSAndrew Rist * specific language governing permissions and limitations 18*3b8558fdSAndrew Rist * under the License. 19cdf0e10cSrcweir * 20*3b8558fdSAndrew Rist *************************************************************/ 21*3b8558fdSAndrew Rist 22*3b8558fdSAndrew Rist 23cdf0e10cSrcweir #include "precompiled_linguistic.hxx" 24cdf0e10cSrcweir 25cdf0e10cSrcweir #include <com/sun/star/container/XContentEnumerationAccess.hpp> 26cdf0e10cSrcweir #include <com/sun/star/container/XEnumeration.hpp> 27cdf0e10cSrcweir #include <com/sun/star/container/XNameAccess.hpp> 28cdf0e10cSrcweir #include <com/sun/star/container/XNameContainer.hpp> 29cdf0e10cSrcweir #include <com/sun/star/container/XNameReplace.hpp> 30cdf0e10cSrcweir #include <com/sun/star/i18n/XBreakIterator.hpp> 31cdf0e10cSrcweir #include <com/sun/star/lang/XComponent.hpp> 32cdf0e10cSrcweir #include <com/sun/star/lang/XServiceInfo.hpp> 33cdf0e10cSrcweir #include <com/sun/star/lang/XMultiServiceFactory.hpp> 34cdf0e10cSrcweir #include <com/sun/star/linguistic2/XSupportedLocales.hpp> 35cdf0e10cSrcweir #include <com/sun/star/linguistic2/XProofreader.hpp> 36cdf0e10cSrcweir #include <com/sun/star/linguistic2/XProofreadingIterator.hpp> 37cdf0e10cSrcweir #include <com/sun/star/linguistic2/SingleProofreadingError.hpp> 38cdf0e10cSrcweir #include <com/sun/star/linguistic2/ProofreadingResult.hpp> 39cdf0e10cSrcweir #include <com/sun/star/linguistic2/LinguServiceEvent.hpp> 40cdf0e10cSrcweir #include <com/sun/star/linguistic2/LinguServiceEventFlags.hpp> 41cdf0e10cSrcweir #include <com/sun/star/registry/XRegistryKey.hpp> 42cdf0e10cSrcweir #include <com/sun/star/text/TextMarkupType.hpp> 43cdf0e10cSrcweir #include <com/sun/star/text/TextMarkupDescriptor.hpp> 44cdf0e10cSrcweir #include <com/sun/star/text/XTextMarkup.hpp> 45cdf0e10cSrcweir #include <com/sun/star/text/XMultiTextMarkup.hpp> 46cdf0e10cSrcweir #include <com/sun/star/text/XFlatParagraph.hpp> 47cdf0e10cSrcweir #include <com/sun/star/text/XFlatParagraphIterator.hpp> 48cdf0e10cSrcweir #include <com/sun/star/uno/XComponentContext.hpp> 49cdf0e10cSrcweir #include <com/sun/star/lang/XSingleComponentFactory.hpp> 50cdf0e10cSrcweir 51cdf0e10cSrcweir #include <sal/config.h> 52cdf0e10cSrcweir #include <osl/conditn.hxx> 53cdf0e10cSrcweir #include <osl/thread.hxx> 54cdf0e10cSrcweir #include <cppuhelper/implbase4.hxx> 55cdf0e10cSrcweir #include <cppuhelper/implementationentry.hxx> 56cdf0e10cSrcweir #include <cppuhelper/interfacecontainer.h> 57cdf0e10cSrcweir #include <cppuhelper/factory.hxx> 58cdf0e10cSrcweir #include <i18npool/mslangid.hxx> 59cdf0e10cSrcweir #include <unotools/processfactory.hxx> 60cdf0e10cSrcweir #include <comphelper/extract.hxx> 61cdf0e10cSrcweir 62cdf0e10cSrcweir #include <deque> 63cdf0e10cSrcweir #include <map> 64cdf0e10cSrcweir #include <vector> 65cdf0e10cSrcweir 66cdf0e10cSrcweir #include "linguistic/misc.hxx" 67cdf0e10cSrcweir #include "defs.hxx" 68cdf0e10cSrcweir #include "lngopt.hxx" 69cdf0e10cSrcweir 70cdf0e10cSrcweir #include "gciterator.hxx" 71cdf0e10cSrcweir 72cdf0e10cSrcweir using ::rtl::OUString; 73cdf0e10cSrcweir using namespace linguistic; 74cdf0e10cSrcweir using namespace ::com::sun::star; 75cdf0e10cSrcweir 76cdf0e10cSrcweir // forward declarations 77cdf0e10cSrcweir static ::rtl::OUString GrammarCheckingIterator_getImplementationName() throw(); 78cdf0e10cSrcweir static uno::Sequence< OUString > GrammarCheckingIterator_getSupportedServiceNames() throw(); 79cdf0e10cSrcweir 80cdf0e10cSrcweir 81cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////// 82cdf0e10cSrcweir 83cdf0e10cSrcweir // white space list: obtained from the fonts.config.txt of a Linux system. 84cdf0e10cSrcweir static sal_Unicode aWhiteSpaces[] = 85cdf0e10cSrcweir { 86cdf0e10cSrcweir 0x0020, /* SPACE */ 87cdf0e10cSrcweir 0x00a0, /* NO-BREAK SPACE */ 88cdf0e10cSrcweir 0x00ad, /* SOFT HYPHEN */ 89cdf0e10cSrcweir 0x115f, /* HANGUL CHOSEONG FILLER */ 90cdf0e10cSrcweir 0x1160, /* HANGUL JUNGSEONG FILLER */ 91cdf0e10cSrcweir 0x1680, /* OGHAM SPACE MARK */ 92cdf0e10cSrcweir 0x2000, /* EN QUAD */ 93cdf0e10cSrcweir 0x2001, /* EM QUAD */ 94cdf0e10cSrcweir 0x2002, /* EN SPACE */ 95cdf0e10cSrcweir 0x2003, /* EM SPACE */ 96cdf0e10cSrcweir 0x2004, /* THREE-PER-EM SPACE */ 97cdf0e10cSrcweir 0x2005, /* FOUR-PER-EM SPACE */ 98cdf0e10cSrcweir 0x2006, /* SIX-PER-EM SPACE */ 99cdf0e10cSrcweir 0x2007, /* FIGURE SPACE */ 100cdf0e10cSrcweir 0x2008, /* PUNCTUATION SPACE */ 101cdf0e10cSrcweir 0x2009, /* THIN SPACE */ 102cdf0e10cSrcweir 0x200a, /* HAIR SPACE */ 103cdf0e10cSrcweir 0x200b, /* ZERO WIDTH SPACE */ 104cdf0e10cSrcweir 0x200c, /* ZERO WIDTH NON-JOINER */ 105cdf0e10cSrcweir 0x200d, /* ZERO WIDTH JOINER */ 106cdf0e10cSrcweir 0x200e, /* LEFT-TO-RIGHT MARK */ 107cdf0e10cSrcweir 0x200f, /* RIGHT-TO-LEFT MARK */ 108cdf0e10cSrcweir 0x2028, /* LINE SEPARATOR */ 109cdf0e10cSrcweir 0x2029, /* PARAGRAPH SEPARATOR */ 110cdf0e10cSrcweir 0x202a, /* LEFT-TO-RIGHT EMBEDDING */ 111cdf0e10cSrcweir 0x202b, /* RIGHT-TO-LEFT EMBEDDING */ 112cdf0e10cSrcweir 0x202c, /* POP DIRECTIONAL FORMATTING */ 113cdf0e10cSrcweir 0x202d, /* LEFT-TO-RIGHT OVERRIDE */ 114cdf0e10cSrcweir 0x202e, /* RIGHT-TO-LEFT OVERRIDE */ 115cdf0e10cSrcweir 0x202f, /* NARROW NO-BREAK SPACE */ 116cdf0e10cSrcweir 0x205f, /* MEDIUM MATHEMATICAL SPACE */ 117cdf0e10cSrcweir 0x2060, /* WORD JOINER */ 118cdf0e10cSrcweir 0x2061, /* FUNCTION APPLICATION */ 119cdf0e10cSrcweir 0x2062, /* INVISIBLE TIMES */ 120cdf0e10cSrcweir 0x2063, /* INVISIBLE SEPARATOR */ 121cdf0e10cSrcweir 0x206A, /* INHIBIT SYMMETRIC SWAPPING */ 122cdf0e10cSrcweir 0x206B, /* ACTIVATE SYMMETRIC SWAPPING */ 123cdf0e10cSrcweir 0x206C, /* INHIBIT ARABIC FORM SHAPING */ 124cdf0e10cSrcweir 0x206D, /* ACTIVATE ARABIC FORM SHAPING */ 125cdf0e10cSrcweir 0x206E, /* NATIONAL DIGIT SHAPES */ 126cdf0e10cSrcweir 0x206F, /* NOMINAL DIGIT SHAPES */ 127cdf0e10cSrcweir 0x3000, /* IDEOGRAPHIC SPACE */ 128cdf0e10cSrcweir 0x3164, /* HANGUL FILLER */ 129cdf0e10cSrcweir 0xfeff, /* ZERO WIDTH NO-BREAK SPACE */ 130cdf0e10cSrcweir 0xffa0, /* HALFWIDTH HANGUL FILLER */ 131cdf0e10cSrcweir 0xfff9, /* INTERLINEAR ANNOTATION ANCHOR */ 132cdf0e10cSrcweir 0xfffa, /* INTERLINEAR ANNOTATION SEPARATOR */ 133cdf0e10cSrcweir 0xfffb /* INTERLINEAR ANNOTATION TERMINATOR */ 134cdf0e10cSrcweir }; 135cdf0e10cSrcweir 136cdf0e10cSrcweir static int nWhiteSpaces = sizeof( aWhiteSpaces ) / sizeof( aWhiteSpaces[0] ); 137cdf0e10cSrcweir 138cdf0e10cSrcweir static bool lcl_IsWhiteSpace( sal_Unicode cChar ) 139cdf0e10cSrcweir { 140cdf0e10cSrcweir bool bFound = false; 141cdf0e10cSrcweir for (int i = 0; i < nWhiteSpaces && !bFound; ++i) 142cdf0e10cSrcweir { 143cdf0e10cSrcweir if (cChar == aWhiteSpaces[i]) 144cdf0e10cSrcweir bFound = true; 145cdf0e10cSrcweir } 146cdf0e10cSrcweir return bFound; 147cdf0e10cSrcweir } 148cdf0e10cSrcweir 149cdf0e10cSrcweir static sal_Int32 lcl_SkipWhiteSpaces( const OUString &rText, sal_Int32 nStartPos ) 150cdf0e10cSrcweir { 151cdf0e10cSrcweir // note having nStartPos point right behind the string is OK since that one 152cdf0e10cSrcweir // is a correct end-of-sentence position to be returned from a grammar checker... 153cdf0e10cSrcweir 154cdf0e10cSrcweir const sal_Int32 nLen = rText.getLength(); 155cdf0e10cSrcweir bool bIllegalArgument = false; 156cdf0e10cSrcweir if (nStartPos < 0) 157cdf0e10cSrcweir { 158cdf0e10cSrcweir bIllegalArgument = true; 159cdf0e10cSrcweir nStartPos = 0; 160cdf0e10cSrcweir } 161cdf0e10cSrcweir if (nStartPos > nLen) 162cdf0e10cSrcweir { 163cdf0e10cSrcweir bIllegalArgument = true; 164cdf0e10cSrcweir nStartPos = nLen; 165cdf0e10cSrcweir } 166cdf0e10cSrcweir if (bIllegalArgument) 167cdf0e10cSrcweir { 168cdf0e10cSrcweir DBG_ASSERT( 0, "lcl_SkipWhiteSpaces: illegal arguments" ); 169cdf0e10cSrcweir } 170cdf0e10cSrcweir 171cdf0e10cSrcweir sal_Int32 nRes = nStartPos; 172cdf0e10cSrcweir if (0 <= nStartPos && nStartPos < nLen) 173cdf0e10cSrcweir { 174cdf0e10cSrcweir const sal_Unicode *pText = rText.getStr() + nStartPos; 175cdf0e10cSrcweir while (nStartPos < nLen && lcl_IsWhiteSpace( *pText )) 176cdf0e10cSrcweir ++pText; 177cdf0e10cSrcweir nRes = pText - rText.getStr(); 178cdf0e10cSrcweir } 179cdf0e10cSrcweir 180cdf0e10cSrcweir DBG_ASSERT( 0 <= nRes && nRes <= nLen, "lcl_SkipWhiteSpaces return value out of range" ); 181cdf0e10cSrcweir return nRes; 182cdf0e10cSrcweir } 183cdf0e10cSrcweir 184cdf0e10cSrcweir static sal_Int32 lcl_BacktraceWhiteSpaces( const OUString &rText, sal_Int32 nStartPos ) 185cdf0e10cSrcweir { 186cdf0e10cSrcweir // note: having nStartPos point right behind the string is OK since that one 187cdf0e10cSrcweir // is a correct end-of-sentence position to be returned from a grammar checker... 188cdf0e10cSrcweir 189cdf0e10cSrcweir const sal_Int32 nLen = rText.getLength(); 190cdf0e10cSrcweir bool bIllegalArgument = false; 191cdf0e10cSrcweir if (nStartPos < 0) 192cdf0e10cSrcweir { 193cdf0e10cSrcweir bIllegalArgument = true; 194cdf0e10cSrcweir nStartPos = 0; 195cdf0e10cSrcweir } 196cdf0e10cSrcweir if (nStartPos > nLen) 197cdf0e10cSrcweir { 198cdf0e10cSrcweir bIllegalArgument = true; 199cdf0e10cSrcweir nStartPos = nLen; 200cdf0e10cSrcweir } 201cdf0e10cSrcweir if (bIllegalArgument) 202cdf0e10cSrcweir { 203cdf0e10cSrcweir DBG_ASSERT( 0, "lcl_BacktraceWhiteSpaces: illegal arguments" ); 204cdf0e10cSrcweir } 205cdf0e10cSrcweir 206cdf0e10cSrcweir sal_Int32 nRes = nStartPos; 207cdf0e10cSrcweir sal_Int32 nPosBefore = nStartPos - 1; 208cdf0e10cSrcweir const sal_Unicode *pStart = rText.getStr(); 209cdf0e10cSrcweir if (0 <= nPosBefore && nPosBefore < nLen && lcl_IsWhiteSpace( pStart[ nPosBefore ] )) 210cdf0e10cSrcweir { 211cdf0e10cSrcweir nStartPos = nPosBefore; 212cdf0e10cSrcweir if (0 <= nStartPos && nStartPos < nLen) 213cdf0e10cSrcweir { 214cdf0e10cSrcweir const sal_Unicode *pText = rText.getStr() + nStartPos; 215cdf0e10cSrcweir while (pText > pStart && lcl_IsWhiteSpace( *pText )) 216cdf0e10cSrcweir --pText; 217cdf0e10cSrcweir // now add 1 since we want to point to the first char after the last char in the sentence... 218cdf0e10cSrcweir nRes = pText - pStart + 1; 219cdf0e10cSrcweir } 220cdf0e10cSrcweir } 221cdf0e10cSrcweir 222cdf0e10cSrcweir DBG_ASSERT( 0 <= nRes && nRes <= nLen, "lcl_BacktraceWhiteSpaces return value out of range" ); 223cdf0e10cSrcweir return nRes; 224cdf0e10cSrcweir } 225cdf0e10cSrcweir 226cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////// 227cdf0e10cSrcweir 228cdf0e10cSrcweir extern "C" void workerfunc (void * gci) 229cdf0e10cSrcweir { 230cdf0e10cSrcweir ((GrammarCheckingIterator*)gci)->DequeueAndCheck(); 231cdf0e10cSrcweir } 232cdf0e10cSrcweir 233cdf0e10cSrcweir static lang::Locale lcl_GetPrimaryLanguageOfSentence( 234cdf0e10cSrcweir uno::Reference< text::XFlatParagraph > xFlatPara, 235cdf0e10cSrcweir sal_Int32 nStartIndex ) 236cdf0e10cSrcweir { 237cdf0e10cSrcweir //get the language of the first word 238cdf0e10cSrcweir return xFlatPara->getLanguageOfText( nStartIndex, 1 ); 239cdf0e10cSrcweir } 240cdf0e10cSrcweir 241cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////// 242cdf0e10cSrcweir /* 243cdf0e10cSrcweir class MyThread : punlic osl::Thread 244cdf0e10cSrcweir { 245cdf0e10cSrcweir void run () 246cdf0e10cSrcweir { 247cdf0e10cSrcweir DequeueAndCheck(); 248cdf0e10cSrcweir } 249cdf0e10cSrcweir 250cdf0e10cSrcweir void own_terminate () 251cdf0e10cSrcweir { 252cdf0e10cSrcweir m_bEnd = true; 253cdf0e10cSrcweir wait (3000); 254cdf0e10cSrcweir terminate (); 255cdf0e10cSrcweir } 256cdf0e10cSrcweir } 257cdf0e10cSrcweir 258cdf0e10cSrcweir MyThread m_aQueue; 259cdf0e10cSrcweir 260cdf0e10cSrcweir vois startGrammarChecking() 261cdf0e10cSrcweir { 262cdf0e10cSrcweir if (!m_aQueue.isRunning ()) 263cdf0e10cSrcweir m_aQueue.create (); 264cdf0e10cSrcweir } 265cdf0e10cSrcweir 266cdf0e10cSrcweir void stopGrammarChecking () 267cdf0e10cSrcweir { 268cdf0e10cSrcweir if (m_aQueue.isRunning ()) 269cdf0e10cSrcweir m_aQueue.own_terminate (); 270cdf0e10cSrcweir } 271cdf0e10cSrcweir */ 272cdf0e10cSrcweir 273cdf0e10cSrcweir GrammarCheckingIterator::GrammarCheckingIterator( const uno::Reference< lang::XMultiServiceFactory > & rxMgr ) : 274cdf0e10cSrcweir m_xMSF( rxMgr ), 275cdf0e10cSrcweir m_bEnd( sal_False ), 276cdf0e10cSrcweir m_aCurCheckedDocId(), 277cdf0e10cSrcweir m_bGCServicesChecked( sal_False ), 278cdf0e10cSrcweir m_nDocIdCounter( 0 ), 279cdf0e10cSrcweir m_nLastEndOfSentencePos( -1 ), 280cdf0e10cSrcweir m_aEventListeners( MyMutex::get() ), 281cdf0e10cSrcweir m_aNotifyListeners( MyMutex::get() ) 282cdf0e10cSrcweir { 283cdf0e10cSrcweir osl_createThread( workerfunc, this ); 284cdf0e10cSrcweir } 285cdf0e10cSrcweir 286cdf0e10cSrcweir 287cdf0e10cSrcweir GrammarCheckingIterator::~GrammarCheckingIterator() 288cdf0e10cSrcweir { 289cdf0e10cSrcweir ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() ); 290cdf0e10cSrcweir } 291cdf0e10cSrcweir 292cdf0e10cSrcweir 293cdf0e10cSrcweir sal_Int32 GrammarCheckingIterator::NextDocId() 294cdf0e10cSrcweir { 295cdf0e10cSrcweir ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() ); 296cdf0e10cSrcweir m_nDocIdCounter += 1; 297cdf0e10cSrcweir return m_nDocIdCounter; 298cdf0e10cSrcweir } 299cdf0e10cSrcweir 300cdf0e10cSrcweir 301cdf0e10cSrcweir OUString GrammarCheckingIterator::GetOrCreateDocId( 302cdf0e10cSrcweir const uno::Reference< lang::XComponent > &xComponent ) 303cdf0e10cSrcweir { 304cdf0e10cSrcweir // internal method; will always be called with locked mutex 305cdf0e10cSrcweir 306cdf0e10cSrcweir OUString aRes; 307cdf0e10cSrcweir if (xComponent.is()) 308cdf0e10cSrcweir { 309cdf0e10cSrcweir if (m_aDocIdMap.find( xComponent.get() ) != m_aDocIdMap.end()) 310cdf0e10cSrcweir { 311cdf0e10cSrcweir // return already existing entry 312cdf0e10cSrcweir aRes = m_aDocIdMap[ xComponent.get() ]; 313cdf0e10cSrcweir } 314cdf0e10cSrcweir else // add new entry 315cdf0e10cSrcweir { 316cdf0e10cSrcweir sal_Int32 nRes = NextDocId(); 317cdf0e10cSrcweir aRes = OUString::valueOf( nRes ); 318cdf0e10cSrcweir m_aDocIdMap[ xComponent.get() ] = aRes; 319cdf0e10cSrcweir xComponent->addEventListener( this ); 320cdf0e10cSrcweir } 321cdf0e10cSrcweir } 322cdf0e10cSrcweir return aRes; 323cdf0e10cSrcweir } 324cdf0e10cSrcweir 325cdf0e10cSrcweir 326cdf0e10cSrcweir void GrammarCheckingIterator::AddEntry( 327cdf0e10cSrcweir uno::WeakReference< text::XFlatParagraphIterator > xFlatParaIterator, 328cdf0e10cSrcweir uno::WeakReference< text::XFlatParagraph > xFlatPara, 329cdf0e10cSrcweir const OUString & rDocId, 330cdf0e10cSrcweir sal_Int32 nStartIndex, 331cdf0e10cSrcweir sal_Bool bAutomatic ) 332cdf0e10cSrcweir { 333cdf0e10cSrcweir // we may not need/have a xFlatParaIterator (e.g. if checkGrammarAtPos was called) 334cdf0e10cSrcweir // but we always need a xFlatPara... 335cdf0e10cSrcweir uno::Reference< text::XFlatParagraph > xPara( xFlatPara ); 336cdf0e10cSrcweir if (xPara.is()) 337cdf0e10cSrcweir { 338cdf0e10cSrcweir FPEntry aNewFPEntry; 339cdf0e10cSrcweir aNewFPEntry.m_xParaIterator = xFlatParaIterator; 340cdf0e10cSrcweir aNewFPEntry.m_xPara = xFlatPara; 341cdf0e10cSrcweir aNewFPEntry.m_aDocId = rDocId; 342cdf0e10cSrcweir aNewFPEntry.m_nStartIndex = nStartIndex; 343cdf0e10cSrcweir aNewFPEntry.m_bAutomatic = bAutomatic; 344cdf0e10cSrcweir 345cdf0e10cSrcweir // add new entry to the end of this queue 346cdf0e10cSrcweir ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() ); 347cdf0e10cSrcweir m_aFPEntriesQueue.push_back( aNewFPEntry ); 348cdf0e10cSrcweir 349cdf0e10cSrcweir // wake up the thread in order to do grammar checking 350cdf0e10cSrcweir m_aWakeUpThread.set(); 351cdf0e10cSrcweir } 352cdf0e10cSrcweir } 353cdf0e10cSrcweir 354cdf0e10cSrcweir 355cdf0e10cSrcweir void GrammarCheckingIterator::ProcessResult( 356cdf0e10cSrcweir const linguistic2::ProofreadingResult &rRes, 357cdf0e10cSrcweir const uno::Reference< text::XFlatParagraphIterator > &rxFlatParagraphIterator, 358cdf0e10cSrcweir bool bIsAutomaticChecking ) 359cdf0e10cSrcweir { 360cdf0e10cSrcweir DBG_ASSERT( rRes.xFlatParagraph.is(), "xFlatParagraph is missing" ); 361cdf0e10cSrcweir //no guard necessary as no members are used 362cdf0e10cSrcweir sal_Bool bContinueWithNextPara = sal_False; 363cdf0e10cSrcweir if (!rRes.xFlatParagraph.is() || rRes.xFlatParagraph->isModified()) 364cdf0e10cSrcweir { 365cdf0e10cSrcweir // if paragraph was modified/deleted meanwhile continue with the next one... 366cdf0e10cSrcweir bContinueWithNextPara = sal_True; 367cdf0e10cSrcweir } 368cdf0e10cSrcweir else // paragraph is still unchanged... 369cdf0e10cSrcweir { 370cdf0e10cSrcweir // 371cdf0e10cSrcweir // mark found errors... 372cdf0e10cSrcweir // 373cdf0e10cSrcweir 374cdf0e10cSrcweir sal_Int32 nTextLen = rRes.aText.getLength(); 375cdf0e10cSrcweir bool bBoundariesOk = 0 <= rRes.nStartOfSentencePosition && rRes.nStartOfSentencePosition <= nTextLen && 376cdf0e10cSrcweir 0 <= rRes.nBehindEndOfSentencePosition && rRes.nBehindEndOfSentencePosition <= nTextLen && 377cdf0e10cSrcweir 0 <= rRes.nStartOfNextSentencePosition && rRes.nStartOfNextSentencePosition <= nTextLen && 378cdf0e10cSrcweir rRes.nStartOfSentencePosition <= rRes.nBehindEndOfSentencePosition && 379cdf0e10cSrcweir rRes.nBehindEndOfSentencePosition <= rRes.nStartOfNextSentencePosition; 380cdf0e10cSrcweir (void) bBoundariesOk; 381cdf0e10cSrcweir DBG_ASSERT( bBoundariesOk, "inconsistent sentence boundaries" ); 382cdf0e10cSrcweir uno::Sequence< linguistic2::SingleProofreadingError > aErrors = rRes.aErrors; 383cdf0e10cSrcweir 384cdf0e10cSrcweir uno::Reference< text::XMultiTextMarkup > xMulti( rRes.xFlatParagraph, uno::UNO_QUERY ); 385cdf0e10cSrcweir if (xMulti.is()) // use new API for markups 386cdf0e10cSrcweir { 387cdf0e10cSrcweir try 388cdf0e10cSrcweir { 389cdf0e10cSrcweir // length = number of found errors + 1 sentence markup 390cdf0e10cSrcweir sal_Int32 nErrors = rRes.aErrors.getLength(); 391cdf0e10cSrcweir uno::Sequence< text::TextMarkupDescriptor > aDescriptors( nErrors + 1 ); 392cdf0e10cSrcweir text::TextMarkupDescriptor * pDescriptors = aDescriptors.getArray(); 393cdf0e10cSrcweir 394cdf0e10cSrcweir // at pos 0 .. nErrors-1 -> all grammar errors 395cdf0e10cSrcweir for (sal_Int32 i = 0; i < nErrors; ++i) 396cdf0e10cSrcweir { 397cdf0e10cSrcweir const linguistic2::SingleProofreadingError &rError = rRes.aErrors[i]; 398cdf0e10cSrcweir text::TextMarkupDescriptor &rDesc = aDescriptors[i]; 399cdf0e10cSrcweir 400cdf0e10cSrcweir rDesc.nType = rError.nErrorType; 401cdf0e10cSrcweir rDesc.nOffset = rError.nErrorStart; 402cdf0e10cSrcweir rDesc.nLength = rError.nErrorLength; 403cdf0e10cSrcweir 404cdf0e10cSrcweir // the proofreader may return SPELLING but right now our core 405cdf0e10cSrcweir // does only handle PROOFREADING if the result is from the proofreader... 406cdf0e10cSrcweir // (later on we may wish to color spelling errors found by the proofreader 407cdf0e10cSrcweir // differently for example. But no special handling right now. 408cdf0e10cSrcweir if (rDesc.nType == text::TextMarkupType::SPELLCHECK) 409cdf0e10cSrcweir rDesc.nType = text::TextMarkupType::PROOFREADING; 410cdf0e10cSrcweir } 411cdf0e10cSrcweir 412cdf0e10cSrcweir // at pos nErrors -> sentence markup 413cdf0e10cSrcweir // nSentenceLength: includes the white-spaces following the sentence end... 414cdf0e10cSrcweir const sal_Int32 nSentenceLength = rRes.nStartOfNextSentencePosition - rRes.nStartOfSentencePosition; 415cdf0e10cSrcweir pDescriptors[ nErrors ].nType = text::TextMarkupType::SENTENCE; 416cdf0e10cSrcweir pDescriptors[ nErrors ].nOffset = rRes.nStartOfSentencePosition; 417cdf0e10cSrcweir pDescriptors[ nErrors ].nLength = nSentenceLength; 418cdf0e10cSrcweir 419cdf0e10cSrcweir xMulti->commitMultiTextMarkup( aDescriptors ) ; 420cdf0e10cSrcweir } 421cdf0e10cSrcweir catch (lang::IllegalArgumentException &) 422cdf0e10cSrcweir { 423cdf0e10cSrcweir DBG_ERROR( "commitMultiTextMarkup: IllegalArgumentException exception caught" ); 424cdf0e10cSrcweir } 425cdf0e10cSrcweir } 426cdf0e10cSrcweir 427cdf0e10cSrcweir // other sentences left to be checked in this paragraph? 428cdf0e10cSrcweir if (rRes.nStartOfNextSentencePosition < rRes.aText.getLength()) 429cdf0e10cSrcweir { 430cdf0e10cSrcweir AddEntry( rxFlatParagraphIterator, rRes.xFlatParagraph, rRes.aDocumentIdentifier, rRes.nStartOfNextSentencePosition, bIsAutomaticChecking ); 431cdf0e10cSrcweir } 432cdf0e10cSrcweir else // current paragraph finished 433cdf0e10cSrcweir { 434cdf0e10cSrcweir // set "already checked" flag for the current flat paragraph 435cdf0e10cSrcweir if (rRes.xFlatParagraph.is()) 436cdf0e10cSrcweir rRes.xFlatParagraph->setChecked( text::TextMarkupType::PROOFREADING, true ); 437cdf0e10cSrcweir 438cdf0e10cSrcweir bContinueWithNextPara = sal_True; 439cdf0e10cSrcweir } 440cdf0e10cSrcweir } 441cdf0e10cSrcweir 442cdf0e10cSrcweir if (bContinueWithNextPara) 443cdf0e10cSrcweir { 444cdf0e10cSrcweir // we need to continue with the next paragraph 445cdf0e10cSrcweir uno::Reference< text::XFlatParagraph > xFlatParaNext; 446cdf0e10cSrcweir if (rxFlatParagraphIterator.is()) 447cdf0e10cSrcweir xFlatParaNext = rxFlatParagraphIterator->getNextPara(); 448cdf0e10cSrcweir { 449cdf0e10cSrcweir AddEntry( rxFlatParagraphIterator, xFlatParaNext, rRes.aDocumentIdentifier, 0, bIsAutomaticChecking ); 450cdf0e10cSrcweir } 451cdf0e10cSrcweir } 452cdf0e10cSrcweir } 453cdf0e10cSrcweir 454cdf0e10cSrcweir 455cdf0e10cSrcweir uno::Reference< linguistic2::XProofreader > GrammarCheckingIterator::GetGrammarChecker( 456cdf0e10cSrcweir const lang::Locale &rLocale ) 457cdf0e10cSrcweir { 458cdf0e10cSrcweir (void) rLocale; 459cdf0e10cSrcweir uno::Reference< linguistic2::XProofreader > xRes; 460cdf0e10cSrcweir 461cdf0e10cSrcweir // ---- THREAD SAFE START ---- 462cdf0e10cSrcweir ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() ); 463cdf0e10cSrcweir 464cdf0e10cSrcweir // check supported locales for each grammarchecker if not already done 465cdf0e10cSrcweir if (!m_bGCServicesChecked) 466cdf0e10cSrcweir { 467cdf0e10cSrcweir //GetAvailableGCSvcs_Impl(); 468cdf0e10cSrcweir GetConfiguredGCSvcs_Impl(); 469cdf0e10cSrcweir //GetMatchingGCSvcs_Impl(); 470cdf0e10cSrcweir m_bGCServicesChecked = sal_True; 471cdf0e10cSrcweir } 472cdf0e10cSrcweir 473cdf0e10cSrcweir const LanguageType nLang = MsLangId::convertLocaleToLanguage( rLocale ); 474cdf0e10cSrcweir GCImplNames_t::const_iterator aLangIt( m_aGCImplNamesByLang.find( nLang ) ); 475cdf0e10cSrcweir if (aLangIt != m_aGCImplNamesByLang.end()) // matching configured language found? 476cdf0e10cSrcweir { 477cdf0e10cSrcweir OUString aSvcImplName( aLangIt->second ); 478cdf0e10cSrcweir GCReferences_t::const_iterator aImplNameIt( m_aGCReferencesByService.find( aSvcImplName ) ); 479cdf0e10cSrcweir if (aImplNameIt != m_aGCReferencesByService.end()) // matching impl name found? 480cdf0e10cSrcweir { 481cdf0e10cSrcweir xRes = aImplNameIt->second; 482cdf0e10cSrcweir } 483cdf0e10cSrcweir else // the service is to be instatiated here for the first time... 484cdf0e10cSrcweir { 485cdf0e10cSrcweir try 486cdf0e10cSrcweir { 487cdf0e10cSrcweir uno::Reference< lang::XMultiServiceFactory > xMgr( 488cdf0e10cSrcweir utl::getProcessServiceFactory(), uno::UNO_QUERY_THROW ); 489cdf0e10cSrcweir uno::Reference< linguistic2::XProofreader > xGC( 490cdf0e10cSrcweir xMgr->createInstance( aSvcImplName ), uno::UNO_QUERY_THROW ); 491cdf0e10cSrcweir uno::Reference< linguistic2::XSupportedLocales > xSuppLoc( xGC, uno::UNO_QUERY_THROW ); 492cdf0e10cSrcweir 493cdf0e10cSrcweir if (xSuppLoc->hasLocale( rLocale )) 494cdf0e10cSrcweir { 495cdf0e10cSrcweir m_aGCReferencesByService[ aSvcImplName ] = xGC; 496cdf0e10cSrcweir xRes = xGC; 497cdf0e10cSrcweir 498cdf0e10cSrcweir uno::Reference< linguistic2::XLinguServiceEventBroadcaster > xBC( xGC, uno::UNO_QUERY ); 499cdf0e10cSrcweir if (xBC.is()) 500cdf0e10cSrcweir xBC->addLinguServiceEventListener( this ); 501cdf0e10cSrcweir } 502cdf0e10cSrcweir else 503cdf0e10cSrcweir { 504cdf0e10cSrcweir DBG_ASSERT( 0, "grammar checker does not support required locale" ); 505cdf0e10cSrcweir } 506cdf0e10cSrcweir } 507cdf0e10cSrcweir catch (uno::Exception &) 508cdf0e10cSrcweir { 509cdf0e10cSrcweir DBG_ASSERT( 0, "instantiating grammar checker failed" ); 510cdf0e10cSrcweir } 511cdf0e10cSrcweir } 512cdf0e10cSrcweir } 513cdf0e10cSrcweir // ---- THREAD SAFE END ---- 514cdf0e10cSrcweir 515cdf0e10cSrcweir return xRes; 516cdf0e10cSrcweir } 517cdf0e10cSrcweir 518cdf0e10cSrcweir 519cdf0e10cSrcweir void GrammarCheckingIterator::DequeueAndCheck() 520cdf0e10cSrcweir { 521cdf0e10cSrcweir uno::Sequence< sal_Int32 > aLangPortions; 522cdf0e10cSrcweir uno::Sequence< lang::Locale > aLangPortionsLocale; 523cdf0e10cSrcweir 524cdf0e10cSrcweir // ---- THREAD SAFE START ---- 525cdf0e10cSrcweir bool bEnd = false; 526cdf0e10cSrcweir { 527cdf0e10cSrcweir ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() ); 528cdf0e10cSrcweir bEnd = m_bEnd; 529cdf0e10cSrcweir } 530cdf0e10cSrcweir // ---- THREAD SAFE END ---- 531cdf0e10cSrcweir while (!bEnd) 532cdf0e10cSrcweir { 533cdf0e10cSrcweir // ---- THREAD SAFE START ---- 534cdf0e10cSrcweir bool bQueueEmpty = false; 535cdf0e10cSrcweir { 536cdf0e10cSrcweir ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() ); 537cdf0e10cSrcweir bQueueEmpty = m_aFPEntriesQueue.empty(); 538cdf0e10cSrcweir } 539cdf0e10cSrcweir // ---- THREAD SAFE END ---- 540cdf0e10cSrcweir 541cdf0e10cSrcweir if (!bQueueEmpty) 542cdf0e10cSrcweir { 543cdf0e10cSrcweir uno::Reference< text::XFlatParagraphIterator > xFPIterator; 544cdf0e10cSrcweir uno::Reference< text::XFlatParagraph > xFlatPara; 545cdf0e10cSrcweir FPEntry aFPEntryItem; 546cdf0e10cSrcweir OUString aCurDocId; 547cdf0e10cSrcweir sal_Bool bModified = sal_False; 548cdf0e10cSrcweir // ---- THREAD SAFE START ---- 549cdf0e10cSrcweir { 550cdf0e10cSrcweir ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() ); 551cdf0e10cSrcweir aFPEntryItem = m_aFPEntriesQueue.front(); 552cdf0e10cSrcweir xFPIterator = aFPEntryItem.m_xParaIterator; 553cdf0e10cSrcweir xFlatPara = aFPEntryItem.m_xPara; 554cdf0e10cSrcweir m_aCurCheckedDocId = aFPEntryItem.m_aDocId; 555cdf0e10cSrcweir aCurDocId = m_aCurCheckedDocId; 556cdf0e10cSrcweir 557cdf0e10cSrcweir m_aFPEntriesQueue.pop_front(); 558cdf0e10cSrcweir } 559cdf0e10cSrcweir // ---- THREAD SAFE END ---- 560cdf0e10cSrcweir 561cdf0e10cSrcweir if (xFlatPara.is() && xFPIterator.is()) 562cdf0e10cSrcweir { 563cdf0e10cSrcweir OUString aCurTxt( xFlatPara->getText() ); 564cdf0e10cSrcweir lang::Locale aCurLocale = lcl_GetPrimaryLanguageOfSentence( xFlatPara, aFPEntryItem.m_nStartIndex ); 565cdf0e10cSrcweir 566cdf0e10cSrcweir bModified = xFlatPara->isModified(); 567cdf0e10cSrcweir if (!bModified) 568cdf0e10cSrcweir { 569cdf0e10cSrcweir // ---- THREAD SAFE START ---- 570cdf0e10cSrcweir ::osl::ClearableGuard< ::osl::Mutex > aGuard( MyMutex::get() ); 571cdf0e10cSrcweir 572cdf0e10cSrcweir sal_Int32 nStartPos = aFPEntryItem.m_nStartIndex; 573cdf0e10cSrcweir sal_Int32 nSuggestedEnd = GetSuggestedEndOfSentence( aCurTxt, nStartPos, aCurLocale ); 574cdf0e10cSrcweir DBG_ASSERT( (nSuggestedEnd == 0 && aCurTxt.getLength() == 0) || nSuggestedEnd > nStartPos, 575cdf0e10cSrcweir "nSuggestedEndOfSentencePos calculation failed?" ); 576cdf0e10cSrcweir 577cdf0e10cSrcweir linguistic2::ProofreadingResult aRes; 578cdf0e10cSrcweir 579cdf0e10cSrcweir uno::Reference< linguistic2::XProofreader > xGC( GetGrammarChecker( aCurLocale ), uno::UNO_QUERY ); 580cdf0e10cSrcweir if (xGC.is()) 581cdf0e10cSrcweir { 582cdf0e10cSrcweir aGuard.clear(); 583cdf0e10cSrcweir uno::Sequence< beans::PropertyValue > aEmptyProps; 584cdf0e10cSrcweir aRes = xGC->doProofreading( aCurDocId, aCurTxt, aCurLocale, nStartPos, nSuggestedEnd, aEmptyProps ); 585cdf0e10cSrcweir 586cdf0e10cSrcweir //!! work-around to prevent looping if the grammar checker 587cdf0e10cSrcweir //!! failed to properly identify the sentence end 588cdf0e10cSrcweir if (aRes.nBehindEndOfSentencePosition <= nStartPos) 589cdf0e10cSrcweir { 590cdf0e10cSrcweir DBG_ASSERT( 0, "!! Grammarchecker failed to provide end of sentence !!" ); 591cdf0e10cSrcweir aRes.nBehindEndOfSentencePosition = nSuggestedEnd; 592cdf0e10cSrcweir } 593cdf0e10cSrcweir 594cdf0e10cSrcweir aRes.xFlatParagraph = xFlatPara; 595cdf0e10cSrcweir aRes.nStartOfSentencePosition = nStartPos; 596cdf0e10cSrcweir } 597cdf0e10cSrcweir else 598cdf0e10cSrcweir { 599cdf0e10cSrcweir // no grammar checker -> no error 600cdf0e10cSrcweir // but we need to provide the data below in order to continue with the next sentence 601cdf0e10cSrcweir aRes.aDocumentIdentifier = aCurDocId; 602cdf0e10cSrcweir aRes.xFlatParagraph = xFlatPara; 603cdf0e10cSrcweir aRes.aText = aCurTxt; 604cdf0e10cSrcweir aRes.aLocale = aCurLocale; 605cdf0e10cSrcweir aRes.nStartOfSentencePosition = nStartPos; 606cdf0e10cSrcweir aRes.nBehindEndOfSentencePosition = nSuggestedEnd; 607cdf0e10cSrcweir } 608cdf0e10cSrcweir aRes.nStartOfNextSentencePosition = lcl_SkipWhiteSpaces( aCurTxt, aRes.nBehindEndOfSentencePosition ); 609cdf0e10cSrcweir aRes.nBehindEndOfSentencePosition = lcl_BacktraceWhiteSpaces( aCurTxt, aRes.nStartOfNextSentencePosition ); 610cdf0e10cSrcweir 611cdf0e10cSrcweir //guard has to be cleared as ProcessResult calls out of this class 612cdf0e10cSrcweir aGuard.clear(); 613cdf0e10cSrcweir ProcessResult( aRes, xFPIterator, aFPEntryItem.m_bAutomatic ); 614cdf0e10cSrcweir // ---- THREAD SAFE END ---- 615cdf0e10cSrcweir } 616cdf0e10cSrcweir else 617cdf0e10cSrcweir { 618cdf0e10cSrcweir // the paragraph changed meanwhile... (and maybe is still edited) 619cdf0e10cSrcweir // thus we simply continue to ask for the next to be checked. 620cdf0e10cSrcweir uno::Reference< text::XFlatParagraph > xFlatParaNext( xFPIterator->getNextPara() ); 621cdf0e10cSrcweir AddEntry( xFPIterator, xFlatParaNext, aCurDocId, 0, aFPEntryItem.m_bAutomatic ); 622cdf0e10cSrcweir } 623cdf0e10cSrcweir } 624cdf0e10cSrcweir 625cdf0e10cSrcweir // ---- THREAD SAFE START ---- 626cdf0e10cSrcweir { 627cdf0e10cSrcweir ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() ); 628cdf0e10cSrcweir m_aCurCheckedDocId = OUString(); 629cdf0e10cSrcweir } 630cdf0e10cSrcweir // ---- THREAD SAFE END ---- 631cdf0e10cSrcweir } 632cdf0e10cSrcweir else 633cdf0e10cSrcweir { 634cdf0e10cSrcweir // ---- THREAD SAFE START ---- 635cdf0e10cSrcweir { 636cdf0e10cSrcweir ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() ); 637cdf0e10cSrcweir // Check queue state again 638cdf0e10cSrcweir if (m_aFPEntriesQueue.empty()) 639cdf0e10cSrcweir m_aWakeUpThread.reset(); 640cdf0e10cSrcweir } 641cdf0e10cSrcweir // ---- THREAD SAFE END ---- 642cdf0e10cSrcweir 643cdf0e10cSrcweir //if the queue is empty 644cdf0e10cSrcweir // IMPORTANT: Don't call condition.wait() with locked 645cdf0e10cSrcweir // mutex. Otherwise you would keep out other threads 646cdf0e10cSrcweir // to add entries to the queue! A condition is thread- 647cdf0e10cSrcweir // safe implemented. 648cdf0e10cSrcweir m_aWakeUpThread.wait(); 649cdf0e10cSrcweir } 650cdf0e10cSrcweir 651cdf0e10cSrcweir // ---- THREAD SAFE START ---- 652cdf0e10cSrcweir { 653cdf0e10cSrcweir ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() ); 654cdf0e10cSrcweir bEnd = m_bEnd; 655cdf0e10cSrcweir } 656cdf0e10cSrcweir // ---- THREAD SAFE END ---- 657cdf0e10cSrcweir } 658cdf0e10cSrcweir 659cdf0e10cSrcweir //!! This one must be the very last statement to call in this function !! 660cdf0e10cSrcweir m_aRequestEndThread.set(); 661cdf0e10cSrcweir } 662cdf0e10cSrcweir 663cdf0e10cSrcweir 664cdf0e10cSrcweir void SAL_CALL GrammarCheckingIterator::startProofreading( 665cdf0e10cSrcweir const uno::Reference< ::uno::XInterface > & xDoc, 666cdf0e10cSrcweir const uno::Reference< text::XFlatParagraphIteratorProvider > & xIteratorProvider ) 667cdf0e10cSrcweir throw (uno::RuntimeException, lang::IllegalArgumentException) 668cdf0e10cSrcweir { 669cdf0e10cSrcweir // get paragraph to start checking with 670cdf0e10cSrcweir const bool bAutomatic = true; 671cdf0e10cSrcweir uno::Reference<text::XFlatParagraphIterator> xFPIterator = xIteratorProvider->getFlatParagraphIterator( 672cdf0e10cSrcweir text::TextMarkupType::PROOFREADING, bAutomatic ); 673cdf0e10cSrcweir uno::Reference< text::XFlatParagraph > xPara( xFPIterator.is()? xFPIterator->getFirstPara() : NULL ); 674cdf0e10cSrcweir uno::Reference< lang::XComponent > xComponent( xDoc, uno::UNO_QUERY ); 675cdf0e10cSrcweir 676cdf0e10cSrcweir // ---- THREAD SAFE START ---- 677cdf0e10cSrcweir ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() ); 678cdf0e10cSrcweir if (xPara.is() && xComponent.is()) 679cdf0e10cSrcweir { 680cdf0e10cSrcweir OUString aDocId = GetOrCreateDocId( xComponent ); 681cdf0e10cSrcweir 682cdf0e10cSrcweir // create new entry and add it to queue 683cdf0e10cSrcweir AddEntry( xFPIterator, xPara, aDocId, 0, bAutomatic ); 684cdf0e10cSrcweir } 685cdf0e10cSrcweir // ---- THREAD SAFE END ---- 686cdf0e10cSrcweir } 687cdf0e10cSrcweir 688cdf0e10cSrcweir 689cdf0e10cSrcweir linguistic2::ProofreadingResult SAL_CALL GrammarCheckingIterator::checkSentenceAtPosition( 690cdf0e10cSrcweir const uno::Reference< uno::XInterface >& xDoc, 691cdf0e10cSrcweir const uno::Reference< text::XFlatParagraph >& xFlatPara, 692cdf0e10cSrcweir const OUString& rText, 693cdf0e10cSrcweir const lang::Locale& rLocale, 694cdf0e10cSrcweir sal_Int32 nStartOfSentencePos, 695cdf0e10cSrcweir sal_Int32 nSuggestedEndOfSentencePos, 696cdf0e10cSrcweir sal_Int32 nErrorPosInPara ) 697cdf0e10cSrcweir throw (lang::IllegalArgumentException, uno::RuntimeException) 698cdf0e10cSrcweir { 699cdf0e10cSrcweir (void) rLocale; 700cdf0e10cSrcweir 701cdf0e10cSrcweir // for the context menu... 702cdf0e10cSrcweir 703cdf0e10cSrcweir linguistic2::ProofreadingResult aRes; 704cdf0e10cSrcweir 705cdf0e10cSrcweir uno::Reference< lang::XComponent > xComponent( xDoc, uno::UNO_QUERY ); 706cdf0e10cSrcweir if (xFlatPara.is() && xComponent.is() && 707cdf0e10cSrcweir ( nErrorPosInPara < 0 || nErrorPosInPara < rText.getLength())) 708cdf0e10cSrcweir { 709cdf0e10cSrcweir // iterate through paragraph until we find the sentence we are interested in 710cdf0e10cSrcweir linguistic2::ProofreadingResult aTmpRes; 711cdf0e10cSrcweir sal_Int32 nStartPos = nStartOfSentencePos >= 0 ? nStartOfSentencePos : 0; 712cdf0e10cSrcweir 713cdf0e10cSrcweir bool bFound = false; 714cdf0e10cSrcweir do 715cdf0e10cSrcweir { 716cdf0e10cSrcweir lang::Locale aCurLocale = lcl_GetPrimaryLanguageOfSentence( xFlatPara, nStartPos ); 717cdf0e10cSrcweir sal_Int32 nOldStartOfSentencePos = nStartPos; 718cdf0e10cSrcweir uno::Reference< linguistic2::XProofreader > xGC; 719cdf0e10cSrcweir OUString aDocId; 720cdf0e10cSrcweir 721cdf0e10cSrcweir // ---- THREAD SAFE START ---- 722cdf0e10cSrcweir { 723cdf0e10cSrcweir ::osl::ClearableGuard< ::osl::Mutex > aGuard( MyMutex::get() ); 724cdf0e10cSrcweir aDocId = GetOrCreateDocId( xComponent ); 725cdf0e10cSrcweir nSuggestedEndOfSentencePos = GetSuggestedEndOfSentence( rText, nStartPos, aCurLocale ); 726cdf0e10cSrcweir DBG_ASSERT( nSuggestedEndOfSentencePos > nStartPos, "nSuggestedEndOfSentencePos calculation failed?" ); 727cdf0e10cSrcweir 728cdf0e10cSrcweir xGC = GetGrammarChecker( aCurLocale ); 729cdf0e10cSrcweir } 730cdf0e10cSrcweir // ---- THREAD SAFE START ---- 731cdf0e10cSrcweir sal_Int32 nEndPos = -1; 732cdf0e10cSrcweir if (xGC.is()) 733cdf0e10cSrcweir { 734cdf0e10cSrcweir uno::Sequence< beans::PropertyValue > aEmptyProps; 735cdf0e10cSrcweir aTmpRes = xGC->doProofreading( aDocId, rText, aCurLocale, nStartPos, nSuggestedEndOfSentencePos, aEmptyProps ); 736cdf0e10cSrcweir 737cdf0e10cSrcweir //!! work-around to prevent looping if the grammar checker 738cdf0e10cSrcweir //!! failed to properly identify the sentence end 739cdf0e10cSrcweir if (aTmpRes.nBehindEndOfSentencePosition <= nStartPos) 740cdf0e10cSrcweir { 741cdf0e10cSrcweir DBG_ASSERT( 0, "!! Grammarchecker failed to provide end of sentence !!" ); 742cdf0e10cSrcweir aTmpRes.nBehindEndOfSentencePosition = nSuggestedEndOfSentencePos; 743cdf0e10cSrcweir } 744cdf0e10cSrcweir 745cdf0e10cSrcweir aTmpRes.xFlatParagraph = xFlatPara; 746cdf0e10cSrcweir aTmpRes.nStartOfSentencePosition = nStartPos; 747cdf0e10cSrcweir nEndPos = aTmpRes.nBehindEndOfSentencePosition; 748cdf0e10cSrcweir 749cdf0e10cSrcweir if ((nErrorPosInPara< 0 || nStartPos <= nErrorPosInPara) && nErrorPosInPara < nEndPos) 750cdf0e10cSrcweir bFound = true; 751cdf0e10cSrcweir } 752cdf0e10cSrcweir if (nEndPos == -1) // no result from grammar checker 753cdf0e10cSrcweir nEndPos = nSuggestedEndOfSentencePos; 754cdf0e10cSrcweir nStartPos = lcl_SkipWhiteSpaces( rText, nEndPos ); 755cdf0e10cSrcweir aTmpRes.nBehindEndOfSentencePosition = nEndPos; 756cdf0e10cSrcweir aTmpRes.nStartOfNextSentencePosition = nStartPos; 757cdf0e10cSrcweir aTmpRes.nBehindEndOfSentencePosition = lcl_BacktraceWhiteSpaces( rText, aTmpRes.nStartOfNextSentencePosition ); 758cdf0e10cSrcweir 759cdf0e10cSrcweir // prevent endless loop by forcefully advancing if needs be... 760cdf0e10cSrcweir if (nStartPos <= nOldStartOfSentencePos) 761cdf0e10cSrcweir { 762cdf0e10cSrcweir DBG_ASSERT( 0, "end-of-sentence detection failed?" ); 763cdf0e10cSrcweir nStartPos = nOldStartOfSentencePos + 1; 764cdf0e10cSrcweir } 765cdf0e10cSrcweir } 766cdf0e10cSrcweir while (!bFound && nStartPos < rText.getLength()); 767cdf0e10cSrcweir 768cdf0e10cSrcweir if (bFound && !xFlatPara->isModified()) 769cdf0e10cSrcweir aRes = aTmpRes; 770cdf0e10cSrcweir } 771cdf0e10cSrcweir 772cdf0e10cSrcweir return aRes; 773cdf0e10cSrcweir } 774cdf0e10cSrcweir 775cdf0e10cSrcweir 776cdf0e10cSrcweir sal_Int32 GrammarCheckingIterator::GetSuggestedEndOfSentence( 777cdf0e10cSrcweir const OUString &rText, 778cdf0e10cSrcweir sal_Int32 nSentenceStartPos, 779cdf0e10cSrcweir const lang::Locale &rLocale ) 780cdf0e10cSrcweir { 781cdf0e10cSrcweir // internal method; will always be called with locked mutex 782cdf0e10cSrcweir 783cdf0e10cSrcweir uno::Reference< i18n::XBreakIterator > xBreakIterator; 784cdf0e10cSrcweir if (!m_xBreakIterator.is()) 785cdf0e10cSrcweir { 786cdf0e10cSrcweir uno::Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory(); 787cdf0e10cSrcweir if ( xMSF.is() ) 788cdf0e10cSrcweir xBreakIterator = uno::Reference < i18n::XBreakIterator >( xMSF->createInstance( 789cdf0e10cSrcweir ::rtl::OUString::createFromAscii("com.sun.star.i18n.BreakIterator") ), uno::UNO_QUERY ); 790cdf0e10cSrcweir } 791cdf0e10cSrcweir sal_Int32 nTextLen = rText.getLength(); 792cdf0e10cSrcweir sal_Int32 nEndPosition = nTextLen; 793cdf0e10cSrcweir if (m_xBreakIterator.is()) 794cdf0e10cSrcweir { 795cdf0e10cSrcweir sal_Int32 nTmpStartPos = nSentenceStartPos; 796cdf0e10cSrcweir do 797cdf0e10cSrcweir { 798cdf0e10cSrcweir nEndPosition = nTextLen; 799cdf0e10cSrcweir if (nTmpStartPos < nTextLen) 800cdf0e10cSrcweir nEndPosition = m_xBreakIterator->endOfSentence( rText, nTmpStartPos, rLocale ); 801cdf0e10cSrcweir if (nEndPosition < 0) 802cdf0e10cSrcweir nEndPosition = nTextLen; 803cdf0e10cSrcweir 804cdf0e10cSrcweir ++nTmpStartPos; 805cdf0e10cSrcweir } 806cdf0e10cSrcweir while (nEndPosition <= nSentenceStartPos && nEndPosition < nTextLen); 807cdf0e10cSrcweir if (nEndPosition > nTextLen) 808cdf0e10cSrcweir nEndPosition = nTextLen; 809cdf0e10cSrcweir } 810cdf0e10cSrcweir return nEndPosition; 811cdf0e10cSrcweir } 812cdf0e10cSrcweir 813cdf0e10cSrcweir 814cdf0e10cSrcweir void SAL_CALL GrammarCheckingIterator::resetIgnoreRules( ) 815cdf0e10cSrcweir throw (uno::RuntimeException) 816cdf0e10cSrcweir { 817cdf0e10cSrcweir GCReferences_t::iterator aIt( m_aGCReferencesByService.begin() ); 818cdf0e10cSrcweir while (aIt != m_aGCReferencesByService.end()) 819cdf0e10cSrcweir { 820cdf0e10cSrcweir uno::Reference< linguistic2::XProofreader > xGC( aIt->second ); 821cdf0e10cSrcweir if (xGC.is()) 822cdf0e10cSrcweir xGC->resetIgnoreRules(); 823cdf0e10cSrcweir ++aIt; 824cdf0e10cSrcweir } 825cdf0e10cSrcweir } 826cdf0e10cSrcweir 827cdf0e10cSrcweir 828cdf0e10cSrcweir sal_Bool SAL_CALL GrammarCheckingIterator::isProofreading( 829cdf0e10cSrcweir const uno::Reference< uno::XInterface >& xDoc ) 830cdf0e10cSrcweir throw (uno::RuntimeException) 831cdf0e10cSrcweir { 832cdf0e10cSrcweir // ---- THREAD SAFE START ---- 833cdf0e10cSrcweir ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() ); 834cdf0e10cSrcweir 835cdf0e10cSrcweir sal_Bool bRes = sal_False; 836cdf0e10cSrcweir 837cdf0e10cSrcweir uno::Reference< lang::XComponent > xComponent( xDoc, uno::UNO_QUERY ); 838cdf0e10cSrcweir if (xComponent.is()) 839cdf0e10cSrcweir { 840cdf0e10cSrcweir // if the component was already used in one of the two calls to check text 841cdf0e10cSrcweir // i.e. in startGrammarChecking or checkGrammarAtPos it will be found in the 842cdf0e10cSrcweir // m_aDocIdMap unless the document already disposed. 843cdf0e10cSrcweir // If it is not found then it is not yet being checked (or requested to being checked) 844cdf0e10cSrcweir const DocMap_t::const_iterator aIt( m_aDocIdMap.find( xComponent.get() ) ); 845cdf0e10cSrcweir if (aIt != m_aDocIdMap.end()) 846cdf0e10cSrcweir { 847cdf0e10cSrcweir // check in document is checked automatically in the background... 848cdf0e10cSrcweir OUString aDocId = aIt->second; 849cdf0e10cSrcweir if (m_aCurCheckedDocId.getLength() > 0 && m_aCurCheckedDocId == aDocId) 850cdf0e10cSrcweir { 851cdf0e10cSrcweir // an entry for that document was dequed and is currently being checked. 852cdf0e10cSrcweir bRes = sal_True; 853cdf0e10cSrcweir } 854cdf0e10cSrcweir else 855cdf0e10cSrcweir { 856cdf0e10cSrcweir // we need to check if there is an entry for that document in the queue... 857cdf0e10cSrcweir // That is the document is going to be checked sooner or later. 858cdf0e10cSrcweir 859cdf0e10cSrcweir sal_Int32 nSize = m_aFPEntriesQueue.size(); 860cdf0e10cSrcweir for (sal_Int32 i = 0; i < nSize && !bRes; ++i) 861cdf0e10cSrcweir { 862cdf0e10cSrcweir if (aDocId == m_aFPEntriesQueue[i].m_aDocId) 863cdf0e10cSrcweir bRes = sal_True; 864cdf0e10cSrcweir } 865cdf0e10cSrcweir } 866cdf0e10cSrcweir } 867cdf0e10cSrcweir } 868cdf0e10cSrcweir // ---- THREAD SAFE END ---- 869cdf0e10cSrcweir 870cdf0e10cSrcweir return bRes; 871cdf0e10cSrcweir } 872cdf0e10cSrcweir 873cdf0e10cSrcweir 874cdf0e10cSrcweir void SAL_CALL GrammarCheckingIterator::processLinguServiceEvent( 875cdf0e10cSrcweir const linguistic2::LinguServiceEvent& rLngSvcEvent ) 876cdf0e10cSrcweir throw (uno::RuntimeException) 877cdf0e10cSrcweir { 878cdf0e10cSrcweir if (rLngSvcEvent.nEvent == linguistic2::LinguServiceEventFlags::PROOFREAD_AGAIN) 879cdf0e10cSrcweir { 880cdf0e10cSrcweir try 881cdf0e10cSrcweir { 882cdf0e10cSrcweir uno::Reference< uno::XInterface > xThis( dynamic_cast< XLinguServiceEventBroadcaster * >(this) ); 883cdf0e10cSrcweir linguistic2::LinguServiceEvent aEvent( xThis, linguistic2::LinguServiceEventFlags::PROOFREAD_AGAIN ); 884cdf0e10cSrcweir m_aNotifyListeners.notifyEach( 885cdf0e10cSrcweir &linguistic2::XLinguServiceEventListener::processLinguServiceEvent, 886cdf0e10cSrcweir aEvent); 887cdf0e10cSrcweir } 888cdf0e10cSrcweir catch (uno::RuntimeException &) 889cdf0e10cSrcweir { 890cdf0e10cSrcweir throw; 891cdf0e10cSrcweir } 892cdf0e10cSrcweir catch (::uno::Exception &rE) 893cdf0e10cSrcweir { 894cdf0e10cSrcweir (void) rE; 895cdf0e10cSrcweir // ignore 896cdf0e10cSrcweir DBG_WARNING1("processLinguServiceEvent: exception:\n%s", 897cdf0e10cSrcweir OUStringToOString(rE.Message, RTL_TEXTENCODING_UTF8).getStr()); 898cdf0e10cSrcweir } 899cdf0e10cSrcweir } 900cdf0e10cSrcweir } 901cdf0e10cSrcweir 902cdf0e10cSrcweir 903cdf0e10cSrcweir sal_Bool SAL_CALL GrammarCheckingIterator::addLinguServiceEventListener( 904cdf0e10cSrcweir const uno::Reference< linguistic2::XLinguServiceEventListener >& xListener ) 905cdf0e10cSrcweir throw (uno::RuntimeException) 906cdf0e10cSrcweir { 907cdf0e10cSrcweir if (xListener.is()) 908cdf0e10cSrcweir { 909cdf0e10cSrcweir // ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() ); 910cdf0e10cSrcweir m_aNotifyListeners.addInterface( xListener ); 911cdf0e10cSrcweir } 912cdf0e10cSrcweir return sal_True; 913cdf0e10cSrcweir } 914cdf0e10cSrcweir 915cdf0e10cSrcweir 916cdf0e10cSrcweir sal_Bool SAL_CALL GrammarCheckingIterator::removeLinguServiceEventListener( 917cdf0e10cSrcweir const uno::Reference< linguistic2::XLinguServiceEventListener >& xListener ) 918cdf0e10cSrcweir throw (uno::RuntimeException) 919cdf0e10cSrcweir { 920cdf0e10cSrcweir if (xListener.is()) 921cdf0e10cSrcweir { 922cdf0e10cSrcweir // ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() ); 923cdf0e10cSrcweir m_aNotifyListeners.removeInterface( xListener ); 924cdf0e10cSrcweir } 925cdf0e10cSrcweir return sal_True; 926cdf0e10cSrcweir } 927cdf0e10cSrcweir 928cdf0e10cSrcweir 929cdf0e10cSrcweir void SAL_CALL GrammarCheckingIterator::dispose() 930cdf0e10cSrcweir throw (uno::RuntimeException) 931cdf0e10cSrcweir { 932cdf0e10cSrcweir lang::EventObject aEvt( (linguistic2::XProofreadingIterator *) this ); 933cdf0e10cSrcweir m_aEventListeners.disposeAndClear( aEvt ); 934cdf0e10cSrcweir 935cdf0e10cSrcweir // 936cdf0e10cSrcweir // now end the thread... 937cdf0e10cSrcweir // 938cdf0e10cSrcweir m_aRequestEndThread.reset(); 939cdf0e10cSrcweir // ---- THREAD SAFE START ---- 940cdf0e10cSrcweir { 941cdf0e10cSrcweir ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() ); 942cdf0e10cSrcweir m_bEnd = sal_True; 943cdf0e10cSrcweir } 944cdf0e10cSrcweir // ---- THREAD SAFE END ---- 945cdf0e10cSrcweir m_aWakeUpThread.set(); 946cdf0e10cSrcweir const TimeValue aTime = { 3, 0 }; // wait 3 seconds... 947cdf0e10cSrcweir m_aRequestEndThread.wait( &aTime ); 948cdf0e10cSrcweir // if the call ends because of time-out we will end anyway... 949cdf0e10cSrcweir 950cdf0e10cSrcweir 951cdf0e10cSrcweir // ---- THREAD SAFE START ---- 952cdf0e10cSrcweir { 953cdf0e10cSrcweir ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() ); 954cdf0e10cSrcweir 955cdf0e10cSrcweir // releaase all UNO references 956cdf0e10cSrcweir 957cdf0e10cSrcweir m_xMSF.clear(); 958cdf0e10cSrcweir m_xBreakIterator.clear(); 959cdf0e10cSrcweir 960cdf0e10cSrcweir // clear containers with UNO references AND have those references released 961cdf0e10cSrcweir GCReferences_t aTmpEmpty1; 962cdf0e10cSrcweir DocMap_t aTmpEmpty2; 963cdf0e10cSrcweir FPQueue_t aTmpEmpty3; 964cdf0e10cSrcweir m_aGCReferencesByService.swap( aTmpEmpty1 ); 965cdf0e10cSrcweir m_aDocIdMap.swap( aTmpEmpty2 ); 966cdf0e10cSrcweir m_aFPEntriesQueue.swap( aTmpEmpty3 ); 967cdf0e10cSrcweir } 968cdf0e10cSrcweir // ---- THREAD SAFE END ---- 969cdf0e10cSrcweir } 970cdf0e10cSrcweir 971cdf0e10cSrcweir 972cdf0e10cSrcweir void SAL_CALL GrammarCheckingIterator::addEventListener( 973cdf0e10cSrcweir const uno::Reference< lang::XEventListener >& xListener ) 974cdf0e10cSrcweir throw (uno::RuntimeException) 975cdf0e10cSrcweir { 976cdf0e10cSrcweir if (xListener.is()) 977cdf0e10cSrcweir { 978cdf0e10cSrcweir // ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() ); 979cdf0e10cSrcweir m_aEventListeners.addInterface( xListener ); 980cdf0e10cSrcweir } 981cdf0e10cSrcweir } 982cdf0e10cSrcweir 983cdf0e10cSrcweir 984cdf0e10cSrcweir void SAL_CALL GrammarCheckingIterator::removeEventListener( 985cdf0e10cSrcweir const uno::Reference< lang::XEventListener >& xListener ) 986cdf0e10cSrcweir throw (uno::RuntimeException) 987cdf0e10cSrcweir { 988cdf0e10cSrcweir if (xListener.is()) 989cdf0e10cSrcweir { 990cdf0e10cSrcweir // ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() ); 991cdf0e10cSrcweir m_aEventListeners.removeInterface( xListener ); 992cdf0e10cSrcweir } 993cdf0e10cSrcweir } 994cdf0e10cSrcweir 995cdf0e10cSrcweir 996cdf0e10cSrcweir void SAL_CALL GrammarCheckingIterator::disposing( const lang::EventObject &rSource ) 997cdf0e10cSrcweir throw (uno::RuntimeException) 998cdf0e10cSrcweir { 999cdf0e10cSrcweir // if the component (document) is disposing release all references 1000cdf0e10cSrcweir //!! There is no need to remove entries from the queue that are from this document 1001cdf0e10cSrcweir //!! since the respectives xFlatParagraphs should become invalid (isModified() == true) 1002cdf0e10cSrcweir //!! and the call to xFlatParagraphIterator->getNextPara() will result in an empty reference. 1003cdf0e10cSrcweir //!! And if an entry is currently checked by a grammar checker upon return the results 1004cdf0e10cSrcweir //!! should be ignored. 1005cdf0e10cSrcweir //!! Also GetOrCreateDocId will not use that very same Id again... 1006cdf0e10cSrcweir //!! All of the above resulting in that we only have to get rid of the implementation pointer here. 1007cdf0e10cSrcweir uno::Reference< lang::XComponent > xDoc( rSource.Source, uno::UNO_QUERY ); 1008cdf0e10cSrcweir if (xDoc.is()) 1009cdf0e10cSrcweir { 1010cdf0e10cSrcweir // ---- THREAD SAFE START ---- 1011cdf0e10cSrcweir ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() ); 1012cdf0e10cSrcweir m_aDocIdMap.erase( xDoc.get() ); 1013cdf0e10cSrcweir // ---- THREAD SAFE END ---- 1014cdf0e10cSrcweir } 1015cdf0e10cSrcweir } 1016cdf0e10cSrcweir 1017cdf0e10cSrcweir 1018cdf0e10cSrcweir uno::Reference< util::XChangesBatch > GrammarCheckingIterator::GetUpdateAccess() const 1019cdf0e10cSrcweir { 1020cdf0e10cSrcweir if (!m_xUpdateAccess.is()) 1021cdf0e10cSrcweir { 1022cdf0e10cSrcweir try 1023cdf0e10cSrcweir { 1024cdf0e10cSrcweir // get configuration provider 1025cdf0e10cSrcweir uno::Reference< lang::XMultiServiceFactory > xConfigurationProvider; 1026cdf0e10cSrcweir uno::Reference< lang::XMultiServiceFactory > xMgr = utl::getProcessServiceFactory(); 1027cdf0e10cSrcweir if (xMgr.is()) 1028cdf0e10cSrcweir { 1029cdf0e10cSrcweir xConfigurationProvider = uno::Reference< lang::XMultiServiceFactory > ( 1030cdf0e10cSrcweir xMgr->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( 1031cdf0e10cSrcweir "com.sun.star.configuration.ConfigurationProvider" ) ) ), 1032cdf0e10cSrcweir uno::UNO_QUERY_THROW ) ; 1033cdf0e10cSrcweir } 1034cdf0e10cSrcweir 1035cdf0e10cSrcweir // get configuration update access 1036cdf0e10cSrcweir beans::PropertyValue aValue; 1037cdf0e10cSrcweir aValue.Name = A2OU( "nodepath" ); 1038cdf0e10cSrcweir aValue.Value = uno::makeAny( A2OU("org.openoffice.Office.Linguistic/ServiceManager") ); 1039cdf0e10cSrcweir uno::Sequence< uno::Any > aProps(1); 1040cdf0e10cSrcweir aProps[0] <<= aValue; 1041cdf0e10cSrcweir m_xUpdateAccess = uno::Reference< util::XChangesBatch >( 1042cdf0e10cSrcweir xConfigurationProvider->createInstanceWithArguments( 1043cdf0e10cSrcweir A2OU( "com.sun.star.configuration.ConfigurationUpdateAccess" ), aProps ), 1044cdf0e10cSrcweir uno::UNO_QUERY_THROW ); 1045cdf0e10cSrcweir } 1046cdf0e10cSrcweir catch (uno::Exception &) 1047cdf0e10cSrcweir { 1048cdf0e10cSrcweir } 1049cdf0e10cSrcweir } 1050cdf0e10cSrcweir 1051cdf0e10cSrcweir return m_xUpdateAccess; 1052cdf0e10cSrcweir } 1053cdf0e10cSrcweir 1054cdf0e10cSrcweir 1055cdf0e10cSrcweir void GrammarCheckingIterator::GetConfiguredGCSvcs_Impl() 1056cdf0e10cSrcweir { 1057cdf0e10cSrcweir GCImplNames_t aTmpGCImplNamesByLang; 1058cdf0e10cSrcweir 1059cdf0e10cSrcweir try 1060cdf0e10cSrcweir { 1061cdf0e10cSrcweir // get node names (locale iso strings) for configured grammar checkers 1062cdf0e10cSrcweir uno::Reference< container::XNameAccess > xNA( GetUpdateAccess(), uno::UNO_QUERY_THROW ); 1063cdf0e10cSrcweir xNA.set( xNA->getByName( A2OU("GrammarCheckerList") ), uno::UNO_QUERY_THROW ); 1064cdf0e10cSrcweir const uno::Sequence< OUString > aElementNames( xNA->getElementNames() ); 1065cdf0e10cSrcweir const OUString *pElementNames = aElementNames.getConstArray(); 1066cdf0e10cSrcweir 1067cdf0e10cSrcweir sal_Int32 nLen = aElementNames.getLength(); 1068cdf0e10cSrcweir for (sal_Int32 i = 0; i < nLen; ++i) 1069cdf0e10cSrcweir { 1070cdf0e10cSrcweir uno::Sequence< OUString > aImplNames; 1071cdf0e10cSrcweir uno::Any aTmp( xNA->getByName( pElementNames[i] ) ); 1072cdf0e10cSrcweir if (aTmp >>= aImplNames) 1073cdf0e10cSrcweir { 1074cdf0e10cSrcweir if (aImplNames.getLength() > 0) 1075cdf0e10cSrcweir { 1076cdf0e10cSrcweir // only the first entry is used, there should be only one grammar checker per language 1077cdf0e10cSrcweir const OUString aImplName( aImplNames[0] ); 1078cdf0e10cSrcweir const LanguageType nLang = MsLangId::convertIsoStringToLanguage( pElementNames[i] ); 1079cdf0e10cSrcweir aTmpGCImplNamesByLang[ nLang ] = aImplName; 1080cdf0e10cSrcweir } 1081cdf0e10cSrcweir } 1082cdf0e10cSrcweir else 1083cdf0e10cSrcweir { 1084cdf0e10cSrcweir DBG_ASSERT( 0, "failed to get aImplNames. Wrong type?" ); 1085cdf0e10cSrcweir } 1086cdf0e10cSrcweir } 1087cdf0e10cSrcweir } 1088cdf0e10cSrcweir catch (uno::Exception &) 1089cdf0e10cSrcweir { 1090cdf0e10cSrcweir DBG_ASSERT( 0, "exception caught. Failed to get configured services" ); 1091cdf0e10cSrcweir } 1092cdf0e10cSrcweir 1093cdf0e10cSrcweir { 1094cdf0e10cSrcweir // ---- THREAD SAFE START ---- 1095cdf0e10cSrcweir ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() ); 1096cdf0e10cSrcweir m_aGCImplNamesByLang = aTmpGCImplNamesByLang; 1097cdf0e10cSrcweir // ---- THREAD SAFE END ---- 1098cdf0e10cSrcweir } 1099cdf0e10cSrcweir } 1100cdf0e10cSrcweir 1101cdf0e10cSrcweir /* 1102cdf0e10cSrcweir void GrammarCheckingIterator::GetMatchingGCSvcs_Impl() 1103cdf0e10cSrcweir { 1104cdf0e10cSrcweir GCImplNames_t aTmpGCImplNamesByLang; 1105cdf0e10cSrcweir 1106cdf0e10cSrcweir try 1107cdf0e10cSrcweir { 1108cdf0e10cSrcweir // get node names (locale iso strings) for configured grammar checkers 1109cdf0e10cSrcweir uno::Reference< container::XNameAccess > xNA( GetUpdateAccess(), uno::UNO_QUERY_THROW ); 1110cdf0e10cSrcweir xNA.set( xNA->getByName( A2OU("GrammarCheckers") ), uno::UNO_QUERY_THROW ); 1111cdf0e10cSrcweir const uno::Sequence< OUString > aGCImplNames( xNA->getElementNames() ); 1112cdf0e10cSrcweir const OUString *pGCImplNames = aGCImplNames.getConstArray(); 1113cdf0e10cSrcweir 1114cdf0e10cSrcweir sal_Int32 nLen = aGCImplNames.getLength(); 1115cdf0e10cSrcweir for (sal_Int32 i = 0; i < nLen; ++i) 1116cdf0e10cSrcweir { 1117cdf0e10cSrcweir uno::Reference< container::XNameAccess > xTmpNA( xNA->getByName( pGCImplNames[i] ), uno::UNO_QUERY_THROW ); 1118cdf0e10cSrcweir uno::Any aTmp( xTmpNA->getByName( A2OU("Locales") ) ); 1119cdf0e10cSrcweir uno::Sequence< OUString > aIsoLocaleNames; 1120cdf0e10cSrcweir if (aTmp >>= aIsoLocaleNames) 1121cdf0e10cSrcweir { 1122cdf0e10cSrcweir const OUString *pIsoLocaleNames = aIsoLocaleNames.getConstArray(); 1123cdf0e10cSrcweir for (sal_Int32 k = 0; k < aIsoLocaleNames.getLength(); ++k) 1124cdf0e10cSrcweir { 1125cdf0e10cSrcweir // if there are more grammar checkers for one language, for the time being, 1126cdf0e10cSrcweir // the last one found here will win... 1127cdf0e10cSrcweir const LanguageType nLang = MsLangId::convertIsoStringToLanguage( pIsoLocaleNames[k] ); 1128cdf0e10cSrcweir aTmpGCImplNamesByLang[ nLang ] = pGCImplNames[i]; 1129cdf0e10cSrcweir } 1130cdf0e10cSrcweir } 1131cdf0e10cSrcweir else 1132cdf0e10cSrcweir { 1133cdf0e10cSrcweir DBG_ASSERT( 0, "failed to get aImplNames. Wrong type?" ); 1134cdf0e10cSrcweir } 1135cdf0e10cSrcweir } 1136cdf0e10cSrcweir } 1137cdf0e10cSrcweir catch (uno::Exception &) 1138cdf0e10cSrcweir { 1139cdf0e10cSrcweir DBG_ASSERT( 0, "exception caught. Failed to get matching grammar checker services" ); 1140cdf0e10cSrcweir } 1141cdf0e10cSrcweir 1142cdf0e10cSrcweir { 1143cdf0e10cSrcweir // ---- THREAD SAFE START ---- 1144cdf0e10cSrcweir ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() ); 1145cdf0e10cSrcweir m_aGCImplNamesByLang = aTmpGCImplNamesByLang; 1146cdf0e10cSrcweir // ---- THREAD SAFE END ---- 1147cdf0e10cSrcweir } 1148cdf0e10cSrcweir } 1149cdf0e10cSrcweir */ 1150cdf0e10cSrcweir 1151cdf0e10cSrcweir /* 1152cdf0e10cSrcweir void GrammarCheckingIterator::GetAvailableGCSvcs_Impl() 1153cdf0e10cSrcweir { 1154cdf0e10cSrcweir // internal method; will always be called with locked mutex 1155cdf0e10cSrcweir if (m_xMSF.is()) 1156cdf0e10cSrcweir { 1157cdf0e10cSrcweir uno::Reference< container::XContentEnumerationAccess > xEnumAccess( m_xMSF, uno::UNO_QUERY ); 1158cdf0e10cSrcweir uno::Reference< container::XEnumeration > xEnum; 1159cdf0e10cSrcweir if (xEnumAccess.is()) 1160cdf0e10cSrcweir xEnum = xEnumAccess->createContentEnumeration( A2OU( SN_GRAMMARCHECKER ) ); 1161cdf0e10cSrcweir 1162cdf0e10cSrcweir if (xEnum.is()) 1163cdf0e10cSrcweir { 1164cdf0e10cSrcweir while (xEnum->hasMoreElements()) 1165cdf0e10cSrcweir { 1166cdf0e10cSrcweir uno::Any aCurrent = xEnum->nextElement(); 1167cdf0e10cSrcweir uno::Reference< lang::XSingleComponentFactory > xCompFactory; 1168cdf0e10cSrcweir uno::Reference< lang::XSingleServiceFactory > xFactory; 1169cdf0e10cSrcweir 1170cdf0e10cSrcweir uno::Reference< uno::XComponentContext > xContext; 1171cdf0e10cSrcweir uno::Reference< beans::XPropertySet > xProps( m_xMSF, uno::UNO_QUERY ); 1172cdf0e10cSrcweir xProps->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ))) >>= xContext; 1173cdf0e10cSrcweir 1174cdf0e10cSrcweir if ( xContext.is() && 1175cdf0e10cSrcweir (cppu::extractInterface( xCompFactory, aCurrent ) || 1176cdf0e10cSrcweir cppu::extractInterface( xFactory, aCurrent )) ) 1177cdf0e10cSrcweir { 1178cdf0e10cSrcweir try 1179cdf0e10cSrcweir { 1180cdf0e10cSrcweir uno::Reference< linguistic2::XProofreader > xSvc( ( xCompFactory.is() ? xCompFactory->createInstanceWithContext( xContext ) : xFactory->createInstance() ), uno::UNO_QUERY ); 1181cdf0e10cSrcweir if (xSvc.is()) 1182cdf0e10cSrcweir { 1183cdf0e10cSrcweir OUString aImplName; 1184cdf0e10cSrcweir uno::Reference< XServiceInfo > xInfo( xSvc, uno::UNO_QUERY ); 1185cdf0e10cSrcweir if (xInfo.is()) 1186cdf0e10cSrcweir aImplName = xInfo->getImplementationName(); 1187cdf0e10cSrcweir DBG_ASSERT( aImplName.getLength(), "empty implementation name" ); 1188cdf0e10cSrcweir uno::Reference< linguistic2::XSupportedLocales > xSuppLoc( xSvc, uno::UNO_QUERY ); 1189cdf0e10cSrcweir DBG_ASSERT( xSuppLoc.is(), "interfaces not supported" ); 1190cdf0e10cSrcweir if (xSuppLoc.is() && aImplName.getLength() > 0) 1191cdf0e10cSrcweir { 1192cdf0e10cSrcweir uno::Sequence< lang::Locale > aLocaleSequence( xSuppLoc->getLocales() ); 1193cdf0e10cSrcweir // ---- THREAD SAFE START ---- 1194cdf0e10cSrcweir ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() ); 1195cdf0e10cSrcweir m_aGCLocalesByService[ aImplName ] = aLocaleSequence; 1196cdf0e10cSrcweir m_aGCReferencesByService[ aImplName ] = xSvc; 1197cdf0e10cSrcweir // ---- THREAD SAFE END ---- 1198cdf0e10cSrcweir } 1199cdf0e10cSrcweir } 1200cdf0e10cSrcweir } 1201cdf0e10cSrcweir catch (uno::Exception &) 1202cdf0e10cSrcweir { 1203cdf0e10cSrcweir DBG_ASSERT( 0, "instantiating grammar checker failed" ); 1204cdf0e10cSrcweir } 1205cdf0e10cSrcweir } 1206cdf0e10cSrcweir } 1207cdf0e10cSrcweir } 1208cdf0e10cSrcweir } 1209cdf0e10cSrcweir } 1210cdf0e10cSrcweir */ 1211cdf0e10cSrcweir 1212cdf0e10cSrcweir 1213cdf0e10cSrcweir sal_Bool SAL_CALL GrammarCheckingIterator::supportsService( 1214cdf0e10cSrcweir const OUString & rServiceName ) 1215cdf0e10cSrcweir throw(uno::RuntimeException) 1216cdf0e10cSrcweir { 1217cdf0e10cSrcweir uno::Sequence< OUString > aSNL = getSupportedServiceNames(); 1218cdf0e10cSrcweir const OUString * pArray = aSNL.getConstArray(); 1219cdf0e10cSrcweir for( sal_Int32 i = 0; i < aSNL.getLength(); ++i ) 1220cdf0e10cSrcweir if( pArray[i] == rServiceName ) 1221cdf0e10cSrcweir return sal_True; 1222cdf0e10cSrcweir return sal_False; 1223cdf0e10cSrcweir } 1224cdf0e10cSrcweir 1225cdf0e10cSrcweir 1226cdf0e10cSrcweir OUString SAL_CALL GrammarCheckingIterator::getImplementationName( ) throw (uno::RuntimeException) 1227cdf0e10cSrcweir { 1228cdf0e10cSrcweir return GrammarCheckingIterator_getImplementationName(); 1229cdf0e10cSrcweir } 1230cdf0e10cSrcweir 1231cdf0e10cSrcweir 1232cdf0e10cSrcweir uno::Sequence< OUString > SAL_CALL GrammarCheckingIterator::getSupportedServiceNames( ) throw (uno::RuntimeException) 1233cdf0e10cSrcweir { 1234cdf0e10cSrcweir return GrammarCheckingIterator_getSupportedServiceNames(); 1235cdf0e10cSrcweir } 1236cdf0e10cSrcweir 1237cdf0e10cSrcweir 1238cdf0e10cSrcweir void GrammarCheckingIterator::SetServiceList( 1239cdf0e10cSrcweir const lang::Locale &rLocale, 1240cdf0e10cSrcweir const uno::Sequence< OUString > &rSvcImplNames ) 1241cdf0e10cSrcweir { 1242cdf0e10cSrcweir ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() ); 1243cdf0e10cSrcweir 1244cdf0e10cSrcweir LanguageType nLanguage = LocaleToLanguage( rLocale ); 1245cdf0e10cSrcweir OUString aImplName; 1246cdf0e10cSrcweir if (rSvcImplNames.getLength() > 0) 1247cdf0e10cSrcweir aImplName = rSvcImplNames[0]; // there is only one grammar checker per language 1248cdf0e10cSrcweir 1249cdf0e10cSrcweir if (nLanguage != LANGUAGE_NONE && nLanguage != LANGUAGE_DONTKNOW) 1250cdf0e10cSrcweir { 1251cdf0e10cSrcweir if (aImplName.getLength() > 0) 1252cdf0e10cSrcweir m_aGCImplNamesByLang[ nLanguage ] = aImplName; 1253cdf0e10cSrcweir else 1254cdf0e10cSrcweir m_aGCImplNamesByLang.erase( nLanguage ); 1255cdf0e10cSrcweir } 1256cdf0e10cSrcweir } 1257cdf0e10cSrcweir 1258cdf0e10cSrcweir 1259cdf0e10cSrcweir uno::Sequence< OUString > GrammarCheckingIterator::GetServiceList( 1260cdf0e10cSrcweir const lang::Locale &rLocale ) const 1261cdf0e10cSrcweir { 1262cdf0e10cSrcweir ::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() ); 1263cdf0e10cSrcweir 1264cdf0e10cSrcweir uno::Sequence< OUString > aRes(1); 1265cdf0e10cSrcweir 1266cdf0e10cSrcweir OUString aImplName; // there is only one grammar checker per language 1267cdf0e10cSrcweir LanguageType nLang = LocaleToLanguage( rLocale ); 1268cdf0e10cSrcweir GCImplNames_t::const_iterator aIt( m_aGCImplNamesByLang.find( nLang ) ); 1269cdf0e10cSrcweir if (aIt != m_aGCImplNamesByLang.end()) 1270cdf0e10cSrcweir aImplName = aIt->second; 1271cdf0e10cSrcweir 1272cdf0e10cSrcweir if (aImplName.getLength() > 0) 1273cdf0e10cSrcweir aRes[0] = aImplName; 1274cdf0e10cSrcweir else 1275cdf0e10cSrcweir aRes.realloc(0); 1276cdf0e10cSrcweir 1277cdf0e10cSrcweir return aRes; 1278cdf0e10cSrcweir } 1279cdf0e10cSrcweir 1280cdf0e10cSrcweir 1281cdf0e10cSrcweir LinguDispatcher::DspType GrammarCheckingIterator::GetDspType() const 1282cdf0e10cSrcweir { 1283cdf0e10cSrcweir return DSP_GRAMMAR; 1284cdf0e10cSrcweir } 1285cdf0e10cSrcweir 1286cdf0e10cSrcweir 1287cdf0e10cSrcweir /////////////////////////////////////////////////////////////////////////// 1288cdf0e10cSrcweir 1289cdf0e10cSrcweir 1290cdf0e10cSrcweir static OUString GrammarCheckingIterator_getImplementationName() throw() 1291cdf0e10cSrcweir { 1292cdf0e10cSrcweir return A2OU( "com.sun.star.lingu2.ProofreadingIterator" ); 1293cdf0e10cSrcweir } 1294cdf0e10cSrcweir 1295cdf0e10cSrcweir 1296cdf0e10cSrcweir static uno::Sequence< OUString > GrammarCheckingIterator_getSupportedServiceNames() throw() 1297cdf0e10cSrcweir { 1298cdf0e10cSrcweir uno::Sequence< OUString > aSNS( 1 ); 1299cdf0e10cSrcweir aSNS.getArray()[0] = A2OU( SN_GRAMMARCHECKINGITERATOR ); 1300cdf0e10cSrcweir return aSNS; 1301cdf0e10cSrcweir } 1302cdf0e10cSrcweir 1303cdf0e10cSrcweir 1304cdf0e10cSrcweir static uno::Reference< uno::XInterface > SAL_CALL GrammarCheckingIterator_createInstance( 1305cdf0e10cSrcweir const uno::Reference< lang::XMultiServiceFactory > & rxSMgr ) 1306cdf0e10cSrcweir throw(uno::Exception) 1307cdf0e10cSrcweir { 1308cdf0e10cSrcweir return static_cast< ::cppu::OWeakObject * >(new GrammarCheckingIterator( rxSMgr )); 1309cdf0e10cSrcweir } 1310cdf0e10cSrcweir 1311cdf0e10cSrcweir 1312cdf0e10cSrcweir void * SAL_CALL GrammarCheckingIterator_getFactory( 1313cdf0e10cSrcweir const sal_Char *pImplName, 1314cdf0e10cSrcweir lang::XMultiServiceFactory *pServiceManager, 1315cdf0e10cSrcweir void * /*pRegistryKey*/ ) 1316cdf0e10cSrcweir { 1317cdf0e10cSrcweir void * pRet = 0; 1318cdf0e10cSrcweir if ( !GrammarCheckingIterator_getImplementationName().compareToAscii( pImplName ) ) 1319cdf0e10cSrcweir { 1320cdf0e10cSrcweir uno::Reference< lang::XSingleServiceFactory > xFactory = 1321cdf0e10cSrcweir cppu::createOneInstanceFactory( 1322cdf0e10cSrcweir pServiceManager, 1323cdf0e10cSrcweir GrammarCheckingIterator_getImplementationName(), 1324cdf0e10cSrcweir GrammarCheckingIterator_createInstance, 1325cdf0e10cSrcweir GrammarCheckingIterator_getSupportedServiceNames()); 1326cdf0e10cSrcweir // acquire, because we return an interface pointer instead of a reference 1327cdf0e10cSrcweir xFactory->acquire(); 1328cdf0e10cSrcweir pRet = xFactory.get(); 1329cdf0e10cSrcweir } 1330cdf0e10cSrcweir return pRet; 1331cdf0e10cSrcweir } 1332