diff options
author | Ivo Hinkelmann <ihi@openoffice.org> | 2008-07-16 12:46:41 +0000 |
---|---|---|
committer | Ivo Hinkelmann <ihi@openoffice.org> | 2008-07-16 12:46:41 +0000 |
commit | db1f4b4277139ee218beff8a6872714b57fe7e80 (patch) | |
tree | 6dbe5e1231d24a84408be1e1350fcc1842174806 /linguistic | |
parent | 6c4f3b117e68ecc89b94e02debc598669244b13e (diff) |
INTEGRATION: CWS tl55 (1.3.8); FILE MERGED
2008/07/01 13:21:19 tl 1.3.8.25: #i85999# grammar checking framework
2008/07/01 13:17:58 tl 1.3.8.24: #i85999# grammar checking framework
2008/07/01 07:51:33 tl 1.3.8.23: #i85999# grammar checking framework
2008/06/30 11:53:11 os 1.3.8.22: #i85999# iteration fixed for dialog access
2008/06/29 11:35:00 tl 1.3.8.21: #i85999# grammar checking framework
2008/06/25 14:13:24 tl 1.3.8.20: #i85999# grammar checking framework
2008/06/25 14:11:42 tl 1.3.8.19: #i85999# grammar checking framework
2008/06/25 07:07:02 tl 1.3.8.18: #i85999# grammar checking framework
2008/06/25 06:30:05 tl 1.3.8.17: #i85999# grammar checking framework
2008/06/24 10:24:13 os 1.3.8.16: #83776# additional locals fixed
2008/06/19 14:55:09 tl 1.3.8.15: #i85999# grammar checking framework
2008/06/16 11:34:42 tl 1.3.8.14: #i85999# grammar checking framework
2008/06/13 15:20:17 tl 1.3.8.13: #i85999# grammart checking framework
2008/06/11 10:40:56 tl 1.3.8.12: #i85999# grammar checking framework
2008/06/11 10:02:16 tl 1.3.8.11: #i85999# grammar checking framework
2008/06/11 09:02:00 tl 1.3.8.10: #i85999# MAC line ends removed
2008/06/11 08:17:41 mba 1.3.8.9: some fixes
2008/06/07 15:24:21 tl 1.3.8.8: #i85999# grammar checking framework
2008/05/31 16:47:55 tl 1.3.8.7: #i85999# grammar checking framework
2008/05/31 12:33:10 tl 1.3.8.6: #i85999# grammar checking framework
2008/05/27 11:17:52 tl 1.3.8.5: #i85999# improve grammar checking framework
2008/05/23 11:00:13 tl 1.3.8.4: #158047# customer specific extension
2008/05/23 05:54:46 tl 1.3.8.3: #158047# customer specific extension
2008/05/22 14:00:59 tl 1.3.8.2: #158047# customer specific extension
2008/05/21 09:59:51 tl 1.3.8.1: #158047# customer specific extension
Diffstat (limited to 'linguistic')
-rw-r--r-- | linguistic/source/gciterator.cxx | 1242 |
1 files changed, 850 insertions, 392 deletions
diff --git a/linguistic/source/gciterator.cxx b/linguistic/source/gciterator.cxx index cfbe6a9b76..4d70a84429 100644 --- a/linguistic/source/gciterator.cxx +++ b/linguistic/source/gciterator.cxx @@ -1,13 +1,13 @@ /************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * + * * Copyright 2008 by Sun Microsystems, Inc. * * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: gciterator.cxx,v $ - * $Revision: 1.3 $ + * $Revision: 1.4 $ * * This file is part of OpenOffice.org. * @@ -29,238 +29,424 @@ ************************************************************************/ #include "precompiled_linguistic.hxx" -#include <sal/config.h> -#include <com/sun/star/uno/XComponentContext.hpp> -#include <cppuhelper/implbase4.hxx> +#include <com/sun/star/container/XContentEnumerationAccess.hpp> +#include <com/sun/star/container/XEnumeration.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/container/XNameReplace.hpp> +#include <com/sun/star/i18n/XBreakIterator.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/linguistic2/XSupportedLocales.hpp> +#include <com/sun/star/linguistic2/XGrammarChecker.hpp> #include <com/sun/star/linguistic2/XGrammarCheckingIterator.hpp> -#include <deque> +#include <com/sun/star/linguistic2/SingleGrammarError.hpp> +#include <com/sun/star/linguistic2/GrammarCheckingResult.hpp> +#include <com/sun/star/linguistic2/LinguServiceEvent.hpp> +#include <com/sun/star/linguistic2/LinguServiceEventFlags.hpp> +#include <com/sun/star/registry/XRegistryKey.hpp> #include <com/sun/star/text/TextMarkupType.hpp> +#include <com/sun/star/text/XTextMarkup.hpp> #include <com/sun/star/text/XFlatParagraph.hpp> #include <com/sun/star/text/XFlatParagraphIterator.hpp> -#include <map> -#include <com/sun/star/i18n/XBreakIterator.hpp> -#include <vcl/unohelp.hxx> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/lang/XSingleComponentFactory.hpp> -#include <osl/mutex.hxx> -#include <vcl/svapp.hxx> +#include <sal/config.h> #include <osl/conditn.hxx> +#include <osl/thread.hxx> #include <cppuhelper/implbase4.hxx> -#include <com/sun/star/lang/XComponent.hpp> -#include <com/sun/star/lang/XServiceInfo.hpp> -#include <com/sun/star/linguistic2/XGrammarCheckingResultListener.hpp> -#include <com/sun/star/linguistic2/XGrammarChecker.hpp> -#include <com/sun/star/linguistic2/XGrammarCheckingResultBroadcaster.hpp> -#include "misc.hxx" -#include "defs.hxx" +#include <cppuhelper/implementationentry.hxx> +#include <cppuhelper/interfacecontainer.h> +#include <cppuhelper/extract.hxx> #include <cppuhelper/factory.hxx> -#include <com/sun/star/registry/XRegistryKey.hpp> -#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <vcl/unohelp.hxx> +#include <i18npool/mslangid.hxx> +#include <unotools/processfactory.hxx> -#include <com/sun/star/linguistic2/SingleGrammarError.hpp> +#include <deque> +#include <map> +#include <vector> + +#include "misc.hxx" +#include "defs.hxx" +#include "lngopt.hxx" #include "gciterator.hxx" -#include "grammarchecker.hxx" -#include <unotools/processfactory.hxx> -#include <com/sun/star/container/XContentEnumerationAccess.hpp> -#include <com/sun/star/container/XEnumeration.hpp> -#include <cppuhelper/interfacecontainer.h> -#include <com/sun/star/lang/XMultiServiceFactory.hpp> -#include <cppuhelper/factory.hxx> -#include "lngopt.hxx" -#include <com/sun/star/linguistic2/XSupportedLocales.hpp> +using ::rtl::OUString; +using namespace ::com::sun::star; -#include <vcl/unohelp.hxx> -#include <com/sun/star/linguistic2/SingleGrammarError.hpp> -#include <com/sun/star/linguistic2/GrammarCheckingResult.hpp> -#include <cppuhelper/extract.hxx> -#include <i18npool/mslangid.hxx> -#include <osl/thread.hxx> -#include <com/sun/star/text/XTextMarkup.hpp> +// forward declarations +static ::rtl::OUString GrammarCheckingIterator_getImplementationName() throw(); +static uno::Sequence< OUString > GrammarCheckingIterator_getSupportedServiceNames() throw(); -using namespace ::utl; -using namespace ::rtl; -using namespace ::com::sun::star; -using namespace linguistic; +////////////////////////////////////////////////////////////////////// extern "C" void workerfunc (void * gci) { - ((GrammarCheckingIterator*)gci)->dequeueAndCheck(); + ((GrammarCheckingIterator*)gci)->DequeueAndCheck(); } -//////////////////////////////////////////////////////////// +static lang::Locale lcl_GetPrimaryLanguageOfSentence( + uno::Reference< text::XFlatParagraph > xFlatPara, + sal_Int32 nStartIndex ) +{ + //get the language of the first word + return xFlatPara->getLanguageOfText( nStartIndex, 1 ); +} -GrammarCheckingIterator::GrammarCheckingIterator( /* uno::Reference< uno::XComponentContext > const & context */ ) : - /*m_xContext(context)*/ +////////////////////////////////////////////////////////////////////// +/* +class MyThread : punlic osl::Thread +{ + void run () + { + DequeueAndCheck(); + } + + void own_terminate () + { + m_bEnd = true; + wait (3000); + terminate (); + } +} + +MyThread m_aQueue; + +vois startGrammarChecking() +{ + if (!m_aQueue.isRunning ()) + m_aQueue.create (); +} + +void stopGrammarChecking () +{ + if (m_aQueue.isRunning ()) + m_aQueue.own_terminate (); +} +*/ + +GrammarCheckingIterator::GrammarCheckingIterator( const uno::Reference< lang::XMultiServiceFactory > & rxMgr ) : + m_xMSF( rxMgr ), m_bEnd( sal_False ), - m_nDocID( 0 ) + m_bGCServicesChecked( sal_False ), + m_nDocIdCounter( 0 ), + m_nCurCheckedDocId( - 1 ), + m_nLastEndOfSentencePos( -1 ), + m_aMutex(), + m_aEventListeners( m_aMutex ), + m_aNotifyListeners( m_aMutex ) { - osl_createThread(workerfunc, this); + osl_createThread( workerfunc, this ); } + GrammarCheckingIterator::~GrammarCheckingIterator() { -} + ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex ); +} -//create new DocID -const ::sal_Int32 GrammarCheckingIterator::NextDocId() -{ - osl::Guard< osl::Mutex > aGuard(GetMutex()); - m_nDocID += 1; - return m_nDocID; +sal_Int32 GrammarCheckingIterator::NextDocId() +{ + ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex ); + m_nDocIdCounter += 1; + return m_nDocIdCounter; } -lang::Locale getPrimaryLanguageOfSentence( uno::Reference< text::XFlatParagraph > xFlatPara, sal_Int32 nStartIndex ) + +sal_Int32 GrammarCheckingIterator::GetOrCreateDocId( + const uno::Reference< lang::XComponent > &xComponent ) { - (void) nStartIndex; - //get the language of the first word - return xFlatPara->getLanguageOfText(nStartIndex, 1);//nStartIndex + // internal method; will always be called with locked mutex + + sal_Int32 nRes = -1; + if (xComponent.is()) + { + if (m_aDocIdMap.find( xComponent ) != m_aDocIdMap.end()) + { + // add new entry + nRes = m_aDocIdMap[ xComponent ]; + xComponent->addEventListener( this ); + } + else // return already existing entry + { + nRes = NextDocId(); + m_aDocIdMap[ xComponent ] = nRes; + } + } + return nRes; } + -void GrammarCheckingIterator::AddEntry( - uno::WeakReference< text::XFlatParagraphIterator > xFlatParaIterator, - uno::WeakReference< text::XFlatParagraph > xFlatPara, - sal_Int32 nDocID, - sal_Int32 nStartIndex, +void GrammarCheckingIterator::AddEntry( + uno::WeakReference< text::XFlatParagraphIterator > xFlatParaIterator, + uno::WeakReference< text::XFlatParagraph > xFlatPara, + sal_Int32 nDocId, + sal_Int32 nStartIndex, sal_Bool bAutomatic ) -{ - osl::Guard< osl::Mutex > aGuard(GetMutex()); - - FPEntry aNewFPEntry; - aNewFPEntry.m_xParaIterator = xFlatParaIterator; - aNewFPEntry.m_xPara = xFlatPara; - aNewFPEntry.m_nDocID = nDocID; - aNewFPEntry.m_nStartIndex = nStartIndex; - aNewFPEntry.m_bAutomatic = bAutomatic; +{ + // we may not need/have a xFlatParaIterator (e.g. if checkGrammarAtPos was called) + // but we always need a xFlatPara... + uno::Reference< text::XFlatParagraph > xPara( xFlatPara ); + if (xPara.is()) + { + FPEntry aNewFPEntry; + aNewFPEntry.m_xParaIterator = xFlatParaIterator; + aNewFPEntry.m_xPara = xFlatPara; + aNewFPEntry.m_nDocId = nDocId; + aNewFPEntry.m_nStartIndex = nStartIndex; + aNewFPEntry.m_bAutomatic = bAutomatic; + + // add new entry to the end of this queue + ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex ); + m_aFPEntriesQueue.push_back( aNewFPEntry ); + + // wake up the thread in order to do grammar checking + m_aWakeUpThread.set(); + } +} + + +void GrammarCheckingIterator::ProcessResult( + const linguistic2::GrammarCheckingResult &rRes, + sal_Int32 nSentenceStartPos, + const uno::Reference< text::XFlatParagraphIterator > &rxFlatParagraphIterator, + bool bIsAutomaticChecking ) +{ + DBG_ASSERT( rRes.xFlatParagraph.is(), "xFlatParagraph is missing" ); + + sal_Bool bContinueWithNextPara = sal_False; + if (!rRes.xFlatParagraph.is() || rRes.xFlatParagraph->isModified()) + { + // if paragraph was modified/deleted meanwhile continue with the next one... + bContinueWithNextPara = sal_True; + } + else // paragraph is still unchanged... + { + // mark found errors... + bool bBoundariesOk = 0 <= nSentenceStartPos && nSentenceStartPos <= rRes.nEndOfSentencePos; + DBG_ASSERT( bBoundariesOk, "inconsistent sentence boundaries" ); + uno::Sequence< linguistic2::SingleGrammarError > aErrors = rRes.aGrammarErrors; + if (aErrors.getLength() > 0 && bBoundariesOk) + { + for (sal_Int16 i = 0; i < aErrors.getLength(); ++i) + { + linguistic2::SingleGrammarError aError = aErrors[aErrors.getLength() - 1 - i]; + + OUString aIdentifier; + uno::Reference< container::XStringKeyMap > xStringKeyMap; + + // display the grammar error mark + rRes.xFlatParagraph->commitTextMarkup( aError.nErrorType, aIdentifier, aError.nErrorStart, aError.nErrorLength, xStringKeyMap ); + + // commit sentence markup to identify sentence boundaries + const sal_Int32 nSentenceLength = rRes.nEndOfSentencePos - nSentenceStartPos; + rRes.xFlatParagraph->commitTextMarkup( text::TextMarkupType::SENTENCE, aIdentifier, nSentenceStartPos, nSentenceLength, xStringKeyMap ); + } + } + + // other sentences left to be checked in this paragraph? + if (rRes.nEndOfSentencePos < rRes.aText.getLength()) + { + AddEntry( rxFlatParagraphIterator, rRes.xFlatParagraph, rRes.nDocumentId, rRes.nEndOfSentencePos, bIsAutomaticChecking ); + } + else // current paragraph finished + { + // set "already checked" flag for the current flat paragraph + if (rRes.xFlatParagraph.is()) + rRes.xFlatParagraph->setChecked( text::TextMarkupType::GRAMMAR, true ); - // add new entry to the end of this queue - m_aFPQueue.push_back(aNewFPEntry); + bContinueWithNextPara = sal_True; + } + } - // wake up the thread in order to do grammar checking - m_aCondition.set(); + if (bContinueWithNextPara) + { + // we need to continue with the next paragraph + uno::Reference< text::XFlatParagraph > xFlatParaNext; + if (rxFlatParagraphIterator.is()) + xFlatParaNext = rxFlatParagraphIterator->getNextPara(); + { + AddEntry( rxFlatParagraphIterator, xFlatParaNext, rRes.nDocumentId, 0, bIsAutomaticChecking ); + } + } } -//doGrammarChecking_Impl -void GrammarCheckingIterator::doGrammarChecking_Impl( - sal_Int32 nDocId, - const uno::Reference< text::XFlatParagraph > & xFlatPara, - const lang::Locale & rLocale, - sal_Int32 nStartOfSentencePos, - sal_Int32 nSuggestedSentenceEndPos) + +uno::Reference< linguistic2::XGrammarChecker > GrammarCheckingIterator::GetGrammarChecker( + const lang::Locale &rLocale ) { - //check the locale - /*if(m_aGCLocales.size() == 0) + (void) rLocale; + uno::Reference< linguistic2::XGrammarChecker > xRes; + + // ---- THREAD SAFE START ---- + ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex ); + + // check supported locales for each grammarchecker if not already done + if (!m_bGCServicesChecked) { - GetAvailableGCSvcs_Impl(); + //GetAvailableGCSvcs_Impl(); + //GetConfiguredGCSvcs_Impl(); + GetMatchingGCSvcs_Impl(); + m_bGCServicesChecked = sal_True; } - for (GCLocales_t::const_iterator it = m_aGCLocales.begin(); it != m_aGCLocales.end(); ++ it) + + const LanguageType nLang = MsLangId::convertLocaleToLanguage( rLocale ); + GCImplNames_t::const_iterator aLangIt( m_aGCImplNamesByLang.find( nLang ) ); + if (aLangIt != m_aGCImplNamesByLang.end()) // matching configured language found? { - uno::Sequence< lang::Locale > aLocales = it->second; - for (sal_Int32 i=0; i<aLocales.getLength(); ++i) + OUString aSvcImplName( aLangIt->second ); + GCReferences_t::const_iterator aImplNameIt( m_aGCReferencesByService.find( aSvcImplName ) ); + if (aImplNameIt != m_aGCReferencesByService.end()) // matching impl name found? { - if( MsLangId::convertLocaleToLanguage(aLocales[i]) == MsLangId::convertLocaleToLanguage(rLocale)) + xRes = aImplNameIt->second; + } + else // the service is to be instatiated here for the first time... + { + try { - GrammarChecker* pGC=new GrammarChecker(); - pGC->addGrammarCheckingResultListener((XGrammarCheckingResultListener *) this); - pGC->doGrammarChecking(nDocId, xFlatPara, rLocale, nStartOfSentencePos, nSuggestedSentenceEndPos);//rFlatParaText - break; + uno::Reference< lang::XMultiServiceFactory > xMgr( + utl::getProcessServiceFactory(), uno::UNO_QUERY_THROW ); + uno::Reference< linguistic2::XGrammarChecker > xGC( + xMgr->createInstance( aSvcImplName ), uno::UNO_QUERY_THROW ); + uno::Reference< linguistic2::XSupportedLocales > xSuppLoc( xGC, uno::UNO_QUERY_THROW ); + + if (xSuppLoc->hasLocale( rLocale )) + { + m_aGCReferencesByService[ aSvcImplName ] = xGC; + xRes = xGC; + + uno::Reference< linguistic2::XLinguServiceEventBroadcaster > xBC( xGC, uno::UNO_QUERY ); + if (xBC.is()) + xBC->addLinguServiceEventListener( this ); + } + else + { + DBG_ASSERT( 0, "grammar checker does not support required locale" ); + } } - } - }*/ - GrammarChecker* pGC=new GrammarChecker(); - pGC->addGrammarCheckingResultListener((XGrammarCheckingResultListener *) this); - pGC->doGrammarChecking(nDocId, xFlatPara, rLocale, nStartOfSentencePos, nSuggestedSentenceEndPos);//rFlatParaText - + catch (uno::Exception &) + { + DBG_ASSERT( 0, "instantiating grammar checker failed" ); + } + } + } + // ---- THREAD SAFE END ---- + + return xRes; } -//get every element from the queue and check it -void GrammarCheckingIterator::dequeueAndCheck() +void GrammarCheckingIterator::DequeueAndCheck() { + uno::Sequence< sal_Int32 > aLangPortions; + uno::Sequence< lang::Locale > aLangPortionsLocale; + // ---- THREAD SAFE START ---- - osl::ResettableGuard< osl::Mutex > aGuard(GetMutex()); - bool bEnd( m_bEnd ); - aGuard.clear(); + bool bEnd = false; + { + ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex ); + bEnd = m_bEnd; + } // ---- THREAD SAFE END ---- - while( !bEnd ) + while (!bEnd) { // ---- THREAD SAFE START ---- - aGuard.reset(); - bool bQueueEmpty = m_aFPQueue.empty(); - aGuard.clear(); + bool bQueueEmpty = false; + { + ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex ); + bQueueEmpty = m_aFPEntriesQueue.empty(); + } // ---- THREAD SAFE END ---- - if( !bQueueEmpty ) + if (!bQueueEmpty) { + uno::Reference< text::XFlatParagraphIterator > xFPIterator; + uno::Reference< text::XFlatParagraph > xFlatPara; + FPEntry aFPEntryItem; + sal_Int32 nCurDocId = - 1; + sal_Bool bModified = sal_False; // ---- THREAD SAFE START ---- - aGuard.reset(); - - FPEntry aFPEntryItem = m_aFPQueue.front(); - - uno::Reference< text::XFlatParagraphIterator > xFPIterator( uno::Reference< text::XFlatParagraphIterator >( aFPEntryItem.m_xParaIterator ), uno::UNO_QUERY); + { + ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex ); + aFPEntryItem = m_aFPEntriesQueue.front(); + xFPIterator = aFPEntryItem.m_xParaIterator; + xFlatPara = aFPEntryItem.m_xPara; + m_nCurCheckedDocId = aFPEntryItem.m_nDocId; + nCurDocId = m_nCurCheckedDocId; + + m_aFPEntriesQueue.pop_front(); + } + // ---- THREAD SAFE END ---- - uno::Reference< text::XFlatParagraph > xFlatPara( uno::Reference< text::XFlatParagraph >( aFPEntryItem.m_xPara ), uno::UNO_QUERY ); - if(xFlatPara.is()) + if (xFlatPara.is() && xFPIterator.is()) { - OUString aCurTxt = xFlatPara->getText(); - sal_Int32 nEndPos=aCurTxt.getLength(); - lang::Locale aCurLocale=getPrimaryLanguageOfSentence(xFlatPara, 0); - sal_Int32 nCurDocID=aFPEntryItem.m_nDocID; + OUString aCurTxt( xFlatPara->getText() ); + lang::Locale aCurLocale = lcl_GetPrimaryLanguageOfSentence( xFlatPara, aFPEntryItem.m_nStartIndex ); - sal_Int32 nStartPos=aFPEntryItem.m_nStartIndex; - while(nStartPos<nEndPos) + bModified = xFlatPara->isModified(); + if (!bModified) { + // ---- THREAD SAFE START ---- + ::osl::ClearableGuard< ::osl::Mutex > aGuard( m_aMutex ); - sal_Int32 nCurEndPos=getSuggestedEndOfSentence( aCurTxt, nStartPos, aCurLocale); - //////////////////////////////////////////////// - //..............doGrammarChecking............... - //////////////////////////////////////////////// - doGrammarChecking_Impl(nCurDocID, xFlatPara, aCurLocale, nStartPos, nCurEndPos); - - nStartPos=nCurEndPos+1; - - //update the startIndex of the entry - aFPEntryItem.m_nStartIndex=nStartPos; - m_aFPQueue.pop_front(); - m_aFPQueue.push_front(aFPEntryItem); - } - //remove the first element from the queue - m_aFPQueue.pop_front(); + sal_Int32 nStartPos = aFPEntryItem.m_nStartIndex; + sal_Int32 nSuggestedEnd = GetSuggestedEndOfSentence( aCurTxt, nStartPos, aCurLocale ); - - - if(xFlatPara->isModified( )) - { - //there is something unprocessed left in the current flat paragraph - //add this flat paragraph to the end of the queue - AddEntry( xFPIterator, xFlatPara, nCurDocID, 0, aFPEntryItem.m_bAutomatic ); + linguistic2::GrammarCheckingResult aRes; + + uno::Reference< linguistic2::XGrammarChecker > xGC( GetGrammarChecker( aCurLocale ), uno::UNO_QUERY ); + if (xGC.is()) + { + aGuard.clear(); + aRes = xGC->doGrammarChecking( nCurDocId, aCurTxt, aCurLocale, nStartPos, nSuggestedEnd, aLangPortions, aLangPortionsLocale ); + aRes.xFlatParagraph = xFlatPara; + aRes.nStartOfSentencePos = nStartPos; + } + else + { + // no grammar checker -> no error + // but we need to provide the data below in order to continue with the next sentence + aRes.nDocumentId = nCurDocId; + aRes.xFlatParagraph = xFlatPara; + aRes.aText = aCurTxt; + aRes.aLocale = aCurLocale; + aRes.nStartOfSentencePos = nStartPos; + aRes.nEndOfSentencePos = nSuggestedEnd; + } + ProcessResult( aRes, nStartPos, xFPIterator, aFPEntryItem.m_bAutomatic ); + // ---- THREAD SAFE END ---- } else { - //set "alread checked" flag for the current flat paragraph - //get the next flat paragraph to create a new entry - - xFlatPara->setChecked(text::TextMarkupType::GRAMMAR, true); - uno::Reference< text::XFlatParagraph > xFlatParaNext = xFPIterator->getNextPara( );//getParaAfter( xFlatPara );// - if( xFlatParaNext.is() ) - { - AddEntry(xFPIterator, xFlatParaNext, nCurDocID, 0, aFPEntryItem.m_bAutomatic); - } + // the paragraph changed meanwhile... (and maybe is still edited) + // thus we simply continue to ask for the next to be checked. + uno::Reference< text::XFlatParagraph > xFlatParaNext( xFPIterator->getNextPara() ); + AddEntry( xFPIterator, xFlatParaNext, nCurDocId, 0, aFPEntryItem.m_bAutomatic ); } } - aGuard.clear(); + + // ---- THREAD SAFE START ---- + { + ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex ); + m_nCurCheckedDocId = -1; + } // ---- THREAD SAFE END ---- } else { // ---- THREAD SAFE START ---- - aGuard.reset(); - // Check queue state again - if ( m_aFPQueue.empty() ) - m_aCondition.reset(); - aGuard.clear(); + { + ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex ); + // Check queue state again + if (m_aFPEntriesQueue.empty()) + m_aWakeUpThread.reset(); + } // ---- THREAD SAFE END ---- //if the queue is empty @@ -268,352 +454,601 @@ void GrammarCheckingIterator::dequeueAndCheck() // mutex. Otherwise you would keep out other threads // to add entries to the queue! A condition is thread- // safe implemented. - m_aCondition.wait(); + m_aWakeUpThread.wait(); } // ---- THREAD SAFE START ---- - aGuard.reset(); - bEnd = m_bEnd; - aGuard.clear(); - // ---- THREAD SAFE END ---- + { + ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex ); + bEnd = m_bEnd; + } + // ---- THREAD SAFE END ---- } + + //!! This one must be the very last statement to call in this function !! + m_aRequestEndThread.set(); } -// linguistic2::XGrammarCheckingIterator: void SAL_CALL GrammarCheckingIterator::startGrammarChecking( - const uno::Reference< ::uno::XInterface > & xDoc, - const uno::Reference< text::XFlatParagraphIteratorProvider > & xIteratorProvider, - ::sal_Bool bAutomatic) - throw (uno::RuntimeException, lang::IllegalArgumentException) + const uno::Reference< ::uno::XInterface > & xDoc, + const uno::Reference< text::XFlatParagraphIteratorProvider > & xIteratorProvider, + sal_Bool bAutomatic) +throw (uno::RuntimeException, lang::IllegalArgumentException) { - (void) xDoc; + // get paragraph to start checking with + uno::Reference<text::XFlatParagraphIterator> xFPIterator = xIteratorProvider->getFlatParagraphIterator( + text::TextMarkupType::GRAMMAR, bAutomatic ); + uno::Reference< text::XFlatParagraph > xPara( xFPIterator.is()? xFPIterator->getFirstPara() : NULL ); + uno::Reference< lang::XComponent > xComponent( xDoc, uno::UNO_QUERY ); - /****************************************************************** - Add a returned value for this function???? - *******************************************************************/ - // TODO: Insert your implementation for "startGrammarChecking" here. - - // Create new entry and push it to the global queue - osl::Guard< osl::Mutex > aGuard(GetMutex()); - uno::Reference<text::XFlatParagraphIterator> xFPIterator= - xIteratorProvider->getFlatParagraphIterator( - text::TextMarkupType::GRAMMAR,bAutomatic); - - uno::Reference< text::XFlatParagraph > xPara= xFPIterator->getFirstPara(); - if(xPara.is()) + // ---- THREAD SAFE START ---- + ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex ); + if (xPara.is() && xComponent.is()) { - ::sal_Int32 nDocID = NextDocId(); - m_aDocMap[xDoc]=nDocID; - AddEntry(xFPIterator, xPara, nDocID, 0, bAutomatic); + sal_Int32 nDocId = GetOrCreateDocId( xComponent ); + + // create new entry and add it to queue + AddEntry( xFPIterator, xPara, nDocId, 0, bAutomatic ); } + // ---- THREAD SAFE END ---- } -void SAL_CALL GrammarCheckingIterator::checkGrammarAtPos( - const uno::Reference< ::uno::XInterface > & xDoc, - const uno::Reference< text::XFlatParagraph > & xStartPara, - sal_Int32 nPosInPara) - throw (uno::RuntimeException, lang::IllegalArgumentException) + +linguistic2::GrammarCheckingResult SAL_CALL GrammarCheckingIterator::checkGrammarAtPos( + 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 ) +throw (lang::IllegalArgumentException, uno::RuntimeException) { - - // TODO: Insert your implementation for "checkGrammarAtPos" here. - - //for the context menu - OUString aTxt = xStartPara->getText(); - //sal_Int32 nEndPos=rTxt.getLength(); - lang::Locale aLocale=getPrimaryLanguageOfSentence(xStartPara, nPosInPara); - uno::Reference< i18n::XBreakIterator > xBreakIterator; - if(!xBreakIterator.is()) - { - xBreakIterator=vcl::unohelper::CreateBreakIterator(); - } - if(xBreakIterator.is()) + (void) rLocale; + + // for the context menu... + + linguistic2::GrammarCheckingResult aRes; + + uno::Reference< lang::XComponent > xComponent( xDoc, uno::UNO_QUERY ); + if (xFlatPara.is() && xComponent.is() && + ( nErrorPosInPara < 0 || nErrorPosInPara < rText.getLength())) { - sal_Int32 nStartPosition=xBreakIterator->beginOfSentence(aTxt, nPosInPara, aLocale);; - sal_Int32 nEndPosition=xBreakIterator->endOfSentence(aTxt, nStartPosition, aLocale); + uno::Sequence< sal_Int32 > aLangPortions; + uno::Sequence< lang::Locale > aLangPortionsLocale; + + // iterate through paragraph until we find the sentence we are interested in + linguistic2::GrammarCheckingResult aTmpRes; + sal_Int32 nStartPos = nErrorPosInPara > 0 ? 0 : nStartOfSentencePos; + bool bFound = false; + do + { + lang::Locale aCurLocale = lcl_GetPrimaryLanguageOfSentence( xFlatPara, nStartPos ); + sal_Int32 nOldStartOfSentencePos = nStartPos; + uno::Reference< linguistic2::XGrammarChecker > xGC; + sal_Int32 nDocId = -1; - //////////////////////////////////////////////// - //..............doGrammarChecking............... - //////////////////////////////////////////////// + // ---- THREAD SAFE START ---- + { + ::osl::ClearableGuard< ::osl::Mutex > aGuard( m_aMutex ); + nDocId = GetOrCreateDocId( xComponent ); + nSuggestedEndOfSentencePos = GetSuggestedEndOfSentence( rText, nStartPos, aCurLocale ); + + xGC = GetGrammarChecker( aCurLocale ); + } + // ---- THREAD SAFE START ---- + sal_Int32 nEndPos = -1; + if (xGC.is()) + { + aTmpRes = xGC->doGrammarChecking( nDocId, rText, aCurLocale, nStartPos, nSuggestedEndOfSentencePos, aLangPortions, aLangPortionsLocale ); + aTmpRes.xFlatParagraph = xFlatPara; + aTmpRes.nStartOfSentencePos = nStartPos; + nEndPos = aTmpRes.nEndOfSentencePos; + + if ((nErrorPosInPara< 0 || nStartPos <= nErrorPosInPara) && nErrorPosInPara < nEndPos) + bFound = true; + } + if (nEndPos == -1) // no result from grammar checker + nEndPos = nSuggestedEndOfSentencePos; + nStartPos = nEndPos; - sal_Int32 nDocID=m_aDocMap[xDoc]; - doGrammarChecking_Impl(nDocID, xStartPara, aLocale, nStartPosition, nEndPosition);//aTxt + // prevent endless loop by forcefully advancing if needs be... + if (nStartPos <= nOldStartOfSentencePos) + { + DBG_ASSERT( 0, "end-of-sentence detection failed?" ); + nStartPos = nOldStartOfSentencePos + 1; + } + } + while (!bFound && nStartPos < rText.getLength()); + + if (bFound && !xFlatPara->isModified()) + aRes = aTmpRes; } + + return aRes; } -sal_Int32 GrammarCheckingIterator::getSuggestedEndOfSentence( const OUString aText, sal_Int32 nSentenceStartPos, const lang::Locale aLocale ) -{ - // TODO: Exchange the default return implementation for "getEndOfSentence" !!! - // Exchange the default return implementation. - // NOTE: Default initialized polymorphic structs can cause problems because of - // missing default initialization of primitive types of some C++ compilers or - // different Any initialization in Java and C++ polymorphic structs. + +sal_Int32 GrammarCheckingIterator::GetSuggestedEndOfSentence( + const OUString &rText, + sal_Int32 nSentenceStartPos, + const lang::Locale &rLocale ) +{ + // internal method; will always be called with locked mutex + uno::Reference< i18n::XBreakIterator > xBreakIterator; - if(!xBreakIterator.is()) + if (!m_xBreakIterator.is()) { - xBreakIterator=vcl::unohelper::CreateBreakIterator(); + m_xBreakIterator = vcl::unohelper::CreateBreakIterator(); } - sal_Int32 nEndPosition=0; - if(xBreakIterator.is()) + sal_Int32 nTextLen = rText.getLength(); + sal_Int32 nEndPosition = nTextLen; + if (m_xBreakIterator.is()) { - nEndPosition=xBreakIterator->endOfSentence(aText, nSentenceStartPos, aLocale); + sal_Int32 nTmpStartPos = nSentenceStartPos; + do + { + nEndPosition = nTextLen; + if (nTmpStartPos < nTextLen) + nEndPosition = m_xBreakIterator->endOfSentence( rText, nTmpStartPos, rLocale ); + ++nTmpStartPos; + } + while (nEndPosition <= nSentenceStartPos && nEndPosition < nTextLen); + if (nEndPosition > nTextLen) + nEndPosition = nTextLen; } return nEndPosition; } -sal_Int32 SAL_CALL GrammarCheckingIterator::getEndOfSentence( sal_Int32 nSentenceStartPos ) - throw (uno::RuntimeException, lang::IllegalArgumentException) -{ - // TODO: Exchange the default return implementation for "getEndOfSentence" !!! - // Exchange the default return implementation. - // NOTE: Default initialized polymorphic structs can cause problems because of - // missing default initialization of primitive types of some C++ compilers or - // different Any initialization in Java and C++ polymorphic structs. +sal_Int32 SAL_CALL GrammarCheckingIterator::getEndOfSentence( + const uno::Reference< text::XFlatParagraph >& xFlatPara, + sal_Int32 nSentenceStartPos ) +throw (lang::IllegalArgumentException, uno::RuntimeException) +{ + ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex ); + (void) xFlatPara; (void)nSentenceStartPos; - /*uno::Reference< i18n::XBreakIterator > xBreakIterator; - if(!xBreakIterator.is()) - { - xBreakIterator=vcl::unohelper::CreateBreakIterator(); - } - sal_Int32 nEndPosition=0; - if(xBreakIterator.is()) - { - - struct FPEntry aNewFPEntry=m_aFPQueue.front(); - uno::Reference< text::XFlatParagraph > xFlatPara( uno::Reference< text::XFlatParagraph >( aNewFPEntry.xPara ), uno::UNO_QUERY ); - if(xFlatPara.is()) - { - OUString aCurTxt = xFlatPara->getText(); - lang::Locale aCurLocale=getPrimaryLanguageOfSentence(xFlatPara, 0); - nEndPosition=xBreakIterator->endOfSentence(aCurTxt, nSentenceStartPos, aCurLocale); - } - } - return nEndPosition;*/ return 0; - } -::sal_Bool SAL_CALL GrammarCheckingIterator::isChecking( const uno::Reference< ::uno::XInterface > & xDoc ) - throw (uno::RuntimeException) + +sal_Bool SAL_CALL GrammarCheckingIterator::isGrammarChecking( + const uno::Reference< uno::XInterface >& xDoc, + sal_Bool bAutomatic ) +throw (uno::RuntimeException) { - // TODO: Exchange the default return implementation for "isChecking" !!! - // Exchange the default return implementation. - // NOTE: Default initialized polymorphic structs can cause problems because of - // missing default initialization of primitive types of some C++ compilers or - // different Any initialization in Java and C++ polymorphic structs. - osl::Guard< osl::Mutex > aGuard(GetMutex()); - sal_Bool bCheck=sal_False; - if(m_aDocMap.find(xDoc) != m_aDocMap.end()) + // ---- THREAD SAFE START ---- + ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex ); + + (void) bAutomatic; + sal_Bool bRes = sal_False; + + uno::Reference< lang::XComponent > xComponent( xDoc, uno::UNO_QUERY ); + if (xComponent.is()) { - sal_Int32 nDocID = m_aDocMap[xDoc]; - if(!m_aFPQueue.empty()) + sal_Int32 nDocId = m_aDocIdMap[ xComponent ]; + if (m_nCurCheckedDocId >= 0 && m_nCurCheckedDocId == nDocId) + bRes = sal_True; + else if (m_aDocIdMap.find( xComponent ) != m_aDocIdMap.end()) { - sal_Int32 nSize = m_aFPQueue.size(); - for( sal_Int32 i=0; i < nSize; ++i ) + sal_Int32 nSize = m_aFPEntriesQueue.size(); + for (sal_Int32 i = 0; i < nSize && !bRes; ++i) { - FPEntry aNewFPEntry = m_aFPQueue[i]; - if( nDocID == aNewFPEntry.m_nDocID ) - { - return true; - } + if (nDocId == m_aFPEntriesQueue[i].m_nDocId /*&& m_aFPEntriesQueue[i].m_bAutomatic == bAutomatic*/) + bRes = sal_True; } } } - return bCheck; - + // ---- THREAD SAFE END ---- + + return bRes; } -// linguistic2::XGrammarCheckingResultListener: -::sal_Bool SAL_CALL GrammarCheckingIterator::GrammarCheckingFinished( const linguistic2::GrammarCheckingResult & aRes ) - throw (uno::RuntimeException, lang::IllegalArgumentException) -{ - // TODO: Exchange the default return implementation for "GrammarCheckingFinished" !!! - // Exchange the default return implementation. - // NOTE: Default initialized polymorphic structs can cause problems because of - // missing default initialization of primitive types of some C++ compilers or - // different Any initialization in Java and C++ polymorphic structs. - - //mark the error sign - uno::Sequence< linguistic2::SingleGrammarError > aErrors=aRes.aGrammarErrors; - if(aErrors.getLength()>0) +void SAL_CALL GrammarCheckingIterator::processLinguServiceEvent( + const linguistic2::LinguServiceEvent& rLngSvcEvent ) +throw (uno::RuntimeException) +{ + if (rLngSvcEvent.nEvent == linguistic2::LinguServiceEventFlags::GRAMMAR_CHECK_AGAIN) { - for( sal_Int16 i=0; i < aErrors.getLength(); ++i) + try { - - linguistic2::SingleGrammarError aError = aErrors[aErrors.getLength()-1-i]; - /////////////////////////////////////////////////////////////////////////////////////////////// - //spelling checkers and grammar checkers spontaneously simultaneously check the same sentence// - //linguistic::GetLinguProperties()???????????????????????????????????????????????????????????? - /////////////////////////////////////////////////////////////////////////////////////////////// - - uno::Sequence< beans::PropertyValue > aAttributes; - OUString aIdentifier; - uno::Reference< container::XStringKeyMap > xStringKeyMap; - //display the grammar error mark - aRes.xPara->commitTextMarkup(aError.nErrorType, aIdentifier ,aError.nErrorStart ,aError.nErrorLen, xStringKeyMap); - + uno::Reference< uno::XInterface > xThis(*this); + linguistic2::LinguServiceEvent aEvent( xThis, linguistic2::LinguServiceEventFlags::GRAMMAR_CHECK_AGAIN ); + m_aNotifyListeners.notifyEach( + &linguistic2::XLinguServiceEventListener::processLinguServiceEvent, + aEvent); + } + catch (uno::RuntimeException &) + { + throw; + } + catch (::uno::Exception &rE) + { + (void) rE; + // ignore + DBG_WARNING1("processLinguServiceEvent: exception:\n%s", + OUStringToOString(rE.Message, RTL_TEXTENCODING_UTF8).getStr()); } } +} - sal_Bool bResult=aRes.nEndOfSentencePos < aRes.xPara->getText().getLength(); - aRes.xPara->setChecked(text::TextMarkupType::GRAMMAR, bResult); - return bResult; + +sal_Bool SAL_CALL GrammarCheckingIterator::addLinguServiceEventListener( + const uno::Reference< linguistic2::XLinguServiceEventListener >& xListener ) +throw (uno::RuntimeException) +{ + if (xListener.is()) + { +// ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex ); + m_aNotifyListeners.addInterface( xListener ); + } + return sal_True; } -/*// linguistic2::XGrammarCheckingResultListener: -void SAL_CALL GrammarCheckingIterator::processGrammarCheckingResult( - com::sun::star::linguistic2::GrammarCheckingResult aRes, - sal_Bool bLastInCurrentPara) - throw (uno::RuntimeException) + +sal_Bool SAL_CALL GrammarCheckingIterator::removeLinguServiceEventListener( + const uno::Reference< linguistic2::XLinguServiceEventListener >& xListener ) +throw (uno::RuntimeException) { - (void) aRes; - (void) bLastInCurrentPara; -}*/ + if (xListener.is()) + { +// ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex ); + m_aNotifyListeners.removeInterface( xListener ); + } + return sal_True; +} + -void SAL_CALL GrammarCheckingIterator::dispose( ) throw (uno::RuntimeException) +void SAL_CALL GrammarCheckingIterator::dispose() +throw (uno::RuntimeException) { + lang::EventObject aEvt( (linguistic2::XGrammarCheckingIterator *) this ); + m_aEventListeners.disposeAndClear( aEvt ); + + // + // now end the thread... + // + m_aRequestEndThread.reset(); + // ---- THREAD SAFE START ---- + { + ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex ); + m_bEnd = sal_True; + } + // ---- THREAD SAFE END ---- + m_aWakeUpThread.set(); + const TimeValue aTime = { 3, 0 }; // wait 3 seconds... + m_aRequestEndThread.wait( &aTime ); + // if the call ends because of time-out we will end anyway... + + + // ---- THREAD SAFE START ---- + { + ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex ); + // releaase all UNO references + + m_xMSF.clear(); + m_xBreakIterator.clear(); + + // clear containers with UNO references AND have those references released + GCReferences_t aTmpEmpty1; + DocMap_t aTmpEmpty2; + FPQueue_t aTmpEmpty3; + m_aGCReferencesByService.swap( aTmpEmpty1 ); + m_aDocIdMap.swap( aTmpEmpty2 ); + m_aFPEntriesQueue.swap( aTmpEmpty3 ); + } + // ---- THREAD SAFE END ---- } - -void SAL_CALL GrammarCheckingIterator::addEventListener( const uno::Reference< lang::XEventListener >& xListener ) - throw (uno::RuntimeException) + + +void SAL_CALL GrammarCheckingIterator::addEventListener( + const uno::Reference< lang::XEventListener >& xListener ) +throw (uno::RuntimeException) +{ + if (xListener.is()) + { +// ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex ); + m_aEventListeners.addInterface( xListener ); + } +} + + +void SAL_CALL GrammarCheckingIterator::removeEventListener( + const uno::Reference< lang::XEventListener >& xListener ) +throw (uno::RuntimeException) +{ + if (xListener.is()) + { +// ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex ); + m_aEventListeners.removeInterface( xListener ); + } +} + + +void SAL_CALL GrammarCheckingIterator::disposing( const lang::EventObject &rSource ) +throw (uno::RuntimeException) +{ + // if the component (document) is disposing release all references + //!! There is no need to remove entries from the queue that are from this document + //!! since the respectives xFlatParagraphs should become invalid (isModified() == true) + //!! and the call to xFlatParagraphIterator->getNextPara() will result in an empty reference. + //!! And if an entry is currently checked by a grammar checker upon return the results + //!! should be ignored. + //!! All of the above resulting in that we only have to get rid of all references here. + uno::Reference< lang::XComponent > xDoc( rSource.Source, uno::UNO_QUERY ); + if (xDoc.is()) + { + // ---- THREAD SAFE START ---- + ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex ); + m_aDocIdMap.erase( xDoc ); + // ---- THREAD SAFE END ---- + } +} + + +uno::Reference< util::XChangesBatch > GrammarCheckingIterator::GetUpdateAccess() const { - (void) xListener; + if (!m_xUpdateAccess.is()) + { + try + { + // get configuration provider + uno::Reference< lang::XMultiServiceFactory > xConfigurationProvider; + uno::Reference< lang::XMultiServiceFactory > xMgr = utl::getProcessServiceFactory(); + if (xMgr.is()) + { + xConfigurationProvider = uno::Reference< lang::XMultiServiceFactory > ( + xMgr->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.configuration.ConfigurationProvider" ) ) ), + uno::UNO_QUERY_THROW ) ; + } + + // get configuration update access + beans::PropertyValue aValue; + aValue.Name = A2OU( "nodepath" ); + aValue.Value = uno::makeAny( A2OU("org.openoffice.Office.Linguistic/ServiceManager") ); + uno::Sequence< uno::Any > aProps(1); + aProps[0] <<= aValue; + m_xUpdateAccess = uno::Reference< util::XChangesBatch >( + xConfigurationProvider->createInstanceWithArguments( + A2OU( "com.sun.star.configuration.ConfigurationUpdateAccess" ), aProps ), + uno::UNO_QUERY_THROW ); + } + catch (uno::Exception &) + { + } + } + + return m_xUpdateAccess; } -void SAL_CALL GrammarCheckingIterator::removeEventListener( const uno::Reference< lang::XEventListener >& xListener ) - throw (uno::RuntimeException) +/* +void GrammarCheckingIterator::GetConfiguredGCSvcs_Impl() { - (void) xListener; + GCImplNames_t aTmpGCImplNamesByLang; + + try + { + // get node names (locale iso strings) for configured grammar checkers + uno::Reference< container::XNameAccess > xNA( GetUpdateAccess(), uno::UNO_QUERY_THROW ); + xNA.set( xNA->getByName( A2OU("GrammarCheckerList") ), uno::UNO_QUERY_THROW ); + const uno::Sequence< OUString > aElementNames( xNA->getElementNames() ); + const OUString *pElementNames = aElementNames.getConstArray(); + + sal_Int32 nLen = aElementNames.getLength(); + for (sal_Int32 i = 0; i < nLen; ++i) + { + uno::Sequence< OUString > aImplNames; + uno::Any aTmp( xNA->getByName( pElementNames[i] ) ); + if (aTmp >>= aImplNames) + { + if (aImplNames.getLength() > 0) + { + // only the first entry is used, there should be only one grammar checker per language + const OUString aImplName( aImplNames[0] ); + const LanguageType nLang = MsLangId::convertIsoStringToLanguage( pElementNames[i] ); + aTmpGCImplNamesByLang[ nLang ] = aImplName; + } + } + else + { + DBG_ASSERT( 0, "failed to get aImplNames. Wrong type?" ); + } + } + } + catch (uno::Exception &) + { + DBG_ASSERT( 0, "exception caught. Failed to get configured services" ); + } + + { + // ---- THREAD SAFE START ---- + ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex ); + m_aGCImplNamesByLang = aTmpGCImplNamesByLang; + // ---- THREAD SAFE END ---- + } } +*/ -const void GrammarCheckingIterator::GetAvailableGCSvcs_Impl() +void GrammarCheckingIterator::GetMatchingGCSvcs_Impl() { - uno::Reference< lang::XMultiServiceFactory > xFac( getProcessServiceFactory() ); - if (xFac.is()) + GCImplNames_t aTmpGCImplNamesByLang; + + try { - uno::Reference< container::XContentEnumerationAccess > xEnumAccess( xFac, uno::UNO_QUERY ); + // get node names (locale iso strings) for configured grammar checkers + uno::Reference< container::XNameAccess > xNA( GetUpdateAccess(), uno::UNO_QUERY_THROW ); + xNA.set( xNA->getByName( A2OU("GrammarCheckers") ), uno::UNO_QUERY_THROW ); + const uno::Sequence< OUString > aGCImplNames( xNA->getElementNames() ); + const OUString *pGCImplNames = aGCImplNames.getConstArray(); + + sal_Int32 nLen = aGCImplNames.getLength(); + for (sal_Int32 i = 0; i < nLen; ++i) + { + uno::Reference< container::XNameAccess > xTmpNA( xNA->getByName( pGCImplNames[i] ), uno::UNO_QUERY_THROW ); + uno::Any aTmp( xTmpNA->getByName( A2OU("Locales") ) ); + uno::Sequence< OUString > aIsoLocaleNames; + if (aTmp >>= aIsoLocaleNames) + { + const OUString *pIsoLocaleNames = aIsoLocaleNames.getConstArray(); + for (sal_Int32 k = 0; k < aIsoLocaleNames.getLength(); ++k) + { + // if there are more grammar checkers for one language, for the time being, + // the last one found here will win... + const LanguageType nLang = MsLangId::convertIsoStringToLanguage( pIsoLocaleNames[k] ); + aTmpGCImplNamesByLang[ nLang ] = pGCImplNames[i]; + } + } + else + { + DBG_ASSERT( 0, "failed to get aImplNames. Wrong type?" ); + } + } + } + catch (uno::Exception &) + { + DBG_ASSERT( 0, "exception caught. Failed to get matching grammar checker services" ); + } + + { + // ---- THREAD SAFE START ---- + ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex ); + m_aGCImplNamesByLang = aTmpGCImplNamesByLang; + // ---- THREAD SAFE END ---- + } +} + + +/* +void GrammarCheckingIterator::GetAvailableGCSvcs_Impl() +{ + // internal method; will always be called with locked mutex + if (m_xMSF.is()) + { + uno::Reference< container::XContentEnumerationAccess > xEnumAccess( m_xMSF, uno::UNO_QUERY ); uno::Reference< container::XEnumeration > xEnum; if (xEnumAccess.is()) - xEnum = xEnumAccess->createContentEnumeration( - A2OU( "com.sun.star.lingu2.GrammarChecker" ) );//SN_SPELLCHECKER + xEnum = xEnumAccess->createContentEnumeration( A2OU( SN_GRAMMARCHECKER ) ); if (xEnum.is()) { while (xEnum->hasMoreElements()) { uno::Any aCurrent = xEnum->nextElement(); + uno::Reference< lang::XSingleComponentFactory > xCompFactory; uno::Reference< lang::XSingleServiceFactory > xFactory; - if (!::cppu::extractInterface( xFactory, aCurrent )) - continue; + uno::Reference< uno::XComponentContext > xContext; + uno::Reference< beans::XPropertySet > xProps( m_xMSF, uno::UNO_QUERY ); + xProps->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ))) >>= xContext; - uno::Reference< linguistic2::XGrammarChecker > xSvc( xFactory->createInstance(), uno::UNO_QUERY ); - if (xSvc.is()) + if ( xContext.is() && + (cppu::extractInterface( xCompFactory, aCurrent ) || + cppu::extractInterface( xFactory, aCurrent )) ) { - OUString aImplName; - //uno::Sequence< INT16 > aLanguages; - uno::Reference< XServiceInfo > xInfo( xSvc, uno::UNO_QUERY ); - if (xInfo.is()) - aImplName = xInfo->getImplementationName(); - DBG_ASSERT( aImplName.getLength(), - "empty implementation name" ); - uno::Reference< linguistic2::XSupportedLocales > xSuppLoc( xSvc, uno::UNO_QUERY ); - DBG_ASSERT( xSuppLoc.is(), "interfaces not supported" ); - if (xSuppLoc.is()) { - uno::Sequence< lang::Locale > aLocaleSequence(xSuppLoc->getLocales()); - m_aGCLocales[aImplName]=aLocaleSequence; - //aLanguages = LocaleSeqToLangSeq( aLocaleSequence ); + try + { + uno::Reference< linguistic2::XGrammarChecker > xSvc( ( xCompFactory.is() ? xCompFactory->createInstanceWithContext( xContext ) : xFactory->createInstance() ), uno::UNO_QUERY ); + if (xSvc.is()) + { + OUString aImplName; + uno::Reference< XServiceInfo > xInfo( xSvc, uno::UNO_QUERY ); + if (xInfo.is()) + aImplName = xInfo->getImplementationName(); + DBG_ASSERT( aImplName.getLength(), "empty implementation name" ); + uno::Reference< linguistic2::XSupportedLocales > xSuppLoc( xSvc, uno::UNO_QUERY ); + DBG_ASSERT( xSuppLoc.is(), "interfaces not supported" ); + if (xSuppLoc.is() && aImplName.getLength() > 0) + { + uno::Sequence< lang::Locale > aLocaleSequence( xSuppLoc->getLocales() ); + // ---- THREAD SAFE START ---- + ::osl::Guard< ::osl::Mutex > aGuard( m_aMutex ); + m_aGCLocalesByService[ aImplName ] = aLocaleSequence; + m_aGCReferencesByService[ aImplName ] = xSvc; + // ---- THREAD SAFE END ---- + } + } + } + catch (uno::Exception &) + { + DBG_ASSERT( 0, "instantiating grammar checker failed" ); } - - //pAvailSpellSvcs->Insert( new SvcInfo( aImplName, aLanguages ), - // pAvailSpellSvcs->Count() ); - //m_aGCLocales[aImplName]=aLocaleSequence;//aLanguages; } } } } } +*/ -sal_Bool SAL_CALL GrammarCheckingIterator::supportsService( const OUString& ServiceName ) throw(uno::RuntimeException) -{ - osl::Guard< osl::Mutex > aGuard(GetMutex()); +sal_Bool SAL_CALL GrammarCheckingIterator::supportsService( + const OUString & rServiceName ) +throw(uno::RuntimeException) +{ uno::Sequence< OUString > aSNL = getSupportedServiceNames(); const OUString * pArray = aSNL.getConstArray(); for( INT32 i = 0; i < aSNL.getLength(); ++i ) - if( pArray[i] == ServiceName ) + if( pArray[i] == rServiceName ) return TRUE; return FALSE; } -uno::Sequence< OUString > GrammarCheckingIterator::getSupportedServiceNames_Static() throw() -{ - //osl::Guard< osl::Mutex > aGuard(GetMutex()); - uno::Sequence< OUString > aSNS( 1 ); // auch mehr als 1 Service moeglich - aSNS.getArray()[0] = A2OU( "com.sun.star.linguistic2.GrammarCheckingIterator" );//SN_LINGU_SERVCICE_MANAGER - return aSNS; +OUString SAL_CALL GrammarCheckingIterator::getImplementationName( ) throw (uno::RuntimeException) +{ + return GrammarCheckingIterator_getImplementationName(); } -uno::Sequence< OUString > SAL_CALL GrammarCheckingIterator::getSupportedServiceNames() throw(uno::RuntimeException) + +uno::Sequence< OUString > SAL_CALL GrammarCheckingIterator::getSupportedServiceNames( ) throw (uno::RuntimeException) { - osl::Guard< osl::Mutex > aGuard(GetMutex()); - return getSupportedServiceNames_Static(); + return GrammarCheckingIterator_getSupportedServiceNames(); } -OUString SAL_CALL GrammarCheckingIterator::getImplementationName() throw(uno::RuntimeException) + +/////////////////////////////////////////////////////////////////////////// + + +static OUString GrammarCheckingIterator_getImplementationName() throw() { - osl::Guard< osl::Mutex > aGuard(GetMutex()); - return getImplementationName_Static(); + return A2OU( "com.sun.star.lingu2.GrammarCheckingIterator" ); } -sal_Bool SAL_CALL GrammarCheckingIterator_writeInfo( void * /*pServiceManager*/, registry::XRegistryKey * pRegistryKey ) -{ - try - { - String aImpl( '/' ); - aImpl += GrammarCheckingIterator::getImplementationName_Static().getStr(); - aImpl.AppendAscii( "/UNO/SERVICES" ); - uno::Reference< registry::XRegistryKey > xNewKey = - pRegistryKey->createKey( aImpl ); - uno::Sequence< OUString > aServices = GrammarCheckingIterator::getSupportedServiceNames_Static(); - for( INT32 i = 0; i < aServices.getLength(); ++i ) - xNewKey->createKey( aServices.getConstArray()[i] ); - return sal_True; - } - catch(uno::Exception &) - { - return sal_False; - } +static uno::Sequence< OUString > GrammarCheckingIterator_getSupportedServiceNames() throw() +{ + uno::Sequence< OUString > aSNS( 1 ); + aSNS.getArray()[0] = A2OU( "com.sun.star.linguistic2.GrammarCheckingIterator" ); + return aSNS; } -uno::Reference< uno::XInterface > SAL_CALL GrammarCheckingIterator_CreateInstance( - const uno::Reference< lang::XMultiServiceFactory > & /*rSMgr*/ ) - throw(uno::Exception) + +static uno::Reference< uno::XInterface > SAL_CALL GrammarCheckingIterator_createInstance( + const uno::Reference< lang::XMultiServiceFactory > & rxSMgr ) +throw(uno::Exception) { - uno::Reference< uno::XInterface > xService = (cppu::OWeakObject*) new GrammarCheckingIterator; - return xService; + return static_cast< ::cppu::OWeakObject * >(new GrammarCheckingIterator( rxSMgr )); } + void * SAL_CALL GrammarCheckingIterator_getFactory( - const sal_Char * pImplName, - lang::XMultiServiceFactory * pServiceManager, + const sal_Char *pImplName, + lang::XMultiServiceFactory *pServiceManager, void * /*pRegistryKey*/ ) { - void * pRet = 0; - if ( !GrammarCheckingIterator::getImplementationName_Static().compareToAscii( pImplName ) ) + if ( !GrammarCheckingIterator_getImplementationName().compareToAscii( pImplName ) ) { uno::Reference< lang::XSingleServiceFactory > xFactory = cppu::createOneInstanceFactory( pServiceManager, - GrammarCheckingIterator::getImplementationName_Static(), - GrammarCheckingIterator_CreateInstance, - GrammarCheckingIterator::getSupportedServiceNames_Static()); + GrammarCheckingIterator_getImplementationName(), + GrammarCheckingIterator_createInstance, + GrammarCheckingIterator_getSupportedServiceNames()); // acquire, because we return an interface pointer instead of a reference xFactory->acquire(); pRet = xFactory.get(); @@ -621,3 +1056,26 @@ void * SAL_CALL GrammarCheckingIterator_getFactory( return pRet; } + +sal_Bool SAL_CALL GrammarCheckingIterator_writeInfo( + void * /*pServiceManager*/, + registry::XRegistryKey * pRegistryKey ) +{ + try + { + OUString aImpl( '/' ); + aImpl += GrammarCheckingIterator_getImplementationName().getStr(); + aImpl += A2OU( "/UNO/SERVICES" ); + uno::Reference< registry::XRegistryKey > xNewKey = pRegistryKey->createKey( aImpl ); + uno::Sequence< OUString > aServices = GrammarCheckingIterator_getSupportedServiceNames(); + for( sal_Int32 i = 0; i < aServices.getLength(); i++ ) + xNewKey->createKey( aServices.getConstArray()[i] ); + + return sal_True; + } + catch (uno::Exception &) + { + return sal_False; + } +} + |