update emoji autocorrect entries from po-files
[LibreOffice.git] / linguistic / source / convdiclist.cxx
blob0144fa32518e61863391e7e7afc5c352da2cdb0f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <boost/noncopyable.hpp>
23 #include <com/sun/star/container/XNameContainer.hpp>
24 #include <com/sun/star/lang/Locale.hpp>
25 #include <com/sun/star/linguistic2/ConversionDictionaryType.hpp>
26 #include <com/sun/star/linguistic2/XConversionDictionary.hpp>
27 #include <com/sun/star/linguistic2/XConversionDictionaryList.hpp>
28 #include <com/sun/star/registry/XRegistryKey.hpp>
29 #include <com/sun/star/uno/Reference.h>
30 #include <com/sun/star/util/XFlushable.hpp>
31 #include <cppuhelper/factory.hxx>
32 #include <comphelper/processfactory.hxx>
33 #include <cppuhelper/supportsservice.hxx>
34 #include <rtl/instance.hxx>
35 #include <tools/stream.hxx>
36 #include <tools/urlobj.hxx>
37 #include <ucbhelper/content.hxx>
38 #include <unotools/localfilehelper.hxx>
39 #include <unotools/lingucfg.hxx>
40 #include <unotools/pathoptions.hxx>
41 #include <unotools/useroptions.hxx>
43 #include "convdic.hxx"
44 #include "convdiclist.hxx"
45 #include "defs.hxx"
46 #include "hhconvdic.hxx"
47 #include "lngreg.hxx"
48 #include "linguistic/misc.hxx"
50 using namespace osl;
51 using namespace com::sun::star;
52 using namespace com::sun::star::lang;
53 using namespace com::sun::star::uno;
54 using namespace com::sun::star::container;
55 using namespace com::sun::star::linguistic2;
56 using namespace linguistic;
58 #define SN_CONV_DICTIONARY_LIST "com.sun.star.linguistic2.ConversionDictionaryList"
60 bool operator == ( const Locale &r1, const Locale &r2 )
62 return r1.Language == r2.Language &&
63 r1.Country == r2.Country &&
64 r1.Variant == r2.Variant;
67 OUString GetConvDicMainURL( const OUString &rDicName, const OUString &rDirectoryURL )
69 // build URL to use for new (persistent) dictionaries
71 OUString aFullDicName = OUString(rDicName) + CONV_DIC_DOT_EXT;
73 INetURLObject aURLObj;
74 aURLObj.SetSmartProtocol( INetProtocol::File );
75 aURLObj.SetSmartURL( rDirectoryURL );
76 aURLObj.Append( aFullDicName, INetURLObject::ENCODE_ALL );
77 DBG_ASSERT(!aURLObj.HasError(), "invalid URL");
78 if (aURLObj.HasError())
79 return OUString();
80 else
81 return aURLObj.GetMainURL( INetURLObject::DECODE_TO_IURI );
84 class ConvDicNameContainer :
85 public cppu::WeakImplHelper1
87 ::com::sun::star::container::XNameContainer
89 private boost::noncopyable
91 uno::Sequence< uno::Reference< XConversionDictionary > > aConvDics;
93 sal_Int32 GetIndexByName_Impl( const OUString& rName );
95 public:
96 ConvDicNameContainer();
97 virtual ~ConvDicNameContainer();
99 // XElementAccess
100 virtual ::com::sun::star::uno::Type SAL_CALL getElementType( ) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
101 virtual sal_Bool SAL_CALL hasElements( ) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
103 // XNameAccess
104 virtual ::com::sun::star::uno::Any SAL_CALL getByName( const OUString& aName ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
105 virtual ::com::sun::star::uno::Sequence< OUString > SAL_CALL getElementNames( ) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
106 virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) throw (::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
108 // XNameReplace
109 virtual void SAL_CALL replaceByName( const OUString& aName, const ::com::sun::star::uno::Any& aElement ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
111 // XNameContainer
112 virtual void SAL_CALL insertByName( const OUString& aName, const ::com::sun::star::uno::Any& aElement ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::container::ElementExistException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
113 virtual void SAL_CALL removeByName( const OUString& Name ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
115 // looks for conversion dictionaries with the specified extension
116 // in the directory and adds them to the container
117 void AddConvDics( const OUString &rSearchDirPathURL, const OUString &rExtension );
119 // calls Flush for the dictionaries that support XFlushable
120 void FlushDics() const;
122 sal_Int32 GetCount() const { return aConvDics.getLength(); }
123 uno::Reference< XConversionDictionary > GetByName( const OUString& rName );
125 const uno::Reference< XConversionDictionary > GetByIndex( sal_Int32 nIdx )
127 return aConvDics.getConstArray()[nIdx];
131 ConvDicNameContainer::ConvDicNameContainer()
135 ConvDicNameContainer::~ConvDicNameContainer()
139 void ConvDicNameContainer::FlushDics() const
141 sal_Int32 nLen = aConvDics.getLength();
142 const uno::Reference< XConversionDictionary > *pDic = aConvDics.getConstArray();
143 for (sal_Int32 i = 0; i < nLen; ++i)
145 uno::Reference< util::XFlushable > xFlush( pDic[i] , UNO_QUERY );
146 if (xFlush.is())
150 xFlush->flush();
152 catch(Exception &)
154 OSL_FAIL( "flushing of conversion dictionary failed" );
160 sal_Int32 ConvDicNameContainer::GetIndexByName_Impl(
161 const OUString& rName )
163 sal_Int32 nRes = -1;
164 sal_Int32 nLen = aConvDics.getLength();
165 const uno::Reference< XConversionDictionary > *pDic = aConvDics.getConstArray();
166 for (sal_Int32 i = 0; i < nLen && nRes == -1; ++i)
168 if (rName == pDic[i]->getName())
169 nRes = i;
171 return nRes;
174 uno::Reference< XConversionDictionary > ConvDicNameContainer::GetByName(
175 const OUString& rName )
177 uno::Reference< XConversionDictionary > xRes;
178 sal_Int32 nIdx = GetIndexByName_Impl( rName );
179 if ( nIdx != -1)
180 xRes = aConvDics.getArray()[nIdx];
181 return xRes;
184 uno::Type SAL_CALL ConvDicNameContainer::getElementType( )
185 throw (RuntimeException, std::exception)
187 MutexGuard aGuard( GetLinguMutex() );
188 return uno::Type( cppu::UnoType<XConversionDictionary>::get());
191 sal_Bool SAL_CALL ConvDicNameContainer::hasElements( )
192 throw (RuntimeException, std::exception)
194 MutexGuard aGuard( GetLinguMutex() );
195 return aConvDics.getLength() > 0;
198 uno::Any SAL_CALL ConvDicNameContainer::getByName( const OUString& rName )
199 throw (NoSuchElementException, WrappedTargetException, RuntimeException, std::exception)
201 MutexGuard aGuard( GetLinguMutex() );
202 uno::Reference< XConversionDictionary > xRes( GetByName( rName ) );
203 if (!xRes.is())
204 throw NoSuchElementException();
205 return makeAny( xRes );
208 uno::Sequence< OUString > SAL_CALL ConvDicNameContainer::getElementNames( )
209 throw (RuntimeException, std::exception)
211 MutexGuard aGuard( GetLinguMutex() );
213 sal_Int32 nLen = aConvDics.getLength();
214 uno::Sequence< OUString > aRes( nLen );
215 OUString *pName = aRes.getArray();
216 const uno::Reference< XConversionDictionary > *pDic = aConvDics.getConstArray();
217 for (sal_Int32 i = 0; i < nLen; ++i)
218 pName[i] = pDic[i]->getName();
219 return aRes;
222 sal_Bool SAL_CALL ConvDicNameContainer::hasByName( const OUString& rName )
223 throw (RuntimeException, std::exception)
225 MutexGuard aGuard( GetLinguMutex() );
226 return GetByName( rName ).is();
229 void SAL_CALL ConvDicNameContainer::replaceByName(
230 const OUString& rName,
231 const uno::Any& rElement )
232 throw (IllegalArgumentException, NoSuchElementException, WrappedTargetException, RuntimeException, std::exception)
234 MutexGuard aGuard( GetLinguMutex() );
236 sal_Int32 nRplcIdx = GetIndexByName_Impl( rName );
237 if (nRplcIdx == -1)
238 throw NoSuchElementException();
239 uno::Reference< XConversionDictionary > xNew;
240 rElement >>= xNew;
241 if (!xNew.is() || xNew->getName() != rName)
242 throw IllegalArgumentException();
243 aConvDics.getArray()[ nRplcIdx ] = xNew;
246 void SAL_CALL ConvDicNameContainer::insertByName(
247 const OUString& rName,
248 const Any& rElement )
249 throw (IllegalArgumentException, ElementExistException, WrappedTargetException, RuntimeException, std::exception)
251 MutexGuard aGuard( GetLinguMutex() );
253 if (GetByName( rName ).is())
254 throw ElementExistException();
255 uno::Reference< XConversionDictionary > xNew;
256 rElement >>= xNew;
257 if (!xNew.is() || xNew->getName() != rName)
258 throw IllegalArgumentException();
260 sal_Int32 nLen = aConvDics.getLength();
261 aConvDics.realloc( nLen + 1 );
262 aConvDics.getArray()[ nLen ] = xNew;
265 void SAL_CALL ConvDicNameContainer::removeByName( const OUString& rName )
266 throw (NoSuchElementException, WrappedTargetException, RuntimeException, std::exception)
268 MutexGuard aGuard( GetLinguMutex() );
270 sal_Int32 nRplcIdx = GetIndexByName_Impl( rName );
271 if (nRplcIdx == -1)
272 throw NoSuchElementException();
274 // physically remove dictionary
275 uno::Reference< XConversionDictionary > xDel = aConvDics.getArray()[nRplcIdx];
276 OUString aName( xDel->getName() );
277 OUString aDicMainURL( GetConvDicMainURL( aName, GetDictionaryWriteablePath() ) );
278 INetURLObject aObj( aDicMainURL );
279 DBG_ASSERT( aObj.GetProtocol() == INetProtocol::File, "+HangulHanjaOptionsDialog::OkHdl(): non-file URLs cannot be deleted" );
280 if( aObj.GetProtocol() == INetProtocol::File )
284 ::ucbhelper::Content aCnt( aObj.GetMainURL( INetURLObject::NO_DECODE ),
285 uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >(),
286 comphelper::getProcessComponentContext() );
287 aCnt.executeCommand( "delete", makeAny( true ) );
289 catch( ::com::sun::star::ucb::CommandAbortedException& )
291 SAL_WARN( "linguistic", "HangulHanjaOptionsDialog::OkHdl(): CommandAbortedException" );
293 catch( ... )
295 SAL_WARN( "linguistic", "HangulHanjaOptionsDialog::OkHdl(): Any other exception" );
299 sal_Int32 nLen = aConvDics.getLength();
300 uno::Reference< XConversionDictionary > *pDic = aConvDics.getArray();
301 for (sal_Int32 i = nRplcIdx; i < nLen - 1; ++i)
302 pDic[i] = pDic[i + 1];
303 aConvDics.realloc( nLen - 1 );
306 void ConvDicNameContainer::AddConvDics(
307 const OUString &rSearchDirPathURL,
308 const OUString &rExtension )
310 const Sequence< OUString > aDirCnt(
311 utl::LocalFileHelper::GetFolderContents( rSearchDirPathURL, false ) );
312 const OUString *pDirCnt = aDirCnt.getConstArray();
313 sal_Int32 nEntries = aDirCnt.getLength();
315 for (sal_Int32 i = 0; i < nEntries; ++i)
317 OUString aURL( pDirCnt[i] );
319 sal_Int32 nPos = aURL.lastIndexOf('.');
320 OUString aExt( aURL.copy(nPos + 1).toAsciiLowerCase() );
321 OUString aSearchExt( rExtension.toAsciiLowerCase() );
322 if(aExt != aSearchExt)
323 continue; // skip other files
325 sal_Int16 nLang;
326 sal_Int16 nConvType;
327 if (IsConvDic( aURL, nLang, nConvType ))
329 // get decoded dictionary file name
330 INetURLObject aURLObj( aURL );
331 OUString aDicName = aURLObj.getBase( INetURLObject::LAST_SEGMENT,
332 true, INetURLObject::DECODE_WITH_CHARSET,
333 RTL_TEXTENCODING_UTF8 );
335 uno::Reference < XConversionDictionary > xDic;
336 if (nLang == LANGUAGE_KOREAN &&
337 nConvType == ConversionDictionaryType::HANGUL_HANJA)
339 xDic = new HHConvDic( aDicName, aURL );
341 else if ((nLang == LANGUAGE_CHINESE_SIMPLIFIED || nLang == LANGUAGE_CHINESE_TRADITIONAL) &&
342 nConvType == ConversionDictionaryType::SCHINESE_TCHINESE)
344 xDic = new ConvDic( aDicName, nLang, nConvType, false, aURL );
347 if (xDic.is())
349 uno::Any aAny;
350 aAny <<= xDic;
351 insertByName( xDic->getName(), aAny );
357 namespace
359 struct StaticConvDicList : public rtl::StaticWithInit<
360 uno::Reference<XInterface>, StaticConvDicList> {
361 uno::Reference<XInterface> operator () () {
362 return (cppu::OWeakObject *) new ConvDicList;
367 void ConvDicList::MyAppExitListener::AtExit()
369 rMyDicList.FlushDics();
370 StaticConvDicList::get().clear();
373 ConvDicList::ConvDicList() :
374 aEvtListeners( GetLinguMutex() )
376 pNameContainer = 0;
377 bDisposing = false;
379 pExitListener = new MyAppExitListener( *this );
380 xExitListener = pExitListener;
381 pExitListener->Activate();
384 ConvDicList::~ConvDicList()
387 if (!bDisposing && pNameContainer)
388 pNameContainer->FlushDics();
390 pExitListener->Deactivate();
393 void ConvDicList::FlushDics()
395 // check only pointer to avoid creating the container when
396 // the dictionaries were not accessed yet
397 if (pNameContainer)
398 pNameContainer->FlushDics();
401 ConvDicNameContainer & ConvDicList::GetNameContainer()
403 if (!pNameContainer)
405 pNameContainer = new ConvDicNameContainer;
406 pNameContainer->AddConvDics( GetDictionaryWriteablePath(), OUString(CONV_DIC_EXT) );
407 xNameContainer = pNameContainer;
409 // access list of text conversion dictionaries to activate
410 SvtLinguOptions aOpt;
411 SvtLinguConfig().GetOptions( aOpt );
412 sal_Int32 nLen = aOpt.aActiveConvDics.getLength();
413 const OUString *pActiveConvDics = aOpt.aActiveConvDics.getConstArray();
414 for (sal_Int32 i = 0; i < nLen; ++i)
416 uno::Reference< XConversionDictionary > xDic =
417 pNameContainer->GetByName( pActiveConvDics[i] );
418 if (xDic.is())
419 xDic->setActive( sal_True );
422 // since there is no UI to active/deactivate the dictionaries
423 // for chinese text conversion they should be activated by default
424 uno::Reference< XConversionDictionary > xS2TDic(
425 pNameContainer->GetByName( "ChineseS2T" ), UNO_QUERY );
426 uno::Reference< XConversionDictionary > xT2SDic(
427 pNameContainer->GetByName( "ChineseT2S" ), UNO_QUERY );
428 if (xS2TDic.is())
429 xS2TDic->setActive( sal_True );
430 if (xT2SDic.is())
431 xT2SDic->setActive( sal_True );
434 return *pNameContainer;
437 uno::Reference< container::XNameContainer > SAL_CALL ConvDicList::getDictionaryContainer( ) throw (RuntimeException, std::exception)
439 MutexGuard aGuard( GetLinguMutex() );
440 GetNameContainer();
441 DBG_ASSERT( xNameContainer.is(), "missing name container" );
442 return xNameContainer;
445 uno::Reference< XConversionDictionary > SAL_CALL ConvDicList::addNewDictionary(
446 const OUString& rName,
447 const Locale& rLocale,
448 sal_Int16 nConvDicType )
449 throw (NoSupportException, ElementExistException, RuntimeException, std::exception)
451 MutexGuard aGuard( GetLinguMutex() );
453 sal_Int16 nLang = LinguLocaleToLanguage( rLocale );
455 if (GetNameContainer().hasByName( rName ))
456 throw ElementExistException();
458 uno::Reference< XConversionDictionary > xRes;
459 OUString aDicMainURL( GetConvDicMainURL( rName, GetDictionaryWriteablePath() ) );
460 if (nLang == LANGUAGE_KOREAN &&
461 nConvDicType == ConversionDictionaryType::HANGUL_HANJA)
463 xRes = new HHConvDic( rName, aDicMainURL );
465 else if ((nLang == LANGUAGE_CHINESE_SIMPLIFIED || nLang == LANGUAGE_CHINESE_TRADITIONAL) &&
466 nConvDicType == ConversionDictionaryType::SCHINESE_TCHINESE)
468 xRes = new ConvDic( rName, nLang, nConvDicType, false, aDicMainURL );
471 if (!xRes.is())
472 throw NoSupportException();
473 else
475 xRes->setActive( sal_True );
476 uno::Any aAny;
477 aAny <<= xRes;
478 GetNameContainer().insertByName( rName, aAny );
480 return xRes;
483 uno::Sequence< OUString > SAL_CALL ConvDicList::queryConversions(
484 const OUString& rText,
485 sal_Int32 nStartPos,
486 sal_Int32 nLength,
487 const Locale& rLocale,
488 sal_Int16 nConversionDictionaryType,
489 ConversionDirection eDirection,
490 sal_Int32 nTextConversionOptions )
491 throw (IllegalArgumentException, NoSupportException, RuntimeException, std::exception)
493 MutexGuard aGuard( GetLinguMutex() );
495 sal_Int32 nCount = 0;
496 uno::Sequence< OUString > aRes( 20 );
497 OUString *pRes = aRes.getArray();
499 bool bSupported = false;
500 sal_Int32 nLen = GetNameContainer().GetCount();
501 for (sal_Int32 i = 0; i < nLen; ++i)
503 const uno::Reference< XConversionDictionary > xDic( GetNameContainer().GetByIndex(i) );
504 bool bMatch = xDic.is() &&
505 xDic->getLocale() == rLocale &&
506 xDic->getConversionType() == nConversionDictionaryType;
507 bSupported |= bMatch;
508 if (bMatch && xDic->isActive())
510 Sequence< OUString > aNewConv( xDic->getConversions(
511 rText, nStartPos, nLength,
512 eDirection, nTextConversionOptions ) );
513 sal_Int32 nNewLen = aNewConv.getLength();
514 if (nNewLen > 0)
516 if (nCount + nNewLen > aRes.getLength())
518 aRes.realloc( nCount + nNewLen + 20 );
519 pRes = aRes.getArray();
521 const OUString *pNewConv = aNewConv.getConstArray();
522 for (sal_Int32 k = 0; k < nNewLen; ++k)
523 pRes[nCount++] = pNewConv[k];
528 if (!bSupported)
529 throw NoSupportException();
531 aRes.realloc( nCount );
532 return aRes;
535 sal_Int16 SAL_CALL ConvDicList::queryMaxCharCount(
536 const Locale& rLocale,
537 sal_Int16 nConversionDictionaryType,
538 ConversionDirection eDirection )
539 throw (RuntimeException, std::exception)
541 MutexGuard aGuard( GetLinguMutex() );
543 sal_Int16 nRes = 0;
544 GetNameContainer();
545 sal_Int32 nLen = GetNameContainer().GetCount();
546 for (sal_Int32 i = 0; i < nLen; ++i)
548 const uno::Reference< XConversionDictionary > xDic( GetNameContainer().GetByIndex(i) );
549 if (xDic.is() &&
550 xDic->getLocale() == rLocale &&
551 xDic->getConversionType() == nConversionDictionaryType)
553 sal_Int16 nC = xDic->getMaxCharCount( eDirection );
554 if (nC > nRes)
555 nRes = nC;
558 return nRes;
561 void SAL_CALL ConvDicList::dispose( )
562 throw (RuntimeException, std::exception)
564 MutexGuard aGuard( GetLinguMutex() );
565 if (!bDisposing)
567 bDisposing = true;
568 EventObject aEvtObj( (XConversionDictionaryList *) this );
569 aEvtListeners.disposeAndClear( aEvtObj );
571 FlushDics();
575 void SAL_CALL ConvDicList::addEventListener(
576 const uno::Reference< XEventListener >& rxListener )
577 throw (RuntimeException, std::exception)
579 MutexGuard aGuard( GetLinguMutex() );
580 if (!bDisposing && rxListener.is())
581 aEvtListeners.addInterface( rxListener );
584 void SAL_CALL ConvDicList::removeEventListener(
585 const uno::Reference< XEventListener >& rxListener )
586 throw (RuntimeException, std::exception)
588 MutexGuard aGuard( GetLinguMutex() );
589 if (!bDisposing && rxListener.is())
590 aEvtListeners.removeInterface( rxListener );
593 OUString SAL_CALL ConvDicList::getImplementationName()
594 throw (RuntimeException, std::exception)
596 MutexGuard aGuard( GetLinguMutex() );
597 return getImplementationName_Static();
600 sal_Bool SAL_CALL ConvDicList::supportsService( const OUString& rServiceName )
601 throw (RuntimeException, std::exception)
603 return cppu::supportsService(this, rServiceName);
606 uno::Sequence< OUString > SAL_CALL ConvDicList::getSupportedServiceNames()
607 throw (RuntimeException, std::exception)
609 MutexGuard aGuard( GetLinguMutex() );
610 return getSupportedServiceNames_Static();
613 uno::Sequence< OUString > ConvDicList::getSupportedServiceNames_Static()
614 throw()
616 uno::Sequence< OUString > aSNS( 1 );
617 aSNS.getArray()[0] = SN_CONV_DICTIONARY_LIST;
618 return aSNS;
621 uno::Reference< uno::XInterface > SAL_CALL ConvDicList_CreateInstance(
622 const uno::Reference< XMultiServiceFactory > & /*rSMgr*/ )
623 throw(Exception)
625 return StaticConvDicList::get();
628 void * SAL_CALL ConvDicList_getFactory(
629 const sal_Char * pImplName,
630 XMultiServiceFactory * pServiceManager, void * )
632 void * pRet = 0;
633 if ( ConvDicList::getImplementationName_Static().equalsAscii( pImplName ) )
635 uno::Reference< XSingleServiceFactory > xFactory =
636 cppu::createOneInstanceFactory(
637 pServiceManager,
638 ConvDicList::getImplementationName_Static(),
639 ConvDicList_CreateInstance,
640 ConvDicList::getSupportedServiceNames_Static());
641 // acquire, because we return an interface pointer instead of a reference
642 xFactory->acquire();
643 pRet = xFactory.get();
645 return pRet;
648 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */