1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: unolingu.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
39 #include <unolingu.hxx>
40 #include <tools/debug.hxx>
41 #include <tools/urlobj.hxx>
42 #include <rtl/logfile.hxx>
43 #include <svtools/pathoptions.hxx>
44 #include <com/sun/star/frame/XModel.hpp>
45 #include <com/sun/star/frame/XStorable.hpp>
46 #include <com/sun/star/lang/XEventListener.hpp>
47 #include <com/sun/star/linguistic2/XAvailableLocales.hpp>
48 #include <com/sun/star/ucb/XAnyCompareFactory.hpp>
49 #include <com/sun/star/ucb/XContentAccess.hpp>
50 #include <com/sun/star/ucb/XSortedDynamicResultSetFactory.hpp>
51 #include <com/sun/star/ucb/NumberedSortingInfo.hpp>
52 #include <com/sun/star/ucb/XContentAccess.hpp>
53 #include <com/sun/star/sdbc/XResultSet.hpp>
54 #include <com/sun/star/sdbc/XRow.hpp>
55 #include <com/sun/star/util/DateTime.hpp>
57 #include <comphelper/processfactory.hxx>
58 #include <cppuhelper/implbase1.hxx> // helper for implementations
59 #include <i18npool/mslangid.hxx>
60 #include <svtools/lingucfg.hxx>
61 #include <unotools/ucbhelper.hxx>
62 #include <unotools/localfilehelper.hxx>
63 #include <ucbhelper/commandenvironment.hxx>
64 #include <ucbhelper/content.hxx>
65 #include <comphelper/processfactory.hxx>
66 #include <vcl/msgbox.hxx>
67 #include <tools/shl.hxx>
68 #include <linguistic/misc.hxx>
69 #include <svx/dialmgr.hxx>
70 #include <svx/dialogs.hrc>
72 using namespace ::rtl
;
73 using namespace ::comphelper
;
74 using namespace ::linguistic
;
75 using namespace ::com::sun::star
;
76 using namespace ::com::sun::star::util
;
77 using namespace ::com::sun::star::uno
;
78 using namespace ::com::sun::star::lang
;
79 using namespace ::com::sun::star::beans
;
80 using namespace ::com::sun::star::frame
;
81 using namespace ::com::sun::star::linguistic2
;
83 #define CSS com::sun::star
85 ///////////////////////////////////////////////////////////////////////////
88 static uno::Reference
< XLinguServiceManager
> GetLngSvcMgr_Impl()
90 uno::Reference
< XLinguServiceManager
> xRes
;
91 uno::Reference
< XMultiServiceFactory
> xMgr
= getProcessServiceFactory();
94 xRes
= uno::Reference
< XLinguServiceManager
> ( xMgr
->createInstance(
95 OUString( RTL_CONSTASCII_USTRINGPARAM(
96 "com.sun.star.linguistic2.LinguServiceManager" ) ) ), UNO_QUERY
) ;
101 ///////////////////////////////////////////////////////////////////////////
103 BOOL
lcl_FindEntry( const OUString
&rEntry
, const Sequence
< OUString
> &rCfgSvcs
)
106 INT32 nEntries
= rCfgSvcs
.getLength();
107 const OUString
*pEntry
= rCfgSvcs
.getConstArray();
108 for (INT32 i
= 0; i
< nEntries
&& nRes
== -1; ++i
)
110 if (rEntry
== pEntry
[i
])
117 Sequence
< OUString
> lcl_RemoveMissingEntries(
118 const Sequence
< OUString
> &rCfgSvcs
,
119 const Sequence
< OUString
> &rAvailSvcs
)
121 Sequence
< OUString
> aRes( rCfgSvcs
.getLength() );
122 OUString
*pRes
= aRes
.getArray();
125 INT32 nEntries
= rCfgSvcs
.getLength();
126 const OUString
*pEntry
= rCfgSvcs
.getConstArray();
127 for (INT32 i
= 0; i
< nEntries
; ++i
)
129 if (pEntry
[i
].getLength() && lcl_FindEntry( pEntry
[i
], rAvailSvcs
))
130 pRes
[ nCnt
++ ] = pEntry
[i
];
133 aRes
.realloc( nCnt
);
138 Sequence
< OUString
> lcl_GetLastFoundSvcs(
139 SvtLinguConfig
&rCfg
,
140 const OUString
&rLastFoundList
,
141 const Locale
&rAvailLocale
)
143 Sequence
< OUString
> aRes
;
145 OUString
aCfgLocaleStr( MsLangId::convertLanguageToIsoString(
146 SvxLocaleToLanguage( rAvailLocale
) ) );
148 Sequence
< OUString
> aNodeNames( rCfg
.GetNodeNames(rLastFoundList
) );
149 BOOL bFound
= lcl_FindEntry( aCfgLocaleStr
, aNodeNames
);
153 Sequence
< OUString
> aNames(1);
154 OUString
&rNodeName
= aNames
.getArray()[0];
155 rNodeName
= rLastFoundList
;
156 rNodeName
+= OUString::valueOf( (sal_Unicode
)'/' );
157 rNodeName
+= aCfgLocaleStr
;
158 Sequence
< Any
> aValues( rCfg
.GetProperties( aNames
) );
159 #if OSL_DEBUG_LEVEL > 1
161 pValue
= aValues
.getConstArray();
163 if (aValues
.getLength())
165 DBG_ASSERT( aValues
.getLength() == 1, "unexpected length of sequence" );
166 Sequence
< OUString
> aSvcImplNames
;
167 if (aValues
.getConstArray()[0] >>= aSvcImplNames
)
168 aRes
= aSvcImplNames
;
171 DBG_ERROR( "type mismatch" );
180 Sequence
< OUString
> lcl_GetNewEntries(
181 const Sequence
< OUString
> &rLastFoundSvcs
,
182 const Sequence
< OUString
> &rAvailSvcs
)
184 INT32 nLen
= rAvailSvcs
.getLength();
185 Sequence
< OUString
> aRes( nLen
);
186 OUString
*pRes
= aRes
.getArray();
189 const OUString
*pEntry
= rAvailSvcs
.getConstArray();
190 for (INT32 i
= 0; i
< nLen
; ++i
)
192 if (pEntry
[i
].getLength() && !lcl_FindEntry( pEntry
[i
], rLastFoundSvcs
))
193 pRes
[ nCnt
++ ] = pEntry
[i
];
196 aRes
.realloc( nCnt
);
201 Sequence
< OUString
> lcl_MergeSeq(
202 const Sequence
< OUString
> &rCfgSvcs
,
203 const Sequence
< OUString
> &rNewSvcs
)
205 Sequence
< OUString
> aRes( rCfgSvcs
.getLength() + rNewSvcs
.getLength() );
206 OUString
*pRes
= aRes
.getArray();
209 for (INT32 k
= 0; k
< 2; ++k
)
211 // add previously configuerd service first and append
212 // new found services at the end
213 const Sequence
< OUString
> &rSeq
= k
== 0 ? rCfgSvcs
: rNewSvcs
;
215 INT32 nLen
= rSeq
.getLength();
216 const OUString
*pEntry
= rSeq
.getConstArray();
217 for (INT32 i
= 0; i
< nLen
; ++i
)
219 if (pEntry
[i
].getLength() && !lcl_FindEntry( pEntry
[i
], aRes
))
220 pRes
[ nCnt
++ ] = pEntry
[i
];
224 aRes
.realloc( nCnt
);
228 ///////////////////////////////////////////////////////////////////////////
230 // static member initialization
231 INT16
SvxLinguConfigUpdate::nNeedUpdating
= -1;
232 INT32
SvxLinguConfigUpdate::nCurrentDataFilesChangedCheckValue
= -1;
234 void SvxLinguConfigUpdate::UpdateAll( sal_Bool bForceCheck
)
236 RTL_LOGFILE_CONTEXT( aLog
, "svx: SvxLinguConfigUpdate::UpdateAll" );
238 if (IsNeedUpdateAll( bForceCheck
))
240 typedef OUString OUstring_t
;
241 typedef Sequence
< OUString
> Sequence_OUString_t
;
242 typedef std::vector
< OUstring_t
> OUString_vector_t
;
243 typedef std::set
< OUstring_t
> OUString_set_t
;
244 std::vector
< OUString_vector_t
> aVector
;
245 typedef std::map
< OUstring_t
, Sequence_OUString_t
> list_entry_map_t
;
247 RTL_LOGFILE_CONTEXT( aLog
, "svx: SvxLinguConfigUpdate::UpdateAll - updating..." );
249 DBG_ASSERT( nNeedUpdating
== 1, "SvxLinguConfigUpdate::UpdateAll already updated!" );
251 uno::Reference
< XLinguServiceManager
> xLngSvcMgr( GetLngSvcMgr_Impl() );
252 DBG_ASSERT( xLngSvcMgr
.is(), "service manager missing");
253 if (!xLngSvcMgr
.is())
258 const int nNumServices
= 4;
259 const sal_Char
* apServices
[nNumServices
] = { SN_SPELLCHECKER
, SN_GRAMMARCHECKER
, SN_HYPHENATOR
, SN_THESAURUS
};
260 const sal_Char
* apCurLists
[nNumServices
] = { "ServiceManager/SpellCheckerList", "ServiceManager/GrammarCheckerList", "ServiceManager/HyphenatorList", "ServiceManager/ThesaurusList" };
261 const sal_Char
* apLastFoundLists
[nNumServices
] = { "ServiceManager/LastFoundSpellCheckers", "ServiceManager/LastFoundGrammarCheckers", "ServiceManager/LastFoundHyphenators", "ServiceManager/LastFoundThesauri" };
263 // usage of indices as above: 0 = spell checker, 1 = grammar checker, 2 = hyphenator, 3 = thesaurus
264 std::vector
< list_entry_map_t
> aLastFoundSvcs(nNumServices
);
265 std::vector
< list_entry_map_t
> aCurSvcs(nNumServices
);
267 for (int k
= 0; k
< nNumServices
; ++k
)
269 OUString
aService( A2OU( apServices
[k
] ) );
270 OUString
aActiveList( A2OU( apCurLists
[k
] ) );
271 OUString
aLastFoundList( A2OU( apLastFoundLists
[k
] ) );
275 // remove configured but not available language/services entries
277 Sequence
< OUString
> aNodeNames( aCfg
.GetNodeNames( aActiveList
) ); // list of configured locales
278 INT32 nNodeNames
= aNodeNames
.getLength();
279 const OUString
*pNodeName
= aNodeNames
.getConstArray();
280 for (i
= 0; i
< nNodeNames
; ++i
)
282 Locale
aLocale( SvxCreateLocale( MsLangId::convertIsoStringToLanguage(pNodeName
[i
]) ) );
283 Sequence
< OUString
> aCfgSvcs(
284 xLngSvcMgr
->getConfiguredServices( aService
, aLocale
));
285 Sequence
< OUString
> aAvailSvcs(
286 xLngSvcMgr
->getAvailableServices( aService
, aLocale
));
287 #if OSL_DEBUG_LEVEL > 1
288 const OUString
* pCfgSvcs
= aCfgSvcs
.getConstArray();;
289 const OUString
* pAvailSvcs
= aAvailSvcs
.getConstArray();;
293 aCfgSvcs
= lcl_RemoveMissingEntries( aCfgSvcs
, aAvailSvcs
);
295 aCurSvcs
[k
][ pNodeName
[i
] ] = aCfgSvcs
;
299 // add new available language/servcice entries
301 uno::Reference
< XAvailableLocales
> xAvail( xLngSvcMgr
, UNO_QUERY
);
302 Sequence
< Locale
> aAvailLocales( xAvail
->getAvailableLocales(aService
) );
303 INT32 nAvailLocales
= aAvailLocales
.getLength();
304 const Locale
*pAvailLocale
= aAvailLocales
.getConstArray();
305 for (i
= 0; i
< nAvailLocales
; ++i
)
307 Sequence
< OUString
> aAvailSvcs(
308 xLngSvcMgr
->getAvailableServices( aService
, pAvailLocale
[i
] ));
309 Sequence
< OUString
> aLastSvcs(
310 lcl_GetLastFoundSvcs( aCfg
, aLastFoundList
, pAvailLocale
[i
] ));
311 Sequence
< OUString
> aNewSvcs
=
312 lcl_GetNewEntries( aLastSvcs
, aAvailSvcs
);
313 #if OSL_DEBUG_LEVEL > 1
314 const OUString
* pAvailSvcs
= aAvailSvcs
.getConstArray();
315 const OUString
* pLastSvcs
= aLastSvcs
.getConstArray();
316 const OUString
* pNewSvcs
= aNewSvcs
.getConstArray();
322 OUString
aCfgLocaleStr( MsLangId::convertLanguageToIsoString(
323 SvxLocaleToLanguage( pAvailLocale
[i
] ) ) );
324 Sequence
< OUString
> aCfgSvcs( aCurSvcs
[k
][ aCfgLocaleStr
] );
326 // merge services list (previously configured to be listed first).
327 aCfgSvcs
= lcl_MergeSeq( aCfgSvcs
, aNewSvcs
);
330 // there is at most one Hyphenator per language allowed
331 // to be configured, thus we only use the first one found.
332 if (k == 2 && aCfgSvcs.getLength() > 1)
335 aCurSvcs
[k
][ aCfgLocaleStr
] = aCfgSvcs
;
339 // set last found services to currently available ones
341 for (i
= 0; i
< nAvailLocales
; ++i
)
343 Sequence
< OUString
> aSvcImplNames(
344 xLngSvcMgr
->getAvailableServices( aService
, pAvailLocale
[i
] ) );
346 #if OSL_DEBUG_LEVEL > 1
347 INT32 nSvcs
= aSvcImplNames
.getLength();
348 const OUString
*pSvcImplName
= aSvcImplNames
.getConstArray();
349 for (INT32 j
= 0; j
< nSvcs
; ++j
)
351 OUString
aImplName( pSvcImplName
[j
] );
355 OUString
aCfgLocaleStr( MsLangId::convertLanguageToIsoString(
356 SvxLocaleToLanguage( pAvailLocale
[i
] ) ) );
357 aLastFoundSvcs
[k
][ aCfgLocaleStr
] = aSvcImplNames
;
362 // write new data back to configuration
364 for (int k
= 0; k
< nNumServices
; ++k
)
366 for (int i
= 0; i
< 2; ++i
)
368 const sal_Char
*pSubNodeName
= (i
== 0) ? apCurLists
[k
] : apLastFoundLists
[k
];
369 OUString
aSubNodeName( A2OU(pSubNodeName
) );
371 list_entry_map_t
&rCurMap
= (i
== 0) ? aCurSvcs
[k
] : aLastFoundSvcs
[k
];
372 list_entry_map_t::const_iterator
aIt( rCurMap
.begin() );
373 sal_Int32 nVals
= static_cast< sal_Int32
>( rCurMap
.size() );
374 Sequence
< PropertyValue
> aNewValues( nVals
);
375 PropertyValue
*pNewValue
= aNewValues
.getArray();
376 while (aIt
!= rCurMap
.end())
378 OUString
aCfgEntryName( aSubNodeName
);
379 aCfgEntryName
+= OUString::valueOf( (sal_Unicode
) '/' );
380 aCfgEntryName
+= (*aIt
).first
;
382 #if OSL_DEBUG_LEVEL > 1
383 Sequence
< OUString
> aSvcImplNames( (*aIt
).second
);
384 INT32 nSvcs
= aSvcImplNames
.getLength();
385 const OUString
*pSvcImplName
= aSvcImplNames
.getConstArray();
386 for (INT32 j
= 0; j
< nSvcs
; ++j
)
388 OUString
aImplName( pSvcImplName
[j
] );
391 pNewValue
->Name
= aCfgEntryName
;
392 pNewValue
->Value
<<= (*aIt
).second
;
396 DBG_ASSERT( pNewValue
- aNewValues
.getArray() == nVals
,
397 "possible mismatch of sequence size and property number" );
400 RTL_LOGFILE_CONTEXT( aLog
, "svx: SvxLinguConfigUpdate::UpdateAll - ReplaceSetProperties" );
401 // add new or replace existing entries.
402 BOOL bRes
= aCfg
.ReplaceSetProperties( aSubNodeName
, aNewValues
);
405 #if OSL_DEBUG_LEVEL > 1
406 DBG_ERROR( "failed to set new configuration values" );
412 DBG_ASSERT( nCurrentDataFilesChangedCheckValue
!= -1, "SvxLinguConfigUpdate::UpdateAll DataFilesChangedCheckValue not yet calculated!" );
415 // for the time being (developer builds until OOo 3.0)
416 // we should always check for everything available
417 // otherwise we may miss a new installed extension dicitonary
418 // just because e.g. the spellchecker is not asked what
419 // languages it does support currently...
420 // Since the check is on-demand occuring and executed once it should
421 // not be too troublesome.
422 // In OOo 3.0 we will not need the respective code anymore at all.
423 // aAny <<= nCurrentDataFilesChangedCheckValue;
424 aAny
<<= (INT32
) -1; // keep the value set to 'need to check'
426 aCfg
.SetProperty( A2OU( "DataFilesChangedCheckValue" ), aAny
);
428 //! Note 1: the new values are commited when the 'aCfg' object
430 //! Note 2: the new settings in the configuration get applied
431 //! because the 'LngSvcMgr' (in linguistic/source/lngsvcmgr.hxx)
432 //! listens to the configuration for changes of the relevant
433 //! properties and then applies the new settings.
435 // nothing needs to be done anymore
441 INT32
SvxLinguConfigUpdate::CalcDataFilesChangedCheckValue()
443 RTL_LOGFILE_CONTEXT( aLog
, "svx: SvxLinguConfigUpdate::CalcDataFilesChangedCheckValue" );
446 // nothing to be checked anymore since those old directory paths are gone by now
451 BOOL
SvxLinguConfigUpdate::IsNeedUpdateAll( sal_Bool bForceCheck
)
453 RTL_LOGFILE_CONTEXT( aLog
, "svx: SvxLinguConfigUpdate::IsNeedUpdateAll" );
454 if (nNeedUpdating
== -1 || bForceCheck
) // need to check if updating is necessary
456 // calculate hash value for current data files
457 nCurrentDataFilesChangedCheckValue
= CalcDataFilesChangedCheckValue();
459 // compare hash value and check value to see if anything has changed
460 // and thus the configuration needs to be updated
461 SvtLinguOptions aLinguOpt
;
463 aCfg
.GetOptions( aLinguOpt
);
464 nNeedUpdating
= (nCurrentDataFilesChangedCheckValue
== aLinguOpt
.nDataFilesChangedCheckValue
) ? 0 : 1;
466 DBG_ASSERT( nNeedUpdating
!= -1,
467 "need for linguistic configuration update should have been already checked." );
469 return nNeedUpdating
== 1;
472 ///////////////////////////////////////////////////////////////////////////
475 //! Dummy implementation in order to avoid loading of lingu DLL
476 //! when only the XSupportedLocales interface is used.
477 //! The dummy accesses the real implementation (and thus loading the DLL)
478 //! when "real" work needs to be done only.
479 class ThesDummy_Impl
:
480 public cppu::WeakImplHelper1
< XThesaurus
>
482 uno::Reference
< XThesaurus
> xThes
; // the real one...
483 Sequence
< Locale
> *pLocaleSeq
;
485 void GetCfgLocales();
490 ThesDummy_Impl() : pLocaleSeq(0) {}
494 virtual ::com::sun::star::uno::Sequence
<
495 ::com::sun::star::lang::Locale
> SAL_CALL
497 throw(::com::sun::star::uno::RuntimeException
);
498 virtual sal_Bool SAL_CALL
499 hasLocale( const ::com::sun::star::lang::Locale
& rLocale
)
500 throw(::com::sun::star::uno::RuntimeException
);
503 virtual ::com::sun::star::uno::Sequence
<
504 ::com::sun::star::uno::Reference
<
505 ::com::sun::star::linguistic2::XMeaning
> > SAL_CALL
506 queryMeanings( const ::rtl::OUString
& rTerm
,
507 const ::com::sun::star::lang::Locale
& rLocale
,
508 const ::com::sun::star::beans::PropertyValues
& rProperties
)
509 throw(::com::sun::star::lang::IllegalArgumentException
,
510 ::com::sun::star::uno::RuntimeException
);
514 ThesDummy_Impl::~ThesDummy_Impl()
520 void ThesDummy_Impl::GetCfgLocales()
525 String
aNode( A2OU( "ServiceManager/ThesaurusList" ) );
526 Sequence
< OUString
> aNodeNames( aCfg
.GetNodeNames( aNode
) );
527 const OUString
*pNodeNames
= aNodeNames
.getConstArray();
528 INT32 nLen
= aNodeNames
.getLength();
529 pLocaleSeq
= new Sequence
< Locale
>( nLen
);
530 Locale
*pLocale
= pLocaleSeq
->getArray();
531 for (INT32 i
= 0; i
< nLen
; ++i
)
533 pLocale
[i
] = SvxCreateLocale(
534 MsLangId::convertIsoStringToLanguage( pNodeNames
[i
] ) );
540 void ThesDummy_Impl::GetThes_Impl()
542 // update configuration before accessing the service
543 if (SvxLinguConfigUpdate::IsNeedUpdateAll())
544 SvxLinguConfigUpdate::UpdateAll();
548 uno::Reference
< XLinguServiceManager
> xLngSvcMgr( GetLngSvcMgr_Impl() );
550 xThes
= xLngSvcMgr
->getThesaurus();
554 // no longer needed...
555 delete pLocaleSeq
; pLocaleSeq
= 0;
561 uno::Sequence
< lang::Locale
> SAL_CALL
562 ThesDummy_Impl::getLocales()
563 throw(uno::RuntimeException
)
565 if (!SvxLinguConfigUpdate::IsNeedUpdateAll()) // configuration already update and thus lingu DLL's already loaded ?
568 return xThes
->getLocales();
569 else if (!pLocaleSeq
) // if not already loaded save startup time by avoiding loading them now
576 ThesDummy_Impl::hasLocale( const lang::Locale
& rLocale
)
577 throw(uno::RuntimeException
)
579 if (!SvxLinguConfigUpdate::IsNeedUpdateAll()) // configuration already update and thus lingu DLL's already loaded ?
582 return xThes
->hasLocale( rLocale
);
583 else if (!pLocaleSeq
) // if not already loaded save startup time by avoiding loading them now
587 INT32 nLen
= pLocaleSeq
->getLength();
588 const Locale
*pLocale
= pLocaleSeq
->getConstArray();
589 const Locale
*pEnd
= pLocale
+ nLen
;
590 for ( ; pLocale
< pEnd
&& !bFound
; ++pLocale
)
592 bFound
= pLocale
->Language
== rLocale
.Language
&&
593 pLocale
->Country
== rLocale
.Country
&&
594 pLocale
->Variant
== rLocale
.Variant
;
600 uno::Sequence
< uno::Reference
< linguistic2::XMeaning
> > SAL_CALL
601 ThesDummy_Impl::queryMeanings(
602 const rtl::OUString
& rTerm
,
603 const lang::Locale
& rLocale
,
604 const beans::PropertyValues
& rProperties
)
605 throw(lang::IllegalArgumentException
,
606 uno::RuntimeException
)
609 uno::Sequence
< uno::Reference
< linguistic2::XMeaning
> > aRes
;
610 DBG_ASSERT( xThes
.is(), "Thesaurus missing" );
612 aRes
= xThes
->queryMeanings( rTerm
, rLocale
, rProperties
);
617 ///////////////////////////////////////////////////////////////////////////
620 //! Dummy implementation in order to avoid loading of lingu DLL.
621 //! The dummy accesses the real implementation (and thus loading the DLL)
622 //! when it needs to be done only.
623 class SpellDummy_Impl
:
624 public cppu::WeakImplHelper1
< XSpellChecker1
>
626 uno::Reference
< XSpellChecker1
> xSpell
; // the real one...
628 void GetSpell_Impl();
632 // XSupportedLanguages (for XSpellChecker1)
633 virtual ::com::sun::star::uno::Sequence
< sal_Int16
> SAL_CALL
635 throw(::com::sun::star::uno::RuntimeException
);
636 virtual sal_Bool SAL_CALL
637 hasLanguage( sal_Int16 nLanguage
)
638 throw(::com::sun::star::uno::RuntimeException
);
640 // XSpellChecker1 (same as XSpellChecker but sal_Int16 for language)
641 virtual sal_Bool SAL_CALL
642 isValid( const ::rtl::OUString
& rWord
, sal_Int16 nLanguage
,
643 const ::com::sun::star::beans::PropertyValues
& rProperties
)
644 throw(::com::sun::star::lang::IllegalArgumentException
,
645 ::com::sun::star::uno::RuntimeException
);
646 virtual ::com::sun::star::uno::Reference
<
647 ::com::sun::star::linguistic2::XSpellAlternatives
> SAL_CALL
648 spell( const ::rtl::OUString
& rWord
, sal_Int16 nLanguage
,
649 const ::com::sun::star::beans::PropertyValues
& rProperties
)
650 throw(::com::sun::star::lang::IllegalArgumentException
,
651 ::com::sun::star::uno::RuntimeException
);
655 void SpellDummy_Impl::GetSpell_Impl()
657 // update configuration before accessing the service
658 if (SvxLinguConfigUpdate::IsNeedUpdateAll())
659 SvxLinguConfigUpdate::UpdateAll();
663 uno::Reference
< XLinguServiceManager
> xLngSvcMgr( GetLngSvcMgr_Impl() );
665 xSpell
= uno::Reference
< XSpellChecker1
>( xLngSvcMgr
->getSpellChecker(), UNO_QUERY
);
670 uno::Sequence
< sal_Int16
> SAL_CALL
671 SpellDummy_Impl::getLanguages()
672 throw(uno::RuntimeException
)
676 return xSpell
->getLanguages();
678 return uno::Sequence
< sal_Int16
>();
683 SpellDummy_Impl::hasLanguage( sal_Int16 nLanguage
)
684 throw(uno::RuntimeException
)
689 bRes
= xSpell
->hasLanguage( nLanguage
);
695 SpellDummy_Impl::isValid( const rtl::OUString
& rWord
, sal_Int16 nLanguage
,
696 const beans::PropertyValues
& rProperties
)
697 throw(lang::IllegalArgumentException
,
698 uno::RuntimeException
)
703 bRes
= xSpell
->isValid( rWord
, nLanguage
, rProperties
);
708 uno::Reference
< linguistic2::XSpellAlternatives
> SAL_CALL
709 SpellDummy_Impl::spell( const rtl::OUString
& rWord
, sal_Int16 nLanguage
,
710 const beans::PropertyValues
& rProperties
)
711 throw(lang::IllegalArgumentException
,
712 uno::RuntimeException
)
715 uno::Reference
< linguistic2::XSpellAlternatives
> xRes
;
717 xRes
= xSpell
->spell( rWord
, nLanguage
, rProperties
);
722 ///////////////////////////////////////////////////////////////////////////
725 //! Dummy implementation in order to avoid loading of lingu DLL.
726 //! The dummy accesses the real implementation (and thus loading the DLL)
727 //! when it needs to be done only.
728 class HyphDummy_Impl
:
729 public cppu::WeakImplHelper1
< XHyphenator
>
731 uno::Reference
< XHyphenator
> xHyph
; // the real one...
738 virtual ::com::sun::star::uno::Sequence
<
739 ::com::sun::star::lang::Locale
> SAL_CALL
741 throw(::com::sun::star::uno::RuntimeException
);
742 virtual sal_Bool SAL_CALL
743 hasLocale( const ::com::sun::star::lang::Locale
& rLocale
)
744 throw(::com::sun::star::uno::RuntimeException
);
747 virtual ::com::sun::star::uno::Reference
<
748 ::com::sun::star::linguistic2::XHyphenatedWord
> SAL_CALL
749 hyphenate( const ::rtl::OUString
& rWord
,
750 const ::com::sun::star::lang::Locale
& rLocale
,
751 sal_Int16 nMaxLeading
,
752 const ::com::sun::star::beans::PropertyValues
& rProperties
)
753 throw(::com::sun::star::lang::IllegalArgumentException
,
754 ::com::sun::star::uno::RuntimeException
);
755 virtual ::com::sun::star::uno::Reference
<
756 ::com::sun::star::linguistic2::XHyphenatedWord
> SAL_CALL
757 queryAlternativeSpelling( const ::rtl::OUString
& rWord
,
758 const ::com::sun::star::lang::Locale
& rLocale
,
760 const ::com::sun::star::beans::PropertyValues
& rProperties
)
761 throw(::com::sun::star::lang::IllegalArgumentException
,
762 ::com::sun::star::uno::RuntimeException
);
763 virtual ::com::sun::star::uno::Reference
<
764 ::com::sun::star::linguistic2::XPossibleHyphens
> SAL_CALL
765 createPossibleHyphens(
766 const ::rtl::OUString
& rWord
,
767 const ::com::sun::star::lang::Locale
& rLocale
,
768 const ::com::sun::star::beans::PropertyValues
& rProperties
)
769 throw(::com::sun::star::lang::IllegalArgumentException
,
770 ::com::sun::star::uno::RuntimeException
);
774 void HyphDummy_Impl::GetHyph_Impl()
776 // update configuration before accessing the service
777 if (SvxLinguConfigUpdate::IsNeedUpdateAll())
778 SvxLinguConfigUpdate::UpdateAll();
782 uno::Reference
< XLinguServiceManager
> xLngSvcMgr( GetLngSvcMgr_Impl() );
784 xHyph
= xLngSvcMgr
->getHyphenator();
789 uno::Sequence
< lang::Locale
> SAL_CALL
790 HyphDummy_Impl::getLocales()
791 throw(uno::RuntimeException
)
795 return xHyph
->getLocales();
797 return uno::Sequence
< lang::Locale
>();
802 HyphDummy_Impl::hasLocale( const lang::Locale
& rLocale
)
803 throw(uno::RuntimeException
)
808 bRes
= xHyph
->hasLocale( rLocale
);
813 uno::Reference
< linguistic2::XHyphenatedWord
> SAL_CALL
814 HyphDummy_Impl::hyphenate(
815 const rtl::OUString
& rWord
,
816 const lang::Locale
& rLocale
,
817 sal_Int16 nMaxLeading
,
818 const beans::PropertyValues
& rProperties
)
819 throw(lang::IllegalArgumentException
,
820 uno::RuntimeException
)
823 uno::Reference
< linguistic2::XHyphenatedWord
> xRes
;
825 xRes
= xHyph
->hyphenate( rWord
, rLocale
, nMaxLeading
, rProperties
);
830 uno::Reference
< linguistic2::XHyphenatedWord
> SAL_CALL
831 HyphDummy_Impl::queryAlternativeSpelling(
832 const rtl::OUString
& rWord
,
833 const lang::Locale
& rLocale
,
835 const PropertyValues
& rProperties
)
836 throw(lang::IllegalArgumentException
,
837 uno::RuntimeException
)
840 uno::Reference
< linguistic2::XHyphenatedWord
> xRes
;
842 xRes
= xHyph
->queryAlternativeSpelling( rWord
, rLocale
, nIndex
, rProperties
);
847 uno::Reference
< linguistic2::XPossibleHyphens
> SAL_CALL
848 HyphDummy_Impl::createPossibleHyphens(
849 const rtl::OUString
& rWord
,
850 const lang::Locale
& rLocale
,
851 const beans::PropertyValues
& rProperties
)
852 throw(lang::IllegalArgumentException
,
853 uno::RuntimeException
)
856 uno::Reference
< linguistic2::XPossibleHyphens
> xRes
;
858 xRes
= xHyph
->createPossibleHyphens( rWord
, rLocale
, rProperties
);
863 ///////////////////////////////////////////////////////////////////////////
866 typedef cppu::WeakImplHelper1
< XEventListener
> LinguMgrAppExitLstnrBaseClass
;
868 class LinguMgrAppExitLstnr
: public LinguMgrAppExitLstnrBaseClass
870 uno::Reference
< XComponent
> xDesktop
;
873 LinguMgrAppExitLstnr();
874 virtual ~LinguMgrAppExitLstnr();
876 virtual void AtExit() = 0;
879 // lang::XEventListener
880 virtual void SAL_CALL
disposing(const EventObject
& rSource
)
881 throw( RuntimeException
);
884 LinguMgrAppExitLstnr::LinguMgrAppExitLstnr()
886 // add object to frame::Desktop EventListeners in order to properly call
887 // the AtExit function at appliction exit.
889 uno::Reference
< XMultiServiceFactory
> xMgr
= getProcessServiceFactory();
892 xDesktop
= uno::Reference
< XComponent
> ( xMgr
->createInstance(
893 OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.frame.Desktop" ) ) ), UNO_QUERY
) ;
895 xDesktop
->addEventListener( this );
899 LinguMgrAppExitLstnr::~LinguMgrAppExitLstnr()
903 xDesktop
->removeEventListener( this );
904 xDesktop
= NULL
; //! release reference to desktop
906 DBG_ASSERT(!xDesktop
.is(), "reference to desktop should be realeased");
909 void LinguMgrAppExitLstnr::disposing(const EventObject
& rSource
)
910 throw( RuntimeException
)
912 if (xDesktop
.is() && rSource
.Source
== xDesktop
)
914 xDesktop
->removeEventListener( this );
915 xDesktop
= NULL
; //! release reference to desktop
921 ///////////////////////////////////////////////////////////////////////////
923 class LinguMgrExitLstnr
: public LinguMgrAppExitLstnr
926 virtual void AtExit();
929 void LinguMgrExitLstnr::AtExit()
931 // release references
932 LinguMgr::xLngSvcMgr
= 0;
933 LinguMgr::xSpell
= 0;
936 LinguMgr::xDicList
= 0;
938 LinguMgr::xIgnoreAll
= 0;
939 LinguMgr::xChangeAll
= 0;
941 LinguMgr::bExiting
= sal_True
;
943 //TL:TODO: MBA fragen wie ich ohne Absturz hier meinen Speicher
944 // wieder freibekomme...
945 //delete LinguMgr::pExitLstnr;
946 LinguMgr::pExitLstnr
= 0;
949 ///////////////////////////////////////////////////////////////////////////
952 // static member initialization
953 LinguMgrExitLstnr
* LinguMgr::pExitLstnr
= 0;
954 sal_Bool
LinguMgr::bExiting
= sal_False
;
955 uno::Reference
< XLinguServiceManager
> LinguMgr::xLngSvcMgr
= 0;
956 uno::Reference
< XSpellChecker1
> LinguMgr::xSpell
= 0;
957 uno::Reference
< XHyphenator
> LinguMgr::xHyph
= 0;
958 uno::Reference
< XThesaurus
> LinguMgr::xThes
= 0;
959 uno::Reference
< XDictionaryList
> LinguMgr::xDicList
= 0;
960 uno::Reference
< XPropertySet
> LinguMgr::xProp
= 0;
961 uno::Reference
< XDictionary
> LinguMgr::xIgnoreAll
= 0;
962 uno::Reference
< XDictionary
> LinguMgr::xChangeAll
= 0;
965 uno::Reference
< XLinguServiceManager
> LinguMgr::GetLngSvcMgr()
971 pExitLstnr
= new LinguMgrExitLstnr
;
973 if (!xLngSvcMgr
.is())
974 xLngSvcMgr
= GetLngSvcMgr_Impl();
980 uno::Reference
< XSpellChecker1
> LinguMgr::GetSpellChecker()
982 return xSpell
.is() ? xSpell
: GetSpell();
985 uno::Reference
< XHyphenator
> LinguMgr::GetHyphenator()
987 return xHyph
.is() ? xHyph
: GetHyph();
990 uno::Reference
< XThesaurus
> LinguMgr::GetThesaurus()
992 return xThes
.is() ? xThes
: GetThes();
995 uno::Reference
< XDictionaryList
> LinguMgr::GetDictionaryList()
997 return xDicList
.is() ? xDicList
: GetDicList();
1000 uno::Reference
< XPropertySet
> LinguMgr::GetLinguPropertySet()
1002 return xProp
.is() ? xProp
: GetProp();
1005 uno::Reference
< XDictionary
> LinguMgr::GetStandardDic()
1007 //! don't hold reference to this
1008 //! (it may be removed from dictionary list and needs to be
1009 //! created empty if accessed again)
1010 return GetStandard();
1013 uno::Reference
< XDictionary
> LinguMgr::GetIgnoreAllList()
1015 return xIgnoreAll
.is() ? xIgnoreAll
: GetIgnoreAll();
1018 uno::Reference
< XDictionary
> LinguMgr::GetChangeAllList()
1020 return xChangeAll
.is() ? xChangeAll
: GetChangeAll();
1023 uno::Reference
< XSpellChecker1
> LinguMgr::GetSpell()
1029 pExitLstnr
= new LinguMgrExitLstnr
;
1031 //! use dummy implementation in order to avoid loading of lingu DLL
1032 xSpell
= new SpellDummy_Impl
;
1034 /* if (!xLngSvcMgr.is())
1035 xLngSvcMgr = GetLngSvcMgr_Impl();
1037 if (xLngSvcMgr.is())
1039 xSpell = uno::Reference< XSpellChecker1 > (
1040 xLngSvcMgr->getSpellChecker(), UNO_QUERY );
1046 uno::Reference
< XHyphenator
> LinguMgr::GetHyph()
1052 pExitLstnr
= new LinguMgrExitLstnr
;
1054 //! use dummy implementation in order to avoid loading of lingu DLL
1055 xHyph
= new HyphDummy_Impl
;
1058 if (!xLngSvcMgr.is())
1059 xLngSvcMgr = GetLngSvcMgr_Impl();
1061 if (xLngSvcMgr.is())
1063 xHyph = xLngSvcMgr->getHyphenator();
1069 uno::Reference
< XThesaurus
> LinguMgr::GetThes()
1075 pExitLstnr
= new LinguMgrExitLstnr
;
1077 //! use dummy implementation in order to avoid loading of lingu DLL
1078 //! when only the XSupportedLocales interface is used.
1079 //! The dummy accesses the real implementation (and thus loading the DLL)
1080 //! when "real" work needs to be done only.
1081 xThes
= new ThesDummy_Impl
;
1083 if (!xLngSvcMgr.is())
1084 xLngSvcMgr = GetLngSvcMgr_Impl();
1086 if (xLngSvcMgr.is())
1088 xThes = xLngSvcMgr->getThesaurus();
1095 void LinguMgr::UpdateAll()
1100 uno::Reference
< XDictionaryList
> LinguMgr::GetDicList()
1106 pExitLstnr
= new LinguMgrExitLstnr
;
1108 uno::Reference
< XMultiServiceFactory
> xMgr( getProcessServiceFactory() );
1111 xDicList
= uno::Reference
< XDictionaryList
> ( xMgr
->createInstance(
1112 A2OU("com.sun.star.linguistic2.DictionaryList") ), UNO_QUERY
);
1117 uno::Reference
< XPropertySet
> LinguMgr::GetProp()
1123 pExitLstnr
= new LinguMgrExitLstnr
;
1125 uno::Reference
< XMultiServiceFactory
> xMgr( getProcessServiceFactory() );
1128 xProp
= uno::Reference
< XPropertySet
> ( xMgr
->createInstance(
1129 A2OU("com.sun.star.linguistic2.LinguProperties") ), UNO_QUERY
);
1134 uno::Reference
< XDictionary
> LinguMgr::GetIgnoreAll()
1140 pExitLstnr
= new LinguMgrExitLstnr
;
1142 uno::Reference
< XDictionaryList
> xTmpDicList( GetDictionaryList() );
1143 if (xTmpDicList
.is())
1145 xIgnoreAll
= uno::Reference
< XDictionary
> ( xTmpDicList
->getDictionaryByName(
1146 A2OU("IgnoreAllList") ), UNO_QUERY
);
1151 uno::Reference
< XDictionary
> LinguMgr::GetChangeAll()
1157 pExitLstnr
= new LinguMgrExitLstnr
;
1159 uno::Reference
< XDictionaryList
> _xDicList( GetDictionaryList() , UNO_QUERY
);
1162 xChangeAll
= uno::Reference
< XDictionary
> (
1163 _xDicList
->createDictionary(
1164 A2OU("ChangeAllList"),
1165 SvxCreateLocale( LANGUAGE_NONE
),
1166 DictionaryType_NEGATIVE
, String() ), UNO_QUERY
);
1171 uno::Reference
< XDictionary
> LinguMgr::GetStandard()
1173 // Tries to return a dictionary which may hold positive entries is
1174 // persistent and not read-only.
1179 uno::Reference
< XDictionaryList
> xTmpDicList( GetDictionaryList() );
1180 if (!xTmpDicList
.is())
1183 const OUString
aDicName( RTL_CONSTASCII_USTRINGPARAM( "standard.dic" ) );
1184 uno::Reference
< XDictionary
> xDic( xTmpDicList
->getDictionaryByName( aDicName
),
1188 // try to create standard dictionary
1189 uno::Reference
< XDictionary
> xTmp
;
1192 xTmp
= xTmpDicList
->createDictionary( aDicName
,
1193 SvxCreateLocale( LANGUAGE_NONE
),
1194 DictionaryType_POSITIVE
,
1195 linguistic::GetWritableDictionaryURL( aDicName
) );
1197 catch(com::sun::star::uno::Exception
&)
1201 // add new dictionary to list
1203 xTmpDicList
->addDictionary( xTmp
);
1204 xDic
= uno::Reference
< XDictionary
> ( xTmp
, UNO_QUERY
);
1206 #if OSL_DEBUG_LEVEL > 1
1207 uno::Reference
< XStorable
> xStor( xDic
, UNO_QUERY
);
1208 DBG_ASSERT( xDic
.is() && xDic
->getDictionaryType() == DictionaryType_POSITIVE
,
1209 "wrong dictionary type");
1210 DBG_ASSERT( xDic
.is() && SvxLocaleToLanguage( xDic
->getLocale() ) == LANGUAGE_NONE
,
1211 "wrong dictionary language");
1212 DBG_ASSERT( !xStor
.is() || (xStor
->hasLocation() && !xStor
->isReadonly()),
1213 "dictionary not editable" );
1219 ///////////////////////////////////////////////////////////////////////////
1221 uno::Reference
< XSpellChecker1
> SvxGetSpellChecker()
1223 return LinguMgr::GetSpellChecker();
1226 uno::Reference
< XHyphenator
> SvxGetHyphenator()
1228 return LinguMgr::GetHyphenator();
1231 uno::Reference
< XThesaurus
> SvxGetThesaurus()
1233 return LinguMgr::GetThesaurus();
1236 uno::Reference
< XDictionaryList
> SvxGetDictionaryList()
1238 return LinguMgr::GetDictionaryList();
1241 uno::Reference
< XPropertySet
> SvxGetLinguPropertySet()
1243 return LinguMgr::GetLinguPropertySet();
1246 //TL:TODO: remove argument or provide SvxGetIgnoreAllList with the same one
1247 uno::Reference
< XDictionary
> SvxGetOrCreatePosDic(
1248 uno::Reference
< XDictionaryList
> /* xDicList */ )
1250 return LinguMgr::GetStandardDic();
1253 uno::Reference
< XDictionary
> SvxGetIgnoreAllList()
1255 return LinguMgr::GetIgnoreAllList();
1258 uno::Reference
< XDictionary
> SvxGetChangeAllList()
1260 return LinguMgr::GetChangeAllList();
1263 ///////////////////////////////////////////////////////////////////////////
1266 #include <com/sun/star/linguistic2/XHyphenatedWord.hpp>
1268 SvxAlternativeSpelling
SvxGetAltSpelling(
1269 const ::com::sun::star::uno::Reference
<
1270 ::com::sun::star::linguistic2::XHyphenatedWord
> & rHyphWord
)
1272 SvxAlternativeSpelling aRes
;
1273 if (rHyphWord
.is() && rHyphWord
->isAlternativeSpelling())
1275 OUString
aWord( rHyphWord
->getWord() ),
1276 aAltWord( rHyphWord
->getHyphenatedWord() );
1277 INT16 nHyphenationPos
= rHyphWord
->getHyphenationPos(),
1278 nHyphenPos
= rHyphWord
->getHyphenPos();
1279 INT16 nLen
= (INT16
)aWord
.getLength();
1280 INT16 nAltLen
= (INT16
)aAltWord
.getLength();
1281 const sal_Unicode
*pWord
= aWord
.getStr(),
1282 *pAltWord
= aAltWord
.getStr();
1284 // count number of chars from the left to the
1285 // hyphenation pos / hyphen pos that are equal
1287 while (nL
<= nHyphenationPos
&& nL
<= nHyphenPos
1288 && pWord
[ nL
] == pAltWord
[ nL
])
1290 // count number of chars from the right to the
1291 // hyphenation pos / hyphen pos that are equal
1293 INT32 nIdx
= nLen
- 1;
1294 INT32 nAltIdx
= nAltLen
- 1;
1295 while (nIdx
> nHyphenationPos
&& nAltIdx
> nHyphenPos
1296 && pWord
[ nIdx
-- ] == pAltWord
[ nAltIdx
-- ])
1299 aRes
.aReplacement
= OUString( aAltWord
.copy( nL
, nAltLen
- nL
- nR
) );
1300 aRes
.nChangedPos
= (INT16
) nL
;
1301 aRes
.nChangedLength
= nLen
- nL
- nR
;
1302 aRes
.bIsAltSpelling
= TRUE
;
1303 aRes
.xHyphWord
= rHyphWord
;
1309 ///////////////////////////////////////////////////////////////////////////
1311 SvxDicListChgClamp::SvxDicListChgClamp( uno::Reference
< XDictionaryList
> &rxDicList
) :
1312 xDicList ( rxDicList
)
1316 xDicList
->beginCollectEvents();
1320 SvxDicListChgClamp::~SvxDicListChgClamp()
1324 xDicList
->endCollectEvents();
1328 ///////////////////////////////////////////////////////////////////////////
1330 short SvxDicError( Window
*pParent
, sal_Int16 nError
)
1333 if (DIC_ERR_NONE
!= nError
)
1338 case DIC_ERR_FULL
: nRid
= RID_SVXSTR_DIC_ERR_FULL
; break;
1339 case DIC_ERR_READONLY
: nRid
= RID_SVXSTR_DIC_ERR_READONLY
; break;
1341 nRid
= RID_SVXSTR_DIC_ERR_UNKNOWN
;
1342 DBG_ASSERT(0, "unexpected case");
1344 nRes
= InfoBox( pParent
, SVX_RESSTR( nRid
) ).Execute();
1349 LanguageType
SvxLocaleToLanguage( const Locale
& rLocale
)
1351 // empty Locale -> LANGUAGE_NONE
1352 if ( rLocale
.Language
.getLength() == 0 )
1353 return LANGUAGE_NONE
;
1355 return MsLangId::convertLocaleToLanguage( rLocale
);
1358 Locale
& SvxLanguageToLocale( Locale
& rLocale
, LanguageType eLang
)
1360 if ( eLang
!= LANGUAGE_NONE
/* && eLang != LANGUAGE_SYSTEM */)
1361 MsLangId::convertLanguageToLocale( eLang
, rLocale
);
1368 Locale
SvxCreateLocale( LanguageType eLang
)
1371 if ( eLang
!= LANGUAGE_NONE
/* && eLang != LANGUAGE_SYSTEM */)
1372 MsLangId::convertLanguageToLocale( eLang
, aLocale
);