xref: /trunk/main/linguistic/source/thesdsp.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_linguistic.hxx"
30 #include <i18npool/lang.h>
31 #include <tools/debug.hxx>
32 #include <svl/lngmisc.hxx>
33 
34 #include <cppuhelper/factory.hxx>   // helper for factories
35 #include <com/sun/star/registry/XRegistryKey.hpp>
36 #include <com/sun/star/beans/XPropertySet.hpp>
37 #include <unotools/processfactory.hxx>
38 #include <osl/mutex.hxx>
39 
40 #include "thesdsp.hxx"
41 #include "linguistic/lngprops.hxx"
42 
43 using namespace utl;
44 using namespace osl;
45 using namespace rtl;
46 using namespace com::sun::star;
47 using namespace com::sun::star::beans;
48 using namespace com::sun::star::lang;
49 using namespace com::sun::star::uno;
50 using namespace com::sun::star::linguistic2;
51 using namespace linguistic;
52 
53 ///////////////////////////////////////////////////////////////////////////
54 
55 static sal_Bool SvcListHasLanguage(
56         const Sequence< Reference< XThesaurus > > &rRefs,
57         const Locale &rLocale )
58 {
59     sal_Bool bHasLanguage = sal_False;
60 
61     const Reference< XThesaurus > *pRef = rRefs.getConstArray();
62     sal_Int32 nLen = rRefs.getLength();
63     for (sal_Int32 k = 0;  k < nLen  &&  !bHasLanguage;  ++k)
64     {
65         if (pRef[k].is())
66             bHasLanguage = pRef[k]->hasLocale( rLocale );
67     }
68 
69     return bHasLanguage;
70 }
71 
72 ///////////////////////////////////////////////////////////////////////////
73 
74 
75 ThesaurusDispatcher::ThesaurusDispatcher()
76 {
77 }
78 
79 
80 ThesaurusDispatcher::~ThesaurusDispatcher()
81 {
82     ClearSvcList();
83 }
84 
85 
86 void ThesaurusDispatcher::ClearSvcList()
87 {
88     // release memory for each table entry
89     ThesSvcByLangMap_t aTmp;
90     aSvcMap.swap( aTmp );
91 }
92 
93 
94 Sequence< Locale > SAL_CALL
95     ThesaurusDispatcher::getLocales()
96         throw(RuntimeException)
97 {
98     MutexGuard  aGuard( GetLinguMutex() );
99 
100     Sequence< Locale > aLocales( static_cast< sal_Int32 >(aSvcMap.size()) );
101     Locale *pLocales = aLocales.getArray();
102     ThesSvcByLangMap_t::const_iterator aIt;
103     for (aIt = aSvcMap.begin();  aIt != aSvcMap.end();  ++aIt)
104     {
105         *pLocales++ = CreateLocale( aIt->first );
106     }
107     return aLocales;
108 }
109 
110 
111 sal_Bool SAL_CALL
112     ThesaurusDispatcher::hasLocale( const Locale& rLocale )
113         throw(RuntimeException)
114 {
115     MutexGuard  aGuard( GetLinguMutex() );
116     ThesSvcByLangMap_t::const_iterator aIt( aSvcMap.find( LocaleToLanguage( rLocale ) ) );
117     return aIt != aSvcMap.end();
118 }
119 
120 
121 Sequence< Reference< XMeaning > > SAL_CALL
122     ThesaurusDispatcher::queryMeanings(
123             const OUString& rTerm, const Locale& rLocale,
124             const PropertyValues& rProperties )
125         throw(IllegalArgumentException, RuntimeException)
126 {
127     MutexGuard  aGuard( GetLinguMutex() );
128 
129     Sequence< Reference< XMeaning > >   aMeanings;
130 
131     sal_Int16 nLanguage = LocaleToLanguage( rLocale );
132     if (nLanguage == LANGUAGE_NONE  || !rTerm.getLength())
133         return aMeanings;
134 
135     // search for entry with that language
136     ThesSvcByLangMap_t::iterator    aIt( aSvcMap.find( nLanguage ) );
137     LangSvcEntries_Thes     *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
138 
139     if (!pEntry)
140     {
141 #ifdef LINGU_EXCEPTIONS
142         throw IllegalArgumentException();
143 #endif
144     }
145     else
146     {
147         OUString aChkWord( rTerm );
148         aChkWord = aChkWord.replace( SVT_HARD_SPACE, ' ' );
149         RemoveHyphens( aChkWord );
150         if (IsIgnoreControlChars( rProperties, GetPropSet() ))
151             RemoveControlChars( aChkWord );
152 
153         sal_Int32 nLen = pEntry->aSvcRefs.getLength();
154         DBG_ASSERT( nLen == pEntry->aSvcImplNames.getLength(),
155                 "lng : sequence length mismatch");
156         DBG_ASSERT( pEntry->nLastTriedSvcIndex < nLen,
157                 "lng : index out of range");
158 
159         sal_Int32 i = 0;
160 
161         // try already instantiated services first
162         {
163             const Reference< XThesaurus > *pRef = pEntry->aSvcRefs.getConstArray();
164             while (i <= pEntry->nLastTriedSvcIndex
165                    &&  aMeanings.getLength() == 0)
166             {
167                 if (pRef[i].is()  &&  pRef[i]->hasLocale( rLocale ))
168                     aMeanings = pRef[i]->queryMeanings( aChkWord, rLocale, rProperties );
169                 ++i;
170             }
171         }
172 
173         // if still no result instantiate new services and try those
174         if (aMeanings.getLength() == 0
175             &&  pEntry->nLastTriedSvcIndex < nLen - 1)
176         {
177             const OUString *pImplNames = pEntry->aSvcImplNames.getConstArray();
178             Reference< XThesaurus > *pRef = pEntry->aSvcRefs.getArray();
179 
180             Reference< XMultiServiceFactory >  xMgr( getProcessServiceFactory() );
181             if (xMgr.is())
182             {
183                 // build service initialization argument
184                 Sequence< Any > aArgs(1);
185                 aArgs.getArray()[0] <<= GetPropSet();
186 
187                 while (i < nLen  &&  aMeanings.getLength() == 0)
188                 {
189                     // create specific service via it's implementation name
190                     Reference< XThesaurus > xThes;
191                     try
192                     {
193                         xThes = Reference< XThesaurus >(
194                                 xMgr->createInstanceWithArguments(
195                                 pImplNames[i], aArgs ), UNO_QUERY );
196                     }
197                     catch (uno::Exception &)
198                     {
199                         DBG_ASSERT( 0, "createInstanceWithArguments failed" );
200                     }
201                     pRef[i] = xThes;
202 
203                     if (xThes.is()  &&  xThes->hasLocale( rLocale ))
204                         aMeanings = xThes->queryMeanings( aChkWord, rLocale, rProperties );
205 
206                     pEntry->nLastTriedSvcIndex = (sal_Int16) i;
207                     ++i;
208                 }
209 
210                 // if language is not supported by any of the services
211                 // remove it from the list.
212                 if (i == nLen  &&  aMeanings.getLength() == 0)
213                 {
214                     if (!SvcListHasLanguage( pEntry->aSvcRefs, rLocale ))
215                         aSvcMap.erase( nLanguage );
216                 }
217             }
218         }
219     }
220 
221     return aMeanings;
222 }
223 
224 
225 void ThesaurusDispatcher::SetServiceList( const Locale &rLocale,
226         const Sequence< OUString > &rSvcImplNames )
227 {
228     MutexGuard  aGuard( GetLinguMutex() );
229 
230     sal_Int16 nLanguage = LocaleToLanguage( rLocale );
231 
232     sal_Int32 nLen = rSvcImplNames.getLength();
233     if (0 == nLen)
234         // remove entry
235         aSvcMap.erase( nLanguage );
236     else
237     {
238         // modify/add entry
239         LangSvcEntries_Thes *pEntry = aSvcMap[ nLanguage ].get();
240         if (pEntry)
241         {
242             pEntry->Clear();
243             pEntry->aSvcImplNames = rSvcImplNames;
244             pEntry->aSvcRefs = Sequence< Reference < XThesaurus > >( nLen );
245         }
246         else
247         {
248             boost::shared_ptr< LangSvcEntries_Thes > pTmpEntry( new LangSvcEntries_Thes( rSvcImplNames ) );
249             pTmpEntry->aSvcRefs = Sequence< Reference < XThesaurus > >( nLen );
250             aSvcMap[ nLanguage ] = pTmpEntry;
251         }
252     }
253 }
254 
255 
256 Sequence< OUString >
257     ThesaurusDispatcher::GetServiceList( const Locale &rLocale ) const
258 {
259     MutexGuard  aGuard( GetLinguMutex() );
260 
261     Sequence< OUString > aRes;
262 
263     // search for entry with that language and use data from that
264     sal_Int16 nLanguage = LocaleToLanguage( rLocale );
265     ThesaurusDispatcher             *pThis = (ThesaurusDispatcher *) this;
266     const ThesSvcByLangMap_t::iterator  aIt( pThis->aSvcMap.find( nLanguage ) );
267     const LangSvcEntries_Thes       *pEntry = aIt != aSvcMap.end() ? aIt->second.get() : NULL;
268     if (pEntry)
269         aRes = pEntry->aSvcImplNames;
270 
271     return aRes;
272 }
273 
274 
275 LinguDispatcher::DspType ThesaurusDispatcher::GetDspType() const
276 {
277     return DSP_THES;
278 }
279 
280 
281 ///////////////////////////////////////////////////////////////////////////
282 
283