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
10*3b8558fdSAndrew Rist  *
11*3b8558fdSAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*3b8558fdSAndrew Rist  *
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.
19*3b8558fdSAndrew Rist  *
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 
lcl_IsWhiteSpace(sal_Unicode cChar)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 
lcl_SkipWhiteSpaces(const OUString & rText,sal_Int32 nStartPos)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 
lcl_BacktraceWhiteSpaces(const OUString & rText,sal_Int32 nStartPos)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 
workerfunc(void * gci)228cdf0e10cSrcweir extern "C" void workerfunc (void * gci)
229cdf0e10cSrcweir {
230cdf0e10cSrcweir     ((GrammarCheckingIterator*)gci)->DequeueAndCheck();
231cdf0e10cSrcweir }
232cdf0e10cSrcweir 
lcl_GetPrimaryLanguageOfSentence(uno::Reference<text::XFlatParagraph> xFlatPara,sal_Int32 nStartIndex)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 
GrammarCheckingIterator(const uno::Reference<lang::XMultiServiceFactory> & rxMgr)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 
~GrammarCheckingIterator()287cdf0e10cSrcweir GrammarCheckingIterator::~GrammarCheckingIterator()
288cdf0e10cSrcweir {
289cdf0e10cSrcweir 	::osl::Guard< ::osl::Mutex > aGuard( MyMutex::get() );
290cdf0e10cSrcweir }
291cdf0e10cSrcweir 
292cdf0e10cSrcweir 
NextDocId()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 
GetOrCreateDocId(const uno::Reference<lang::XComponent> & xComponent)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 
AddEntry(uno::WeakReference<text::XFlatParagraphIterator> xFlatParaIterator,uno::WeakReference<text::XFlatParagraph> xFlatPara,const OUString & rDocId,sal_Int32 nStartIndex,sal_Bool bAutomatic)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 
ProcessResult(const linguistic2::ProofreadingResult & rRes,const uno::Reference<text::XFlatParagraphIterator> & rxFlatParagraphIterator,bool bIsAutomaticChecking)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 
GetGrammarChecker(const lang::Locale & rLocale)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 
DequeueAndCheck()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 
startProofreading(const uno::Reference<::uno::XInterface> & xDoc,const uno::Reference<text::XFlatParagraphIteratorProvider> & xIteratorProvider)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 
checkSentenceAtPosition(const uno::Reference<uno::XInterface> & xDoc,const uno::Reference<text::XFlatParagraph> & xFlatPara,const OUString & rText,const lang::Locale & rLocale,sal_Int32 nStartOfSentencePos,sal_Int32 nSuggestedEndOfSentencePos,sal_Int32 nErrorPosInPara)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 
GetSuggestedEndOfSentence(const OUString & rText,sal_Int32 nSentenceStartPos,const lang::Locale & rLocale)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 
resetIgnoreRules()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 
isProofreading(const uno::Reference<uno::XInterface> & xDoc)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 
processLinguServiceEvent(const linguistic2::LinguServiceEvent & rLngSvcEvent)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 
addLinguServiceEventListener(const uno::Reference<linguistic2::XLinguServiceEventListener> & xListener)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 
removeLinguServiceEventListener(const uno::Reference<linguistic2::XLinguServiceEventListener> & xListener)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 
dispose()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 
addEventListener(const uno::Reference<lang::XEventListener> & xListener)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 
removeEventListener(const uno::Reference<lang::XEventListener> & xListener)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 
disposing(const lang::EventObject & rSource)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 
GetUpdateAccess() const1018cdf0e10cSrcweir 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 
GetConfiguredGCSvcs_Impl()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 
supportsService(const OUString & rServiceName)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 
getImplementationName()1226cdf0e10cSrcweir OUString SAL_CALL GrammarCheckingIterator::getImplementationName(  ) throw (uno::RuntimeException)
1227cdf0e10cSrcweir {
1228cdf0e10cSrcweir     return GrammarCheckingIterator_getImplementationName();
1229cdf0e10cSrcweir }
1230cdf0e10cSrcweir 
1231cdf0e10cSrcweir 
getSupportedServiceNames()1232cdf0e10cSrcweir uno::Sequence< OUString > SAL_CALL GrammarCheckingIterator::getSupportedServiceNames(  ) throw (uno::RuntimeException)
1233cdf0e10cSrcweir {
1234cdf0e10cSrcweir     return GrammarCheckingIterator_getSupportedServiceNames();
1235cdf0e10cSrcweir }
1236cdf0e10cSrcweir 
1237cdf0e10cSrcweir 
SetServiceList(const lang::Locale & rLocale,const uno::Sequence<OUString> & rSvcImplNames)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 
GetServiceList(const lang::Locale & rLocale) const1259cdf0e10cSrcweir 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 
GetDspType() const1281cdf0e10cSrcweir LinguDispatcher::DspType GrammarCheckingIterator::GetDspType() const
1282cdf0e10cSrcweir {
1283cdf0e10cSrcweir     return DSP_GRAMMAR;
1284cdf0e10cSrcweir }
1285cdf0e10cSrcweir 
1286cdf0e10cSrcweir 
1287cdf0e10cSrcweir ///////////////////////////////////////////////////////////////////////////
1288cdf0e10cSrcweir 
1289cdf0e10cSrcweir 
GrammarCheckingIterator_getImplementationName()1290cdf0e10cSrcweir static OUString GrammarCheckingIterator_getImplementationName() throw()
1291cdf0e10cSrcweir {
1292cdf0e10cSrcweir     return A2OU( "com.sun.star.lingu2.ProofreadingIterator" );
1293cdf0e10cSrcweir }
1294cdf0e10cSrcweir 
1295cdf0e10cSrcweir 
GrammarCheckingIterator_getSupportedServiceNames()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 
GrammarCheckingIterator_createInstance(const uno::Reference<lang::XMultiServiceFactory> & rxSMgr)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 
GrammarCheckingIterator_getFactory(const sal_Char * pImplName,lang::XMultiServiceFactory * pServiceManager,void *)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